一、什么是泛型?泛型的起源?
泛型是指参数化类型的能力,可以定义带泛型的类或方法,我们在使用时这些带泛型的类或方法时编译器会用具体的类型来替换它。泛型时在JDK1.5开始引入的,所以JDK必须是1.5或者以上版本才能使用泛型。
二、为什么要引入泛型?
1.使用泛型能够在程序编译时检测错误,而不是在运行时检测错误。
Comparable c = new Date();
system.out.println(c.compareTo("red"));
在运行时会报错,因为日期类型不能与字符串类型比较
Comparable<Date> c = new Date();
system.out.println(c.compareTo("red"));
编译器会自动提示错误。
2.免去类型强转
例如:
ArrayList<String> list = new ArrayList<String>();
list.add("China");
list.add("changsha");
String china = list.get(0); //在JDK1.5以后不需要类型强转 ,在JDK1.5之前必须类型强转,否则会出现语法错误。
三、java中如何定义泛型类和方法?
没有引入泛型时的接口定义
public interface Comparable {
public int compareTo(Object o);
}
引入泛型后的接口定义
public interface Comparable<T>{
public int compareTo(T o);
}
这里的<T>表示形式泛型类型(formal generic type),在实际运用中可以用具体类型来替换它。
替换泛型类型称为泛型实例化,T也可以用E来替代。
四、泛型使用时需注意:
2.泛型类型必须是引用类型
ArrayList<int> list = new ArrayList(int);
以上定义错误,因为int是基本数据类型,不是引用类型。正确定义如下:
ArrayList<Integer> list = new ArrayList(Integer);
五、泛型类的运用
1.先定义泛型GenericStack类
程序清单:GenericStack.java
public class GenericStack<E>{
private java.util.ArrayList<E> list = new java.util.ArrayList<E>;//一个存储元素的数组列表
public GenericStack(){//创建一个空栈
}
public int getSize(){
return list.size();//返回这个栈的元素个数
}
public E peek(){
return list.get(getSize() - 1);//返回栈顶元素
}
public void push(E o){//向栈顶添加一个元素
list.add(o);
}
public E pop(){//返回并删除这个栈顶元素
E o = list.get(getSize()-1);
list.remove(getSize()-1);
return o;
}
public boolean isEmpty(){//如果栈为空,返回true
return list.isEmpty();
}
}
2.在主入口函数main中调用如下
定义存储字符串的栈
GenericStack<String> stack1 = new GenericStack<String>();
stack1.push("changsha");
stack1.push("shenzhen");
定义存储整数的栈
GenericStack<Integer> stack2 = new GenericStack<Integer>();
stack2.push(2);
stack2.push(20);
也可以不使用泛型定义
使用泛型能够提高程序的可读性和可靠性
补充,泛型类多个参数定义,只需在尖括号内添加参数就可以了。例如GenericStack<E1,E2,E3>
六、泛型方法定义与运用
1.定义泛型方法print
public static <E> void print(E[] list){
for(int i = 0;i < list.length ; i++)
System.out.println(list[i]+"");
}
2.使用泛型方法print
在主入口程序main下
Integer[] integers = {1,2,3,4,5};
String[] strings = {"wuhan","changsha","shenzhen"};
this.<Integer>print(integers);
this.<String>print(strings);
为了调用泛型方法,需要将实际类型放在尖括号内作为方法名前缀
七、关于非受限泛型类型与受限泛型类型
非受限泛型类型<E>和<E extends Object>是一样的
受限泛型类型<E extends String> :定义了受限泛型类型String以后,是不是只能够使用String类型呢?
八、小结
简而言之,使用泛型能够在程序编译时检测错误,而不是在运行时检测错误,免除类型强转,提高程序的可读性。