Java构造函数继承:调用基类构造函数为何仍能构建派生类实例
你的理解完全正确!在Java里,不管调用派生类(子类)的哪个构造函数,最终一定会触发基类(父类)构造函数的执行——要么是你显式在子类构造第一行写super(...)指定调用的父类构造,要么是编译器自动帮你插入无参的super()(前提是父类存在无参构造,不然编译直接报错)。
很多人会疑惑:既然先跑了父类的构造,那最终得到的到底是父类实例还是子类实例?其实答案很明确:你得到的仍然是完整的子类实例,父类构造函数只是负责初始化对象里「继承自父类」的那部分内容而已,整个构建流程是分阶段的:
第一步:初始化父类部分
当你调用子类构造函数时,JVM会先跳转到父类的构造函数,完成父类成员变量的赋值、父类构造里的逻辑代码。这一步是为了保证子类继承来的所有属性都处于合法的初始状态,毕竟子类随时可能用到这些父类成员。第二步:初始化子类特有部分
等父类的构造逻辑跑完,JVM会回到子类构造函数,先初始化子类自己的成员变量,再执行子类构造函数里的业务代码。
用一段简单的代码就能看清楚这个过程:
class Animal { protected String type = "动物"; public Animal() { System.out.println("Animal构造函数执行,type = " + type); } } class Dog extends Animal { private String name = "旺财"; public Dog() { // 编译器自动帮我们加了super()在这里 System.out.println("Dog构造函数执行,name = " + name); } public static void main(String[] args) { Dog dog = new Dog(); System.out.println("实例类型:" + dog.getClass()); System.out.println("子类特有属性:" + dog.name); System.out.println("继承自父类的属性:" + dog.type); } }
运行这段代码的输出是:
Animal构造函数执行,type = 动物
Dog构造函数执行,name = 旺财
实例类型:class Dog
子类特有属性:旺财
继承自父类的属性:动物
你看,虽然先执行了父类构造,但最终的实例明确是Dog类型,既能访问子类自己的name,也能访问继承来的type——这说明整个对象是完整的子类实例,只是父类部分先被初始化了而已。
简单来说,Java的继承就像“搭积木”:父类是底层的积木块,子类是在它上面叠加的新积木。要搭好子类这个整体,必须先把底层的父类积木搭稳,再往上加子类的部分。
内容的提问来源于stack exchange,提问作者Saurabh

