Java类初始化顺序可能引起的bug
最近编程中遇到的问题, 类的成员初始化过程大家都很了解,都是基础知识,但是有些地方很微妙,重新学习
下,来提高代码质量。
先描述下遇到的场景:
子类构造器中调用super(),然后在父类构造器中调用子类有@overwrite的方法,子类在overwrite的方法中对自己成
员赋值,log输出成功赋值,在子类new完,log打印发现部分成员变量值丢失了。
打印log发现list数据丢失了,int值还在,如下:
看了半天感觉还是很奇怪,有点不相信代码的感觉,最后debug发现类成员的初始化影响了特殊情况数据的
丢失(重写赋值)。
下面代码研究下类成员的初始化,有些特殊而微妙的地方需要注意:
执行结果:
结论:
1继承体系的所有静态成员初始化(先父类,后子类)
2父类初始化完成(普通成员的初始化-->构造函数的调用)
3子类初始化(普通成员-->构造函数)
结合第一个有bug场景例子,可以很清晰的看出,父类构造完后会对子类(需要初始化)的成员进行初始化,这个
时候已经赋值的成员list会重新初始化,然后list数据丢失bug就出现了,解决这个问题只要赋值放在子类自己构造器里
(成员初始化后),问题就解决了。
那么问题来了,为什么同样是成员变量的intValue没有数据丢失呢? 继续初始化分析debug,发现非静态成员,
如果没有显式初始化赋值的话,相应类型的数据有默认的初始值(int类型为0,引用类型为null)。在类非静态成员
初始化过程中,不会对这些值显示赋值,所以上面例子中intValue在父类构造器中赋值后,数据能够保留下来。so,例
子中的bug, 简单的解决办法还可以直接把定义地方的显示赋值去掉就ok了。
后话:
1.java类中类是动态加载的,static成员可以在类未被实例化而使用,且对于静态变量在内存中只有一个拷贝(节省存),JVM
只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配。在类初始化时,减少类初始化步骤,对代码优化有一定提
高。
2.类成员的操作尽量要在自己类中调用操作,要尽量复合类设计原则:单一职责。不要产生过多复杂的引用关系,产生bug时
才能够尽快分析出原因。
3.类非静态成员定义时,如果业务逻辑允许,尽量不要对其定义时赋值,这样,类在构造的时候就可以少很多初始化步骤,
加快类的初始化。