Java中的泛型:为什么需要以及如何使用

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

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) 在确切类型未知或不重要时使用。用问号 ? 表示。有三种类型: