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”。
(生产者只有写访问权限,而消费者只有读访问权限)