学习

深入理解Java中的泛型(三)泛型类型擦除与泛型转译

2021-08-23  本文已影响0人  不思进取的码农

什么是泛型类型擦除

先看一道经典的测试题

List<String> list1 = new ArrayList<String>(); 
List<Integer> list2 = new ArrayList<Integer>();
System.out.println(list1getClass() == list1.getClass()); 

上面代码最终结果输出的是什么?不了解泛型的和很熟悉泛型的同学应该能够答出来,而对泛型有所了解,但是了解不深入的同学可能会答错。

正确答案是 true。

上面的代码中涉及到了泛型,而输出的结果缘由是类型擦除

简单概括泛型的类型擦除
泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。

通过泛型转译来解决类型擦除问题

public class Erasure <T>{
    T object;

    public Erasure(T object) {
        this.object = object;
    }
    
}

Erasure 是一个泛型类,我们查看它在运行时的状态信息可以通过反射

Erasure<String> erasure = new Erasure<String>("hello");
 Class eclz = erasure.getClass(); 
System.out.println("erasure class is:"+eclz.getName());

打印的结果是

erasure class is:com.frank.test.Erasure

Class 的类型仍然是 Erasure 并不是 Erasure<T>这种形式,那我们再看看泛型类中 T 的类型在 jvm 中是什么具体类型。

Field[] fs = eclz.getDeclaredFields();
for ( Field f:fs) {
    System.out.println("Field name "+f.getName()+" type:"+f.getType().getName());
}

打印结果是

Field name object type:java.lang.Object

那我们可不可以说,泛型类被类型擦除后,相应的类型就被替换成 Object 类型呢?

这种说法,不完全正确。

我们更改一下代码。

public class Erasure <T extends String>{
//  public class Erasure <T>{
    T object;

    public Erasure(T object) {
        this.object = object;
    }
    
}

现在再看测试结果:

Field name object type:java.lang.String

我们现在可以下结论了,在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如<T>则会被转译成普通的 Object 类型,如果指定了上限如<T extends String>则类型参数就被替换成类型上限。

上一篇 下一篇

猜你喜欢

热点阅读