Generic Type Resolution - Compiler Steps

2019-09-16 12:48发布

问题:

Assume the following methods (Java 8):

public <T> List<Class<T>> getList() {
  return new ArrayList<>();
}

public <T> List<T> getList2() {
  return new ArrayList<>();
}

And the following code using those methods:

@Test
public void testLists() {
  getList().add(String.class); // Does not compile
  this.<String>getList().add(String.class); // Compiles
  getList2().add(String.class); // Compiles
}

The second and third call compile fine, whereas the first one gives:

add(java.lang.Class<java.lang.Object>) in List cannot be applied to add(java.lang.Class<java.lang.String>)


I do not fully understand the resolution steps here, maybe someone could explain why I need the type witness and the compiler does not infer the type automatically?

回答1:

Because the compiler doesn't/cannot infer generic arguments based on future method calls.

In your case, when you call getList() or getList2() the type T is already inferred as Object. This means getList() will return you an List<Class<Object>> object and you cannot add a Class<String> object into it.

In your third statement, you have List<Object> so you are able to add a Class<String> to it.



回答2:

In a word, String is a Object, whereas Class<String> is not a Class<Object>

ref:javadoc



回答3:

use something like this in place of:

getList().add(String.class);

<String>getList().add(String.class);
for
 public <T> List<Class<T>> getList() {
  return new ArrayList<>();
}

Now when you call it, the parameter and return type must match.