如果你在一个类的子类中覆盖一个字段,那么这个子类有两个同名字(不同类型)的字段?

我有三节课:

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);
}
63152 次浏览

字段不能是 覆盖; 它们首先不能以多态方式访问——您只需在每种情况下声明一个新字段。

之所以编译,是因为在每种情况下,表达式的编译时类型都足以确定所谓 number哪个字段。

在现实世界的编程中,您可以通过两种方法来避免这种情况:

  • 常识: 隐藏字段会使代码更难读,所以不要这样做
  • 可见性: 如果将所有字段都设置为私有,子类无论如何都不会知道它们

成员变量不能像方法一样被重写。类 BetaGama中的 number变量是 躲起来(不重写)超类的成员变量 number

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

隐藏字段

当后继者的 场地与超类的字段具有相同的 姓名时,它被称为-隐藏一块地

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());
}

[迅速覆盖属性]

作为一种变通方法,您可以使用 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;
}
}