Java generics boundary problem, super keyword

Don't take super literate meaning

The super keyword is used in a method of a class to indicate a reference to an object of the parent class.
Indicates a generic lower bound in the generic bound syntax.

Suppose there is an inheritance relationship, A<-B<-C<-D<-E

   void f( List<? super C>  param){...}

Indicates that this is a parent class of , , , and for methods that are accepted List<B>as List<A>parameters List<C>, when passing the above four types, it can be implicitly upcast and safe. In the method, the items taken out are of type Object, and the types taken out are all Objects, not C or other specific classes .List<Object>List<? super C>fList<? super C>

If the item that needs to be cast out is a specific type, the programmer himself guarantees that the objects in the List can be safely cast. The best application scenario is that there is no need to deal with specific types of items, and the second is that the programmer himself ensures that all items can be safely cast.

List<D>, List<E>cannot be passed to f, and even cast cannot compile. This is what the generic rules dictate: they have no parent-child relationship with List<B>, List<A>, .List<C>

within the method

     List<? super C>  param;
     param.add(new B());// ERROR
     param.add(new Object());//ERROR
     param.add(new D());//right

List<? super C>The storage restrictions are large and seem a bit odd: any C superclass and any object of type C cannot be stored, and subclasses of C can. List<...>It seems to contradict the father -son relationship laid out in the previous section .

Let's talk about the conclusion first: The generic type restricted by super is not suitable for storage, only suitable for consuming it

    PECS(producer extends,Consumer super)规则。
  • Why does List<? super C> param take out Object instead of concrete type?

Because when declaring param, only this param is required to be List<? super C>, the translation into human language is to declare that param is one of List<B>, List<A>, List<C>, List<Object>or List<? super B>, List<? super A>and it cannot be guaranteed which specific one is, so the compiler cannot guarantee The items taken out are all of the same specific type. If the programmer himself can guarantee that the item of the same specific type is passed in, he will cast it himself, but the compiler can only simply agree on the Object type taken out List<? super C>from it .

  • Why can't I List<? super C>store the AB Object type, but I can store C and DE?

Because storing the AB or Object type may destroy the type consistency of the original List, it is to avoid this problem that the generic feature was introduced in JDK5, so it cannot be allowed. When stored in a subclass of C, implicit conversion to C can ensure that the consistency of the item type in the List is not destroyed.

  • Since there is no guarantee that the items taken out are of the same specific type, what is the use of super?

Super does not restrict fwhich specific List<..> it accepts, and also makes certain restrictions, which cannot be Lists other than List<B>, List<A>, List<C>, List<Object>or List<? super B>. List<? super A>If you pass an List<?>unbounded cast it's another matter.

Scenario (for some reason, the item list of subclass DE does not need to be processed by f):

    void f( List<? super C>  param){
        if(param.get(0) instanceof A){
            for(Object item : param){
                A a = (A)item;
                a.doAsA();
            }
        } else(param.get(0) instanceof B){
             for(Object item : param){
                B b = (B)item;
                b.doAsB();
            }
        }
    }
    

The above scenario code is still a bit far-fetched, and I didn't think of the actual application scenario. This may also be the shortcoming of the Java feature that the keyword super restricts the generic lower bound, but it is not a bad thing to provide an option other than extends.

extends

The PECS rule states that extends is used when producing items to generics.

    List<? extends C>  void f(){
        List<? extends C> ret = getNewList();
        for(int i =0; i<10; i++){
            ret.add(new C());
            ret.add(new D());
        }
        return ret;
    }

The calling fcode can get a List, and the compiler ensures that the items in the List are all C types. It's easier to understand, it seems that extends is more powerful, is there a better scenario to use super than to use extends to limit the boundaries of generics?

Probably when the upper bound does not need restrictions, then if you use <? extends Object>, then it is equivalent to no restrictions.
So super is not completely replaceable by extends, one more option is better.

Replenish

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325221334&siteId=291194637