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());