泛型
概念
泛型实现了参数化类型的概念,使代码可以运用于多种类型。泛型正如其名他是一种方法,通过它可以编写出更“泛化”的代码,这些代码对于它们能够作用的类型具有更少的限制,因此单个的代码段可以应用到更多的类型上。所以泛型的通用语言特性的目的在于表达性而不仅仅是为了创建类型安全的容器。
简单泛型
泛型出现的最引人注意的一个原因就是为了创造容器类。泛型最主要的目的就是用来指定容器要持有什么类型的对象。如:
public Class Test<T>{
private T a;
public Test(T a){
this.a =a;
}
public void set(T a){
this.a =a;
}
public T get(){
return a;
}
}
一个元组类库
概念:将一组对象直接打包存储于其中的一个单一对象。这个容器对象允许读取其中元素,但是不允许想其中存放新的对象。也可以称为数据传送对象或信使。
public Class TwoTuple<A,B>{
public final A first;
public final B second;
public TwoTuple(A a,B b){
first = a;second=b;
}
public String toString(){
return "("+first+","+second+")";
}
}
泛型接口
泛型也可以应用于接口。例如生成器(generator),这是一种专门负责创建对象的类。这是工厂发放设计模式的一种应用。
基本类型无法作为类型参数。但是java SE5 具备了自动打包的功能。
泛型方法
泛型方法可以使得该方法能够独立于类儿发生变化。泛型的基本指导原则:无论何时,只要你能做到,你就应该只使用泛型方法。这样可以是事情更清楚明白。
public Class GenericMethods{
public <T> void f(T x){
system.out.println(x.getClass().getName());
}
}
泛型的擦除
在泛型代码的内部,无法获得任何有关泛型参数类型的信息
Java的泛型是使用擦除来实现的,这意味着当你在使用泛型时,任何具体的类型都会被擦除了,你唯一知道的就是你在使用一个对象。因此List<String>与List<Integer>在运行时事实上是相同的类型。他们都被擦除成“原生”类型List。
擦除的核心动机是使得泛化的客户端可以用非泛化的类库来使用,反之亦然,这经常被称之为“迁移兼容性”;擦除的代价使得泛型不能用于显示的引用运行时类型的操作之中,例如转型instanceof操作和new表达式。因为所有参数的类型信息都丢失了。
擦除的补偿
引入类型标签,就可以转而使用动态的isInstance();
public class ClassType<T>{
Class<T> kind;
public ClassType(Class<T> kind){
this.kind = kind;
}
public boolean f(Object arg){
return kind.isInstance(arg);
}
}
边界
使得你可以在用于泛型的参数类型上设置限制条件尽管这是的你可以强制规定泛型可以应用的类型,但是其潜在的一个更重要的效果是你可以按照自己的边界类型来调用方法。
Class Colored<T extend HashColor>{}
通配符被限制为单一边界。
通配符
List<? extends Fruit> first通配符引用的是明确的类型,因此他意味着“某种first引用没有指定的具体类型”
逆变
List<? super MyClass> 添加MyClass或者其子类
无界通配符 <?>可以被认为是一种装饰,可以理解为要写一个泛型的程序
泛型的注意事项
1)任何基本类型都不能作为类型参数
2)一个类不能实现同一个泛型接口的两种变体,由于擦除的原因这两个变体会成为相同的接口。
3)带有泛型类型参数的转型或instanceof不会有任何效果
4)下面的程序不能被编译,由于擦除的原因,重载方法将产生相同的类型签名
public class UseList<W,T>{
public void f<W>{};
public void t<T>{};
}
5)基类劫持了接口
自限定类型
class SelfBounded<T extends SelfBounded<T>>
1)循环泛型,基类用导出类代替其参数
Class GenericType<T>{...}
Class CuriouslyRecurringGeneric extends GenericType<CuriouslyRecurringGeneric>{...}
2)自限定
3)参数协变
自限定类型的价值在于他们可以产生协变参数类型—方法参数类型会随子类发生变化。
动态类型安全
java.util.Collections中有一组便利工具,可以解决在这种情况下的类型检查问题,它们是:静态方法checkedCollection()、checkedList()、checkedMap()、checkedSet()、checkedSortedMap()、checkedSortedSet().
这些方法每一个都会将你希望动态检查的容器当做第一个检查参数接受,并将你希望强制要求的类型作为第二个参数接受。
异常
catch语句不能捕获放心类型的异常,因为在编译器和运行时都必须知道异常的确切类型。泛型类也不能直接或者简介继承自Throwable。但是类型参数可能会在一个方法的throws自居中用到。
混型
。。。。