Java中的泛型
泛型 (generics) 是Java 5.0 参考C++中模板(templates) 而引入的新特性. 但在Java中, 泛型只是一个提供给编译工具和程序员的功能而在程序运行时不具备实际意义. 这是由于JVM不支持像C++模板那样的语句.
使用泛型能够让代码中对于类型的指定更加清晰明确. 同时也能在编译时期就能发现并避免一些平时难以注意到的错误. 下面这个例子能看出这个错误:
//不用泛型时的麻烦
ArrayList arrLis = new ArrayList();//建立一个不使用泛型的数组列表
arrLis.add("abc");//传入一个String
String str = (String) arrLis.iterator().next();//提取时, 编译器不知道列表里面是什么类型的元素,所以要加上cast,否则编译不通过
通过加入(String)这个cast, 我们可以把提取出来的类型告诉编译器, 可是这样做会带来两个问题:
- 开发者自身是清楚列表中存放了什么类型的元素的, 加入(String) 对于开发者来说毫无意义.
- 如果上面代码中对str赋值的时候真的出现错误了 (iterator迭代器中输出的下一个元素不是 String 类型), 加入(String)反而会隐藏错误, 使开发者在程序真正运行前无法意识到程序中的错误.
下面这个例子中, 最后的赋值动作加入了封装整数类型的强转符号, 可从集合中取出的元素却是String类型的.
ArrayList arrLis2 = new ArrayList();
arrLis2.add(1);
arrLis2.add(1L);
arrLis2.add("abc");
int i = (Integer) arrLis2.get(2);
而在编译这段代码时, 编译器没有报出任何错误. 这就能看出, 如果一个集合中元素类型无法明确, 就必须在取出集合元素时才对元素进行强转. 但对于一个不限定类型的集合中取出的元素, 使用强转就会降低安全性, 因为就是类型不匹配, 在语法上也是没有任何错误的.
而JDK 1.5中给上面问题提供的答案就是: 泛型.
Java中泛型的应用
JDK 1.5面世后, 很多Java中的函数都支持使用泛型来确定函数中参数的类型. 通过查阅API就能发现, 很多地方出现了"< >"这个新的语法. 最典型的例子就是Collection下面的子类, 可以通过使用泛型来确定该集合传入的是什么类型的元素. 这样就避免了cast的使用. 同时如果出现错误的写入类型, 编译器在编译时就会报错, 而不是等到运行时.
换个方法说, 泛型的使用就是给函数们都加上一个标签, 使它们的功能和所作用的目标更明确.