使用Integer调用不明确的方法

时间:2017-10-19 19:08:18

标签: java android junit ambiguous

我正在Android中编写一些Junit测试,如果我这样做:

public void testSetId(){
    Friend friend = new Friend(5);
    assertEquals(5,friend.getId());
}

我得到一个模糊的方法调用错误。

  

模糊方法调用:   AssertEquals(int,int)和   AssertEquals(Object,Object)匹配

然而,如果我这样做:

public void testSetId(){
    Integer ID = 5;
    Friend friend = new Friend(ID);
    assertEquals(ID, friend.getId());
}

有效。我觉得第二个功能应该做同样的事情。

这里发生了什么?

1 个答案:

答案 0 :(得分:5)

在Java 5之前,没有自动装箱或自动拆箱。这意味着如果方法foo的参数类型为Integer,则以下内容无法编译

foo(5);    // 5 needs to be autoboxed

同样,如果方法bar的参数类型为int,则无法编译

bar(new Integer(5));    // The Integer needs to be unboxed

当引入自动装箱和自动拆箱时,现有代码必须以与以前完全相同的方式继续工作。因此,当编译器决定调用哪个方法时,它首先只考虑不需要自动装箱或自动拆箱的适用方法。只有在没有这样的方法时,编译器才会考虑需要自动装箱和/或自动拆箱的方法。

由于getId返回Integer,因此在第一个参数也是Object的情况下,可以在没有自动装箱的情况下调用ObjectInteger方法。但是,intint方法只能通过自动取消装箱第二个参数来调用。因此,在第二个示例中,第一遍选择了ObjectObject重载。

在第一个示例中,您尝试传递intIntegerintint方法仅适用于自动取消装箱第二个参数,而ObjectObject方法仅适用于自动装箱第一个参数。因此,在第一次传递时无法选择重载,并且因为这两种方法都不比另一种方法更具体(您需要查看最后一位),编译器无法在两种方法之间进行选择。

重载分辨率非常复杂,我实际上已经将它简化了一些(还有涉及var-args的规则)。但是在实践中,您不需要学习所有这些规则 - 如果您需要告诉编译器应用哪种方法,您可以始终包含显式强制转换或强制转换:

assertEquals((Integer) id, friend.getId());