Explanation and Example of Java Generics

  • 2021-12-11 07:38:35
  • OfStack

Directory 1. Use of generics 2. Definition of generic classes-type boundaries 3. Type erasure 4. Use of generic classes-wildcards 5. Generic methods 6. Restrictions on generics

1. Use of generics

When we studied collections earlier, we briefly talked about the use of generics. As follows:


ArrayList<Integer> list = new ArrayList<>();
Queue<Integer> queue = new LinkedList<>();

So the use is so simple, what should we pay attention to?

Types in angle brackets can only be written as reference types If the basic data type, you need to write the corresponding wrapper type Generics are only a mechanism at compile time, and there is no concept of generics at runtime.

2. Definition of generic classes-type boundaries

There is another point about generics: 泛型的上界 . (Type parameter extends type boundary) has the following code:


public class Algorithm<T extends Comparable<T>> {
    public T findMax(T[] array) {
    
	}
}

In the above code, the function of the method is to pass an array in and ask to return the maximum value in this array.

At this time, the problem comes. Generic type is T type. When calling this method, the parameter type passed in the past is not 1, which is a simple data type. So how to judge the size at this time? ? ?

In this case, the function of this generic writing is: T extends Comparable, which is called 泛型的上界 When passing a parameter type, the parameter type must be passed in the past and must be a type that implements the Comparable interface. In other words, the types passed in the past must be comparable.

When we define a class Node and then implement the Comparable interface, we can call the above methods.

切记,这样写的泛型,传递过去的参数类型,必须是实现了Comparable接口的,当然也可以传递Comparable接口本身 .

3. Type erasure

The type erase value is: When the code is compiled, all generic T will be erased to Object type. The following code:


ArrayList<Integer> list = new ArrayList<>();

The above 1 line of code, although written in type Integer at this time, will automatically erase Integer to Object after compilation. That's what it looks like: ArrayList.

Then some students may wonder. Anyway, they have to be erased as Object type. Then why do you need generics? ? ?

That's because with generics, you can check the type when compiling, just like the above code, which is written as Integer type, so the parameter type passed in the past must be Integer type before compiling. Type checking is done, and when using get method to get a certain value, the data will be automatically converted from Object to Integer.

All of the above just explains the erase mechanism of writing only T type. Then use 泛型的上界 If so, JVM will not be directly erased as Object type, but what type is the upper bound, just erase why type. For example


public class Algorithm<T extends Comparable<T>> {
    
}

In the above code, the upper bound is Comparable interface, so the formal parameter part of this code is only this interface at most, that is to say, the ceiling is this interface. At this time, when JVM is erased, it can be erased directly to Comparable interface type.

Summary: Type erasure mainly depends on the boundary of the type.

4. Use of generic classes-wildcards

In generics, Known as wildcards. There are the following codes:


public class MyArrayList<E> {
    // Custom 1 Category 
}

//main Method in the 1 A common method 
public static void printAll(MyArrayList<?> list) {
    // Print the passed parameters list
}

The above code may seem strange to everyone. Simple analysis 1:

MyArrayList type, programmer-defined a class, using generics.

The printAll method needs to print the data of MyArrayList, but MyArrayList is a separate java file, while printAll method is in main method. There is no connection between them. At this time, when printAll is called, the formal parameter part cannot be defined.

At this time, you can only use MyArrayList < ? > Type is part of the formal parameter. If defined in this way, MyArrayList and printAll methods of whatever type are passed can be received.

There is the following calling code:


public static void main(String[] args) {
    MyArrayList<String> list1 = new MyArrayList<>();
    MyArrayList<Integer> list2 = new MyArrayList<>();
    MyArrayList<Double> list3 = new MyArrayList<>();
    
    printAll(list1); //String Type 
    printAll(list2); //Integer Type 
    printAll(list3); //Double Type 
}

The above code will not report errors when running. The printAll method, which can receive instance objects of all types of MyArrayList classes.

Upper bound of wildcard character: < ? extends upper bound >


public static void printAll(MyArrayList<? extends Number> list) {
    
}

The above code is based on the original code, adding an upper bound. The original code can accept any type of MyArrayList instance object. When an upper bound is added here, it means that this method can only accept this upper bound type and all subclass types of the upper bound.

Take the above code as an example, the upper bound is Number type, so the formal parameter type that this printAll method can only receive is Number or Number subclass type.


public static void main(String[] args) {
    MyArrayList<String> list1 = new MyArrayList<>();
    MyArrayList<Integer> list2 = new MyArrayList<>();
    MyArrayList<Double> list3 = new MyArrayList<>();
    
    //printAll(list1); 
    //String Type , At this time String Type will report an error because String No Number Subclass of 
    
    printAll(list2); //Integer Type 
    printAll(list3); //Double Type 
}

As in the code above, MyArrayList of type String, calling the printAll method, will report an error because String is not a subclass of the Number class.

Similarly, if there is an upper bound of wildcards, there is also a lower bound of wildcards.

Lower bound of wildcard character: < ? super lower bound >


public static void printAll(MyArrayList<? super Integer> list) {
    
}

Similarly, the type of MyArrayList instance object passed in the past can only be Integer type or parent class of Integer type.


public static void main(String[] args) {
    MyArrayList<String> list1 = new MyArrayList<>();
    MyArrayList<Integer> list2 = new MyArrayList<>();
    MyArrayList<Double> list3 = new MyArrayList<>();
    MyArrayList<Number> list4 = new MyArrayList<>(); 
    MyArrayList<Object> list5 = new MyArrayList<>();
    
    //printAll(list1); 
    // At this time String Type will report an error because String Is not the parent class of Integer
    
    printAll(list3); //Double Type 
    // At this time Double Type will also report errors, Double The parent class of type is not Integer
    
    printAll(list2); //Integer Type 
    printAll(list4); //Number Type 
    printAll(list5); //Object Type, which is the parent class of all classes 
}

The above code is the lower bound of wildcard characters. The parameter type passed can only be the lower bound or the parent class of the lower bound.

5. Generic methods

In addition to generic classes, there is a concept of generic methods. Compare the following two codes:


public class Algorithm<T extends Comparable<T>> {
    public T findMax(T[] array) {
    
	}
}
0

At this point, I want to write the findMax method as static. After writing static, this method does not depend on the object, and can be called only by the class name. Maybe you will think that this is not simple, so you write the following code:


public class Algorithm<T extends Comparable<T>> {
    public T findMax(T[] array) {
    
	}
}
1

The code written above is definitely wrong. The correct writing is as follows:


public class Algorithm<T extends Comparable<T>> {
    public T findMax(T[] array) {
    
	}
}
2

In the above code, since we are writing generic methods, we only need to write the generic that was originally written after the class name after the static keyword. This is a generic method.

6. Restrictions on generics

Generic types do not support basic data types, and can only pass wrapper classes of basic data types Cannot instantiate an object of a generic type. (E. G. new T) You cannot declare a static property with a generic type You cannot use instanceof to determine a generic type with a type parameter Unable to create an array of generic classes. (Only new Object [], then strong) Unable to create, catch, throw1 generic class exceptions (exceptions do not support generics) A generic type is not part 1 of a formal parameter and cannot be overloaded

Ok, this update is over. See you next time! ! !


Related articles: