Java 为什么我们在声明子类的对象时调用了超类的构造函数?(爪哇)
考虑以下代码:Java 为什么我们在声明子类的对象时调用了超类的构造函数?(爪哇),java,object,constructor,superclass,Java,Object,Constructor,Superclass,考虑以下代码: class Test { Test() { System.out.println("In constructor of Superclass"); } int adds(int n1, int n2) { return(n1+n2); } void print(int sum) { System.out.println("the sums are " + sum); } } c
class Test {
Test() {
System.out.println("In constructor of Superclass");
}
int adds(int n1, int n2) {
return(n1+n2);
}
void print(int sum) {
System.out.println("the sums are " + sum);
}
}
class Test1 extends Test {
Test1(int n1, int n2) {
System.out.println("In constructor of Subclass");
int sum = this.adds(n1,n2);
this.print(sum);
}
public static void main(String[] args) {
Test1 a=new Test1(13,12);
Test c=new Test1(15,14);
}
}
如果我们在超类中有一个构造函数,它将被我们为子类构造的每个对象调用(例如,类Test1
调用Test1(int n1,int n2)
的对象a
,以及它的父对象Test()
)
为什么会发生这种情况
该程序的输出为:
在超类的构造函数中
在子类的构造函数中
总数是25
在超类的构造函数中
在子类的构造函数中
总数是29
这就是Java的工作原理。如果创建子对象,则会(隐式)调用超级构造函数。是。必须先构造超类,然后才能构造派生类,否则派生类中应可用的某些字段无法初始化 请注意: 如果必须显式调用超级类构造函数并向其传递一些参数:
baseClassConstructor(){
super(someParams);
}
然后超级构造函数必须是派生构造函数的第一个方法调用。
例如,这不会编译:
baseClassConstructor(){
foo();
super(someParams); // compilation error
}
子类从它的超类继承字段,并且这些字段必须被构造/初始化(这是构造函数的通常用途:初始化类成员以便实例按要求工作。我们知道有些人,但这些糟糕的构造函数中有更多的功能…)构造函数实现使对象准备好工作的逻辑。对象可以在私有字段中保存状态,因此只有其类的方法才能访问它们。所以,如果您希望子类的实例在调用构造函数后真正准备好工作(即,它的所有功能,包括从基类继承的功能都可以),则必须调用基类的构造函数 这就是系统以这种方式工作的原因
自动调用基类的默认构造函数。如果要更改此设置,必须通过在子类构造函数的第一行中写入
super()
来显式调用基类构造函数。Java类按以下顺序实例化:
(在类加载时)
0静态成员和静态初始值设定项块的初始值设定项,顺序为
声明的内容
(在每个新对象上)
因为它将确保在调用构造函数时,它可以依赖于其超类中所有被初始化的字段
请参见中的3.4.4,将在派生类构造函数之前调用基类构造函数。这是有意义的,因为它保证在执行派生类的构造函数时正确构造基类。这允许您在构造派生类时使用基类中的一些数据。当我们创建子类的对象时,它必须考虑在超类中定义的所有成员函数和成员变量。可能会出现这样的情况:某些成员变量可能在某些超类构造函数中初始化因此,当我们创建一个子类对象时,相应继承树中的所有构造函数都会以自上而下的方式调用。 特别是当变量被定义为受保护时,无论子类是否在同一个包中,它总是可以在子类中访问。现在从子类开始,如果我们调用一个超类函数来打印这个受保护变量的值(可能在超类的构造函数中初始化),我们必须得到正确的初始化值。因此,所有超类构造函数都被调用 Java在内部调用每个构造函数中的super()。因此,每个子类构造函数都使用super()调用它的超类构造函数,因此它们是以自上而下的方式执行的
注意:函数可以被重写,而不是变量 由于您将基类属性继承到派生类中,因此在某些情况下,派生类构造函数可能需要一些基类变量来初始化其变量。所以首先它必须初始化基类变量,然后是派生类变量。这就是为什么Java首先调用基类构造函数,然后调用派生类构造函数
而且在不初始化父类的情况下初始化子类也没有任何意义。中的超类构造函数首先被调用,因为程序中的所有方法首先出现在堆中,编译后存储在堆栈中,由于先调用哪个超类构造函数。简单地说,如果超类具有参数化构造函数,则需要在子类构造函数的第一行显式调用super(params),否则隐式调用所有超类构造函数,直到对象类到达为止。有一个默认的super()调用子类的默认构造函数
//Default constructor of subClass
subClass() {
super();
}
super()由编译器自动添加到每个类构造函数中
正如我们所知,默认构造函数是由编译器自动提供的,但它也会为第一条语句添加super()