考虑一下:
class A {
int x =5;
}
class B extends A{
int x =6;
}
public class CovariantTest {
public A getObject() {
return new A();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
class SubCovariantTest extends CovariantTest {
public B getObject(){
return new B();
}
}
据我所知,JVM根据其对象的真实类型选择一种方法。这里的真实类型是SubCovariantTest,它定义了一个覆盖方法getObject。
程序打印5,而不是6.为什么?
答案 0 :(得分:10)
该方法确实是由对象的运行时类型选择的。运行时类型未选择的是整数字段 x
。 x
对象有两个B
副本,一个用于A.x
,另一个用于B.x
。您是静态从A
类中选择字段,因为getObject
返回的对象的编译时类型为A
。可以通过向A
和B
添加方法来验证此事实:
class A {
public String print() {
return "A";
}
}
class B extends A {
public String print() {
return "B";
}
}
并将测试表达式更改为:
System.out.println(c1.getObject().print());
答案 1 :(得分:1)
除非我弄错了,默认情况下方法在java中是虚拟的,所以你要正确地覆盖方法。然而,字段(如“x”)不是虚拟的,无法覆盖。当你在B中声明“int x”时,实际上是在创建一个全新的变量。
多态性对字段不起作用,所以当你尝试在一个被转换为A类型的对象上检索x时,你将获得5,如果该对象被转换为类型B,你将得到6。
答案 2 :(得分:1)
当超级和子类中的字段具有相同的名称时,它被称为“隐藏”。除了问答中提到的问题外,还有其他方面可能会产生微妙的问题:
来自http://java.sun.com/docs/books/tutorial/java/IandI/hidevariables.html
在一个类中,一个具有该字段的字段 与超类中的字段同名 隐藏超类的字段,即使 他们的类型不同。内 子类,超类中的字段 不能简单引用 名称。相反,该领域必须 通过超级访问,这是 将在下一节中介绍。通常 说起来,我们不建议隐藏 字段,因为它使代码很难 读取。
有些编译器会警告不要隐藏变量