在参加SCJP 6考试时,我在考试中遇到了这个问题:
class A{
private static String staticProperty = " a ";
String getStaticProperty() { return staticProperty; }
}
class B extends A {
private static String staticProperty = " b ";
public static void main(String[] args){
new B().go(new A());
}
void go(A t){
String s = t.getStaticProperty() + B.staticProperty + staticProperty + (new B().getStaticProperty());
System.out.println(s);
}
}
输出是什么?
此处的输出为a b b a
我完全理解a b b
,但最后并不理解“a”。如果你继承了一个方法(在这种情况下,B从A继承getStaticProperty()),并且该方法返回一个来自父(staticProperty)的静态变量,你在子节点中重新定义,你将总是使用父静态变量值??
顺便说一下,删除静态标识符并使staticField成为类的实例成员会返回相同的结果。修改从私有到公共或其他的访问修饰符返回相同的结果。我需要覆盖getStaticProperty方法以获得我想要看到的内容。
答案 0 :(得分:4)
字段访问不受dynamic dispatch方法访问的约束,即字段无法覆盖。 A类中的这一行:
String getStaticProperty() { return staticProperty; }
因此引用了A类中的字段staticProperty
。具有相同名称的B类字段无关紧要,或者更确切地说:隐藏超类字段,而B类中的所有代码都将使用此字段。 Sun's Java tutorial就此事提出了这个问题:
在一个类中,一个具有该字段的字段 与超类中的字段同名 隐藏超类的字段,即使 他们的类型不同。内 子类,超类中的字段 不能简单引用 名称。相反,该领域必须 通过
super
访问,这是 将在下一节中介绍。通常 说起来,我们不建议隐藏 字段,因为它使代码很难 读取。
答案 1 :(得分:3)
new B().getStaticProperty()
正在调用A
中的方法,该方法返回A
的静态属性,因为它的作用域为A
。
答案 2 :(得分:1)
函数在Java中是虚拟的,但类成员(静态或实例)不是。因此,虽然B对staticProperty
的定义可能会掩盖A的定义,但它不会覆盖它。
// in B
String fromChild = staticProperty; // == "b"
String fromParent = A.staticProperty; // == "a", was masked but not overridden
让A访问B中定义的变量的唯一方法是在A中定义一个getter函数,并按照你的建议在B中覆盖它。
答案 3 :(得分:1)
在考虑诸如此类的继承问题时,您可能会发现在调用new B()
时会发生什么变得有帮助。当B的构造函数执行时,它执行的第一个操作(因为没有对A的构造函数的显式调用)是super()
。此时创建了A的实例,在此对象中,getStaticProperty()
方法明确指的是A的staticProperty
。 B的构造函数的主体然后运行(再次,只有在成功执行A的构造函数之后),并且因为它没有做任何改变或覆盖由A的构造函数实例化的getStaticProperty()
方法,它当然不会改变行为那个方法要么。
这最初可能看起来令人困惑,但它可以是一种有用的方式来思考各种继承问题的含义。
答案 4 :(得分:0)
getStaticProperty()是在类A上定义的方法。该方法未在类B上重写,因此使用了类A中的方法。由于A不能以任何方式“看到”B的静态属性,因此它返回它自己的值。