1.为什么需要泛型
泛型在Java中有很重要的地位,网上很多文章罗列各种理论,不便于理解,本篇将立足于代码介绍、总结了关于泛型的知识。希望能给你带来一些帮助。
先看下面的代码:
List list = new ArrayList();
list.add("CSDN_SEU_Cavin");
list.add(100);
for (int i = 0; i < list.size(); i++) {
String name = (String) list.get(i); //取出Integer时,运行时出现异常
System.out.println("name:" + name);
}
本例向list类型集合中加入了一个字符串类型的值和一个Integer
类型的值。(这样合法,因为此时list
默认的类型为Object
类型)。在之后的循环中,由于忘记了之前在list
中也加入了Integer
类型的值或其他原因,运行时会出现java.lang.ClassCastException
异常。为了解决这个问题,泛型应运而生。
2.泛型的使用
Java泛型编程是JDK1.5
版本后引入的。泛型让编程人员能够使用类型抽象,通常用于集合里面。
只要在上例中将第1行代码改成如下形式,那么就会在编译list.add(100)
时报错。
List<String> list = new ArrayList<String>();
通过List<String>
,直接限定了list集合中只能含有String
类型的元素,从而在上例中的第6行中,无须进行强制类型转换,因为集合能够记住其中元素的类型信息,编译器已经能够确认它是String
类型了。
3.泛型只在编译阶段有效
看下面的代码:
AyyayList<String> a = new ArrayList<String>();
ArrayList b = new ArrayList();
Class c1 = a.getClass();
Class c2 = b.getClass();
System.out.println(a == b); //true
上面程序的输出结果为true
。所有反射的操作都是在运行时的,既然为true
,就证明了编译之后,程序会采取去泛型化的措施,也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。
上述结论可通过下面反射的例子来印证:
ArrayList<String> a = new ArrayList<String>();
a.add("CSDN_SEU_Cavin");
Class c = a.getClass();
try{
Method method = c.getMethod("add",Object.class);
method.invoke(a,100);
System.out.println(a);
}catch(Exception e){
e.printStackTrace();
}
因为绕过了编译阶段也就绕过了泛型,输出结果为:
[CSDN_SEU_Cavin, 100]
4.泛型类和泛型方法
如下,我们看一个泛型类和方法的使用例子,和未使用泛型的使用方法进行了对比,两者输出结果相同,在这里贴出来方便读者体会两者的差异。泛型接口的例子有兴趣可以去找一些资料,这里就不赘述了。
(1)使用泛型的情况
public static class FX<T> {
private T ob; // 定义泛型成员变量
public FX(T ob) {
this.ob = ob;
}
public T getOb() {
return ob;
}
public void showTyep() {
System.out.println("T的实际类型是: " + ob.getClass().getName());
}
}
public static void main(String[] args) {
FX<Integer> intOb = new FX<Integer>(100);
intOb.showTyep();
System.out.println("value= " + intOb.getOb());
System.out.println("----------------------------------");
FX<String> strOb = new FX<String>("CSDN_SEU_Calvin");
strOb.showTyep();
System.out.println("value= " + strOb.getOb());
}
(2)不使用泛型的情况
public static class FX {
private Object ob; // 定义泛型成员变量
public FX(Object ob) {
this.ob = ob;
}
public Object getOb() {
return ob;
}
public void showTyep() {
System.out.println("T的实际类型是: " + ob.getClass().getName());
}
}
public static void main(String[] args) {
FX intOb = new FX(new Integer(100));
intOb.showTyep();
System.out.println("value= " + intOb.getOb());
System.out.println("----------------------------------");
FX strOb = new FX("CSDN_SEU_Calvin");
strOb.showTyep();
System.out.println("value= " + strOb.getOb());
}
输出结果均为:
T的实际类型是: java.lang.Integer
value= 100
T的实际类型是: java.lang.String
value= CSDN_SEU_Calvin