好处:
1)将运行时期的ClassCastException异常转移到了编译时期,进行检查,并以编译失败来体现。 这样有利于程序员尽早解决问题。
2)避免了向下转型(强转)的麻烦。
什么时候写泛型呢?
只要在使用类或者接口时,该类或者接口在api文档描述时都带着<>,就需要在使用时定义泛型。
其实,泛型无非就是通过<>定义了一个形式参数,专门用于接收具体的引用类型。在使用时,一定要传递对应的实际参数类型。
集合中泛型的应用特别多见。
泛型的擦除
泛型技术是用于编译时期的技术,编译器会按照<>中的指定类型对元素进行检查,检查不匹配,就编译失败,匹配,就编译通过,通过后,产生的class文件中是没有泛型的,这就成为泛型的擦除。
使用泛型的动机举例(以集合为例):
对集合中存放元素的类型进行限定,防止后期出错。如果限定某个集合只能存放Person类对象(因为后期会把元素取出来当作Person对象来处理),这样放其它类型的对象在编译时就会报错。相当于把一个类泛化成很多个不同类型(具体化,限定化)的类。泛型使用的代码如:
List<Person> persons = new ArrayList<Person>;
Map<String,String> m = new HashMap<String,String>;
在定义泛型类或声明泛型类的变量时,使用尖括号来指定形式类型参数,称为类型形参,在调用时传递的实际类型成为类型实参。类型形参与类型实参之间的关系类似于形式方法参数与实际方法参数之间的关系,只是类型参数表示类型,而不是表示值。
注意:当一个变量被声明为泛型时,只能被实例变量和方法调用,而不能被静态变量和方法调用。原因很简单,参数化的泛型是一些实例。静态成员是被类的实例和参数化的类所共享的,所以静态成员不应该有类型参数和他们关联。
这里我做了些测试:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.junit.Test;
public class GenericHello {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test//没有泛型时的代码
public void demo1(){
List list = new ArrayList();
list.add("abc");
list.add("hello");
list.add(10);//※没有使用泛型时会出现的bug
Iterator it = list.iterator();
while(it.hasNext()){
Object obj = it.next();
//※下面两句,如果集合中存在非String类型元素,则会挂!---运行期的错误
char ch = ((String)obj).charAt(0);
System.out.print(ch+" ");
System.out.println(obj);
}
}
@Test//带泛型时的代码 ---讲解泛型的基本用法和好处
public void demo2(){
List<String> list = new ArrayList<String>();
list.add("abc");
list.add("hello");
//list.add(123); //泛型的好处1: 把运行期的错误提前到编译期
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = it.next();//泛型的好处2:可以自动识别出元素的类型,不用类型强转
char ch = str.charAt(0);
System.out.print(ch+" ");
System.out.println(str);
}
}
@Test //让我们的MySet也有泛型的功能
public void demo3(){
@SuppressWarnings({ "unchecked", "rawtypes" })
MySet<String> set = new MySet();
set.add("abcd");
//set.add(123);//泛型的好处1---把运行期的错误提前到编译期
String s = set.getLast(); //泛型的好处2:可以自动识别出元素的类型,不用类型强转
System.out.println(s);
}
}
MySet:
package cn.hncu.generic.v1;
public class MySet<E> {
private Object[] objs=new Object[0];
public boolean add(E obj){
if(contains(obj)){
return false;
}
Object tmpObjs[] = new Object[ objs.length+1 ];
System.arraycopy(objs, 0, tmpObjs, 0, objs.length);
tmpObjs[objs.length] = obj;
objs=tmpObjs;
return true;
}
public Object[] getAll(){
return objs;
}
@SuppressWarnings("unchecked")
public E getLast(){
return (E) objs[size()-1];
}
public boolean contains(Object obj){
for(Object tm: objs){
if(tm.equals(obj)){
return true;
}
}
return false;
}
public int size(){
return objs.length;
}
}