Полиморфизм Java - Как определить, будет ли вызываться метод суперкласса против подкласса, а переменная суперкласса - переменная подкласса? - PullRequest
0 голосов
/ 15 октября 2018

Пример кода:

public class A {

    public int number;

    public A(int number) {
        this.number = number;
    }

    public int getNumber() {
        return number;
    }

}



public class B extends A{

    public int number;

    public B(int number) {
        super(number);
    }


    public int getNumber() {
        return number;
    }

}


public class C {

    public static void main(String args[]) {

        A test1 = new B(2);
        B test2 = new B(2);

        System.out.println(test1.number) // prints 2
        System.out.println(test2.number) // prints 0
        System.out.println(test1.getNumber()) //prints 0
        System.out.println(test2.getNumber()) // prints 0
    }

}

Как показано выше, test1.number не равен test1.getNumber ().

Поэтому, когда я делаю test1 объектом типа A test1.numberссылается на номер int в классе A.

Но когда я вызываю test1.getNumber (), он вызывает getNumber () в классе B?

Почему это происходит?

Ответы [ 3 ]

0 голосов
/ 15 октября 2018

Все методы в Java являются виртуальными.Я вернусь к тому, что это значит через секунду.

Итак, в этой строке:

A test1 = new B(2);

Вы присвоили новый экземпляр класса B переменной, объявленной какA.

Когда вы используете test1.number, вы используете переменную number, объявленную в классе A, что означает, что конструктор для B вызывает super(number)2.

Тем не менее, когда вы вызываете test1.getNumber(), именно здесь запускается виртуальный. Virtual означает, что он всегда будет вызывать метод в созданном классе, а не тип переменной, которую вы объявили как,Другими словами, вместо того, чтобы звонить A getNumber, как вы думали, вместо этого он на самом деле вызывает B getNumber.Конструктор B не присваивает значение переменной B number, поэтому вы получаете 0.

0 голосов
/ 15 октября 2018

Это потому, что Java допускает переопределение для методов, но не для полей.

Спецификация записывает :

Если класс объявляет поле с определеннымname, тогда говорят, что объявление этого поля скрывает все доступные объявления полей с одинаковыми именами в суперклассах и суперинтерфейсах класса.

В этом отношении сокрытие полей отличается от сокрытия методов (§8.4.8.3), поскольку в скрытии полей не проводится различий между статическими и нестатическими полями, тогда как различие проводится междустатические и нестатические методы в скрытии методов.

Доступ к скрытому полю можно получить с помощью квалифицированного имени (§6.5.6.2), если оно статическое, или с помощью выражения доступа к полю, которое содержитключевое слово super (§15.11.2) или приведение к типу суперкласса.

В этом отношении скрытие полей аналогично сокрытию методов.

То есть каждый экземпляр B имеет два разных поля, которые имеют одно и то же имя.Когда вы используете имя поля в выражении доступа к полю, таком как test1.number, имя поля интерпретируется относительно типа времени компиляции test1.

Напротив, методы экземпляра могут быть переопределены :

Метод экземпляра mC, объявленный (или унаследованный) в классе C, переопределяет из C другой метод mAобъявлен в классе A, если все следующее верно:

  • C является подклассом A.

  • ...

  • Подпись mC является подписью (§8.4.2) подписи mA.

(где «подпись» означает, чтоимя метода и параметры совместимы.)

Переопределение разрешено следующим образом :

В противном случае должен быть вызван метод экземпляра, и существует цельссылка.Если целевая ссылка равна нулю, в этой точке генерируется исключение NullPointerException.В противном случае говорят, что целевая ссылка ссылается на целевой объект и будет использоваться в качестве значения ключевого слова this в вызываемом методе.

...

В противном случае, [...] может произойти переопределение.Динамический метод поиска используется.Процесс динамического поиска начинается с класса S, определяемого следующим образом:

  • Если режим вызова является интерфейсным или виртуальным, то первоначально S является фактическим классом R времени выполнения целевого объекта.,

  • ...

Для поиска в динамическом методе используется следующая процедура для поиска в классе S, а затем в суперклассах и суперинтерфейсах класса S,при необходимости для метода m.

То есть, если вы напишите test1.getNumber(), среда выполнения оценит test1, чтобы получить целевой объект, определить его класс и затем найти подходящий метод в этом классе.

В вашем примере test1 ссылается на объект класса B, поэтому вызывается B.getNumber().

Затем реализация B.getNumber() переходит к чтению B.number, которое никогда не назначалось и, следовательно, все еще содержит значение по умолчанию 0.

0 голосов
/ 15 октября 2018

По этому сайту я нашел некоторую информацию, которая объясняет иерархию классов в Java.Когда вы расширяете класс, вы в основном копируете код из этого класса и помещаете его в тот, который расширяет его, чтобы вам не приходилось переписывать методы, а вы делаете это в классе B. Поэтому вместо использования метода вкласс A будет использовать тот, который вы закодировали в класс B.

https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...