Java не переопределяет поля (иначе атрибуты или переменные-члены). Вместо этого они затеняют друг друга. Если вы запустите программу через отладчик, вы найдете две x
переменные в любом объекте типа B
.
Вот объяснение того, что происходит. Программа сначала извлекает что-то, что неявно имеет тип A
, а затем вызывает x
, который, как предполагается, происходит от A
. Несмотря на то, что это явно подтип, в вашем примере объект типа B
создается с помощью SubCovariantTest
, он все еще предполагает, что вы возвращаете что-то в getObj () с неявным типом A. Поскольку Java не может переопределять поля, тест звоните A.x
а не B.x
.
CovariantTest c = new SubCovariantTest();
// c is assumed the type of CovariantTest as it is
// implicitly declared
System.out.println(c.getObj().x);
// In this method chain the following happens:
// c.getObj() will return object of type B
// BUT will assume it is an A
// c.getObj().x will return the x from A
// since in this context the compiler assumes
// it is an A and make the call to A.x
Кажется, это ошеломляет, потому что методы всегда переопределяются в Java (по сравнению с C ++ и C #, в которых их нет). Обычно вы не сталкиваетесь с этой проблемой, потому что соглашение Java-кода запрещает напрямую обращаться к полям. Вместо этого убедитесь, что поля всегда доступны через методы доступа , т.е. getters :
class A {
private int x = 5;
public int getX() { // <-- This is a typical accessor method
return x;
}
}
class B extends A {
private int x = 6;
@override
public int getX() {
// will be called instead even though B is implied to be A
// @override is optional because methods in Java are always virtual
// thus are always overridden
return x;
}
}
Код для получения этой работы следующий:
c.getObj().getX();
// Will now call getX() in B and return the x that is defined in B's context.