内容简介:我们都知道,java中对类型的检查是很严格的,所以我们平操作时,也往往很小心。如题: (T[]) new Object[size],这种写法是一般我们是不会干的!但是有点经验的同学,还是会遇到这样写的。那么,今天咱们就来看看,像这样的写法对不对,也顺便深入理解java的类型转换机制吧!问题1: 如题 (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 us = arrayAGeneric.pop(); 9 System.out.println("us1: " + us); 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[] 。
其实只要再深入一点,就不致被表面现象迷惑!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 深入理解Java虚拟机 - 字节码指令集
- 深入理解Java虚拟机(类文件结构+类加载机制+字节码执行引擎)
- 《深入理解Java虚拟机》-----第8章 虚拟机字节码执行引擎——Java高级开发必须懂的
- 主机字节序和网络字节序
- 操作 Java 字节码
- JVM基础 -- 字节码
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
设计模式之禅(第2版)
秦小波 / 机械工业出版社 / 2014-2-25 / 89.00元
本书是设计模式领域公认的3本经典著作之一,“极具趣味,容易理解,但讲解又极为严谨和透彻”是本书的写作风格和方法的最大特点。第1版2010年出版,畅销至今,广受好评,是该领域的里程碑著作。深刻解读6大设计原则和28种设计模式的准确定义、应用方法和最佳实践,全方位比较各种同类模式之间的异同,详细讲解将不同的模式组合使用的方法。第2版在第1版的基础上有两方面的改进,一方面结合读者的意见和建议对原有内容中......一起来看看 《设计模式之禅(第2版)》 这本书的介绍吧!