1.基础
//类型参数
public class Box<T>{}
public class Box<K,V>{}
//多重参数或接口边界
public class Box<T extends Employee & Printable & Listable>{}
//无界通配符
private List<?> result;
//有界通配符:上边界
private List<? extends Number> result;
//有界通配符:下边界
private List<? super Student> result;
2.编译时类型擦除
interface A{
int calc(Map<String,List<String>> orders);
int calc(Map<String,Integer> orders);
}
擦除以后剩下的是原始类型(raw type) Map
3.通配符
例1
//不能编译
List<Object> result=new ArrayList<String>();
//合法
List<?> result=new ArrayList<String>();
例2
//不安全的,计算参数的和
<T> double sum(T ... args){}
//安全的
<T extends Number> double sum(T ... args){}
4.泛型类型
例1
public class Box<T>{
private T t;
public void set(T t){
this.t=t;
}
public void test(Box<T> obj){
//ETC
}
}
测试
Box<Number> b=new Box<>();
//OK
b.set(new Integer(10));
//不能编译
Box<Integer> a=new Box<>();
b.test(a);
例2
public abstract class BaseEntity<T>{
//ETC
private Page<T> page;
public Page<T> getPage() {
return page;
}
public void setPage(Page<T> page) {
this.page = page;
}
}
public class Article extends BaseEntity<Article> {
//ETC
}
public class Page<T extends BaseEntity<T>> {
private List<T> result;
}
在开发者工具中会提示BaseEntity.page类型错误,改成
public abstract class BaseEntity<T>{
private Page<?> page;
public Page<?> getPage() {
return page;
}
public void setPage(Page<?> page) {
this.page = page;
}
}
测试
Article a=new Article();
//Refer也继承了BaseEnity
Page<Refer> rs=new Page<>(1,1);
//绕开了类型检查,但不符合逻辑
a.setPage(rs);
需要修改Page的声明,才可以让原来的开发工具中的警告消失同时类型检查合法并符合逻辑
5.类型变体(协变和逆变:PECS)
String[] strArr={"hello","java","world"}
Object[] objArr=strArr;
//运行时出错
objArr[1]=new Integer(37);
System.out.println(objArr[1]);
java(5以后)集合库大量使用了协变和逆变,使用这种变体的目的是确保泛型作正确的事及表现的行为不会让人感觉怪诞
6.编译时和运行时类型
List<String> str=new ArrayList<>();
System.out.println(str);
javac看到str是 List-of-String
jvm 看到str是ArrayList类型的对象
最后
推荐看一看这几本书.书中对泛型的讲解个人认为都不错,可能初读起来比较绕.抽时间静下来读还是能读懂的
java学习指南(第四版)
java语言导学(第五版)
java技术手册(第六版)