YAIC (еще одна путаница наследования)

#java

#java

Вопрос:

Я уверен, что такого рода вопросы задают каждый день, но я изо всех сил пытаюсь понять, почему объект mammal создается как cat и сообщает, что его имя — Моррис. Однако, в отличие от большинства кошек, у него нет 9 жизней. Если объект не является cat, почему он сообщает, что его имя — Morris?

 class Mammal  {
    int temp;
    String name = "George";

    public Mammal() {
        temp = 98;
    }

    public String getName() {
        return name;
    }
}

class Cat extends Mammal {
    int lives;
    String name = "Morris";

    public Cat() {
        lives = 9;
    }

    public String getName() {
        return name;
    }
}

public class Inheritance {
    public static void main(String[] args) {
        Mammal mm = new Cat();
        System.out.println("Mam Temp:"   mm.temp);
        //System.out.println("Cat Lives:"   mm.lives);        <-- error
        System.out.println("Mam Name:"   mm.getName());  
    }
}
 

Комментарии:

1. Вы просматриваете Cat как Mammal .

Ответ №1:

Здесь есть два связанных, но конкретно отдельных понятия.

  1. Тип объекта во время выполнения.
  2. Статический (и во время выполнения) тип переменной.

Тип объекта во время выполнения будет определять, как он ведет себя во время выполнения. Это определяется конструктором, который вы вызывали при использовании new ключевого слова.

Статический тип переменной определяет, как ваш код может взаимодействовать с этой переменной или ссылаться на нее (и объект, на который она ссылается). Это определяется типом, который вы указываете при объявлении этой переменной (или поля, параметра и т. Д.).

В этом случае статический тип переменной Mammal равен, а тип среды выполнения объекта, на который она указывает, равен Cat . Таким образом, хотя Cat во время выполнения он ведет себя как a и показывает свое имя как ‘Morris’, во время компиляции компилятор знает только, что это a Mammal , и не может ссылаться на lives переменную (которая определена в Cat , not Mammal ).

Комментарии:

1. Похоже, я задаю неправильный вопрос (наследование). Вместо этого я задаю вопрос о кастинге.

Ответ №2:

Потому что переменная имеет тип Mammal , который был установлен в строке Mammal mm = new Cat(); . Mammal Класс не содержит переменной lives и поэтому выдает ошибку. ((Cat)mm).lives Однако, если вы это сделаете, вы должны получить правильный результат, потому что вы приводите mm переменную к типу Cat (с которым она была инициализирована).

Редактировать

Кроме того, вы переопределили getName() метод в Cat классе, который «скрывает» метод в Mammal классе. Вы создали mm как тип Mammal , но на самом деле это Cat так, что вызов getName() метода on mm вызовет дочерний метод getName() , который возвращает "Morris" вместо "George" .

Комментарии:

1. Перегружен или переопределен? Я думал, что переопределил их метод.

2. @BusterBunker Вы правы, это было переопределено, что было моей ошибкой. Я это исправлю.

Ответ №3:

Вы создали экземпляр Cat , но рассматриваете его как Mammal . Mammal.lives не существует, поэтому при попытке печати вы получаете сообщение об ошибке mm.lives .

Кстати, это хороший пример того, почему наследование может быть опасным и должно использоваться экономно. Cat и Mammal тесно связаны по наследованию, поэтому вы должны понимать оба класса и то, как они взаимодействуют, чтобы понять код, который Cat имеет дело с.

Ответ №4:

созданный объект принадлежит Cat, поэтому метод getName при вызове находится в объекте Cat, и, следовательно, его имя сообщается как «моррис». Однако локальная переменная определяется как млекопитающее, поэтому доступ к lives невозможен, если вы явно не передадите ее cat .