Java 泛型和擦除过程

Java 泛型和擦除过程,java,generics,Java,Generics,我对用Java编写的这篇文章感到怀疑: 在介绍中,我们看到了泛型类型的调用 声明列表,如列表。在调用中(通常是 称为参数化类型),所有出现的形式化类型 参数(在本例中为E)替换为实际类型参数 (在本例中为整数) 但是,如果没有限制,则形式类型参数不会被Object替换? 为什么说E被整数代替 此外,Java教程中还提到: 要从代码中引用泛型Box类,必须 执行泛型类型调用,用一些具体的 值,例如整数: 但是,由于擦除,编译时T in-box类被替换了 按对象而不是按整数。整数类型仅为强制转换操作

我对用Java编写的这篇文章感到怀疑:

在介绍中,我们看到了泛型类型的调用 声明列表,如列表。在调用中(通常是 称为参数化类型),所有出现的形式化类型 参数(在本例中为E)替换为实际类型参数 (在本例中为整数)

但是,如果没有限制,则形式类型参数不会被Object替换? 为什么说E被整数代替

此外,Java教程中还提到:

要从代码中引用泛型Box类,必须 执行泛型类型调用,用一些具体的 值,例如整数:

但是,由于擦除,编译时T in-box类被替换了 按对象而不是按整数。整数类型仅为强制转换操作编写

事实上,仍然是这样说的:

在类型擦除过程中,Java编译器将擦除所有类型 如果类型为 参数是有界的,如果类型参数是无界的,则为对象

我真的很困惑。这是事实吗?
T
是被
整数
替换还是被
对象
替换

the formal type parameter is not replaced by Object?

运行时中表示为
对象的泛型类型。但是您可以通过反射获取有关
的信息。擦除涉及到与旧类别的兼容性。这是个坏主意

你说的是不同的事情

本教程中的引用谈到类型实例化。这与类型擦除无关,类型擦除是一个命名错误的概念,只是意味着泛型类型在运行时不再可用

但在编译时它们是,实例化发生在编译时

要回答您的问题,“在编译时”是一个宽泛的概念。以下部分均在编译时完成:

  • 读取源文件
  • 词汇分析
  • 解析
  • 类型检查
  • 代码生成
  • 请注意,这份清单绝对不完整。 但是,正如您所看到的,在类型检查期间,编译器知道您的类型实例化并可以检查它们

    之后,它会发出字节码,因为字节码无法表示泛型,所以类型被“擦除”,这意味着在这里和那里插入强制转换

    因此,您认为“编译时”是所有事情同时发生的瞬间的假设是不正确的


    进一步编辑:

    我认为你把这一切(即“替换”一词)看得太字面了。当然,编译器有一些数据结构,其中包含程序中所有项的类型、名称和作用域

    听着,原则上很简单,如果我们有:

    static <X> List<X> meth(X[] arr) { .... }
    
    静态列表方法(X[]arr){….}
    
    然后,你会:

    Integer arr = new Integer[100];
    List<Integer> list = meth(arr);
    Integer foo = list.get(1);
    
    Integer arr=新整数[100];
    列表=方法(arr);
    整数foo=list.get(1);
    
    然后实例化meth方法的类型:

    static List<Integer> meth(Integer[] arr) { .... }
    
    静态列表方法(整数[]arr){..}
    
    泛型的要点是说
    meth
    适用于任何类型。这正是编译器检查的内容。它将知道,对于所有X如果你传递一个X数组,你会得到一个X的列表,因此,由于你传递了整数[],结果必须是
    list
    ,并且
    list
    赋值是正确的。此外,编译器知道**对于所有X**,如果您从
    列表
    中获得一个元素,它将是一个X

    因此,编译器注意并检查foo是否为
    整数。稍后,在代码生成时,它将在那里插入一个转换为整数的转换,因为由于类型擦除,List.get的返回值是Object

    还要注意,“替换”并不意味着编译器会以某种方式修改代码。它只是从泛型类型签名创建(可能是临时的)一个非泛型签名(如果您更喜欢的话,可以将所有类型参数替换为它们的实际类型),并使用它来检查类型

    这就像在数学中,如果我说:请用42替换a,检查等式是否正确:

    a+1=43


    那么,问“到底在哪里”这个替换发生是没有意义的。最有可能是在你的大脑中。

    那句话不是在谈论擦除。那它意味着什么?问题到底是什么?@Nicusan,我不明白为什么说类型参数被类型参数替换,而由于擦除,如果没有边界,类型参数被编译时的对象替换。因此,在运行时,当我创建泛型类的实例时,如果我放置了,等等,它们不会替换类型参数,但仅用于类型检查、强制转换等。当它们在调用中说
    (通常称为参数化类型)时,所有形式类型参数的出现(在本例中为E)都会被实际的类型参数替换(在本例中为整数)。
    ,这并不意味着替换发生在编译时(当源文件转换为.class文件时)。这只是关于编译器在源代码开发期间如何查看参数化实例以供进一步参考。我的理解是,在编译时,擦除将用对象或上限类型替换类型参数。之后,在运行时,反射或其他API(如getClass())会检查该对象引用的内容(整数、字符串等)。对我来说,“在编译时”意味着编译器进行源代码编译,如果在编译时也进行了擦除,那么泛型类型信息如何仍然可用,或者整数如何替换T?@xdevel2000回答了有关“编译时”的问题.那么,您的意思是,在第7步-代码生成-发生擦除之前,类型参数将被实际的类型参数替换?但如果发生这种情况,则存储该信息(例如,T被整数替换)