Ответ
Компиляция Java-кода в платформо-независимый байт-код выполняется компилятором javac. Это многоэтапный процесс:
Основные этапы работы javac:
-
Лексический анализ (Lexical Analysis): Исходный код разбивается на лексемы (токены) — ключевые слова, идентификаторы, операторы, литералы.
int x = 10 + y;→[int, x, =, 10, +, y, ;]
-
Синтаксический анализ (Parsing): Токены преобразуются в Абстрактное Синтаксическое Дерево (AST), отражающее грамматическую структуру программы.
(Statement (VariableDeclaration (Type: int) (Identifier: x) (Expression (10 + y)))) -
Семантический анализ: Проверка корректности программы с точки зрения языка:
- Проверка типов (Type Checking).
- Разрешение символов (нахождение объявлений переменных, методов).
- Проверка доступности (например, private-методов).
-
Генерация промежуточного кода и оптимизация: AST преобразуется в промежуточное представление. Выполняются простые оптимизации (например, свертка констант
10 + 5→15). -
Генерация байт-кода: Финальный этап — создание
.classфайла, содержащего байт-код для JVM.
Структура .class файла (кратко):
- Магическое число (0xCAFEBABE) — идентификатор формата.
- Версии класса (для JVM).
- Constant Pool — таблица констант (строки, имена классов, методы).
- Код методов — непосредственно байт-код в мнемониках JVM.
- Прочая метаинформация.
Пример: Исходный код:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, JVM!");
}
}
Часть байт-кода метода main (показан в мнемонике):
getstatic java/lang/System.out:Ljava/io/PrintStream; // Взять статическое поле `out`
ldc "Hello, JVM!" // Загрузить строку из пула констант
invokevirtual java/io/PrintStream.println:(Ljava/lang/String;)V // Вызвать метод
return // Вернуть управление
Итог: javac переводит высокоуровневый Java-код в низкоуровневые, но не машинные, инструкции для виртуальной машины (JVM), которая затем интерпретирует или JIT-компилирует их в машинный код.