一个类中,对象构造时的构造过程
顺序如下:
1、变量定义时给出初始值,则先获得初始值。
2、调用构造块
3、调用相应的构造函数
非final成员没有在上述任何地方赋值,则获得相应类型的默认值。
先来看一个类中,初始化时,各个构造方法的调用顺序
下面是一个例子
public class Main { public static void main(String[] args) { Base b = new Base(); System.out.println("Base中baseVal的最终值为:"+b.baseVal); /* baseVal=11 baseVal=12 Base中baseVal的最终值为:12 */ } } class Base { public int baseVal = 10; // ① { // ②构造块 baseVal = 11; System.out.println("baseVal=" + baseVal); } public Base() // ③ { baseVal = 12; System.out.println("baseVal=" + baseVal); } }
一个继承链中,对象构造时的过程
1、java中,子类的构造函数,如果你不显式用super写出来的话,默认会调用父类的默认构造函数。
你可以通过super 显式指定调用父类的哪个构造函数。需要注意的是:这个super调用必须是子类构造函数的第一条语句
下面是例子。
我们不为字段的初始值编号了,而只为初始化块和构造函数编号。
可以发现:构造一个子类,会先去调用父类的整套构造机制(注意:我并没有这样说:构造一个子类,会先去构造一个父类,原因待会解释),父类又会调用父类的父类的构造机制,.......一直带到Object为止。那么,这就会引发一条调用链,过程有点类似递归,只有高层的函数调用完了,底层的函数才会执行完。
public class Main { public static void main(String[] args) { SubClass sub = new SubClass(); /* * console: * ①baseVal=11 ②baseVal=12 ③baseVal=12 sub Val=91 ④baseVal=12 sub Val=92 */ } } class Base { public int baseVal = 10; { baseVal = 11; System.out.println("①baseVal=" + baseVal); } public Base() { baseVal = 12; System.out.println("②baseVal=" + baseVal); } } class SubClass extends Base { public int subVal = 90; { subVal = 91; System.out.println("③baseVal="+baseVal+" sub Val=" + subVal); } public SubClass() { // super() //子类构造函数默认隐式调用父类的默认构造函数 ,当然你也可以显示调用 subVal = 92; System.out.println("④baseVal="+baseVal+" sub Val=" + subVal); } }
子类的构造,会生成一个父类对象吗?
我不知道那些说:构造子类时,会先去构造一个父类对象,他们说的这个过程,到底是怎样一个模型。
这个问题的关键在于:是生成的一个内嵌的父类,还是生成一个独立的父类。
显然,我认为是生成的是内嵌的父类,即子类包含父类的数据,父类并不是独立存在的。
试想一下:如果new一个子类对象,会生成一个独立的父类,那么,对于深层次的继承链。比如10层,new一个最高层子类,岂不是会在内存生成 10个对象,显然是不可以的,不高效的。
那么子类对象在构造时,为什么要调用父类地方构造 函数呢?那是因为,子类要借用父类的构造函数类构造自己。因为子类包含父类的数据。
写在最后的总结
1、java 中的对象都在堆中生成,而引用他们的引用变量则视情况而定。比如一个类对象中有一个String成员,变量名为name,那么name也在堆中。C++中,如果使用new,则对象生成在堆中,如果不用new,一般在栈中。
2、类的成员变量如果不显式初始化,则赋值为默认值。但最好明确地个一个初始值。
3、构造函数可以重载。
4、如果自定义类不给出构造函数,那么会获得一个默认的无参的构造函数。如果手动提供了自定义的构造函数,则系统不会提供默认的无参构造函数,如果你需要无参的构造函数,你应该自己添加。
5、final成员变量必须在new对象时被初始化,包括定义final变量时给初始值,或者在初始化块中,或者在构造函数中。
6、静态构造块的语句会在类第一次被加载时执行,当你使用类时,这个过程就完成了。