List of object list for class type parameter list

I am trying to understand the various results of compiling seemingly similar code. Apparently, it is possible to distinguish List<Object> to List<T> , but only if T not limited to a particular class. So given ...

 List<Object> bis = new ArrayList<>(); 

The following are compiled in class Test<T> , as well as in class Test<T extends CharSequence> , but not in class Test<T extends BigDecimal> and class Test<T extends BigDecimal & CharSequence> .

 List<T> result = (List<T>) bis; 

So, where does the difference come from for T , limited by the class type and interface type?

Edit

Some complete code for the request. This compiles with a compiler warning on line 9. This is really unsafe because it works on result elements, as if they were CharSequence instances, resulting in a ClassCastException .

  public class Sandbox<T extends CharSequence> { public static void main(String[] args) { new Sandbox<CharSequence>().foo(); } private void foo() { List<Object> bis = Arrays.asList(Integer.valueOf(1)); List<T> result = (List<T>) bis; System.out.println(result); } } 

However, this does not compile at all:

  public class Sandbox<T extends BigDecimal> { public static void main(String[] args) { new Sandbox<BigDecimal>().foo(); } private void foo() { List<Object> bis = Arrays.asList(Integer.valueOf(1)); List<T> result = (List<T>) bis; System.out.println(result); } } 

Compiler error on line 9: Cannot apply List<Object> to List<T> .

+5
source share
2 answers

well, this List<Object> bis = Arrays.asList(Integer.valueOf(1)); obviously does not compile because Arrays.asList(Integer.valueOf(1)) will return List<Integer> , so you get Cannot cast List<Object> to List<T> .

The second case, eclipse is absurdly compiled using T extends CharSequence , but I checked it with an online compiler and it does not compile, so it is quite possible that this is an eclipse error.

0
source

The key to understanding this behavior is understanding what the erasure type really does. Despite the widespread belief that it removes type parameters at run time - in fact, this does not work that way. What he does is he reduces them to the declared parameter boundaries. Therefore, wherever you type List<T> , where T has borders, it actually comes down to List<[lower-bound-of-T]> . And since Object not CharSequence , List<Object> cannot be added to List<T> (since this means at least List<CharSequence> )

Why is this happening? Imagine your Sandbox class has a method that accepts a parameter of type T:

 public class Sandbox<T extends CharSequence> { void bar(T param) { //... } } 

bar(T) can take T and T is all that extends CharSequence , so basically at runtime it works effectively as

  void bar(CharSequence param) { //... } 

and therefore, it cannot accept simple Object . Therefore, simply existing non-empty lower bound of the parameter limits free discards from ...<Object>

Also, a wildcard type parameter ? may just blow your mind. He tells the compiler something like, "I have no idea what it is, but I'm sure it satisfies all boundaries." Quite strange, including the fact that you can use (almost?) Anything, so it makes it possible

  List<Object> bis = Arrays.asList(Integer.valueOf(1)); List<T> result = (List<T>) (List<?>) bis; 

So, when it comes to the generic development class, you have to be very careful.

0
source

Source: https://habr.com/ru/post/1236088/


All Articles