在同一个类中,我有两个重载方法:
public static <T> void foo(Collection<T> collection, T valueToAppend);
public static <T> void foo(Collection<T> collection, Collection<T> valueToAppend);
以下测试应调用第二种方法:
@Test
public void testFoo() {
ArrayList ftList = Lists.newArrayList();
List<Double> doubleList = Lists.newArrayList(1.0, 2.0);
foo(ftList, doubleList);
}
当我运行测试时,我得到以下编译错误:
对foo的引用是不明确的,path.to.class中的方法foo(java.util.Collection,T)和path.to.class中的方法foo(java.util.Collection,java.util.Collection)匹配
我在第二个参数中传递了一个集合,所以为什么编译器不知道
转到第二种方法?
如果我改变方法签名并从第一个参数中删除泛型我将
没有得到编译错误,为什么会这样?
答案 0 :(得分:3)
这是我的解释。当编译器必须在重载之间进行选择时,它总是选择最具体的重载。从第一个参数中删除类型信息时,签名变为
public static <T> void foo(Collection collection, T valueToAppend)
public static <T> void foo(Collection collection, Collection<T> valueToAppend)
其中第二个更具体。第一种方法也可以接受第二种方法可以接受的任何参数对,因为任何Collection
都是Object
。因此,当您去除类型参数时,没有歧义 - 如果您传递两个Collection
,则选择第二种方法。
但是对于类型信息,签名如下所示:
public static <T> void foo(Collection<T> collection, T valueToAppend)
public static <T> void foo(Collection<T> collection, Collection<T> valueToAppend)
这些签名都没有比另一个更具体。参数new ArrayList<String>()
和"Foo"
将被第一个签名接受,但不会被第二个签名接受。参数new ArrayList<String>()
和new ArrayList<String>()
将被第二个签名接受,但不会被第一个签名接受。
因此,如果两个签名都适用,则存在问题。
您正在尝试传递原始ArrayList
和List<Double>
。由于您使用的是原始类型ArrayList
(您永远不应该这样做),ftList
可以作为任何 Collection<T>
的{{1}}传递(尝试尝试将原始T
传递给参数类型为List
的方法。它可以工作)。因此,您只需要看到List<String>
与两个重载的第二个参数匹配。如果doubleList
为T
,则匹配第一个签名,如果List<Double>
为T
则匹配第二个签名。
答案 1 :(得分:0)
由于第二个参数<T>
也可能是Collection
,因此解释者会感到困惑,无论是Collection<T>
还是<T>
答案 2 :(得分:0)
编译器无法识别<T>
和Collection<T>