Java 中的继承 - 创建子类的对象也会调用超类的构造函数。为什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/488727/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Inheritance in Java - creating an object of the subclass invokes also the constructor of the superclass. Why exactly?
提问by user42155
I have a question about inheritance in Java.
我有一个关于 Java 继承的问题。
I have two classes A
and B
, and class B, inheritsfrom A:
我有两个类A
和B
和类 B,从 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();
}
}
When I run program B, the output is:
当我运行程序 B 时,输出是:
Hi!
Bye!
Question: why the constructorof
class A
is invoked, when I create and object ofclass B
?
问:为什么构造函数的
class A
调用,当我创建和对象的class B
?
I know that B inherits everything from A - all instance or class variables, and all methods, and in this sense an object of B has all characteristics of A plus some other characteristics defined in B. However, I didn't know and didn't imagine that when I create an object of type B, the constructor of A is also invoked. So, writing this:
我知道 B 继承了 A 的所有内容——所有实例或类变量,以及所有方法,从这个意义上说,B 的对象具有 A 的所有特征以及 B 中定义的一些其他特征。但是,我不知道也没有想象一下,当我创建一个类型 B 的对象时,A 的构造函数也被调用了。所以,写这个:
B b = new B();
creates Two objects - one of type B, and one of type A.
创建两个对象 - 一个类型为 B ,一个类型为 A。
This is getting interesting,
这个越来越有意思了
can somebody explain why exactly this happens?
有人可以解释为什么会发生这种情况吗?
回答by Brian Rasmussen
Remember inheritance is an "is a" relationship between the base class and the subclass, thus every time you have an instance of a subclass, by definition you will also have an instance of the base class (as part of the instance, not as two separate instances). To initialize the base class properly the constructor is called.
记住继承是基类和子类之间的“是”关系,因此每次你有一个子类的实例时,根据定义,你也会有一个基类的实例(作为实例的一部分,而不是两个单独的实例)。为了正确初始化基类,调用构造函数。
Additionally, think about what would happen if you subclass depended on some internal state of the base class. Wouldn't you want the instance of the base class to be initialized then?
此外,考虑一下如果子类依赖于基类的某些内部状态会发生什么。那么您不希望基类的实例被初始化吗?
回答by Outlaw Programmer
It doesn't create 2 objects, it only creates one instance of B. The reason the super class constructor is invoked is because, like you said, B has all of the fields of A, and these fields need to be initialized.
它不创建 2 个对象,它只创建 B 的一个实例。调用超类构造函数的原因是,就像你说的,B 具有 A 的所有字段,并且这些字段需要初始化。
回答by Kevin
It doesn't create two objects, only one: B.
它不会创建两个对象,只有一个:B。
When inheriting from another class, you mustcall super() in your constructor. If you don't, the compiler will insert that call for you as you can plainly see.
从另一个类继承时,必须在构造函数中调用 super()。如果你不这样做,编译器会为你插入那个调用,你可以清楚地看到。
The superclass constructors are called because otherwise the object would be left in an uninitialized state, possibly unbeknownst to the developer of the subclass.
调用超类构造函数是因为否则对象将处于未初始化状态,子类的开发人员可能不知道。
Your subclass actually looks like this after the compiler inserts the super call:
在编译器插入 super 调用后,您的子类实际上是这样的:
public class B extends A {
public B() {
super();
System.out.println("Bye!");
}
}
回答by basszero
If A intializes members in it's constructor and you forget to call super in your derived class then the members of A could be in a bad state. Java is trying to stop you from shooting yourself in the foot.
如果 A 在其构造函数中初始化成员,而您忘记在派生类中调用 super ,则 A 的成员可能处于错误状态。Java 试图阻止您用脚射击自己。
回答by Eddie
The constructor contains all of the initialization for A. You are not creating two objects. You are creating one object, then running the initializer for the superclass to initialize its members, and then running the initializer for the deriving class to initialize its members.
构造函数包含 A 的所有初始化。您不是在创建两个对象。您正在创建一个对象,然后运行超类的初始化程序以初始化其成员,然后运行派生类的初始化程序以初始化其成员。
回答by Rob Di Marco
It does not create two objects, it just creates one object b. b is of type B and of type A. A constructor is basically saying here is what you need to do to construct me. So when you are creating a new "B" instance, you are building an object that is both a B() and an A(). Imagine the following scenario:
它不创建两个对象,它只创建一个对象 b。b 是类型 B 和类型 A。构造函数基本上是说这里是你需要做什么来构造我。因此,当您创建一个新的“B”实例时,您正在构建一个既是 B() 又是 A() 的对象。想象以下场景:
class Q {
int i;
public Q() {
// set default value
i= 99;
}
}
class Z extends Q {
public Z() {
}
}
If the constructor for Q WAS NOT called, how would i get its default value?
如果没有调用 Q 的构造函数,我将如何获得它的默认值?
回答by Nir
Only one object is created, both contractors are running on the same object.
只创建一个对象,两个承包商都在同一个对象上运行。
The reason is simple, as you know B has all the variables and methods of A, so if some variable of A needs initializing so methods of A can work someone has to initialize it - and that someone is A's constructor.
原因很简单,正如你所知,B 拥有 A 的所有变量和方法,所以如果 A 的某个变量需要初始化以便 A 的方法可以工作,则必须有人对其进行初始化 - 而有人是 A 的构造函数。
for example:
例如:
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
}
}
回答by Powerlord
This is done because the constructor is used to initialize the object. Since B is also an A, it calls the constructor for A first, then the constructor for B.
这样做是因为构造函数用于初始化对象。由于 B 也是 A,它首先调用 A 的构造函数,然后调用 B 的构造函数。
As a side note, you can use super(arg1, etc)
to choose which constructor of A is called based on the parameter types you pass... but it must be the first line in the constructor.
作为旁注,您可以使用super(arg1, etc)
根据您传递的参数类型来选择调用 A 的哪个构造函数......但它必须是构造函数中的第一行。
回答by Leonidas
The creation of B does not create an extra A.
B 的创建不会创建额外的 A。
But by creating B, you create a kind of A, because B is aA.
但是通过创建 B,你创建了一种 A,因为 B是一个A。
Java/C++ call the constructor of A for your implicitly. Why? Language design. But doing so is fine, because the constructor of A might contain some initializations. And as B uses all the features and bugs of A, these features better be initialized properly.
Java/C++ 为您隐式调用 A 的构造函数。为什么?语言设计。但是这样做很好,因为 A 的构造函数可能包含一些初始化。由于 B 使用了 A 的所有功能和错误,因此最好正确初始化这些功能。
回答by ShuggyCoUk
The constructor of a class is very important concept in most OOP
类的构造函数是大多数 OOP 中非常重要的概念
Classes, by providing state and the means to manipulate that state, allow the easier maintenance of invariants. The constructors role is to get the class into a state that conforms to those invariants (or throws thus forbidding usage of an invliad object). this is somewhat looser than intended in many languages since the constructor is allowed to pass its own 'this' reference elsewhere but this is at least under the control of the class (as such it can know that it is in a sufficiently stable and valid state for it to be accessible to the rest of the world)
类通过提供状态和操作该状态的方法,可以更轻松地维护不变量。构造函数的作用是使类进入符合那些不变量的状态(或抛出从而禁止使用 invliad 对象)。这在许多语言中比预期的要宽松一些,因为允许构造函数在其他地方传递它自己的“this”引用,但这至少在类的控制之下(因此它可以知道它处于足够稳定和有效的状态以便世界其他地方可以访问它)
Inheritance makes this complex since B is-a A in a very real sense and thus can invoke any of the methods provided by A. The parts of B that are A should therefore get their chance to initialize themselves before B gets a look in, thus the constructor for A is called before the real work of the B constructor begins.
继承使这变得复杂,因为 B 是真正意义上的 A,因此可以调用 A 提供的任何方法。因此,作为 A 的 B 部分应该有机会在 B 看到之前初始化自己,因此A 的构造函数在 B 构造函数的实际工作开始之前被调用。