# assumes that
class Food {}
class Fruit extends Food {}
class Apple extends Fruit {}
class Orange extends Fruit{}
#? extends class
Extends is straightforward, inheritance. A class inherits from class. For example? Extends Fruit, which means that some class inherits Fruit, Orange, whatever.
Insert data: Absolutely not. When a type is erased, the compiler only knows that it is a class that inherits from class, but does not know what class it is. Inserting data can cause type errors.
For example, there is now a method called public void add(ArrayList<? extends Fruit> fruit) {fruit.add(new Apple()); }, temporarily do not judge right or wrong, first analyze.
Suppose ArrayList points to ArrayList<Apple>, that’s fine; Assuming you’re pointing to ArrayList<Orange>, that’s obviously a typeclass error.
Object can’t be inserted, Object doesn’t inherit from Fruit.
So to be type safe, fruit.add(new Apple()) must generate a compilation error.
Read data: Absolutely. Since it is a class that inherits from class, it must be possible to cast the elements up to class.
For example, there is now a method called public void get(ArrayList<? extends Fruit> fruit) {fruit.get(); }, temporarily do not judge right or wrong, first analyze.
Let’s say ArrayList points to ArrayList<Apple>, and we’re going to turn the Apple up to Fruit; Let’s say I’m pointing to an ArrayList<Orange>, and I’m going to turn the Orange I pulled up to Fruit.
Therefore, feasible.
#? super class
Super is pretty straightforward, inherited. A class is inherited by a class. For example? Super Fruit, that means something is inherited by Fruit, it could be Food, whatever.
Insert data: part ok. When a type is erased, the compiler knows that it is at most a class, and can cast classes that inherit from class up and then insert them instead of classes that inherit from class. The cast down is not guaranteed to succeed, so it cannot be added.
For example, there is now a method called public void add(ArrayList<? Super Fruit> Fruit) {Fruit. Add (new Apple())}
This ArrayList plugs into Apple, and that’s fine, but this Apple is going to go up; What if it points to ArrayList<Orange>? There’s no problem transforming Orange up, but ArrayList<? Super Fruit> There must be, right? Extend Fruit class.
Therefore, feasible.
Objecet cannot be inserted either. Specifically, classes that are inherited by class cannot be inserted.
For example, there is now a method called public void add(ArrayList<? Super Fruit> Fruit) {Fruit. Add (new Object())}
This ArrayList actually points to ArrayList<Object>, and that’s fine, but this Apple is going to go up; What if it points to an ArrayList<Food>? Object is not Food. You cannot convert an inserted Object to Food.
So to be type safe, fruit.add(new Object()) must generate a compilation error.
Reading data: Awkward, but ok. The compiler can know that it is at most a class, but it cannot know which parent of the class it is, so it can only be converted to the most basic parent, Object.
For example, there is now a method called public void get(ArrayList<? super Fruit> fruit) {fruit.get(); }, temporarily do not judge right or wrong, first analyze.
Given that an ArrayList could point to an ArrayList<Fruit> or an ArrayList<Food>, the safest thing to do is return Object — and that’s certainly true.
Therefore, feasible.
# summary
As a developer, Java generics suck and the mechanics are too complex.
As a builder of Java, Java’s generics are great because they guarantee backward compatibility.
PECS principle:
- If you want to read data of type T from the collection and cannot write to it, you can use? extendsclass (Producer Extends)
- If you want to write data of type T from a collection and do not need to read, you can use? superclass Wildcard (Consumer Super)
- Do not use any wildcards if you want to both save and take