Подтвердить что ты не робот

Переменная затенение в Java

У меня есть некоторые сомнения относительно этого Java-кода. Вывод, который он дает, - "пушистый брей". Мои вопросы:

  • Почему я получаю этот вывод?
  • Как я могу получить доступ к ссылке "Имя" объекта String в классе ZooKeeper?
  • Если это имеет какое-то отношение к переменной shadowing, то какая переменная затеняется?

Код:

class Mammal {
   String name = "furry ";
   String makeNoise() { return "generic noise"; }
 }
 class Zebra extends Mammal {
   String name = "stripes ";
   String makeNoise() { return "bray"; }
 }
 public class ZooKeeper {
   public static void main(String[] args) { new ZooKeeper().go(); }
   void go() {
     Mammal m = new Zebra();
     System.out.println(m.name + m.makeNoise());
     //Output comes as "furry bray". Please explain this.
     //And how can we access the name variable, the one having "stripes " in it.
     //Does it have something to do with Variable Shadowing?
   }
 }
4b9b3361

Ответ 1

Переменные не являются полиморфными. Когда вы обращаетесь к m.name, это всегда будет использовать поле Mammal.name, которое является частью этого объекта, независимо от типа времени выполнения объекта. Если вам нужно получить доступ к Zebra.name, вам понадобится выражение с типом времени компиляции Zebra.

Метод makeNoise вызывается практически, хотя реализация, используемая во время выполнения, зависит от типа объекта.

Обратите внимание, что если вы сделаете все свои поля частными, что в целом является хорошей идеей, все равно это не проблема.

Это скорее скрытие, чем затенение. Подробнее о скрытии см. JLS раздел 8.3 и раздел 6.4.1 для затенения. Я не могу сказать, что я всегда сохраняю различия прямо...

Ответ 2

Выход идет как "пушистый брей". Пожалуйста, объясните это.

fields в Java-программах не удается получить доступ через динамический поиск. Вместо этого они решают статически во время компиляции. Вот почему вы получаете furry для m.name. В то время как methods в java-программах можно получить через динамический поиск. Вот почему вы получаете bray для m.makeNoise().

И как мы можем получить доступ к переменной имени, которая имеет "полосы" в это?

И если вы хотите получить доступ к Zebra.name, вы должны ввести cast m в "Zebra". Это будет выглядеть так:

System.out.println(((Zebra)m).name + m.makeNoise());

UPDATE
Явления, которые здесь проявляются, являются результатом "Скрытия полей" , а не переменной тени.

Ответ 3

В Java нет переопределения переменных, вы объявили имя как родительскому, так и дочернему, но вы указали его через родительскую ссылочную переменную. Вот почему вы получили "пушистый".

Существует переопределение методов, поэтому вы получили брей. Потому что во время выполнения он смотрел на реальный объект в куче и видел его Зебра.

Ответ 4

Переменные имена в Java разрешаются ссылочным типом, а не объектом, на который они ссылаются. Итак, m.name ссылается на имя переменной в Mammal, даже тесто m является Zebra.

Ответ 5

Это произошло потому, что ваше поле name из Mammal просто скрыто в поле name из Zebra. Затем вы можете получить к нему доступ, просто нажав на требуемый тип.
С другой стороны, метод makeNoise() переопределяет тот же метод от родителя, чтобы вы больше не могли получить доступ к реализации из родителя.