泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
加在类上: public class DemoClass<T>{} 加在方法上:public <T> void getCollection(T[] a, Collection<T> c){} //list接口中的数组转换方法 <T> T[] toArray(T[] a);
方法上的<T>代表括号里面要用到泛型参数,若类中传了泛型,此处可以不传,调用类型上面的泛型参数,前提是方法中使用的泛型与类中传来的泛型一致。
[1]List<T> al=new ArrayList<T>();指定集合元素只能是T类型 [2]List<?> al=new ArrayList<?>();集合元素可以是任意类型,这种没有意义,一般是方法中,只是为了说明用法 [3]List<? extends E> al=new ArrayList<? extends E>(); E:接收E类型或者E的子类型
一般用于定义一个引用变量,这么做的好处是,如下所示,定义一个sup的引用变量,就可以指向多个对象。
SuperClass<?> sup = new SuperClass<String>("lisi"); sup = new SuperClass<People>(new People()); sup = new SuperClass<Animal>(new Animal());
若不用?,用固定的类型的话,则:
SuperClass<String> sup1 = new SuperClass<String>("lisi"); SuperClass<People> sup2 = new SuperClass<People>("lisi"); SuperClass<Animal> sup3 = new SuperClass<Animal>("lisi");
这就是?通配符的好处。
//ArrayList集合的构造器,extends代表E范型或是E范型的子类,否则报错。 public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } } //Demo,代指此范型参数必须为object或object的父类 public void getString(Demo<? super Object> Demo){ System.out.println("范型方法执行"); }
? extends E:接收E类型或者E的子类型。 ?super E:接收E类型或者E的父类型
1.在整个类中只有一处使用了泛型,使用时注意加了泛型了参数不能调用与参数类型有关的方法比如“+”,比如打印出任意参数化类型集合中的所有内容,就适合用通配符泛型<?>
2.当一个类型变量用来表达两个参数之间或者参数与返回值之间的关系时,即统一各类型变量在方法签名的两处被使用,或者类型变量在方法体代码中也被使用而不仅仅在签名的时候使用,这是应该用自定义泛型<T>。泛型方可以调用一些时间类型的方法。比如集合的add方法。
乏型:
抽象指定类型,让开发者使用时更方便,优化、设计方面的作用。
通配符:
指定类型范围,避免开发不知道该数据只支持的范围,设置错误类型导致出现bug。