这是一个纯粹的理论问题.
给出三个简单的类:
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只是查看函数的所有不同版本并选择需要最小遍历继承堆栈的函数吗?这标准化了吗?它是在任何文档中写出来的吗?
形式规范可以在Java语言规范(JLS)的第15.12.2.5部分中找到.感谢泛型,这非常复杂,因此您可能希望查看第一版JLS的相同部分.
它基本上说编译器试图找到该方法的一个版本,其中包括调用该方法的对象的所有参数都是最具体的.如果不存在这样的方法(例如,既然你有method(Base, Sub)
,method(Sub, Base)
但没有method(Sub, Sub)
),那么编译就失败了.
请注意,方法的实际选择取决于实例方法的目标对象的动态类型,但不取决于参数.您的示例在实例级别上仍然可以正常工作.
您应该能够通过强制转换或重新声明类型来为编译器提供帮助ss
.如果声明的变量类型与签名完全匹配,那么编译器和维护程序员也清楚一切.只要声明的类型匹配,如果您再分配更具体的类型并不重要.