Java泛型/通配符/泛型擦除
Java泛型设计原则:只要在编译时期没有出现警告,那么运行时期就不会出现ClassCastException异常.
泛型:把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型
参数化类型:
- 把类型当作是参数一样传递
<数据类型>
只能是引用类型
相关术语:
ArrayList<E>
中的E称为类型参数变量ArrayList<Integer>
中的Integer称为实际类型参数- 整个称为
ArrayList<E>
泛型类型 - 整个
ArrayList<Integer>
称为参数化的类型ParameterizedType
关于List和List关系的解释Demo
public class testGenericity {
static void formArrayToCollection(Object[] arr, Collection<Object> collection){
for (Object o : arr){
collection.add(o);
}
}
public static void main(String[] args) {
String[] str = {"a","b"};
List<String> list = new ArrayList<>();
testGenericity.formArrayToCollection(str,list);
}
}
泛型中的List和List中不是继承关系。
Collection并不能说是Collection,Collection的父类从而替代这两个类型的集合,无法通过编译。
下面是通过正确使用泛型后的修改代码:
public class testGenericity {
static <T> void formArrayToCollection(T[] arr, Collection<T> collection){
for (T o : arr){
collection.add(o);
}
}
public static void main(String[] args) {
String[] str = {"a","b"};
List<String> list = new ArrayList<>();
testGenericity.formArrayToCollection(str,list);
for (String item : list){
System.out.println(item);
}
}
}
设定通配符号上限
//传递进来的只能是Type或Type的子类
List<? extends Type>
设定通配符下限
//传递进来的只能是Type或Type的父类
< ? super Type>
无论是设定通配符上限还是下限,都是不能操作与对象有关的方法,只要涉及到了通配符,它的类型都是不确定的!
public class testGenericity {
public static <T> void test(List<?> list ){
Object o = new Object();
list.add(o);
}
}
//会报错
无限制泛型擦除
擦除前
擦除后
ReturnVo<String> test = new Return<>();
反编译后,本来类型为T的data变量,类型被编译器变为Object了。
当在外面调用ReturnVo类时,传入String类型,看看编译器是如何将data变量从Object类型转化为String类型的:
- invokevirtual是一种动态分派的调用指令,此时编译器并不能确定data变量的类型,还是当做Object进行处理的;
- 随着编译器插入了一条checkcast指令,将data从Object类型强转为String类型。
有限制类型擦除
有限制擦除类型就是如:T extends B这种,在编译的时候会将类中T类型的变量类型变成B。
擦除前:
擦除后:
创建一个继承了Person的Student类