1

在准备 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 方法才能得到我想看到的东西。

4

5 回答 5

4

字段访问不受方法访问等动态调度的影响,即不能覆盖字段。A类中的这一行:

String getStaticProperty() { return staticProperty; }  

因此指的是staticPropertyA类中的字段。B类的同名字段是无关紧要的,或者更确切地说:它隐藏了超类字段,B类中的所有代码都会使用该字段。Sun 的 Java 教程对此事有这样的说法:

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

于 2009-12-15T15:53:22.740 回答
3

new B().getStaticProperty()正在调用A返回A静态属性的方法,因为它的范围为A.

于 2009-12-15T15:37:11.380 回答
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 中覆盖它。

于 2009-12-15T15:51:17.113 回答
1

new B()在考虑诸如此类的继承问题时,您可能会发现考虑调用时会发生什么很有帮助。当 B 的构造函数执行时,它执行的第一个操作(因为没有显式调用 A 的构造函数)是super(). 此时创建了一个 A 的实例,并且在这个对象中,该getStaticProperty()方法清楚地引用了 A 的staticProperty。然后 B 的构造函数的主体运行(同样,仅在成功执行 A 的构造函数之后),并且由于它不会更改或覆盖getStaticProperty()由 A 的构造函数实例化的方法,因此它当然也不会更改该方法的行为。

起初这可能看起来令人困惑,但它可能是一种有助于思考各种继承问题的含义的方法。

于 2009-12-15T18:03:36.707 回答
0

getStaticProperty() 是在 A 类上定义的方法。该方法在 B 类上没有被覆盖,因此使用 A 类的方法。由于 A 无法以任何方式“看到”B 的静态属性,因此它返回它自己的值。

于 2009-12-15T15:46:45.667 回答