泛型:就是参数化类型
泛型介绍
泛型类:具有一个或多个类型变量的类
class A<T>{
}
在创建泛型类实例的时候需要给其类型变量赋值:
A <String> a=new A<String>();
注意:为了兼容旧版本,在建立实例时,可以不给类型变量赋值,但是会有警告!
泛型方法:具有一个或多个类型变量的方法,称之为泛型方法。
class A<T>{
public T fun(T t1){}
}
fun()方法不是泛型方法,只是泛型类中的一个方法
public <T> T fun(T t1){}:是泛型方法。
泛型方法和泛型类没有必然关系,泛型方法不一定需要在泛型类中。
class A<T> {
private T bean;//泛型可在成员变量上使用
public T fun(T t) {}//泛型可以在类中的方法上(返回值和参数类型)使用!
public void fun2() {//泛型还可以在局部变量的引用类型上使用
T b = ...
new T();//不行的!
}
}
泛型和数组比较理解
* (1)存放类型任意时
* Object[] a=new Object[10];//存放任意类型,但是长度固定
* List b=new ArrayList();//也可以存放任意类型,长度任意
* (2)存放类型指定时
* Object[]a=new String[10];//只能存放String类型
* a[0]=new Integer(100);//会报存储异常 ArrayStoreException
*
* List<Object> b=new ArrayList<String>();//泛型两边的类型必须相同,否则编译不通过
* 因为泛型仅仅是在编译时起作用,编译后会擦除
* 所以如果上面通过了编译,编译擦除后,下面的添加就不会报错!
* b.add(new Integer(100));
需要注意的是:Java中的泛型是“假”的。只是在编译的时候有效,编译后会进行泛型擦除。
继承泛型类
class AA extends A<String> {}
AA不是泛型类,其父类是泛型类
这里子类不是泛型类,需要给父类传递类型变量。
class AA1<E> extends A<E> {}
AA1和其父类都是泛型类
子类是泛型类:可以给父类传类型常量,也可以传递类型变量
泛型的通配符
通配符使用的场景
方法的形参
通配符的优点
使方法更加通用
通配符分类
- 无界通配:?
- 子类限定:? extends Object
- 父类限定:? super Integer
通配符缺点
- 使变量使用上不再方便
- 无界:参数和返回值为泛型的方法,不能使用!
- 子类:参数为泛型的方法不能使用
- 父类:返回值为泛型的方法不能使用
比较通配符
通过对java中的数列中方法:addAll的两种泛型通配符的使用对比
boolean addAll(Collection<E> c)
List<Number> numList = new ArrayList<Number>();
List<Integer> intList = new ArrayList<Integer>();
numList.addAll(intList);//addAll(Collection<Number> c), 传递的是List<Integer>
上面赋值会报错,在泛型中,赋值两边的泛型类必须相同,添加进去相当于进行了 List<Number>=List<Integer>,无法通过编译。
boolean addAll(Collection<? extends E> c)
List<Number> numList = new ArrayList<Number>();
List<Integer> intList = new ArrayList<Integer>();
numList.addAll(intList);//addAll(Collection<? extends Number> c), 传递的是List<Integer>
继承泛型通配符可以将子类或其自身添加进来。
通过反射得到泛型类类型
public class Demo2 {
@Test
public void func1(){
AA aa=new AA();
AA2 aa2=new AA2();
}
}
class A<T>{
public A(){
/**
* 1、得到目标对象
* 2、获得目标对象的Type
* 3、获得目标对象的ParameterizeType
* 4、获得目标对象参数类型
*/
Class clazz=this.getClass();
//获得父类的Type,并转化成ParameterizedType类型(A<T>)
ParameterizedType type= (ParameterizedType) clazz.getGenericSuperclass();
//得到父类的真实参数类型数组
Type[] types = type.getActualTypeArguments();
Class c= (Class) types[0];
System.out.println(c.getName());
}
}
class AA extends A<Integer>{
}
class AA2 extends A<String>{
}