Java中的inheritance – 创建子类的对象也会调用超类的构造函数。 为什么呢?

我有一个关于Javainheritance的问题。

我有两个AB类, Binheritance自A:

 public class A { public A() { System.out.println("Hi!"); } } public class B extends A { public B() { System.out.println("Bye!"); } public static void main(String[] args) { B b = new B(); } } 

当我运行程序B时,输出是:

 Hi! Bye! 

问题 :为什么在创建class B对象时调用class A构造函数

我知道Binheritance了A中的所有实例或类变量以及所有方法,在这个意义上,B的对象具有A的所有特征以及B中定义的一些其他特征。但是,我不知道并且没有’我想象当我创建一个B类型的对象时,也会调用A的构造函数。 所以写下这个:

 B b = new B(); 

创建两个对象 – 一个是B类,另一个是A类

这很有趣,

有人可以解释为什么会发生这种情况吗?

它不会创建两个对象,只有一个: B

从其他类inheritance时, 必须在构造函数中调用super()。 如果不这样,编译器将为您插入该调用,您可以清楚地看到。

调用超类构造函数,因为否则对象将保持未初始化状态,可能是子类开发人员不知道的。

在编译器插入超级调用之后,您的子类实际上看起来像这样:

 public class B extends A { public B() { super(); System.out.println("Bye!"); } } 

它不会创建2个对象,它只会创建一个B实例。调用超类构造函数的原因是,正如您所说,B具有A的所有字段,并且这些字段需要初始化。

记住inheritance是基类和子类之间的“是一种”关系,因此每次你有一个子类的实例时,根据定义你也会有一个基类的实例(作为实例的一部分,而不是两个单独的实例)。 要正确初始化基类,将调用构造函数。

另外,考虑如果子类依赖于基类的某些内部状态会发生什么。 您不希望初始化基类的实例吗?

这样做是因为构造函数用于初始化对象。 由于B也是A,它首先调用A的构造函数,然后调用B的构造函数。

作为旁注,您可以使用super(arg1, etc)根据您传递的参数类型选择调用哪个构造函数…但它必须是构造函数中的第一行。

它不会创建两个对象,它只创建一个对象b。 b是B类型和A类型。构造函数基本上说这是构建我需要做的事情。 因此,当您创建一个新的“B”实例时,您正在构建一个既是B()又是A()的对象。 想象一下以下场景:

 class Q { int i; public Q() { // set default value i= 99; } } class Z extends Q { public Z() { } } 

如果没有调用Q WAS的构造函数,我将如何获得其默认值?

如果A初始化其构造函数中的成员而您忘记在派生类中调用super,则A的成员可能处于错误状态。 Java试图阻止你在脚下射击自己。

构造函数包含A的所有初始化。您没有创建两个对象。 您正在创建一个对象,然后运行超类的初始化程序以初始化其成员,然后运行派生类的初始化程序以初始化其成员。

只创建了一个对象,两个承包商都在同一个对象上运行。

原因很简单,因为你知道B有A的所有变量和方法,所以如果A的某个变量需要初始化,那么A的方法可以工作,有人必须初始化它 – 而且某人是A的构造函数。

例如:

 public class A { public A() { x = 1; } private int x; public int getX() { return x; } } public class B extends A { public B() { } public static void main(String[] args) { B b = new B(); System.out.println(b.getX()); // should print 1 } } 

B的创建不会产生额外的A.

但是通过创建B,你创建了一种A,因为B A.

Java / C ++隐式调用A的构造函数。 为什么? 语言设计。 但这样做很好,因为A的构造函数可能包含一些初始化。 并且由于B使用A的所有function和错误,因此可以更好地初始化这些function。

在大多数OOP中,类的构造函数是非常重要的概念

通过提供状态和操作该状态的方法,类允许更容易地维护不变量。 构造函数的作用是使类进入符合那些不变量的状态(或抛出因此禁止使用invliad对象)。 这有点比许多语言中的预期更宽松,因为允许构造函数在其他地方传递自己的’this’引用,但这至少在类的控制之下(因此它可以知道它处于足够稳定和有效的状态为了让世界其他地方可以进入)

inheritance使得这个复杂,因为B是非常真实意义上的A,因此可以调用A提供的任何方法。因此,B的A部分应该有机会在B查看之前初始化自己,因此在B构造函数的实际工作开始之前调用A的构造函数。

当创建新对象(B)时,创建BA对象内部(因为扩展关键字)。 在B类JVM中搜索B类构造函数,但由于扩展关键字,它会转到超类构造函数。 在内部初始化类x值。 但是x是私有的,所以我们可以访问外部类抛出getXxx()方法并获得结果。

当创建子类对象时,内部它不是为超类对象创建的。但是应该为超类成员分配内存。

在java中,当你创建子类的对象时,总是调用父类的构造函数,因为Object类是每个超类的父类,当你调用Object类的构造函数时,那么只创建你的对象而java不支持多重inheritance在类的情况下,如果你扩展任何其他类,那么你的子类和Object类之间的关系是通过Parent类,所以为了调用Object类的构造函数,必须调用Parent类的构造函数。

每个超类都有一个构造函数,层次结构中的每个构造函数在创建子类的对象时运行。

如果没有创建超类对象,则子类如何访问超类非静态方法和变量。

我研究过只能通过对象访问非静态方法和变量。