This is the standard pattern of the for-each loop.
When you write
for(Type variable: expression) {
// body
}
the expression
will be evaluated exactly once at the beginning of the loop and the resulting collection or array reference is remembered throughout the loop. This also implies, that if expression
is a variable and this variable is assigned within the loop body, it has no effect on the ongoing loop.
The relevant part of the specification says:
…
Otherwise, the Expression necessarily has an array type, T[]
.
Let L1
... Lm
be the (possibly empty) sequence of labels immediately preceding the enhanced for
statement.
The enhanced for
statement is equivalent to a basic for
statement of the form:
T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) {
{VariableModifier} TargetType Identifier = #a[#i];
Statement
}
#a
and #i
are automatically generated identifiers that are distinct from any other identifiers (automatically generated or otherwise) that are in scope at the point where the enhanced for
statement occurs.
TargetType is the declared type of the local variable in the header of the enhanced for
statement.
If you compare the decompiled version
public static int hashCode(byte[] value) {
int h = 0;
byte[] var2 = value;
int var3 = value.length;
for(int var4 = 0; var4 < var3; ++var4) {
byte v = var2[var4];
h = 31 * h + (v & 255);
}
return h;
}
with the actual source code
public static int hashCode(byte[] value) {
int h = 0;
for (byte v : value) {
h = 31 * h + (v & 0xff);
}
return h;
}
you will recognize the translation. var2
, var3
, and var4
are all synthetic variables. Things to note:
- In principle, a compiler could analyze the scenario to recognize that
value
is a local variable which is not assigned in the loop body, so no additional variable would be needed here. But the savings compared to following the standard translation strategy have not been considered worth implementing the additional logic.
- Likewise, it’s the compilers decision whether to remember the invariant array size in another local variable. As shown above, the specification does not mandate it.
You could say that it is a weakness of the decompiler not to recognize the for-each loop and translate it back, however, there’s generally an ambiguity when trying to map compiled code to source code constructs, as a lot of variants exist to produce the same code.