泛型
(一)泛型出现的原因:
1、首先从集合开始说起,集合存放的数据类型不确定,但如果直接只限定一种数据类型又不太合适,这时候泛型就产生了
2、如果集合不不使用泛型,则集合中的元素不统一,在遍历集合的时候只能拿出来Object类型,需要做大量的强制类型转换,所以可以统一集合中的数据类型,可以减少强制类型转换,而且从集合中取出数据用Object接收后面再使用类型强转是有风险的;
3、泛型和集合一起使用,能够弥补集合最大的缺点------存储数据的数据类型不固定;能够在编译阶段控制集合中的数据必须为指定数据类型。
(1)举一个例子
List arrayList = new ArrayList();
arrayList.add("aaaa");
arrayList.add(100);
for(int i = 0; i< arrayList.size();i++){
String item = (String)arrayList.get(i);
Log.d("泛型测试","item = " + item);
}
毫无疑问,程序的运行结果会以崩溃结束:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
(二)泛型的应用
泛型的使用方式有三种:泛型类、泛型接口、泛型方法;泛型类和泛型接口的使用基本一样
自定义泛型类:当你的类中有无法确定的数据类型,使用泛型替代类数据不确定的位置
设计一个类Point,有两个属性x,y分别表示x坐标,y坐标;但属性的数据类型不确定
泛型类:
public class Point<X,Y> {
public X a;
public Y b;
public X getA() {
return a;
}
public void setA(X a) {
this.a = a;
}
public Y getB() {
return b;
}
public void setB(Y b) {
this.b = b;
}
public void test(X a,Y b) {
}
}
测试类:
public class PointTest {
public static void main(String[] args) {
Point<Integer,Double> point = new Point();
point.setA(10);
point.setB(10.9);
}
}
这是使用泛型类的时候只需要指定泛型实参就可以限定那些get/set方法的返回类型和参数类型了;
如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。
(三)泛型的书写
List后面<>中就是泛型,约束这个集合中所存放的数据类型;
加上这个泛型后,集合中出现的数据类型只能为泛型所规定的数据类型,或者是它的子类型
泛型一旦添加,会在编译阶段对放入集合中的数据进行数据类型约束,而且当这个类被编译后开始运行时,所有的泛型都会被去除,所以说泛型只有在编译阶段起作用。
泛型的语法要求:
(1)前后泛型声明类型一致
(2)后面的泛型可以省略
(3)泛型前面不声明,后面声明没效果
(4)同时使用多个泛型在一个集合中,泛型在使用时,要看这个泛型类是怎么声明的;
ArrayList<Integer> list1 = new ArrayList<Integer>(); //书写规范
List<Integer> list2 = new ArrayList<>(); //书写规范
List list3 = new ArrayList<Integer>(); //书写不规范,泛型不起作用
(四)泛型通配符
我们知道Ingeter是Number的一个子类,但是Generic<Number>和Generic<Ingeter>并不是父子类关系;
那么在使用Generic<Number>作为形参的方法中,能否使用Generic<Ingeter>的实例传入呢?答案是不可以的。
public class Generic<T> {
private T key;
public T getKey() {
return key;
}
public void setKey(T key) {
this.key = key;
}
public Generic() {
super();
}
public Generic(T key) {
super();
this.key = key;
}
public void showKeyValue1(Generic<Number> obj){
System.out.println("泛型测试"+"key value is " + obj.getKey());
}
}
public static void main(String[] args) {
Generic<?> generic = new Generic();
Generic<Integer> gInteger = new Generic<Integer>(123);
Generic<Number> gNumber = new Generic<Number>(456);
generic.showKeyValue1(gInteger);
//showKeyValue1(gInteger);方法编译不通过;因为这个方法的形参不接受Generic<Integer>类型
//The method showKeyValue1(Generic<Number>) in the type Generic<capture#1-of ?>
//is not applicable for the arguments (Generic<Integer>)
}
为了解决这一问题:类型通配符产生了,类型通配符一般是使用?代替具体的类型实参,注意了,此处’?’是类型实参,而不是类型形参 。意思就是,此处的?和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。是一种真实的类型。
可以解决当具体类型不确定的时候,这个通配符就是 ? ;当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能。那么可以用 ? 通配符来表未知类型。
public void showKeyValue1(Generic<Number> obj){
System.out.println("泛型测试"+"key value is " + obj.getKey());
}