Имея 2 переменные с тем же именем в классе, который расширяет другой класс в 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;
    }
}

Спасибо за ваше время

Ответ 1

В некотором смысле вы являетесь основными полями суперкласса. Но это намного проще сделать случайно, потому что нет перегрузки полей (у вас есть только одна переменная с заданным именем, тип не имеет значения). Это называется переменной "скрытие" или "затенение". Итак, вы правы, вы получите два поля с тем же именем.

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

Кроме того, если вы спрячете поле с другим именем, вы все равно можете ссылаться на них как super.x, super.y, vs. this.x, this.y, вам следует избегать этой ситуации, если вообще возможное.

Ответ 2

Да, у вас будет две переменные, одна из которых скрывает другую. Имеет смысл разрешить это по двум причинам:

  • Предположим, у вас есть базовый класс Base и производный класс Derived, о котором автор понятия Base понятия не имеет. Если автор Base никогда не сможет добавлять какие-либо поля, просто потому, что производный класс может делиться полями? Или следует Derived прекратить компиляцию, когда изменение на Base не влияет на правильность?
  • Ваши поля должны быть почти всегда закрытыми, и в этот момент не имеет значения, дублируются ли имена или нет - ни одна из сторон не будет знать о переменных других.

Ответ 3

В дополнение к тому, что говорили другие: Is Body a Point? Нет, Body имеет свойство position типа Point. Поэтому Body, вероятно, не следует расширять Point. Если вы избавитесь от наследования (реализации), вы избавитесь от множества проблем. Это и используйте private (не protected!) И final либерально.

Ответ 4

Я быстро понял, что это создаст две переменные внутри класса Body, называемые x, и две другие переменные в Body, называемые y. Как это возможно, и почему на самом деле Java даже разрешает это?

На самом деле нет, вы не создаете две переменные с тем же именем, очевидно, компилятор не должен и не допускал этого.

То, что вы делаете, это затенение существующих переменных, определенных как x и y, что означает, что Body.x и Body.y по существу перекрывают имена Point.x и Point.y, что делает последние две переменные полностью недоступный из класса Body (ссылка на определение языка Java "shadowing" ).

Затенение имен обычно воспринимается как плохая практика и причина ошибок, и если вы включите предупреждения компилятора javac, компилятор будет с вами об этом предупреждать.