从Java类初始化,来看代码优化

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.类非静态成员定义时,如果业务逻辑允许,尽量不要对其定义时赋值,这样,类在构造的时候就可以少很多初始化步骤,

加快类的初始化。

时间: 2024-10-09 20:25:07

从Java类初始化,来看代码优化的相关文章

java类初始化

class SuperClass{ static{ System.out.println("super class init!"); } static int superInt = 1; static String superString = "supString"; } class SubClass extends SuperClass{ static{ System.out.println("sub class init!"); } stat

java类初始化顺序

java类初始化顺序 执行顺序如下: 没有继承其他类时: 静态变量 静态初始化块 变量 初始化块 构造器 继承其他类时: 父类--静态变量 父类--静态初始化块 子类--静态变量 子类--静态初始化块 父类--变量 父类--初始化块 父类--构造器 子类--变量 子类--初始化块 子类--构造器 执行顺序图:

静态代码块、构造代码块、构造函数以及Java类初始化顺序

静态代码块:用staitc声明,jvm加载类时执行,仅执行一次构造代码块:类中直接用{}定义,每一次创建对象时执行.执行顺序优先级:静态块,main(),构造块,构造方法. 构造函数 public HelloA(){//构造函数 } 关于构造函数,以下几点要注意:1.对象一建立,就会调用与之相应的构造函数,也就是说,不建立对象,构造函数时不会运行的.2.构造函数的作用是用于给对象进行初始化.3.一个对象建立,构造函数只运行一次,而一般方法可以被该对象调用多次. 构造代码块 {//构造代码块 }

[读书笔记] java类初始化

以下内容来自周志明的<深入理解java虚拟机>: 类初始化阶段是类加载过程的最后一步,前面的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制. 到了初始化阶段,才真正开始执行类中定义的Java程序代码(或者说是字节码). 在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化类变量和其他资源,或者可以从另外一个角度来表达:初始化阶段是执行类构造器<clinit>()方法的过程.

Android(java)学习笔记136:Java类初始化顺序

Java类中初试化的顺序: 由此得出Java普通类初始化顺序结论: 静态变量 静态初始化块 变量 初始化块 构造器 由此得出Java继承类初始化顺序结论: 1 .继承体系的所有静态成员初始化(先父类,后子类) 2 .父类初始化完成(普通成员的初始化-->构造函数的调用) 3 .子类初始化(普通成员-->构造函数) Java初始化顺序如图: 代码演示: class Sample { Sample(String s) { System.out.println(s); } Sample() { Sy

转!!关于java类初始化顺序

原文地址:http://www.cnblogs.com/luckygxf/p/4796955.html 1.没有继承 静态变量->静态初始化块->变量->变量初始化块->构造方法 2.有继承的情况 父类静态变量->父类静态初始化块->子类静态变量->子类静态变量初始化块->父类变量初始化->父类变量初始化块->父类构造方法->子类变量初始化->子类变量初始化块->子类构造方法 --------------------------

Java类初始化顺序经典实例

一.阿里巴巴笔试题: 1 public class T implements Cloneable { 2 public static int k = 0; 3 public static T t1 = new T("t1"); 4 public static T t2 = new T("t2"); 5 public static int i = print("i"); 6 public static int n = 99; 7 8 public

Java类 初始化块

java里初始化一个类的对象,通过初始化快或者构造方法进行数据赋值.与其相关的执行代码有这么几种: 静态初始化块 初始化块 构造方法 静态初始化块 静态初始化块只在类加载时执行一次,同时静态初始化块只能给静态变量赋值,不能初始化普通的成员变量. 非静态初始化块 非静态初始化块在每次初始化实例对象的时候都执行一次,可以给任意变量赋值. 构造方法 在每次初始化实例对象时调用. 重点:执行顺序-> 在加载类时执行一次静态初始化块(之后不再调用). 在每次初始化实例对象时:先执行非静态初始化块,再执行构

java类初始化,使用构造方法

public class test { /** * java类的初步学习: *   学会使用和类名相同的两种构造方法,对公共类方法的调用: */ public static void main(String[] args) { Point point = new Point(100,27); //注意:打印对象的方法 System.out.print(point); //为什么它没有调用toString方法也可以呢? //System.out.print(point.toString()); /