记一次Java泛型与类型继承的讨论

首先申明个人观点,仅供参考。

  1. 抛出观点:

    1. Java泛型不考虑类型继承

  2. 验证过程:

    1. 首先明确Java泛型在编译之后是类型擦除的,即ArrayList<Integer>和ArrayList<String>编译之后是同一种class

    2. public static void main(String[] args) {
          List<Integer> list1 = new ArrayList<>();
          List<String> list2 = new ArrayList<>();
      
          System.out.println(list1.getClass() == list2.getClass());
      }
      输出为true
    3. 泛型在编译前会有类型检查

    4. public static void main(String[] args) {
          List<Integer> list1 = new ArrayList<>();
          List<String> list2 = new ArrayList<>();
      
          list1.add("aaa"); // 编译不过
      }
    5. 类型擦除之后会用原始类型来存储对象引用,即ArrayList<Integer>最后的原始类型是Object

    6. public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
              List<Integer> list1 = new ArrayList<>();
              List<String> list2 = new ArrayList<>();
      
              list1.add(1);
      //        list1.add("aaa"); //此处编译不过
              list1.getClass().getMethod("add", Object.class).invoke(list1, "aaa");
              System.out.println(list1.get(1));
          }
      最后输出aaa,
      这样是可以运行的,说明list1编译之后擦除了类型,类型检查只在编译前执行,list1擦除类型之后使用Object作为原始类型,可以存储String对象
    7. List类型在get元素时会有一次类型强制转换,对应转换后的类型按变量申明的类型

    8. E elementData(int index) {
          return (E) elementData[index];
      }
      // Object obj = list1.get(1)
      这样取list1的元素,list1强转时对应E就是Object
      // Integer int1 = list1.get(1)
      这样取对应的E就是Integer,此时运行会报ClassCastException,因为第二个元素存储的是一个String
    9. 翻看对应的字节码可以看的更清楚,截取了部分字节码

    10. public static void main(java.lang.String[]) throws java.lang.NoSuchMethodException, java.lang.reflect.InvocationTargetException, java.lang.IllegalAccessException;
          Code:
             0: new           #2                  // class java/util/ArrayList
             3: dup
             4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
             7: astore_1
             8: aload_1
             9: iconst_1
            10: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
            13: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
            18: pop
            19: aload_1
            20: invokevirtual #6                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
            23: ldc           #7                  // String add
            25: iconst_1
            26: anewarray     #8                  // class java/lang/Class
            29: dup
            30: iconst_0
            31: ldc           #9                  // class java/lang/Object
            33: aastore
            34: invokevirtual #10                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
            37: aload_1
            38: iconst_1
            39: anewarray     #9                  // class java/lang/Object
            42: dup
            43: iconst_0
            44: ldc           #11                 // String aaa
            46: aastore
            47: invokevirtual #12                 // Method java/lang/reflect/Method.invoke:(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
            50: pop
            51: aload_1
            52: invokeinterface #13,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
            57: astore_2
            58: aload_2
            59: invokeinterface #14,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
            64: ifeq          87
            67: aload_2
            68: invokeinterface #15,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
            73: checkcast     #16                 // class java/lang/Integer // 此处会发生类型强转
            76: astore_3
            77: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
            80: aload_3
            81: invokevirtual #18                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
            84: goto          58
            87: return
    11. 说到正题,List<Integer>和List<Object>

    12. public class Generic {
      
          public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
              List<Integer> list1 = new ArrayList<>();
              List<Object> list2 = new ArrayList<>();
      
              list1.getClass().getMethod("add", Object.class).invoke(list1, "aaa");
              list2.add(111);
              
              A a = new A();
              a.print(list1); // 编译不过
          }
      }
      
      class A {
          void print(List<Object> lst) {
              System.out.println(lst.get(0));
          }
      }

    13. 此时必须使用通配符才能解决问题

    14. class A {
          void print(List<? extends Object> lst) {
              System.out.println(lst.get(0));
          }
      }

    15. 这样给我的理解就是泛型是不会考虑类型继承的,虽然Integer是Object的子类,但是List<Integer>和List<String>并不等价.



转载于:https://my.oschina.net/mxjun/blog/660480

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值