Java 中的 Generics:为什么需要以及如何使用
Generics(泛型)是 Java 的关键特性之一,从 J2SE 5.0 版本开始引入。它允许创建在调用时指定数据类型的类、接口和方法。您无需为 Integer、String 和 Double 编写单独的实现,只需编写一个通用代码。在本文中,我们将探讨为什么需要 Java 中的 Generics,如何在实际中使用它们,以及需要注意哪些陷阱。
为什么需要 Java 中的 Generics?
在 Generics 出现之前,开发人员使用 Object 来存储任何类型。这种方法虽然可行,但导致了两个严重问题:
- 编译阶段缺乏类型检查。 您可能不小心将
String放入本应是Integer的列表中,而错误只在程序运行时才显现。 - 需要显式类型转换。 每次从集合中提取元素时都需要进行强制转换:
(String) list.get(0)。这使得代码冗长且危险。
Generics 解决了这两个问题。它们允许编译器检查类型的正确性并自动执行转换。来看一个简单的例子:
// 没有 Generics(旧风格)List list = new ArrayList();list.add("Hello");String s = (String) list.get(0); // 需要显式转换
// 使用 GenericsList<String> list = new ArrayList<>();list.add("Hello");String s = list.get(0); // 无需转换代码变得更安全、更易读。类型错误在编译阶段就能被发现,而不是在运行时。
如何使用 Generics:基本结构
1. Generic 类
您可以定义一个接受一个或多个类型参数的类。最常用的是单个字母:T (Type)、E (Element)、K (Key)、V (Value)。
public class Box<T> { private T content;
public void put(T item) { this.content = item; }
public T get() { return content; }}
// 使用Box<String> stringBox = new Box<>();stringBox.put("Java");String value = stringBox.get(); // 自动转换参数 T 在创建对象时被替换为实际类型。编译器保证不能将 Integer 放入 Box<String> 中。
2. Generic 方法
方法也可以是泛型的,即使类本身不是泛型。类型参数在返回类型之前指定:
public class Utils { public static <T> T getMiddle(T... args) { return args[args.length / 2]; }}
// 调用String middle = Utils.<String>getMiddle("A", "B", "C");// 或者直接:Utils.getMiddle("A", "B", "C") — 编译器会推断类型Generic 方法对于处理不同类型数据的工具函数非常有用。
3. 受限类型 (Bounded Type Parameters)
有时需要限制可以替换的类型。例如,让方法只处理数字:
public class Calculator { public static <T extends Number> double sum(T a, T b) { return a.doubleValue() + b.doubleValue(); }}
// 适用于 Integer、Double、Float 等double result = Calculator.sum(5, 10); // 15.0关键字 extends 表示 T 必须是指定类(或实现接口)的子类型。
通配符:未知类型
通配符 (Wildcards) 在确切类型未知或不重要时使用。用问号 ? 表示。有三种类型:
博客
书籍推荐
推荐阅读