Java知识体系之-泛型与泛型擦除

#Java泛型与进阶
##什么是泛型
泛型是Java中一种常用的用于解决编译期间的类型转换异常的方式,防止在运行期间出现classCastException。

代码如下:

public class GlmapperGeneric<T> {
		private T t;
    public void set(T t) { this.t = t; }
    public T get() { return t; }
  
    public static void main(String[] args) {
        // do nothing
    }

  /**
    * 不指定类型
    */
  public void noSpecifyType(){
    GlmapperGeneric glmapperGeneric = new GlmapperGeneric();
    glmapperGeneric.set("test");
    // 需要强制类型转换
    String test = (String) glmapperGeneric.get();
    System.out.println(test);
  }

  /**
    * 指定类型
    */
  public void specifyType(){
    GlmapperGeneric<String> glmapperGeneric = new GlmapperGeneric();
    glmapperGeneric.set("test");
    // 不需要强制类型转换
    String test = glmapperGeneric.get();
    System.out.println(test);
  }
}

##泛型中的通配符
在泛型中,通常使用的通配符有如下几种:T,E,K,V ? ,这些符号你可以自己指定,但是为了更好的理解,我们通常使用上述作为默认规则。
T:代表指定的Java类型;
E:代表Element;
K和V:用于在Map中存储的key-value;
?:代表不确定的Java类型;

###?通配符
我们先来看一个例子:List<? extend Animals> list = new List();
此时,它表示的意思就是我们的这个list可以传递的就是继承了Animals的子类;

###上届通配符
所谓的上届通配符就是< ? extends E>,代表的意思是传递任意一个E本身或者E的子类都OK。
###下届通配符
所谓的下届通配符就是< ? super E>,代表的意思是传递任意一个是E本身或者E的父类都OK。

private <T> void test(List<? super T> dst, List<T> src){
    for (T t : src) {
        dst.add(t);
    }
}

public static void main(String[] args) {
    List<Dog> dogs = new ArrayList<>();
    List<Animal> animals = new ArrayList<>();
    new Test3().test(animals,dogs);
}
// Dog 是 Animal 的子类
class Dog extends Animal {

}

###?和T的区别
从字面的意思上来看:?代表的是非指定的任意Java类,T代表的是指定的Java类,T只可以继承某个类,而?可以标识父类或者子类:? extend A , ? super A。

##泛型擦除

// 指定泛型为String

List<String> list1 = new ArrayList<>();
// 指定泛型为Integer
List<Integer> list2 = new ArrayList<>();

System.out.println(list1.getClass() == list2.getClass()); // true

在编译时,对于这些已经指定过的泛型,编译器会将它们都清除掉,这样的操作我们叫做泛型擦除。
规则:如果我们给泛型指定了上届,那么在擦除之后,它会指定到上届。否则,它将指定到Object。

##参考地址

https://juejin.im/post/5d5789d26fb9a06ad0056bd9

https://juejin.im/post/5ceba1a2f265da1b95703558