java中有类(class)、方法(method)、域(field) 、接口 它们都能使用泛型,但域的泛型要和类关联(且除了静态数据成员以外,因为它不和实例相关联,泛型类是和实例相关联的)。
简单介绍下泛型的一些基本术语,以ArrayList<E>和ArrayList<Integer>做简要介绍:
整个成为ArrayList<E>泛型类型
ArrayList<E>中的 E称为类型变量或者类型参数
class Generic<E>{}中的E称为泛型参数
整个ArrayList<Integer> 称为参数化的类型
ArrayList<Integer>中的integer称为类型参数的实例或者实际类型参数
·ArrayList<Integer>中的<Integer>念为typeof Integer
ArrayList称为原始类型
①边界
边界是类型参数的一种限制条件(约束),一般都是限制某个参数为某个类型的子集(定义的时候),为了执行这种限制,java泛型重用了extends关键字。
1、不管该限定是类还是接口,统一都使用关键字 extends,泛型参数不能给出超类型边界(即super)
如class CanineHero <P extends superHearing & SuperMell>
extends后面是一个确切类型
自限定:Class Generic <T extends Generic<T>>{} Generic<T>相当于Generic<String>是一个参数类型为T的类型,是T的边界
②通配符
List<?> 包含的是任意类型的List(无界通配符)
List<? extends Number>包含的是Number或者其子类的List(上界通配符)
List<? super Integer> 包含的是Integer或者其父类的List(逆变,下界通配符)
这个其实已经是指定了类型参数了,指定类型参数包括两种,一是直接确定类型参数;而是用通配符。因此可以是List<String>或者List<?>这样
③泛型擦除
由于java和C++实现泛型方式不一样,java是code share的方式,即只有一个字节码对应多种不同的类型。实现此方式需要用到泛型擦除,这是java实现泛型的底层原理。
如何擦除?
1.将所有的泛型参数用其最左边界类型(限定类型)替换。<T>等同于<T extends Object>即T会用Object代替
2.移除所有的类型参数。
class Collections {
public static <A extends Comparable<A>>A max(Collection <A> xs) { //<>中的A不用管,只有定义的时候方法前面的是泛型参数,方法内部的是类型参数
Iterator <A> xi = xs.iterator();
A w = xi.next();
while (xi.hasNext()) {
A x = xi.next();
if (w.compareTo(x) < 0) w = x;
}
return w;
}
}
类型擦除后:
class Collections {
public static Comparable max(Collection xs) {
Iterator xi = xs.iterator();
Comparable w = (Comparable) xi.next();
while (xi.hasNext()) {
Comparable x = (Comparable) xi.next();
if (w.compareTo(x) < 0) w = x;
}
return w;
}
}
首先A被Comparable<A>代替 静态方法内部不用管,则A w = xi.next(); 类型擦除后变成Comparable<A> w = xi.next();
第二步移除所有的类型参数 Comparable<A> w = xi.next(); 变成 Comparable w = xi.next();
④类型擦除引起的问题及解决方法
先检查,再编译。检查针对的是引用。
既然说类型变量会在编译的时候擦除掉,那为什么我们往ArrayList<String> arrayList=new ArrayList<String>();所创建的数组列表arrayList中,不能使用add方法添加整形呢?不是说泛型变量Integer会在编译时候擦除变为原始类型Object吗,为什么不能存别的类型呢?既然类型擦除了,如何保证我们只能使用泛型变量限定的类型呢?
java是如何解决这个问题的呢?java编译器是通过先检查代码中泛型的类型,然后再进行类型擦除,再进行编译的。
public static void main(String[] args) {
ArrayList<String> arrayList=new ArrayList<String>();
arrayList.add("123");
arrayList.add(123);//编译错误
}
因为arrayList是ArrayList<String>类型的引用,编译器会查看上下文,检查到第三行arrayList.add(123)时,由于其中加的是整型数据,所以自动报错。
接着会编译。
部分参考:http://blog.csdn.net/lonelyroamer/article/details/7868820