Наличие двух переменных с одинаковым именем в классе, расширяющем другой класс в Java.
Вопрос
Ниже приведена часть моего кода для проекта:
public class Body extends Point{
public double x, y, mass;
public Body() {
x = y = mass = 0;
}
public Body(double x, double y, double mass) {
this.mass = mass;
this.x = x;
this.y = y;
}
}
public class Point {
public double x;
public double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
}
Я быстро понял, что это создаст два переменные внутри класса Body с именем x и две другие переменные в Body с именем y.Как это вообще возможно и почему Java вообще это допускает?
Я предполагаю, что это правильный код класса Body:
public class Body extends Point{
public double mass;
public Body() {
super();
mass = 0;
}
public Body(double x, double y, double mass) {
super(x,y);
this.mass = mass;
}
}
Спасибо за ваше время
Решение
В некотором смысле вы переопределяете поля суперкласса.Но это гораздо проще сделать случайно, потому что нет перегрузки полей (у вас есть только одна переменная с заданным именем, тип не имеет значения).Это называется «скрытием» или «затенением» переменной.Итак, вы правы, у вас получится два поля с одинаковым именем.
Ваш второй пример верен.Они унаследованы от суперкласса и, поскольку не объявлены частными, они видны подклассу.Как правило, прямая ссылка на поля суперкласса является плохой практикой, и, если нет веской причины, их следует объявить закрытыми.Ваш пример вызова суперконструктора - лучший подход.
Кроме того, если вы скроете одно поле с другим полем с таким же именем, вы все равно сможете ссылаться на него как super.x, super.y, vs.this.x, this.y, вам следует избегать этой ситуации, если это вообще возможно.
Другие советы
Да, у вас будет две переменные, одна из которых скрывает другую.Разрешить это имеет смысл по двум причинам:
- Предположим, у вас есть базовый класс
Base
и производный классDerived
который авторBase
понятия не имеет о.Должен ли авторBase
никогда не смогу добавлять поля только потому, что производный класс мощь поделитесь полями?Или долженDerived
прекратить компиляцию, когда произойдет изменение наBase
на корректность не влияет? - Ваши поля почти всегда должны быть закрытыми, и в этот момент не имеет значения, дублируются ли имена или нет — ни одна «сторона» не будет знать о переменных другой.
В дополнение к тому, что сказали другие:Является Body
а Point
?Нет, Body
имеет свойство позиции типа Point
.Так Body
наверное, не стоит расширять Point
.Если вы избавитесь от наследования (от реализации), вы избавитесь от множества проблем.Это и использовать private
(нет protected
!) и final
либерально.
Я быстро понял, что при этом внутри класса Body будут созданы две переменные с именем x и две другие переменные в Body с именем y.Как это вообще возможно и почему Java вообще это допускает?
На самом деле нет, вы не создаете две переменные с одинаковым именем, очевидно, что компилятор не должен и не допустит этого.
Что ты являются это затеняет существующие переменные, определенные как x
и y
, что означает, что Body.x и Body.y по существу перекрывают имена Point.x и Point.y, что делает последние две переменные полностью недоступными из класса Body (ссылка на определение «затенения» в спецификации языка Java).
Скрытие имен обычно воспринимается как плохая практика и причина ошибок, и если вы включите предупреждения компилятора javac, компилятор послушно предупредит вас об этом.