为什么不根据对象的运行时类型选择此方法?

时间:2009-12-16 23:54:37

标签: java methods override

考虑一下:

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.为什么?

3 个答案:

答案 0 :(得分:10)

该方法确实是由对象的运行时类型选择的。运行时类型未选择的是整数字段 xx对象有两个B副本,一个用于A.x,另一个用于B.x。您是静态A类中选择字段,因为getObject返回的对象的编译时类型为A 。可以通过向AB添加方法来验证此事实:

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

  

在一个类中,一个具有该字段的字段   与超类中的字段同名   隐藏超类的字段,即使   他们的类型不同。内   子类,超类中的字段   不能简单引用   名称。相反,该领域必须   通过超级访问,这是   将在下一节中介绍。通常   说起来,我们不建议隐藏   字段,因为它使代码很难   读取。

有些编译器会警告不要隐藏变量