Подтвердить что ты не робот

Как Java знает, куда прыгать при выходе из цикла?

while (condition) {

    if (condition) {
        statement1;
        statement2;

        break;
    } else {
        statement3;
        statement4;
    }

}

Используя break в предложении if, мы гарантируем, что цикл остановлен и вышел.

Я не понимаю, как оператор break "знает", что он находится в цикле для его выхода изначально или как он "знает", куда перейти. Как это происходит?

4b9b3361

Ответ 1

Я не понимаю, как оператор break "знает", что он находится в цикле для его выхода изначально.

Оператор break не знает, что он находится в операторе switch или цикла. Компилятор проверяет, что оператор break находится в операторе switch или цикла. Если он встречает оператор break, который не входит в оператор цикла, он выдаст ошибку времени компиляции.

Если инструкция switch, while, do или for в непосредственном вложении метода, конструктор или инициализатор содержит оператор break, возникает ошибка времени компиляции.

Если компилятор может проверить, что оператор break находится в операторе switch или цикла, он затем выдаст инструкции JVM для внезапного перехода в первый оператор сразу после ближайшего замкнутого цикла.

Таким образом:

for(int i = 0; i < 10; i++) {
    if(i % 2 == 0) {
         break;
    }
}

будет переведен компилятором в:

0:  iconst_0        # push integer 0 onto stack
1:  istore_1        # store top of stack in local 1 as integer                  
                    # i = 0
2:  iload_1         # push integer in local 1 onto stack
3:  bipush 10       # push integer 10 onto stack
5:  if_icmpge 23    # pop and compare top two (as integers), jump if first >= second
                    # if i >= 10, end for
8:  iload_1         # push integer in local 1 onto stack
9:  iconst_2        # push integer 2 onto stack
10: irem            # pop top two and computes first % second and pushes result
                    # i % 2
11: ifne 17         # pop top (as integer) and jump if not zero to 17
                    # if(i % 2 == 0) 
14: goto 23         # this is the break statement
17: iinc 1, 1       # increment local 1 by 1
                    # i++
20: goto 2          # go to top of loop
                    # loop
23: return          # end of loop body

Ответ 2

break не является вашей стандартной функцией. Это ключевое слово, используемое компилятором Java. Когда он увидит это, он будет вставлять инструкцию байт-кода для перехода непосредственно за пределы цикла после него. Это простой байт-код goto, как показано в ответе Джейсона.

Аналогично, ключевое слово continue эффективно перескакивает в начало цикла 1.

return делает это из функционального блока, хотя и имеет несколько отличий, поскольку может потребоваться перенос значения или ссылки, указывающей на кучу.


1 - На самом деле это немного сложнее, чем это. Вероятно, лучшая простая, но точная "модель", которая работает для всех циклов Java, заключается в том, что continue эквивалентно прыжку в воображаемую пустую инструкцию в конце тела цикла.

Ответ 3

Я не понимаю, как оператор break "знает", что он находится в цикле для его выхода изначально.

Компилятор превращает вашу программу в дерево разбора. Все в дереве разбора имеет родительский элемент, кроме корня. Оператор break должен иметь родительский цикл где-то вверх по дереву (или, конечно же, родительский оператор switch).

Ответ 4

Если вы когда-либо взглянули на сборку или байт-код Java, это будет иметь больше смысла. На более низком уровне ваша программа скомпилирована в "байт-код", который использует регистры, адреса и т.д. Простой оператор if может быть переведен на следующее:

3: if_icmpeq 5
4: goto 10
5: iconst_1
6: iload_1
7: iconst_2
8: iload_2
9: if_icmpeq 10
10: // end of if-else statement

Это может быть (очень плохо) байт-код для:

if ( x == y )
  if ( 1 == 2 )

По сути, на более низком уровне вы используете метки/номера строк и gotos для перехода по коду. Таким образом, break по существу означает, goto последняя строка оператора if или цикла.

Ответ 5

Оператор break имеет две формы: с меткой и без метки.

Вы можете использовать немеченный разрыв для завершения for, while, or do-while loop.

Оператор без метки завершает innermost switch, for, while, or do-while statement, но labeled break terminates an outer statement.

   search:
        for (i = 0; i < arrayOfInts.length; i++) {
            for (j = 0; j < arrayOfInts[i].length;
                 j++) {
                if (arrayOfInts[i][j] == 5) {
                    foundIt = true;
                    break search;
                }
            }
        }

Надеюсь, это поможет.