In the last video, I covered the principles and basic usage of generics in Java. In this article, I will cover the more advanced aspects of generics: wildcards, PECS principles, and type erasers.

1. Type wildcard

Type wildcard: Err… Just one, right? . You can write List when you’re sure that the set is of a certain type, and List<? >. It can also be represented by other letters, such as E — Element, which is used in Java Collection. List,Iterator,Set K,V – Key, Value, N – Number, T – Type, Type, such as String, Integer, etc. These are just common conventions and don’t need to be remembered. We can use any of the 26 letters. As for? The difference with letters is that, in the Java Collections framework, parameter values are of unknown type (i.e., “? Wildcard), can only be read, cannot be added or deleted, because the compiler does not know its type, except for NULL. The following code compiles in error

List<? > list=new ArrayList<String>();
Copy the code

List is a borderless wildcard. If you add String to an l of unknown type, the compiler will report an error. If you add NULL, the compiler will not report an error. In general, there are three types of wildcards:

  1. Borderless wildcard :
    is? , such as the Set
    , List
    , the Map
List<? > l=newArrayList(); Set<? > s=new TreeSet();
Copy the code
  1. Subclass qualified wildcards :
    indicates the ability to accept data of the specified class and its subclass types. Ask to
    must be E or a subclass of E.
public static void c(List<? extends String> l){
public static void main(String[] args) {
		List<Integer> l1=new ArrayList();
		List<String> l2=new ArrayList();
		//error:The method c(List<? extends String>) in the type TestT is not applicable for the arguments (List<Integer>)
Copy the code
  1. Superclass qualified wildcards :
    indicates the ability to accept data of the specified class and its superclass type. > must be E or E’s parent.
public static void superD(List<? super Integer> s){
List<String> lString=new ArrayList();
List<Object> lObject=new ArrayList();
//error: The method superD(List
      ) in the type TestT is not applicable for the arguments (List
Copy the code

2. The principle of PECS

PECS is written as “Producer Extends, Consumer Super”, which means that producers use Extends when they act as producers and Super when they act as consumers. What the hell?? If you don’t understand, let’s look at the following example:

List<? extends Ineteger> fe = new ArrayList();		
List<? super Ineteger> fs=new ArrayList();

//The method add(capture#5-of ? extends Object) in the type List<capture#5-of ? extends Object> is not applicable for the arguments (String)
// Producer operations
// Consumer operations
for (Integer s : fe) {
for (Integer s : fs) {
Copy the code

If fe.add () is used as a producer action to add String data to the collection, the compiler will raise an error: Since Java does not allow indefinite types to be added to a collection as subclasses of Integer, the compiler does not know exactly what subtype FE is being added to, so it will raise an error. That would be an error when reading the contents of the list, because Java simply limits the rule to the front. In the case of consumer operations, fs traverses the data, because the data type is Integer or its parent, so <? > does not know which type, so the compiler will report an error. The PECS principle is that the compiler must know the type of a production or consumption operation. From the above example, we can sort out the rules:

  1. If you want to read data of type T from the collection and cannot write to it, you can use? Extends wildcard; (Producer Extends)
  2. If you want to write data of type T from a collection and do not need to read, you can use? Super wildcard; (Consumer Super)
  3. Do not use any wildcards if you want to both save and take

3. Type erasure:

In JDK1.5, generics were introduced to reduce type casting and increase the safety of parameter types. However, generics are scoped at compile time. After compile, all generic parameter types are removed, which is called type erasure. Let’s look at some code:

List<String> listString=new ArrayList();
List<Integer> listInteger=new ArrayList();
// Output: class java.util.arrayList
// Output: class java.util.arrayList
// Output: true
Copy the code

The code above concludes the following:

  1. ListString and listInteger are not subclasses of ArrayList; they are both ArrayLists
  2. ListString and listInteger both point to the same memory address

Thus, generics exist only at compile time, their types are erased at run time, and there is no such thing as a superclass or subclass of generics.

Find this article helpful? Please share it with more people

Focus on “programming without boundaries” and improve your skills