为什么出现泛型
早期Java没有泛型,每次从List中取数据要强转,使用泛型后在定义List时就定义好一个类型,每次取数据不用强转了
类型擦除
java的泛型使用类型擦除来实现,在编译时删掉泛型声明,使所有T声明等价于Object,加入强转,运行时无发获取泛型的类型
测试类:
public class c01<T extends Reader> {
void bar(String s){}
void foo(){
List list1 = new ArrayList<String>();
List<String> list2 = new ArrayList<>();
c01 obj1 = new c01<BufferedReader>();
// c01 obj2 = new c01<String>(); 编译报错
list2.add("1");
bar(list2.get(0));
}
}
反编译后
public class c01<T extends Reader> { //Line Num
public c01() { // 1
} // 2
// 3
void bar(String var1) { // 4
} // 5
// 6
void foo() { // 7
new ArrayList(); // 8
ArrayList var2 = new ArrayList(); // 9
new c01(); // 10
var2.add("1"); // 11
this.bar((String)var2.get(0)); // 12
}
}
从上面的代码可以看到:
1: c01 obj1 = new c01<BufferedReader>();
在反编译后变成了new c01();
2: list2.get(0)
在反编译后变成了(String)var2.get(0)
被编译器自动加上了强转
3: List list1 = new ArrayList<String>();
在反编译后变成了new ArrayList();
说明泛型完全没起到作用,即使在java代码中向list1中插入其他类型也只会得到一条警告,不影响运行。
如何在普通类声明泛型
void funlist(List<? super Reader> list){
}
<R extends Reader> void funlist2(List<R> list){
}
?通配符的意义
示例代码
public class c03 {
class A{}
class B extends A{}
void foo(){
A[] x = null;
B[] y = new B[]{new B()};
List<A> aa = null;
List<B> bb = null;
test(y); //正常运行
// t2(bb); //编译器提示报错,类型不匹配
boolean ret = y instanceof A[]; //编译器提示,always true
}
void test(A[] aaa){}
void t2(List<A> parm){}
}
也就是说如果B继承A,那么B数组继承与A数组,但B集合不继承于A集合
当我们真的想表示一个类型子类的集合的时候就需要使用通配符?来实现。
通配符集合只能get,不能put,即使在指定了上下边界的情况下。