Java 泛型擦除

1352040452 发布于 05/07 16:42
浏览 4K+
收藏 20

精选30+云产品,助力企业轻松上云!>>>

比来在进修泛型,一向不睬解泛型擦除是怎样回事,也查阅很多博客但照样不睬解,都没说清楚泛型擦除是怎样停止的,是怎样擦除的,都是说泛型擦除是在编译后,然后将泛型信息擦除,将泛型编译为参数类型对应的类型:

有Test.java文件,文件内容为

public static void main(String[] args){

List<String> list=new ArrayList();①

}

成绩1:泛型擦除是在编译后,编译后就是把全部.java文件编译成.class文件,擦除是擦除的是履行①后的实际对象中的吗?这仿佛也说不通,由于new ArrayList() 的时辰并没无限制类型,只是在声明的时辰限制了类型

 

成绩2:由于查阅材料都说的是编译落先行泛型擦除,就是说这个弗成能是在new一个对象的时辰停止泛型擦除,由于编译时还不克不及肯定new 的详细是哪个对象,

那么泛型擦除究竟是哪个阶段停止的?泛型擦除的详细wei'z是在哪?

加载中
1
乌龟壳
乌龟壳

泛型擦除这个器械实际上是很罕见,就像面向对象常常说起封装一样,封装其实不只是面向对象才有,泛型擦除乃至类型擦除很多说话都须要这么做

比如你在计算 10 个苹果 + 5 个苹果,一共有若干个苹果,输入给计算器的是 10 + 5 就好了,计算器其实不须要知道你是在算苹果,苹果这个类型就被你擦除

同理在 c 说话里定义一个 struct,编译成机械码后其实不存在甚么 struct 这类的器械,这就是类型擦除

再回到 java 的泛型,java 普通的编译目标是 jvm 的 bytecode,这个 jvm 的 bytecode 不支撑表现任何泛型信息(这是汗青缘由形成的缺点),然则类型信息还有,所以就特别叫其泛型擦除

然则这个平平常常的任务为甚么会特别提出来呢?就是由于 java 设计上的缺点,又要支撑运转时反射,又没法携带泛型信息,如许就招致 java 的泛型功能很受限制,比如没法针对 int/double 这类标量类型做泛型,有些数学相干的请求性能的库,会是以没法借助泛型去停止通用的高性能完成

懂得由于 java 编译器和 jvm 的缺点,招致的泛型擦除,有助于懂得 java 的一些限制的由来,我小我懂得这是 java 的遗憾罢了,等待将来能处理

其实比来我也在渐渐测验测验用其他说话,比如 Rust TypeScript 等去处理成绩,而不会绑逝世在 java 平台上,java 平台过于重视汗青兼容性,会制约 java 的生长

过马路的蚂蚁
过马路的蚂蚁
java 平台过于重视汗青兼容性 ----------------------------------------------------- 确切如此。应当吧java1.2、1.3标记不建议应用的器械都从jdk中删除。 运转时泛型参加,欲望Oracle后续渐渐参加了。
0
tcxu
tcxu

    Java中的泛型根本上都是在编译器这个层次来完成的,在生成的Java字节代码中是不包含泛型中的类型信息的。就是说,Java 的泛型在编译器有效,在编译后都邑被清除掉落 (类型擦除type erasure)。成果,由泛型附加的类型信息对JVM来讲是弗成见的。如许做的目标是,进步运转期的效力,更好地支撑原生类型(Raw Type),确保版本兼容。

图1. 泛型类型信息擦除(type erasure)产生的地位

成绩1:Java 泛型(generics)是 JDK 5 中引入的一个新特点, 它供给了编译时类型安然检测机制。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。比如,要创建一个 元素为字符串类型的数组列表,代码必须写成:

List<String> list = new ArrayList<String>();

jdk 1.7 中的更新包含:"泛型类实例化也不消繁琐的将泛型声明再写一遍"。这时候,上述代码行便可以写成:

 List<String>  list = new ArrayList<>();

