构造函数中的多态方法 (Java)
类A
在构造函数中调用公共方法f()
。 B 类用它自己的实现重写方法f()
。
假设您实例化对象B
..对象B
的方法f()
将在对象A
的构造函数中调用>,尽管对象 B
尚未完全初始化。
谁能解释这种行为?
编辑:是的,不推荐这样做..但我不明白为什么Java没有调用f()< /code> 实现基类
A
,而不是“延伸”到派生类 B
的 f()
实现。
代码:
class A {
A() {
System.out.println("A: constructor");
f();
}
public void f() {
System.out.println("A: f()");
}
}
class B extends A {
int x = 10;
B() {
System.out.println("B: constructor");
}
@Override
public void f() {
System.out.println("B: f()");
this.x++;
System.out.println("B: x = " + x);
}
}
public class PolyMethodConst {
public static void main(String[] args) {
new B();
}
}
输出:
A: constructor
B: f()
B: x = 1
B: constructor
Class A
calls the public method f()
in the Constructor. Class B overrides method f()
with its own implementation.
Suppose you intantiate Object B
.. method f()
of Object B
would be called in the Constructor of Object A
, although Object B
is not fully initialized.
Can anyone explain this behavior?
EDIT: Yes, it's not recommended practice.. yet i don't understand why Java is not calling the f()
implementation of the base-Class A
instead of "reaching out" to the f()
implementation of the derived Class B
.
Code:
class A {
A() {
System.out.println("A: constructor");
f();
}
public void f() {
System.out.println("A: f()");
}
}
class B extends A {
int x = 10;
B() {
System.out.println("B: constructor");
}
@Override
public void f() {
System.out.println("B: f()");
this.x++;
System.out.println("B: x = " + x);
}
}
public class PolyMethodConst {
public static void main(String[] args) {
new B();
}
}
Output:
A: constructor
B: f()
B: x = 1
B: constructor
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你是对的,这就是它的工作原理。不过,不建议这样做,因为从您的类继承的人可能会无意中破坏它。
You're correct, that is the way it works. It's not recommended practice though, because somebody who inherits from your class can unintentionally break it.
每当创建子类的实例时,都会首先调用超类构造函数(隐式
super()
)。因此它打印出f()
is invoked next,并且由于子类重写了超类方法,因此调用了子类f()
。所以你会看到现在,子类还没有初始化(super()仍在执行),所以
x
默认值为0
,因为是int
类型的默认值。因为您递增了它 (this.x++;
),所以它变为1
现在,超类构造函数已完成并在子类构造函数处恢复,因此
实例变量现在设置为您指定的值(与对应于类型的默认值(
0
表示数字,false
表示boolean
和null
代码>供参考))注意:如果您现在在新创建的对象上打印
x
的值,它将是10
因为这是一个不好的做法,静态如果您尝试执行此操作,代码分析工具(PMD、FINdBugs 等)会向您发出警告。
Whenever you create an instance of the subclass, the super classes constructor is invoked first (implicit
super()
). So it printsf()
is invoked next and since subclass overrides the superclass method, the subclassf()
is invoked. So you will seeNow, the subclass is not initialized yet (still super() is executing) so
x
default's to the value0
because that is the default value for typeint
. Because you incremented it (this.x++;
) it becomes1
Now, the superclass constructor is complete and resumes at the subclasses constructor and hence
The instance variables are now set to the values you have specified (against the default values that correspondt to the type (
0
for numerics,false
forboolean
andnull
for references))NOTE: If you now print the value of
x
on the newly created object, it will be10
Since this is a bad practice, the static code analysis tools (PMD, FIndBugs etc) warn you if you try to do this.
我只会提供一个链接,因为我对这个主题不太了解。请参阅此处了解有关构造函数调用顺序的教程。
该页面末尾与您所描述的情况相关的最突出的引述如下:
因此,正如您在示例中所示,基类被初始化,然后以下每个类被初始化,最后成员变量被初始化。
但正如比尔所提到的,这不是一个好的做法。遵循比尔所说的。他的名气比我大。
编辑:有关更完整的答案,请参阅此 Jon Skeet 答案。此答案中的链接已损坏,并且据我所知只能找到 JLS 的 pdf 副本。 这里是 .pdf 格式的 JLS 副本格式。相关章节为第 8.8.7.1 节。该答案中有关于构造函数调用顺序的解释。
I'll just provide a link, since I'm not very well-informed on the subject. See here for a tutorial that talks about the invocation order of constructors.
The most prominent quote at the end of the page related to the situation you describe is the following:
So, as you've shown in your example, the base-class is initialised, then each of the following classes is instatiated and finally the member variables are initialised.
But as Bill as mentioned, this is not a good practice. Follow what Bill says. He has more rep than me.
EDIT: For a more complete answer, see this Jon Skeet answer. The link in this answer is broken, and only a pdf copy of the JLS can be found AFAIK. Here is a copy of the JLS in .pdf format. The relevant section is Section 8.8.7.1. There is an explanation of what the constructor invocation order is in that answer.
当
new B()
时,A的构造函数被隐式调用或通过super()
调用。虽然它是在 A 类中定义的,但实际上当前的类是 B。尝试将以下调试信息添加到
A
的构造函数和函数中。在您的情况下,A类中的函数f()已被B类覆盖,因此A()中的函数将调用B()的实现。然而,如果f()是私有方法并且不能被B覆盖,则Af()将以更高的优先级被调用。
但正如其他人评论的那样,这不是一个好的做法。
When
new B()
, A's Constructor is called implicitly or called viasuper()
. Although it is defined in Class A, actually the current class is B.Try add the below debug info into
A
's constructor and functions.In your case, the function f() in Class A has been overriden by Class B, so the function in A() will call B()'s implementation. However, if the f() is a private method and can not be override by B, the A.f() will be called with higher priorities.
But as others commented, it's not a good practice.