tags:

views:

65

answers:

4

Why doesn't this work?

public class FooImpl implements Foo { /* ... */ }

public class Main {
    public static <T> Collection<T> getList(Class<? extends T> itemClass) { /* ... */ }

    public static void main(String[] args) {
        Collection<Foo> foos = getList(FooImpl.class);
    }
}

On the line where foos is declared, I'm getting "Incompatible types. Required: Collection<Foo>, found: Collection<FooImpl>" error. Any idea why?

+4  A: 

Try this :

Collection<Foo> foos = Main.<Foo>getList(FooImpl.class);

When you create your getList() method, it says that it will be Typed with T. And it also says that it will need a parameter of a subtype of T (a class of subtype of T to be precise).

As you never specify what will T be, getList suppose that it will be FooImpl so getList() returns a Collection of FooImpl.

With the solution I gave you, you specify that T is Foo, so the parameter will need to be a subtype of Foo. FooImpl for example.


Resources :

Colin Hebert
Accepting this answer as this is the only solution working in javac. For more elegant solution, refer to the answer of BalusC below
Sergey Mikhanov
+1  A: 

change getList return type to Collection<? extends T>

FooImpl is instance of a Foo

But

Collection<FooImpl> is NOT instance of Collection<Foo>

mohammad shamsi
Nothing has changed. Still, JVM chooses the most concrete class to assign to wildcard
Sergey Mikhanov
+3  A: 

Because it is returning a collection of FooImpl while you like it to return a collection of its supertype. You need to define that a bit more explicitly:

public class FooImpl implements Foo { /* ... */ }

public class Main {
    public static <S, T extends S> Collection<S> getList(Class<T> itemClass) { /* ... */ }

    public static void main(String[] args) {
        Collection<Foo> foos = getList(FooImpl.class);
    }
}

Update: I had to mention that there's a JLS/javac bug related to this which caused it not to compile when using "plain vanilla" javac. See also javac bug 6369605, JLS bug 6369608 and this related question. It works fine in Eclipe however.

If you insist in using the javac over Eclipse, then your safest bet until the Java guys get it fixed is indeed to manually force the return type in the method call as demonstrated by Colin Hebert.

BalusC
A: 

I agree with BaluC's answer.

Just for basic understanding of "extends" in generics check section The "extends" Wildcard Boundary

when using a wildcard with an upper bound it is not safe to write to the List. After all, a Car is always a Vehicle, but a Vehicle is not always a Car.

YoK