前言
前两天看了Thinking in Java - chapter Generics - Migration compatibility
觉得收获很大,本文做一下记录和总结
泛型类型擦除
首先给出书上提到的例子:
//: generics/ErasedTypeEquivalence.java
import java.util.*;
public class ErasedTypeEquivalence {
public static void main(String[] args) {
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2);
}
} /* Output:
true
*///:~
在上面的代码中我们可以看到,两个传入了不同参数化类型(即String和Integer)的ArrayList类的类对象在Java看来其实是同一个对象(==号得出结论是两边是同一个对象)
也就是说尽管我们字面上理解这两个列表在类型上应该是不同的类型(它们一个存储字符串类一个存储整数类),但其实他们是同一个类型,即<>中的内容并没有起作用
以上可以证明,在我们使用泛型的时候,我们必须了解在Java程序运行的时候其实它本身并不知道某个类的类型参数,而是将所有规定了的参数化类型的都给抹除掉。
There’s no information about generic parameter types available inside generic code.
移植兼容性
那么为什么Java要擦除这些信息呢,直接将传入了不同类型参数的类定义为不同的类不是理所当然的事情么?
这里就牵涉到历史遗留的问题了,对于Java而言,泛型一开始并不是Java语言本身的内容,直到Java SE5泛型功能才被加入到Java语言中。那么在语言设计者在设计Java泛型之前已经有很多重要的程序被写出来并且运行在各种地方。如果JavaSE5发布后原先的程序变得无法运行,这个改动的成本就显得无法接受。为了向这种历史性问题妥协,即为了保证更新后不改变原有Java程序的正常运行或者原有程序可以很方便的被重写为使用了泛型的程序,我们才选择了在目前看来唯一且最好的解决方案——泛型类型擦除
感悟
在工程领域中更多时候我们是在做取舍,我总期待着写程序就应该纯粹一些,一切为了写出更好的软件去改变人的生活,但事实上如果为了写出更好的软件付出了不可接收的成本,那反而得不偿失了。