为什么 Java 不能实现真正意义上的泛型呢?背后的原因是什么?
第一,兼容性
Java 在 2004 年已经积累了较为丰富的生态,如果把现有的类修改为泛型类,需要让所有的用户重新修改源代码并且编译,这就会导致 Java 1.4 之前打下的江山可能会完全覆灭。
想象一下,你的代码原来运行的好好的,就因为 JDK 的升级,导致所有的源代码都无法编译通过并且无法运行,是不是会非常痛苦?
类型擦除就完美实现了兼容性,Java 1.5 之后的类可以使用泛型,而 Java 1.4 之前没有使用泛型的类也可以保留,并且不用做任何修改就能在新版本的 Java 虚拟机上运行。
老用户不受影响,新用户可以自由地选择使用泛型,可谓一举两得。
第二,不是“实现不了”
这部分内容参考自 R大@RednaxelaFX
Pizza,1996 年的实验语言,在 Java 的基础上扩展了泛型。
Pizza 教程地址:
http://pizzacompiler.sourcefo…
这里插一下 Java 的版本历史,大家好有一个时间线上的观念。
-
1995年5月23日,Java语言诞生
-
1996年1月,JDK1.0 诞生
-
1997年2月18日,JDK1.1发布
-
《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 1998年2月,JDK1.1被下载超过2,000,000次
-
2000年5月8日,JDK1.3发布
-
2000年5月29日,JDK1.4发布
-
2004年9月30日18:00 PM,J2SE1.5 发布
也就是说,Pizza 在 JDK 1.0 的版本上就实现了“真正意义上的”泛型,我引过来两段例子,大家一看就明白了。
首先是 StoreSomething,一个泛型类,标识符是大写字母 A 而不是我们熟悉的大写字母 T。
class StoreSomething {
A something;
StoreSomething(A something) {
this.something = something;
}
void set(A something) {
this.something = something;
}
A get() {
return something;
}
}
这个 A 呢,可以是任何合法的 Java 类型:
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();
对吧?这就是我们想要的“真正意义上的泛型”,A 不仅仅可以是引用类型 String,还可以是基本数据类型。要知道,Java 的泛型不允许是基本数据类型,只能是包装器类型。
除此之外,Pizza 的泛型还可以直接使用 new 关键字进行声明,并且 Pizza 编译器会从构造方法的参数上推断出具体的对象类型,究竟是 String 还是 int。要知道,Java 的泛型因为类型擦除的原因,程序员是无法知道一个 ArrayList 究竟是 ArrayList 还是 ArrayList 的。
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
都是 ArrayList 而已。
那 Pizza 这种“真正意义上的泛型”为什么没有被 Java 采纳呢?这是大家都很关心的问题。
事实上,Java 的核心开发组对 Pizza 的泛型设计非常感兴趣,并且与 Pizza 的设计者 Martin 和 Phil 取得了联系,新合作了一个项目 Generic Java,争取在 Java 中添加泛型支持,但不引入 Pizza 的其他功能,比如说函数式编程。
这里再补充一点维基百科上的资料,Martin Odersky 是一名德国计算机科学家,他和其他人一起设计了 Scala 编程语言,以及 Generic Java(还有之前的 Pizza),他实现的 Generic Java 编译器成为了 Java 编译器 javac 的基础。
站在马后炮的思维来看,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);
这样取行吗?
不行。
还得加上强制转换。



