目录
一、什么是泛型?
泛型是Java编程语言中的一个重要特性,它允许类、接口和方法在定义时使用一个或多个类型参数,这些类型参数在使用时可以被指定为具体的类型。
泛型的主要目的是在编译时提供更强的类型检查,并在编译后能够保留类型信息,避免了在运行时出现类型转换异常。
为什么需要泛型?
- 适用于多种数据类型执行相同的代码,如一下实例。
private static int add(int a, int b) {
System.out.println(a + "+" + b + "=" + (a + b));
return a + b;
}
private static float add(float a, float b) {
System.out.println(a + "+" + b + "=" + (a + b));
return a + b;
}
如果没有泛型,要实现不同数据类型的加法,那只能通过定义不同的方法来实现,如果引入泛型,我们可以复用一个方法:
privat static <T extends Number> add(T a, T b) {
System.out.printlen(a + "+" + b + "=" + (a + b));
return a + b;
}
泛型中的类型在使用时指定,不需要强制类型转换(类型安全, 编译器会检查类型)
如下例子:
List list = new ArrayList();
list.add("jerry");
list.add(new Person());
list.add(123);
上述例子中,list中的类型都是Object,无法约束其中的类型,所以在取出类型的时候需要认为进行强制类型转换为目标类型,很容易出现java.lang.ClassCastException异常。
引入泛型后:
List<String> list = new ArrryList<>();
// list中只能存储String类型的数据,不能放其他类型的数据。
二、为什么说是伪泛型?
回顾完什么是泛型后,我们来讲为什么Java中的泛型是伪泛型。
2.1 类型擦除(Type Erasure)
Java中的泛型被称为伪泛型,主要是因为Java的泛型是通过**类型擦除(Type Erasure)**实现的,而不是像某些其他语言(如C#)那样在运行时保留泛型类型信息。
Java的泛型在编译后会进行类型擦除,即所有泛型类型参数都会被替换为它们的上限类型(通常是Object
),或者指定的边界类型(如extends SomeClass
)。这意味着在运行时,泛型类型信息会被擦除,无法直接获取。
List<String> stringList = new ArrayList<>();
List<Integer> integerList = new ArrayList<>();
// 编译后,两者的类型都会被擦除为原始类型 List
System.out.println(stringList.getClass() == integerList.getClass()); // 输出 true
在运行时,stringList
和integerList
的类型都是List
,而不是List<String>
或List<Integer>
。
2.2 Java选择伪泛型的原因
Java选择使用类型擦除来实现泛型,主要是为了向后兼容和简化迁移:
-
向后兼容:Java在引入泛型(Java 5)之前已经存在大量的非泛型代码(如
ArrayList
、HashMap
等)。通过类型擦除,泛型代码可以与旧的非泛型代码兼容。 -
简化迁移:类型擦除使得旧代码可以逐步迁移到泛型,而不需要重写所有代码。
2.3伪泛型的局限性
由于类型擦除,Java的泛型存在一些局限性:
-
无法获取泛型的实际类型参数:
List<String> list = new ArrayList<>();
System.out.println(list.getClass().getTypeParameters()); // 输出 [E],而不是 String
-
无法创建泛型类型的实例:
public static <T> T createInstance(Class<T> clazz) { return new T(); // 编译错误:无法创建泛型类型的实例 }
-
无法使用基本类型作为泛型参数:
List<int> list = new ArrayList<>(); // 编译错误:必须使用包装类型
List<Integer> list = new ArrayList<>(); // 正确
三、总结
Java的泛型被称为伪泛型,主要是因为:
-
通过类型擦除实现,泛型类型信息在运行时不可用。
-
设计目的是为了向后兼容和简化迁移。
-
存在一些局限性,但可以通过其他方式(如反射)部分解决。
尽管是伪泛型,Java的泛型仍然提供了强大的类型安全性和代码复用能力,是Java语言中不可或缺的特性。