Я думаю, что сначала мы должны обсудить разницу между выполнением интерпретируемой рабочей среды и временем выполнения machinecode и временем выполнения байт-кода.
В интерпретируемой рабочей среде исходный код (обычно читаемый человеком) преобразуется в машинный код интерпретатором только в момент, когда выполняется код. Как правило, это дает преимущества, такие, что код не зависит от платформы (до тех пор, пока для вашей платформы существует интерпретатор) и простота отладки (код прямо там перед вами), но за счет относительно медленной скорости выполнения, поскольку у вас есть накладные расходы преобразования исходного кода в машинный код при запуске программы.
В скомпилированной среде исполнения исходный код был скомпилирован в собственный машинный код заранее выделенным компилятором. Это дает быструю скорость выполнения (потому что код уже в формате, ожидаемом процессором), но означает, что вещь, которую вы распространяете (скомпилированный двоичный файл), обычно привязывается к данной платформе.
Время исполнения bytecode - это своего рода дом на полпути, целью которого является предоставление преимуществ как интпретации, так и компиляции. В этом случае исходный код доводится до промежуточного формата (байт-кода) досрочно, а затем преобразуется в машинный код во время выполнения. Байт-код предназначен для удобства работы с машинами, а не для человека, что означает, что гораздо быстрее конвертировать в машинный код, чем на традиционно интерпретируемый язык. Кроме того, поскольку фактическое преобразование в машинный код выполняется во время выполнения, вы все равно получаете всю эту хорошую независимость от платформы.
Обратите внимание, что выбор того, следует ли инетретировать или компилировать, не зависит от используемого языка: например, в теории нет оснований, почему у вас не может быть c intepreter или компилировать python непосредственно в машинный код. Конечно, на практике большинство языков обычно компилируются или интерпретируются.
Итак, это возвращает нас к вопросу о том, что делает компилятор Java - по сути, это основная задача - превратить все ваши приятные человекообразные java-файлы в java-байт-код (файлы классов), чтобы JVM мог эффективно их выполнять.
Основная задача JVM, с другой стороны, состоит в том, чтобы взять эти файлы классов и превратить их в машинный код во время выполнения. Конечно, он также выполняет другие функции (например, он управляет вашей памятью и предоставляет различные стандартные библиотеки), но с точки зрения вашего вопроса это важно для преобразования в машинный код!
Основными причинами для этого способа являются (i) переносимость объектного кода и (ii) таким образом вам нужен только один компилятор и * N * JVM, а не * N * компиляторы. – EJP
Настройка среды сборки сложна и требует много времени. Более крупный проект может занять несколько минут для создания (включая javadoc). Вы не хотите делать это каждый раз, когда запускаете программу. –
В Java есть компиляторы, которые генерируют машинный код (Excelsior JET). Однако Java выигрывает от динамического усложнения, оптимизируя на основе того, как код фактически используется и может быть намного быстрее, чем AOT. –