Это стандартный шаблон для каждого l oop.
Когда вы пишете
for(Type variable: expression) {
// body
}
, expression
будет оцениваться ровно один раз в начале l oop, а полученная ссылка на коллекцию или массив запоминается в течение l oop. Это также подразумевает, что если expression
является переменной, и эта переменная присваивается в теле l oop, это не влияет на текущую l oop.
соответствующую часть спецификация гласит:
…
В противном случае Выражение обязательно имеет тип массива, T[]
.
Пусть L1
... Lm
будет (возможно, пустой) последовательностью меток, непосредственно предшествующих расширенному оператору for
.
Расширенный оператор for
эквивалентен основному c for
оператор формы:
T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) {
{VariableModifier} TargetType Identifier = #a[#i];
Statement
}
#a
и #i
- это автоматически генерируемые идентификаторы, которые отличаются от любых других идентификаторов (автоматически генерируемых или иным образом), которые находятся в области действия на точка, в которой происходит расширенный оператор for
.
TargetType - это объявленный тип локальной переменной в заголовке расширенного оператора for
.
Если вы сравните декомпилированную версию sion
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;
}
с фактическим исходным кодом
public static int hashCode(byte[] value) {
int h = 0;
for (byte v : value) {
h = 31 * h + (v & 0xff);
}
return h;
}
вы узнаете перевод. var2
, var3
и var4
являются синтетическими c переменными. Стоит отметить:
- В принципе, компилятор может проанализировать сценарий, чтобы распознать, что
value
является локальной переменной, которая не назначена в теле l oop, поэтому никаких дополнительных переменных не будет нужен здесь. Но экономия по сравнению со стандартной стратегией перевода не считалась целесообразной реализацией дополнительной логики c. - Аналогичным образом, это решение компилятора, стоит ли запоминать размер инвариантного массива в другой локальной переменной. Как показано выше, спецификация не обязывает его.
Можно сказать, что слабым местом декомпилятора является не распознавать для каждого l oop и переводить его обратно, однако есть как правило, неоднозначность при попытке отобразить скомпилированный код в конструкции исходного кода, так как существует множество вариантов для создания одного и того же кода.