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