首页 > 解决方案 > 重写 toString() 是否被认为是多态性?

问题描述

我今天在参加 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

我的用户类在哪里:

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

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

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

但是,在这篇文章中指出:

方法覆盖是运行时多态的一个例子。当父类引用指向子类对象时,对被覆盖方法的调用是在运行时确定的,因为在方法调用期间,要执行哪个方法(父类或子类)取决于对象的类型。这个在运行时解决对被覆盖方法的调用的过程称为动态方法分派。

那么:方法重写是否足以满足多态性,或者是否需要有对子类对象的父类引用?我可以在面试中说仅仅重写 toString() 就是多态性的一个例子吗?

标签: javapolymorphismoverridinglate-bindingupcasting

解决方案


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

有人可能会争辩说,覆盖 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);

变量的类型对我们的问题无关紧要,重要的是它所指的对象,以及它所指的所有可能对象中的哪一个(即父对象或子对象),由运行时决定。

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

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

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

它不能通过 Object 类变量获得:

在此处输入图像描述

它只能通过 User 类变量获得。

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


推荐阅读