Java中的泛型类型擦除

Java中的泛型类型擦除,java,generics,type-erasure,Java,Generics,Type Erasure,代码如下: public class Main { public static void main(String[] args) { Gen<Integer> g = new Gen<Integer>(5); System.out.println(g.getClass()); System.out.println(g.ob.getClass()); } } class Gen<T> {

代码如下:

public class Main {
    public static void main(String[] args) {
        Gen<Integer> g = new Gen<Integer>(5);

        System.out.println(g.getClass());
        System.out.println(g.ob.getClass());
    }
}

class Gen<T> {
    T ob;

    public Gen(T x) {
        ob = x;
    }
}
我知道类型参数
T
在运行时被擦除,但是为什么
ob
的类型参数在运行时仍然存在?

正在发生。泛型是一种编译时类型检查系统。在运行时,仍然会得到类(它是运行时类型信息)。链接类型擦除文档说明(部分)

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

如果类型参数是无界的,则用其边界或对象替换泛型类型中的所有类型参数。因此,生成的字节码只包含普通类、接口和方法

您的实例有一个类型,它是
Object
。但是
对象
引用可以引用Java中的任何子类(即每个类)。您将获得它所指的类型。

考虑这一点:

Object x = new Integer(1);
System.out.println(x.toString());
您将获得
1

但是我不应该得到Object.toString()吗

否。虽然
x
是类型为
Object
的引用,但实际引用的是
整数
,因此在运行时调用
整数
实现
toString


这与
getClass
相同

无论变量的类型是什么,
getClass()
的返回值取决于变量的内容。因此,由于您基本上有一个变量
对象ob
,它包含一个
整数
(您的
int
在作为构造函数的参数提供时被转换为该变量),
ob.getClass()
的输出是
class java.lang.Integer

另外,关于为什么
getClass()
会记住类型参数的问题:它不会。它所做的只是确定内容的类别。例如:

class Foo {
    public Foo() {}
}

class Bar extends Foo {
    public Bar() {}
}

class Baz<T> {
    public T object;

    public Baz(T object) { this.object = object; }
}
class-Foo{
公共Foo(){}
}
类栏扩展了Foo{
公共栏(){}
}
Baz类{
公众反对;
公共Baz(T对象){this.object=object;}
}
如果现在运行以下代码段

public static void main(String... args) {
    Baz<Foo> obj = new Baz(new Bar());
    System.out.println(obj.object.getClass());
}
publicstaticvoidmain(字符串…参数){
Baz obj=新的Baz(新条());
System.out.println(obj.object.getClass());
}

您将注意到,输出不是
class Foo
,而是
类栏

,因为编译时,class Gen有一个对象ob;仿制药从最终产品中消失。尖括号仅在编译时、静态类型检查期间起作用。这是编译器可以为您做的事情,让您有更好的安心,确保您正确使用集合和其他参数化类型


运行时分配给ob的实际对象是Integer类的实例,ob.getClass()用于查找指针->引用的对象的实际类,因此您将看到java.lang.Integer打印出来


记住,结果实际上是类Gen{Object ob;…}

因为我第一次接触泛型是使用C#,所以花了一些时间来掌握java中的擦除类型

但是在更好地理解java泛型之后,我意识到在我的问题中我混合了两个不同的主题:泛型和反射

主要问题是,为什么第二个电话打到这里

 System.out.println(g.getClass());
 System.out.println(g.ob.getClass());
返回
java.lang.Integer
而不是
java.lang.Object

查看
getClass()
的文档,答案变得显而易见

返回此对象的运行时类

因此,
getClass()
不返回引用的类型,而是返回引用引用的实际对象

例如:

Object o =  "abc";
System.out.println(o.getClass());

输出将不是引用
java.lang.Object
的类型,而是对象
java.lang.String

actual类型。这并没有回答OP的问题,即所包含对象的运行时类型为什么没有“擦除”。但它是(在字节码处),他把rtti和编译时信息搞混了。如果
carc=new Mercedes(),您需要开始区分变量、引用和对象你认为c.getClass()的结果应该是什么?为什么?谢谢大家的回答,我明白了now@Pshemo如果
car=new Volkswagen()你认为c.getEmissionValues()的结果应该是什么。。。抱歉,完全不相关,但我无法抗拒。@Pshemo可能取决于您是从单元测试还是实际生产代码中调用它。或者更痛苦的是,如果调用代码没有设置try/catch,它只会抛出异常。这就是我要做的。这并不能解释为什么
getClass()
返回
Integer
。在运行时分配给ob的实际对象是Integer类的一个实例。这就是你将如何发现的…那应该在答案中
Object o =  "abc";
System.out.println(o.getClass());