在 Java 中,泛型是一种用于在编译时期提供类型安全性的特性。这里主要介绍下 T、T extends T 和 ? super T 的用法和区别。
T:T是一种类型参数,代表着一个具体的类型。它可以是任何合法的 Java 类型,例如 String、Integer 等。T 通常在类、方法或接口的定义中使用,表示在使用该类、方法或接口时,将会传递或返回一个具体的类型。例如,下面是一个泛型类的示例,其中T代表一个占位符类型:
public class Box<T> {private T item;public void setItem(T item) {this.item = item;}public T getItem() {return item;}}
在使用时,可以为 T 传递具体的类型,例如:
Box<String> stringBox = new Box<>();stringBox.setItem("Hello");String item = stringBox.getItem();
? extends T:这是一种通配符上界的用法,表示类型参数可以是T或者T的子类。通配符上界可以用于灵活地接受不同的子类型对象。例如,假设有一个方法接收一个 List,并且你只希望从列表中获取元素而不做任何修改,可以使用通配符上界来表示:
public void processList(List<? extends Number> list) {for (Number number : list) {// 处理元素}}
在调用该方法时,可以传递 List<Number>、List<Integer> 或 List<Double>等类型的列表。
? super T:这是一种通配符下界的用法,表示类型参数可以是T或者T的父类。通配符下界可以用于灵活地接受不同的父类型对象。例如,假设有一个方法接收一个 List,并且你希望向列表中添加 T 类型的元素,可以使用通配符下界来表示:
public void addToList(List<? super T> list, T item) {list.add(item);}
在调用该方法时,可以传递List<Object>、List<Number>或List<Object>等类型的列表。
? extends T: 当你需要从泛型集合中获取元素时,但不需要修改集合中的内容时,使用? extends T。这允许你接受T类型或T的子类作为参数。泛型对象提供 T 元素 时使用
例如,你可能需要一个方法来计算给定列表中元素的总和,但不修改列表本身:
public double calculateSum(List<? extends Number> numbers) {double sum = 0;for (Number number : numbers) {sum += number.doubleValue();}return sum;}
? super T: 当你需要向泛型集合中添加元素时,但不关心元素的具体类型时,使用? super T。这允许你接受T类型或T的父类作为参数。泛型对象接收 T 元素 时使用
例如,你可能需要一个方法来向给定列表中添加元素:
public void addElements(List<? super T> list, T[] elements) {for (T element : elements) {list.add(element);}}
需要注意的是,使用? extends T和? super T通配符时,你只能读取或写入泛型集合中的元素,而无法同时读取和写入。这是为了确保类型安全性。
如果需要读取和写入泛型集合中的元素,那就直接用 T。