4

I have a utility method that creates a one-element list out of some object:

public static final <T> List<T> list(T t) {
    final List<T> rv = new ArrayList<>();
    rv.add(t);
    return rv;
}

I also have a method that accepts an argument of type List<Class<?>>. So I have to create an object of that type. Here's what I try to do:

final Class<?> aClass = Integer.class;
final List<Class<?>> trivialListOfClasses = list(aClass);

… this fails with:

[javac] /some/path/Foo.java:41: error: incompatible types
[javac]             final List<Class<?>> trivialListOfClasses = list(aClass);
[javac]                                                                  ^
[javac]   required: List<Class<?>>
[javac]   found:    List<Class<CAP#1>>
[javac]   where CAP#1 is a fresh type-variable:
[javac]     CAP#1 extends Object from capture of ?
[javac] 1 error

What's the proper way to accomplish the above? I understand the part about Java generics being invariant but what exactly is going on here?

Marcus Junius Brutus
  • 26,087
  • 41
  • 189
  • 331

3 Answers3

6

Was able to reproduce with -source 7 -target 7 on javac 1.8.0_144.

One thing that works if you're only planning to take things out of the list is to use ? extends Class<?>:

Class<?> aClass = Integer.class;
List<? extends Class<?>> trivialListOfClasses = list(aClass);
Class<?> bClass = trivialListOfClasses.get(0); // works
// trivialListOfClasses.add(String.class); // doesn't work, though

What also works is to manually supply the generic type in the call to list:

Class<?> aClass = Integer.class;
List<Class<?>> trivialListOfClasses = Util.<Class<?>>list(aClass);
Class<?> bClass = trivialListOfClasses.get(0); // works
trivialListOfClasses.add(String.class); // also works

It seems that the compiler just isn't able to reconcile the wildcard type of List<Class<?>> with the one returned by list on it's own.

Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93
1
final List<Class<?>> trivialListOfClasses = list(aClass);

works in Java 1.8 and 9

final List<?> trivialList = list(aClass);
@SuppressWarnings("unchecked")
final List<Class<?>> trivialListOfClasses = (List<Class<?>>) trivialList;

is a workaround for 1.7. Seems like the 1.7 compiler cannot verify the type returned from list(T t) is dependent on T

qwerty
  • 171
  • 1
  • 11
-2

There is a oracle javadoc i'am not so sure about either but it works in java 8. And 9 is just out ;)

public static void main(String [] args) throws Exception {
    final Class<?> aClass = Integer.class;
    final List<Class<?>> trivialListOfClasses = Program.list(aClass);

}

public static final <T> List<T> list(T t) {
    final List<T> rv = new ArrayList<>();
    rv.add(t);
    return rv;
}