多态模糊区分如何工作?

Pet*_*ann 4 java oop polymorphism overloading

鉴于我有一个包含两个构造函数的类:

public class TestClass {
    ObjectOne o1;
    ObjectTwo o2;

    public TestClass(ObjectOne o1) {
        // ..
    }

    public TestClass(ObjectTwo o2) {
        // ..
    }
}
Run Code Online (Sandbox Code Playgroud)

请假设,这ObjectOne是一种interface类型,并且ObjectTwo implements ObjectOne.如果我打电话,会发生什么:

new TestClass(null);
Run Code Online (Sandbox Code Playgroud)

如何确定调用的正确方法?谁决定了?Java和其他OOP语言之间是否存在差异?

pol*_*nts 16

这个问题实际上是关于解决暧昧过载,而不是真正的运行时多态性(因为选择哪些重载方法调用是在完成编译时).

方法解析是一件复杂的事情,在这种情况下,代码是否完全编译取决于所涉及的类型.在很多情况下代码都会编译.请参阅下面的代码(注意String implements CharSequence):

public class MyClass {
    MyClass(CharSequence charSeq) {
        System.out.println("CharSequence");
    }
    MyClass(String s) {
        System.out.println("String");
    }   
    public static void main(String[] args) {
        new MyClass(null); // prints "String"
        new MyClass(""); // prints "String"
        new MyClass((CharSequence) null); // prints "CharSequence"
        new MyClass((CharSequence) "");   // prints "CharSequence"
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果没有强制转换,String则选择过载.这与JLS中指定的完全相同:

JLS 15.12.2.5选择最具体的方法

如果多个成员方法都可访问并适用于方法调用,则必须选择一个为运行时方法调度提供描述符.Java编程语言使用选择最具体方法的规则.

A String是-a CharSequence,但不是全部CharSequence是-a String.因此,String更具体的CharSequence,因此,为什么String过载被选择在上述的例子.


值得注意的是,这个确切的问题(实质上)出现在精彩的Java Puzzlers(强烈推荐)中,特别是Puzzle 46:令人困惑的构造函数的案例

Java的重载解析过程分两个阶段进行.第一阶段选择可访问和适用的所有方法或构造函数.第二阶段选择在第一阶段中选择的最具体的方法或构造函数.如果一个方法或构造函数可以接受传递给另一个的任何参数,则它的特定性不如另一个

理解这个难题的关键是对哪个方法或构造函数最具体的测试不使用实际参数:调用中出现的参数.它们仅用于确定适用的过载.一旦编译器确定哪些重载适用且可访问,它就只使用形式参数选择最具体的重载:声明中出现的参数.


我将结束有效Java第2版的引用,第41项:明智地使用重载:

确定选择哪个重载的规则非常复杂.它们在语言规范中占用了三十三页,很少有程序员理解它们的所有细微之处.

毋庸置疑,这本书也值得推荐.

也可以看看

  • +1教我一些有趣的东西. (3认同)

mko*_*ela 5

没有魔力.您必须将null参数转换为ObjectOne或ObjectTwo.

所以:

 new TestClass((ObjectOne) null);
Run Code Online (Sandbox Code Playgroud)

要么

 new TestClass((ObjectTwo) null);
Run Code Online (Sandbox Code Playgroud)