大家先看看下面这段小程序
import java.util.List;
// 申明一个泛型类
public class GenericClass ... {
public static void main(String [] args) ...{
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
new Product().prt(list);
}
}
// 制造一个类用于说明问题
class Product ... {
public void prt(List<String> lt) ...{
System.out.println(lt);
}
}
编译器报错,说无法将Product中的prt(java.util.List<java.lang.String>)应用于(java.util.List<java.lang.Integer>)。前面定义了List<Integer> list = new ArrayList<Integer>();后面却调用 public void prt(List<String> lt)用list做参数,肯定是错误的用法。编译器报错的行为是很正确的,他帮助你避免了潜在错误的发生。这里要注意泛型的作用:List<Integer>和List<String>虽然看着都是List,但编译器把他们当作不同的class,不能相互替代。这是泛型的基本原则。你可以把他们看成一个是Class1, 一个是Class2, 当然不能给一个需要类型为Class1的参数的方法传一个类型为Class2的参数的方法啦。
再来看上面程序稍微改动一处的情况
import java.util.List;
// 申明一个泛型类
public class GenericClass ... {
public static void main(String [] args) ...{
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
new Product().prt(list);
}
}
// 制造一个类用于说明问题
class Product <T> ... {
public void prt(List<String> lt) ...{
System.out.println(lt);
}
}
编译器说使用了未经检查或不安全的操作,但能编译通过并运行显示 [1, 2]。
这又是为什么呢?就是红色的那一个<T>就变化这么大吗?似乎不是和刚才效果应该一样拉,怎么这回又可以了?
原因是这样的:第次程序里面,只是把class Product改成了class Product<T>,尽管类型T在Product的代码里压根从没用到,但是这个定义把一个普通类(class)变成了原始类型(raw class)。generic class Product<T>在JVM运行时是不存在的,Product这个原始类型不是类型安全的。因为在new Product.prt(list)里面,使用的是原始类型的Product,所以里面的list也会被擦拭成原始类型的,所以类型就符合了,不会有编译错误而可以运行。
虽然这个时候程序尽管可以运行,但其使用泛型的方法,无疑是错误的。 在这里我只是想和大家分析一些泛型的细节问题。要大家通过这个细节明白泛型的细节之处(檫试,原始类型)。具体的内容我就不在说了,很多书都有。推荐java参考大全5edition page264 和 core Java I 7edition Chapter 13. Generic Programming