泛型

泛型概述

Java泛型是Java语言中的一个重要特性,它提供了一种参数化类型的机制,可以使代码更加灵活、可重用,并增加类型安全性。通过使用泛型,我们可以在编译时指定类、接口和方法的参数类型,从而提高代码的可读性和可维护性。

泛型原理

Java泛型的原理基于类型擦除(Type Erasure)。在编译时,所有的泛型类型信息都会被擦除,编译器会将泛型类型转换为其原始类型(Raw Type)。这意味着在运行时,无法访问泛型类型的具体信息。

泛型的类型参数会被擦除并替换为其上限或Object类型。例如,List<String> 在运行时会被擦除为 ListList<Object>

泛型特性

Java泛型具有以下特性:

  1. 类型安全性:泛型提供了编译时的类型检查机制,可以在编译时检测类型错误,减少了运行时的异常风险。

  2. 代码重用:泛型可以实现类型无关的代码,提高了代码的重用性和灵活性。

  3. 避免类型转换:泛型可以避免手动进行类型转换,减少了代码中的冗余和错误的可能性。

泛型类

在Java中,我们可以使用泛型来定义泛型类。泛型类在类名后面使用尖括号 <T> 来指定类型参数,并在类的属性、方法或构造函数中使用这个类型参数。

下面是一个示例的泛型类的定义:

public class MyGenericClass<T> {
    private T item;
​
    public void setItem(T item) {
        this.item = item;
    }
​
    public T getItem() {
        return item;
    }
}

在上述示例中,MyGenericClass<T> 是一个泛型类,其中的 T 是类型参数。我们可以在类的方法中使用 T 来代表泛型类型,从而使该类可以适用于不同类型的数据。

泛型方法

除了泛型类,Java还支持泛型方法。泛型方法是指在方法声明中使用泛型类型参数的方法。

下面是一个示例的泛型方法的定义:

public class MyGenericMethod {
    public <T> void printItem(T item) {
        System.out.println("Item: " + item);
    }
}

在上述示例中,printItem() 是一个泛型方法,其中的 <T> 表示类型参数。通过使用泛型方法,我们可以在调用方法时指定参数的类型,从而使方法可以适用于不同类型的参数。

通配符

通配符是泛型中的一个重要概念,用于表示未知类型。在Java泛型中,我们可以使用通配符来限制类型参数的范围。

  • ?:表示未知类型,可以用于表示任意类型。

  • ? extends T:表示类型的上界限定,表示类型参数是 T 或 T 的子类。

  • ? super T:表示类型的下界限定,表示类型参数是 T 或 T 的父类。

下面是一个示例,展示如何使用通配符:

public class GenericExample {
    public void process(List<?> list) {
        for (Object item : list) {
            System.out.println("Item: " + item);
        }
    }
​
    public void addItems(List<? super Integer> list) {
        list.add(1);
        list.add(2);
        list.add(3);
    }
​
    public List<? extends Number> getNumbers() {
        List<Integer> integers = new ArrayList<>();
        integers.add(1);
        integers.add(2);
        integers.add(3);
        return integers;
    }
}

在上述示例中,process() 方法接收一个通配符类型的 List,并对列表中的元素进行遍历打印。

addItems() 方法接收一个下界限定为 IntegerList,并向列表中添加整数元素。

getNumbers() 方法返回一个上界限定为 Number 的列表,其中元素为整数。

类型擦除

Java泛型使用了类型擦除(Type Erasure)的机制。在编译时,泛型类型会被擦除,并替换为其上界或Object类型。这意味着在运行时无法获取泛型类型的具体信息。

例如,List<String> 在编译时会被擦除为 ListList<Object>

虽然在运行时无法获取泛型类型的具体信息,但在编译时仍然可以进行类型检查,以确保类型的安全性。