Java 泛型
Java 泛型
Section titled “Java 泛型”想象一下,您需要对不同类型的数组进行排序:Integer、String、自定义对象。如果没有泛型,您需要为每种类型编写单独的排序方法。这会导致代码重复和潜在的错误。
Java 泛型允许您编写对指定为参数的类型进行操作的代码。通过单个泛型方法声明,您可以定义一组相关方法;通过单个泛型类声明,可以定义一组相关类型。这提高了代码的可重用性和灵活性。
泛型的一个关键好处是增强了编译时类型安全。编译器会检查您是否使用了正确的类型,在程序运行之前捕获潜在的 ClassCastException 错误。
使用泛型,我们可以编写一个 sort 方法,该方法适用于实现 Comparable 接口的任何类型的数组,确保元素可以排序。然后可以使用 Integer 数组、String 数组等调用这个方法。
泛型方法是使用类型参数声明的方法。编译器根据调用时传递的参数推断实际类型。定义泛型方法的规则:
- 类型参数部分包含在尖括号(
< >)中,位于方法的返回类型之前(例如,<T>)。 - 它包含一个或多个类型参数(例如,
<K, V>),用逗号分隔。类型参数(或类型变量)充当特定类型的占位符。 - 类型参数可以在方法的返回类型、参数类型以及方法内部的局部变量中使用。
- 方法体使用类型参数作为实际类型的占位符来实现。
- 重要:类型参数只能表示引用类型(如 String、Integer、自定义类),不能表示基本类型(int、double、char)。对于基本类型,请使用包装类(Integer、Double、Character)。
示例:打印数组
Section titled “示例:打印数组”此示例演示了使用单个泛型方法 printArray 来打印不同引用类型数组的元素:
import java.util.Arrays;
public class GenericMethodTest {
// 泛型方法 printArray // <E> 声明一个名为 E 的类型参数 public static <E> void printArray(E[] inputArray) { // 使用 Streams API 显示数组元素,以实现简洁 Arrays.stream(inputArray).forEach(element -> System.out.printf("%s ", element)); System.out.println(); }
public static void main(String[] args) { // 现代数组声明风格 // 创建 Integer、Double 和 Character 数组 Integer[] intArray = {1, 2, 3, 4, 5}; Double[] doubleArray = {1.1, 2.2, 3.3, 4.4}; Character[] charArray = {'H', 'E', 'L', 'L', 'O'};
System.out.println("数组 integerArray 包含:"); printArray(intArray); // 传递一个 Integer 数组
System.out.println("\n数组 doubleArray 包含:"); printArray(doubleArray); // 传递一个 Double 数组
System.out.println("\n数组 characterArray 包含:"); printArray(charArray); // 传递一个 Character 数组 }}输出:
Array integerArray contains:1 2 3 4 5
Array doubleArray contains:1.1 2.2 3.3 4.4
Array characterArray contains:H E L L O有界类型参数
Section titled “有界类型参数”有时,您需要限制可以用作类型参数参数的类型。例如,执行计算的方法可能只接受 Number 的子类型。有界类型参数可以实现这一点。
使用 extends 关键字后跟上界类或接口来声明有界类型参数。注意:在这种上下文中,extends 用于扩展类和实现接口。示例:<T extends Number> 表示 T 必须是 Number 或其子类。
示例:查找最大值
Section titled “示例:查找最大值”此泛型方法查找三个对象中的最大值。它使用有界类型参数 <T extends Comparable<T>> 来确保对象可以使用 compareTo 方法进行比较。
public class MaximumTest {
// 确定三个 Comparable 对象中的最大值 // 使用有界类型参数 T,它必须实现 Comparable<T> public static <T extends Comparable<T>> T maximum(T x, T y, T z) { T max = x; // 假设 x 最初是最大的 if (y.compareTo(max) > 0) { max = y; // y 是目前最大的 } if (z.compareTo(max) > 0) { max = z; // z 现在是最大的 } return max; }
public static void main(String[] args) { System.out.printf("Max of %d, %d and %d is %d%n%n", 3, 4, 5, maximum(3, 4, 5)); // 3, 4 和 5 的最大值是 5
System.out.printf("Max of %.1f, %.1f and %.1f is %.1f%n%n", 6.6, 8.8, 7.7, maximum(6.6, 8.8, 7.7)); // 6.6, 8.8 和 7.7 的最大值是 8.8
System.out.printf("Max of %s, %s and %s is %s%n", "pear", "apple", "orange", maximum("pear", "apple", "orange")); // "pear", "apple" 和 "orange" 的最大值是 "pear" }}输出:
Max of 3, 4 and 5 is 5
Max of 6.6, 8.8 and 7.7 is 8.8
Max of pear, apple and orange is pear与泛型方法类似,您可以声明泛型类。类名后跟类型参数部分。
像 class Box<T> 这样的泛型类定义创建了一个蓝图。当您创建实例时,您提供实际类型,例如 Box<Integer>。这些称为参数化类型。
示例:泛型 Box
Section titled “示例:泛型 Box”此示例展示了一个简单的泛型类 Box<T>,它可以容纳任何类型 T 的对象:
public class Box<T> { // T 代表“类型” private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
public static void main(String[] args) { // 使用菱形运算符 <> 创建具有特定类型的 Box 实例 // 编译器从变量声明中推断类型。 Box<Integer> integerBox = new Box<>(); Box<String> stringBox = new Box<>();
// 使用 var 进行局部变量类型推断 (Java 10+) // var stringBox = new Box<String>();
// 自动装箱将 int 10 转换为 Integer 对象 integerBox.set(10); stringBox.set("Hello World"); // 设置字符串值
// 由于泛型,无需强制类型转换 System.out.printf("整数值: %d%n", integerBox.get()); System.out.printf("字符串值: %s%n", stringBox.get()); }}输出:
Integer Value: 10String Value: Hello World通配符(?)在使用泛型类型时提供了更大的灵活性,尤其是在方法参数中。了解更多关于 ? extends Type(上界通配符)和 ? super Type(下界通配符)的信息,以应对更高级的使用场景。