2010-02-10 138 views
4

给出:继承和类成员

class A 
{ 
    String s = "A"; 
} 

class B extends A 
{ 
    String s = "B"; 
} 

public class C 
{ 
    public static void main(String[] args){ new C().go();} 
    void go() 
    { 
     A a = new B(); 
     System.out.println(a.s); 
    } 
} 

问:

什么是JVM背后的机制,当运行这些代码? a怎么打印回“A”。

+0

除了其他回答之外,请注意,没有向B的s成员使用而不将其向下转换为B的访问,例如, ((B)a).s – 2010-02-10 16:22:30

回答

4

字段引用不受多态性,所以在编译时,编译器引用的字段,因为您的局部变量的类型为A的

换句话说,现场的行为就像是在方法的Java超载行为,而不是Java压倒一切的行为。

+0

谢谢你的回答。如果你可以,我想从你的回答中澄清以下内容:[1]在运行时和编译时,“a”有什么不同。 [2]代码中的哪一点会发生实际的重载机制? – Krolique 2010-02-10 17:11:48

+0

错误,更正:[2] ....是否会出现实际字段“重载”机制? =) – Krolique 2010-02-10 17:22:40

+0

@Krolique,A实际上在编译时没有任何东西(它只是一个定义,它不是执行代码)。当你在类B中定义一个变量s时发生重载。在这一点上,你有两个在两个不同类中具有相同名字的字段。编译器是决定在代码中引用哪一个的编译器。它不是动态的。 – Yishai 2010-02-10 17:38:44

1

这不是多态(标记为)。

Java有virtual methods而不是虚拟成员变量 - 即您不覆盖属性 - 您将其隐藏。

+1

这不是一个属性,它是一个领域。 – 2010-02-10 16:10:07

+0

和一个成员变量。术语并不严格 – Bozho 2010-02-10 16:10:55

+0

谢谢你的回答。我错过了虚拟(继承?)方法和成员之间的细微区别。 – Krolique 2010-02-10 17:13:37

2

您可能期望字段被重写,如方法,基于对象的运行时类型的动态分派。

这不是Java的工作原理。字段没有被覆盖,它们是隐藏的。这意味着类B的对象具有名为“s”的两个字段,但是其中哪些被访问取决于上下文。

至于为什么会这样:重写字段没有任何意义,因为当类型不同时没有任何有用的方法使其工作,并且当类型相同时(如你可以使用超类字段)。就个人而言,我认为它应该只是一个编译器错误。

+0

谢谢你的回答。看看我是否正确掌握了这个概念。上下文隐含了声明类型? 可以说,如果有可能upcast,我做了以下:B b = new A();那么在b.s中应该打印“B”? – Krolique 2010-02-10 17:08:42

+0

既然这是不可能的,争论它“应该”打印什么是没有意义的,但是是的,这是基本的想法。 – 2010-02-10 17:12:25

+0

谢谢,我认为这个说明很多! – Krolique 2010-02-10 23:30:20

0

虽然成员变量是从基类继承的,但它们不是多态调用的(即动态调用不适用于成员变量)。

所以,a.s将引用基类中的成员而不是派生类。

话虽如此,代码并不遵循面向对象的原则。根据业务用例,类的成员需要是私有/保护的(不是公共或默认的),并且您需要提供公共方法来获取和设置成员的值。

+0

谢谢你的回答。在所有正常情况下,我会照你的建议去做。 – Krolique 2010-02-10 17:14:57