Java 泛型 (Generics)
泛型(Generics)是 Java SE 5.0 引入的一个强大特性,它允许我们在定义类、接口和方法时使用类型参数 (type parameters)。使用泛型可以编写出更灵活、更安全、更清晰的代码。
为什么需要泛型?
在泛型出现之前,Java 的集合类(如 ArrayList)只能存储 Object 类型的对象。这样做有两个主要问题:
- 类型不安全:你可以向一个
ArrayList中添加任何类型的对象,但在编译时无法发现错误。 - 需要强制类型转换:从集合中取出元素时,你必须手动将其转换为期望的类型,这很繁琐且可能在运行时抛出
ClassCastException。
泛型通过将类型检查从运行时提前到编译时,完美地解决了这些问题。
泛型类
我们可以定义自己的泛型类。类型参数(通常用单个大写字母表示,如 T for Type, E for Element, K for Key, V for Value)在类名后的尖括号 <> 中声明。
泛型方法
除了泛型类,我们还可以定义泛型方法。泛型方法有自己的类型参数,这些参数在方法返回类型之前声明。
有界类型参数 (Bounded Type Parameters)
有时,我们希望限制可以用作类型参数的类型。例如,一个方法可能只接受 Number 或其子类的实例。这可以通过有界类型参数实现。
<T extends UpperBound>:T必须是UpperBound类型或其子类型。
通配符 (Wildcards)
通配符 ? 用于表示未知的类型,常用于泛型方法的参数中,以增加灵活性。
-
上界通配符 (
? extends Type): 表示参数类型是Type或其任意子类型。这种集合是只读的(不能添加元素,除了null),因为我们无法确定集合的确切类型。 -
下界通配符 (
? super Type): 表示参数类型是Type或其任意父类型。这种集合是只写的(可以添加Type及其子类型的实例),但读取时只能得到Object。 -
无界通配符 (
?): 表示任何类型。当类型不重要时使用,例如List<?>。
类型擦除 (Type Erasure)
Java 的泛型是通过类型擦除来实现的。这意味着在编译后,所有泛型类型信息都会被移除。Box<String> 和 Box<Integer> 在运行时都会变成原始的 Box 类,类型参数 T 会被替换为它的边界(默认为 Object)。编译器会在必要的地方自动插入类型转换代码,以保证类型安全。