Считается ли переопределение toString () полиморфизмом? - PullRequest
4 голосов
/ 14 января 2020

Сегодня у меня был экзамен в Java, и экзаменатор спросил меня, могу ли я привести какие-либо примеры использования полиморфизма в моем проекте Spring Boot.

Поскольку я сначала ничего не мог придумать, он указал, что я переопределил toString () в моих моделях и что это динамический / динамический полиморфизм.

Однако я не уверен, что понимаю его точку зрения, потому что, насколько я понимаю поведение считается полиморфным c, когда у нас есть ссылка на родительский класс, указывающая на объект подкласса (с акцентом на динамический c полиморфизм).

Затем во время выполнения фактический объект , на который указывает родительская переменная класса, извлекается и вызывается ее метод, как хорошо объяснено здесь .

Однако я не использую апкастинг в своем проекте (т.е. инициализирую мой POJO классы с переменной класса Object).

Таким образом, мой вопрос - переопределяет toString () считается полиморфизмом, хотя родительский класс (Obj ect) никогда не используется в качестве ссылочной переменной?

Все примеры полиморфизма времени выполнения, которые я нахожу на Stackoverflow, включая те, которые здесь и это один с toString, проиллюстрируйте ситуацию, когда у нас есть переменная родительского класса, указывающая на объект подкласса, например:

    Object object = new User("petar");
    String name = object.toString(); // assign to variable for clarity`s sake
    System.out.println(name);
    // prints petar

Где мой класс User:

public class User {

    String name;

    public User(String name) {
        this.name = name;
    }

    public String toString() {
        return name;
    }
}

Однако в моем проекте я просто создайте пользователей и другие классы POJO с их собственными ссылочными переменными, например:

    User user = new User("petar");
    String name = user.toString();
    System.out.println(name);
    // prints petar, as toString is overriden

Является ли рассмотренный выше полиморфизм, хотя в него не включена восходящая / родительская ссылочная переменная?

Мой одноклассник утверждает, что это так, потому что для неконечные методы экземпляра компилятор не знает, какой метод вызывать - он только гарантирует, что такой метод существует в суперклассе, поэтому он продлевает это решение вплоть до времени выполнения ( позднее связывание ) путем вставки инструкции в скомпилированный код, который затем проверяется, и фактического объекта, для которого переменная iable указывает на, извлекается и вызывается его метод ( source ).

Однако в этой статье указано, что:

Переопределение метода является примером полиморфизма во время выполнения. Когда ссылка на родительский класс указывает на дочерний объект класса, то вызов переопределенного метода определяется во время выполнения , потому что во время вызова метода какой метод (родительский класс или дочерний класс) должен быть выполнен, определяется тип объекта. Этот процесс, в котором вызов переопределенного метода разрешается во время выполнения, называется динамическим диспетчеризацией c метода.

Итак: достаточно ли переопределения метода для полиморфизма, или это требование, которое есть ссылка родительского класса на объект подкласса? Могу ли я сказать на собеседовании, что простое переопределение toString () является примером полиморфизма?

1 Ответ

0 голосов
/ 14 января 2020

Благодаря комментариям и нескольким другим источникам, я думаю, что теперь я могу ответить на мой вопрос следующим образом:

Можно утверждать, что overriding toString () равно пример полиморфизма , поскольку :

Виртуальная машина Java (JVM) всегда выбирает метод вызывать не окончательные методы instance , основанные на объекте, на который он ссылается, а не на методе, определенном типом переменной. Это называется динамическим вызовом метода c или поздним связыванием, т.е. решением о том, какой метод вызывать, происходит во время выполнения, отсюда и формулировка полиморфизма «времени выполнения». Источник: Oracle Документы , JavaWorld .

Таким образом, независимо от того, используем ли мы сознательно полиморфизм, например, , программируя интерфейсы , или мы делаем простое переопределение метода toString (), но все равно продолжаем использовать наши классы с их собственными переменными класса (т.е. используя переменную «User» вместо родительской переменной «Object»), принимает решение о том, какой метод вызывать всегда во время выполнения, проверяя тип объекта, на который ссылаются наши переменные .

Таким образом, оценка, по какой модели вызывать (т.е. поведение polimorphi c) происходит, независимо от того, какую из двух инициализаций мы используем:

    User user = new User("username1");
    System.out.println(user);

    // or

    Object object = new User("username1");
    System.out.println(object);

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

1038 * тип переменной имеет отношение только к ограничению области действия доступных методов в родительском классе и, возможно, более используется его дочерними элементами (если мы используем родительскую ссылочную переменную класса) или для доступа к указанным c методам дочернего элемента (если мы используем дочернюю ссылочную переменную класса).

Например, если мы добавил новый метод в наш класс User:

    public String instanceMethod () {
    return "User instance method called";
}

Он не будет доступен через переменную класса Object:

enter image description here

Он будет доступен только через переменную класса User.

Надеюсь, что это устранит путаницу для всех, кому тоже нужно более подробное объяснение.

...