Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions lessons/java-core/035/Compilation and interpretation in Java.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Компиляция и интерпретация в Java

Сегодняшний урок будет ознакомительным. В нем мы поверхностно познакомимся с механизмами JVM, превращающими Java-код в
работающую программу.

**Высокоуровневые языки программирования** (в той или иной степени, сюда можно отнести почти все широко известные языки,
кроме **ассемблера**) обладают высокой степенью абстракции над **машинным кодом** – условно говоря, нулями и единицами,
воспринимаемыми процессором.

Отсюда рождается необходимость в механизме «перевода» программного кода на высокоуровневом языке в то, что будет понятно
условному процессору, который будет исполнять программу. Такой процесс называется **компиляцией**.

Справедливости ради, программы на высокоуровневых языках не превращаются в **бинарный код** напрямую (те самые нули и
единицы), вместо этого они компилируются в эквивалентные программы на языке, понятном конкретному процессору. Таким
языком может выступать ассемблер. Главное, что нужно вынести на текущем этапе – результатом компиляции программы на
условном C++ является программа на не менее условном ассемблере.

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

Итак, мы имеем некий процесс компиляции, который из понятного разработчику кода сделает непонятный разработчику код. Но
во многих языках на этом решили не останавливаться и появился еще один термин – **интерпретация**.

**Интерпретация** – построчный анализ, обработку и выполнение программного кода. В рамках определения не играет роли
язык, на котором написана программа.

Важным отличием компиляции от интерпретации является то, что компиляция обрабатывает весь текст программы целиком,
интерпретация – это всегда про построчную обработку. Второе важное отличие – компиляция не выполняет программу, это лишь
процесс «перевода».

**Интерпретируемые языки программирования** – достаточно обширная тема, нас же интересует интерпретируемость в рамках
Java (в целом, для ряда других языков, вроде Python или Basic, описанное тоже будет, отчасти, верно).

Проблема компилируемых языков в том, что они зависят от конкретного процессора. Как более верхнеуровневая надстройка,
они зависят от операционной системы. Скажем, не любая программа, написанная на C и работающая на Linux, будет работать
на Windows.

Java, в свою очередь, была создана под лозунгом _«Write Once, Run Anywhere»_. Наиболее популярный, хоть и не совсем
корректный русский перевод – _«Написано однажды – работает везде»_. Таким образом, Java гарантирует, что программа,
написанная на Java будет работать одинаково вне зависимости от архитектуры процессора, операционной системы и
политических тенденций. На самом деле, в любом правиле есть свои исключения, но сегодня не об этом.

Как бы там ни было, подход, направленный на универсальность кода привел к рождению **JVM – Java Virtual Machine**,
которая является прослойкой между Java-кодом и всем тем, что влияет на исполнение программы (от операционной системы до
процессора).

По сути, в этом контексте JVM является интерфейсом, который с одной стороны принимает Java-код, с другой – имеет
различные реализации под различные операционные системы, что и позволяет программе иметь одинаковое поведение.

Однако для JVM потребовался некий аналог машинного кода, понятный интерпретатору виртуальной машины. Такой аналог
называется **байткодом**. Байткод не является чем-то характерным только для Java – он существует во многих
интерпретируемых языках.

На данном этапе мы можем описать путь от Java-кода до выполнения программы следующим образом: Java-код компилируется в
байткод, байткод выполняется интерпретатором. Общий термин, объединяющий компиляцию и интерпретацию – **трансляция**.
Его тоже стоит запомнить, ибо в рамках данной темы он частоупотребим.

Безусловно, на практике все немного сложнее, но есть и плюс – Java-разработчику редко приходится даже работать с
настройкой JVM, не говоря о практическом применении информации о более глубоких механизмах, связанных с компиляцией и
интерпретацией. Но кое-что знать, все же стоит.

Предлагаю обратить внимание на данную
[статью](https://javarush.com/groups/posts/2256-kompiljacija-i-ispolnenie-java-prilozheniy-pod-kapotom)

В ней достаточно лаконично пересказывается изложенное выше и немного описываются более низкоуровневые механизмы. Также
она знакомит с компилятором в bytecode – _javac_ и интерпретатором – _java_. Как итог, демонстрирует запуск
Java-программы без помощи IDE.

К сожалению, автор обошел стороной несколько важных моментов, но их постараюсь подсветить я. В подробности вдаваться не
будем, боюсь, тема и так получилась нелегкой.

Продемонстрированная в статье компиляцией одного единственного класса – это хорошо в рамках примера. Но в реальных
условиях все было бы немного сложнее.

Предлагаю обратить внимание на следующую [статью](https://javarush.com/groups/posts/2318-kompiljacija-v-java).
Рекомендую дочитать до раздела _«Создание JAR-файлов»_, с ним и тем, что после – ознакомимся в свое время.

К сожалению, в данной статье примеры компиляции и запуска приводятся только для Windows, но кардинальных отличий для
других ОС не будет.

Кроме того, в рамках первой статьи была упомянута и достаточно неплохо описана, насколько позволял формат, *
*JIT-компиляция** (она также называется **динамической**). Однако в рамках Java такой подход является не единственно
возможным. С Java 9 существует также **AOT – Ahead-of-Time** – компиляция. Она же – **статическая компиляция**. Именно
этот тип компиляции используется в классических **компилируемых языках** (например, C++).

Основная разница заключается в том, что JIT компилирует байткод в машинный код (да, интерпретация тоже подразумевает
компиляцию внутри себя), но поскольку JIT отрабатывает прямо по ходу выполнения программы, это достаточно дорого и
долго, в том числе поэтому приложения на Java (и интерпретируемых языках в целом) работают медленнее, чем приложения,
написанные на компилируемых языках.

В это время AOT компилирует байткод в машинный код заранее. Тем самым делает процесс запуска и работы приложения
быстрее. Как показывает практика, это нужно далеко не всегда, но сам факт наличия такой возможности в Java был
определенным шагом вперед.

Тема JIT и AOT компиляций достаточно сложная и требует определенного уровня экспертизы. В рамках данной статьи она
дается очень поверхностно - по сути, на уровне базовых определений. Но вы можете попытаться разобраться в ней
самостоятельно, если данная тема кажется интересной, поскольку в рамках курса мы нырять в это не будем.

#### На сегодня все!

![img.png](../../../commonmedia/justTheoryFooter.png)

> Если что-то непонятно или не получается – welcome в комменты к посту или в лс:)
>
> Канал: https://t.me/ViamSupervadetVadens
>
> Мой тг: https://t.me/ironicMotherfucker
>
> **Дорогу осилит идущий!**