泛型&通配符详解
泛型与通配符详解
一、泛型(Generics)
泛型是 Java 的一种类型机制,用来在类、接口和方法中创建可以操作不同类型数据的代码。通过泛型,我们能够在编译时检查类型安全,避免了强制类型转换的麻烦。
1. 泛型类
泛型类是指类中使用了泛型参数的类。在定义类时,可以指定一个或多个类型参数,这些类型参数将在使用类时指定具体的类型。
public class Box<T> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}在创建 Box 对象时,我们可以指定具体的类型:
Box<Integer> intBox = new Box<>();
intBox.setValue(10);
Integer value = intBox.getValue();2. 泛型方法
泛型方法是指方法中使用了泛型参数的代码块。方法的泛型类型可以与方法所在的类的泛型类型不同。
public class GenericMethod {
// 泛型方法
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
}调用时,指定具体的类型:
Integer[] intArray = {1, 2, 3};
String[] strArray = {"Hello", "World"};
GenericMethod.printArray(intArray);
GenericMethod.printArray(strArray);3. 泛型约束(边界)
泛型参数可以有边界限制,意味着我们可以限制泛型参数的类型范围。使用 extends 关键字来指定类型边界。
public class NumberBox<T extends Number> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}该类只能接受 Number 或其子类(如 Integer、Double)作为类型参数。
NumberBox<Integer> integerBox = new NumberBox<>();
integerBox.setValue(10);二、通配符(Wildcard)
通配符是指不指定具体类型,而是通过一个特殊的符号 ? 来表示可以匹配任意类型的泛型。通配符在泛型类型中常用于方法的参数类型,表示方法可以接受多种类型的参数。
1. 无上下限通配符 <?>
无上下限的通配符表示可以接受任何类型的对象。它常用于只读操作,比如打印集合中的元素。
public static void printList(List<?> list) {
for (Object item : list) {
System.out.println(item);
}
}List<?> 表示可以是任何类型的 List。
2. 上限通配符 <? extends T>
上限通配符 <? extends T> 表示泛型类型是 T 的子类或 T 自身。它通常用于方法的输入参数,表示接受 T 或 T 的任何子类型。
public static void printNumbers(List<? extends Number> list) {
for (Number number : list) {
System.out.println(number);
}
}可以传递 List<Integer>, List<Float>, List<Double> 等。
3. 下限通配符 <? super T>
下限通配符 <? super T> 表示泛型类型是 T 的父类或 T 自身。它通常用于方法的输出参数,表示可以接收 T 或 T 的父类型。
public static void addNumbers(List<? super Integer> list) {
list.add(10); // 可以添加 Integer 或其子类
}List<? super Integer> 可以接受 List<Integer>, List<Number>, List<Object> 等。
三、通配符的实际应用
1. 上限通配符(<? extends T>)的应用场景
上限通配符通常用于读取数据时,允许接受某个类型及其子类型。它的一个常见用途是提高方法的通用性。
public static double sum(List<? extends Number> list) {
double sum = 0.0;
for (Number num : list) {
sum += num.doubleValue();
}
return sum;
}
List<Integer> intList = Arrays.asList(1, 2, 3);
List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);
System.out.println(sum(intList)); // 6.0
System.out.println(sum(doubleList)); // 6.62. 下限通配符(<? super T>)的应用场景
下限通配符通常用于向集合中添加元素,它允许传入 T 或其父类的类型。
public static void addNumbers(List<? super Integer> list) {
list.add(10); // 只允许添加 Integer 或其子类的对象
}四、泛型与通配符的结合使用
泛型和通配符可以结合使用,以提高代码的通用性。例如,我们可以使用上限通配符与泛型结合来约束集合中的元素类型。
public static <T> void printList(List<? extends T> list) {
for (T element : list) {
System.out.println(element);
}
}五、泛型与原始类型(Raw Type)
泛型引入后,Java 中仍然可以使用原始类型(不带类型参数的泛型),但这种做法已经不推荐。原始类型会失去编译时的类型检查,因此会带来类型安全问题。
List rawList = new ArrayList();
rawList.add("Hello");
rawList.add(123); // 不会有编译时错误,但会在运行时抛出 ClassCastException为了确保类型安全,应该避免使用原始类型,而是尽量指定泛型类型参数。
总结
- 泛型 提供了一种在类、接口和方法中使用参数化类型的方式,从而避免了运行时类型转换错误,提高了代码的类型安全性。
- 通配符(
?)用于使代码更加通用,通配符可以有上下限,用于不同的场景:<?>:无上下限,可以接受任何类型;<? extends T>:上限通配符,表示接受T或其子类;<? super T>:下限通配符,表示接受T或其父类。
