zoukankan      html  css  js  c++  java
  • Java 泛型小结

    1、什么是泛型?

     

    泛型(Generics )是把类型参数化,运用于类、接口、方法中,可以通过执行泛型类型调用 分配一个类型,将用分配的具体类型替换泛型类型。然后,所分配的类型将用于限制容器内使用的值,这样就无需进行类型转换,还可以在编译时提供更强的类型检查。 

     

    2、泛型有什么用?

     

    泛型主要有两个好处:

     

    (1)消除显示的强制类型转换,提高代码复用

     

    (2)提供更强的类型检查,避免运行时的ClassCastException

     

    3、泛型的使用

     

    类型参数(又称类型变量)用作占位符,指示在运行时为类分配类型。根据需要,可能有一个或多个类型参数,并且可以用于整个类。根据惯例,类型参数是单个大写字母,该字母用于指示所定义的参数类型。下面列出每个用例的标准类型参数:

     

    E:元素

    K:键

    N:数字

    T:类型

    V:值

    S、U、V 等:多参数情况中的第 2、3、4 个类型

    ? 表示不确定的java类型(无限制通配符类型)

     

    4、有界泛型

    <? extends T>:是指 “ 上界通配符 (Upper Bounds Wildcards) ”

     

    <? super T>:是指 “ 下界通配符 (Lower Bounds Wildcards) ”

     

    —这里有个坑

    如 List<? extends T> 大家以为元素为 T以及其所有子类的对象 的List。其实不是。元素类型 仅指T的某一个不确定的子类,是单一的一个不确定类,没有具体哪个类。因此不能插入一个不确定的。

     

    List<? super T> 大家以为元素为 T以及其父类的对象 的List。其实不是,元素类型 仅指T的某一个不确定的父类,是单一的一个不确定类(只确定是T的父类),没有具体哪个类。

     

    因此:

     

    不能往List<? extends T>中插入任何类型的对象。唯一可以保证的是,你可以从中读取到T或者T的子类。

     

    可以往List<? super T>中插入T或者T子类的对象,但不可以插入T父类的对象。可以读取到Object或者Object子类的对象(你并不知道具体的子类是什么)

    总结一下:

    如果频繁支持读取数据,不要求写数据,使用<? extends T>。即生产者 使用 <? extends T>;

    如果频繁支持写入数据,不特别要求读数据,使用<? super T>。即消费者 使用 <? super T>;

    如果都需要支持,使用<T>。 

    5、类型擦除

    Java的泛型在编译期间,所有的泛型信息都会被擦除掉。 

    • Class c1 = new ArrayList<Integer>().getClass();  

      Class c2 = new ArrayList<Long>().getClass();   

      System.out.println(c1 == c2); 

      这就是 Java 泛型的类型擦除造成的,因为不管是 ArrayList<Integer> 还是 ArrayList<Long>,在编译时都会被编译器擦除成了 ArrayList。Java 之所以要避免在创建泛型实例时而创建新的类,从而避免运行时的过度消耗。

    6、泛型类型信息 

    • 那么,如果我们确实某些场景,如HTTP或RPC或jackson需要获取泛型进行序列化反序列化的时候,需要获取泛型类型信息。

      可以参照如下:

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      //获取运行时的泛型类型信息
      public class Test2 {
        
          static class ParameterizedTypeReference<T> {
              protected final Type type;
        
              public ParameterizedTypeReference() {
                  Type superClass = this.getClass().getGenericSuperclass();
                  //if (superClass instanceof Class) {
          // throw new IllegalArgumentException(
      //"Internal error: TypeReference constructed without actual type information");
                  //  } else {
                      this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
                  //}
              }
        
              public Type getType() {
                  return type;
              }
          }
        
          public static void main(String[] args) {
      // System.out.println(new ParameterizedTypeReference<String>().getType());
      // java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
      // 此处会输出报错,因此ParameterizedTypeReference 应不能直接实例化,可以考虑加abstract
        
              System.out.println(new ParameterizedTypeReference<String>() { }.getType());
      // ParameterizedTypeReference 的匿名内部类,可以触发super(),
      //即 ParameterizedTypeReference()的构造器逻辑,正常运行
          }
        
      }

        

    • 注意一个关键点:

      可以通过定义类的方式(通常为匿名内部类,因为我们创建这个类只是为了获得泛型信息)在运行时获得泛型参数。

  • 相关阅读:
    牛客网-练习题
    牛客网-趋势科技-2020届校园招聘上机考试-1
    976. Largest Perimeter Triangle--Easy
    812. Largest Triangle Area--Easy
    123. Best Time to Buy and Sell Stock III--Hard
    1131. Maximum of Absolute Value Expression--Medium
    1103. Distribute Candies to People--Easy
    满足高并发的I/O Reactor线程模型 (附图,附代码)
    最简洁易懂的方式介绍I/O模型
    从鸿蒙OS的特性看华为应对封锁的策略
  • 原文地址:https://www.cnblogs.com/shoshana-kong/p/8979221.html
Copyright © 2011-2022 走看看