今天我注意到,自动装箱有时能在方法重载歧义。最简单的例子看来是这样的:

public class Test {
    static void f(Object a, boolean b) {}
    static void f(Object a, Object b) {}

    static void m(int a, boolean b) { f(a,b); }
}

当编译,它会导致以下错误:

Test.java:5: reference to f is ambiguous, both method
    f(java.lang.Object,boolean) in Test and method
    f(java.lang.Object,java.lang.Object) in Test match

static void m(int a, boolean b) { f(a, b); }
                                  ^

在修复这个错误很简单:只需使用明确的自动装箱:

static void m(int a, boolean b) { f((Object)a, b); }

哪些正确调用按预期所述第一过载。

那么,为什么重载决策失败?为什么没有编译器自动框中的第一个参数,通常接受第二个参数?为什么我要明确要求自动装箱?

有帮助吗?

解决方案

当在投射到对象自己的第一个参数,则编译器将匹配方法不使用自动装箱(JLS3 15.12.2):

  

第一阶段(§15.12.2.2)执行   重载解析,但不允许   装箱或取消装箱转换,或   使用可变元数的方法   调用。如果没有适用的方法是   在这个阶段发现的,然后   处理继续到第二   相。

如果你不明确投它,它会去试图找到一个匹配的方法,允许自动装箱第二阶段,然后它确实是不明确的,因为你的第二个参数可以通过布尔值或者对象相匹配。

  

第二阶段(§15.12.2.3)执行   同时允许重载解析   装箱和拆箱,但仍   排除使用变量的元数   方法调用。

为什么,在第二阶段中,不编译器选择所述第二方法,因为没有布尔参数的自动装箱是必要的?因为它已找到两个匹配的方法后,仅亚型转换被用于确定所述两个最具体方法,不管发生在第一位置与它们匹配任何拳击或取消装箱的(§15.12.2.5)。

此外:拳击需要的编译器不能总是选择基于自(未)的数量的最特定的方法。它仍然会导致不确定的情况下。例如,这仍然是不明确的:

public class Test {
    static void f(Object a, boolean b) {}
    static void f(int a, Object b) {}

    static void m(int a, boolean b) { f(a, b); } // ambiguous
}

记住,该算法用于选择匹配方法(编译时步骤2)是固定的并且在JLS说明。一旦在阶段2中没有选择性自动装箱或取消装箱。编译器将找到的所有的可访问(在这些情况下,这两种方法),并适用(再次两种方法)方法,然后才选择不看装箱/拆箱,这是最具体的一个这里不明确的

其他提示

在编译器的没有自动框中的第一个参数。一旦已完成,这是这是不明确的,因为它可以被看作是任一布尔或对象的第二个参数。

此页解释了自动装箱和选择哪个方法的规则调用。编译器首先尝试选择的方法的不使用任何自动装箱在所有,因为装箱和拆箱携带性能损失。如果没有方法能够不诉诸拳击,因为在这种情况下被选择,然后拳击是在桌子上的所有的参数这种方法。

当你说的 F(A,B ),编译为哪个函数应该参照混淆。

这是因为<强>一个是一个的 INT ,但预期在参数的˚F是一个对象。所以compliler决定为转换为对象。现在的问题是,如果的可以被转换为一个对象,所以可的 B'/强>

这意味着该函数调用可以参考任一定义。这使得呼叫模糊的。

当你手动转换 到对象时,编译器只是看起来最接近的匹配,然后是指它。

  

为什么没有编译器选择   可以通过“做来达到功能   的最小可能数   装箱/拆箱转化“?

请参阅下面的情况:

f(boolean a, Object b)
f(Object a , boolean b)

如果我们称之为例如 F(Boolean一个,布尔b)中下,应该把它选择哪个功能?它ambigous吧?同样,当不少争论都存在,这将变得更加复杂。所以编译器选择给你一个警告吧。

由于没有办法知道哪个的程序员真的打算调用的功能的一个,编译器提供了一个错误。

  

那么,为什么做了重载解析   失败?为什么没有编译器自动箱   第一个参数,并接受   通常第二个参数?为什么我   有权要求自动装箱   明确地

有未正常接受第二个参数。请记住,“布尔”可以装箱为对象了。你可以有显式转换布尔参数对象,以及它会工作。

请参阅 HTTP://java.sun。 COM /文档/书籍/ JLS / third_edition / HTML / expressions.html#20448

在投帮助,因为这样不需要拳击找到要调用的方法。没有铸造第二次尝试是允许拳击,然后也布尔可以装箱。

最好是有明确的和可以理解的规范说会发生什么,而不是让人们猜测。

Java编译器可解决相重载方法和构造函数。在第一阶段[§15.12.2.2],它由子类型[§4.10]识别可应用的方法。在这个例子中,既不方法是适用的,因为int是不是对象的子类型。

在第二阶段[§15.12.2.3],编译器识别由方法调用转换[§5.3],它是自动装箱和子类型的组合的应用的方法。 int参数可以被转换成整数,这是对象的子类型,对于过载。 boolean参数需要为第一过载无转换,并且可以被转换成布尔值,对象的子类型,对于第二。因此,这两种方法均适用于第二阶段。

由于一个以上的方法是适用的,编译器必须确定哪一个是最具体的[§15.12.2.5]。它比较的参数类型,没有参数类型,并且它不autobox他们。对象和布尔是无关的类型,所以它们被视为同样具体。既不方法比其他更具体的,因此该方法调用是不明确的。

要解决的模糊性是改变布尔参数布尔类型,这是对象的子类型的一种方法。第一过载将始终是更具体的(适用时)比所述第二

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top