This is the 8th day of my participation in the August Text Challenge.More challenges in August

1. What are generics?

For most of you, the term generics is familiar, as it is often used in Java development. Common lists and maps are used, so the importance of generics in Java is self-evident. Generics are also widely used in object-oriented programming and various design patterns. So what exactly are generics, and why do we use them?

Here’s a quiz question to explain:

List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();

System.out.println(l1.getClass() == l2.getClass());
Copy the code

What is the result of the output above? Those of you who know generics know the answer, which is true, because this is typically generic type erasure.

Generics are unique to Java5. Before this, the collection of objects in Java usually needs to be converted to Object objects, and fetching objects also needs to be cast again, which brings the risk of ClassCastException. The addition of generics makes it possible to infer the element types in the collection at compile time, reducing the risk of code bloat and exceptions.

The nature of generics is to parameterize types (to control the types of parameters that are specifically restricted by the different types specified by generics without creating new types). That is, in the use of generics, the data type of the operation is specified as a parameter, which can be used in classes, interfaces, and methods, called generic classes, generic interfaces, and generic methods, respectively.

2. Use of generics

Use type parameters (generics) when defining a class, interface, or method, which are dynamically specified when declaring variables, creating objects, and calling methods.

2.1 a generic class

public class Apple<T> {
    // Use type T to define instance variables
    private T info;
    public Apple(a){}
    // Use type T to define the constructor
    public Apple(T info){
        this.info = info;
    }
    public T getInfo(a) {
        return info;
    }
    public void setInfo(T info) {
        this.info = info; }}/ / use
Apple<String> name = new Apple<>(The word "apple");
Apple<Double> price = newApple<>(.) ;Copy the code

The difference between a generic class and a normal class is that the generic parameter is declared after the method name, and then T can be used as a type in the class (as in the above directly defined variable info).

2.2 Generic interfaces

// The generic parameter E
public interface loadResult<E>{
    //E as the parameter type
    void returnResult(E result);
}
public interface addResult<E>{
    //E is used as a type
    E add(a);
}
Copy the code

Generic interfaces are basically the same as generic class declarations and use the same scope.

2.3 Generic methods

List is not a subclass of List. If you want to put each String element into a collection, the collection must be of type String:

     String[] fruitArray = new String[]{"apple"."banana"."peach"};
     List<String> fruitList = new ArrayList<>();
     array2Collection(fruitArray,fruitList);
     Log.d(TAG,">>>>>> fruitList = " + fruitList);

    // code omitted...
    private void array2Collection(String[] array, List<Object> list) {
        for(String str : array) { list.add(str); }}Copy the code

The code above, for example, raises an exception under compilation. So if you need to place an Integer type later, you need to create a new set of Integers again, which is very limited.

To solve this problem, Java has designed generic methods. Generic methods have more generic parameter declarations than normal methods. All generic parameter declarations are placed between the modifier and the method return value.

Modifier <T,S> Return value type method name (parameter list){/ / the method body
}
Copy the code
private static <T> void add(T t) {
   Log.d(TAG, "> > > > > >" + t + "100");
}
Copy the code

Use generic methods to accomplish putting array data elements into collections

// Define a generic method in which the T generic parameter can only be used
private <T> void array2Collection(T[] array, List<T> list) {
    for(T str : array) { list.add(str); }}// Use the generic method
String[] fruitArray = new String[]{"apple"."banana"."peach"};
List<String> fruitList = new ArrayList<>();
Integer[] integers = new Integer[]{3};
Float[] floats = new Float[]{1.0 f.2.0 f.3.2 f};
List<Number> numberList = new ArrayList<>();
array2Collection(integers, numberList);
Log.d(TAG, ">>>>>> Integer[] numberList = " + numberList);
array2Collection(floats, numberList);
Log.d(TAG, ">>>>>> Float[] numberList = " + numberList);
array2Collection(fruitArray, fruitList);
Log.d(TAG, ">>>>>> List<String> fruitList = " + fruitList);

// Output result:
D: >>>>>> Integer[] numberList = [3]
D: >>>>>> Float[] numberList = [1.23.2.]
D: >>>>>> List<String> fruitList = [apple, banana, peach]
Copy the code

3. Generic wildcards

In addition to using

to represent generics, we often encounter
< p style = “max-width: 100%; clear: both; min-height: 1em; It’s called a wildcard.

Wildcards are usually used to specify the type range within a generic type. Wildcards can be simplified into three forms: wildcards called unbounded, wildcards called upper bound, and wildcards called lower bound.

3.1. Unqualified wildcards

The unqualified wildcard is often used in conjunction with container classes, where? It actually stands for unknown type, so what does it say? Must be type independent.

public static void showShapes(List
        shapeList) {}Copy the code

When
< span style = “box-size: border-box; color: RGB (74, 74, 74); display: block; display: block;

public static void showShapes(List
        shapeList) { 
    shapeList.add(new Circle());/ / an error? cannot applied to Circle
}
Copy the code

provides read-only functionality, which means it strips out the ability to add type-specific elements and retains only functionality that is not specific to the type. It doesn’t care what type of elements are loaded into the container. It only cares about the number of elements and whether the container is empty.

3.2. Upper bound wildcards

Upper bound wildcards are used to loosen restrictions on variable types in methods. Represents type T and subclasses of T.

The above method is changed to:

public static void showShapes(List<? extends Shape> shapeList) {
     for (Shape shape:shapeList){
         Log.i(TAG,"shape="+shape.getShape());
     }
}

showShapes(circleList);// It works
showShapes(triangleList);// It works

shapeList.add(null);/ / is not an error
shapeList.add(new Circle());Shape cannot applied to Circle
Copy the code

You can check the? Object to perform an operation. Note, however, that for the upper bound generic list, we do not allow any objects other than empty to be added to the list.

3.3. Lower bound wildcards

Upper bound generic list, cannot add objects, if need to add, can be done with a lower bound wildcard.

public static void showShapes(List<? super Shape> shapeList) {
    shapeList.add(new Circle());
    shapeList.add(new Circle());
}
Copy the code

Ok, so that’s all I have to say about generics this week. Did you get it?