两种分配方式的区别
Difference between two types of allocations
foo[] 示例 = new foo[4];
变体 1
example [0] = example [1] = example [2] = example [3] = new foo(5);
变体 2
example [0] = new foo(5);
example [1] = example [0];
example [2] = example [0];
example [3] = example [0];
Java 在内部处理这两种分配的方式有区别吗?第一个变体有一个特殊的名字吗?字节码有什么区别?
郑重声明,字节码确实不同。这是为第一个版本生成的字节码:
0: iconst_4
1: anewarray #2 // class com/foo/Allocation$Foo
4: astore_1
5: aload_1
6: iconst_0
7: aload_1
8: iconst_1
9: aload_1
10: iconst_2
11: aload_1
12: iconst_3
13: new #2 // class com/foo/Allocation$Foo
16: dup
17: iconst_5
18: invokespecial #3 // Method com/foo/Allocation$Foo."<init>":(I)V
21: dup_x2
22: aastore
23: dup_x2
24: aastore
25: dup_x2
26: aastore
27: aastore
28: return
这是为第二个生成的字节码:
0: iconst_4
1: anewarray #2 // class com/foo/Allocation$Foo
4: astore_1
5: aload_1
6: iconst_0
7: new #2 // class com/foo/Allocation$Foo
10: dup
11: iconst_5
12: invokespecial #3 // Method com/foo/Allocation$Foo."<init>":(I)V
15: aastore
16: aload_1
17: iconst_1
18: aload_1
19: iconst_0
20: aaload
21: aastore
22: aload_1
23: iconst_2
24: aload_1
25: iconst_0
26: aaload
27: aastore
28: aload_1
29: iconst_3
30: aload_1
31: iconst_0
32: aaload
33: aastore
34: return
我个人认为这两个版本的可读性都低于
Arrays.fill(example, new Foo(5));
第一个版本是all one expression。赋值表达式将值存储到数组中,然后表达式计算为存储的值。所以它都是一个巨大的表达式,相同的值存储在每个数组位置,没有中间读取。
在第二个版本中,它每次都从数组中读取。如果您有多线程代码并且另一个线程正在同时修改数组,那么这可能会 return 不同的结果。
对于单线程代码,它们实际上是相同的。
注意:这是第一个版本的样子,添加了括号以指示评估顺序。
example [0] = (example [1] = (example [2] = (example [3] = (new foo(5)))));
相当于下面的代码(注意缺少数组读取)
foo t = new foo(5);
example[3] = t;
example[2] = t;
example[1] = t;
example[0] = t;
P.S。另一个区别是它们以相反的顺序分配数组元素。因此,如果数组的长度小于 4,第一个版本将立即抛出,而第二个版本将部分填充数组。
foo[] 示例 = new foo[4];
变体 1
example [0] = example [1] = example [2] = example [3] = new foo(5);
变体 2
example [0] = new foo(5);
example [1] = example [0];
example [2] = example [0];
example [3] = example [0];
Java 在内部处理这两种分配的方式有区别吗?第一个变体有一个特殊的名字吗?字节码有什么区别?
郑重声明,字节码确实不同。这是为第一个版本生成的字节码:
0: iconst_4
1: anewarray #2 // class com/foo/Allocation$Foo
4: astore_1
5: aload_1
6: iconst_0
7: aload_1
8: iconst_1
9: aload_1
10: iconst_2
11: aload_1
12: iconst_3
13: new #2 // class com/foo/Allocation$Foo
16: dup
17: iconst_5
18: invokespecial #3 // Method com/foo/Allocation$Foo."<init>":(I)V
21: dup_x2
22: aastore
23: dup_x2
24: aastore
25: dup_x2
26: aastore
27: aastore
28: return
这是为第二个生成的字节码:
0: iconst_4
1: anewarray #2 // class com/foo/Allocation$Foo
4: astore_1
5: aload_1
6: iconst_0
7: new #2 // class com/foo/Allocation$Foo
10: dup
11: iconst_5
12: invokespecial #3 // Method com/foo/Allocation$Foo."<init>":(I)V
15: aastore
16: aload_1
17: iconst_1
18: aload_1
19: iconst_0
20: aaload
21: aastore
22: aload_1
23: iconst_2
24: aload_1
25: iconst_0
26: aaload
27: aastore
28: aload_1
29: iconst_3
30: aload_1
31: iconst_0
32: aaload
33: aastore
34: return
我个人认为这两个版本的可读性都低于
Arrays.fill(example, new Foo(5));
第一个版本是all one expression。赋值表达式将值存储到数组中,然后表达式计算为存储的值。所以它都是一个巨大的表达式,相同的值存储在每个数组位置,没有中间读取。
在第二个版本中,它每次都从数组中读取。如果您有多线程代码并且另一个线程正在同时修改数组,那么这可能会 return 不同的结果。
对于单线程代码,它们实际上是相同的。
注意:这是第一个版本的样子,添加了括号以指示评估顺序。
example [0] = (example [1] = (example [2] = (example [3] = (new foo(5)))));
相当于下面的代码(注意缺少数组读取)
foo t = new foo(5);
example[3] = t;
example[2] = t;
example[1] = t;
example[0] = t;
P.S。另一个区别是它们以相反的顺序分配数组元素。因此,如果数组的长度小于 4,第一个版本将立即抛出,而第二个版本将部分填充数组。