Java Language确定在“ T”,`之间?超级T`和`?扩展T`
示例
Java泛型有界通配符的语法,用来表示未知类型?:
?extendsT表示上限通配符。未知类型表示必须是T的子类型或类型T本身的类型。
?superT表示下界通配符。未知类型表示必须是T的超类型或类型T本身的类型。
根据经验,您应该使用
?extendsT如果您只需要“读取”访问权限(“输入”)
?superT如果您需要“写”访问权限(“输出”)
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()); //允许,因为苹果是水果 fruits.add(new Banana()); //允许,因为香蕉是一种水果 fruitHelper.addApple(fruits); //允许的, as "Fruit super Apple" fruitHelper.eatAll(fruits); //允许的 Collection<Banana> bananas = new ArrayList<>(); bananas.add(new Banana()); //允许的 //fruitHelper.addApple(bananas); //编译错误:只能包含香蕉! fruitHelper.eatAll(bananas); //允许的, as all Bananas are Fruits Collection<Apple> apples = new ArrayList<>(); fruitHelper.addApple(apples); //允许的 apples.add(new GrannySmith()); //允许的, as this is an Apple fruitHelper.eatAll(apples); //允许的, as all Apples are Fruits. Collection<GrannySmith> grannySmithApples = new ArrayList<>(); fruitHelper.addApple(grannySmithApples); //编译错误:不允许。 //GrannySmith不是Apple的超类型 apples.add(new GrannySmith()); //仍然允许,GrannySmith是一个苹果 fruitHelper.eatAll(grannySmithApples);//仍然允许,GrannySmith是一种水果 Collection<Object> objects = new ArrayList<>(); fruitHelper.addApple(objects); //允许的, as Object super Apple objects.add(new Shoe()); //不是水果 objects.add(new IPhone()); //不是水果 //fruitHelper.eatAll(objects); //编译错误:也可能包含Shoe! }
选择rightT,?superT或者?extendsT是允许与子类型一起使用所必需的。然后,编译器可以确保类型安全。如果正确使用它们,则无需进行强制转换(这不是类型安全的,并且可能导致编程错误)。
如果不容易理解,请记住PECS规则:
Producer使用“Ëxtends”和Çonsumer使用“ŞUPER”。
(生产者只有写访问权限,而消费者只有读访问权限)