Explicit Java Generics Behavior

It's hard to explain in words, but Java Generics give me an unexpected result. I expected that if I say that the list is of type ? extends Object ? extends Object , I could store something there. Therefore, if the list is of type Wrapper<? extends Object> Wrapper<? extends Object> , I could store any Wrapper there. And so on. That makes sense to me. But suppose we have:

 private static class Wrapper<T> { public Wrapper(T t) { /**/ } } 

And I want something like:

 private static final List<Wrapper<Wrapper<? extends Object>>> ls1 = new ArrayList<>(); 

Please note that this gives me an error:

 public static <T> doit(T t) { Wrapper<Wrapper<T>> l1 = new Wrapper<>(new Wrapper<>(t)); ls1.add(l1); // nok // add (Wrapper<Wrapper<? extends java.lang.Object>>) in List // cannot be applied to (Wrapper<Wrapper<T>> } 

But if I put Wrapper in a secondary Wrapper (rs), then:

 private static class C<T> extends Wrapper<Wrapper<T>> { public C(T t) { super(new Wrapper<>(t)); } } private static final List<C<? extends Object>> ls2 = new ArrayList<>(); public static <T> doit(T t) { ls2.add(new C<>(t)); // ok } 

Note that this is one and the same; it makes no sense to me.

PS. In my case, I am not creating a wrapper wrapper, but a ThreadLocal class of a general class.

+6
source share
3 answers

I think,

 ? extends Object ---> equals ? 

You can do it as follows:

 List<Wrapper<Wrapper<?>>> ls1 = new ArrayList<>(); And Wrapper<Wrapper<?>> l1 = new Wrapper<>(new Wrapper<>(t)); ls1.add(l1); // OK 
+2
source

Honestly, I would have to study it in more detail, why this will not work. Most likely, this is due to the erasure of the generic type. I have a workaround, I know that this solution is losing type for object l1. If this is normal, take it.

 Wrapper<Wrapper<? extends Object>> l1 = new Wrapper<>(new Wrapper<>(t)); ls1.add(l1); 
0
source

Basically you need to decide, more importantly, to be general in comparison with what you want to put in the wrapper, on top of or what you take out of the wrapper (you cannot safely both). After making the decision, you will need to choose between extends and super .

If you just want to keep the pointer, then List<Wrapper<Wrapper>> will be enough, but then you will need to do some casting later.


When you use extends , then ? extends Foo ? extends Foo means that any data type returned by the structure will be a subtype of type Foo (or Foo ).

For example, if you have void doIt1( List< ? extends Mammal> l ){} , you can pass List<Human> , List<Primate> , List<Simian> or List<Mammal> .

However, when using ? extends ? extends you don’t know what you can safely insert.

Consider this:

 void addElephant( List< ? extends Mammal> l ){ l.add( new Elephant() ); //wrong! } 

This is clearly unsafe ! I could go to List<Human> as l , and now my Human list has an Elephant in it!

On the other hand, you have super , where ? super Foo ? super Foo means the container can accept Foo .

So, for void doIt2( List< ? extends Human> l ){} , how could you go to List<Human> , List<Primate> , List<Simian> , List<Mammal> or List<Object> .

 void ( List< ? super Human> l ){ l.add( new Human() ); } 

And that's fine, but you can’t guarantee anything about what you choose from the container.

 void ( List< ? super Human> l ){ Human h = l.get(0); //wrong! } 

This is because if l really was a List<Primate> , it could have a mixture of Human and Gorilla , and there is no guarantee that the first element will be Human .

To do this, you will get the abbreviation PECS = "[a] P roducer ** E xtends, [but a] C onsumer S.

If you the container returns the object to the method (for example, get ), then you are a "production" (therefore use extends ), otherwise, if you take elements (for example, add ) to the container, the container "consumes" the object, so use " super". ( Nb :) , to remember PECS, it is that it is from the point of view of the container, not the calling code!).

If you want to produce and consume, you will need to have a specific list of List<Primate> types, where you can add Human and get Primate s.


See also:

0
source

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


All Articles