使用局部变量来保存全局变量的目的是什么?



我查看了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是全局变量,表示字符串的字符数。

为什么局部变量len在这里用于循环条件,而不是全局变量本身?因为没有对变量进行操作,只有读取。如果使用全局字段进行读取或写入,那么使用局部变量是否是良好的实践?如果答案是肯定的,为什么阅读也是如此呢?

在String类中,我发现了一个关于String.trim()方法中对局部变量的奇怪赋值的注释,读为"avoid getfield opcode"

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优化器可能会优化循环,但也可能不会,因此开发人员可能会选择手动执行的安全路径。

有一个关于避免getfield操作码的单独问题,它有详细信息

访问局部变量列表比访问实例变量更快。新的Java 8代码(参见Anubians的回答)也考虑到了这一点。这就是为什么它们使用局部变量h进行哈希计算,而不直接访问实例变量this.hash并创建局部指针char val[] = value;的原因。但是考虑到这一点,我不知道为什么他们不在for循环中使用i < val.length;或者更好的z = val.length; i < z;,而是使用i < value.length;

如果count可以修改,那么您需要一个局部变量。如果您正在进行多线程,那么您需要一个局部变量。创建一个局部变量是最安全的。然而,这并不是绝对必要的。

在这种情况下,这是多余的,因为字符串无论如何都是不可变的。count的值甚至不能改变

它没什么用,这就是为什么在Java 8中它看起来像这样:

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;
        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

他们甚至不再有count了,他们使用value.length,其中value是一个final char数组。

他们正在做char val[] = value,但这只是一个参考,严格来说是不必要的。

通过使用局部变量可能会有一些微妙的微增强,或者可能是为了可读性而做的,但这是不必要的(在我看来可读性较差)。

相关内容

  • 没有找到相关文章

最新更新