使用 Integer 的模糊方法调用
Ambiguous method call with Integer
我正在 Android 中编写一些 Junit 测试,如果我这样做:
public void testSetId(){
Friend friend = new Friend(5);
assertEquals(5,friend.getId());
}
我收到一个不明确的方法调用错误。
Ambiguous Method Call:
Both AssertEquals(int, int) and
AssertEquals(Object, Object) match
但是如果我这样做:
public void testSetId(){
Integer ID = 5;
Friend friend = new Friend(ID);
assertEquals(ID, friend.getId());
}
有效。我觉得第二个函数应该做完全相同的事情。
这是怎么回事?
在 Java 5 之前没有自动装箱或自动拆箱。这意味着如果一个方法 foo
有一个类型为 Integer
的参数,下面的代码不会编译
foo(5); // 5 needs to be autoboxed
类似地,如果一个方法 bar
有一个 int
类型的参数,这不会编译
bar(new Integer(5)); // The Integer needs to be unboxed
引入自动装箱和自动拆箱后,现有代码必须继续以与以前完全相同的方式工作。因此,当编译器决定调用哪个方法时,它首先只考虑不需要自动装箱或自动拆箱的适用方法。只有当没有这样的方法时,编译器才会考虑需要自动装箱的方法and/or 自动拆箱。
由于 getId
returns 和 Integer
,在第一个参数也是一个 Integer
。但是 int
, int
方法只能通过自动拆箱第二个参数来调用。因此,在您的第二个示例中,Object
、Object
重载在第一遍被选中。
在您的第一个示例中,您试图传递 int
和 Integer
。 int
、int
方法仅适用于自动拆箱第二个参数,而 Object
、Object
方法仅适用于自动装箱第一个参数。因此,无法在第一遍选择重载,并且因为两种方法都不比另一种更具体(您需要查看最后一点)编译器无法在这两种方法之间进行选择。
重载决议非常复杂,我实际上已经简化了很多(也有涉及var-args的规则)。然而在实践中,你不需要学习所有这些规则——如果你需要告诉编译器应用哪种方法,你总是可以包含一个或多个显式强制转换:
assertEquals((Integer) id, friend.getId());
我正在 Android 中编写一些 Junit 测试,如果我这样做:
public void testSetId(){
Friend friend = new Friend(5);
assertEquals(5,friend.getId());
}
我收到一个不明确的方法调用错误。
Ambiguous Method Call: Both AssertEquals(int, int) and AssertEquals(Object, Object) match
但是如果我这样做:
public void testSetId(){
Integer ID = 5;
Friend friend = new Friend(ID);
assertEquals(ID, friend.getId());
}
有效。我觉得第二个函数应该做完全相同的事情。
这是怎么回事?
在 Java 5 之前没有自动装箱或自动拆箱。这意味着如果一个方法 foo
有一个类型为 Integer
的参数,下面的代码不会编译
foo(5); // 5 needs to be autoboxed
类似地,如果一个方法 bar
有一个 int
类型的参数,这不会编译
bar(new Integer(5)); // The Integer needs to be unboxed
引入自动装箱和自动拆箱后,现有代码必须继续以与以前完全相同的方式工作。因此,当编译器决定调用哪个方法时,它首先只考虑不需要自动装箱或自动拆箱的适用方法。只有当没有这样的方法时,编译器才会考虑需要自动装箱的方法and/or 自动拆箱。
由于 getId
returns 和 Integer
,在第一个参数也是一个 Integer
。但是 int
, int
方法只能通过自动拆箱第二个参数来调用。因此,在您的第二个示例中,Object
、Object
重载在第一遍被选中。
在您的第一个示例中,您试图传递 int
和 Integer
。 int
、int
方法仅适用于自动拆箱第二个参数,而 Object
、Object
方法仅适用于自动装箱第一个参数。因此,无法在第一遍选择重载,并且因为两种方法都不比另一种更具体(您需要查看最后一点)编译器无法在这两种方法之间进行选择。
重载决议非常复杂,我实际上已经简化了很多(也有涉及var-args的规则)。然而在实践中,你不需要学习所有这些规则——如果你需要告诉编译器应用哪种方法,你总是可以包含一个或多个显式强制转换:
assertEquals((Integer) id, friend.getId());