大家好,我是“福尔摩斯”上身的二哥呀!
创新互联建站专注于中大型企业的做网站、成都做网站和网站改版、网站营销服务,追求商业策划与数据分析、创意艺术与技术开发的融合,累计客户千余家,服务满意度达97%。帮助广大客户顺利对接上互联网浪潮,准确优选出符合自己需要的互联网运用,我们将一直专注品牌网站建设和互联网程序开发,在前进的路上,与客户一起成长!
由于最近经常在知乎上回答问题,所以吴某和都某的瓜我第一时间就吃了。我心想,这次XX彻底凉凉了呀,没想到最后警方通报是一期金钱诈骗案,我当时就炸了!
我去,还带这种操作呀!
这件事给二哥造成了极坏的后遗症,以至于我满脑子都是破案、破案、破案,一直到现在,还没有彻底消退。
这不,有读者在《教妹学Java》专栏的第 46 讲:泛型里提了这样一个问题:关于类型擦除的。
我当时就决定了:我一定要破这个案!Java 泛型表面一套背后一套的作法实在是太可恶了。
害,为了让大家学点真正的技术,二哥也是费尽心思啊。
简单来回顾一下类型擦除,看下面这段代码。
- public class Cmower {
- public static void method(ArrayList
list) { - System.out.println("Arraylist
list"); - }
- public static void method(ArrayList
list) { - System.out.println("Arraylist
list"); - }
- }
在浅层的意识上,我们会认为 ArrayList list 和 ArrayList list 是两种不同的类型,因为 String 和 Date 是两个不同的类。
但由于类型擦除的原因,以上代码是不会编译通过的——编译器会提示一个错误:
'method(ArrayList)' clashes with 'method(ArrayList)'; both methods have same erasure
意思就是说,两个 method() 方法经过类型擦除后的方法签名是完全相同的,Java 是不允许这样做的。
按照我们的假设:如果 Java 能够实现真正意义上的泛型,两个 method() 方法是可以同时存在的,就好像方法重载一样。
- public class Cmower {
- public static void method(String list) {
- }
- public static void method(Date list) {
- }
- }
为什么 Java 不能实现真正意义上的泛型呢?背后的原因是什么?
第一,兼容性
Java 在 2004 年已经积累了较为丰富的生态,如果把现有的类修改为泛型类,需要让所有的用户重新修改源代码并且编译,这就会导致 Java 1.4 之前打下的江山可能会完全覆灭。
想象一下,你的代码原来运行的好好的,就因为 JDK 的升级,导致所有的源代码都无法编译通过并且无法运行,是不是会非常痛苦?从此再也不爱 Java 了呢?
类型擦除就完美实现了兼容性,Java 1.5 之后的类可以使用泛型,而 Java 1.4 之前没有使用泛型的类也可以保留,并且不用做任何修改就能在新版本的 Java 虚拟机上运行。
老用户不受影响,新用户可以自由地选择使用泛型,可谓一举两得。
第二,不是“实现不了真正的泛型”
Pizza,1996 年的实验语言,在 Java 的基础上扩展了泛型。
Pizza 教程地址:http://pizzacompiler.sourceforge.net/doc/tutorial.html
这里插一下 Java 的版本历史,大家好有一个时间线上的观念。
也就是说,Pizza 在 JDK 1.0 的版本上就实现了“真正意义上的”泛型,我引过来两段例子,大家一看就明白了。
首先是 StoreSomething,一个泛型类,标识符是大写字母 A 而不是我们熟悉的大写字母 T。
这个 A 呢,可以是任何合法的 Java 类型(比如说 String 和 int):
- StoreSomething
a = new StoreSomething("I'm a string!"); - StoreSomething
b = new StoreSomething(17+4); - b.set(9);
- int i = b.get();
- String s = a.get();
- ArrayList
ints = new ArrayList (); - ArrayList
strs = new ArrayList (); - System.out.println(ints.getClass());
- System.out.println(strs.getClass());
- class java.util.ArrayList
- class java.util.ArrayList
那 Pizza 这种“真正意义上的泛型”为什么没有被 Java 采纳呢?想必这是大家都很关心的问题。
站在马后炮的思维来看,Pizza 的泛型设计和函数式编程非常具有历史前瞻性。然而 Java 的核心开发组在当时似乎并不想把函数式编程引入到 Java 中。
以至于 Java 在 1.4 之前仍然是不支持泛型的,为什么 Java 1.5 的时候又突然支持泛型了呢?
- ArrayList list = new ArrayList();
- list.add("沉默王二");
- list.add(new Date());
不管是 String 类型,还是 Date 类型,都可以一股脑塞进 ArrayList 当中,这看起来似乎很方便,但取的时候就悲剧了。
- String s = list.get(1);
- String s = (String) list.get(1);
- Exception in thread "main" java.lang.ClassCastException: java.util.Date cannot be cast to java.lang.String
Java 语言和其他编程语言不一样,有着沉重的历史包袱,1.5 之前已经有大量的程序部署在生产环境下了,这时候如果一刀切,原来没有使用泛型的代码直接扼杀了,后果不堪想象。
但 Java 并不支持高版本 JDK 编译生成的字节码文件在低版本的 JRE(Java 运行时环境)上跑。
- ArrayList
ints = new ArrayList (); - ArrayList
strs = new ArrayList (); - ArrayList list;
- list = ints;
- list = strs;
如果要实现泛型,又要保证之前的代码不受影响,上面这段代码必须得能够编译运行。怎么办呢?
编译前进行泛型检测,ArrayList 只能放 Integer,ArrayList 只能放 String,取的时候就不用担心类型强转出错了。
但编译后的字节码文件里,是没有泛型的,放的都是 Object。
一个好消息是 Valhalla 项目正在努力解决这些因为泛型擦除带来的历史遗留问题。
Project Valhalla:正在进行当中的 OpenJDK 项目,计划给未来的 Java 添加改进的泛型支持。
源码地址:http://openjdk.java.net/projects/valhalla/
希望能给我们带来真正意义上的泛型?也许 9 月份的 JDK 17 就有了?
本文转载自微信公众号「沉默王二」,可以通过以下二维码关注。转载本文请联系沉默王二公众号。
新闻标题:破案了!关于Java泛型擦除的那些破事
当前路径:http://www.kswsj.com/qtweb/news11/186211.html
网站建设、网络推广公司-成都快上网,一家网站设计、网站制作公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 成都快上网