Переменная затенение в 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?
}
}
Ответы
Ответ 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()
переопределяет тот же метод от родителя, чтобы вы больше не могли получить доступ к реализации из родителя.