Compilation error for an ambiguous method reference when using a typed collection

In the same class, I have two overloading methods:

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

      

The next test should call the second method:

 @Test 
   public void testFoo() {
   ArrayList ftList = Lists.newArrayList();
   List<Double> doubleList = Lists.newArrayList(1.0, 2.0);
   foo(ftList, doubleList);
}

      

When I run the test, I get the following compilation error:

the reference to foo is ambiguous, and the foo (java.util.Collection, T) method in path.to.class and the foo (java.util.Collection, java.util.Collection) method in match.to.class match.

I am passing the collection in the second argument, so why doesn't the compiler know to go to the second method?
If I change method signatures and remove generics from the first parameter, I will not get a compilation error, why is that?

+3


source to share


3 answers


Here is my explanation. When the compiler has to choose between overloads, it always chooses the most specific overload. When you strip the type information from the first parameter, the captions become

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

      

The second one is more specific. Any pair of parameters that can be accepted by the second method can also be accepted by the first, since either Collection

is Object

. So when you remove the type parameter, there is no ambiguity - the second method is chosen if you pass two Collection

s.

However, with type information, the signatures look like this:



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

      

None of these signatures are more specific than the other. Parameters new ArrayList<String>()

and "Foo"

will be accepted by the first signature, but not the second. The parameters new ArrayList<String>()

and new ArrayList<String>()

will be accepted by the second signature, but not by the first.

So, if both signatures apply, then a problem arises.

You are trying to pass raw ArrayList

and List<Double>

. Since you are using a raw type ArrayList

(which you should never do) ftList

can pass as Collection<T>

for anyone T

(Try it. Try passing a raw List

method with a type parameter List<String>

. It works). Therefore you only need to see what the doubleList

second parameter matches for both overloads. It matches the first signature if T

- List<Double>

and matches the second signature if T

- Double

.

+3


source


Since the 2nd parameter <T>

can also be Collection

, the interpreter gets confused as to whether it is Collection<T>

or<T>



0


source


The compiler cannot identify between <T>

andCollection<T>

0


source







All Articles