本文主要介绍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子类和父类的实例化顺序 及 陷阱的更多相关文章

  1. java中子类继承父类程序执行顺序

    java中子类继承父类程序执行顺序 FatherTest.java public class FatherTest { private String name; public FatherTest() ...

  2. java中子类继承父类程序执行顺序问题

    Java中,new一个类的对象,类里面的静态代码块.非静态代码.无参构造方法.有参构造方法.类的一般方法等部分,它们的执行顺序相对来说比较简单,用程序也很容易验证.比如新建一个测试父类. public ...

  3. Java入门-浅析Java学习从入门到精通【转】

    一. JDK (Java Development Kit)  JDK是整个Java的核心,包括了Java运行环境(Java Runtime Envirnment),一堆Java工具和Java基础的类库 ...

  4. Java 中变量初始化、子类和父类构造器调用的顺序

    先说结论 变量初始化 -> 父类构造器 -> 子类构造器 贴代码 Animcal.java 父类 public class Animal { private static int inde ...

  5. Java子类继承父类的执行顺序

    父类的静态代码块(static) 子类的静态代码块(static) 父类的非静态代码块(父类成员初始化) 父类的构造方法 子类的非静态代码块(子类成员初始化) 子类的构造方法

  6. [ Java学习基础 ] 浅析Java方法调用

     先看一个示例,读者可先自行阅读判断输出结果: public class TestClass { private static void testMethod(){ System.out.printl ...

  7. JAVA面试题 浅析Java中的static关键字

    面试官Q1:请说说static关键字,你在项目中是怎么使用的? static 关键字可以用来修饰:属性.方法.内部类.代码块: static 修饰的资源属于类级别,是全体对象实例共享的资源: 使用 s ...

  8. java 子类重写父类的方法应注意的问题

    若想实现一个合格重写方法,而不是重载,那么必须同时满足下面的要求! A.重写规则之一:    重写方法不能比被重写方法限制有更严格的访问级别.(但是可以更广泛,比如父类方法是包访问权限,子类的重写方法 ...

  9. java 子类、父类中静态代码块、字段,非静态代码块、字段以及构造函数的初始化顺序和次数

    一个类中的数据初始化顺序是面试官非常喜欢出的面试题之一,本文用一个实例来介绍java中子类.父类中静态代码块.字段,非静态代码块.字段以及构造函数的执行顺序和次数. 一.包结构

随机推荐

  1. Qt调用word 例子

    Qt调用word 例子 Getting Microsoft Word Object to SaveAs #include <QtGui> #include <QAxObject> ...

  2. hdu 4472 Count (2012 ACM-ICPC 成都现场赛)

    递推,考虑到一n可以由i * j + 1组合出来,即第二层有j个含有i个元素的子树...然后就可以了.. #include<algorithm> #include<iostream& ...

  3. Spring框架简单介绍

    原文地址:  http://my.oschina.net/myriads/blog/37922 1.使用框架的意义与Spring的主要内容 随着软件结构的日益庞大,软件模块化趋势出现,软件开发也须要多 ...

  4. HDU2586 How far away ?(LCA模板题)

    题目链接:传送门 题意: 给定一棵树,求两个点之间的距离. 分析: LCA 的模板题目 ans = dis[u]+dis[v] - 2*dis[lca(u,v)]; 在线算法:详细解说 传送门 代码例 ...

  5. 通信协议:HTTP、TCP、UDP(转)

    原文出处: 碧雪轩的博客 TCP   HTTP   UDP: 都是通信协议,也就是通信时所遵守的规则,只有双方按照这个规则“说话”,对方才能理解或为之服务. TCP   HTTP   UDP三者的关系 ...

  6. oracle数据库恢复与备份

    一.oracle数据库恢复 1.恢复刚才删除的一条数据 delete from emp e where e.empname='SMITH' select * from flashback_transa ...

  7. java 线程 新类库中的构件 countDownLatch 使用

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhbmdydWkxOTg4/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  8. Objective-C之成魔之路【9-类构造方法和成员变量作用域、以及变量】

    郝萌主倾心贡献,尊重作者的劳动成果.请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额任意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 构造方法 ...

  9. 初窥Linux 之 文件权限

    一.用户与用户组 为了更好地理解文件权限,我们需要先有用户和用户组的概念.因为在Linux里面,任何一个文件都具有“User(用户).Group(用户组)及Others(其他用户)”3种身份的个别权限 ...

  10. Sql Server函数全解<四>日期和时间函数

    原文:Sql Server函数全解<四>日期和时间函数   日期和时间函数主要用来处理日期和时间值,本篇主要介绍各种日期和时间函数的功能和用法,一般的日期函数除了使用date类型的参数外, ...