Java中的泛型类型擦除

时间:2015-10-16 18:40:11

标签: 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> {
    T ob;

    public Gen(T x) {
        ob = x;
    }
}

这是输出

class Gen               // This I understand
class java.lang.Integer // But if type erasure is happening, shouldn't this be java.lang.Object?

我认为Type参数T在运行时被删除,但为什么ob的类型参数在运行时会存活?

5 个答案:

答案 0 :(得分:4)

都能跟得上!

考虑一下:

Object x = new Integer(1);
System.out.println(x.toString());

你会得到1

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

没有。虽然xObject类型的引用,但实际引用是Integer,因此在运行时,Integer的{​​{1}}实现会被调用。

toString的情况相同。

答案 1 :(得分:2)

Type erasure正在发生。泛型是一个编译时类型检查系统。在运行时,您仍然可以获得该类(它是运行时类型信息)。链接的类型擦除文档说(部分)

  

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

     

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

您的实例有一个类型,它是Object。但是Object引用可以引用Java中的任何子类(每个类)。你得到它所引用的类型。

答案 2 :(得分:2)

无论变量具有什么类型,getClass()的返回值都取决于变量的内容。因此,由于您基本上有一个变量Object ob,其中包含Integer(您在提供它时将int转换为该构造函数的参数),{{1}的输出是} 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; }
}

您会注意到输出不是public static void main(String... args) { Baz<Foo> obj = new Baz(new Bar()); System.out.println(obj.object.getClass()); } ,而是class Foo

答案 3 :(得分:2)

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

在运行时分配给ob的实际对象是Integer类的实例,而ob.getClass()用于找出指针引用的对象的实际类 - &gt;因此你会看到java.lang.Integer打印。

记住,出来的是有效的类Gen {Object ob; ......}

答案 4 :(得分:0)

由于我第一次接触泛型是使用C#,所以需要时间来掌握java中的类型擦除。

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

主要问题是,为什么第二次打电话

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

返回java.lang.Integer而不是java.lang.Object

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

  

返回此Object的运行时类。

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

例如:

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

输出不是参考java.lang.Object的类型,而是对象java.lang.String实际类型。