参考于( Java 通配符解惑 )泛型类型的子类型的不相关性。比如 现在List<Cat>并不是List<Anilmal>是两种不同的类型;且无继承关系 。那么,我们像想要传入的参数既可能是List<Cat>
也有可能是List<Annimal>
public class AnimalTrainer { public void act(List<? extends Animal> list) { //备注:如果用 List<Animal> 作为形参列表,是无法传入List<Cat>for (Animal animal : list) { animal.eat(); } } }
act(List<? extends Animal> list),当中“?”就是通配符,而“? extends Animal”则表示通配符“?”的上界为Animal,换句话说就是,“? extends Animal”可以代表Animal或其子类,可代表不了Animal的父类(如Object),因为通配符的上界是Animal。
所以,泛型内是不存在父子关系,但是利用通配符可以产生类似的效果:假设给定的泛型类型为G,(如List<E>中的List),两个具体的泛型参数X、Y,当中Y是X的子类(如上的Animal和Cat))
G<? extends Y> 是 G<? extends X>的子类型(如List<? extends Cat> 是 List<? extends Animal>的子类型)。
G<X> 是 G<? extends X>的子类型(如List<Animal> 是 List<? extends Animal>的子类型)
G<?> 与 G<? extends Object>等同,如List<?> 与List<? extends Objext>等同
三: 泛型可以用到那些地方泛型可以用到容器,方法,接口,内部类,抽象类
四: Java中泛型独特之处泛型是Java1.5之后才引入的,为了兼容。Java采用了C++完全不同的实现思想。Java中的泛型更多的看起来像是编译期用的,比如我定义一个使用泛型的demo
我在查看它的class文件时,发现class文件并没有任何泛型信息。
Java会在编辑期把泛型擦除掉在JAVA的虚拟机中并不存在泛型,泛型只是为了完善java体系,增加程序员编程的便捷性以及安全性而创建的一种机制,在JAVA虚拟机中对应泛型的都是确定的类型,在编写泛型代码后,java虚拟中会把这些泛型参数类型都擦除,用相应的确定类型来代替,代替的这一动作叫做类型擦除,而用于替代的类型称为原始类型,在类型擦除过程中,一般使用第一个限定的类型来替换,若无限定,则使用Object.
擦除的原理以及边界关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。
可以参考Java泛型-类型擦除。 运行期编译期会去掉泛型信息,转换为左边界,在调用的地方添加类型转换。
泛型擦除肯可能导致的问题 用泛型不可以区分方法签名public void test(List<String> ls){ System.out.println("Sting"); } public void test(List<Integer> li){ System.out.println("Integer"); } //这回报错,编译期无法区分这两个方法
泛型类的静态变量是共享
public class StaticTest{ public static void main(String[] args){ GT<Integer> gti = new GT<Integer>(); gti.var=1; GT<String> gts = new GT<String>(); gts.var=2; System.out.println(gti.var); } } class GT<T>{ public static int var=0; public void nothing(T x){} }
五: 泛型中特殊使用java中的泛型不只是上述说的内容,还有一些特殊的地方,如果这些地方也用泛型该怎么设计。比如说“动态类型”,“潜在类型”,“异常”
程序如果运行时需要类型信息就在调用的地方传入类型信息
异常中使用泛型不能抛出也不能捕获泛型类的对象。事实上,泛型类扩展Throwable都不合法,因为泛型信息会被擦除,相当于catch两个相同的异常,是不可以的
数组与泛型