Наследование и приведение в Java - PullRequest
5 голосов
/ 30 января 2009

У меня есть вопрос о наследовании и приведении в Java. У меня есть два следующих примера классов и тестовый класс, и я задаю свой вопрос после уроков:

public class Automobile {
    public int var;

    public Automobile () {
        var = 1;
    }

    public String toString () {
        return "AUTOMOBILE: " + var;
    }
}


public class Porsche extends Automobile {
    public int var;

    public Porsche () {
        var = 2;
    }

    public String toString () {
        return "PORSCHE: " + var;
    }
}

public class Test {
    public static void main (String [] args) {
        Porsche p = new Porsche();
        Automobile a = new Automobile();

        System.out.println ("(Automobile) p = " + (Automobile)p);

        System.out.println ("(Automobile) p.var = " + ((Automobile)p).var); 
    }
}

Вывод:

(Automobile) p = PORSCHE: 2
(Automobile) p.var = 1

Я не понимаю, почему во втором утверждении мы имеем 1. Разве это не должно быть 2? Потому что после того, как я приведу p к Automobile в первом утверждении, я все еще получаю PORSCHE: 2 как представление p - я понимаю это следующим образом:

тем не менее я привел p к автомобилю p сохраняет свою "первоначальную природу" - p является объектом класса Porsche, но поскольку Porsche расширяет Automobile, мы можем сказать, что p также является автомобилем. И поэтому, когда мы явно приводим его к Automobile, он продолжает использовать свои методы - в В нашем случае метод toString() определен в Porsche.

С другой стороны, если то, что я пишу, правильно, то второе выражение print должно давать 2, а не 1.

Теперь это кажется мне противоречием, но, поскольку это работает в Java, кажется, что я не понимаю, что происходит во время приведения и процесса наследования.

Ответы [ 5 ]

16 голосов
/ 30 января 2009

Я считаю, что вы не можете переопределить переменные в Java. Подкласс фактически скрывает переменную var.

Когда вы приводите к Automobile, вы получаете версию переменной var для суперкласса. Однако метод toString() все еще ищет версию экземпляра переменной var.

Если вы удалили public int var из подкласса Porsche, он должен работать как положено.

Следует отметить, что не рекомендуется использовать общедоступные переменные экземпляра, вы всегда должны создавать методы получения / установки для правильной инкапсуляции .

5 голосов
/ 30 января 2009

Затенение переменной var.

Ваш Porche.var является переменной, отличной от Automobile.var.

Метод Porsche.toString() использует Porsche.var, тогда как приведение говорит компилятору использовать Automobile версию.

2 голосов
/ 30 января 2009

Доступ к полям не является полиморфным - он зависит только от типа времени выражения выражения.

Выражение ((Automobile) p) имеет тип времени компиляции Automobile, поэтому используются его поля.

1 голос
/ 26 марта 2013

Объявление переменной "var" в обоих классах фактически создает два поля в памяти.

Экземпляр "Porsche" будет иметь в памяти два поля "var": одно из класса "Porsche" и одно из суперкласса "Automobile". Поле «var» суперкласса скрыто, когда вы ссылаетесь на «var» из известного экземпляра «Porsche». Если вы приведете этот экземпляр к «Automobile» и ссылаетесь на поле «var», вы ссылаетесь на поле «Automobile» var.

В полях нет переопределения. Новые поля с тем же именем затеняют поля суперкласса.

Чтобы получить ожидаемый результат, вы вообще не должны объявлять поле "var" в классе "Porsche".

0 голосов
/ 26 декабря 2015

Однако:

Если у вас есть метод, который возвращает родительский объект класса A, он может вернуть любой тип объекта классу, который его расширяет (пример фабрики). Теперь, если этот метод возвращает объект подкласса B и если вы не преобразуете его в B, все его атрибуты будут родительскими. Если вы приведете его к B, то его атрибуты будут атрибутами A и B.

class A {
int a1,a2;
public A(){}


  public static A getInstance () {
  return new B() ;
  }
}
class B {
int b1,b2;
  public B() {}

}
 class Test{

 public static void main (String [] args) {

  A theA = A.getInstance() ; //here theA has only a1,a2 as attributes
  B theB = (B)theA    // here theB has b1,a2 and a1,a2 as attributes 
  }


}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...