本文目录导读:

我来为你详细讲解泛型擦除(Type Erasure)的典型案例,包括原理、示例和注意事项。
什么是泛型擦除
Java 的泛型是编译期实现的,编译器会擦除所有的泛型类型信息,这意味着:
- 编译时:有完整的泛型类型检查
- 运行时:泛型信息完全消失
典型擦除案例
案例1:基本类型擦除
import java.util.ArrayList;
import java.util.List;
public class BasicErasure {
public static void main(String[] args) throws Exception {
// 编译时:泛型类型检查
List<String> strList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();
// 运行时:两个 List 是同一个类型
System.out.println("strList 类型: " + strList.getClass());
System.out.println("intList 类型: " + intList.getClass());
System.out.println("是否相同类型: " +
(strList.getClass() == intList.getClass())); // true!
// 通过反射添加错误类型的数据
List<String> list = new ArrayList<>();
list.add("Hello");
// 利用反射绕过泛型检查
list.getClass().getMethod("add", Object.class)
.invoke(list, 123); // 可以添加 Integer!
System.out.println("List 内容: " + list);
// 输出: List 内容: [Hello, 123]
}
}
案例2:方法签名擦除
public class MethodErasure {
// 编译错误:方法签名冲突
// public void process(List<String> list) { }
// public void process(List<Integer> list) { }
// 无法共存!因为擦除后都是 List
// 解决方式:使用不同的方法名
public void processString(List<String> list) {
System.out.println("处理字符串列表");
for (String s : list) {
System.out.println(s.toUpperCase());
}
}
public void processInteger(List<Integer> list) {
System.out.println("处理整数列表");
for (Integer i : list) {
System.out.println(i * 2);
}
}
public static void main(String[] args) {
MethodErasure demo = new MethodErasure();
List<String> strings = List.of("java", "python");
List<Integer> integers = List.of(1, 2, 3);
demo.processString(strings);
demo.processInteger(integers);
}
}
案例3:继承中的泛型擦除
import java.util.ArrayList;
import java.util.List;
class Parent<T> {
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
class Child extends Parent<String> {
// 编译器会自动生成桥接方法
@Override
public String get() {
System.out.println("调用了 Child.get()");
return super.get();
}
// 桥接方法(编译器自动生成):
// public Object get() { return this.get(); }
}
public class InheritanceErasure {
public static void main(String[] args) throws Exception {
Child child = new Child();
child.set("Hello");
// 查看桥接方法
for (var method : Child.class.getDeclaredMethods()) {
System.out.println("方法: " + method.getName()
+ ", 参数: " + java.util.Arrays.toString(method.getParameterTypes())
+ ", 返回: " + method.getReturnType());
}
// 通过父类类型调用
Parent<String> parent = child;
System.out.println("获取值: " + parent.get());
}
}
案例4:泛型数组问题
import java.util.List;
public class ArrayErasure {
public static void main(String[] args) {
// 编译错误:不能直接创建泛型数组
// List<String>[] array = new List<String>[10]; // 错误!
// 正确方式:使用 ArrayList 代替
List<String>[] array = new List[10]; // 使用原始类型创建
// 或者使用 List<List<String>>
List<List<String>> nestedList = new java.util.ArrayList<>();
// 示例:泛型数组的实际问题
List<Integer> intList = List.of(1, 2, 3);
List<String> strList = List.of("a", "b", "c");
Object[] objects = new List[2];
objects[0] = intList;
objects[1] = strList;
// 运行时可能会抛出 ClassCastException
try {
List<Integer>[] intArrays = (List<Integer>[]) new List[2];
intArrays[0] = List.of(1, 2, 3);
// intArrays[1] = List.of("string"); // 运行时错误!
System.out.println("数组第一个元素: " + intArrays[0]);
} catch (Exception e) {
System.out.println("捕获异常: " + e);
}
}
}
案例5:工具类中的类型转换
import java.util.ArrayList;
import java.util.List;
public class TypeConversionErasure {
// 辅助方法:安全的类型转换
@SuppressWarnings("unchecked")
public static <T> List<T> castList(Object obj) {
if (obj instanceof List) {
return (List<T>) obj; // 运行时只是转成 List
}
return null;
}
// 显示运行时类型信息
public static void printRuntimeInfo() {
List<String> list = new ArrayList<>();
list.add("Hello");
System.out.println("=== 运行时泛型信息 ===");
System.out.println("List 运行时类型: " + list.getClass());
System.out.println("List 的父类: " + list.getClass().getGenericSuperclass());
// 查看类型参数(运行时已经擦除)
System.out.println("类型参数个数: " +
list.getClass().getTypeParameters().length);
}
public static void main(String[] args) {
printRuntimeInfo();
Object obj = new ArrayList<String>();
obj = List.of("a", "b", "c");
List<String> result = castList(obj);
if (result != null) {
System.out.println("转换成功: " + result);
}
}
}
案例6:泛型与重载
import java.util.List;
public class OverloadErasure {
// 以下两个方法不能共存!
// public void print(List<String> list) { }
// public void print(List<Integer> list) { }
// 正确方式:使用不同的方法名
public void printStringList(List<String> list) {
System.out.println("字符串列表: " + list);
}
public void printIntegerList(List<Integer> list) {
System.out.println("整数列表: " + list);
}
// 或者使用不同的参数个数
public void print(List<String> list, String... extra) {
System.out.println("带额外参数的字符串列表: " + list);
}
public static void main(String[] args) {
OverloadErasure demo = new OverloadErasure();
demo.printStringList(List.of("a", "b"));
demo.printIntegerList(List.of(1, 2));
demo.print(List.of("x"), "extra");
}
}
额外发现和解决方案
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;
public class ErasureSolutions {
// 1. 通过 TypeToken 获取泛型类型
public static class TypeToken<T> {
private final Type type;
protected TypeToken() {
Type superclass = getClass().getGenericSuperclass();
if (superclass instanceof ParameterizedType) {
type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
} else {
throw new RuntimeException("无法获取泛型类型");
}
}
public Type getType() {
return type;
}
}
// 2. 类型安全的容器类
public static class SafeMap {
private final java.util.Map<String, Object> map = new java.util.HashMap<>();
@SuppressWarnings("unchecked")
public <T> T get(String key) {
return (T) map.get(key);
}
public <T> void put(String key, T value) {
map.put(key, value);
}
}
public static void main(String[] args) {
// 使用 TypeToken 获取泛型类型
TypeToken<List<String>> token = new TypeToken<List<String>>() {};
System.out.println("泛型类型: " + token.getType());
// 使用类型安全容器
SafeMap safeMap = new SafeMap();
safeMap.put("name", "张三");
safeMap.put("age", 25);
String name = safeMap.get("name");
Integer age = safeMap.get("age");
System.out.println("姓名: " + name + ", 年龄: " + age);
}
}
泛型擦除的核心要点:
- 编译期检查,运行期擦除:类型安全在编译时保证
- 不能创建泛型数组:运行时类型信息不足
- 不能重载擦除后相同的方法:方法签名冲突
- 桥接方法:JVM 自动生成以维持多态
- 运行时需手动转型:泛型信息丢失后需要显式转换
最佳实践:
- 使用
List而不是数组来保存泛型元素 - 使用明确的类型边界(
<? extends T>等) - 避免混合原始类型和泛型类型
- 使用类型令牌(TypeToken)获取运行时类型信息
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播