This article mainly introduces some advanced use and rules of Java generics, including the following two aspects:

  1. Method parameter wildcard usage rules;
  2. Rules for using wildcards when creating generic objects

First, take a look at the class relationships used in the rest of the tutorial to help you understand the logic behind the code. Apple from Fruit, Fruit from Food; Generic is a Generic class;

Note: the // commented statement in the code indicates that the compilation failed

public class Apple extends Fruit { } public class Fruit extends Food { } public class Generic<T> { private T data; public T getData() { return data; } public void setData(T data) { this.data = data; }}Copy the code

Method parameter wildcard:

1. Used in method parameters? extends XxxThe wildcard

public static void print1(Generic<? extends Fruit> generic){

}
Copy the code

Now wildcard? Extends Fruit limits the upper bound of the Generic to Fruit, so Generic

objects and Generic

objects can be passed to print1 as arguments, but Generic

objects cannot be passed as arguments. Because Food is the parent of Fruit, it goes beyond the upper bounds of the generic rules; The specific code is shown below


Generic<Fruit> fruitGeneric1 = new Generic<>(); print1(fruitGeneric1); Generic<Apple> appleGeneric1 = new Generic<>(); print1(appleGeneric1); // Generic<Food> foodGeneric1 = new Generic<>(); // print1(foodGeneric1);Copy the code

2. Used in method parameters? super FruitThe wildcard

public static void print2(Generic<? super Fruit> generic){

}
Copy the code

Now wildcard? Super Fruit limits the lower bound of generics to Fruit, so Generic

objects and Generic

objects can be passed as arguments to print2, but Generic

objects cannot be passed as arguments, Because Apple is a Fruit subclass, it’s outside the lower bounds of the generic rules; The specific code is shown below


Generic<Fruit> fruitGeneric2 = new Generic<>(); print2(fruitGeneric2); Generic<Food> foodGeneric2 = new Generic<>(); print2(foodGeneric2); // Generic<Apple> appleGeneric2 = new Generic<>(); // print2(appleGeneric2);Copy the code

2. Wildcard generic object parameters read and modify

1. Use? extends XxxCreate a wildcard generic object

Generic<? extends Fruit> generic = new Generic<>();
Fruit fruit1 = new Fruit();
Apple apple1 = new Apple();
Food food1 = new Food();
//    generic.setData(fruit1);
//    generic.setData(apple1);
//    generic.setData(food1);
Fruit data1 = generic.getData();
Copy the code

Above code analysis: Using? The extends Fruit method specifies that the upper bound of the generic is Fruit, but there is no way to determine the specific type of the generic, so you cannot modify an object of any type using the setData method. But you can use the getData method to determine that the object type is Fruit, because upcasting is safe in Java, so Fruit is definitely not a problem; So use? The generics specified by extends Fruit are safe to read the parameters, but not to modify them. This is important and needs to be mastered!

2. Use? super FruitCreate a wildcard generic object

Generic<? super Fruit> generic2 = new Generic<>();
Fruit fruit2 = new Fruit();
Apple apple2 = new Apple();
Food food2 = new Food();
generic2.setData(fruit1);
generic2.setData(apple1);
//    generic2.setData(food1);
Object data2 = generic2.getData();
Copy the code

Above code analysis: Using? Super Fruit specifies that the lower boundary of the generic type is “Fruit”, so the element accessed inside is “Fruit” or its parent class. Therefore, we can pass in “Fruit” or “Fruit” subclass object in setData method, which can also be understood as upward transformation is safe. However, we cannot pass an object of type Food, because we can only determine that the element is Fruit or its parent, but not exactly which parent, so we cannot pass the object of type Food. In the same way, the getData method can only determine whether the fetched element is Fruit or its parent, but it cannot determine which parent, and since Object is the parent of all classes, there is no problem accepting Object. This is important and needs to be mastered!

Use 3.?Create a wildcard generic object

Generic<? > generic3 = new Generic<>(); Fruit fruit3 = new Fruit(); Apple apple3 = new Apple(); Food food3 = new Food(); // generic3.setData(fruit1); // generic3.setData(apple1); // generic3.setData(food1); Object data3 = generic3.getData();Copy the code

Code analysis above: Can we assume this is the case? The wildcard is not restricted, so you can’t use setData to operate on any Object, and since Object is the parent of all classes, Object acceptance is fine.

Use 4.? extends XxxCreate wildcard generic objects using analysis

List<Integer> list0 = new ArrayList<>();
list0.add(100);
List<? extends Number> list = new LinkedList<>(list0);
//    list.add(10);
Integer number = (Integer) list.get(0);
System.out.println(number);
Copy the code

The above code analysis, according to the above situation 1? Summary of extends XXX, it is straightforward to conclude that a List object is safe to read parameters, but not to modify them.

5. Use? super XxxCreate wildcard generic objects using analysis

List<? super Number> list2 = new LinkedList<>();
list2.add(10);
Integer object = (Integer) list2.get(0);
System.out.println(object);
Copy the code

According to the above code analysis, 2 pairs of? Super XXX summary, can be directly derived from the list2 Object can be modified parameters, parameters read can use Object type.