Наличие 2 переменных с одинаковым именем в классе, который расширяет другой класс в Java - PullRequest
12 голосов
/ 21 апреля 2009

Ниже приведена часть моего кода для проекта:

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;
    }
}

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

Ответы [ 4 ]

13 голосов
/ 21 апреля 2009

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

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

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

5 голосов
/ 21 апреля 2009

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

  1. Предположим, у вас есть базовый класс Base и производный класс Derived, о которых автор Base понятия не имеет. Должен ли автор Base никогда не иметь возможности добавлять какие-либо поля только потому, что производный класс может совместно использовать поля? Или Derived должен прекратить компиляцию, когда изменение на Base фактически не влияет на корректность?
  2. Ваши поля почти всегда должны быть закрытыми, и в этот момент не имеет значения, дублированы ли имена или нет - ни одна «сторона» не узнает о переменных другого.
4 голосов
/ 21 апреля 2009

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

1 голос
/ 21 апреля 2009

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

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

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

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

...