我正在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());
}
有效。我觉得第二个功能应该做同样的事情。
这里发生了什么?
答案 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
的情况下,可以在没有自动装箱的情况下调用Object
,Integer
方法。但是,int
,int
方法只能通过自动取消装箱第二个参数来调用。因此,在第二个示例中,第一遍选择了Object
,Object
重载。
在第一个示例中,您尝试传递int
和Integer
。 int
,int
方法仅适用于自动取消装箱第二个参数,而Object
,Object
方法仅适用于自动装箱第一个参数。因此,在第一次传递时无法选择重载,并且因为这两种方法都不比另一种方法更具体(您需要查看最后一位),编译器无法在两种方法之间进行选择。
重载分辨率非常复杂,我实际上已经将它简化了一些(还有涉及var-args的规则)。但是在实践中,您不需要学习所有这些规则 - 如果您需要告诉编译器应用哪种方法,您可以始终包含显式强制转换或强制转换:
assertEquals((Integer) id, friend.getId());