Skip to content

擦拭法(Type Erasure)是 Java 泛型的实现方式之一。它是一种在编译时期擦除泛型类型信息的机制,使得泛型类型在运行时被擦除为其上界(或者是 Object 类型)。

在 Java 中,泛型是通过类型擦除来实现的。这意味着在编译时,泛型类型参数会被擦除,替换为它们的上界或 Object 类型。这样做是为了保持与旧版 Java 代码的向后兼容性。

擦拭法的一个重要结果是,在运行时无法获得泛型类型的具体信息。例如,无法在运行时判断一个对象的泛型类型参数是什么。这是因为在编译时,泛型类型信息已经被擦除了。

擦拭法的另一个结果是,泛型类型参数被擦除为它们的上界或 Object 类型,因此在使用泛型时需要注意类型安全性。编译器会插入必要的类型转换来确保类型安全,但在某些情况下可能会导致编译错误或运行时异常。

尽管擦拭法限制了在运行时获取泛型类型信息的能力,但它仍然提供了编译时类型检查和类型安全的好处。它使得泛型代码可以与非泛型代码进行互操作,并且可以在编译时捕获一些类型错误。

总之,擦拭法是 Java 泛型的一种实现方式,通过擦除泛型类型信息来实现类型安全和向后兼容性。虽然在运行时无法获得泛型类型的具体信息,但它仍然提供了编译时类型检查和类型安全的好处。

首先,让我们看一个使用多个泛型类型的例子:

public interface Pair<K, V> {
    K getKey();
    V getValue();
}

public class OrderedPair<K, V> implements Pair<K, V> {
    private K key;
    private V value;

    public OrderedPair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }

    public static void main(String[] args) {
        Pair<String, Integer> pair = new OrderedPair<>("One", 1);
        System.out.println("Key: " + pair.getKey());
        System.out.println("Value: " + pair.getValue());
    }
}

在这个例子中,我们定义了一个泛型接口Pair,它有两个类型参数KV,并声明了两个方法getKey()getValue()。然后,我们实现了这个接口的一个具体类OrderedPair,并在main方法中创建了一个 OrderedPair对象,其中K的类型是StringV的类型是Integer。通过这个例子,我们可以看到泛型接口的灵活性,我们可以根据需要指定具体的类型参数。

接下来,让我们看一个关于擦拭法的例子:

public class Node<T> {
    private T data;
    private Node<T> next;

    public Node(T data) {
        this.data = data;
        this.next = null;
    }

    public void setNext(Node<T> next) {
        this.next = next;
    }

    public Node<T> getNext() {
        return next;
    }

    public T getData() {
        return data;
    }

    public static void main(String[] args) {
        Node<String> node1 = new Node<>("Hello");
        Node<Integer> node2 = new Node<>(123);

        System.out.println("Node 1 data: " + node1.getData());
        System.out.println("Node 2 data: " + node2.getData());
    }
}

在这个例子中,我们定义了一个泛型类Node<T>,它有一个类型参数T。我们在类中使用了泛型类型T,并在构造函数和方法中使用了这个类型。然后,在main方法中,我们创建了两个Node对象,一个是Node<String> 类型的,另一个是Node<Integer>类型的。通过这个例子,我们可以看到擦拭法是如何在运行时擦除泛型类型信息的。