这是一个纯理论问题。
给定三个简单的类:
class Base {
}
class Sub extends Base {
}
class SubSub extends Sub {
}
还有一个用于对这些类进行操作的函数:
public static void doSomething(Base b) {
System.out.println("BASE CALLED");
}
public static void doSomething(Sub b) {
System.out.println("SUB CALLED");
}
似乎是下面的代码:
SubSub ss = new SubSub();
doSomething(ss);
可能合法地导致打印 BASE CALLED 或 SUB CALLED,因为 SubSub 可以转换为这两者。事实上,删除函数的 Sub 版本会导致打印 BASE CALLED。实际发生的是打印“SUB CALLED”。这似乎意味着调用哪个函数并不取决于函数定义的顺序,因为 Base 版本首先被调用。
Java 是否只是查看函数的所有不同版本并选择需要最少遍历继承堆栈的版本?这是标准化的吗?它是否写在任何文档中?
最佳答案
正式规范可以在part 15.12.2.5 of the Java Language Specification (JLS)中找到.感谢泛型,这非常复杂,所以你可能想看看 same section of the first edition of the JLS .
它基本上是说编译器试图找到一个方法版本,其中所有参数(包括调用该方法的对象)都是最具体的。如果不存在这样的方法(例如,因为您有 method(Base, Sub)
和 method(Sub, Base)
但没有 method(Sub, Sub)
),则编译失败。
请注意,方法的实际选择取决于实例方法的目标对象的动态类型,而不是参数。您的示例在实例级别上仍然可以正常工作。
您应该能够通过转换或重新声明 ss
的类型来帮助编译器。如果变量的声明类型与签名完全匹配,那么对于编译器和维护程序员来说一切都是清楚的。只要声明的类型匹配,您随后是否分配更具体的类型并不重要。
关于java - Java 如何选择调用哪个重载函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/385551/