java对象创建过程与初始化顺序
单个类,不含继承
1 假设有个名为Dog的类,当首次创建型为Dog的对象时(构造器可以看成静态方法),或者Dog类的静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
然后载入Dog.class(这将创建一个Class对象),有关静态初始化的动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。
2 当你用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。
3 这块存储空间会被清零,这就自动地将Dog中的所有基本类型数据设置成了默认值(对数字来说就是0,对布尔型和字符型也相同),而引用则被置成了null
4执行所有出现于字段定义处的初始化动作,变量定义的先后顺序决定了初始化的顺序
5执行构造器。
存在继承关系的初始化
from:
1.分配空间。要注意的是,分配空间不光是分配子类的空间,子类对象中包含的父类对象所需要的空间,一样在这一步统一分配。在分配的空间的时候,会把所有的属性设置为默认值。
2.递归的构造父类对象。
3.初始化本类属性。
4.调用本类的构造方法。
class A{ int valueA = 100; public A(){ valueA = 150; }}class B extends A { int valueB = 200; public B(){ valueB= 250; }}public calss TestInherit{ public static void main(Stirng []){ B b = new B(); }}
创建过程如下:
我们在main方法中创建了一个b对象,创建的过程如下:
1.分配空间。在分配空间时,会把B、A这两个对象的空间一次性都分配完毕,然后将这两个对象的属性都设置为默认值,这样,valueA、valueB这两个属性都被设置为0。
2.递归构造B对象的父类对象。这里,要构造的就是A类对象。
3.初始化B的属性。即把valueB赋值为200。
4.调用B的构造方法。
其中第2步,创建A类对象,不需要再重新分配空间,需要一下几步:
2.1 递归的构造A类对象的父类对象。创建的步骤与创建A类对象同理。此例中以为A没有任何的父类,没有任何的输出。
2.2 初始化A类属性。把valueA 赋值为100.
2.3 调用A类的构造方法。
总结一下,创建B类对象的步骤一共有5步
1.分配空间
2.初始化A类属性。
3.调用A类的构造方法.
4.初始化B的属性。
5.调用B的构造方法。
另外一个例子
/**父类*/package test;public class Father { static { System.out.println("父类静态初始化块");} { System.out.println("父类初始化块"); } private static int b = 1; public Father() { System.out.println("调用了父类无参构造器"); } public Father(int b) { this.b = b; System.out.println("调用父类的有参构造器"); }}/**子类*/package test;public class Son extends Father { static { System.out.println("子类静态初始化块"); } { System.out.println("子类初始化块"); } private static int a =1; public Son() { System.out.println("调用子类的构造器"); } public Son(int a){ this.a=a; System.out.println("调用子类的有参构造器"); }}package test;public class Test { public static void main(String[] args) { Son son = new Son(); }}
打印语句:
父类静态初始化块
子类静态初始化块
父类初始化块
调用了父类无参构造器
子类初始化块
调用子类的构造器
如果构造器中调用了其他函数
package extend;public class A { public A(){ draw(); } public void draw(){ System.out.println("调用了父类的draw方法"); }}package extend;public class B extends A{ public int i = 1; public B(int i){ this.i=i; } public void draw(){ System.out.println("调用的子类的方法"); System.out.println("i 等于:"+i); } public static void main(String[] args) { B b = new B(5); }}
输出
i 等于:0
调用的子类的方法
原因:在调用父类的构造函数时,里面的draw调用的是子类的!而此时子类中i被初始化为0