68

我有 3 节课:

public class Alpha {
    public Number number;
}

public class Beta extends Alpha {
    public String number;
}

public class Gama extends Beta {
    public int number;
}

为什么下面的代码会编译?而且,为什么测试通过而没有任何运行时错误?

@Test
public void test() {
    final Beta a = new Gama();
    a.number = "its a string";
    ((Alpha) a).number = 13;
    ((Gama) a).number = 42;

    assertEquals("its a string", a.number);
    assertEquals(13, ((Alpha) a).number);
    assertEquals(42, ((Gama) a).number);
}
4

4 回答 4

87

成员变量不能像方法一样被覆盖。number您的类中的变量Beta隐藏(Gama不是覆盖)number超类的成员变量。

通过强制转换,您可以访问超类中的隐藏成员。

于 2012-02-23T14:34:31.770 回答
54

字段不能被覆盖;首先它们没有被多态访问——你只是在每种情况下声明一个新字段。

它可以编译,因为在每种情况下,表达式的编译时类型足以确定您所指字段。number

在实际编程中,您可以通过两种方式避免这种情况:

  • 常识:阴影字段使您的代码更难阅读,所以不要这样做
  • 可见性:如果您将所有字段设为私有,子类无论如何都不会知道它们
于 2012-02-23T14:32:59.520 回答
3

当后继有一个与超类的字段同名字段时,它被称为 -隐藏一个字段

Java的字段不支持多态,也不考虑字段的类型

class A {
    String field = "A: field";

    String foo() {
        return "A: foo()";
    }
}

class B extends A {
    //B's field hides A's field
    String field = "B: field";

    String foo() {
        return "B: foo()";
    }
}

@Test
public void testPoly() {
    A a = new A();
    assertEquals("A: field", a.field);
    assertEquals("A: foo()", a.foo());

    B b = new B();
    assertEquals("B: field", b.field);
    assertEquals("B: foo()", b.foo());

    //B cast to A
    assertEquals("A: field", ((A)b).field);  //<--
    assertEquals("B: foo()", ((A)b).foo());
}

[Swift 覆盖属性]

于 2020-06-01T12:24:29.733 回答
2

作为一种解决方法,您可以使用 getter 方法:

class A {
    private String field = "A: field";

    String getField() {
        return field;
    }
}

class B extends A {
    private String field = "B: field";

    @Override        
    String getField() {
        return field;
    }
}
于 2021-09-16T14:03:41.503 回答