泛型

(泛型使用基本类型
方法是否泛型和其所在类是否泛型无关:
方法可使用两种泛型:一是如果类也是泛型类,类的泛型可用。而是在
返回值前加<T>来定义专属该方法的泛型
使用泛型类必须声明泛型,而使用泛型方法不用:编译器会采用类型参数推断技术猜出来。
方便的生成容器:由于技术有限,容器的生成必须经显式的声明泛型,十分麻烦,本来容器应该可以根据往其中填充的类型推断的。所以使用类型参数推断(只在等号处生效)可以简化过程:由Set<String> set=new Set<String>();改进为
Set<String> set=makeset(); Set<T> makeset(){return Set<T>;}可以方便的生成容器 ;
所有的泛型生成器都可以尝试使用类型参数推断来简化
类型参数推断最好限定在生成器中,以免造成混淆
在SE7中,增添了菱形语法,即简单的省略为new Set<>;即可。
可变参数与泛型无冲突 main(T...args)
擦除的神秘之处
可以声明 ArrayList.class不能生成ArrayList<Integer>.class
泛型并不会改变其使用类的.class内容
泛型挟带的信息都会在运行之前遭到擦除,可以认为在静态检查阶段没有报错的泛型到达运行阶段时都可以被当作其可代表的最基层类(其非泛型上界)
java并不是第一个使用泛型的语言,java的泛型是对其他语言过渡者的“兼容”或者一种学习,并不是在设计之初就打算实现的,所以其是一种折中,这种这种造成泛型的擦除,而擦除让泛型并不是那么有用。
折中(擦除出现的理由):核心动机是为了泛型化的客户端仍然可以使用非泛化的老库,反之亦然,这被叫做“迁移兼容性”。简言之,由于之初并没有为泛型留出空间,导致以前的程序和现在机制的兼容很困难,既然以前的库不认可泛型,那么就把泛型扔掉好了,只在本地使用,代码的本地计算机专用的当然就是静态检查过程,所以擦除诞生了。使用擦除来折中是无奈之举。擦除是否好用还需时间证明
擦除的代价:泛型不能显示的运用,例如转型(会变成转到非泛型上界)、instanceof(判断其左边对象是否为其右边类的实例,返回boolean类型的数据)、构造器(谨慎的不接受非泛型上界,直接报错)
擦除的补偿:1、通过构造器显示的传递.class(Class类) 2、使用Class类的newInstance方法可以生成实例。
数组:数组将跟踪其实际类型,即其被创建时的类型,我们只能用泛型来做静态检查而无法改变数组的类型。
现今标准库中仍有许多会报警告的泛型问题,我们可以正当的使用@SuppressWarnings来忽略他们。
边界:自定义擦除的结果和静态检查范围
边界重用了表示继承的extends:<T extends father>  <? extends father>
通配符: 问号?:
?符和T的区别:T作用于类和方法的定义,在使用是需要替换成某种确切的类名,而?不需要,它可和extends结合,和“某种确切的类名”使用范围一致。
超类型通配符:super :和extend相同,只不过没有自定义非泛型基类的能力
无界通配符:就是单独用的问号
数组和容器并不继承其持有对象的关系,如son extends father ,but son[] !extends father[] 
List<?>和List<Object>(等同List)的区别:前者会要求必须是同一类型及其基类,而后者是所有类均可混合
擦除带来的问题:
  1. 由于数组不适用于自动包装机制而泛型不适应原形所以数组的使用会出现问题
  2. 泛型化的接口并不能用不同的泛型来区分,所以无法让一个类实现同接口的不同泛型分类,但是重复实现非泛型接口却是被允许的
  3. 泛型不能作为重载的区分点
自限定:形如A<T extends A<T>>的class声明方式,自限定使得必须像这样声明A的继承类:B extends A<B>,即要求其继承类必须继承自限定的泛型参数基类
动态容器保护:
由于老的代码仍然可以接受泛型容器,老的代码不进行泛型的静态检查,所以必须主动的调用Collections下的check方法来监控是否有非法类插入到容器,如果不调用则报错会出现在使用时,而造成错误的插入已经在时间和空间上相隔甚远了。
原文地址:https://www.cnblogs.com/gjl-blog/p/8562956.html