在 T super T 和 T 之間做出決定
Java 泛型有界萬用字元的語法,由 ?
表示未知型別:
-
? extends T
代表一個上限有界的萬用字元。未知型別表示必須是 T 的子型別或型別 T 本身的型別。 -
? super T
代表一個下限的萬用字元。未知型別表示必須是 T 的超型別或型別 T 本身的型別。
根據經驗,你應該使用
? extends T
如果你只需要讀取訪問許可權(輸入)? super T
如果你需要寫入訪問許可權(輸出)T
如果你需要兩者(修改)
使用 extends
或 super
通常*更好,*因為它使你的程式碼更靈活(如:允許使用子型別和超型別),如下所示。
class Shoe {}
class IPhone {}
interface Fruit {}
class Apple implements Fruit {}
class Banana implements Fruit {}
class GrannySmith extends Apple {}
public class FruitHelper {
public void eatAll(Collection<? extends Fruit> fruits) {}
public void addApple(Collection<? super Apple> apples) {}
}
編譯器現在能夠檢測到某些不良用法:
public class GenericsTest {
public static void main(String[] args){
FruitHelper fruitHelper = new FruitHelper() ;
List<Fruit> fruits = new ArrayList<Fruit>();
fruits.add(new Apple()); // Allowed, as Apple is a Fruit
fruits.add(new Banana()); // Allowed, as Banana is a Fruit
fruitHelper.addApple(fruits); // Allowed, as "Fruit super Apple"
fruitHelper.eatAll(fruits); // Allowed
Collection<Banana> bananas = new ArrayList<>();
bananas.add(new Banana()); // Allowed
//fruitHelper.addApple(bananas); // Compile error: may only contain Bananas!
fruitHelper.eatAll(bananas); // Allowed, as all Bananas are Fruits
Collection<Apple> apples = new ArrayList<>();
fruitHelper.addApple(apples); // Allowed
apples.add(new GrannySmith()); // Allowed, as this is an Apple
fruitHelper.eatAll(apples); // Allowed, as all Apples are Fruits.
Collection<GrannySmith> grannySmithApples = new ArrayList<>();
fruitHelper.addApple(grannySmithApples); //Compile error: Not allowed.
// GrannySmith is not a supertype of Apple
apples.add(new GrannySmith()); //Still allowed, GrannySmith is an Apple
fruitHelper.eatAll(grannySmithApples);//Still allowed, GrannySmith is a Fruit
Collection<Object> objects = new ArrayList<>();
fruitHelper.addApple(objects); // Allowed, as Object super Apple
objects.add(new Shoe()); // Not a fruit
objects.add(new IPhone()); // Not a fruit
//fruitHelper.eatAll(objects); // Compile error: may contain a Shoe, too!
}
選擇正確的 T
,? super T
或 ? extends T
是*必要的,*以允許使用亞型。然後編譯器可以確保型別安全; 如果你正確使用它們,你不需要強制轉換(這不是型別安全的,可能會導致程式設計錯誤)。
如果不容易理解,請記住 PECS 規則:
P roducer 使用“ E xtends”, C onsumer 使用“ S uper”。
(生產者只有寫訪問許可權,而消費者只有讀訪問許可權)