当前位置:  开发笔记 > 编程语言 > 正文

为什么autoboxing会在Java中使一些调用变得模棱两可?

如何解决《为什么autoboxing会在Java中使一些调用变得模棱两可?》经验,为你挑选了1个好方法。

我今天注意到自动装箱有时会导致方法重载分辨率的模糊.最简单的例子似乎是这样的:

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); }

这正确地按预期正确调用第一个重载.

那么为什么重载决策失败了呢?为什么编译器没有自动包装第一个参数,并正常接受第二个参数?为什么我必须明确请求自动装箱?



1> eljenso..:

当您自己将第一个参数转换为Object时,编译器将匹配该方法而不使用自动装箱(JLS3 15.12.2):

第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换,或使用变量arity方法调用.如果在此阶段没有找到适用的方法,则处理继续到第二阶段.

如果你没有明确地转换它,它将进入第二阶段试图找到一个匹配的方法,允许自动装箱,然后它确实是模棱两可的,因为你的第二个参数可以匹配boolean或Object.

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

为什么在第二阶段,编译器不会选择第二种方法,因为不需要自动装箱布尔参数?因为在找到两种匹配方法之后,只使用子类型转换来确定两者的最具体方法,无论是否首先匹配它们的装箱或拆箱(第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,就没有选择性自动装箱或拆箱.编译器将找到所有可访问的方法(在这些情况下都是这两种方法)和适用的(再次是两种方法),然后只选择最具体的方法而不查看装箱/拆箱,这在这里是不明确的.

推荐阅读
Life一切安好
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有