Java中泛型的擦除机制

2023-12-21 10:28:35

Java中的泛型擦除(Generics Type Erasure)是Java编译器应用的一个过程,用来允许泛型代码与在Java引入泛型之前(Java 5之前)编写的遗留代码兼容。泛型擦除的主要作用是在编译时期检查泛型的类型安全,并提供泛型的类型信息,但在编译后的字节码中去除所有泛型类型信息。这意味着泛型类和方法在字节码层面上将只使用原生类型(Raw Types)。

泛型擦除的具体行为包括:

  1. 类型擦除:泛型类型变量被擦除替换为第一个边界的类型(如果存在边界),或者Object(如果没有指定边界)。例如,List<T>在运行时会变成ListList<String>也会变成List

  2. 类型检查:编译器在编译时期会使用泛型信息进行类型检查,确保代码中对泛型类型的使用是类型安全的。

  3. 桥接方法:如果泛型类型擦除导致方法签名的变化,编译器会生成桥接方法(Bridge Methods)来保持多态性。这是Java编译器生成的额外方法,用来保证子类能正确地覆盖父类或接口中的泛型方法。

  4. 类型转换:在必要的地方插入类型转换,以保证类型安全的实例化。由于运行时类型信息已经被擦除,所以需要在代码中的特定位置插入强制类型转换,以维持程序的行为。

举个例子,下面的泛型类在运行时会受到类型擦除的影响:

public class Box<T> {

    private T t;

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

    public T get() {
        return t;
    }
}

// 使用泛型
Box<String> stringBox = new Box<>();
stringBox.set("Hello World");
String value = stringBox.get();

在编译时,Box<T> 中的 T 被擦除,并替换为 Object。所以,即使你创建了一个 Box<String>,在运行时 Box 类中的所有 T 都会被当作 Object 类型处理。因此,编译后的代码会类似于下面这样:

public class Box {

    private Object t;

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

    public Object get() {
        return t;
    }
}

// 使用擦除后的类型
Box stringBox = new Box();
stringBox.set("Hello World");
String value = (String) stringBox.get(); // 显式的类型转换

注意,泛型擦除可能导致某些类型信息在编译后不可用,这意味着你在运行时无法获取泛型的类型参数。例如,你无法直接检查一个集合是否是 List<String>List<Integer>,因为在运行时它们都只是 List。这就是为什么有时你需要通过其他方式来传递类型信息,如通过方法参数(Class<T> clz)或使用反射技术。

文章来源:https://blog.csdn.net/weixin_45979976/article/details/135122570
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。