🌟 什么是泛型?
泛型(Generics) 是 JDK 5 引入的一项重要特性,旨在增强代码的可读性、类型安全性和复用性。
使用泛型后,编译器可以在编译阶段对传入的参数进行类型检查,避免运行时因类型不匹配导致的错误。例如:
ArrayList<Person> persons = new ArrayList<>();
persons.add(new Person()); // ✅ 合法
persons.add("Hello"); // ❌ 编译错误!
📌 关键点:
-
泛型确保了集合只能存储指定类型的对象
-
如果试图添加不符合泛型类型的对象,编译器会直接报错
-
这不是运行时报错,而是编译期就能发现的错误
🔁 泛型的三大使用方式
1️⃣ 泛型类(Generic Class)
通过在类名后加上 <T>
,声明一个泛型类,使类具有通用性。
// T 可以是任意标识符,常见如 T、E、K、V 等
public class Generic<T> {
private T key;
public Generic(T key) {
this.key = key;
}
public T getKey() {
return key;
}
}
📌 使用示例:
Generic<String> stringGeneric = new Generic<>("Hello");
System.out.println(stringGeneric.getKey()); // 输出: Hello
Generic<Integer> integerGeneric = new Generic<>(123);
System.out.println(integerGeneric.getKey()); // 输出: 123
2️⃣ 泛型接口(Generic Interface)
接口也可以定义为泛型形式,允许实现类根据需要指定具体类型。
public interface Generator<T> {
T method();
}
📌 实现示例:
public class StringGenerator implements Generator<String> {
@Override
public String method() {
return "Generated String";
}
}
3️⃣ 泛型方法(Generic Method)
即使类本身不是泛型类,也可以单独定义泛型方法。
public static <E> void printArray(E[] inputArray) {
for (E element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println();
}
📌 特别注意:
-
静态方法要使用泛型,必须在方法前显式声明
<E>
-
普通方法如果在泛型类中,可以直接使用类上的泛型参数(如
T
) -
如果普通方法不在泛型类中,也必须自己声明泛型参数
📌 使用示例:
Integer[] intArray = {1, 2, 3};
String[] strArray = {"Java", "泛型", "真香"};
printArray(intArray); // 输出: 1 2 3
printArray(strArray); // 输出: Java 泛型 真香
⚠️ 类型擦除(Type Erasure)
Java 的泛型是编译期特性,在运行时会被“擦除”,即所谓的 类型擦除(Type Erasure)。
这意味着:
-
在 JVM 层面,
ArrayList<Person>
和ArrayList<String>
被视为相同的类型 -
所有泛型信息在编译后都会被替换为原始类型(raw type),比如
ArrayList
-
编译器会在必要处插入类型检查和强制转换,以保证类型安全
💡 那为什么还能保证类型安全?
因为编译器做了严格的检查,并且在必要时插入了隐式类型转换。
举个例子:
Person p = list.get(0); // ✅ 安全,编译器自动插入 (Person)
编译器确保你取出来的对象一定是 Person
类型,不需要你自己再强转。
📌 示例:
ArrayList<Integer> list1 = new ArrayList<>(); ArrayList<String> list2 = new ArrayList<>(); System.out.println(list1.getClass() == list2.getClass()); // true
💡 小贴士
问题 | 回答 |
---|---|
泛型类可以继承吗? | ✅ 可以,但子类必须明确泛型类型或继续使用泛型 |
接口和类能同时使用泛型吗? | ✅ 可以,泛型接口可以由泛型类或普通类实现 |
如何限制泛型类型? | ✅ 使用通配符,如 <T extends Number> |
静态方法能否使用类级别的泛型? | ❌ 不行,必须自己声明泛型 |