构造器与返回类型:
构造器没有返回类型,若将返回值类型(包括void)添加到构造器上,编译不会报错,但此时不再是构造器了,而只是一个与所在类同名的方法而已。
构造器与方法是两个不同的概念:
- 构造器不能像方法一样能被对象引用调用。
- 构造器是创建对象时需执行的代码,由new调用。方法是类或对象具有的行为,由引用调用。
无参数的构造器(资料来源:《Java核心技术卷1(中文第9版)》127页):
如果在编写一个类时没有编写构造器,那么系统就会提供一个无参数的构造器。这个构造器将所有实例域设置为默认值(如果实例域在类中没有被初始化)。
如果类中至少提供了一个构造器,但是没有提供无参数的构造器,则在构造对象时如果没有提供参数就会被视为不合法。
有关构造器与继承关系的问题(构造器的级联调用):
class Animal { public Animal() { System.out.println("我是Animal的构造器!"); } } class Bird extends Animal { public Bird() { System.out.println("我是Bird的构造器!"); } } public class Sample10_6 { public static void main(String[] args) { new Bird(); } }
- 执行new Bird()语句,进入Bird构造器体。
- 调用Animal的构造器,进入Animal构造器体,因为Animal是Bird的父类。
- 调用Object的构造器,进入Object构造器体,因为Object是Animal的父类。
- 执行Object构造器中的代码直到完成,返回Animal构造器。
- 执行Animal构造器中的代码直到完成,返回Bird构造器。
- 执行Bird构造器中的代码直到完成。
如果没有在构造器中明确调用指定的父类或兄弟构造器,编译器会自动将调用父类无参数构造器的代码添加为构造器代码的第一句。
由上可知,由于级联调用,自己编写的调用父类构造器的代码必须位于构造器的第一句,否则编译报错。即在第一句里写上super然后加上一对圆括号,圆括号中放上对应父类构造器需要的参数。所以,如果开发人员需要自己编写,那么编译器就不会再自动添加调用父类(无参数)构造器的代码。
在实际开发中,若不在构造器中编写调用父类构造器的代码,系统只能自动调用父类的无参数构造器;若需要明确调用父类中某个构造器,则必须自己编写代码。
构造器被设计为级联调用的原因:
根据替代性原理,子类对象必须能够替代父类对象,因此在构造子类对象之前,要首先构造一个父类对象,然后在父类对象的基础上进一步构造子类对象。Java的子类对象中都隐含着一个父类对象,子类对象是在父类对象的基础上进一步雕琢完成的。
调用兄弟构造器:
一旦使用了“this(XX)”调用兄弟构造器,在该构造器中编译器将不再自动添加“super();”,即在该构造器中系统将不再自动调用父类的无参数构造器。因为用this(XX)执行到调用的构造器时,会执行构造器中编译器自动为其添加的“super();”或开发人员自己编写的super语句。
单列模式:
class Singleton { private static Singleton singleInstance; public static Singleton getInstance() { if (singleInstance == null) { singleInstance = new Singleton(); } return singleInstance; } private Singleton() { System.out.println("执行单列模式类的构造器!!"); } } public class Sample10_15 { public static void main(String[] args) { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); if (s1 == s2) { System.out.println("两个引用指向同一个对象!"); } else { System.out.println("两个引用指向不同的对象!"); } } } 输出的结果为: 执行单列模式类的构造器!! 两个引用指向同一个对象!虽然获取了两次对象引用,但构造器只执行了一次,说明只创建了一个对象。
两次获取的引用相等,也说明了只有一个对象。
程序的加载:
在Java中,当创建一个对象时总的加载过程如下:
- 首先加载要创建对象的类及其直接父类与间接父类。
- 在类被加载的同时会加载静态成员,主要包括静态成员变量的初始化、静态语句块的执行,在加载时按代码的先后顺序执行。
- 需要的类加载完成后,开始创建对象。首先会加载非静态的成员,主要包括非静态成员变量的初始化、非静态成员块的执行,在加载时按代码的先后顺序执行。
- 最后执行构造器。构造器执行完成,则对象生成。
上面那一段话是《Java开发手册》书上的总结。
而我的总结是:
- 首先加载要创建对象的类及其直接父类与间接父类。
- 在加载类这一步中,先加载对象类的“顶层”类,然后再由“顶层”类加载到下一层的类,……,直到加载到对象的类为止。
- 在上一步中,加载每一个类时,先加载静态成员,这一点和书上的总结一样。
- 需要的类加载完成后,开始创建对象。
- 在创建对象这一步中,先创建“顶层”类的对象,然后再创建下一层类的对象,……,直到所有的对象创建完为止。
- 在上一步中,创建每一个对象时,先加载非静态的成员,然后执行该类的构造器后,才算是创建完了对象。