Java中的泛型:如何不再害怕尖括号,开始编写可靠代码
\n\n在Java世界中,有一件事让新手感到恐惧,几乎不亚于多线程——那就是尖括号 <>。泛型(Generics)看起来神秘,但实际上它是您编写干净、安全代码的最强盟友。让我们通过今天就能应用的示例,来理解Java中的类型化是如何工作的。
想象一下:您正在编写一个方法,它需要同时处理数字、字符串以及您自己的类。没有泛型,您将不得不创建数十个重载方法,或者使用Object并手动检查类型。Java泛型优雅且安全地解决了这个问题。
为什么没有泛型的代码会变成雷区?
\n\n让我们回忆一下在泛型出现之前(Java 5之前)程序员是如何生存的。如果您曾经写过不带类型指定的ArrayList,您就知道这种噩梦:
List list = new ArrayList();\nlist.add("你好");\nlist.add(42);\nlist.add(new Object());\n\n// 在100行代码之后:\nString text = (String) list.get(1); // 运行时ClassCastException!\n\n经典问题:ClassCastException——一种只在运行时才出现的错误。您可能将列表传递给另一个方法,而那里有人确信列表中只有字符串。然后砰!应用程序崩溃了。Java中的泛型将类型检查转移到编译阶段——这就像在您上车之前就生效的保险。
\n\nJava中的泛型:您需要了解的基本语法
\n\n泛型的基础是一个简单的想法:我们用类型来参数化类或方法。我们使用类型参数(通常是一个大写字母:T、E、K、V)来代替具体类型。
最流行的例子是Java集合:
\n\n// 没有泛型——危险\nList rawList = new ArrayList();\n\n// 有泛型——安全\nList<String> safeList = new ArrayList<>();\nsafeList.add("Java");\nsafeList.add("泛型");\n// safeList.add(123); // 编译错误!\n\n现在编译器知道:safeList内部只能包含字符串。尝试添加数字会在编译阶段引发错误,而不是在运行时。这就是Java类型安全的实际体现。
创建您的第一个泛型类
\n\n假设我们正在编写一个简单的容器来存储一个值。没有泛型,我们将不得不使用Object:
public class Box {\n private Object value;\n\n public void set(Object value) { this.value = value; }\n public Object get() { return value; }\n}\n\n现在——使用泛型:
\n\npublic class Box<T> {\n private T value;\n\n public void set(T value) { this.value = value; }\n public T get() { return value; }\n}\n\n// 使用:\nBox<Integer> intBox = new Box<>();\nintBox.set(100);\nint value = intBox.get(); // 无需强制转换!\n\n请注意:我们不再需要编写(Integer) intBox.get()。编译器自己知道get()将返回Integer。这就是Java泛型的魔力。
Java中的类型化:限制与通配符
\n\n如果没有一些细微之处,泛型就太简单了。其中最主要的是有界类型参数(bounded type parameters)。有时我们需要说:“类型T必须是数字”或“T必须实现Comparable接口”。
\n\n// T只能是Number或其子类\npublic class Calculator<T extends Number> {\n private T value;\n\n public double square() {\n return value.doub