最近在看Java源码,在Java容器类中所有容器都用到了泛型,然而Java中的泛型实际上是一种伪泛型。记录一下Java中泛型的实现。
用法
所谓泛型,即将类型参数化。看一个简单的例子,下面是JDK1.6中ArrayList的一个初始化方法
public ArrayList<Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
if(elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
在上面这个例子中,方法参数传入的是Collection<? extend E>, 表示的即一个继承类E的一个容器。
泛型方法
public static <E> void printArray(E[] inputArray)
{
System.out.println("This is genercity method");
}
泛型类
public class Box<T>{
private T t;
public T getT(){
return t;
}
public void setT(T t) {
this.t = t;
}
}
原理
As we all konw, Java中所有的类都继承自Object的类,所有在上面的代码中,将类型参数换成Object是仍然是可以运行的,而Java实现泛型就是通过这种方式实现的,所以叫伪泛型。
- Java的泛型实际上是相对编译器而言的,在Java生成的字节码文件中是不包含泛型信息的。在编译过程中,Java将正确的泛型的类型信息擦除变为Object,叫做类型擦除 *
用下面代码来证明这个过程
public class Test{
public static void main(String[] args) {
ArrayList<Integer> arrayList1 = new ArrayList<Integer>();
ArrayList<String> arrayList2 = new ArrayList<String>();
System.out.prinltn(arrayList1.getClass() == arrayList2.getClass());
}
}
从输出为true可以判断Java字节码中是没有泛型信息的。
类型擦除
既然泛型可以用Object来代替,那么为什么还要有类型擦除呢。看下面代码。
public class Test{
public static void main(String[] args) {
ArrayList<Object> arrayList1 = new ArrayList<Object>();
ArrayList<Integer> arrayList2 = new ArrayList<Integer>();
arrayList1.add(1);
arrayList2.add(1);
arrayList1.add("1"); //添加一个String
}
}
对于上面的arrayList1来说,加入你想把这个容器当成一个Integer容器,但是你却并没有向里面添加Integer。上面编译的代码并不会报错,所有等到运行的时候,取出的时候就很可能报ClassCastException异常。 当时对于arrayList2就不会发生这样的错误。
- Java泛型通常是针对编译器而言的,对于能在编译期间可以解决的错误,不要放在运行的时候去解决。*
类型擦除的局限性
由于种种原因,Java实现的并不是真正意义上的泛型,类型擦除简便的实现了泛型,但是这同样带来一些局限性。
反射
Java字节码中不包含泛型的类型信息,所以反射方面许多写法都不支持。如下
Collection<E>.class //获取泛型的class文件, 不支持
if(T instanceof Pair<Integer>) //不支持,但可以这样写if(T instanceOf Pair<?>)
定义泛型类,方法和接口
- 不能通过类型创建对象
//非法
T ele = new T();
T[] arr = new T[10];
由于类型擦除,Java只能创建Object对象,无法创建T类型对象
- 不能用于静态变量和方法
//非法
publc class Singleton<T> {
private static T instance;
public synchronized static T getInstance() {
if(instance == null) {
}
return instance;
}
}
由于类型擦除,Singleton只有一份,没办法做到每个Singleton
- 泛型与数组
Java禁止创建泛型数组。 泛型容器内部使用Object数组,如果要转换泛型容器为对应的数组,需要使用反射。
参考链接 http://blog.csdn.net/lonelyroamer/article/details/7868820 http://www.cnblogs.com/swiftma/p/5882988.html