📜  Java中的类型擦除

📅  最后修改于: 2022-05-13 01:54:49.830000             🧑  作者: Mango

Java中的类型擦除

先决条件:泛型
Java语言中引入了泛型概念,以在编译时提供更严格的类型检查并支持泛型编程。实现泛型的方式, Java编译器将类型擦除应用于:

  • 如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或 Object。因此,生成的字节码只包含普通的类、接口和方法。
  • 必要时插入类型转换以保持类型安全。
  • 生成桥方法以保留扩展泛型类型中的多态性。

一般来说,编译后的泛型代码实际上只使用Java.lang.Object ,无论您谈论 T (或其他一些类型参数) - 并且有一些元数据告诉编译器它确实是一个泛型类型。当您针对泛型类型或方法编译一些代码时,编译器会计算出您真正的意思(即 T 的类型参数是什么)并在编译时验证您正在做正确的事情,但再次发出的代码只是在Java.lang.Object 方面进行讨论——编译器会在必要时生成额外的强制转换。在执行时,一个List和一个List是完全一样的;额外的类型信息已被编译器删除。

根据程序,类型擦除如何工作?

// Here, T is bounded by Object i.e. java.lang.Object
class GFG {
// Here, T will be replaced by default i.e. Object
    T obj; 
  
    GFG(T o)
    {
        obj = o;
    }
    T getob()
    {
        return obj;
    }
}

编译后,代码被默认 Object 替换,如下所示:

class GFG
{
// Here, T will be replaced by default i.e. Object
    Object obj;
    GFG(Object o)
    {
        obj=o;
    }
    Object getob()
    {
        return obj;
    }
}
// Here, T is bounded by Object i.e. java.lang.Object
class Geeks {
  
 // Here, T will be replaced by String i.e. java.lang.String
    T str;
    Geeks(T o)
    {
        str = o;
    }
    T getob()
    {
        return str;
    }
}

编译后,将代码替换为字符串,如下所示:

class Geeks
{

//Here, T will be replaced by String i.e. java.lang.String
    String str;

    Geeks(String o)
    {
        str=o;
    }
    String getob()
    {
        return str;
    }
}

注意:以上两个类编译完成后,我们可以查看这两个类的内容。编译完成后,GFG 中的 T 类将被 Object 替换,Geeks 中的 T 类将被 String 替换。我们可以通过javap className命令运行编译后的代码来查看内容。

类型擦除实现

// Java program to illustrate
// concept of TypeErasure
  
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericsErasure {
    public static void main(String args[])
    {
        List list = new ArrayList();
        list.add("Hello");
        Iterator iter = list.iterator();
        while (iter.hasNext()) {
            String s = iter.next();
            System.out.println(s);
        }
    }
}

说明:这里当我们编译代码时,它不会向控制台屏幕抛出任何警告消息,因为这里我们使用的是类型擦除。

// Java program to illustrate
// concept of TypeErasure
import java.io.PrintStream;
import java.util.*;
  
public class GenericsErasure {
  
    public GenericsErasure()
    {
    }
  
    public static void main(String args[])
    {
        List list = new ArrayList();
        list.add("Hello");
        String s;
        for (Iterator iter = list.iterator(); iter.hasNext();
             System.out.println(s))
            s = (String)iter.next();
    }
}

说明:这里当我们编译代码时,我们会从编译器那里得到一些注释,即GenericsErasure。 Java使用未经检查或不安全的操作。

参考:
类型擦除
堆栈溢出