Рассмотрим эти два метода:Как декомпиляторы Java распознают цикл for из цикла while?
public static void forLoop(int start, int limit) {
for (int i = start; i < limit; i++) {
}
}
public static void whileLoop(int start, int limit) {
int i = start;
while (i < limit) {
i++;
}
}
При компиляции, они производят байткод (это подробный вывод javap
):
public static void forLoop(int, int);
descriptor: (II)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=2
0: iload_0
1: istore_2
2: iload_2
3: iload_1
4: if_icmpge 13
7: iinc 2, 1
10: goto 2
13: return
LineNumberTable:
line 6: 0
line 9: 13
LocalVariableTable:
Start Length Slot Name Signature
2 11 2 i I
0 14 0 start I
0 14 1 limit I
public static void whileLoop(int, int);
descriptor: (II)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=2
0: iload_0
1: istore_2
2: iload_2
3: iload_1
4: if_icmpge 13
7: iinc 2, 1
10: goto 2
13: return
LineNumberTable:
line 12: 0
line 13: 2
line 14: 7
line 16: 13
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 start I
0 14 1 limit I
2 12 2 i I
Как вы можете видеть, раздел кода для обоих из них методы точно то же самое. Однако, когда я декомпилировать этот класс, используя JD, он правильно производит:
public static void forLoop(int start, int limit) {
for (int i = start; i < limit; i++) {}
}
public static void whileLoop(int start, int limit)
{
int i = start;
while (i < limit) {
i++;
}
}
Как это было в состоянии сделать это? Байт-код этих методов точно такой же! Несмотря на то, что атрибуты были разными для каждого метода, я с неохотой полагаю, что это причина, поскольку это не обязательные атрибуты для атрибута Code
метода, который должен содержать (за section 4.7 of The Java Language Specification, Java SE 8 Edition).
Почему скомпилированный код должен знать локальную область переменных? – shmosel
Я не думаю, что это нужно *, но это, безусловно, помогает при отладке. Я предполагаю, что это единственная причина, по которой это происходит. Вероятно, есть инструменты, которые могут удалить его. –
Я предполагаю, что он помогает более эффективно использовать локальный список переменных. Например, если локальная переменная, хранящаяся в индексе 2, выходит из области видимости, компилятор знает, что он может повторно использовать индекс 2 для другой локальной переменной. Если индексы не были повторно использованы, «максимальные локали» для каждого метода были бы эквивалентны количеству локальных переменных, объявленных в методе, * не * максимальное количество локальных переменных, видимых в определенной области внутри метода. –