泛型定义:
Class tuple<A,B>{
Public final A first;//泛型A的实例变量first;
Public final B second;//泛型B的实例变量second;
Public tuple(A a,B b){first= a; second = B;}//构造函数初始化AB泛型。
}
泛型继承:
Classtuple2<A,B,C> extends tuple<A,B>{
Public final C third;//泛型C的定义;
Public tuple2(A a,B b,C c){super(a,b); //继承上层的泛型
Third = c; //构造函数初始化泛型C
}
泛型使用:
定义函数使用泛型作为返回值:
Tuple<String ,Integer> function(){
Return new Tuple<String, Integer>(“hi”, 47);//返回值新建了一个泛型tuple并且指定了其泛型类型为String和Integer,然后分别初始化了String与Integer为hi和47;
}
泛型方法:
Public <T> void f(T x){
}//此处<T>置于void前的方法即为泛型方法,方法中可以使用泛型参数。
使用泛型类,必须在创建类时指明其类型,当时泛型函数可以自己判断出传入的泛型参数是什么。
可变参数:
可变参数其实就是 “…”,这在C语言中也存在。例如W… args;表示泛型W的args参数可选,可以有多个
泛型擦出:
Java的泛型是用擦出来实现的,这意味着你在使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。因此List<String>和List<Integer>在运行时其实是相同类型。这两种形式都被擦除为其原生的List类型,理解擦除以及如何处理时泛型的最大难点。
解决方案例:
class HasF{
publicvoid f(){ System.out.println("HasF.f()");}
}
classManipulator<T>{
privateT obj;
publicManipulator(T xT) {
//TODOAuto-generated constructor stub
obj= xT;
}
publicvoid manipulate() {
obj.f();//因为擦除了类型信息,编译器此处不知道obj中是否包含f()这个函数,故报错
}
}
classManipulator2<T extends HasF>{
privateT obj;
publicManipulator2( T x) {
//TODOAuto-generated constructor stub
obj= x;
}
publicvoid manipulate(){
obj.f();//这里协助泛型建立了边界,编译器知道其实继承自HasF,故而调用成功。
}
}
此处泛型类将擦除到他的第一边界,实际中他可能有多个边界。
擦除的代价是显著地,泛型不能用于显示的运行时类型的操作之中,例如转型,instanceof操作和new表达式
@SuppressWarnings("unchecked")压制警告要聚焦,不能放在整个类上,那样和压制真正的警告
擦除的补偿:
class Building{}
class House extends Building{}
classClassTypeCapture<T> {
Class<T> kind;
T obj;
publicClassTypeCapture(Class<T> kind) throws InstantiationException,IllegalAccessException {
//TODOAuto-generated constructor stub
this.kind = kind;
obj= kind.newInstance(); /*这句创建了泛型实例,实际编译器是根据传入的类型参数用 newInstance()函数创建的泛型实例
此外,这个操作需要抛出异常*/
}
publicboolean f(Object arg) {
returnkind.isInstance(arg);//instanceof不能用,可以用isInstance来检验标签出入类型参数后是否可以在类型表达式中使用
}
}
public class Tag {
publicstatic voidmain(String[] args) throws InstantiationException,IllegalAccessException {
//TODOAuto-generated method stub
ClassTypeCapture<Building>ctt1 =
new ClassTypeCapture<Building>(Building.class);
System.out.println(ctt1.f(new Building()));
System.out.println(ctt1.f(new House()));
ClassTypeCapture<House>ctt2 =
new ClassTypeCapture<House>(House.class);
System.out.println(ctt2.f(new Building()));
System.out.println(ctt2.f(new House()));
}
}
注意:
List<? ExtendsFruit> flist = new ArrayList<Apple>();//这句意味着一旦执行list的类型转为< ? Extends Fruit>,他讲不能接受接受添加是不能接受对父类不同类型的添加
List<? SuperApple> list = new ArrayList<>();这样可以接受添加工作。
泛型的问题:
1. 任何基本类型不能作为类型参数如:ArrayList<int>是错误的,但ArrayList<Integer>没有问题
2. 不能实现参数化接口:interfacepayable<T> {}
Class Employeeimplements payable<Employee>{}
Class Hourlyextends Employee implements Payable<Hourly>{}
这样是编译通不过的,由于擦除导致子类父类实现同一个接口。了
3. 使用带泛型参数的转型和instanceof不会有任何效果
4. 重载不能编译:public classUseList<W,T>{
a) Void f(List<T> v ) {}
b) Void f(List<W> v ) {}实际上由于编译器擦除,编译器看到的是void f(List v){}这一个函数,故这种情况下函数不能重名