通过引入泛型,我们可以获得的优势: 泛型是在JDK 1.5之后引入的
编译时类型的安全
和运行时更小的抛出ClassCastExceptions的可能。
泛型是变量类型的参数化
泛型是解决什么问题的,
我们都知道一个集合可以添加不同类型的对象,但是在获取对象的时候,必须要知道所有对象的类型才可以取出来,存进去没什么代价,但是取出来的时候代价太大,泛型就是解决集合中存在不同类型对象时的存取问题。
public class GenericityTest {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add(1);
list.add("sss");
list.add(false);
for(int i=0;i < list.size();i++){
String s1=(String)list.get(i); // 会抛出类型异常
System.out.println(s1);
}
}
}
能用泛型的时候一定要使用泛型,尤其是在使用集合的时候
在定义泛型类别的时候,预设可以使用任何的类型来实例化泛型中的类型,但是如果想要限制泛型类别的使用类型,只能用某个特定类型或者其子类型才能实例化该类型的时候,可以在定义类型的时候,使用extends关键字指定这个类型必须是继承自某个类或者实现了某个接口
下面的例子详细的讲解了泛型。
需要注意的是 在下面的例子中,虽然List是接口,但是在泛型中也必须使用extends关键字表明,这是语法要求
public class GenericityTest2<T extends List>{
public static void main(String[] args) {
// ArrayList也是使用了泛型实现的,要求以后在使用集合的时候一定要使用泛型
ArrayList<String> list = new ArrayList<String>();
// 使用了泛型之后必须使用它所规定的类型,否则程序编译不通过
// list.add(100); 错误的
list.add("aaa");
list.add("bb");
for(Iterator<String> iter = list.iterator(); iter.hasNext();){
// String s1 = (String)iter.next(); 未使用泛型时,需要对iter.next() 进行强制类型转换,因为返回的是一个Object对象
// 使用了泛型,就不必再进行强制类型转换,因为系统已经知道对象的类型是String类型
String s1 = iter.next();
System.out.println(s1);
}
HashMap<String,String> hash = new HashMap<String, String>();
hash.put("aa","aaa");
hash.put("bb","bbb");
// GenericityTest2<T> 如果这样书写,那么他可以传进任意类型的数组,
// 但是 GenericityTest2<T extends List> 就对传进来的类型做了要求,传进来的对象类型必须是实现了 List接口的
GenericityTest2<ArrayList<String>> a = new GenericityTest2<ArrayList<String>>();
// 因此当传进来一个HashMap后程序报错,因为HashMap没有实现List 接口
// List 是接口,但是在泛型中依旧使用extends 来声明,记住
// GenericityTest2< HashMap<String,String>> b = new GenericityTest2< HashMap<String,String>>();
}
private T[] t;
public T[] getT() {
return t;
}
public void setT(T[] t) {
this.t = t;
}
}
当泛型没有指定泛型继承的类型或接口时,默认是 extends Object
GenericTest3
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class GenericTest3<T> {
private T foo;
public T getFoo() {
return foo;
}
public void setFoo(T foo) {
this.foo = foo;
}
public static void main(String[] args) {
// 可以实现与 GenericTest3<T extends List>一样的功能,必须是实现了List的接口的
GenericTest3<? extends List> ge =null;
ge=new GenericTest3<ArrayList>();
ge=new GenericTest3<LinkedList>();
GenericTest3<String> ge2 =null;
ge2.setFoo("String");
GenericTest3<? extends Object> ge3;
// 上面一句的等价 ==GenericTest3<? > ge3 一般都是使用这个,默认是继承Object的
// 设置为空,或者将一个特定类型的提取到ge3是没有什么问题的
ge3=null;
ge3=ge2;
// 但是利用它来进行对子类类型的对象赋值时,程序会报错
// ge3.setFoo("String"); 这样是编译错误的,原因是ge3只知道它是一个实现了Object的对象,
// 即是Object的一个子类,但不确定是什么类型,因此编译器不让加入信息,如果你能加入信息的话
// 系统就会认为你已经知道了它的类型,当你调用ge3.getFoo,返回的是一个Object对象,你就必须得进行
//强制类型转换才能使用,而泛型就是设计出来不让你再进行强制类型转换的,这是矛盾的,所以不能加入信息
}
}