Java对象实例化过程分析
2015-04-30 17:50
281 查看
(一) 问题描述
最近,同事遇到一个关于java 初始化的问题,描述如下:
子类构造器中调用super(),然后在父类构造器中调用子类有@overwrite的方法,子类在overwrite的方法中对自己成员赋值,log输出成功赋值,在子类new完,log打印发现部分成员变量值丢失了。
打印log发现list数据丢失了,int值还在。
乍看起来,很奇怪吧? 其实是因为对初始化的一些问题没有理解清楚,导致了数据丢失。初始化问题算是java中比较初级的问题,但也能看出知识点掌握的深不深、牢不牢
(二) 结论
先给出结论,关于对象实例化的顺序,简易描述如下:
先静态,再动态;
先父类,再子类;
先动态字段,再构造函数;
先静态字段,再静态块;
所以,造成上面结果的原因就是,先父类,再子类,在父类的构造函数里调用子类的read初始化后,子类又会进行初始化,list又被重新初始化了。面intVlaue为什么没有初始化?发现非静态成员,如果没有显式初始化赋值的话,相应类型的数据有默认的初始值(int类型为0,引用类型为null)。在类非静态成员初始化过程中,不会对这些值显示赋值,所以上面例子中intValue在父类构造器中赋值后,数据能够保留下来。so, 例子中的bug, 简单的解决办法还可以直接把定义地方的显示赋值去掉就ok了
如果只关注结果或结论,喜欢硬背的话,节省时间,下面可以不用看。 喜欢刨根问底的可以继续看下去,相信会理解的更好!
----------------------------------------------------------------------------------------------------
(三) 结论理解 与 分析
此节分析,上面的那段顺序为什么为是那样的顺序。让我们来分析和理解一下。
1 先静态,再动态。 静态字段是关于类的, 在 ClassLoader加载类的时候就初始化了所以静态的初始化的很早 很早
2 先父类,再子类。 是常识。 但是实现的原理,是在java编译成字节码时, 如果是默认构造函数(如 A() 或不写构造函数时 ),编译器会在编译成的字节码里 会自动加上 super(); 所以就先初始父了。 如果父类构造函数不是默认的,会编译出错,让你手动加上super(a,b)
3 先动态字段,再构造函数; 字节码角度实现上,在字节码中,会把 字段的初始化 放到字节码中的构造函数的最前面。不信来验证一下:
简单类
一个Test中的内部类CC
编译后看字节码:用javap 命令可以看
看 1:位置 会加上 object.init吧 即自动加上super了 说明了 规律2 先父类,再子类 的问题
7: 在初始化函数里 先字段初始化了 "c1"
11: 后又进行真正初始化了 "cccc2"
所以 先动态字段,再构造函数 就很好理解了
4 先静态字段,再静态块; 这个可以根据第3条规律类推了。 从反射上来讲 Class 对象也是个Object对象, static代码块 相当于Class对象的初始化函数,static字段相当于Class对象的字段。 而按3规律的实现上讲,字节码中 可能也是 把static字段的初始化放到static块中最前面了。 此处没有验证
所以实例化过程的 终极规律 就是 如果Class对象没有加载先加载并初始化Class, 再根据Class分配一段实际对象的初始状态的内存(int 字段为 0 object 为null , bool 为false ) 然后执行对象初始化函数 这个对象就产生了 !!!! 按字节码中初始化函数自然执行,最终就是(二)中所说的顺序。
最近,同事遇到一个关于java 初始化的问题,描述如下:
子类构造器中调用super(),然后在父类构造器中调用子类有@overwrite的方法,子类在overwrite的方法中对自己成员赋值,log输出成功赋值,在子类new完,log打印发现部分成员变量值丢失了。
打印log发现list数据丢失了,int值还在。
乍看起来,很奇怪吧? 其实是因为对初始化的一些问题没有理解清楚,导致了数据丢失。初始化问题算是java中比较初级的问题,但也能看出知识点掌握的深不深、牢不牢
(二) 结论
先给出结论,关于对象实例化的顺序,简易描述如下:
先静态,再动态;
先父类,再子类;
先动态字段,再构造函数;
先静态字段,再静态块;
所以,造成上面结果的原因就是,先父类,再子类,在父类的构造函数里调用子类的read初始化后,子类又会进行初始化,list又被重新初始化了。面intVlaue为什么没有初始化?发现非静态成员,如果没有显式初始化赋值的话,相应类型的数据有默认的初始值(int类型为0,引用类型为null)。在类非静态成员初始化过程中,不会对这些值显示赋值,所以上面例子中intValue在父类构造器中赋值后,数据能够保留下来。so, 例子中的bug, 简单的解决办法还可以直接把定义地方的显示赋值去掉就ok了
如果只关注结果或结论,喜欢硬背的话,节省时间,下面可以不用看。 喜欢刨根问底的可以继续看下去,相信会理解的更好!
----------------------------------------------------------------------------------------------------
(三) 结论理解 与 分析
此节分析,上面的那段顺序为什么为是那样的顺序。让我们来分析和理解一下。
1 先静态,再动态。 静态字段是关于类的, 在 ClassLoader加载类的时候就初始化了所以静态的初始化的很早 很早
2 先父类,再子类。 是常识。 但是实现的原理,是在java编译成字节码时, 如果是默认构造函数(如 A() 或不写构造函数时 ),编译器会在编译成的字节码里 会自动加上 super(); 所以就先初始父了。 如果父类构造函数不是默认的,会编译出错,让你手动加上super(a,b)
3 先动态字段,再构造函数; 字节码角度实现上,在字节码中,会把 字段的初始化 放到字节码中的构造函数的最前面。不信来验证一下:
简单类
一个Test中的内部类CC
public static class CC { String c1 = "ccccc"; public CC() { c1 = "cccc2"; } void test() { } }
编译后看字节码:用javap 命令可以看
Compiled from "Test.java" public class Test$CC { java.lang.String c1; public Test$CC(java.lang.String); Code: 0: aload_0 1: invokespecial #10 // Method java/lang/Object."<init>":()V 4: aload_0 5: ldc #13 // String ccccc 7: putfield #15 // Field c1:Ljava/lang/String; 10: aload_0 11: ldc #17 // String cccc2 13: putfield #15 // Field c1:Ljava/lang/String; 16: return void test(); Code: 0: return }
看 1:位置 会加上 object.init吧 即自动加上super了 说明了 规律2 先父类,再子类 的问题
7: 在初始化函数里 先字段初始化了 "c1"
11: 后又进行真正初始化了 "cccc2"
所以 先动态字段,再构造函数 就很好理解了
4 先静态字段,再静态块; 这个可以根据第3条规律类推了。 从反射上来讲 Class 对象也是个Object对象, static代码块 相当于Class对象的初始化函数,static字段相当于Class对象的字段。 而按3规律的实现上讲,字节码中 可能也是 把static字段的初始化放到static块中最前面了。 此处没有验证
所以实例化过程的 终极规律 就是 如果Class对象没有加载先加载并初始化Class, 再根据Class分配一段实际对象的初始状态的内存(int 字段为 0 object 为null , bool 为false ) 然后执行对象初始化函数 这个对象就产生了 !!!! 按字节码中初始化函数自然执行,最终就是(二)中所说的顺序。
相关文章推荐
- java对象实例化过程分析
- Java对象实例化的过程。
- Java基础学习17(子类对象实例化的全过程图解,内存分配)
- [JAVA修炼之路四]-JVM内存模型以及对象实例化过程
- Java 一个对象实例化过程
- 嵌入式软件开发培训笔记——Java第三天(方法重载、对象的构造与初始化过程分析、封装等)
- Java对象创建过程和内存结构分析
- JAVA基础-子类继承父类实例化对象过程
- Java中一个对象的实例化过程
- java学习之路 之 高级类特性-四种权限修饰符、关键字super、子类对象的实例化过程
- Java中的反射(3)——在运行时使用反射分析实例化的对象
- Java知识点整理:第五章:类的声明,构造方法,方法,继承中的构造器,对象实例化过程
- java之面向对象:子类对象的实例化过程详解
- 《对象创建过程中 实例化的顺序》摘自《Thinking in JAVA》
- java之子类对象实例化的全过程
- 深入理解Java对象的创建过程:类的初始化与实例化
- java实例化对象的过程
- 深入理解Java对象的创建过程:类的初始化与实例化
- 深入理解Java对象的创建过程:类的初始化与实例化
- 深入理解Java对象的创建过程:类的初始化与实例化