Goto в байт-коде Java
Итак, на днях, когда я смотрел страницу wikipedia для байт-кода Java, я наткнулся на этот пример:
Рассмотрим следующий код Java:
outer:
for (int i = 2; i < 1000; i++) {
for (int j = 2; j < i; j++) {
if (i % j == 0)
continue outer;
}
System.out.println (i);
}
Компилятор Java может перевести Java-код выше в байтовый код следующим образом, предполагая, что вышеуказанное было помещено в метод:
0: iconst_2
1: istore_1
2: iload_1
3: sipush 1000
6: if_icmpge 44
9: iconst_2
10: istore_2
11: iload_2
12: iload_1
13: if_icmpge 31
16: iload_1
17: iload_2
18: irem
19: ifne 25
22: goto 38
25: iinc 2, 1
28: goto 11
31: getstatic #84; //Field java/lang/System.out:Ljava/io/PrintStream;
34: iload_1
35: invokevirtual #85; //Method java/io/PrintStream.println:(I)V
38: iinc 1, 1
41: goto 2
44: return
И я замечаю, что небольшое слово goto появляется пару раз, что при проверке спецификации JVM действительна. Мой вопрос: почему? GOTO - это зарезервированное, но непригодное для использования ключевое слово в Java, поэтому, когда мы пишем и компилируем Java-код, похоже, он скомпилирован с goto обратно в него. Мне интересно, что это всегда так, как всегда делалось на более низком уровне программирования, или это потому, что JVM доверяет более эффективному использованию слова goto. В конечном счете мне любопытно, почему goto считается такой плохой практикой, что это запрещено в java-коде, но, похоже, он возвращается обратно в ваш код при компиляции.
Ответы
Ответ 1
Функции структурированного программирования Java, такие как циклы (for
/while
), реализуются на уровне байткода с инструкциями условной ветки (IF..
) и безусловного перехода (GOTO
).
break
или continue
во внешний цикл также считаются достаточно полезными и законными в структурированном программировании, что язык Java имеет эти функции (break/continue to label).
На уровне JVM/bytecode они также реализованы с помощью GOTO
.
Смотрите:
Ответ 2
Вы должны различать ключевое слово языка goto
и байтовый код или инструкцию по сборке goto
.
Плохая практика использовать goto
прыжки в высоком уровне кода, например, в C. Поэтому в Java это запрещено.
Оригинальная статья Эдсгера У. Дейкстры о goto.
В скомпилированном коде использование команды безусловного перехода goto
полностью в порядке. Он помещается туда компилятором, и он не забывает о последствиях прыжка вокруг кода, включая инициализацию данных, освобождение памяти и т.д.
Ответ 3
Общая справочная информация:
Аппаратная часть любого микропроцессора знает только, что ей необходимо последовательно выполнять каждую инструкцию, начиная с адреса памяти, - даже не знает, по каким адресам памяти прекратить выполнение инструкций.
Язык ассемблера - очень тонкий преобразователь от "команд" до "двоичных микроинструкций". Список "команд" не включает в себя инструкции потока управления во всем, что у вас есть, инструкции перехода (простые прыжки или условные переходы), что он (хорошо, есть инструкция для безусловных бесконечных циклов и для условных циклов).
Из-за этого операторы потока управления, доступные на более высоких языках, таких как C, реализуются с использованием этих инструкций перехода, поскольку нет другого способа их реализации. Так как это происходит, goto
в C скомпилируется в двоичные команды как простая инструкция безусловного перехода.
Обоснование Java и JVM:
Многие разные аппаратные архитектуры имеют разные стандарты/форматы для "двоичных микроинструкций" и разных наборов инструкций. JVM имеет собственный стандарт и собственный набор инструкций.
Это позволяет компилятору Java всегда выводить одни и те же инструкции независимо от того, на какой аппаратной архитектуре будет выполняться исполняемый файл; это задание JVM для перевода команды из собственного стандарта в текущий стандарт станка.
Итак, по сути, байт-код JVM является "языком ассемблера" для "виртуальной машины Java". Это означает, что у него нет инструкций потока управления. Он имеет безусловные инструкции перехода (которые называются goto
).
break
и continue
на самом низком уровне реализуются как jump
(или goto
). Дело в том, что если вы используете язык более высокого уровня, вы бы хотели избежать использования goto
, даже если он доступен (например, в C), и будет использовать более читаемые структуры управления.
Есть некоторые особые случаи (в C для примера), когда даже программисты, которые уважают все "лучшие методы кодирования", будут использовать goto
, например, реализации coroutine.
Некоторые другие примеры жертвовать стандартами кодирования для лучшей или более надежной производительности - это когда разработчики Kernel имеют специфический для архитектуры код сборки (C позволяет писать инструкции по сборке).
Ответ 4
Bytecode - это своего рода язык ассемблера для виртуальной машины. Очень часто есть инструкции по прыжкам на машинный язык. goto - инструкция безусловного перехода.
Компилятор Java переводит почти все операторы потока управления внутри тела метода в инструкции goto.
Ключевое слово goto, вероятно, было зарезервировано на Java, чтобы сохранить возможность добавить его в более позднюю версию, если бы получилось, что это существо было бы критическим. На самом деле нет ничего плохого в goto с точки зрения машины. У него плохая репутация, потому что он позволяет писать код, который очень трудно читать для человека. Язык Java позволяет использовать break и продолжать использовать метки в качестве замены для goto.
Ответ 5
goto
отлично работает на уровне машины, java-компилятор не пишет код, он только преобразует код из источника java в байт-код.
Для людей, пишущих код, это отличная история, инструкция goto трудно читать и анализировать и код - это беспорядок после многих переходов goto. Вот почему люди должны использовать концепции OO вместо инструкций перехода.
Ответ 6
Вы смотрите на эквивалент JVM машинного кода. Разрешен ли goto
в Java, не имеет значения, разрешено ли это в байт-коде, так же, как указатели не разрешены в байт-коде JVM, но JVM, безусловно, будет компилировать или интерпретировать байт-код в машинный код, который использует указатели.
Ответ 7
bytecode не является Java, программы на других языках, такие как Groovy, могут быть скомпилированы в байт-код, вы можете напрямую писать байт-код, используя некоторые инструменты, такие как BCEL. Что касается goto, вы не можете обойтись без него на низком уровне.
Ответ 8
- SpaceTrucker упомянул (в комментариях к главному вопросу) разницу между самим языком Java и байт-кодом. Ключевое слово
goto
и goto
не являются одинаковыми. Единственное общее название - это имя. В случае байт-кода это всего лишь инструкция JUMP
(JMP
);
- В принципе,
goto
считается плохой практикой в программировании/кодировании из-за реализации кода "spagetti" и ухудшения читаемости кода.
Ответ 9
Готов к операторам программирования - это односторонние операторы, в которых вызовы функций - это двухпозиционный переключатель, возвращающийся обратно в вызываемый раздел кода.
Чтобы использовать эти только байт-коды, используйте goto в них. В случае, если пользователю разрешено использовать средства goto, мы можем использовать его неэффективно (скажем, безусловный оператор goto), который никогда не позволит программе завершить работу.
Jvm является таким интеллектуальным, что никогда не запускает программу бесконечно.