不管如何写这行代码,个中的援用 list, 都规定了列表数组元素的类型必须是 String 类。而这类限制, 即<String>的标记,不是在编辑了这行代码后,而是在编辑器(java compiler)完成了对给定代码文档的全部编译(翻译成字节码文档 .class)以后,才损掉落的。是以,在这行代码行(在创建了这个 字符串数组列表实体)以后,编译器才能时辰监督个中有关数组元素的操作,能否是符合 字符串 String 类型的操作规矩。

成绩2:同上所述,编译 上述代码行 :List<String> list = new ArrayList();   明白标明此处 new 出的详细对象(list)是 字符串数组元素类型的列表。而这个规定,即 这个 参数为字符串类型的泛型标记 <String>, 一向要保存到编译过程的终点,从而得以对该代码行今后的编译,停止"监控",以顺利完成编译出字节码文档的义务。

参考:The Java™ Tutorials — Generics :Type Erasure 类型清除

 

木九天
木九天
哈哈
0
kakai
kakai

总结就是编译时擦除,运转时泛型被擦除,泛型束缚是有效的,在运转过程当中都是Object

0
跟猪谈幻想
跟猪谈幻想

java泛型擦除是如许的

比如你写了 List<String> list=new ArrayList<>()  这里 ArrayList 中的泛型 是由于语法糖,它等价于 List<String> list=new ArrayList<String>() 。

如许你就定义了一个list 对象,当你写 list.add("foo");时辰编译正常经过过程,然则当你写 list.add(1);时辰编译就会报错,经过过程不了。对list中的泛型检查只在编译阶段停止的检查。运转的时辰,是没有泛型的,被擦除掉落了。 你可以经过过程asm等技巧,修改编译后的class文件 , 在list中放入一个 int 类型的1 , 也是可以成功的

0
chentao106
chentao106
java的泛型只是编译时检查机制,编译后都是object,就是所谓擦除
0
1352040452
1352040452
取一个list中的数据他能取出对应类型的元素,而擦除以后是object类型,桥办法是甚么时辰生成的?又怎样根据对应的类型生成乔办法呢?
0
xflcx1991
xflcx1991
楼主你能够困惑为甚么供给了泛型却又供给的不敷完全,干吗要擦出,为甚么c#就不擦出。 这须要看汗青,早期java没有泛型,jdk5开端有了,大年夜的变更引入又要推敲字节码兼容性,这是很大年夜的一个身分。
0
J
Jason909

Java源码中泛型信息出现的处所:类型、办法、字段、变量的声明或定义;构造器、办法的调用。

编译后的字节码中:声明或定义中的泛型信息会被保存,所以开辟对象才能在没有源码的情况下知道一个类或办法是否是泛型的;也能够在运转时经过过程反射获得字段的泛型类型。调用处的泛型信息会被擦除,所以不会像C#那样根据调用构造器时的泛型信息实例化出不合类型的对象,C#的泛型完成方法叫类型收缩法。

运转时,字节码中的泛型信息可以被忽视而不影响法式榜样的履行后果,从而供给更好的兼容性,不过下面提到的经过过程反射获得泛型类型这类代码肯定是没法向后兼容的。不清除运转时可以根据字节码中的泛型信息停止性能优化,比如增添类型检查。

0
f
freezingsky

java 代码 须要 转为asm 代码,转换以后的asm不保存其类型信息。

0
青黑
青黑

c++模板在编译时会展开,std::vector<int> std::vector<double>在编译以后会生成两个自力的类,两个不合的类符号信息,这一过程就是编译期运算,使得c++的模板可以写出扩大性极佳的代码。

java模板在编译时会被擦除,编译的时辰Vector<int> Vector<double>本质上时同一个类,这一过程就是擦除。这使得java的模板只是一个语法,其实不会对最后编译成果有影响。

前往顶部
顶部