泛型简介
- 定义:泛型(Generics)是 Java 提供的一种参数化类型机制,可以让类、接口、方法操作任意类型的数据
- 目的:
- 编译时类型检查,提升类型安全
- 消除强制类型转换
- 代码复用,提高可读性和维护性
泛型基础
1. 泛型类
public class Box<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public static void main(String[] args) {
Box<String> box = new Box<>();
box.setValue("hello");
System.out.println(box.getValue());
}
}
2. 泛型接口
public interface Generator<T> {
T next();
}
public class StringGenerator implements Generator<String> {
public String next() {
return "Hello";
}
}
3. 泛型方法
public class Util {
public static <T> void printArray(T[] array) {
for (T item : array) {
System.out.println(item);
}
}
}
// 使用
Util.printArray(new Integer[]{1, 2, 3});
泛型进阶
4. 通配符 ?
4.1 无限定通配符
List<?>
表示:这是一个元素类型未知的 List
,它可以是任何类型的 List
public void printList(List<?> list) {
for (Object obj : list) {
System.out.println(obj);
}
}
4.2 上界通配符 ? extends
表示参数是某个类或其子类(只读,不能添加元素,安全)
这时,list
可能是:
List<Integer>
List<Double>
List<Number>
public void printNumberList(List<? extends Number> list) {
for (Number n : list) {
System.out.println(n);
}
}
4.3 下界通配符 ? super
表示参数是某个类或其父类(可写,添加时安全)
public void addNumber(List<? super Integer> list) {
list.add(1);
list.add(2);
}
5. 通配符与泛型方法对比
- 通配符常用于方法参数
- 泛型方法常用于方法返回类型和参数之间建立类型关系
四、泛型的类型擦除
类型擦除原理
- Java 泛型是伪泛型,编译后会擦除泛型信息
- 类型擦除后:
- 泛型类型变为
Object
(或上限类型) - 插入强制类型转换
- 不支持泛型数组、泛型的运行时反射
- 泛型类型变为
泛型擦除带来的限制
- 不能使用
instanceof
判断泛型类型 - 不能直接创建泛型数组
- 不能在静态方法、静态变量使用类的泛型参数
获取泛型类型的方式
public class Demo<T> {
public Class<?> getGenericType() {
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
Type[] actualTypes = ((ParameterizedType) type).getActualTypeArguments();
return (Class<?>) actualTypes[0];
}
return Object.class;
}
}
泛型高级用法
泛型约束(限制类型范围)
public class Calculator<T extends Number> {
public double add(T a, T b) {
return a.doubleValue() + b.doubleValue();
}
}
泛型接口的实现
public class MyList<T> implements List<T> {
// 必须全部使用 T,而不能具体化为某个类型
}
泛型方法返回泛型类型
public static <T> T copy(T value) {
return value;
}
多个泛型参数
public class Pair<K, V> {
private K key;
private V value;
}
泛型嵌套
Box<List<String>> box = new Box<>();
泛型的常见陷阱和注意点
- 不支持泛型数组:
new T[]
错误 - 泛型信息在运行时会被擦除:
List<String>
和List<Integer>
是同一个类 instanceof
时不能直接使用泛型- 静态上下文不能使用泛型参数