Generics are added in Java 1.5, and the details of generics are not discussed here, which is very clear in the fourth edition of Thinking in Java, which is about the super and extends keywords, and why there are different limitations when using these two keywords.
First, we define two classes, A and B, and assume that b inherits from a.
Packagecom.wms.test;Importjava.util.ArrayList;Importjava.util.List; Public classGeneric { Public Static voidMain (string[] args) {List<?extendsA> List1 =NewArraylist<a>(); //List1.add (New A ());//error, the compiler cannot determine the type that the list holds, so it is not safe to add objects to itA A = List1.get (0); List<?extendsA> List2 =NewArraylist<b>(); List<?SuperB> List3 =NewArraylist<b>(); List3.add (NewB ()); //to be right, you have to move down, but it's not safe to go down, it's very easy to make mistakes.//b b = list3.get (0);//The compiler cannot determine whether the object type returned by Get is B, or the parent class or object of B.list<?SuperB> List4 =NewArraylist<a>(); } } classa{}classBextendsa{}
It is easier to understand the meaning of the super and extends keywords from the above section of the code that created the list. One of the first things to illustrate is that Java enforces the need to make specific types of type parameters when creating objects, and cannot use wildcards, meaning new arraylist< Extends A> (), New arraylist<?> () This form of initialization statement is not allowed.
From the first and second lines of the main function above, we can understand the meaning of extends, and when creating ArrayList, we can specify a or B as the specific type. That is, if <? extends X> So when we create an instance, we can use X or a class that extends from X as a generic parameter as a specific type, or it can be understood as giving "?" Specifies a specific type, which is what extends means.
Similarly, the third row and the fourth line are explained, if <? Super X> When we create an instance, we can specify any superclass of x or X as the concrete type of the generic parameter.
When we use LIST<? Extends x> This form, invoking the list's Add method will cause compilation to fail, because when we create a specific instance, it may be that X is used as a subclass of X, and this information compiler has no way of knowing, and for arraylist<t For >, only one type of object can be placed. This is the nature of the problem. For a Get method, because we create an instance by using a subclass of X or X, and using a superclass to refer to subclasses in Java is legal, so the Get method can get a reference to an X type, of course, the reference can point to X or any subclass of X.
And when we use LIST<? When super x> this form, the Get method that calls list will fail. Because when we create an instance, we may use an X or a superclass of x, so when we call get, the compiler is not exactly aware of it. Instead of calling the Add method, because we created an instance using the superclass of x or X, it is certainly not a problem to add a subclass of X or X to the list, because a superclass reference can point to a subclass.
Finally, the two keywords appear because generics in Java do not cause the covariant nature of the feature.
Summary (still not very clear here, to be resolved)
extends 可用于的返回类型限定,不能用于参数类型限定。super 可用于参数类型限定,不能用于返回类型限定。>带有super超类型限定的通配符可以向泛型对象中写入,带有extends子类型限定的通配符可以向泛型对象读取。
What is Pecs?
Pecs refers to "Producer Extends,consumer Super". In other words, if the parameterized type represents a producer, the < is used; Extends t>; if it represents a consumer, use < Super T> Maybe you don't understand, but it's okay, then look down.
The following is a simple Stack API interface:
Public Interface Stack<e>{ public Stack (); Public void push (E E): Public E pop (); Public Boolean isEmpty ();}
假设想增加一个方法,按顺序将一系列元素全部放入Stack中,你可能想到的实现方式如下:
Public void Pushall (iterable<e> iter) { for(e e:iter) push (e);}
Suppose there is a stack<number> you want to flexibly handle a collection of subtypes of Integer,long and so on
New Stack<number>(); iterablenull; /* */ / error
Code compilation fails at this point because, for type number and integer, although the latter is a subclass of number, for any number collection (such as list<number>), it is not an integer collection (such as list< integer>), because generics are immutable.
Fortunately, Java provides a parameterized type called a finite wildcard, with the Pushall parameter replaced by the Iterable interface of a subtype of "E":
Public void extends E> iter) { for(e e:iter) push (e);}
This is called again at this time:
/**/ / correct
This can be compiled correctly, here the < Extends e> is the so-called producer-extends. Iterable here is the producer, to use < Extends E>. Because of iterable< Extends e> can accommodate any subclass of E. Each element of an iterative object can be manipulated as e when the operation is performed.
This corresponds to the assumption that there is a method Popall () method that pops each element from the stack collection and adds it to the specified collection.
Public void Popall (collection<e> c) { C.add (pop ());}
Suppose you have a stack<number> and collection<object> object:
New Stack<number>(); Collectionnull; /* * The method to be correct, must c for Collection<number> */ // error
The same above code can not be passed, the solution is to use collection< Super e>. The objects here is the consumer, as is the addition of elements to the objects collection. Use Collection<? After Super e>, no matter what type of objects is the collection, satisfies the point is that he is the superclass of E, so no matter what type of parameterized type can put E into the objects collection.
Public void Super E> c) { C.add (pop ());}
/**/stack.popall01 (c);
Comprehensive Code:
Packagecom.wms.test;Importjava.util.Collection; Public classGeneric { Public Static voidMain (string[] args) {Stack<Number> stack =NewStack<number>(); Iterable<Integer> iter =NULL; /** Code compilation cannot pass at this time, because for type number and integer, although the latter is a subclass of number, * but for any number collection (such as list<number>) is not an integer collection ( such as list<integer>), * Because generics are immutable. */Stack.pushall (ITER);//Error /** This can be compiled correctly, here the <? extends e> is called Producer-extends. * The iterable here is the producer, to use < Extends E>. * Because of iterable< Extends e> can accommodate any subclass of E. Each element of an iterative object can be manipulated as e when the operation is performed. */stack.pushall01 (ITER);//correctCollection<Object> C =NULL; /** The method to be correct, must c for Collection<number>*/Stack.popall (c);//Error /** The same above code can not be passed, the solution is to use collection<? Super e>. * The objects here is the consumer, as is the addition of elements to the objects collection. * Using Collection<? Super e>, no matter what type of objects is the collection, * to satisfy the point is that he is the superclass of E, so regardless of what type of parameterized type can be loaded into the objects set of E. */stack.popall01 (c); }} classStack<e> { PublicStack () {} Public voidpush (e e) {} Public voidPushall (iterable<e>ITER) { for(e e:iter) push (e); } Public voidPushAll01 (iterable<?extendsE>ITER) { for(e e:iter) push (e); } PublicE Pop () {return NULL; } Public voidPopall (collection<e>c) {C.add (pop ()); } Public voidPopAll01 (collection<?SuperE>c) {C.add (pop ()); }}
Talking about the extends and Super keywords in Java generics