Какая команда используется для запуска процесса компиляции исходного файла в байт-код

Обновлено: 04.07.2024

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

Два основных этапа объясняются ниже:

Принцип 1. Компиляция

Сначала исходный файл .java проходит через компилятор, который затем кодирует исходный код в машинно-независимую кодировку, известную как байт-код. Содержимое каждого класса, содержащегося в исходном файле, хранится в отдельном файле «.class». При преобразовании исходного кода в байт-код компилятор выполняет следующие шаги:

Шаг 1. Анализ. Считывает набор исходных файлов *.java и сопоставляет полученную последовательность токенов с узлами AST (абстрактного синтаксического дерева).

Шаг 2. Ввод. Вводит символы для определений в таблицу символов.

Шаг 3. Обработка аннотаций: по запросу обрабатывает аннотации, найденные в указанных единицах компиляции.

Шаг 4. Атрибут. Атрибуты синтаксических деревьев. Этот шаг включает в себя разрешение имен, проверку типов и свертывание констант.

Шаг 5. Поток. Выполняет анализ потока данных для деревьев из предыдущего шага. Сюда входят проверки назначений и доступности.

Шаг 6. Удаление сахара. Переписывает AST и удаляет часть синтаксического сахара.

Шаг 7. Генерация. Создание файлов .Class.

Принцип 2. Выполнение

Давайте обсудим все 3 этапа.

Этап 1. Загрузчик классов

Основной класс загружается в память, минуя свой файл .class в JVM, путем вызова последней. Все остальные классы, на которые есть ссылки в программе, загружаются через загрузчик классов.
Загрузчик классов, сам являющийся объектом, создает плоское пространство имен тел классов, на которые ссылается строковое имя. Определение метода представлено ниже на иллюстрации следующим образом:

Иллюстрация:

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

  • Переменные инициализируются перед использованием.
  • Вызовы методов соответствуют типам ссылок на объекты.
  • Правила доступа к закрытым данным и методам не нарушаются.
  • Доступ к локальным переменным относится к стеку среды выполнения.
  • Стек времени выполнения не переполняется.
  • Если какая-либо из вышеперечисленных проверок не пройдена, верификатор не разрешает загрузку класса.

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


Процесс может быть хорошо проиллюстрирован следующей диаграммой, приведенной выше, из которой мы пришли к выводу.

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

Реализация:

Представьте себе, что простая программа печати написана где-то в локальном каталоге на машине.

