说,我已经使用常量来为数组分配空间。
后来,当我使用for循环访问数组中的每个位置时,是否应该使用数组的.length值或声明期间使用的常量值来寻址测试部分?
换句话说,
for (int i = 0; i < array.length; i++)
或
for (int i = 0; i < constantArraySize; i++)
哪一个更好?
答案 0 :(得分:4)
考虑到性能,没有一个应该优于另一个。两者都应该在缓存中。
考虑到可读性,您应该使用array.length
来明确您想要遍历数组。所以我会选择第一个替代方案。
答案 1 :(得分:0)
我认为你最好的选择是foreach:
for (Item item : array) {
// Do stuff
}
编译器会为您优化它,并且更容易阅读。万岁!
优化,你说?确实。通常它不会有所作为,但如果它更容易阅读和更快,为什么不这样做呢?
考虑这个课程:
final int SIZE = 3;
final String[] a = new String[SIZE];
void doStuff(String s){}
void useLength(){
for (int i = 0; i < a.length; i++) {
doStuff(a[i]);
}
}
void useConstant(){
for (int i = 0; i < SIZE; i++) {
doStuff(a[i]);
}
}
void useForEach(){
for (String s : a) {
doStuff(s);
}
}
反编译,我们得到这段代码:
void useLength();
Code:
0: iconst_0
1: istore_1
2: iload_1
3: aload_0
4: getfield #4 // Field a:[Ljava/lang/String;
7: arraylength
8: if_icmpge 27
11: aload_0
12: aload_0
13: getfield #4 // Field a:[Ljava/lang/String;
16: iload_1
17: aaload
18: invokevirtual #5 // Method doStuff:(Ljava/lang/String;)V
21: iinc 1, 1
24: goto 2
27: return
因此,如果数组是字段,则使用length
将每次迭代加载字段两次。如果该字段引起刷新(例如,如果它是易失性的,或者JIT处于不良情绪中等),则这可以产生差异。如果通过并发线程访问封闭对象(该数组可以在操作7和17之间更改),它也不是线程安全的。
void useConstant();
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_3
4: if_icmpge 23
7: aload_0
8: aload_0
9: getfield #4 // Field a:[Ljava/lang/String;
12: iload_1
13: aaload
14: invokevirtual #5 // Method doStuff:(Ljava/lang/String;)V
17: iinc 1, 1
20: goto 2
23: return
每次迭代只进行一次字段访问,但如果星星是正确的,它仍然会花费我们。如果字段更改值,它也会有相当未指定的行为。
Foreach做的事情略有不同:
void useForEach();
Code:
0: aload_0
1: getfield #4 // Field a:[Ljava/lang/String;
4: astore_1
5: aload_1
6: arraylength
7: istore_2
8: iconst_0
9: istore_3
10: iload_3
11: iload_2
12: if_icmpge 32
15: aload_1
16: iload_3
17: aaload
18: astore 4
20: aload_0
21: aload 4
23: invokevirtual #5 // Method doStuff:(Ljava/lang/String;)V
26: iinc 3, 1
29: goto 10
32: return
只有一个字段访问,一个数组长度检查!它大致相当于:
void useForEach(){
String[] localArr = arr;
for (int i = 0, length = arr.length; i < length; i++) {
doStuff(localArr[i]);
}
}
答案 2 :(得分:0)
由于数组是大小固定的,因此使用哪一个并不重要。除非你修改了数组的引用。让我们看看这个例子:
public class Test
{
final int SIZE = 3;
int[] arr;
public Test()
{
arr = new int[SIZE];
print();
arr = new int[SIZE - 1]; // modify
print();
}
public void print()
{
for (int i = 0; i < SIZE; i++) {
System.out.println(arr[i]);
}
}
public static void main(String[] args)
{
Test t = new Test();
}
}
<强>输出:强>
0
0
0
0
0
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
at testpackage.Test.print(Test.java:19)
at testpackage.Test.<init>(Test.java:13)
at testpackage.Test.main(Test.java:25)
您将收到异常,因为您已将对较小尺寸的数组的引用更改为。如果您使用arr.length
,则不会出现此问题。除非您确定不会修改arr
的引用,否则可以使用常量。
答案 3 :(得分:0)
由于数组是不可变的(我的意思是它的长度不能改变),从功能的角度来看这无关紧要。
从性能的角度来看,对本地变量和array.length
的访问也是相同的。
例如,如果你有几个相同长度的数组,或者你有任何其他原因使用array.length
在特定上下文中的可读性低于使用特殊变量,那么这可能很重要。
答案 4 :(得分:0)
以上两种方法无关紧要。
但如果有任何计算,
<强> e.g 强>
for(int i=0;i< (j*10+10);i++)
{
}
您应该将该计算保存到变量中,并在条件
中使用它像
int temp=j*10+10;
for(int i=0;i<temp;i++)
{
}
进行代码优化。