This article mainly introduces some advanced use and rules of Java generics, including the following two aspects:
- Method parameter wildcard usage rules;
- 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 Xxx
The 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 Fruit
The 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 Xxx
Create 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 Fruit
Create 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 Xxx
Create 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 Xxx
Create 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.