虽是读书笔记,可是如转载请注明出处http://segmentfault.com/blog/exploring/
..拒绝伸手复制党java
Java泛型核心概念: 告诉编译器想使用什么类型,而后编译器帮你处理一切细节。segmentfault
泛型的主要目的:数组
泛型不能作什么:不能显示地引用运行时类型操做,例如转型,instanceof and new表达式。(由于擦除)安全
可变参数(T ... args)与泛型方法(makelist实现util.Arrays.asList方法相同的功能)
用于Generator的泛型方法: 使用泛型方法建立Generator对象,大大减小了咱们要编写的代码dom
javapublic BasicGenerator(Class<T> type){ this.type = type; } public T next(){ try{ return type .newInstance(); } catch(Exception e){ throw new RuntimeException(e); } } }
简化元组的使用 : 经过使用泛型方法整个各个Tuple类,重载static方法建立元组工具
javapublic class Tuple { public static <A,B> TwoTuple<A,B> tuple(A a, B b) { return new TwoTuple<A,B>(a, b); } public static <A,B,C> ThreeTuple <A,B,C> tuple(A a, B b, C c) { return new ThreeTuple<A,B,C>(a, b, c);} public static <A,B,C,D> FourTuple<A,B,C,D> tuple(A a, B b, C c, D d) { return new FourTuple<A,B,C,D>(a, b, c, d); } }
一个Set实用工具this
使用泛型能够简单而安全的建立复杂模型code
Java泛型是经过擦除来实现的,namley 在使用泛型的时候,任何具体的类型信息都被擦除了,你惟一知道的就是你在使用一个对象。对象
在java泛型代码内部,没法得到任何有关泛型参数类型的信息。所以,你没法知道用来建立某个特定实例的实际的类型参数。好比List和List在运行时是相同的类型。blog
擦除的正当理由是从非泛华代码到泛华代码的转变过程,以及不破坏现有类库的状况下,将泛型融入Java语言。擦除使得现有的非泛型客户端代码可以在不改变的状况下继续使用,直至客户端准备好用泛型重写这些代码。
边界处的动做: 非泛型和泛型版本的类似的两个类经过javap -c 命令反编译能够发现字节码是相同的,就是说在运行时使用泛型的代码和普通代码没有什么区别。泛型中的全部动做都发生在边界处—对传递进来的值进行额外的编译期检查,并插入对传递出去的值的转型。这有助于澄清对擦除的混淆,所谓边界,就是发生动做的地方。
泛型不能作:
instanceof
解决方法:使用类型标签,利用动态的isInstance判断
javapublic class ClassTypeCapture<T> { Class<T> kind; //类型标签 public ClassTypeCapture(Class<T> kind){ this.kind = kind; } }
泛型不能作:new表达式
解决方法:传递一个显示的工厂对象,限制其类型,使得只能接受实现这个工厂的类。
javapublic interface FactoryI<T> { T create(); } public class Foo2<T> { private T x ; //工厂 public <F extends FactoryI<T>> Foo2(F factory){ x = factory.create(); } public static void main(){ new Foo2<Integer>(new IntegerFactory()); new Foo2<Widget>(new Widget.Factory()); } }
泛型不能作:建立数组 T[] array
解决方法: 想要建立泛型数组的时候都使用ArrayList. orz...或者使用类型标记
若是实在想建立泛型数组,那么惟一方式就是建立一个被擦除类型的新数组(对象数组),而后对其转型。
javapublic class GenericArray<T> { private T[] array ; public GenericArray(int sz){ //建立一个对象数组,而后对它转型 array = (T[])new Object[sz] ; } }
可是这样并非很好,由于有了擦除,数组运行时候类型就只能是Object[],若是在建立时候对其转型为T[],那么编译器该数组的实际类型就会丢失,而编译器可能会错过潜在的错误检查。因此最为可靠的方式:在集合内部使用Object[],而后当你使用数组元素时,添加一个对T的转型。
javaprivate Object[] array; public T get(int index) { return (T) array[index];//Object转型为T } public T[] rep() { return (T[])array; //Object转型为T }
因此最终解决办法是使用类型标记:
javaT[] array ; public Constructor(Class<T> type, int sz) { array = (T[]) Array.newInstance(type, sz); }
边界 通配符 问题 自限定的类型 动态类型安全 异常 ....