简体   繁体   中英

Need help in understanding Java tutorial on Generics

I was reading a Java tutorial from here . I am having trouble understanding a simple line.

Tutorial says declaration of Collections.emptyList is:

static <T> List<T> emptyList();

So if we write List<String> listOne = Collections.emptyList(); , it works as the Java compiler is able to infer the type parameter, as the returned value should be of type List<String> .

Now consider a method: void processStringList(List<String> stringList) . Now it states:

processStringList(Collections.emptyList()); The Java SE 7 compiler generates an error message similar to the following:

List<'Object> cannot be converted to List<'String>

The compiler requires a value for the type argument T so it starts with the value Object. Consequently, the invocation of Collections.emptyList returns a value of type List<Object> , which is incompatible with the method processStringList

Now what do they mean by: so it starts with the value Object ? I mean start doing what?

Basically this is about the capabilities of the compiler. In other words: to a certain degree, the "amount" of possible type inference is an implementation detail.

With Java 7, you sometimes have to use type helpers/hints/witnesses, where you would go Collections.<String>emptyList() to tell the compiler about that missing part.

Later implementations of the compiler improved the situation that you can almost always go with Collections.emptyList() .

Regarding The compiler requires a value for the type argument T so it starts with the value Object. ... that is actually quite simple: the java compiler has to implement an algorithm, that finally, infers a specific type. Giving some pseudo-code, that might look like:

Class<?> inferType(SomeSyntaxTree construct) {

I am just using Class here to indicate that the algorithm will return something that resembles a known type. Now, that method could be implemented like this:

 Class<?> inferedType = Object.class
 while (whatever) {
   refine inferedType
 }
 return inferedType

In other words: that is a very common approach when you "search" for some value: you initialize with the "most generic" value (in the Java type system, that would be Object.class), and then you see if that generic value can be refined by applying whatever algorithm.

In our case, the refinement might end up in figuring "the most specific type that can be used is String ", but if no further refinement is possible, then you end up with your "initial default", being Object .

The statement

processStringList(Collections.emptyList());

works fine in Java 8 (I'm assuming above 8 as well). The compiler in this case is smart enough to infer the types by checking what is the expected argument type for the method.

In older versions, when compiler sees no explicit return type (as in List<String> listOne = Collections.emptyList(); ), it by default infers <T> to java.lang.Object . But note that List<Object> and List<String> are not compatible.

You can declare the method like void processString(List<? super String> list) to avoid the error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM