Generic method with parameters vs. non-generic method with wildcards

Viewed 1558

According to this entry in the Java Generics FAQ, there are some circumstances where a generic method has no equivalent non-generic method that uses wildcard types. According to that answer,

If a method signature uses multi-level wildcard types then there is always a difference between the generic method signature and the wildcard version of it.

They give the example of a method <T> void print1( List <Box<T>> list), which "requires a list of boxes of the same type." The wildcard version, void print2( List <Box<?>> list), "accepts a heterogenous list of boxes of different types," and thus is not equivalent.

How do you interpret the the differences between the following two method signatures:

 <T extends Iterable<?>> void f(Class<T> x) {}
                         void g(Class<? extends Iterable<?>> x) {}

Intuitively, it seems like these definitions should be equivalent. However, the call f(ArrayList.class) compiles using the first method, but the call g(ArrayList.class) using the second method results in a compile-time error:

g(java.lang.Class<? extends java.lang.Iterable<?>>) in Test
    cannot be applied to (java.lang.Class<java.util.ArrayList>)

Interestingly, both functions can be called with each others' arguments, because the following compiles:

class Test {
    <T extends Iterable<?>> void f(Class<T> x) {
        g(x);
    }
    void g(Class<? extends Iterable<?>> x) {
        f(x);
    }
}

Using javap -verbose Test, I can see that f() has the generic signature

<T::Ljava/lang/Iterable<*>;>(Ljava/lang/Class<TT;>;)V;

and g() has the generic signature

(Ljava/lang/Class<+Ljava/lang/Iterable<*>;>;)V;

What explains this behavior? How should I interpret the differences between these methods' signatures?

4 Answers
Related