《Thinking in Java》——静态、非静态成员变量、子句的初始化顺序(含继承)及对象创建过程

xiaoxiao2021-02-28  74

初始化顺序(详细过程可看继承与初始化部分,相当于没有基类的子类)

1.静态成员变量或子句只有在首次new该类对象或者首次访问该类成员变量或方法时被执行一次; 2.非静态成员变量或子句在每次new该类对象时都会初始化; 3.构造器在成员变量和子句初始化之后才执行,而且需要new语句才会被执行; 4.成员变量和子句之间顺序执行; 5.包含main()方法的类,也需要先初始化静态成员变量,再执行main()方法。

所有的static对象和static代码段都会在加载时依程序中的顺序(即,定义类时的书写顺序)而依次初始化。当然,定义为static的东西只会在被初始化一次。

当通过new 类名()产生一个新对象时,顺序为: 1所有.静态成员变量或子句(仅一次) 2.所有非静态成员变量或子句(new几个对象,执行几次) 3.构造器

当通过类名直接访问某类的静态成员变量或者方法时,顺序为: 1.所有静态成员变量或子句(仅一次) 2.访问变量或方法

对象创建过程

假设有一个Dog类

构造器实际上是静态方法,因此,首次创建类型为Dog的对象时,或者Dog类的静态方法、静态域首次被访问时,Java解释器必须查找类的路径,以定位Dog.class文件;然后载入Dog.class文件,有关静态初始化的所有动作被执行。因此,静态初始化只在Class对象首次加载的时候进行一次;当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间;这块存储空间会被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了默认值(对于数字来说是0,对于布尔类型和字符类型也相同),而引用则被设置成了null;执行所有出现在成员变量定义处的初始化动作;执行构造器。

继承与初始化

package thinkinginjava; class Insect { private int i = 9; protected int j; Insect() { System.out.println("i = " + i + ", j = " + j); j = 39; } private static int x1 = printInit("static Insect.x1 initialized"); static int printInit(String s) { System.out.println(s); return 47; } } public class Beetle extends Insect { private int k = printInit("Beetle.k initialized"); public Beetle() { System.out.println("k = " + k); System.out.println("j = " + j); } private static int x2 = printInit("static Beetle.x2 initialized"); public static void main(String[] args) { System.out.println("Beetle constructor"); Beetle b = new Beetle(); } }

结果:

static Insect.x1 initialized static Beetle.x2 initialized Beetle constructor i = 9, j = 0 Beetle.k initialized k = 47 j = 39 加载类(子类→基类→基类的基类……) 在Beetle上运行Java时,所发生的第一件事就是试图访问Beetle.main()(一个static方法),因为类在其static成员首次被访问时加载,于是加载器开始启动并找出Beetle类的编译代码(在名为Beetle.class的文件中)。在对它进行加载的过程中,编译器注意它有一个基类(这是由关键字extends得知的),于是它继续加载。不管你是否打算产生一个该基类的对象,这都要发生。 如果该基类还有其自身的基类,那么第二个基类将会被加载,以此类推。static初始化(根基类→根基类的子类→根基类子类的子类……) 根基类的static初始化先进行,然后是它的子类,以此类推,这种顺序很重要,因为导出类的static初始化可能会依赖于基类成员能否被正确的初始化。设置默认值 类加载完毕后,对象就可以被创建了。对象中所有的基本类型被设置成0,引用被设置为null——这是通过将对象内存设置为二进制零值而一举生成的(在加载类时,我们已经能够得知该对象占有多少内存了,这其中包括基类的非静态成员变量,子类的非静态成员变量,它们都在这块内存中,会被同时设置为默认值)。调用子类构造器时先调用基类构造器 显示或者隐式调用基类的构造器基类构造器完成之后,实例变量按其次序被初始化构造器的其余部分被执行 (当基类还有基类时,会以相同的顺序执行上述三个过程,直至根基类)
转载请注明原文地址: https://www.6miu.com/read-59360.html

最新回复(0)