I took a look at the bytecode, as @user noted, this is probably an optimization to avoid getting getfield in a loop. But they got messed up and still refer to the value variable in the loop state ... so this actually makes the bytecode longer and slower.
public int h1() { 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; } public int h2() { int h = hash; if (h == 0 && value.length > 0) { for (int i = 0; i < value.length; i++) { h = 31 * h + value[i]; } hash = h; } return h; }
We see that both methods produce almost identical bytecode, however, our βoptimizedβ implementation actually ends up using two more calls.
Notice how the for loop test (lines 39-45 in h1 and lines 37-43 in h2) calls getfield to call the length of the array.
Bytecode:
public int h1(); Code: 0: aload_0 1: getfield #17
If they changed the loop condition to also use the local field,
... for (int i = 0; i < val.length; i++) { ...
Then the bytecode actually gets shorter and loses, possibly, a slower getfield call in the loop,
public int h1(); Code: 0: aload_0 1: getfield #17
Performing a silent simple cycle test over a method several million times on my jdk 1.7.0_79, it consistently shows that the original method funny takes about 5 times longer to run , then either not optimized or properly optimized methods. The last 2 are not have differences in performance.
So, I assume that preserving the local field was an attempt to optimize the bytecode methods, probably before jit could optimize it themselves, but they messed it up and actually made the method much worse ...
This code is actually fixed in Java 9 per, https://bugs.openjdk.java.net/browse/JDK-8058643