zoukankan      html  css  js  c++  java
  • 从字节码看java类型转换【 深入理解 (T[]) new Object[size] 】

      我们都知道,java中对类型的检查是很严格的,所以我们平操作时,也往往很小心。

      如题: (T[]) new Object[size],这种写法是一般我们是不会干的!但是有点经验的同学,还是会遇到这样写的。那么,今天咱们就来看看,像这样的写法对不对,也顺便深入理解java的类型转换机制吧!


    问题1: 如题 (T[]) new Object[size]  的写法对不对?

      答案是肯定的,没毛病。

      为啥呢? 因为 java 的泛型只是语法糖,在java编译后,就不见了,到最后都会转为 object 类型的中间类型,所以,没毛病!


    问题2: 如题所示的变量,能直接使用吗?

      答案待定。不过,我们写的代码应该是不会有什么问题了!如下:

    MyObjClz[] clzArr = getT();    // 直接获取变量,编译不报错

      然后,由于看起来没毛病,我们就可以坑哧坑哧写后续代码了!

      然而事实证明,这是错的!为啥呢? 你应该知道了,这里有类型转换错误!

      好吧,从这里我们得到一个教训,正向没问题的东西,不代表反向也没问题!

      既然整个数组获取回来,会发生类型转换错误,那么我们可以想办法避开这个问题,比如我一个元素一个元素的获取,应该就没问题了吧。因为我们明确知道内部元素的具体类型,而我们只是做了一个 object 的中间转换而已,所以理论正确。比如:

    MyObjClz clz1 = getT()[0];    // 我只获取第一个就行了,因为 整个数组转换已经不OK

      嗯,IDE还是不会报错的,我们又可以坑哧坑哧写代码了。

      糟糕,运行还是异常了!哎,既然都会导致报错,那为嘛要搞这种语法呢?让我们继续看!


    问题3:我们到底怎样才可以使用如题创建的变量?

      其实和我们上面最后一个解题思路是一致的,整个数组类型转换是不可能了,那就单个转呗!不过,这个单个是要从源头开始。即示例如下:

    MyObjClz clz1 = getTOne(i);    // 直接让方法返回 单个元素

      如上,运行妥妥的,我们终于可以安心睡觉了。但是为啥呢?让我们继续!


    问题4:如题所示的语法到底有啥用?

      额,还是很有用的!比如: ArrayList<E>, ArrayQueue<T>, 等等,里面所支持的泛型,最终都会使用到Object 来进行变量保存的,因为既然是泛型,也就是说,在写代码的时候,是不会知道变量类型的,不知道类型自然是保存不了变量的。所以必须使用 Object[] !

    下面来看个应用的例子(可以想像为一个栈队列):

     1 public class ObjectCastToAnother {
     2     public static void main(String[] args) {
     3 
     4         ArrayAGeneric<User> arrayAGeneric = new ArrayAGeneric<>();
     5         arrayAGeneric.push(new User());
     6         arrayAGeneric.push(new User());
     7         // 正确的使用姿势,返回一个元素,直接使用
     8         User us1 = arrayAGeneric.pop();
     9         System.out.println("us1: " + us1);
    10         // 如下是反而教材,这句是会报错的
    11         User us2 = arrayAGeneric.getQueue()[0];
    12         System.out.println("us2: " + us2);
    13     }
    14 }
    15 
    16 class ArrayAGeneric<T> {
    17     private T[] queue;
    18     private int tail = 0;
    19     public ArrayAGeneric() {
    20         System.out.println("gen ok");
    21         queue = newArray(10);
    22     }
    23 
    24     private T[] newArray(int size) {
    25         System.out.println("new array T[]");
    26         return (T[]) new Object[size];
    27     }
    28 
    29     public void push(T u) {
    30         queue[tail++] = u;
    31     }
    32 
    33     public T pop() {
    34         return queue[--tail];
    35     }
    36 
    37     public T[] getQueue() {
    38         return queue;
    39     }
    40 }

      例子一看就懂,就是一个简单的 插入元素,获取元素,使用而已。但是我们的目的是来分析,为什么两种简单的使用,一个会报错,而另一个不会报错,以及 (T[]) new Object[x]为啥不会报错!即如下:

            User us = arrayAGeneric.pop();                // 正确
            User us2 = arrayAGeneric.getQueue()[0];        // 错误
            return (T[]) new Object[size];                // 什么操作?

      看起来差距只在是由谁来取元素的问题了!那么,到底是不是这样呢?(java理论书上肯定有确切的答案)

    那我们换个思路来看问题,然后java代码看不出差别,那么,我们是不是可以换成另一种方式来查看呢?是的,class字节码文件。

    反编译一下,会得到两个文件:

    javap -verbose -p ObjectCastToAnnother.class  # 反编译class

    1. main 文件

      1 Classfile /D:/www/java/target/classes/com/xxx/tester/ObjectCastToAnnother.class
      2   Last modified 2018-11-18; size 1398 bytes
      3   MD5 checksum 8a1815ea41426d67e1a4b68bed4ca914
      4   Compiled from "ObjectCastToAnnother.java"
      5 public class com.xxx.tester.ObjectCastToAnnother
      6   minor version: 0
      7   major version: 52
      8   flags: ACC_PUBLIC, ACC_SUPER
      9 Constant pool:
     10    #1 = Methodref          #20.#41        // java/lang/Object."<init>":()V
     11    #2 = Class              #42            // com/xxx/tester/ArrayAGeneric
     12    #3 = Methodref          #2.#41         // com/xxx/tester/ArrayAGeneric."<init>":()V
     13    #4 = Class              #43            // com/xxx/pojo/user/User
     14    #5 = Methodref          #4.#41         // com/xxx/pojo/user/User."<init>":()V
     15    #6 = Methodref          #2.#44         // com/xxx/tester/ArrayAGeneric.push:(Ljava/lang/Object;)V
     16    #7 = Methodref          #2.#45         // com/xxx/tester/ArrayAGeneric.pop:()Ljava/lang/Object;
     17    #8 = Fieldref           #46.#47        // java/lang/System.out:Ljava/io/PrintStream;
     18    #9 = Class              #48            // java/lang/StringBuilder
     19   #10 = Methodref          #9.#41         // java/lang/StringBuilder."<init>":()V
     20   #11 = String             #49            // us1:
     21   #12 = Methodref          #9.#50         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     22   #13 = Methodref          #9.#51         // java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
     23   #14 = Methodref          #9.#52         // java/lang/StringBuilder.toString:()Ljava/lang/String;
     24   #15 = Methodref          #53.#54        // java/io/PrintStream.println:(Ljava/lang/String;)V
     25   #16 = Methodref          #2.#55         // com/xxx/tester/ArrayAGeneric.getQueue:()[Ljava/lang/Object;
     26   #17 = Class              #56            // "[Lcom/xxx/pojo/user/User;"
     27   #18 = String             #57            // us2:
     28   #19 = Class              #58            // com/xxx/tester/ObjectCastToAnnother
     29   #20 = Class              #59            // java/lang/Object
     30   #21 = Utf8               <init>
     31   #22 = Utf8               ()V
     32   #23 = Utf8               Code
     33   #24 = Utf8               LineNumberTable
     34   #25 = Utf8               LocalVariableTable
     35   #26 = Utf8               this
     36   #27 = Utf8               Lcom/xxx/tester/ObjectCastToAnnother;
     37   #28 = Utf8               main
     38   #29 = Utf8               ([Ljava/lang/String;)V
     39   #30 = Utf8               args
     40   #31 = Utf8               [Ljava/lang/String;
     41   #32 = Utf8               arrayAGeneric
     42   #33 = Utf8               Lcom/xxx/tester/ArrayAGeneric;
     43   #34 = Utf8               us
     44   #35 = Utf8               Lcom/xxx/pojo/user/User;
     45   #36 = Utf8               us2
     46   #37 = Utf8               LocalVariableTypeTable
     47   #38 = Utf8               Lcom/xxx/tester/ArrayAGeneric<Lcom/xxx/pojo/user/User;>;
     48   #39 = Utf8               SourceFile
     49   #40 = Utf8               ObjectCastToAnnother.java
     50   #41 = NameAndType        #21:#22        // "<init>":()V
     51   #42 = Utf8               com/xxx/tester/ArrayAGeneric
     52   #43 = Utf8               com/xxx/pojo/user/User
     53   #44 = NameAndType        #60:#61        // push:(Ljava/lang/Object;)V
     54   #45 = NameAndType        #62:#63        // pop:()Ljava/lang/Object;
     55   #46 = Class              #64            // java/lang/System
     56   #47 = NameAndType        #65:#66        // out:Ljava/io/PrintStream;
     57   #48 = Utf8               java/lang/StringBuilder
     58   #49 = Utf8               us1:
     59   #50 = NameAndType        #67:#68        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     60   #51 = NameAndType        #67:#69        // append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
     61   #52 = NameAndType        #70:#71        // toString:()Ljava/lang/String;
     62   #53 = Class              #72            // java/io/PrintStream
     63   #54 = NameAndType        #73:#74        // println:(Ljava/lang/String;)V
     64   #55 = NameAndType        #75:#76        // getQueue:()[Ljava/lang/Object;
     65   #56 = Utf8               [Lcom/xxx/pojo/user/User;
     66   #57 = Utf8               us2:
     67   #58 = Utf8               com/xxx/tester/ObjectCastToAnnother
     68   #59 = Utf8               java/lang/Object
     69   #60 = Utf8               push
     70   #61 = Utf8               (Ljava/lang/Object;)V
     71   #62 = Utf8               pop
     72   #63 = Utf8               ()Ljava/lang/Object;
     73   #64 = Utf8               java/lang/System
     74   #65 = Utf8               out
     75   #66 = Utf8               Ljava/io/PrintStream;
     76   #67 = Utf8               append
     77   #68 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
     78   #69 = Utf8               (Ljava/lang/Object;)Ljava/lang/StringBuilder;
     79   #70 = Utf8               toString
     80   #71 = Utf8               ()Ljava/lang/String;
     81   #72 = Utf8               java/io/PrintStream
     82   #73 = Utf8               println
     83   #74 = Utf8               (Ljava/lang/String;)V
     84   #75 = Utf8               getQueue
     85   #76 = Utf8               ()[Ljava/lang/Object;
     86 {
     87   public com.xxx.tester.ObjectCastToAnnother();
     88     descriptor: ()V
     89     flags: ACC_PUBLIC
     90     Code:
     91       stack=1, locals=1, args_size=1
     92          0: aload_0
     93          1: invokespecial #1                  // Method java/lang/Object."<init>":()V
     94          4: return
     95       LineNumberTable:
     96         line 8: 0
     97       LocalVariableTable:
     98         Start  Length  Slot  Name   Signature
     99             0       5     0  this   Lcom/xxx/tester/ObjectCastToAnnother;
    100 
    101   public static void main(java.lang.String[]);
    102     descriptor: ([Ljava/lang/String;)V
    103     flags: ACC_PUBLIC, ACC_STATIC
    104     Code:
    105       stack=3, locals=4, args_size=1
    106          0: new           #2                  // class com/xxx/tester/ArrayAGeneric
    107          3: dup
    108          4: invokespecial #3                  // Method com/xxx/tester/ArrayAGeneric."<init>":()V
    109          7: astore_1
    110          8: aload_1
    111          9: new           #4                  // class com/xxx/pojo/user/User
    112         12: dup
    113         13: invokespecial #5                  // Method com/xxx/pojo/user/User."<init>":()V
    114         16: invokevirtual #6                  // Method com/xxx/tester/ArrayAGeneric.push:(Ljava/lang/Object;)V
    115         19: aload_1
    116         20: new           #4                  // class com/xxx/pojo/user/User
    117         23: dup
    118         24: invokespecial #5                  // Method com/xxx/pojo/user/User."<init>":()V
    119         27: invokevirtual #6                  // Method com/xxx/tester/ArrayAGeneric.push:(Ljava/lang/Object;)V
    120         30: aload_1
    121         31: invokevirtual #7                  // Method com/xxx/tester/ArrayAGeneric.pop:()Ljava/lang/Object;
    122         34: checkcast     #4                  // class com/xxx/pojo/user/User
    123         37: astore_2
    124         38: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
    125         41: new           #9                  // class java/lang/StringBuilder
    126         44: dup
    127         45: invokespecial #10                 // Method java/lang/StringBuilder."<init>":()V
    128         48: ldc           #11                 // String us1:
    129         50: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    130         53: aload_2
    131         54: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
    132         57: invokevirtual #14                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    133         60: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    134         63: aload_1
    135         64: invokevirtual #16                 // Method com/xxx/tester/ArrayAGeneric.getQueue:()[Ljava/lang/Object;
    136         67: checkcast     #17                 // class "[Lcom/xxx/pojo/user/User;"
    137         70: iconst_0
    138         71: aaload
    139         72: astore_3
    140         73: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
    141         76: new           #9                  // class java/lang/StringBuilder
    142         79: dup
    143         80: invokespecial #10                 // Method java/lang/StringBuilder."<init>":()V
    144         83: ldc           #18                 // String us2:
    145         85: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    146         88: aload_3
    147         89: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
    148         92: invokevirtual #14                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    149         95: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    150         98: return
    151       LineNumberTable:
    152         line 11: 0
    153         line 12: 8
    154         line 13: 19
    155         line 14: 30
    156         line 15: 38
    157         line 16: 63
    158         line 17: 73
    159         line 18: 98
    160       LocalVariableTable:
    161         Start  Length  Slot  Name   Signature
    162             0      99     0  args   [Ljava/lang/String;
    163             8      91     1 arrayAGeneric   Lcom/xxx/tester/ArrayAGeneric;
    164            38      61     2    us   Lcom/xxx/pojo/user/User;
    165            73      26     3   us2   Lcom/xxx/pojo/user/User;
    166       LocalVariableTypeTable:
    167         Start  Length  Slot  Name   Signature
    168             8      91     1 arrayAGeneric   Lcom/xxx/tester/ArrayAGeneric<Lcom/xxx/pojo/user/User;>;
    169 }
    170 SourceFile: "ObjectCastToAnnother.java"

     2. ArrayAGeneric 文件

      1 Classfile /D:/www/java/target/classes/com/xxx/tester/ArrayAGeneric.class
      2   Last modified 2018-11-18; size 1390 bytes
      3   MD5 checksum fc9f7f9311bf542d9f1b03e39e32aba8
      4   Compiled from "ObjectCastToAnnother.java"
      5 class com.xxx.tester.ArrayAGeneric<T extends java.lang.Object> extends java.lang.Object
      6   minor version: 0
      7   major version: 52
      8   flags: ACC_SUPER
      9 Constant pool:
     10    #1 = Methodref          #9.#46         // java/lang/Object."<init>":()V
     11    #2 = Fieldref           #11.#47        // com/xxx/tester/ArrayAGeneric.tail:I
     12    #3 = Fieldref           #48.#49        // java/lang/System.out:Ljava/io/PrintStream;
     13    #4 = String             #50            // gen ok
     14    #5 = Methodref          #51.#52        // java/io/PrintStream.println:(Ljava/lang/String;)V
     15    #6 = Methodref          #11.#53        // com/xxx/tester/ArrayAGeneric.newArray:(I)[Ljava/lang/Object;
     16    #7 = Fieldref           #11.#54        // com/xxx/tester/ArrayAGeneric.queue:[Ljava/lang/Object;
     17    #8 = String             #55            // new array T[]
     18    #9 = Class              #56            // java/lang/Object
     19   #10 = Class              #13            // "[Ljava/lang/Object;"
     20   #11 = Class              #57            // com/xxx/tester/ArrayAGeneric
     21   #12 = Utf8               queue
     22   #13 = Utf8               [Ljava/lang/Object;
     23   #14 = Utf8               Signature
     24   #15 = Utf8               [TT;
     25   #16 = Utf8               tail
     26   #17 = Utf8               I
     27   #18 = Utf8               <init>
     28   #19 = Utf8               ()V
     29   #20 = Utf8               Code
     30   #21 = Utf8               LineNumberTable
     31   #22 = Utf8               LocalVariableTable
     32   #23 = Utf8               this
     33   #24 = Utf8               Lcom/xxx/tester/ArrayAGeneric;
     34   #25 = Utf8               LocalVariableTypeTable
     35   #26 = Utf8               Lcom/xxx/tester/ArrayAGeneric<TT;>;
     36   #27 = Utf8               newArray
     37   #28 = Utf8               (I)[Ljava/lang/Object;
     38   #29 = Utf8               size
     39   #30 = Utf8               (I)[TT;
     40   #31 = Utf8               push
     41   #32 = Utf8               (Ljava/lang/Object;)V
     42   #33 = Utf8               u
     43   #34 = Utf8               Ljava/lang/Object;
     44   #35 = Utf8               TT;
     45   #36 = Utf8               (TT;)V
     46   #37 = Utf8               pop
     47   #38 = Utf8               ()Ljava/lang/Object;
     48   #39 = Utf8               ()TT;
     49   #40 = Utf8               getQueue
     50   #41 = Utf8               ()[Ljava/lang/Object;
     51   #42 = Utf8               ()[TT;
     52   #43 = Utf8               <T:Ljava/lang/Object;>Ljava/lang/Object;
     53   #44 = Utf8               SourceFile
     54   #45 = Utf8               ObjectCastToAnnother.java
     55   #46 = NameAndType        #18:#19        // "<init>":()V
     56   #47 = NameAndType        #16:#17        // tail:I
     57   #48 = Class              #58            // java/lang/System
     58   #49 = NameAndType        #59:#60        // out:Ljava/io/PrintStream;
     59   #50 = Utf8               gen ok
     60   #51 = Class              #61            // java/io/PrintStream
     61   #52 = NameAndType        #62:#63        // println:(Ljava/lang/String;)V
     62   #53 = NameAndType        #27:#28        // newArray:(I)[Ljava/lang/Object;
     63   #54 = NameAndType        #12:#13        // queue:[Ljava/lang/Object;
     64   #55 = Utf8               new array T[]
     65   #56 = Utf8               java/lang/Object
     66   #57 = Utf8               com/xxx/tester/ArrayAGeneric
     67   #58 = Utf8               java/lang/System
     68   #59 = Utf8               out
     69   #60 = Utf8               Ljava/io/PrintStream;
     70   #61 = Utf8               java/io/PrintStream
     71   #62 = Utf8               println
     72   #63 = Utf8               (Ljava/lang/String;)V
     73 {
     74   private T[] queue;
     75     descriptor: [Ljava/lang/Object;
     76     flags: ACC_PRIVATE
     77     Signature: #15                          // [TT;
     78 
     79   private int tail;
     80     descriptor: I
     81     flags: ACC_PRIVATE
     82 
     83   public com.xxx.tester.ArrayAGeneric();
     84     descriptor: ()V
     85     flags: ACC_PUBLIC
     86     Code:
     87       stack=3, locals=1, args_size=1
     88          0: aload_0
     89          1: invokespecial #1                  // Method java/lang/Object."<init>":()V
     90          4: aload_0
     91          5: iconst_0
     92          6: putfield      #2                  // Field tail:I
     93          9: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
     94         12: ldc           #4                  // String gen ok
     95         14: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     96         17: aload_0
     97         18: aload_0
     98         19: bipush        10
     99         21: invokespecial #6                  // Method newArray:(I)[Ljava/lang/Object;
    100         24: putfield      #7                  // Field queue:[Ljava/lang/Object;
    101         27: return
    102       LineNumberTable:
    103         line 24: 0
    104         line 23: 4
    105         line 25: 9
    106         line 26: 17
    107         line 27: 27
    108       LocalVariableTable:
    109         Start  Length  Slot  Name   Signature
    110             0      28     0  this   Lcom/xxx/tester/ArrayAGeneric;
    111       LocalVariableTypeTable:
    112         Start  Length  Slot  Name   Signature
    113             0      28     0  this   Lcom/xxx/tester/ArrayAGeneric<TT;>;
    114 
    115   private T[] newArray(int);
    116     descriptor: (I)[Ljava/lang/Object;
    117     flags: ACC_PRIVATE
    118     Code:
    119       stack=2, locals=2, args_size=2
    120          0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
    121          3: ldc           #8                  // String new array T[]
    122          5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    123          8: iload_1
    124          9: anewarray     #9                  // class java/lang/Object
    125         12: checkcast     #10                 // class "[Ljava/lang/Object;"
    126         15: areturn
    127       LineNumberTable:
    128         line 30: 0
    129         line 31: 8
    130       LocalVariableTable:
    131         Start  Length  Slot  Name   Signature
    132             0      16     0  this   Lcom/xxx/tester/ArrayAGeneric;
    133             0      16     1  size   I
    134       LocalVariableTypeTable:
    135         Start  Length  Slot  Name   Signature
    136             0      16     0  this   Lcom/xxx/tester/ArrayAGeneric<TT;>;
    137     Signature: #30                          // (I)[TT;
    138 
    139   public void push(T);
    140     descriptor: (Ljava/lang/Object;)V
    141     flags: ACC_PUBLIC
    142     Code:
    143       stack=5, locals=2, args_size=2
    144          0: aload_0
    145          1: getfield      #7                  // Field queue:[Ljava/lang/Object;
    146          4: aload_0
    147          5: dup
    148          6: getfield      #2                  // Field tail:I
    149          9: dup_x1
    150         10: iconst_1
    151         11: iadd
    152         12: putfield      #2                  // Field tail:I
    153         15: aload_1
    154         16: aastore
    155         17: return
    156       LineNumberTable:
    157         line 35: 0
    158         line 36: 17
    159       LocalVariableTable:
    160         Start  Length  Slot  Name   Signature
    161             0      18     0  this   Lcom/xxx/tester/ArrayAGeneric;
    162             0      18     1     u   Ljava/lang/Object;
    163       LocalVariableTypeTable:
    164         Start  Length  Slot  Name   Signature
    165             0      18     0  this   Lcom/xxx/tester/ArrayAGeneric<TT;>;
    166             0      18     1     u   TT;
    167     Signature: #36                          // (TT;)V
    168 
    169   public T pop();
    170     descriptor: ()Ljava/lang/Object;
    171     flags: ACC_PUBLIC
    172     Code:
    173       stack=4, locals=1, args_size=1
    174          0: aload_0
    175          1: getfield      #7                  // Field queue:[Ljava/lang/Object;
    176          4: aload_0
    177          5: dup
    178          6: getfield      #2                  // Field tail:I
    179          9: iconst_1
    180         10: isub
    181         11: dup_x1
    182         12: putfield      #2                  // Field tail:I
    183         15: aaload
    184         16: areturn
    185       LineNumberTable:
    186         line 39: 0
    187       LocalVariableTable:
    188         Start  Length  Slot  Name   Signature
    189             0      17     0  this   Lcom/xxx/tester/ArrayAGeneric;
    190       LocalVariableTypeTable:
    191         Start  Length  Slot  Name   Signature
    192             0      17     0  this   Lcom/xxx/tester/ArrayAGeneric<TT;>;
    193     Signature: #39                          // ()TT;
    194 
    195   public T[] getQueue();
    196     descriptor: ()[Ljava/lang/Object;
    197     flags: ACC_PUBLIC
    198     Code:
    199       stack=1, locals=1, args_size=1
    200          0: aload_0
    201          1: getfield      #7                  // Field queue:[Ljava/lang/Object;
    202          4: areturn
    203       LineNumberTable:
    204         line 43: 0
    205       LocalVariableTable:
    206         Start  Length  Slot  Name   Signature
    207             0       5     0  this   Lcom/xxx/tester/ArrayAGeneric;
    208       LocalVariableTypeTable:
    209         Start  Length  Slot  Name   Signature
    210             0       5     0  this   Lcom/xxx/tester/ArrayAGeneric<TT;>;
    211     Signature: #42                          // ()[TT;
    212 }
    213 Signature: #43                          // <T:Ljava/lang/Object;>Ljava/lang/Object;
    214 SourceFile: "ObjectCastToAnnother.java"

    其实从 main 文件中已经看出端倪,第120~123行,即 us1 赋值的地方:

            30: aload_1
            31: invokevirtual #7                  // Method com/xxx/tester/ArrayAGeneric.pop:()Ljava/lang/Object;
            34: checkcast     #4                  // class com/xxx/pojo/user/User
            37: astore_2

    这里看到,有一个 checkcast 的指令,即是进行类型转换检查,而本身的 pop() 后的元素类型一致,因此运行OK!

    我们来看下一取值方式,第134~138行,即 us2 赋值的地方:

            63: aload_1
            64: invokevirtual #16                 // Method com/xxx/tester/ArrayAGeneric.getQueue:()[Ljava/lang/Object;
            67: checkcast     #17                 // class "[Lcom/xxx/pojo/user/User;"
            70: iconst_0
            71: aaload

       看到了吧,关键的地方: checkcast class "[Lcom/xxx/pojo/user/User", 即将获取到的值进行 数组类型的转换检查,如此检查,自然是通不过的了。所以,理解了吧,是因为,数组元素的获取顺序为先进行类型转换,然后再获取元素值!

      现在,还剩下一个问题: 为什么通过 getOne() 的形式,代码就是可行的呢?

      这个问题的答案,在 ArrayAGeneric 的文件中,可以轻松找到答案:

    ArrayAGeneric 文件,第 174~184行:

             0: aload_0
             1: getfield      #7                  // Field queue:[Ljava/lang/Object;
             4: aload_0
             5: dup
             6: getfield      #2                  // Field tail:I
             9: iconst_1
            10: isub
            11: dup_x1
            12: putfield      #2                  // Field tail:I
            15: aaload
            16: areturn

      可以看出来,这里就只是一个数组元素的获取过程,返回类型为 Object, 而此 Object 的原始类型即是泛型指定的。因此,在外部进行转换自然也不会错!

    好了,到此,疑问已经得到回答。是类型转换的检查时机导致了我们的代码错误。

    另外,我们还可以继续看一下  newArray() 的代码:

             0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
             3: ldc           #8                  // String new array T[]
             5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
             8: iload_1
             9: anewarray     #9                  // class java/lang/Object
            12: checkcast     #10                 // class "[Ljava/lang/Object;"
            15: areturn

      这里也可以明显的看出, T[] 其实就是 Object[] 。

          数组类型的强转要特别注意,其向上转型是ok的,向下转型则是不被允许的,因为继承的关系,父类不能保证所有的所有的元素都能强制转换(元素可以是指定类型的任意子类),所以干脆杜绝了所有的向下转型了!(我猜应该是出于性能的考虑)

      不要以为ArrayList<T>中的T是指的具体泛型类,完。

  • 相关阅读:
    Java JMX 监管
    Spring Boot REST(一)核心接口
    JSR 规范目录
    【平衡树】宠物收养所 HNOI 2004
    【树型DP】叶子的颜色 OUROJ 1698
    【匈牙利匹配】无题II HDU2236
    【贪心】Communication System POJ 1018
    【贪心】Moving Tables POJ 1083
    Calling Extraterrestrial Intelligence Again POJ 1411
    【贪心】Allowance POJ 3040
  • 原文地址:https://www.cnblogs.com/yougewe/p/9978452.html
Copyright © 2011-2022 走看看