Java拾遗(一):浅析Java子类和父类的实例化顺序 及 陷阱
来源:互联网 发布:js点击缩略图显示大图 编辑:程序博客网 时间:2024/04/28 21:04
本文主要介绍Java里常用的子类和父类的变量实例化顺序及陷阱,并结合一个Android实例来探讨此问题。日后编程中应尽量避免此陷阱。
首先看下面一段代码:
定义一个虚类Server.java
- package org.yanzi.test1;
- public abstract class Server {
- private static final int DEFAULT_PORT = 900;
- public Server() {
- // TODO Auto-generated constructor stub
- int port = getPort();
- System.out.println("port = " + port + " DEFAULT_PORT = " + DEFAULT_PORT);
- }
- protected abstract int getPort();
- }
然后定义一个子类SimpleServer.java
- package org.yanzi.test1;
- public class SimpleServer extends Server {
- private int mPort = 100;
- public SimpleServer(int port) {
- // TODO Auto-generated constructor stub
- this.mPort = port;
- }
- @Override
- protected int getPort() {
- // TODO Auto-generated method stub
- return mPort;
- }
- }
测试代码:
- package org.yanzi.test1;
- public class Test1 {
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Server s = new SimpleServer(600);
- }
- }
测试结果:
port = 0 DEFAULT_PORT = 900
在测试代码里,传了一个参数600,我们希望getPort得到也是600,但遗憾的是得到的是一个大大的0!!!出现这个问题是因对Java子类和父类实例化顺序存在模糊,下面来看下其正确顺序:
1、new一个SimpleServer,SimpleServer的构造函数接收参数600;
2、初始化父类Server的静态变量,DEFAULT_PORT赋值为900;
3、为了实例化子类,首先实例化其父类Server。子类有参数的构造中默认包含了super方法,即调用父类的无参构造函数。因此就到了int port = getPort();这一句,调用子类的getPort方法。子类的getPort方法返回mPort,此时mPort还没有赋值,因此还是0.这就是得到大大的0的原因!!!
4、父类初始化完毕后,开始初始化子类的实例变量,mPort赋值100;
5、执行子类的构造函数,mPort赋值600;
6、子类实例化完毕,对象创建完了!
真相大白了,再做一个测试。将SimpleServer里的实例变量mPort搞成静态变量如下:
- package org.yanzi.test1;
- public class SimpleServer extends Server {
- private static int mPort = 100;
- public SimpleServer(int port) {
- // TODO Auto-generated constructor stub
- this.mPort = port;
- }
- @Override
- protected int getPort() {
- // TODO Auto-generated method stub
- return mPort;
- }
- }
port = 100 DEFAULT_PORT = 900
其执行顺序是:
1.第一个步骤同上,SimpleServer接收构造参数600
2.初始化父类的静态代码块,当然包括静态变量,然后初始化子类的静态变量
3.初始化父类的非静态代码,包括非静态的变量等;
4.执行父类的构造函数;
5.初始化子类的非静态代码
6.执行子类的构造函数。
至此完毕,最终的结论就是构造函数越简单越好,不要在构造函数里做太多操作。回过头再来看杂家的前文:Android自定义UI陷阱:LayoutInflater.from().inflate()一定不能工作在父类或虚类里 如果把initView()放在父类里,则子类LAYOUT_ID在使用时还会是0.因此即便要用也要将此弄成static类型的。
本文参考《编写高质量代码:改善Java的151个建议》、链接1、链接2- Java拾遗(一):浅析Java子类和父类的实例化顺序 及 陷阱
- Java拾遗(一):浅析Java子类和父类的实例化顺序 及 陷阱
- Java拾遗(一):浅析Java子类和父类的实例化顺序 及 陷阱
- 浅析Java子类和父类的实例化顺序 及 陷阱
- 浅析Java子类和父类的实例化顺序 及 陷阱
- Java的子类和父类实例化顺序
- Java中子类和父类的实例化顺序
- Java抽象类及子类实例化顺序和方法调用顺序测试
- java 类及子类的初始化顺序
- java子类和父类的执行顺序
- java子类父类的加载顺序
- java中 静态成员、实例成员、构造方法在子类和父类中的执行顺序
- Java抽象类及子类方法的调用顺序
- java 父类子类静态成员,实例成员,构造函数初始化的顺序
- java 父类子类静态成员,实例成员,构造函数初始化的顺序
- java 父类访问子类对象的实例变量 继承过程中的执行顺序
- 基类和子类的调用顺序(C#,java)
- 基类和子类的调用顺序(C#,java)
- JVM Management API
- Memcache安全配置
- matlab GUI控件代码框架
- System.Properties和System.getenv区别
- php知识点3-HTTP 头部-Cache-Control
- Java拾遗(一):浅析Java子类和父类的实例化顺序 及 陷阱
- 【Leetcode】Additive Number
- iOS中数据库的增删改查
- HDU 2865 Birthday Toy(Polya综合)
- 网络状态检测------苹果官方示例Reachability的使用
- HDOJ 1210 Eddy's 洗牌问题
- php知识点3-HTTP 头部-Accept-Encoding
- 基于Bmob的仿微信即时聊天软件
- Python用法:命令行和环境