Чтобы сократить или упростить команду javac, вы можете указать один или несколько файлов, которые сами содержат одно имя файла в строке. В командной строке используйте символ '@' с именем файла, чтобы указать его как список файлов. Когда javac встречает аргумент, начинающийся с символа `@', он работает с именами файлов в этом файле, как если бы они были в командной строке.

Например, вы можете перечислить все имена исходных файлов в файле с именем sourcefiles . Этот файл может выглядеть так:

Затем вы можете запустить компилятор с помощью:

ВАРИАНТЫ

Компилятор имеет набор стандартных опций, которые поддерживаются в текущей среде разработки и будут поддерживаться в будущих версиях. Дополнительный набор нестандартных параметров зависит от текущей реализации виртуальной машины и компилятора и может быть изменен в будущем. Нестандартные параметры начинаются с -X.

Стандартные параметры

Параметры кросс-компиляции

Нестандартные параметры

Эти опции поддерживаются только oldjavac. Они не поддерживаются новым компилятором javac.

-X Показать информацию о нестандартных опциях и выйти.

-Xdepend Рекурсивный поиск во всех доступных классах более свежих исходных файлов для перекомпиляции. Этот параметр более надежно обнаружит классы, которые необходимо перекомпилировать, но может значительно замедлить процесс компиляции.

-Xstdout Отправлять сообщения компилятора в System.out . По умолчанию сообщения компилятора отправляются в System.err.

-Xverbosepath Опишите, как выполнялся поиск путей и стандартных расширений для поиска исходных файлов и файлов классов.

Опция -J

И javac, и oldjavac поддерживают параметр -J. -Joption Передать option средству запуска Java, вызываемому javac. Например, -J-Xms48m задает загрузочную память 48 мегабайт. Хотя он не начинается с -X, это не "стандартный вариант" javac. Общепринятым соглашением для -J является передача параметров базовой виртуальной машине, выполняющей приложения, написанные на Java.

Обратите внимание, что CLASSPATH, -classpath, -bootclasspath и -extdirs не определяют классы, используемые для запуска javac. Возиться с реализацией компилятора таким образом обычно бессмысленно и всегда рискованно. Если вам нужно это сделать, используйте параметр -J, чтобы передать параметры базовому средству запуска Java.

ПРИМЕРЫ

Компиляция простой программы

В одном исходном файле, Hello.java, определяется класс с именем Greetings.Hello. Каталог приветствий является каталогом пакета как для исходного файла, так и для файла класса и находится за пределами текущего каталога. Это позволяет нам использовать путь класса пользователя по умолчанию. Это также избавляет от необходимости указывать отдельный каталог назначения с помощью -d.

Компиляция нескольких исходных файлов

Указание пути к классу пользователя

Поскольку Greetings.Hi ссылается на другие классы в пакете Greetings, компилятору необходимо найти эти другие классы. Приведенный выше пример работает, потому что наш путь к пользовательскому классу по умолчанию — это каталог, содержащий каталог пакета. Но предположим, мы хотим перекомпилировать этот файл и не беспокоиться о том, в каком каталоге мы находимся? Затем нам нужно добавить /examples к пути пользовательского класса. Мы можем сделать это, установив CLASSPATH, но здесь мы будем использовать параметр -classpath.

Если мы снова изменим Greetings.Hi, чтобы использовать утилиту баннера, эта утилита также должна быть доступна через путь к пользовательскому классу.

Разделение исходных файлов и файлов классов

Часто имеет смысл хранить исходные файлы и файлы классов в отдельных каталогах, особенно в больших проектах. Мы используем -d для указания отдельного места назначения файла класса. Поскольку исходные файлы не находятся в пути пользовательского класса, мы используем -sourcepath, чтобы помочь компилятору найти их.

Обратите внимание, что компилятор скомпилировал src/farewells/Base.java , хотя мы не указали его в командной строке. Чтобы отслеживать автоматические компиляции, используйте параметр -verbose.

Пример кросс-компиляции

Опция -target 1.1 гарантирует, что созданные файлы классов будут совместимы с виртуальными машинами версии 1.1. В Java 2 SDK javac по умолчанию компилируется для версии 1.1, поэтому этот параметр не является обязательным. Однако это хороший тон, поскольку другие компиляторы могут иметь другие значения по умолчанию.

Java 2 SDK javac также по умолчанию будет компилироваться с собственными классами начальной загрузки, поэтому вместо этого нам нужно указать javac, чтобы он компилировался с классами начальной загрузки JDK 1.1. Мы делаем это с помощью -bootclasspath и -extdirs. Если этого не сделать, может произойти компиляция с API-интерфейсом платформы Java 2, которого нет на виртуальной машине версии 1.1 и произойдет сбой во время выполнения.


В Java программы не компилируются в исполняемые файлы; они компилируются в байт-код (как обсуждалось ранее), который JVM (виртуальная машина Java) затем выполняет во время выполнения. Исходный код Java компилируется в байт-код, когда мы используем компилятор javac. Байт-код сохраняется на диске с расширением файла .class. Когда программа должна быть запущена, байт-код преобразуется с помощью JIT-компилятора. В результате получается машинный код, который затем загружается в память и выполняется.

Для выполнения код Java необходимо скомпилировать дважды:

  1. Программы Java необходимо компилировать в байт-код.
  2. При запуске байт-код необходимо преобразовать в машинный код.

Класс/байт-код Java компилируются в машинный код и загружаются в память JVM при первой необходимости. Это отличается от других языков, таких как C/C++, где программы должны быть скомпилированы в машинный код и связаны для создания исполняемого файла, прежде чем его можно будет выполнить.

Быстрая процедура компиляции [ edit | изменить источник ]

Чтобы выполнить свою первую программу на Java, следуйте приведенным ниже инструкциям:

Если вы получаете другое сообщение, заканчивающееся на 1 ошибку или . errors , в вашем коде может быть ошибка. Вы уверены, что все слова написаны правильно и в точном регистре, как показано?Есть ли точка с запятой и скобки в соответствующем месте? Вам не хватает цитаты? Обычно в этом случае современные IDE пытаются раскрасить весь исходный код как кавычку.

Если ваш компьютер издает звуковые сигналы, возможно, в файле HelloWorld.java есть недопустимые символы.

Если в той же папке не было создано ни одного файла HelloWorld.class, у вас возникла ошибка. Вы правильно запускаете программу javac?

Если вы получаете сообщение об ошибке, например Exception in thread "main" java.lang.NoSuchMethodError: main , возможно, исходный файл написан неправильно.

Автоматическая компиляция зависимых классов [ edit | изменить источник ]

В Java, если вы использовали какую-либо ссылку на любой другой объект Java, класс для этого объекта будет автоматически скомпилирован, если он еще не был скомпилирован. Эти автоматические компиляции являются вложенными, и это продолжается до тех пор, пока не будут скомпилированы все классы, необходимые для запуска программы. Поэтому обычно достаточно скомпилировать только высокоуровневый класс, поскольку все зависимые классы будут скомпилированы автоматически.

Однако вы не можете полагаться на эту функцию, если ваша программа использует отражение для создания объектов или вы компилируете для сервлетов или пакета "jar". В этих случаях вы должны перечислить эти классы для явной компиляции.

Пакеты, подкаталоги и ресурсы [ edit | изменить источник ]

Каждый класс верхнего уровня Java принадлежит пакету (описанному в главе о пакетах). Это может быть объявлено в операторе пакета в начале файла; если он отсутствует, класс принадлежит безымянному пакету.

Для компиляции файл должен находиться в правильной структуре каталогов. Файл, содержащий класс в безымянном пакете, должен находиться в текущем/корневом каталоге; если класс принадлежит пакету, он должен находиться в каталоге с тем же именем, что и пакет.

Согласно соглашению, имена пакетов и имена каталогов, соответствующие пакету, состоят только из букв нижнего регистра.

Пакет верхнего уровня [ редактировать | изменить источник ]

Класс с этим объявлением пакета

должен находиться в каталоге с именем example .

Подпакеты [ редактировать | изменить источник ]

Класс с этим объявлением пакета

должен находиться в каталоге en, ​​который должен быть подкаталогом wikibooks, который, в свою очередь, должен быть подкаталогом org, что приводит к org/wikibooks/en в Linux или org\wikibooks\en в Windows .

Программы Java часто содержат файлы, не относящиеся к коду, например изображения и файлы свойств. Обычно они называются ресурсами и хранятся в каталогах, локальных для классов, в которых они используются. Например, если класс com.example.ExampleApp использует файл icon.jpg, этот файл можно сохранить как /com/example/resources/icon.jpg . Эти ресурсы представляют собой проблему при компиляции программы, поскольку javac не копирует их туда, куда компилируются файлы .class (см. выше); программист должен переместить файлы и каталоги ресурсов.

Регистр имени файла [ ​​edit | изменить источник ]

Имя исходного файла Java должно совпадать с именем общедоступного класса, содержащегося в файле. Для каждого файла может быть определен только один общедоступный класс. Имя класса Java чувствительно к регистру, как и имя исходного файла.

Согласно соглашению об именовании имя класса должно начинаться с заглавной буквы.

Параметры компилятора [ редактировать | изменить источник ]

Отладка и символьная информация [ edit | изменить источник ]

Что нужно сделать:
заполните этот раздел.


Для отладки системных классов Java, таких как String и ArrayList, вам потребуется специальная версия JRE, которая скомпилирована с "отладочной информацией". JRE, входящая в состав JDK, предоставляет эту информацию, а обычная JRE — нет. Обычная JRE не включает эту информацию для повышения производительности.


Символическая информация: Символьное разрешение выполняется во время загрузки класса на этапе разрешения связывания. Это процесс замены символических ссылок из типа прямыми ссылками. Это делается путем поиска в области метода, чтобы найти указанный объект

JIT-компилятор [ редактировать | изменить источник ]

Компилятор Just-In-Time (JIT) — это компилятор, преобразующий байт-код в машинный код. Он компилирует байт-код один раз, а скомпилированный машинный код повторно используется снова и снова для ускорения выполнения. Ранние компиляторы Java компилировали байт-код в машинный код каждый раз, когда он использовался, но более современные компиляторы кэшируют этот машинный код для повторного использования на машине. Даже тогда JIT-компиляция Java была по-прежнему быстрее, чем "язык-интерпретатор", где код компилируется из языка высокого уровня, а не из байт-кода каждый раз, когда он используется.

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

ПРИМЕЧАНИЕ. Эти инструкции предназначены для использования дистрибутива Java (SDK) Sun без интегрированной среды разработки. Если вы используете какой-либо тип Java IDE (например, Eclipse), вам следует просмотреть его документацию для получения информации об использовании его функций редактирования и отладки.

Компиляция исходного кода Java

Прежде чем виртуальная машина Java (VM) сможет запускать программу Java, исходный код Java программы должен быть скомпилирован в байт-код с помощью компилятора javac. Байт-код Java — это независимая от платформы версия машинного кода; целевой машиной является виртуальная машина Java, а не базовая архитектура. Чтобы скомпилировать файл исходного кода Java Foo.java , вы должны сделать следующее: Параметр командной строки -g является необязательным, но мы рекомендуем использовать его, так как он упрощает отладку.

Если в исходном файле нет ошибок, компилятор Java создаст один или несколько файлов .class (один файл .class для каждого класса, определенного в исходном файле Foo.java). Например, результаты успешной компиляции Foo.java создадут версию класса с байт-кодом в файле с именем Foo.class .

Каждый общедоступный класс, который вы пишете, должен находиться в отдельном файле .java, в котором первая часть имени файла совпадает с именем класса. Файл .java может дополнительно содержать код для защищенных и закрытых классов.

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

Запуск приложения Java

После того как вы успешно скомпилировали исходный код Java, вы можете вызвать виртуальную машину Java для запуска байт-кода вашего приложения: например, для запуска основного метода из класса Foo: любые аргументы командной строки (аргументы для Foo 's main метод) следует за именем класса:

Переменная среды CLASSPATH и файлы JAR

Когда виртуальная машина Java запускает вашу программу, она ищет файлы приложения .class, используя пути, указанные в вашей переменной среды CLASSPATH. Чтобы запустить простое Java-приложение, вам не нужно устанавливать переменную среды CLASSPATH; по умолчанию виртуальная машина Java ищет классы в текущем рабочем каталоге. Однако, если ваша программа использует классы, которых нет в текущем рабочем каталоге, вам необходимо явно указать переменную среды CLASSPATH, чтобы вывести список всех каталогов, содержащих классы, используемые этим приложением. Кроме того, если ваша программа использует классы, содержащиеся в файле JAR (Java ARchive), то файл JAR должен быть указан в вашем CLASSPATH. Файл JAR — это отдельный файл, содержащий множество файлов .class.

После первых нескольких недель занятий мы начнем использовать библиотеку JDSL из книги, и вам нужно будет добавить файл JAR этой библиотеки в свой CLASSPATH. В файл .cshrc добавьте следующее: Каждый путь отделяется знаком ' : '. В этом примере для CLASSPATH заданы два каталога: текущий каталог ( ./ ) и файл dsl_general.jar. Если у вас определена переменная среды CLASSPATH, то виртуальная машина использует пути, указанные в переменной среды CLASSPATH, а не поиск по путям по умолчанию. В результате, если вы установите эту переменную среды, вам нужно добавить текущий путь, иначе виртуальная машина не найдет классы в текущем рабочем каталоге.

Отладка кода Java

Скомпилировать с параметром -g. Это заставит компилятор Java поместить информацию о строке исходного кода Java в файлы .class:

Отладка многопоточных Java-приложений

Отладка многопоточных Java-приложений с помощью jdb немного уродлива. Для многопоточных приложений попробуйте уменьшить общее количество потоков приложений до одного или двух, если это возможно. Кроме того, в классе Thread есть несколько методов, помогающих отлаживать многопоточные Java-приложения. Вы можете явно добавить код отладки в свою программу Java, чтобы распечатать информацию о потоках в вашей программе.

Читайте также: