【发布时间】:2020-04-30 14:56:38
【问题描述】:
今天我在参加 Java 考试,考官问我是否可以提供在我的 Spring Boot 项目中使用多态性的任何示例。
一开始我什么都想不出来,他指出我在我的模型中重写了 toString(),这是动态/运行时多态性。
但是,我不确定我是否理解他的观点,因为据我了解,当我们有一个父类引用变量指向子类对象时,行为被认为是多态的(专注于动态多态)。
然后在运行时获取父类变量指向的实际对象并调用其方法,正如here 很好解释的那样。
但是,我没有在我的项目中使用向上转换(即使用 Object 类变量初始化我的 POJO 类)。
因此,我的问题是 - 是否覆盖 toString() 被认为是多态性,尽管父类 (Object) 从未用作参考变量?
我在 Stackoverflow 上找到的所有运行时多态示例,包括带有 toString 的 here 和 this,说明了我们有一个父类变量指向子类对象的情况,例如:
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