Java 泛型(Generics)是一种参数化类型的机制,它允许在定义类、接口和方法时使用类型参数,从而使代码在编译时就能检测到类型错误。简单来说,泛型的出现让我们可以编写类型安全且可重用的代码。
传统写法的缺陷(没有泛型前)
在 Java 5 之前,我们通常使用 Object 来实现通用容器:
List list = new ArrayList();
list.add("Hello");
list.add(123); // 不同类型都可以放入
String s = (String) list.get(1); // 运行时可能出错
上面的代码在编译时不会报错,但在运行时会抛出 ClassCastException。泛型的目的就是:在编译时发现类型错误,而不是在运行时。
泛型的优势
- 类型安全(Type Safety):泛型让编译器在编译阶段进行类型检查,避免类型转换错误,这是Java编程中的核心实践之一。
- 代码可读性更高:无需到处强制类型转换。
- 可重用性强:可以在不同类型上复用相同的逻辑。
泛型的基本使用
泛型类
定义一个泛型类,类型参数用 <T>:
public class Box<T> {
private T content;
public void set(T content) {
this.content = content;
}
public T get() {
return content;
}
}
使用示例:
public class TestBox {
public static void main(String[] args) {
Box<String> stringBox = new Box<>();
stringBox.set("Hello Generics");
System.out.println(stringBox.get().toUpperCase()); // ✅ 类型安全
Box<Integer> intBox = new Box<>();
intBox.set(42);
System.out.println(intBox.get() + 10);
}
}
泛型方法
泛型不仅可以用于类,还可以用于方法:
public class GenericMethod {
// 声明泛型方法:<T> 必须出现在返回类型前
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3};
String[] strArray = {"Java", "C++", "Python"};
printArray(intArray);
printArray(strArray);
}
}
泛型接口
public interface Repository<T> {
void save(T entity);
T findById(int id);
}
实现类:
public class UserRepository implements Repository<User> {
@Override
public void save(User entity) {
// 保存逻辑
}
@Override
public User findById(int id) {
// 查找逻辑
return null;
}
}
通配符(Wildcard)
Java 泛型还提供了通配符 ?,用于表示未知类型。
无界通配符 <?>:
public static void printList(List<?> list) {
for (Object obj : list) {
System.out.println(obj);
}
}
上界通配符 <? extends Number>: 表示参数类型必须是 Number 或其子类。
public static double sum(List<? extends Number> list) {
double total = 0;
for (Number num : list) {
total += num.doubleValue();
}
return total;
}
下界通配符 <? super Integer>: 表示参数类型必须是 Integer 或其父类。
public static void addIntegers(List<? super Integer> list) {
list.add(10);
list.add(20);
}
类型擦除(Type Erasure)
Java 的泛型是伪泛型,即只在编译期有效。编译后,类型参数会被擦除为 Object 或其上界类型。例如:
List<String> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
System.out.println(list1.getClass() == list2.getClass()); // true
输出结果为 true,说明泛型信息在运行时被擦除了。这种机制确保了向后兼容性,但限制了运行时的类型操作。
总结
Java 泛型是编译期的类型安全机制,本质上通过参数化类型,使得一段逻辑能在多种数据类型上复用,同时避免强制类型转换错误。掌握泛型,可以让你的 Java 代码更安全、优雅、灵活,提升开发效率并减少错误。
| 特性 |
说明 |
| 泛型类 |
类级别的类型参数 |
| 泛型方法 |
方法内部定义的类型参数 |
| 泛型接口 |
接口中定义类型参数 |
| 通配符 |
? 表示未知类型,用于灵活匹配 |
| 类型擦除 |
泛型信息只在编译期存在,运行期被擦除 |
通过合理使用泛型,开发者可以构建更健壮的应用,尤其是在处理数据库和中间件等复杂数据场景时,类型安全显得尤为重要。