访问量 ... 次
访客数 ... 人
你有一个神奇的盒子,它能自动识别放入的物品类型。泛型就像这个盒子的标签系统:
// 普通盒子(可能装错东西)
Box rawBox = new Box();
rawBox.put(123); // 编译通过
String book = (String)rawBox.get(); // 运行时爆炸💥
Box<String>
只接受字符串);
// 泛型盒子(智能分类)
Box<String> safeBox = new Box<>();
safeBox.put(123); // 编译直接报错🚫
String book = safeBox.get(); // 直接使用,无需强制转换
Java中的泛型是通过一种称为类型擦除的机制实现的。在编译生成.class
文件之后,源代码中所有的泛型信息都会被移除,可以认为源代码中泛型相关的信息,就是提供给编译器用。
泛型信息对Java编译器可见,但在运行时对Java虚拟机不可见。
根据Java官方文档的解释,为了实现泛型,Java编译器应用了以下步骤:
List<String>
,编译器会确保你只能向这个列表添加字符串;
// 泛型盒子(智能分类)
Box<String> safeBox = new Box<>();
safeBox.put(123); // 编译直接报错🚫
String book = safeBox.get(); // 直接使用,无需强制转换
Object
);代码中的泛型 | 擦除后 | 替换规则 |
---|---|---|
List<T> |
List |
T → Object |
List<? extends Cat> |
List<Cat> |
保留最近的父类 |
Map<K,V> |
Map |
K/V → Object |
// 你写的代码
String name = names.get(0);
// 编译器暗中添加的类型转换
String name = (String)names.get(0); // 自动插入类型转换
class Parent<T> {
public T getValue() {
return null;
}
}
class Child extends Parent<String> {
@Override
public String getValue() {
return "child value";
}
}
Child
类中会有一个桥方法:
class Child extends Parent<String> {
@Override
public String getValue() {
return "child value";
}
// 生成的桥方法
@Override
public Object getValue() {
return getValue(); // 调用实际的getValue方法
}
}
List
会绕过编译器的类型检查,容易导致运行时ClassCastException
。参数化类型(如List<String>
)能在编码阶段发现类型错误,确保容器内元素的类型安全。
// ❌ 危险:原生类型可能混入错误类型
List rawList = new ArrayList();
rawList.add(123);
String value = (String)rawList.get(0); // 运行时异常
// ✅ 安全:编译时检查类型
List<String> safeList = new ArrayList<>();
safeList.add("Hello");
String text = safeList.get(0); // 无需强制转换
<T>
)自动适应不同数据类型,消除强制转换的风险。
// 通用交换方法(支持任意类型数组)
public static <T> void swap(T[] array, int i, int j) {
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
// 使用示例
String[] words = {"A", "B"};
swap(words, 0, 1); // 自动推断类型为String
? extends
/? super
)遵循PECS
原则(Producer-Extends, Consumer-Super),让API支持更广泛的类型范围。例如List<? extends Number>
可接收Integer
或Double
集合。
// 统计所有数字的总和(支持Integer、Double等)
public double sum(List<? extends Number> numbers) {
return numbers.stream()
.mapToDouble(Number::doubleValue)
.sum();
}
// 调用示例
List<Integer> ints = List.of(1, 2, 3);
sum(ints); // ✅ 合法
getClass()
)可能带来性能损耗。通过缓存Class
对象或避免高频反射调用可优化性能。
// ❌ 低效:每次循环都获取Class对象
for (int i = 0; i < 1000; i++) {
Class<?> clazz = obj.getClass(); // 重复反射调用
}
// ✅ 优化:缓存Class引用
Class<?> clazzCache = obj.getClass();
for (int i = 0; i < 1000; i++) {
// 使用已缓存的clazzCache
}
ClassCastException
。使用instanceof
或Class.isInstance()
预先验证类型安全性。
public <T> T safeCast(Object obj, Class<T> targetType) {
if (targetType.isInstance(obj)) {
return targetType.cast(obj);
}
throw new IllegalArgumentException("类型不匹配: " + obj.getClass());
}
// 安全使用
Object raw = "Hello";
String value = safeCast(raw, String.class); // ✅
Map<String
,List<Map<Integer, String>>>
)会降低代码可读性。工厂方法能隐藏实现细节,简化客户端代码。
public class CollectionFactory {
public static <K, V> Map<K, V> createMap() {
return new HashMap<>();
}
}
// 使用示例
Map<String, List<String>> complexMap = CollectionFactory.createMap();
// 比直接写 new HashMap<String, List<String>>() 更简洁