我看了一下
String.hashcode()方法的源代码.这是6-b14的实施,已经改变了.
public int hashCode() { int h = hash; if (h == 0) { int off = offset; char val[] = value; int len = count; for (int i = 0; i < len; i++) { h = 31*h + val[off++]; } hash = h; } return h; }
我的问题是关于这一行:
int len = count;
其中count是表示String字符数的全局变量.
为什么局部变量len在这里用于循环条件而不是全局变量本身?因为没有操纵变量,只能阅读.如果使用全局字段来读取或写入本地变量,那么使用局部变量是一种好习惯吗?如果答案是肯定的,为什么阅读?
解决方法
在String类中查找我发现了关于
String.trim()方法中对于避免getfield操作码的局部变量的奇怪赋值的注释.
public String trim() { int len = value.length; int st = 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; }
所以整个事情似乎与性能有关,正如Frank Olschewski所指出的那样.
在Java字节码中,实例变量实际上由对象和名称引用(使用GETFIELD指令).如果没有优化,VM必须做更多工作才能访问变量.
因此,代码的潜在性能损失是它在每次通过循环时使用相对昂贵的GETFIELD指令.该方法中的局部赋值在每次循环时都不需要GETFIELD.
JIT优化器可能会优化循环,但也可能没有,因此开发人员可能会采取安全路径手动强制执行它.
Avoiding getfield opcode还有一个单独的问题,其中有详细信息.