1. 为什么擦除:向后兼容性
泛型擦除保证了 Java 向后兼容老版本的代码。如果没有擦除机制,Java 就无法兼容原来的非泛型代码。
示例:泛型擦除保持兼容性
import java.util.List;
public class GenericErasureExample {
public static void main(String[] args) {
// 使用泛型的List
List<String> list = List.of("Hello", "World");
System.out.println(list.getClass()); // 输出: class java.util.ArrayList
}
}
解释:
- 编译时,
List<String>
允许存储String
类型的元素。 - 运行时,泛型类型
String
被擦除,list.getClass()
返回的是java.util.ArrayList
,没有泛型信息。 - 这种机制保证了泛型引入后,原始的
List
类在运行时可以继续使用,而不破坏兼容性。
2. 作用:提供类型安全检查
泛型的作用是在编译时提供类型检查,这意味着可以避免错误的类型传入集合中。
示例:类型检查
import java.util.List;
public class TypeSafetyExample {
public static void main(String[] args) {
List<String> list = List.of("Apple", "Banana");
// list.add(1); // 编译时错误:无法添加非String类型的元素
System.out.println(list);
}
}
解释:
List<String>
在编译时只允许添加String
类型的数据。- 如果尝试向
List<String>
添加非String
类型的元素,编译器会报错。 - 这是泛型提供的类型安全性,尽管运行时
String
类型的信息被擦除,但编译时会做类型检查。
3. 注意事项:无法获取运行时类型
由于泛型信息被擦除,运行时无法知道泛型的具体类型。
示例:运行时无法获取泛型类型
import java.util.List;
public class RuntimeTypeExample {
public static void main(String[] args) {
List<String> list = List.of("Hello", "World");
// 尝试通过 instanceof 判断类型
// if (list instanceof List<String>) { // 编译错误: 泛型类型信息擦除
// System.out.println("It's a List<String>");
// }
// 运行时类型输出
System.out.println(list.getClass()); // 输出: class java.util.ArrayList
}
}
解释:
- 编译时,
List<String>
只允许String
类型的元素,但运行时,泛型类型String
被擦除,只剩下List
。 - 运行时,
list.getClass()
输出的是java.util.ArrayList
,没有String
的信息。你不能用instanceof List<String>
来检查类型,因为编译时泛型信息已经被擦除。
4. 注意事项:无法创建泛型数组
由于泛型擦除,你不能创建具有泛型类型参数的数组。
示例:不能创建泛型数组
public class GenericArrayExample {
public static void main(String[] args) {
// 编译错误:无法创建带泛型的数组
// List<String>[] array = new List<String>[10];
// 正确做法:可以创建一个原始类型的数组
List[] array = new List[10]; // 允许,但会有类型警告
}
}
释:
- 编译时,尝试创建
List<String>[]
数组会报错,因为泛型在运行时被擦除,无法创建带有具体泛型类型的数组。 - 你只能创建原始类型的数组(
List[]
),但这会导致类型不安全,因此编译器会发出警告。
5. 泛型的上限:擦除为边界类型
如果泛型有上限(例如 T extends Number
),在擦除时,T
会被替换为边界类型(Number
)。
示例:泛型上限的擦除
import java.util.List;
public class BoundTypeExample {
public static void main(String[] args) {
// List<Integer> 是 List<Number> 的子类
List<? extends Number> list = List.of(1, 2, 3);
// 运行时擦除:<? extends Number> 会被擦除为 List
System.out.println(list.getClass()); // 输出: class java.util.ArrayList
}
}
解释:
- 这里
List<? extends Number>
的泛型上限是Number
,在运行时,泛型信息被擦除,list.getClass()
输出的是java.util.ArrayList
,而不是java.util.ArrayList<Number>
。 - 这说明在擦除时,
? extends Number
会变成原始的List
类型。