重写 toString() 是否被视为多态?

Pet*_*ski 5 java polymorphism overriding late-binding upcasting

我今天参加 Java 考试,考官问我是否可以提供在 Spring Boot 项目中使用多态性的示例。

由于我一开始想不出任何东西,他指出我在模型中重写了toString() ,这是动态/运行时多态性。

但是,我不确定我是否理解他的观点,因为根据我的理解,当我们有一个指向子类对象的父类引用变量(关注动态多态性)时,行为被认为是多态的。

然后在运行时,获取父类变量指向的实际对象并调用其方法,如此处很好地解释

但是,我在项目中没有使用向上转换(即使用 Object 类变量初始化 POJO 类)。

因此,我的问题是 -尽管父类(Object)从未用作引用变量,但重写 toString() 是否被视为多态?

我在 Stackoverflow 上找到的所有运行时多态性示例(包括此处的示例和带有toString 的示例)都说明了一种情况,即我们有一个父类变量指向子类对象,例如:

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

我的用户类别是:

public class User {

    String name;

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

    public String toString() {
        return name;
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,在我的项目中,我只是使用自己的引用变量创建用户和其他 POJO 类,例如:

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

尽管没有涉及向上转换/父引用变量,上面是否考虑了多态性?

我的同学认为是的,因为对于非最终实例方法,编译器不知道要调用哪个方法 - 它只确保超类中存在这样的方法,因此它将这个决定延长到运行时(后期绑定)通过在编译后的代码中插入一条指令,然后检查该指令并获取变量指向的实际对象,并调用其方法(source)。

然而,这篇文章指出:

方法重写是运行时多态性的一个示例。当父类引用指向子类对象时,对重写方法的调用是在运行时确定的,因为在方法调用期间要执行哪个方法(父类或子类)是由对象的类型决定的。在运行时解析对重写方法的调用的过程称为动态方法分派。

那么:方法重写对于多态性来说是足够的,还是要求子类对象有父类引用?我可以在面试中安全地说仅仅重写 toString() 就是多态性的一个例子吗?

Pet*_*ski 1

感谢评论和其他一些来源,我相信我现在可以回答我的问题如下:

有人可能会说重写 toString() 多态性的一个例子, 因为

Java 虚拟机 (JVM)始终根据引用的对象而不是变量类型定义的方法来选择要在非最终实例方法上调用的方法。这称为动态方法调用或后期绑定,即在运行时决定调用哪个方法,因此称为“运行时”多态性。资料来源:Oracle 文档JavaWorld

因此,无论我们是否有意识地使用多态性,例如通过对接口进行编程,或者我们进行简单的 toString() 方法重写,但仍然继续使用我们的类及其自己的类变量(即使用“用户”变量而不是父类“ Object”变量),关于调用哪个方法的决定总是在运行时通过检查我们的变量所引用的对象的类型来决定

因此,无论我们使用两个初始化中的哪一个,都会对调用哪个模型(即多态行为)进行评估:

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

    Object object = new User("username1");
    System.out.println(object);
Run Code Online (Sandbox Code Playgroud)

变量的类型对于我们的问题来说并不重要,重要的是它所引用的对象,以及它所引用的所有可能对象中的哪一个(即父对象或子对象),都是在运行时决定的。

变量的类型仅与将可用方法的范围限制为父类中的方法并可能被其子类覆盖(如果我们使用父类引用变量)或访问子类的特定方法相关(如果我们使用子类引用变量)。

例如,如果我们向 User 类添加一个新方法:

    public String instanceMethod () {
    return "User instance method called";
}
Run Code Online (Sandbox Code Playgroud)

它无法通过 Object 类变量获得:

在此输入图像描述

它只能通过 User 类变量来使用。

希望这能为其他需要更详细解释的人消除困惑。