我试图理解
为什么this()和super()不能一起使用?
我已经在stackoverflow上阅读了很多相关的讨论,并了解了许多事情。但我只有一个困惑是。
在构造函数中调用this()隐式调用super()
考虑这段代码..
class Top
{
int z;
Top()
{
System.out.println("Top default constructor");
}
}
class A extends Top
{
int x;
A(int num)
{
x=num;
System.out.println("A parameterized constructor");
}
A()
{
this(5);
System.out.println("A default constructor");
}
public static void main(String arg[])
{
new A();
}
}
和OUTPUT是:
顶级默认构造函数
参数化构造函数
默认构造函数
我没想到输出“ Top default constructor ”中的第一行,因为没有super()调用,隐式或显式。
所以可能有一些我误解的东西。请解释一下。
答案 0 :(得分:8)
在构造函数中调用this()是否隐式调用super()?
在构造函数中调用this()
将调用该类的零参数构造函数。如果该类的zero-args构造函数没有对super(...)
的显式调用,那么是的,将会对zero-args super()
构造函数进行隐式调用。如果你的类中的零参数构造函数显式调用了其他一些super
签名,那么当然这样做了。
一般来说,对于构造函数来说都是如此。在A
课程中,由于您的A(int)
构造函数未对this()
或 super()
进行任何调用,因此隐式super()
完了。
我没想到输出“Top default constructor”的第一行,因为没有
super()
隐式或显式调用。
是的,有一个隐含的。 : - )
基本规则是:某些基类构造函数必须在派生类运行的代码之前运行。这就是为什么调用this(...)
或super(...)
必须是构造函数中第一个的东西。如果构造函数没有显式调用super(...)
,则始终会对super()
进行隐式调用(没有args)。
答案 1 :(得分:2)
在构造函数内调用this()
会调用同一个类的另一个构造函数。另一个构造函数会调用super()
构造函数(隐式或显式),这就是为什么你不能在同一个构造函数中调用this()
和super()
,因为这会导致两个{ {1}}被调用的构造函数。
请注意,每当我写super()
或this()
时,我并不一定意味着调用无参数构造函数(除super()
的隐式调用外,该函数始终是参数超级类的构造函数,由Joeblade评论)。两个调用都可以有参数。
在您的代码示例中,super()
构造函数调用A()
构造函数(这是A(int)
所做的),它隐式调用this(5)
(无参数)构造函数。
答案 2 :(得分:2)
this(5)
调用A(int num)
隐式调用super()
。
答案 3 :(得分:1)
在Creation of New Class Instances的Java语言规范部分对此进行了解释,重点是以粗体标记的超类构造函数:
在作为结果返回对新创建的对象的引用之前,处理指示的构造函数以使用以下过程初始化新对象:
将构造函数的参数分配给此构造函数调用的新创建的参数变量。
如果此构造函数以同一个类中的另一个构造函数的显式构造函数调用(第8.8.7.1节)开头(使用此方法),则使用这五个相同步骤计算参数并以递归方式处理该构造函数调用。如果该构造函数调用突然完成,则此过程突然完成,原因相同;否则,继续步骤5.
此构造函数不以同一类中另一个构造函数的显式构造函数调用开头(使用此方法)。 如果此构造函数用于Object以外的类,则此构造函数将以超类构造函数的显式或隐式调用开始(使用super)。使用这五个相同的步骤评估参数并递归处理超类构造函数调用。如果该构造函数调用突然完成,则此过程突然完成,原因相同。否则,请继续执行步骤4.
为此类执行实例初始值设定项和实例变量初始值设定项,将实例变量初始值设定项的值按从左到右的顺序分配给相应的实例变量,在这些顺序中它们以文本方式出现在源代码中类。如果执行任何这些初始值设定项导致异常,则不会处理其他初始化程序,并且此过程会突然完成同样的异常。否则,请继续步骤5.
- 醇>
执行此构造函数的其余部分。如果执行突然完成,则此过程突然完成,原因相同。否则,此过程正常完成。
因此,在您的情况下,当使用A(int num)
调用构造函数this(5)
时,步骤3指示它隐式调用超类构造函数,递归地应用相同的过程。
请注意,您可以通过调试构造函数调用的顺序来执行该过程。