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()的构造器逻辑,正常运行
          }
        
      }

        

    • 注意一个关键点:

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

  • 相关阅读:
    React元素渲染
    初识JSX
    微信小程序复制文本到剪切板
    微信小程序报错request:fail url not in domain list
    小程序,通过自定义编译条件,模拟推荐人功能
    积分抵扣逻辑
    微信小程序 switch 样式
    tomcat 配置开启 APR 模式
    tomcat8 传输json 报错 Invalid character found in the request target. The valid characters are defined in RFC 3986
    c++数组初始化误区
  • 原文地址:https://www.cnblogs.com/shoshana-kong/p/8979221.html
Copyright © 2011-2022 走看看