ОК, я знаю это: мы пишем исходный код Java, компилятор, который не зависит от платформы, переводит его в байт-код,
На самом деле сам компилятор работает как собственный исполняемый файл (отсюда и javac.exe). И правда, он преобразует исходный файл в байт-код. Байт-код не зависит от платформы, поскольку он нацелен на виртуальную машину Java.
затем jvm, который зависит от платформы, переводит его в машинный код.
Не всегда. Что касается JVM от Sun, то здесь есть два jvms: клиент и сервер. Они оба могут, но не обязательно должны компилироваться в нативный код.
Итак, с самого начала мы пишем исходный код Java. Компилятор javac.exe представляет собой файл .exe. Что именно это файл .exe? Разве Java-компилятор не написан на Java, тогда как получается .exe-файл, который его выполняет?
Этот exe
файл представляет собой упакованный байт-код Java. Это для удобства - чтобы избежать сложных пакетных скриптов. Он запускает JVM и запускает компилятор.
Если код компилятора написан на java, то почему код компилятора выполняется на этапе компиляции, так как его задача jvm - выполнять код java.
Это именно то, что делает код переноса.
Как сам язык может компилировать свой собственный код языка? Мне кажется, что это проблема с курицей и яйцом.
Правда, сбивает с толку на первый взгляд. Хотя это не только идиома Java. Компилятор Ады также написан на самой Аде. Это может выглядеть как «проблема с курицей и яйцом», но на самом деле это только проблема начальной загрузки.
Теперь, что именно содержит файл .class? Это абстрактное синтаксическое дерево в текстовой форме, табличная информация, что это?
Это не абстрактное синтаксическое дерево. AST используется токенизатором и компилятором только во время компиляции для представления кода в памяти. Файл .class
похож на сборку, но для JVM. JVM, в свою очередь, является абстрактной машиной, которая может работать на специализированном машинном языке - ориентированной только на виртуальную машину. В простейшем случае, .class
файл имеет структуру, очень похожую на обычную сборку. Сначала объявляются все статические переменные, затем идут несколько таблиц сигнатур внешних функций и, наконец, машинный код.
Если вам действительно любопытно, вы можете покопаться в файле классов, используя утилиту "javap". Вот примерный (запутанный) результат вызова javap -c Main
:
0: new #2; //class SomeObject
3: dup
4: invokespecial #3; //Method SomeObject."<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #4; //Method SomeObject.doSomething:()V
12: return
Итак, вы должны уже иметь представление о том, что это на самом деле.
Кто-нибудь может рассказать мне ясный и подробный способ преобразования моего исходного кода Java в машинный код.
Я думаю, что сейчас это должно быть более понятно, но вот краткое резюме:
Вы вызываете javac
, указывая на файл исходного кода. Внутренний ридер (или токенизатор) javac считывает ваш файл и создает из него реальный AST. Все синтаксические ошибки происходят с этой стадии.
javac
еще не закончил свою работу. Когда у него есть AST, может начаться истинная компиляция. Он использует шаблон посетителя для обхода AST и разрешает внешние зависимости, чтобы добавить смысл (семантику) в код. Готовый продукт сохраняется в виде .class
файла, содержащего байт-код.
Теперь пришло время запустить вещь. Вы вызываете java
с именем .classfile. Теперь JVM запускается снова, но интерпретирует Ваш код. JVM может или не может скомпилировать Ваш абстрактный байт-код в собственную сборку. Компилятор Sun HotSpot в сочетании с компиляцией Just In Time может сделать это при необходимости. Выполняемый код постоянно профилируется JVM и перекомпилируется в собственный код, если соблюдаются определенные правила. Чаще всего код hot компилируется первым.
Edit: без javac
нужно было бы вызвать компилятор, используя что-то похожее на это:
%JDK_HOME%/bin/java.exe -cp:myclasspath com.sun.tools.javac.Main fileToCompile
Как вы можете видеть, он вызывает частный API Sun, поэтому он связан с реализацией Sun JDK.Это сделало бы системы сборки зависимыми от него.Если кто-то переключился на любой другой JDK (вики-списки 5, кроме Sun), приведенный выше код следует обновить, чтобы отразить это изменение (поскольку маловероятно, что компилятор будет находиться в пакете com.sun.tools.javac).Другие компиляторы могут быть написаны на нативном коде.
Поэтому стандартным способом является поставка javac
оболочки с JDK.