在String 类中trim()方法 有这么一段代码:
Public String trim(){
intlen=value.length;
intst=0;
char[] val = value;/*avoid getfield opcode*/
while((st<len)&&(val[st]<='')){
st++;
}
while((st<len)&&(val[len-1]<='')){
len--;
}
return((st>0)||(len<value.length))?substring(st,len):this;
}
我们看带有注释的一行:
char[] val = value;/*avoid getfield opcode*/
这行有什么意义呢, 直接使用value 不行吗? (value是final的)
下面我们通过opcode层面来看这个问题。
写一个测试类:
public class GetfeildTest{
final char[] value=newchar[0];
public String test1(){
int len=value.length;
int st=0;
char[]val=value;/*avoidgetfieldopcode*/
while((st<len)&&(val[st]<='')){
st++;
}
while((st<len)&&(val[len-1]<='')){
len--;
}
return "test1";
}
public Stringtest2(){
int len =value.length;
int st=0;
//char[]val=value;/*avoid get field opcode*/
while((st<len)&&(value[st]<='')){
st++;
}
while((st<len)&&(value[len-1]<='')){
len--;
}
return "test2";
}
}
可以看到 test1 是String中trim的方式,而test2在while直接使用了value字段。
使用javap -c命令查看操作码:
publicjava.lang.String test1();
Code:
0: aload_0
1: getfield #2 // Field value:[C
4: arraylength
5: istore_1
6: iconst_0
7: istore_2
8: aload_0
9: getfield #2 // Field value:[C
12: astore_3
13: iload_2
14: iload_1
15: if_icmpge 32
18: aload_3
19: iload_2
20: caload
21: bipush 32
23: if_icmpgt 32
26: iinc 2, 1
29: goto 13
32: iload_2
33: iload_1
34: if_icmpge 53
37: aload_3
38: iload_1
39: iconst_1
40: isub
41: caload
42: bipush 32
44: if_icmpgt 53
47: iinc 1, -1
50: goto 32
53: ldc #3 // String test1
55: areturn
publicjava.lang.String test2();
Code:
0: aload_0
1: getfield #2 // Field value:[C
4: arraylength
5: istore_1
6: iconst_0
7: istore_2
8: iload_2
9: iload_1
10: if_icmpge 30
13: aload_0
14: getfield #2 // Field value:[C
17: iload_2
18: caload
19: bipush 32
21: if_icmpgt 30
24: iinc 2, 1
27: goto 8
30: iload_2
31: iload_1
32: if_icmpge 54
35: aload_0
36: getfield #2 // Field value:[C
39: iload_1
40: iconst_1
41: isub
42: caload
43: bipush 32
45: if_icmpgt 54
48: iinc 1, -1
51: goto 30
54: ldc #4 // String test2
56: areturn
我们重点看下第一个goto操作所在行:
Test1中
29: goto 13
13: iload_2
14: iload_1
…
这个循环里是一些load push和条件判断。
而test2 中
27: goto 8
8: iload_2
9: iload_1
10: if_icmpge 30
13: aload_0
14: getfield #2 // Field value:[C
17: iload_2
…
可以看到这里出现了一个
14: getfield #2 // Field value:[C
getfield操作是一个访问类变量的操作
也就是说如果使用test2 的方式,在while里的每次都会有一个getfield操作,而test1则不会。
通过局部变量的方式,可以避免 getfield 操作,如果value不是一个数组,这其实不会有什么影响。但是如果value数组的长度很大,像String这种可能有超长字符串,就可能会出现一定的性能差异。