List and List are incompatible types i

2019-02-16 18:32发布

问题:

This question already has an answer here:

  • Cannot convert from List<List> to List<List<?>> 3 answers

I did not get this code to compile either way:

List<List> a = new ArrayList();
List<List<?>> b = new ArrayList();

a = b; // incompatible types
b = a; // incompatible types

It seems that java does not consider List and List<?> to be the same type when it comes to generics.

Why is that? And is there some nice way out?

Context

There is a library function with following signature: public <T> Set<Class<? extends T>> getSubTypesOf(final Class<T> type). This works fine for simple types passed as argument but in case of generics the result is not parametrized with wildcard causing javac to complain about raw type. I would like to propagate the result to the rest of my application as Set<Class<? extends GenericTypeHere<?>>> but simple cast does not work as I expect.

EDIT: Solution

Thanks for the answers, here is how I get it working in the end:

@SuppressWarnings({"rawtypes", "unchecked"})
private static Set<Class<? extends GenericTypeHere<?>>> factoryTypes() {
    return (Set) new Reflections("...").getSubTypesOf(GenericTypeHere.class);
}

回答1:

Okay, so this is due to a subtle semantic difference.

List

This is the raw type of List, which equates to T being of type Object. So it's the same as saying:

List<Object>

Now, the Compiler knows for a fact, that whatever happens, this is a subclass of type Object. And if you do..

List myList = new ArrayList();
myList.add(new Object());

It will work fine! This is because Object is the same or it is some derivation of the type.

List<?>

This is literally a list of unknown (Java Docs). We don't even know that the subclass of the things in here are of type Object. In fact, the ? type is an unknown type all on its own. It has nothing to do with Object! This is why when you try and do..

List<?> myList = new ArrayList<?>();
myList.add(new Object());

You get a compile time error!



回答2:

    List<? extends List> a = new ArrayList();
    List<? extends List<?>> b = new ArrayList();
    a = b;

works

Set<Class<? extends GenericTypeHere<?>>>

would imply Set<Class<YourClass extends AnotherClass<YourClass>>> as mentioned in the above wildcard answer

What stops you from using

Set<Class<YourClass extends AnotherClass>> to propagate throughout your app?