Java类的完整构造执行顺序
这里只说一个完整的结果,至于为什么是这样的顺序,可以参考我以前的文章:深入剖析java类的构造方式
1. 如果父类有静态成员赋值或者静态初始化块,执行静态成员赋值和静态初始化块
2. 如果类有静态成员赋值或者静态初始化块,执行静态成员赋值和静态初始化块
3. 将类的成员赋予初值(原始类型的成员的值为规定值,例如int型为0,float型为0.0f,boolean型为false;对象类型的初始值为null)
4. 如果构造方法中存在this()调用(可以是其它带参数的this()调用)则执行之,执行完毕后进入第7步继续执行,如果没有this调用则进行下一步。(这个有可能存在递归调用其它的构造方法)
5. 执行显式的super()调用(可以是其它带参数的super()调用)或者隐式的super()调用(缺省构造方法),此步骤又进入一个父类的构造过程并一直上推至Object对象的构造。
6. 执行类申明中的成员赋值和初始化块。
7. 执行构造方法中的其它语句。
其中第4步是比较麻烦的,因为this调用实际上会调用类的另外一个构造方法,最终应该是执行类的某个构造方法,它可能会显示的调用super,但是无论是否调用super,最终都是执行super的,也就是父类的构造方法并一直这样递归到Object,所以在子类和父类的构造中,首先构造或者说执行的是父类的构造,但是它是由子类的构造方法调用的,先于构造方法的方法体里面的内容,这个是由编译器决定的。所以我感觉简单直观一些的顺序表述应该是:
1. 如果父类有静态成员赋值或者静态初始化块,执行静态成员赋值和静态初始化块
2. 如果类有静态成员赋值或者静态初始化块,执行静态成员赋值和静态初始化块
3. 将类的成员赋予初值(原始类型的成员的值为规定值,例如int型为0,float型为0.0f,boolean型为false;对象类型的初始值为null)
4. 执行构造方法,并可能递归调用this(),最终先执行父类的构造方法并一直递归到Object的构造方法的执行
5. 父类的构造方法执行完成后,执行类申明中的成员赋值和初始化块。
6. 执行构造方法中的其它语句。
最终的简化顺序版本是:
1. 父类的静态成员赋值和静态块
2. 子类的静态成员和静态块
3. 父类的构造方法
4. 父类的成员赋值和初始化块
5. 父类的构造方法中的其它语句
6. 子类的成员赋值和初始化块
7. 子类的构造方法中的其它语句
2006年11月16日更新:
针对留言中提到的那个文章中的问题发现这个顺序也是有不足的情况,这个顺序是一般的顺序,但是有可能被打破,留言中的那篇文章就是一个例子,因为在执行静态初始化块的时候先执行了类的构造,打破了这个一般顺序。所以这个顺序有个前提就是静态赋值和初始化块中没有对本类的实例化语句。
对于那个文章中的问题,作者最后的解决方法可行,但是不见得是最好的,可以简单的修改静态赋值和静态初始化块的顺序,修改后的代码片断为:
public class CachingEnumResolver {
private static Map CODE_MAP_CACHE;
/*MSGCODE->Category内存索引*/
static {
CODE_MAP_CACHE = new HashMap();
//为了说明问题,我在这里初始化一条数据
CODE_MAP_CACHE.put("0","北京市");
}
//单态实例 一切问题皆由此行引起
private static final CachingEnumResolver SINGLE_ENUM_RESOLVER = new CachingEnumResolver();
2006年11月28日更新:
最后做为是否理解了这个顺序的测试,看看你能不能得到下面的Main类的输出:
public class Parent {
//private static Parent instance=new Child();
private static String message="Parent Static message";
private String m="Parent instance message";
//private static Parent instance=new Child();
static {
System.out.println("Parent static block");
System.out.println(message);
}
{
System.out.println("Parent instance block");
System.out.println(m);
}
//private static Parent instance=new Child();
public Parent() {
System.out.println("Parent construtor");
}
}
public class Child extends Parent{
private static String message="Child Static message";
private String m="Child instance message";
static {
System.out.println("Child static block");
System.out.println(message);
}
{
System.out.println("Child instance block");
System.out.println(m);
}
public Child() {
System.out.println("Child construtor");
}
}
public class Main {
public static void main(String[] args) {
Child child=new Child();
}
}
另外请注意Parent类有三行注释掉的代码,每次取消一行的注释并重新注释其它的,输出又是什么样的?
作者: Cherami
原载: Java 类的完整构造执行顺序
http://www.jiehoo.me/java-constructor-execute-fully-order.htm
版权所有。转载时必须以链接形式注明作者和原始出处及本声明。
分享到:
相关推荐
OC 基础 分类
Java程序设计基础分类复习 答案
大数据应用基础分类算法.pptx
广东会计基础分类模拟28.pdf
Java程序设计基础分类复习题
帮助对各种数据进行基础分类,分类方法包括KNN、随机森林、鉴别分析等
大数据应用基础分类算法115.pptx
货币与金融统计的基础分类.pptx
货币与金融统计的基础分类.ppt
菜鸟也谈运营活动基础分类.rar
防化服的各类标准和基础分类.docx
二次函数基础分类练习题含答案01938.doc
开心版六年级下册小学英语基础分类卷.doc
开心版五年级下册小学英语基础分类卷.doc
软件测试从这里开始 测试方面相对 详细的资料 其内容包括 软件测试简介 质量体系 软件生命周期 软件测试基础 分类和方法 系统测试分类 系统测试流程 功能自动化 性能测试实例 测试工具 团队测试 测试相关知识
二次函数基础分类练习题(含答案).pdf
浙江省会计基础分类模拟21(精编版).pdf
二次函数基础分类练习题(含答案).docx
下货币与金融统计的基础分类资料PPT学习教案.pptx
二次函数经典基础分类练习题(含答案).doc