Java泛型

  • Java中的泛型(Generics)是一种通过参数化类型来增强代码重用性和类型安全性的机制。它使得类、接口和方法能够操作不同类型的数据,而无需在编译时指定具体的类型。

1. 泛型的基本概念

  • 泛型允许在编写类、接口和方法时,不确定它们将操作的对新的类型,而是在实例化时指定具体的类型参数。类似于通配符。

2. 泛型的作用

  • 类型安全: 使用泛型可以在编译时检查类型,减少运行时错误。
  • 代码复用: 泛型允许编写通用的代码,可以处理不同类型的数据。
  • 避免强制类型转换: 使用泛型可以避免在使用对象时进行强制类型转换,提高代码的可读性和安全性。

3. 泛型的基本语法

  • 泛型通常通过尖括号<>来指定,<>是占位符,用来表示类型:
    • 泛型类: class ClassName<T>,其中T代表一种类型。
    • 泛型方法: <T> void method(T param),其中<T>表示传入方法的类型。

4. 泛型的使用示例

  • 假设一个容器类(比如Box),它可以存储任何类型的对象。如果没有泛型,我们就只能存储特定类型的对象,且取出时需要做类型转换。使用泛型后,容器可以存储任何类型的对象,同时避免了类型转换的问题。

  • 没有泛型的容器类示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class Box {
    private Object value;

    public void setValue(Object value) {
    this.value = value;
    }

    public Object getValue() {
    return value;
    }

    public static void main(String[] args) {
    Box box = new Box();
    box.setValue("Hello");
    String message = (String) box.getValue(); // 强制类型转换
    System.out.println(message);
    }
    }
  • 使用泛型的容器类示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class Box<T> {  // 使用泛型 T
    private T value;

    public void setValue(T value) {
    this.value = value;
    }

    public T getValue() {
    return value;
    }

    public static void main(String[] args) {
    Box<String> box = new Box<>(); // 创建一个存储 String 类型的 Box
    box.setValue("Hello");
    String message = box.getValue(); // 不需要强制类型转换
    System.out.println(message);
    }
    }

5. 泛型方法

  • 泛型方法允许在方法级别上使用泛型类型参数。可以在方法声明中指定类型参数,并在方法体内使用它们。

  • 泛型方法示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class GenericMethodExample {
    // 泛型方法
    public static <T> void printArray(T[] array) {
    for (T element : array) {
    System.out.println(element);
    }
    }

    public static void main(String[] args) {
    Integer[] intArray = {1, 2, 3, 4, 5};
    String[] strArray = {"Hello", "World"};

    printArray(intArray); // 调用泛型方法,传入 Integer 数组
    printArray(strArray); // 调用泛型方法,传入 String 数组
    }
    }

    这里的<T>表示该方法是一个泛型方法,可以接收任何类型的数组作为参数。无论是Integer类型的数组,还是String类型的数组,都可以通过这个方法进行打印。

6. 泛型的边界(Bounded Type Parameters)

  • 泛型类型参数可以加边界(Bound),限制其可以接受的范围。使用extends关键字,你可以指定泛型的上边界,这样泛型参数就只能是指定类或其子类的类型。

  • 泛型边界示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class BoundedTypeExample {
    public static <T extends Number> void printNumbers(T[] numbers) {
    for (T num : numbers) {
    System.out.println(num);
    }
    }

    public static void main(String[] args) {
    Integer[] intArray = {1, 2, 3};
    Double[] doubleArray = {1.1, 2.2, 3.3};

    printNumbers(intArray); // 适用于 Integer 类型
    printNumbers(doubleArray); // 适用于 Double 类型
    }
    }

    <T extends Number>表示T只能是Number类或它的子类(如IntegerDouble等)。这确保了T的类型是数字类型。

7. 通配符(Wildcards)

  • 通配符?用于表示未知类型。它可以用在泛型类、接口和方法中,以提高灵活性。常见的通配符:

    • ? extends T:表示类型是TT的子类。
    • ? super T:表示类型是TT的父类。
  • 通配符示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class WildcardExample {
    public static void printList(List<? extends Number> list) {
    for (Number num : list) {
    System.out.println(num);
    }
    }

    public static void main(String[] args) {
    List<Integer> intList = List.of(1, 2, 3);
    List<Double> doubleList = List.of(1.1, 2.2, 3.3);

    printList(intList); // 适用于 Integer 类型
    printList(doubleList); // 适用于 Double 类型
    }
    }

    这里的List<? extends Number>表示可以接受任何Number及其子类的List(如IntegerDouble等)。

8. 泛型的类型擦除

  • Java中的泛型在编译时会进行类型擦除(Type Erasure),这意味着在编译后,所有的泛型类型信息都会被移除,替换为它们的上边界类型(如果没有指定上边界,则替换为Object)。这使得泛型在运行时不会引入额外的开销,但也带来了一些限制,比如不能使用基本数据类型作为泛型参数。

9. 总结

  • 泛型的作用:
    • 提供类型安全的代码。
    • 增强代码的可重用性。
    • 避免强制类型转换和运行时错误。
  • 泛型语法:
    • 泛型类:class ClassName<T>
    • 泛型方法:<T> void method(T param)
    • 边界(Bounded Type):<T extends Number>
  • 通配符:
    • ? extends T表示类型是T的子类
    • ? super T表示类型是T的父类。