Skip to content

泛型

泛型的概念

泛型是 Java 5 引入的一个新特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

泛型类

泛型类是在定义类时使用泛型。以下是一个简单的泛型类示例:

java
// 定义一个泛型类
class Box<T> {
    private T t;

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }
}

public class GenericClassExample {
    public static void main(String[] args) {
        // 创建一个存储 Integer 类型的 Box 对象
        Box<Integer> integerBox = new Box<>();
        integerBox.set(10);
        Integer num = integerBox.get();
        System.out.println("Integer value: " + num);

        // 创建一个存储 String 类型的 Box 对象
        Box<String> stringBox = new Box<>();
        stringBox.set("Hello");
        String str = stringBox.get();
        System.out.println("String value: " + str);
    }
}

在上述代码中,Box 类是一个泛型类,T 是类型参数。在创建 Box 对象时,可以指定具体的类型,如 IntegerString

泛型接口

泛型接口与泛型类的定义和使用方式类似。以下是一个泛型接口的示例:

java
// 定义一个泛型接口
interface Generator<T> {
    T next();
}

// 实现泛型接口
class FruitGenerator implements Generator<String> {
    private String[] fruits = {"Apple", "Banana", "Cherry"};
    private int index = 0;

    @Override
    public String next() {
        if (index < fruits.length) {
            return fruits[index++];
        }
        return null;
    }
}

public class GenericInterfaceExample {
    public static void main(String[] args) {
        FruitGenerator generator = new FruitGenerator();
        String fruit = generator.next();
        while (fruit != null) {
            System.out.println(fruit);
            fruit = generator.next();
        }
    }
}

在这个例子中,Generator 是一个泛型接口,FruitGenerator 类实现了该接口并指定了具体的类型为 String

泛型方法

泛型方法是在定义方法时使用泛型。以下是一个泛型方法的示例:

java
public class GenericMethodExample {
    // 定义一个泛型方法
    public static <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.print(element + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        // 创建一个 Integer 数组
        Integer[] intArray = {1, 2, 3, 4, 5};
        // 创建一个 String 数组
        String[] stringArray = {"Hello", "World"};

        // 调用泛型方法打印 Integer 数组
        printArray(intArray);
        // 调用泛型方法打印 String 数组
        printArray(stringArray);
    }
}

在上述代码中,printArray 是一个泛型方法,它可以接受任何类型的数组作为参数。

泛型的好处

  • 类型安全:泛型的主要目标是提高 Java 程序的类型安全。通过使用泛型,编译器可以在编译时检查类型错误,避免在运行时出现 ClassCastException
  • 代码复用:泛型允许编写通用的代码,这些代码可以处理不同类型的数据,从而提高了代码的复用性。
  • 可读性:泛型代码更具可读性,因为它清楚地表明了所处理的数据类型。

泛型的通配符

在使用泛型时,有时需要使用泛型通配符来表示未知类型。Java 提供了三种通配符:

  • 无界通配符 <?>:表示未知类型。例如,List<?> 表示一个元素类型未知的列表。
  • 上界通配符 <? extends T>:表示类型是 TT 的子类。例如,List<? extends Number> 表示一个元素类型是 Number 或其子类的列表。
  • 下界通配符 <? super T>:表示类型是 TT 的父类。例如,List<? super Integer> 表示一个元素类型是 Integer 或其父类的列表。

以下是一个使用通配符的示例:

java
import java.util.ArrayList;
import java.util.List;

class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

public class WildcardExample {
    // 使用上界通配符
    public static void printAnimals(List<? extends Animal> animals) {
        for (Animal animal : animals) {
            System.out.println(animal);
        }
    }

    public static void main(String[] args) {
        List<Dog> dogs = new ArrayList<>();
        dogs.add(new Dog());
        dogs.add(new Dog());

        List<Cat> cats = new ArrayList<>();
        cats.add(new Cat());
        cats.add(new Cat());

        printAnimals(dogs);
        printAnimals(cats);
    }
}

在这个例子中,printAnimals 方法使用了上界通配符 <? extends Animal>,这意味着它可以接受任何元素类型是 Animal 或其子类的列表。