内容简介:我们都知道,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[] 。
其实只要再深入一点,就不致被表面现象迷惑!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Practical JavaScript, DOM Scripting and Ajax Projects
Frank Zammetti / Apress / April 16, 2007 / $44.99
http://www.amazon.com/exec/obidos/tg/detail/-/1590598164/ Book Description Practical JavaScript, DOM, and Ajax Projects is ideal for web developers already experienced in JavaScript who want to ......一起来看看 《Practical JavaScript, DOM Scripting and Ajax Projects》 这本书的介绍吧!
UNIX 时间戳转换
UNIX 时间戳转换
HEX HSV 转换工具
HEX HSV 互换工具