Java集合的缺点:
把对象“丢进”集合后,集合就会”忘记“这个对象的数据类型,取出时编译类型变成object类型,运行时类型没变。
这样做的原因:设计它的程序员不知用他存放何种类型对象,就设计成object类型,具有通用性。
这样带来了两个问题:
1、集合对元素类型没有任何限制,如只想创建保存单一类型集合,但程序丢进其它类型,引发异常。
2、取出元素时进行强制类型转换既增加编程复杂度,又可能引发ClassCastException异常。
定义泛型:
public class fru<T> {
private T info; public fru() {} public fru(T info) { this.info =info; } public void setInfo(T info) { this.info=info; } public T getInfo() { return this.info;}
}
派生子类:
可以从带泛型声明的接口、父类来派生子类。
public class A extends fru<T>{} --错误
public class A extends fru<String>{} --使用方法时必须为所有的数据形参传入参数值。
也可以不传入实际类型--public class A extends fru{} ,但会发出泛型检查警告,系统将类fru<T>中的T形参当成object类型来处理。
public class A2 extends fru{
public String getInfo()
{
//super.getInfo()方法返回值是object类型,所以加toString()才返回String类型。
return super.getInfo().toString();}
}
并不存在泛型类:
泛型对其所以可能的类型参数,具有同样的行为,可以把相同的类当成许多不同的类来处理。Java类的静态方法、静态初始化或者静态变量的声明和初始化中,不允许使用类型参数。因为系统中不会真正生成泛型类,instanceof运算符处理后不能使用泛型类。
类型通配符:
数组和泛型有所不同,如果SubClass是SuperClass的子类或者子接口,则SubClass[]依然是SuperClass[]的子类,但G<SubClass>不是G<SuperClass>的子类。
类型通配符,写作List<?>,表示各种泛型List的父类,它的元素类型可以匹配任何类型,?称作通配符。
List<?>c=new ArrayList<String>();
c.add(new Object()); //引发编译错误
带通配符的List仅表示各种泛型的父类,并不能把元素加入其中,因为并不知程序中C集合中的元素类型。但有一例外,c.add(null);null是所有引用类型的实例。
设置类型通配符上限:
import java.util.*;
public class Canvas { //同时在画布上绘制多个形状 public void drawAll(List<? extends Shapes>) { for(Shape s : shapes) { s.draw(this); } } public static void main(String[] args) { List<Circle> circleList=new ArrayList<Circle>(); circleList.add(new circle()); Canvas c=new Canvas(); c.drawAll(circleList);
}
设置类型形参上限:
import java.util.*;public class ffruu<T extends Numbers>{ T cool; public static void main(String[] args) { ffruu<integer> ai=new ffruu<integer>(); ffruu<Double> ad=new ffruu<Double>(); ffruu<String> as=new ffruu<String>(); //引起编译异常,String类型传给T形参,但String不是Number的子类型 }
}
另一种情况是,程序需要为类型形参设定多个上限(至多一个父类上限,可以有多个接口上限),表明该类型形参必须是其父类的子类(父类本身也行),并且实现多个上限接口。
public class Apple<T extends Numbers & java.io.Serializable>{...}
上面程序表明T类型必须是Number类或其子类,并必须实现 java.io.Serializable接口。
声明泛型方法:
import java.util.*;public class cefang { //声明一个泛型方法,该泛型方法中带一个T形参 static<T>void fromArrayToCollection(T[]a,Collection<T> c) { for(T o : a) c.add(o); } public static void main(String[] args) { Object[] oa=new Object[100]; Collection<Object>co=new ArrayList<Object>(); //下面代码中T代表Object类型 fromArrayToCollection(oa,co); String[] sa = new String[100]; Collection<String>cs=new ArrayList<String>(); //下面代码中T代表String类型 fromArrayToCollection(sa,cs); //下面代码中T代表Object类型 fromArrayToCollection(sa,co); Integer[] ia =new Integer[100]; Float[] fa=new Float[100]; Number[] na =new Number[100]; Collection<Number>cn=new ArrayList<Number>(); //下面代码中T代表Number类型 fromArrayToCollection(ia,cn); //下面代码中T代表Number类型 fromArrayToCollection(fa,cn); //下面代码中T代表String类型 fromArrayToCollection(na,co); //下面代码中T代表String类型,但na是一个Number数组 //因为Number既不是String类型,也不是它的子类,所以出现编译错误 //fromArrayToCollection(na,cs); }
}
设置通配符下限:
public static void fun(Info<? super String>temp){ //只能接收String或者Object类型的泛型
System.out.println(temp);
}
通过泛型方法返回泛型类:
class Info<T extends Number>{} //指定上限,只能是数字类型
public class genneric{
public static <T extends Number>Info<T>fun(T temp){
Info<T>info=new Info<T>();
Info.setVar(temp);
return info; //返回实例化对象
}
}