第 32 条:谨慎并用泛型和可变参数
在 Java 中,将泛型与可变参数(varargs)结合使用可能导致类型安全问题,需要特别小心处理。
问题本质
可变参数的工作原理
// 可变参数实际上是一个数组
void printAll(String... args) {
// 编译器会将可变参数转换为数组
for (String arg : args) {
System.out.println(arg);
}
}
// 调用时可以是:printAll("a","b","c");
// printAll(new String[]{"a","b","c"});
泛型数组的禁止
之前提到的概念非具体化类型:运行时信息比编译时信息少,这里是因为泛型擦除。
// 这是非法的!编译错误
List<String>[] arrayOfLists = new List<String>[10];
// 原因:类型擦除会导致运行时类型检查失效
// List<String> 和 List<Integer> 在运行时都是 List
泛型和可变参数共用时的危险
// 危险!可能引发堆污染(Heap Pollution)
@SafeVarargs
// 不要轻易添加这个注解!
static <T> void dangerous(List<T>... lists) {
// 这里可以插入类型不安全的代码
Object[] array = lists;
// 合法:可变参数实际是数组
List<Integer> intList = List.of(42);
// 这里发生了堆污染!array[0] = intList;
// 编译时无警告,运行时无异常
// 但这里会抛 ClassCastException!
T t = lists[0].get(0);
// 试图将 Integer 转换为 T
}
public static void main {
List<String> stringList = List.of();
dangerous(stringList);
}








