英文:
Strange infinite loop in java method overriding
问题
在尝试不同的方法重写的排列组合时,我遇到了一个奇怪的无限循环。在超类的修改器方法中从一个被重写的超类方法调用时,程序进入了无限循环。我使用的代码如下:
class A {
private int x = 10;
public void show() {
System.out.println("Inside A's show showing private X: " + x);
}
public void change(int num) {
this.x = num;
// show(); Line 1
this.show(); // Line 2
// 无论是使用Line 1还是Line 2进行交替使用,仍然会产生相同的无限循环。
}
}
class B extends A {
public void show() {
System.out.println("Inside B's show cant show private X:");
// change(8); Line 3
super.change(8); // Line 4
// 无论是使用Line 3还是Line 4进行交替使用,仍然会产生相同的无限循环。
}
}
public class Main
{
public static void main(String[] args) {
B b = new B();
b.show();
}
}
输出为:
Inside B's show cant show private X:
Inside B's show cant show private X:
Inside B's show cant show private X:
Inside B's show cant show private X:
Inside B's show cant show private X:
Inside B's show cant show private X:
Inside B's show cant show private X:
... 很多次,然后
at A.change(Main.java:9)
at B.show(Main.java:17)
at A.change(Main.java:9)
at B.show(Main.java:17)
at A.change(Main.java:9)
at B.show(Main.java:17)
at A.change(Main.java:9)
at B.show(Main.java:17)
at A.change(Main.java:9)
at B.show(Main.java:17)
... 很多次
是什么导致该程序进入这个无限循环,并且如何避免这种情况?
英文:
While trying out different permutations and combinations of method overriding, I encountered a strange infinite loop. While calling an overridden method of the superclass from a mutator method in the superclass, the program goes into an infinite loop. The code which I used is as follows:
class A {
private int x = 10;
public void show() {
System.out.println("Inside A's show showing private X: " + x);
}
public void change(int num) {
this.x = num;
// show(); Line 1
this.show(); // Line 2
// Line 1 and Line 2 on using interchangeably still yields the same infinite loop.
}
}
class B extends A {
public void show() {
System.out.println("Inside B's show cant show private X:");
// change(8); Line 3
super.change(8); // Line 4
// Line 3 and Line 4 on using interchangeably still yields the same infinite loop.
}
}
public class Main
{
public static void main(String[] args) {
B b = new B();
b.show();
}
}
The output is:
Inside B's show cant show private X:
Inside B's show cant show private X:
Inside B's show cant show private X:
Inside B's show cant show private X:
Inside B's show cant show private X:
Inside B's show cant show private X:
Inside B's show cant show private X:
... lots of times and then
at A.change(Main.java:9)
at B.show(Main.java:17)
at A.change(Main.java:9)
at B.show(Main.java:17)
at A.change(Main.java:9)
at B.show(Main.java:17)
at A.change(Main.java:9)
at B.show(Main.java:17)
at A.change(Main.java:9)
at B.show(Main.java:17)
... lots of times
What is causing this program to go into this infinite loop and how can it be avoided?
答案1
得分: 1
在你的 A
类中,你调用了:this.show()
,由于 this
表示 '这个对象',这将调用 '这个对象的 show() 实现',鉴于 '这个对象' 实际上是 B 的一个实例,'show() 的实现' 是在 B.java
中定义的,从而导致无限循环。注意,show();
只是 this.show();
的语法糖 - 难怪这两行会做相同的事情 - 这两行的意思是相同的。
听起来你的意图不是调用 '这个对象的 show() 方法的实现',而是:'在这个文件中定义的 show() 方法'。
在 Java 中你不能这样做。
你无法编写任何东西(既不是 this
,也不是 super
,也没有其他任何东西)来表示:我想要这个显式的实现。
当然,你可以通过以下方式解决这个问题:
public class A {
public void show() {
showImpl();
}
private static void showImpl() {
// 这个方法是静态的。
// 这意味着它完全不参与继承。
System.out.println("Inside A's show showing private X: " + x);
}
public void change(int num) {
this.x = num;
showImpl();
}
}
现在你已经解决了这个问题。对 showImpl
的调用将会准确地进入同一文件中的 showImpl
实现,这是有保障的,因为静态方法不会进行方法的动态查找。
英文:
In your A
class, you call: this.show()
, and as this
means 'this object', that will call 'this object's show() implementation', and given that 'this object' is in fact an instance of B, the 'implementation of show()' is the one defined in B.java
, thus causing the infinite loop. Note that show();
is just syntax sugar for this.show();
- no wonder then that both lines would do the same thing - both lines mean the same thing.
It sounds like your intent is not to call this object's implementation of the show() method, but: the show() method defined in this very file.
You cannot do that in java.
There is nothing you can write (not this
, and not super
, and nothing else either) to say: I want this explicit implementation.
You can work around this, of course:
public class A {
public void show() {
showImpl();
}
private static void showImpl() {
// this method is static.
// that means it has opted out, entirely, of inheritance.
System.out.println("Inside A's show showing private X: " + x);
}
public void change(int num) {
this.x = num;
showImpl();
}
}
Now you've fixed the problem. That call to showImpl will go to that exact implementation of showImpl in the same file, guaranteed, every time, because static methods don't 'do' dynamic lookup of the method.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论