你有没有承诺过一些事情,并为这些承诺付出过代价。

比如你承诺你爸妈,过年回家带个媳妇儿,为了找媳妇儿,你是心力憔悴呀。

比如你给你对象承诺,以后家务都给你做,结果你是天天擦地、刷碗、做饭等。

有些承诺是因为太年轻,比如长大了我就嫁给你。

有些承诺是为了达到目的,比如我会对你好的。

有些承诺是为了保住工作,比如绝对可以按时完成。

我们所熟知的Java,曾经也做过承诺,那就是"二进制向后兼容",这个承诺是被明确写入《Java语言规范》中的。

那“二进制向后兼容”是什么意思呢,就是说比如你在JDK1.2编译出一个Class文件,必须保证这个文件在JDK999或者更新的版本中能够正常运行。

为什么要有这个承诺呢,我想大概率是为了让Java使用者放心大胆的编码,不用考虑版本升级带来的一系列不兼容问题,说白了,就是吸引使用者的到来。

我们前边提到了,承诺一些事情,势必会付出代价。那么Java有没有因此付出过代价呢?

答案是:有的。

一、承诺与代价

我们都知道2004年,也就是在我还在玩泥巴的年龄,Java更新了一个版本,即Java5.0。

这个版本中Java加入了泛型的语法特性。

Java选择的泛型实现方式是“类型擦除”,什么是类型擦除了,就是说,全部的泛型都被替换为原来的裸类型,并且在相应的地方插入了强制转换,比如ArrayList 、ArrayList 编译完后其实是同一个类型ArrayList ,也就可以理解成类型被擦除了。

名词说明:"裸类型"可以被认为是所有该类型泛型化实例的公共父类型

比如:ArrayList 、ArrayList 、ArrayList 的裸类型就是ArrayList

我们可以看下面一段代码:

package ss;

import java.util.ArrayList;

/**
* @author 木子的昼夜编程
*/
public class AA {
public static void main(String[] args) {
ArrayList<String> sarr = new ArrayList<>();
ArrayList<Integer> iarr = new ArrayList<>();

// 这就是裸类型 也就是没有任何泛型修饰
// 跟没穿衣服一样
ArrayList arrayList;

arrayList = sarr;
arrayList = iarr;
}
}

为什么说这是Java付出的代价呢?

  1. 我们无法使用基本类型作为泛型
    因为泛型类型擦除后,在使用的地方用到了强制转换,也就是从Object转换成基本类型,我们知道基本类型是不能强转的比如
Object o = (Object)1;

这种强制转换理论上是要报错的,因为Object不是基本类型的父类和基类。那肯定有人说了,我这样写了,代码没报错呀,那是因为编译器做了处理,自动转换成了

Object o = (Object)Integer.valueOf(1);

Java的作者给出的解决办法很简单,那就是既然没法转换,那我就索性不支持原生类型的泛型了。

好嘛,你这就决定了?作者为什么会这么爽快(也可能纠结了很久)的决定呢,因为。。 Java可以自动装箱、拆箱。这就导致了,我们使用泛型的地方都会涉及到装箱、拆箱,这也成为泛型慢的重要原因。

  1. 无法在运行期获取到泛型类型信息。
    这个是什么意思呢,Java泛型类型被擦除了,在运行期间,我们无法获取到泛型的真实类型,如果我们需要用这个类型创建对象等,我们需要多加一个参数,例如:
package ss;
import java.util.ArrayList;
import java.util.List;

/**
* @author 木子的昼夜编程
*/
public class AA<T> {

public static void main(String[] args) {
//
new AA<String>().test(new ArrayList<>(), String.class);
}

// 我们需要额外的一个参数 classType来传递泛型类型
public void test(List<T> list, Class<T> classType) {

}
}

但是再C#中,他的泛型用的是“具现化泛型”,他就可以支持基本类型,说白了就是你泛型是什么,编译后就会记录成什么,不会丢失。比如下边这段代码,对于学C#的人来说,他们很难想象,在Java中这些语法都是非法的。

/**
* @author 木子的昼夜编程
*/
public class AA<T> {

public void test(Object obj) {
if (obj instanceof T) {

}
T newObj = new T();
T[] arr = new T[10];
}

}

二、展望未来

2014年是Java泛型的10岁生日,这一年Oracle建立了一个名为Valhalla的语言改进项目,希望改进Java语言留下的各种缺陷,当然泛型的缺陷是这个项目的主要目标之一。

作为Java的使用者,我坚信,这门语言会朝着更好的方向发展。