【问题标题】:Why isn't this method chosen based on the runtime-type of its object?为什么不根据对象的运行时类型选择此方法?
【发布时间】:2009-12-16 23:54:37
【问题描述】:

考虑一下:

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

【问题讨论】:

    标签: java methods overriding


    【解决方案1】:

    该方法确实是由对象的运行时类型选择的。运行时类型没有选择的是整数 field xB 对象存在两份x,一份用于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());
    

    【讨论】:

    • 你在解释上比我做得好得多...实际上这个词有点棘手...
    【解决方案2】:

    除非我弄错了,默认情况下,Java 中的方法是虚拟的,因此您正确地覆盖了该方法。然而,字段(如“x”)不是虚拟的,不能被覆盖。当你在 B 中声明“int x”时,你实际上是在创建一个全新的变量。

    多态性不会对字段生效,因此当您尝试在转换为类型 A 的对象上检索 x 时,您将获得 5,如果将对象转换为类型 B,您将获得 6。

    【讨论】:

      【解决方案3】:

      当超类和子类中的字段具有相同名称时,称为“隐藏”。除了问答中提到的问题外,还有其他方面可能会引起微妙的问题:

      来自http://java.sun.com/docs/books/tutorial/java/IandI/hidevariables.html

      在一个类中,一个具有 与超类中的字段同名 隐藏超类的字段,即使 它们的类型不同。内 子类,超类中的字段 不能被其简单引用 姓名。相反,该字段必须是 通过 super 访问,即 在下一节中介绍。一般来说 说起来,我们不建议隐藏 字段,因为它使代码难以 阅读。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-21
        • 2020-08-07
        • 2010-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多