Java有个缺点:当我们把一个对象丢进集合中后,集合就会忘记这个对象的数据类型,把他们当成Object类处理,当再次取出这个对象时,需要强制转化数据类型。
Java集合之所以被设计成这样,是因为集合的程序员不会知道我们需要用它来保存什么类型的对象,所以把他们设计成能保存任何类型的对象,只要求很好的通用性。但是存在两个问题:
l 例如想创建一个只能保存Dog类型的集合,但是程序也可以添加Cat对象进去。
l 给取出元素造成不必要的麻烦。
使用泛型的好处:可以写出更加通用的代码,帮我们检查语法(泛型只在编译阶段有效)。
在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
-
demo
public class TestgenericList { public static void main(String[] args) { Listl=new ArrayList (); l.add("bob"); l.add("张三"); l.add("李四"); //下面的代码将引起编译错误 // l.add(5); for(String str:l){ //无需强制转化 String name=str; System.out.println(name); } } }
定义泛型接口、泛型类
-
List接口
public interfere List{ //在该接口中,E可以作为类型使用 //下面方法可以使用E作为参数类型。 void add(E e); Iterator iterator(); }
不仅集合可以增加泛型,任何类都可以增加,虽然泛型是集合的重要场合。下面自定义了一个Apple类,这个类就可以包含一个泛型声明
public class Apple{ private T info; public Apple(){} public Apple(T info){ this.info=info; } ... }
并不存在的泛型类
-
直接看代码
Listl1=new ArrayList (); List< Integer > l2=new ArrayList (); System.out.println(l1.getClass()==l2.getClass()); // ? true
不可以这样判断:
if(cs instanceof List<String>)
通配符(表示各种泛型List的父类)
问题:形参的类型需要使用通用类型。
public void fun(Genericobj){} Generic gInteger = new Generic (123); fun(gInteger);
这段代码会报错
public void test( List l ) { } // 不管List泛型是什么类型,都被当成了Object类处理
class Apple{ // Number为T的上限,T不能是Number的父类,可以是Number类型 public T info; public String toString(){ return "info: "+this.info; } } class Apple { // Number为T的下限 public T info; public String toString(){ return "info: "+this.info; } }
泛型方法
// T是方法的类型参数,可以根据实参的类型就行推断 public staticvoid test(T[]a,Collection c){ for(T t:a){ c.add(t); } } public static void main(String[] args) { Collection
先在public与返回值之间的<T>必不可少,这表明这是一个泛型方法
也可以定义多个泛型参数:public static <T,S> void fun(){}
限定上下限
void test(Collection a,Collection c){}
擦除和转换
在做类型转换的时候,如果去掉了类型参数,则会造成对象的类型参数丢失,编译器认为类型参数为Object
public static void main(String[] args) { Applea=new Apple (); //a的getSize方法返回一个Integer对象 Integer in=a.getSize(); //把a对象赋值给Apple对象,则会丢失尖括号的信息 Apple a1=a; //下面的代码将会导致编译错误 // Integer in1=a1.getSize(); }