【问题标题】:Is overriding toString() considered polymorphism?重写 toString() 是否被认为是多态性?
【发布时间】:2020-04-30 14:56:38
【问题描述】:

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

一开始我什么都想不出来,他指出我在我的模型中重写了 toString(),这是动态/运行时多态性。

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

然后在运行时获取父类变量指向的实际对象并调用其方法,正如here 很好解释的那样。

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

因此,我的问题是 - 是否覆盖 toString() 被认为是多态性,尽管父类 (Object) 从未用作参考变量?

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

    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)。

但是,在this article 中声明:

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

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

【问题讨论】:

  • 我倾向于同意你同学的观点。它确实是多态性,因为任何程序都可以将 User 实例视为通用 Object 实例。
  • 我会说,拥有动态方法(调用)本身就是 多态性的一部分,即使对象引用本身没有被强制转换为其他任何东西。仍然需要决定调用哪个方法。要说它是“多态性在行动中”,好吧,我猜不是。事情从来都不是非黑即白的。你的教授只是想看看是否明白,所以指向一个被覆盖的方法确实没问题。面试也一样,如果你回答类似的问题,他们会进一步询问(或者他们是糟糕的面试官)。
  • 谢谢大家的回答。 @Maarten-reinstateMonica,谢谢你的详细解释,我相信我现在明白了。总是需要决定哪种方法调用非最终实例方法,因为编译器永远不会真正知道 - 从这个角度来看,人们确实可以争辩说这是多态性,尽管不是你所说的“多态性”。

标签: java polymorphism overriding late-binding upcasting


【解决方案1】:

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

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

Java 虚拟机 (JVM)总是根据它所引用的对象而不是方法来选择在非最终 instance 方法上调用的方法由变量类型定义。这被称为动态方法调用或后期绑定,即在运行时决定调用哪个方法,因此称为“运行时”多态性。来源:Oracle DocsJavaWorld

因此,无论我们是否有意识地使用多态性,例如programming to interfaces 或者我们做一个简单的 toString() 方法覆盖,但仍然继续使用我们的类和它们自己的类变量(即使用“User”变量而不是父类“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 类变量获得:

它只能通过用户类变量获得。

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

【讨论】:

    猜你喜欢
    • 2011-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-20
    • 1970-01-01
    • 1970-01-01
    • 2015-05-08
    • 2018-06-19
    相关资源
    最近更新 更多