tags:

views:

268

answers:

3

I have a class defined like so:

public class Test {
    static <T> List<Class<T>> filter(List<Class<T>> input) {
        // code here
    }

    public static void main(String[] args) {
        List<Class<? extends Throwable>> list =
            new ArrayList<Class<? extends Throwable>>();
        filter(list);
    }
}

The filter method call in main gives the following compile error:

The method filter(List<Class<T>>) in the type Test is not applicable for the
arguments (List<Class<? extends Throwable>>)

I don't understand why <T> doesn't bind to <? extends Throwable>. Are there any generics gurus who can help me?

+3  A: 

Ah, the joys of generic signatures.

You can fix it by declaring the parameter as:

static <T> List<Class<T>> filter(List<Class<? extends T>> input) {
    // code here
}

As to exactly why, I'm not sure. Too many compilation problems with generics are fixed by trying various things until the red line goes away. Not satisfying.

skaffman
Might worth checking out http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
kd304
That fixes the error when calling the method (although I don't understand why), but now I have an error inside the method. Basically, I have a `List<Class<T>>` that holds the result, and I can't add entries to it because `Class<? extends T>` cannot be converted to `Class<T>`. That much, at least, makes sense to me. I changed the method to return `List<Class<? extends T>>`, as well, and that compiles. It's weird, but it works.
Adam Crume
The O'Reilly "Java Generic and Collections" book (http://oreilly.com/catalog/9780596527754/) is also a great investment if you want to understand how generics work.
skaffman
+3  A: 

I believe the problem here is that there is no type for ? that would do.

Consider if we, for simplicity, replaced Class with AtomicReference.

static <T> void filter(List<AtomicReference<T>> input) {
    T value = input.get(0).get();
    input.set(1).set(value);
}

If the input consisted of an AtomicReference<Integer> and an AtomicReference<String> we would be in trouble.

The underlying problem that pointers to pointers in the presence of polymorphism is difficult. Without generics we can just hand wave. With generics we need to actually mean something.

Tom Hawtin - tackline
Nice example. It's beginning to make a glimmer of sense.
Adam Crume
A: 

you can also write main as below :

public static void main(String[] args) {
    List<Class<Throwable>> list =
        new ArrayList<Class<Throwable>>();
    filter(list);
}
mjalil