【问题标题】:Compilation error ambiguous reference to method when using typed collection使用类型化集合时编译错误对方法的模糊引用
【发布时间】:2015-09-24 12:08:05
【问题描述】:

在同一个类中我有两个重载方法:

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) 匹配.

我在第二个参数中传递了一个集合,为什么编译器不知道 去第二种方法?
如果我更改方法签名并从第一个参数中删除泛型,我将 没有出现编译错误,这是为什么呢?

【问题讨论】:

  • 因为&lt;T&gt; 也可以是Collection.. 这是一个和其他类型一样的类型。
  • Arraylist 不是Collection&lt;T&gt;
  • 不相关但不应该是T valueToAppend
  • 你使用了原始类型ArrayList。我认为这可能会导致问题。

标签: java


【解决方案1】:

这是我的解释。当编译器必须在重载之间进行选择时,它总是选择最具体的重载。当您从第一个参数中剥离类型信息时,签名变为

public static <T> void foo(Collection collection, T valueToAppend)
public static <T> void foo(Collection collection, Collection<T> valueToAppend)

其中第二个更具体。第二种方法可以接受的任何一对参数也可以被第一种方法接受,因为任何Collection 都是Object。因此,当您去掉类型参数时,没有歧义 - 如果您传递两个 Collections,则选择第二种方法。

但是使用类型信息,签名看起来像这样:

public static <T> void foo(Collection<T> collection, T valueToAppend)
public static <T> void foo(Collection<T> collection, Collection<T> valueToAppend)

这些签名中没有一个比另一个更具体。参数new ArrayList&lt;String&gt;()"Foo" 将被第一个签名接受,但不被第二个签名接受。参数new ArrayList&lt;String&gt;()new ArrayList&lt;String&gt;() 将被第二个签名而不是第一个签名接受。

所以如果两个签名都适用,那就有问题了。

您正在尝试传递原始ArrayListList&lt;Double&gt;。因为您使用的是原始类型 ArrayList(您永远不应该这样做),所以 ftList 可以作为 Collection&lt;T&gt; 传递 any T(试试看。尝试传递原始 @987654336 @ 到参数类型为List&lt;String&gt; 的方法。它有效)。因此,您只需要看到doubleList 匹配both 重载的第二个参数。如果TList&lt;Double&gt;,它匹配第一个签名,如果TDouble,它匹配第二个签名。

【讨论】:

  • 感谢您的详细解答。您能否解释一下为什么将原始类型 ArrayList 作为第一个参数传递不会自动将 定义为 Object?
  • @D.C 它将&lt;T&gt; 定义为对象。这是你的问题。
  • @Tom 但如果 是对象,那么我希望签名看起来像这样:public static void foo(Collection&lt;Object&gt; collection, Object valueToAppend) public static void boo(Collection&lt;Object&gt; collection, Collection&lt;Object&gt; valueToAppend)。但是这些签名不会导致编译错误。
  • @D.C 我猜原因如下。泛型直到 java 1.5 才存在,所以在此之前你必须写 List。然而即便如此,大多数Lists 是相同类型的对象的Lists,例如["foo", "bar"][1, 2, 3]。当他们引入泛型时,他们希望新代码能够与旧代码一起使用。他们希望第一个List 被需要List&lt;String&gt; 的方法接受,而第二个List&lt;Integer&gt; 被需要List&lt;Integer&gt; 的方法接受。使其工作的唯一方法是说List 可以作为List&lt;T&gt; 传递给任何T。如果它必须是List&lt;Object&gt;,它就行不通了。
【解决方案2】:

因为第二个参数&lt;T&gt; 也可能是Collection,解释器会混淆它是Collection&lt;T&gt; 还是&lt;T&gt;

【讨论】:

    【解决方案3】:

    编译器无法识别&lt;T&gt;Collection&lt;T&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多