itD*_*ing 1 java java-memory-model
前两个例子:
1)
MyClass myClass;
for (int i=0; i<arrayList.size(); i++) {
myClass = arrayList.get(i);
...
}
2)
for (int i=0; i<arrayList.size(); i++) {
MyClass myClass = arrayList.get(i);
...
}
Run Code Online (Sandbox Code Playgroud)
在第一个示例中,引用变量myClass仅创建一次.但是在第二个例子中,它是仅创建一次,还是每次迭代创建一次?我的想法也许是编译器优化了这个,我不知道.
我试图通过编写一个例子回答这个问题,但无法弄明白.如何通过代码证明?
注意:我意识到示例2是更好的样式,因为myClass在for循环之外是未知的,并且它的范围保持最小.我也在这里搜索过,但是没有找到这个确切问题的确定答案(通常这是一个"哪个是首选的?"的问题.)我还假设如果每次迭代都创建了myClass引用,那么它不是一个大的表现问题.
编辑:再说一遍,我不是问哪种编码风格更好.此外,我想知道它是否可以通过代码推断/证明.我试图生成并比较字节码,但我不熟悉字节码,生成的内容不完全匹配.
声明变量时,不要"创建"任何内容.变量只是一个方便的名称,可以帮助您记住放置结果的位置,并允许您控制结果的使用位置,并将某些类型信息与该结果相关联; 但是一旦编译完代码,它们就不再存在了.
比较字节码(*):
void outside(int i, List<?> list) {
Object obj;
for (i = 0; i < list.size(); i++) {
obj = list.get(i);
}
}
void inside(int i, List<?> list) {
for (i = 0; i < list.size(); i++) {
Object obj = list.get(i);
}
}
Run Code Online (Sandbox Code Playgroud)
反编译为:
void outside(int, java.util.List<?>);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: aload_2
4: invokeinterface #2, 1 // InterfaceMethod java/util/List.size:()I
9: if_icmpge 26
12: aload_2
13: iload_1
14: invokeinterface #3, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
19: astore_3
20: iinc 1, 1
23: goto 2
26: return
void inside(int, java.util.List<?>);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: aload_2
4: invokeinterface #2, 1 // InterfaceMethod java/util/List.size:()I
9: if_icmpge 26
12: aload_2
13: iload_1
14: invokeinterface #3, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
19: astore_3
20: iinc 1, 1
23: goto 2
26: return
Run Code Online (Sandbox Code Playgroud)
两者是相同的.使用最易读的.
(*)我已经将循环变量声明i为参数,以避免由于在Object之前或之后声明而导致的生成字节码的任何差异i.这对字节码的唯一区别在于aload_N/ iload_N/ astore_N/ istore_N指令 - N因为变量存储在不同的"槽"中,所以它们是不同的.这不是一个显着的差异.
| 归档时间: |
|
| 查看次数: |
109 次 |
| 最近记录: |