隐藏字段的继承方式

10

在以下代码示例中:

class Parent { 
    int x =5;
    public Integer aMethod(){

        System.out.print("Parent.aMthod ");
        return x;
    }
}

class Child extends Parent {
    int x =6;
    public Integer aMethod(){
        System.out.print("Child.aMthod "); 
        return x;
    }
}


class ZiggyTest2{

    public static void main(String[] args){

        Parent p = new Child();
        Child c = new Child();

        System.out.println(p.x + " " + c.x);

        System.out.println(p.aMethod() + "  \n");
        System.out.println(c.aMethod() + "  \n");
    }   
}

输出结果为:

5 6
Child.aMthod 6  

Child.aMthod 6

当p.x打印6时,为什么p.aMethod()没有打印6?

谢谢。

编辑

糟糕,有一个小笔误:问题应该是“当p.x打印5时,为什么p.aMethod()没有打印5?”- 感谢@thinksteep。


2
我认为你的问题应该是:“当p.x打印5时,为什么p.aMethod()没有打印5?” - kosa
3
语言应禁止变量隐藏;除了引入错误之外,我看不到任何其他用途。它也应该禁止静态方法隐藏。 - toto2
@toto2,也许那样会更好。嵌套作用域已经禁止使用阴影变量(除了类作用域与方法作用域之间的情况)。 - Arjan Tijms
感谢大家的回复。 - ziggy
3个回答

12
在访问类成员字段(实例变量)时,例如 p.x,并没有进行多态解析。换句话说,您将获得在编译时已知的类的结果,而不是在运行时已知的结果。
对于方法调用,情况则不同。它们在运行时调度到引用指向的实际类的对象,即使引用本身具有超类型。(在虚拟机中,这是通过 invokevirtual 操作码实现的,参见例如 http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc6.html#invokevirtual)。

2
在字节码层面上讨论时,获取字段值的字节码不应被省略。它是 getfield(参见 JVM-Spec)。 - A.H.

1

操作总是在对象上进行。在这两种情况下,p.aMethod()c.aMethod(),对象都是子对象,因此在两种情况下都打印了6。当您直接访问变量时,它会读取与左侧关联的变量。


0

因为声明变量不会继承。在类中有两个 x 的副本,一个在父命名空间中,一个在子命名空间中。


9
不完全正确。成员变量会被继承,但它们不具有多态性。 - Oliver Charlesworth
比较 this.x 和 super.x 的结果 - 这两者都可供子类使用。这被称为遮蔽。 - Highland Mark
因此,当子类没有声明自己的版本时,它们会被继承。如果子类声明了自己的版本,则超级版本将被遮蔽而不是覆盖。想想看,这很有趣。 - Mike Braun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接