Если вы перезаписываете поле в подклассе класса, у подкласса есть два поля с одинаковым именем (и разным типом)?
У меня есть 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 ответа
Переменные-члены не могут быть переопределены как методы. number
переменные в ваших классах Beta
а также Gama
скрывают (не переопределяют) переменную-член 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());
}
В качестве обходного пути вы можете использовать методы получения:
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;
}
}