泛型的基本使用:
我们最常用到泛型的地方可能是arraylist中,如:ArrayList<Integer> intList = new ArrayList<Integer>();它可以构造各种类型的变量来组装成不同的list而不必对每一个类型都创建一个Arraylist的类,
- 定义及使用:
//定义class Person<T>{// 此处可以随便写标识符号 private T x ; private T y ; public void setAge(T x){//作为参数 this.x = x ; } public void setName(T y){ this.y = y ; } public T getAge(){//作为返回值 return this.x ; } public T getName(){ return this.y ; } };
因为T表示派生自Object类的任何类,所以尖括号T中必须是继承自Object,如:String,Interger,不能使用原始的类型,如int,double.
//使用//设置年龄 Person<Integer> p = new Person<Integer>() ; p.setAge(new Integer(100)) ; System.out.println(p.getAge()); //设置名字 Person<String> p = new Person<String>() ; p.setName(new String("name")) ; System.out.println(p.getName());
使用的Class<T> object来传递类的class对象
我们在解析Json的时候:
public static List<SuccessModel> parseSuccessArray(String response){ List<SuccessModel> modelList = JSON.parseArray(response, SuccessModel.class); return modelList; }
这样做比较的死板,我们可以吧successmodel抽取出来,当做一个变量,这样就可以使用到泛型了,如下:
public static <T> List<T> parseArray(String response,Class<T> object){ List<T> modelList = JSON.parseArray(response, object); return modelList; }
注意到,我们用的Class<T> object来传递类的class对象,即我们上面提到的SuccessModel.class,这样就可以传递任意的class来解析不同的数据.
//待续。。。。
进阶
类型绑定:
有时候定义泛型的时候可能希望泛型类型只能是一部分类型,就是给泛型指定一个界限,
定义形式为:
<T extends BoundingType>
T和BoundingType可以是类,也可以是接口。另外注意的是,此处的”extends“表示的子类型,不等同于继承。在这里extends后的BoundingType可以是类,也可以是接口.
通配符:
通配符用?表示无边界通配符,通配符的意义就是他是一个未知的符号,可以表示任意的类,如:
Point<?> point; point = new Point<Integer>(3,3); point = new Point<Float>(4.3f,4.3f); point = new Point<Double>(4.3d,4.90d); point = new Point<Long>(12l,23l);
- 通配符?和T的区别:
泛型变量T不能在代码用于创建变量,只能在类,接口,函数中声明以后,才能使用。
而无边界通配符?则只能用于填充泛型变量T,表示通配任何类型
如:
Box<?> box; box = new Box<String>();
?只能出现在Box<?> box;中,其它位置都是不对的
- 通配符?的extends绑定:
通配符可以和泛型一样加以限定。如:
Point<? extends Number> point;
注意:利用<? extends Number>定义的变量,只可取其中的值,不可修改
如:
Point<? extends Number> point = new Point<Integer>(3);
point的类型是由Point<? extends Number>决定的,并不会因为point = new Point<Integer>(3);而改变类型。如果会改变类型那么<? extends Number>就失去了作用。但取值时,正由于泛型变量T被填充为<? extends Number>,所以编译器能确定的是T肯定是Number的子类,编译器就会用Number来填充T。
通配符?的super绑定:
如果说 <? extends XXX>指填充为派生于XXX的任意子类的话,那么<? super XXX>则表示填充为任意XXX的父类.
如:
class CEO extends Manager { } class Manager extends Employee { } class Employee { } List<? super Manager> list; list = new ArrayList<Employee >();list = new ArrayList<Manager >();list = new ArrayList<CEO >();//编译会报错
因为CEO类已经不再是Manager的父类了。所以会报编译错误。
注意:super通配符表示的实例内容:能存不能取
先看存的部分:
List<? super Manager> list; list = new ArrayList<Employee>(); //存 list.add(new Employee()); //编译错误 list.add(new Manager()); list.add(new CEO());
为什么会报编译错误呢?因为
编译器无法确定<? super Manager>的具体类型,但唯一可以确定的是Manager()、CEO()肯定是<? super Manager>的子类,所以肯定是可以add进去的。但Employee不一定是<? super Manager>的子类,所以不能确定,不能确定的,肯定是不允许的,所以会报编译错误。
super和extends相反,使用super关键字时,往里存的只要是Employee的子类,就会强制转换为Employee存储,但是取出来时应该都为父类Employee所以没有意义,所以我们认为super通配符:能存不能取;
登录 | 立即注册