Brief
Everyone in the ordinary work of study, certainly met many of the following statements:
list<? Super t>
list<? extends t>
As we all know, the above code is about Java generics, so what's the difference between these two different ways of writing?
First, when it comes to Java generics, we have to mention the type erasure mechanism of Java generics: Generics in Java are basically implemented at the compiler level. Type information in the generated Java byte code that does not contain a generic type. The type parameters that are added when using generics are removed by the compiler at compile time. This process is called type erasure. Types such as list<object> and list<string>, defined in code, become a list after compilation, and the JVM sees only the list, while the type information attached by generics is not visible to the JVM.
When using generic classes, we can use a specific type, for example, to define an List<integer> object, and our generic argument is Integer; we can also use wildcard characters to represent an unknown type, such as List<?> Indicates that a generic parameter is a type, except that we do not know what its specific type is. What
List<?> declares is that all types are acceptable, but it is important to note that list<?> is not equivalent to List<object> for list<object>, it actually determines the The list contains object and its subclasses, and we can use the object type to receive its elements. List<?>, in contrast, indicates that the element type contained therein is indeterminate and may contain String or Integer. If it contains a String, it is an error to add an Integer element to it. In contrast, we can add a String element to a list<object>, or you can add elements of the Integer type, because they are all subclasses of Object.
Just because the type is unknown, we cannot create a new ArrayList object by means of the new arraylist<?> (), because the compiler cannot know what the specific type is. But for the elements of list<?>, we can all Use object to receive because, although the type is unknown, it must be object and its subclasses.
As we mentioned above, the elements in list<?> can only be referenced using Object, which is not convenient for sure, but fortunately, the Java generics mechanism allows us to restrict the upper and lower bounds of the types of generic parameters, such as list<. Extends number> defines the upper bound of a generic as number, that is, the element type contained in the List is number and its subclasses. and list<? Super number> defines the lower bound of a generic, that is, the list contains number and its parent class.
When the upper and lower bounds of generic parameters are introduced, it is relatively convenient for us to write code, but also introduces a new question: When do we use the upper bounds, when to use the lower bound, and what are their differences and limitations? Let me say my understanding. ? extends T
? Extends T describes the upper bounds of the wildcard character, that is, the specific generic parameter needs to satisfy the condition: the generic parameter must be of type T or its subclass, for example:
list<? Extends number> Numberarray = new arraylist<number> (); Number is list< of number type
; extends number> numberarray = new arraylist<integer> ();//Integer is number The subclass
List< extends number> numberarray = new arraylist<double> (); Double is a subclass of number
All three of these actions are valid because the extends number specifies the upper bound of the generic wildcard character, that is, our actual generic must be a number type or its subclass, and number, Integer, and Double are obviously Numb Subclasses of ER (same type, that is, we can think of number as a subclass of number). Subtype Judgment
Suppose there are type G, as well as superclass and subclass two classes, and superclass is subclass's parent class, then: G<? Extends subclass> is g<? The subtype of the extends superclass>. such as List<? Extends integer> is list<? The subtype of extends number> g<superclass> is g<? The subtypes of extends superclass>, such as list<integer>, are list<? The subtype of the extends integer>. G<?> and g<? Extends object> equals.
can imagine g<? Extends T> is a left-closed interval (T on the far left), G<. Extends object> is the largest interval, when the interval g<? Extends superclass> contains interval g<? When extends subclass>, the larger interval is the parent class. about reading
According to the above example, for list<? Extends number> Numberarray object: We are able to read the number object from the Numberarray because the element contained in the Numberarray is a subtype of number or number. We cannot read the Integer type from the Numberarray because the Double type may be saved in Numberarray. Similarly, we cannot read the Double type from the Numberarray. about writing
According to the above example, for list<? Extends number> Numberarray object: We cannot add number to Numberarray because Numberarray may be list<double> type We cannot add an Integer Into Numberarray because Numberarray could be list<double> type We can't add Double to Numberarray because Numberarray might be list<inte Ger> type
That is, we cannot add any object to the list<? Extends t>, because we cannot be sure of a list<? Extends t> the actual type of object, so it is not possible to determine whether the type of the inserted element matches this List. list<? Extends t> the only guarantee is that the elements we read from this list must be of type T. ? Super T
? Super T describes the bounds of the wildcard character, that is, the specific generic parameter needs to satisfy the condition: the generic parameter must be of type T or its parent class, for example:
Here, the integer can be considered to be an integer "parent"
list< super integer> array = new arraylist<integer> ();
Number is the parent class of Integer
list< Super integer> array = new arraylist<number> ();
Object is the parent class of Integer
list< Super integer> array = new arraylist<object> ();
about reading
For the list< in the above example;? Super Integer> Array Object: We cannot guarantee that the Integer type of data can be read from the array object because the array may be of type list<number>. We cannot guarantee that data of number type can be read from the array object because array may be of type list<object>. The only guarantee is that we can get an instance of an object from the array. about writing
For the list< in the above example;? Super Integer> Array Object: We can add an integer object to an array, or you can add an integer subclass object to an array. We can't add double/number/object wait, not inte. The object of the GER subclass to the array. easy to confuse points
One thing to note is that list<? Super t> and list<? Extends t>, what we call xx is a parent of T (a superclass of T) or a subclass of T (a subclass of T) is actually for generic parameters. Consider, for example, the following examples:
list<? Super integer> L1 = ...
list<? Extends integer> L2 = ...
So here? Super Integer and? Extends is the limit of the Integer to whom? Is that we can insert any object x into L1, as long as X is the parent of the Integer? Is that we can insert any object y into L2 as long as Y is a subclass of Integer?
Not really, we have to discard the above concept,? Super Integer and? Extends the Integer limit is actually a generic parameter, that is, list<? The Super integer> L1 indicates that the generic parameter T of L1 must satisfy T is the parent class of Integer, so such as List<object> The List<number object can be assigned to L1. because we know. The boundary information for the generic parameter in the L1, so we can add an Integer object to the L1, and the inference process is as follows:
T is the generic parameter of the L1, that is,
L1 = list<t> = list<? Super Integer>
Therefore, there is a parent class of Integer or Integer.
If T is Integer, then L1 = List<integer>, obviously we can add any integer object or integer subclass object to L1.
If T is the parent of an integer, then similarly, for an integer or an integer subclass, we can add it to the L1.
According to the same analysis method, list<? The extends Integer> L2 represents a L2 generic parameter that is a subtype of Integer. And if we're going to insert an element into a list<t>, we need to make sure that this element is a subclass of T or T, and here list<. Extends integer> L2, what type of generic parameter L2 is we don't know, and then we can't determine what subclasses of the L2 generic arguments are, so we can't add any elements to the L2.
To a contrast: for list<? Super integer> L1: Correct understanding:? The Super Integer defines a generic parameter. If the generic parameter of the L1 is T, then T is a subclass of integer or integer, so the object of the subclass of Integer or integer can be added to the L1. Wrong understanding:? The Super Integer qualifies the type of the inserted element, so as long as the object of the parent class of integer or integer can be inserted into the L1 for list< Extends integer> L2: Correct understanding:? The extends Integer defines a generic parameter. So that the generic parameter of L2 is T, then T is a subclass of integer or integer, and we cannot find a class X so that X is a subclass of the generic parameter T, so we cannot add elements to the L2. But since we know that the generic parameter T is a subclass of integer or integer, we can read the element from the L2 and store it in the integer. Wrong understanding:? The extends integer defines the type of the inserted element, so as long as the object of the subclass of Integer or integer can be inserted into the L2 to use the scene
Pece principle: Producer Extends, Consumer Super Producer Extends: If we need a list to provide data of type T (that is, we want to read the T-type data from the list), then we need to use the ? Extends T, for example list<? Extends Integer> But we can't add data to this List. Consumer Super: If we need a list to consume T-type data (that is, we want to write T-type data to the list), then we need to use Super T, such as list<? Super Integer>. But this List does not guarantee the type of data that is read from it. If we want both to read and to write, then we must explicitly declare the type of the generic parameter, such as List<integer>
Example:
public class Collections {public
static <T> void copy (LIST<? super t> dest, list<? extends t> src) c3/>{for
(int i=0; i<src.size (); i++)
Dest.set (I,src.get (i));
}
The above example is a copy of the data code, SRC is list<? Extends t> type, so it can read out the data of T type (or its subclasses), Dest is list<? Super t> type, so it can write to the data of the T type or its parent class. Reference
Java Depth Adventure (v)--java generics
Difference-between-super-t-and-extends-t-in-java