java 复习类的实例化顺序

复习一下,这次复习比较详细。

 

记得之前写过这样一篇文章:

think in java 我对上次对象初始化过程的实验

这次重新写个例子复习一遍,希望能测试得更加详细。

一、一些基础概念

(1)虚拟机在首次加载Java类时,会对静态初始化块、静态成员变量、静态方法进行一次初始化。

(2)只有在调用new方法时才会创建类的实例。

(3)类实例的创建过程:按照父子继承关系进行初始化,首先执行父类的初始化块部分,然后是父类的构造方法;再执行本类继承的子类的初始化块,最后是子类的构造方法。

(4)类实例销毁的时候,首先销毁子类部分,再销毁父类部分。(这一点暂时不验证,因为要不停创建对象来吸引GC销毁堆中的对象,才能通过finalize()方法看出来,我不想弄得太复杂了(其实就是懒))

二、无继承下对象初始化的过程

1.直接调用static方法

child.java

结果为:

这说明,如果直接调用类中的静态方法,首先初始化静态成员变量b,然后初始化静态代码块,接着直接调用子类静态方法1。

在此期间child类没有被实例化,所以不会初始化成员变量a,同时也不会运行构造函数。这也说明了为什么静态方法中不能有非静态的成员变量出现:

非静态成员是依赖于对象存在的,对象必须实例化之后,其变量才会在内存中存在。既然没有对象被实例化,那么其非静态成员就不会存在。所以在静态方法中,不能直接访问非静态成员(包括方法和变量)。

总结一下:

如果直接调用static方法,初始化顺序为:静态成员变量->static块->调用方法,没有类被实例化。

2.直接使用static成员变量

和直接调用static方法很像。

child.java

结果为:

总结一下:

如果直接使用static变量,初始化顺序为:静态成员变量->static块->使用static变量,没有类被实例化。

3.正常初始化

child.java

结果为:

这说明,如果正常创建对象,首先初始化静态成员变量b,接着初始化静态代码块,之后初始化非静态成员变量a,然后初始化非静态代码块,最后调用了构造方法。在此期间child类被实例化。

总结一下:

如果正常创建对象,初始化顺序为:静态成员变量->static块->非静态成员变量->非静态代码块->调用构造方法。

二、有继承下对象初始化的过程

1.直接调用子类的static方法

parent.java

child.java

运行结果为:

这说明,如果直接调用子类中的静态方法,首先初始化父类静态成员变量b,再初始化父类静态代码块,接着初始化子类静态成员变量b,然后初始化子类静态代码块,最后调用子类中的静态方法。

总结一下:

如果直接调用static方法,初始化顺序为从父类到子类:父类静态成员变量->父类static块->子类静态成员变量->子类static块,没有类被实例化。

2.直接使用子类的static成员变量

child.java

结果为:

这说明,如果直接使用子类中的静态成员变量,首先初始化父类静态成员变量b,再初始化父类静态代码块,接着初始化子类静态成员变量b,然后初始化子类静态代码块,最后使用子类中的静态成员变量。

总结一下:

如果直接使用子类中的static变量,初始化顺序为从父类到子类:父类静态成员变量->父类static块->子类静态成员变量->子类static块,没有类被实例化。

3.正常初始化子类

child.java

结果为:

这说明,如果正常初始化子类,首先处理静态部分,从父类到子类:初始化父类静态成员变量b,接着初始化父类静态代码块,之后初始化子类非静态成员变量a,然后初始化子类非静态代码块。

处理完静态部分之后,再次从父类到子类:首先初始化父类非静态成员变量a,接着初始化父类非静态代码块,之后调用父类的构造方法,然后初始化子类非静态成员变量a,再之后初始化子类非静态代码块,再然后调用子类的构造方法。

总结一下:

如果如果正常初始化子类,初始化顺序为先静态后非静态,从父类到子类:父类静态成员变量->父类静态代码块->子类静态成员变量->子类静态代码块->父类非静态成员变量->父类非静态代码块->调用父类构造方法->子类非静态成员变量->子类非静态代码块->调用子类构造方法。

三、总结

复习一下。

发表评论

电子邮件地址不会被公开。 必填项已用*标注