一、泛型的概述
泛型: 泛型是jdk1.5出现的新特性。
在以前操作集合时,取出集合元素要判断其类型,很麻烦,并且有可能出现ClassCastException。有了泛型后就不需要进行类型的强制转换了。
<类型>其实就是用来限定类型的.
通过泛型我们将在运行时有可能出现的异常,在编译就进行检查
使用泛型它限定了集合中元素的类型,但是我们在操作集合元素时更方便了。
在api中如果看到某个类后面<>代表这个类是可以用泛型进行限定的。
二、泛型的使用
1.在集合中泛型是最经常使用的,下面看个例子:
ArrayList<Integer> collection2 = new ArrayList<Integer>();
collection2.add(1);
/*collection2.add(1L);
collection2.add(“abc”);*///这两行代码编译时就报告了语法错误
int i2 = collection2.get(0);//不需要再进行类型转换
从这个例子可以看出,泛型的加入使得,集合元素的内省限定了,同时在获取元素的时候不再需要类型转换。
2.泛型的通配符
定义一个方法,该方法用于打印出任意参数化类型的集合中的所有数据,该方法如何定义呢?
一般情况下可能会认为是这样的:
public static void printCollection(Collection<Object> cols) {
for(Object obj:cols) {
System.out.println(obj);
}
/* cols.add("string");//没错
cols = new HashSet<Date>();//会报告错误!*/
}
但上面的这种情况会报错,而正确的情况是使用泛型通配符?
public static void printCollection(Collection<?> cols) {
for(Object obj:cols) {
System.out.println(obj);
}
//cols.add("string");//错误,因为它不知自己未来匹配就一定是String
cols.size();//没错,此方法与类型参数没有关系
cols = new HashSet<Date>();
}
可以看到,使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。
3.通配符的额上下边界
通配符的上边界:
Vector<? extends Number> x = newVector<Integer>();
通配符的下边界:
Vector<? super Integer> x = newVector<Number>();
什么时候使用上下边界呢?通常情况下:在存储元素的时候使用上限,在取出元素的时候使用下限。
存储元素的时候用上限,因为这样取出都是按照上限类型来运算的,不会出现安全隐患。
class myCollection<E>{
public void ass(E e){
}
public void addAll(myCollection<? extends E> e){
}
}
取出元素用下限,例如比较器。
class TreeSet<Worker>{
Tree(Comparator<? super Worker> comp);//比较器
}
其中,Worker是继承自Person的类,而且Person和Worker都具备了相同的比较性,这时就可以采用下限。
4.泛型类
如果类的实例对象中的多处都要用到同一个泛型参数,即这些地方引用的泛型类型要保持同一个实际类型时,这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型,如下:
public class GenericDao<T> {
private T field1;
public void save(T obj){}
public T getById(int id){}
}
GenericDao<String>dao = null;
newgenericDao<String>();
注意:
在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。
当一个变量被声明为泛型时,只能被实例变量、方法和内部类调用,而不能被静态变量和静态方法调用。因为静态成员是被所有参数化的类所共享的,所以静态成员不应该有类级别的类型参数。
下面看一个自定义的泛型类:
class Tools<A> //自定义泛型类
{
private A obj;
public void set(A obj){
this.obj=obj;
}
public A get(){
return obj;
}
}
5.泛型方法
Java的泛型方法没有C++模板函数功能强大,java中的如下代码无通过编译:
<T> T add(T x,T y) {
return (T) (x+y);
//return null;
}
用于放置泛型的类型参数的尖括号应出现在方法的其他所有修饰符之后和在方法的返回类型之前,也就是紧邻返回值之前。按照惯例,类型参数通常用单个大写字母表示。
普通方法、构造方法和静态方法中都可以使用泛型。
在泛型中可以同时有多个类型参数,在定义它们的尖括号中用逗号分,例如:
public static <K,V> V getValue(K key){
return map.get(key); //这时泛型中有两个类型的参数
}
最后举个泛型方法的例子来看看:
编写一个泛型方法,自动将Object类型的对象转换成其他类型。
public static <T> T autoConvertType(Object obj){
return (T)obj;
}
这样就可以将Object类型转换成其他的类型T了。