多态性没有按预期工作,为什么?
Polymorphism doesn't work as expected, why?
我的 java 程序中有这 2 个 classes:
public class A {
private final static A five = new A(5);
public final int x;
public A(int x) {
this.x = x;
}
public boolean equals(Object o) {
return x == ((A) o).x;
}
public String toString() {
return equals(five) ? "five" : (x + "");
}
}
public class B extends A {
public final int x;
public B(int x) {
super(x);
this.x = x + 1;
}
public boolean equals(A o) {
return x == o.x;
}
public String toString() {
return "B: " + super.toString();
}
}
现在我主要在做这两个简单的动作:
public static void main(String[] args) {
System.out.println(new A(5));
System.out.println(new B(5));
}
关于第一行,如我所料,它将创建一个 A 对象 -> 转到 A 的 toString
函数 -> 为 equals
函数获取 True
,最后打印"five".
关于B,我预想的和实际发生的不一样...
我认为它将转到 B 的构造函数 -> 转到 A 构造函数并将数字 5 分配给 x
-> return 给 B 构造函数并将数字 6 分配给 B 的 x
-> 去到 B 的 toString
方法并打印 "B: " (直到这一点我是对的)-> 转到 A 的 toString
-> 转到 B 的 equals
因为对象类型是 B 和这就是你所看到的有关方法激活的内容(* 这是我错的地方)-> return False
因为 B 中的 x
是 6 -> 打印数字 5 因为我们在A 的 toString
.
相反,在调用 A class toString
而不是转到 B equals
方法的部分,它停留在 A 中并激活 A equals
...
我不知道为什么会这样,我只知道激活的方法是由对象类型决定的。
希望有人能向我解释这里有什么不同...谢谢!
正如给出的评论所解释的那样,我没有重写函数,我用方法的全新签名重载了函数。
为了扩展您的答案,供未来的读者使用:
在 A.toString()
中调用 this.equals(five)
,其中 five
的类型为 A
。
在 A 的上下文中,匹配 A
的唯一 equals()
方法是 A.equals(Object o)
。这就是 JVM 调用的方法。
如果有一个覆盖方法 B.equals(Object o)
那么这将被调用。有一个更窄类型的 B.equals()
方法是不够的。
您可以通过提供 A.equals(A a)
方法或扩展 B.equals()
的范围以采用 Object
.
来获得您期望的行为
一些注意事项:
- 仅用几行代码,您就在这里创建了一些非常复杂的内容。我希望这只是为了实验:真正的代码应该更简单。
- 如果您要实施
equals()
使其接受 Object
,那么您将覆盖标准方法。
我的 java 程序中有这 2 个 classes:
public class A {
private final static A five = new A(5);
public final int x;
public A(int x) {
this.x = x;
}
public boolean equals(Object o) {
return x == ((A) o).x;
}
public String toString() {
return equals(five) ? "five" : (x + "");
}
}
public class B extends A {
public final int x;
public B(int x) {
super(x);
this.x = x + 1;
}
public boolean equals(A o) {
return x == o.x;
}
public String toString() {
return "B: " + super.toString();
}
}
现在我主要在做这两个简单的动作:
public static void main(String[] args) {
System.out.println(new A(5));
System.out.println(new B(5));
}
关于第一行,如我所料,它将创建一个 A 对象 -> 转到 A 的 toString
函数 -> 为 equals
函数获取 True
,最后打印"five".
关于B,我预想的和实际发生的不一样...
我认为它将转到 B 的构造函数 -> 转到 A 构造函数并将数字 5 分配给 x
-> return 给 B 构造函数并将数字 6 分配给 B 的 x
-> 去到 B 的 toString
方法并打印 "B: " (直到这一点我是对的)-> 转到 A 的 toString
-> 转到 B 的 equals
因为对象类型是 B 和这就是你所看到的有关方法激活的内容(* 这是我错的地方)-> return False
因为 B 中的 x
是 6 -> 打印数字 5 因为我们在A 的 toString
.
相反,在调用 A class toString
而不是转到 B equals
方法的部分,它停留在 A 中并激活 A equals
...
我不知道为什么会这样,我只知道激活的方法是由对象类型决定的。
希望有人能向我解释这里有什么不同...谢谢!
正如给出的评论所解释的那样,我没有重写函数,我用方法的全新签名重载了函数。
为了扩展您的答案,供未来的读者使用:
在 A.toString()
中调用 this.equals(five)
,其中 five
的类型为 A
。
在 A 的上下文中,匹配 A
的唯一 equals()
方法是 A.equals(Object o)
。这就是 JVM 调用的方法。
如果有一个覆盖方法 B.equals(Object o)
那么这将被调用。有一个更窄类型的 B.equals()
方法是不够的。
您可以通过提供 A.equals(A a)
方法或扩展 B.equals()
的范围以采用 Object
.
一些注意事项:
- 仅用几行代码,您就在这里创建了一些非常复杂的内容。我希望这只是为了实验:真正的代码应该更简单。
- 如果您要实施
equals()
使其接受Object
,那么您将覆盖标准方法。