Как скомпилировать java в class
Перейти к содержимому

Как скомпилировать java в class

  • автор:

Как из .java сделать .class?

Я декомпилировал плагин в одной игре, изменил в нем пару слов и он стал формата .java. Как мне его скомпилировать обратно в формат .class?

Отслеживать
51.6k 199 199 золотых знаков 59 59 серебряных знаков 242 242 бронзовых знака
задан 4 апр 2019 в 11:57
Over_Ghost Over_Ghost
11 1 1 серебряный знак 2 2 бронзовых знака
4 апр 2019 в 12:07

Не работает( пишу C:\Program Files\Java\jdk-12\bin\Levels.java ) мне пишет error: invalid flag: C:\Program Usage: javac use —help for a list of possible options пишу javac Levels.java и так же

4 апр 2019 в 12:38
Блин, я не знаю как там там у вас в полуконсоле на винде это делать. Попробуйте открыть —help
4 апр 2019 в 12:46

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

java — это файл, в нем может быть написано что угодно.
class — это скомпилированный файл.

Для компиляции используйте IDE. Если нет таковой — установите jdk нужной версии. Затем, если файл у вас один, используйте:

Отслеживать
ответ дан 4 апр 2019 в 12:59
michael_best michael_best
1,541 1 1 золотой знак 9 9 серебряных знаков 22 22 бронзовых знака
javac: file not found: Levels.java Usage: javac use -help for a list of possible options
4 апр 2019 в 13:18
@Over_Ghost Нужно указывать правильный путь до файла, а не просто написать его имя.
4 апр 2019 в 13:23

C:\Users\Admin\Desktop\Levels.java:93: error: package Main does not exist Main.econ.withdrawPlayer((OfflinePlayer)p, 100000.0); ^ C:\Users\Admin\Desktop\Levels.java:95: error: cannot find symbol final PermissionUser pm = PermissionsEx.getUser(p); ^ symbol: class PermissionUser location: class Levels 100 errors Получилось после javac C:\Users\Admin\Desktop\Levels.java До ошибок плевать главное где этот файл сохранился? 😀

Как скомпилировать java-файл из консоли

Компиляция java-программы без проблем работает ровно до того момента, пока не потребуется создать что-то сложнее одного файла в проекте. Когда я попытался использовать два java-файла в разных каталогах, компилятор напрочь отказался работать, выдавая загадочные сообщения вроде «cannot find symbol»: чисто интуитивно я понял, что он просто не видит второй исходный файл.

Что может означать команда import (импорт)? Опять же интуитивно — это какой-то импорт из другого файла, например его подключение. В Java это означает лишь «расширение» области видимости — эдакое namespace, которое призвано исключить конфликт одинаковых имён. Никакого импорта здесь и в помине нет.

Другой пример — что такое package (пакет)? Какой-то пакет — набор модулей, файлов под одним именем, может архив. Ан, нет! В Jave к пакетам это никакого отношения не имеет — это всего лишь каталог. Причём каталог, который указывается в полном имени. Или чтобы его не указывать (частично), нужно задать его в import . О как!

При чём тут компиляция? А при том, что компилятор не шибко умный: чтобы он нормально заработал потребуется указать дополнительные параметры, которые завязаны на каталоги, файлы и классы (читай: «package» и «import»).

Проблемы?

Какие могут возникнуть проблемы? Вот список того, с чем мне пришлось столкнуться.

  • В консоли русские тексты крокозяблами.
  • Если исходные файлы в отдельных каталогах, компилятор их не видит.
  • Компилятор требует строгого соответствия указанным package в исходном коде реальной структуре подкаталогов.
  • Чтобы отделить скомпилированные class-файлы от java-файлов, также требуется указывать дополнительные параметры.
  • Каждый Java-проект имеет свои настройки, поскольку у них разные имена main-классов (его следует указывать при запуске программы на выполнение).

Правила для Java-программ

Первое правило — каждая ява-программа должна находиться в своём каталоге. Какой бы она не была примитивной. Только так можно обеспечить корректную работу компилятора, который сам просто не понимает, где корень проекта. Второе правило — исходые файлы нужно отделять от скомпилированных, иначе образуется страшное мессиво. Третье правило — всегда используется хоть какой-то package, который указывает на «базовый» или «основной» подкаталог в каталоге исходных файлах. Четвёртое правило — все исходные программы пишутся в UTF8 без сигнатуры BOM.

Структура файлов/каталогов

Чтобы было понятно, покажу на примере демо-программы HelloAlpha. Это очень простая программа, которая выводит сообщения из кучи одноименных классов. Я её написал, пытаясь разобраться с тонкостями import и package и возможно вам она окажется тоже полезной. Программа имеет свой каталог проекта, который у меня расположен как d:\android\java\HelloAlpha\ У вас он может находиться в другом месте. Каталог src — это исходные java-файлы с подкаталогами, которые совпадают со структурой package.

Напомню, что в тексте программы каталоги package указываются через точку вместо слэша. Вместо package mypackage/first; указывается package mypackage.first;

Каталог bin используется для размещения скомпилированных class-файлов. Компилятор сам повторит структуру подкаталогов из src. В Notepad++ исходный проект выглядит так: Структура проекта HelloAlpha Структура проекта HelloAlphaФайл compiling_and_run.bat используется для компиляции, а start.bat для запуска уже скомпилированного проекта (ему src не нужен). Файл Alpha.java размещён в разных подкаталогах и представляет собой код, который просто выводит сообщение в консоль. Вот пример mypackage/first/Alpha.java:

package mypackage.first; public class Alpha < public void out(String s)< System.out.println(" mypackage/first/Alpha.java" + " " + s); >>

Вы можете загрузить zip-архив со всеми файлами: HelloAlpha.zip В каждом подкаталоге Alpha.java немного разный: указан свой package и своё сообщение. Оно и используется для исследования (это тема другой статьи). 🙂 После запуска compiling_and_run.bat произойдет компиляция и запуск программы на выполнение.

Компиляция

Теперь подходим к самому интересному — компиляции. Перед тем, как её запускать, в файле compiling_and_run.bat укажите полный каталог проекта.

set DIR_PROJECT=d:\android\java\HelloAlpha\

Если этого не сделать, то запускать bat-файл можно будет только из каталога проекта, но не получится из того же Notepad++. Второй момент — перед компиляцией удаляются все class-файлы из bin-каталога. Это сделано умышлено, поскольку в процессе программирования может быть сделано множество постороних class-файлов, которые компилятор сам не удаляет. Если же эта возможность не требуется, то удалите или закомментируйте строчку

del /s %DIR_BIN%\*.class >NUL

Сейчас bat-файл настроен на HelloAlpha, поэтому после запуска (после указания своего каталога!) вы увидите что-то вроде такого: Выполненная HelloAlphaЕсли возникнет ошибка компиляции, то будет немного другой экран: Ошибка компиляции javaПри этом, запуска на выполнение уже не будет.

Настройка bat-файла

Все настройки я вынес в верх файла compiling_and_run.bat:

set DIR_PROJECT=d:\android\java\HelloAlpha\ set MAIN_PACKAGE_DIR=mypackage set MAIN_PACKAGE=mypackage set MAIN_CLASS=HelloAlpha set DIR_SRC=src set DIR_BIN=bin
  • DIR_PROJECT — каталог проекта. Нужно указать слэш в конце.
  • MAIN_PACKAGE_DIR — «основной» пакет, то есть тот каталог, где размещается файл «запуска». Указывается относительно каталога src.
  • MAIN_PACKAGE — тот же «основной» пакет, но только разделители каталогов «\» указываются точками «.». Такое разделение — требование java.
  • MAIN_CLASS — это собственно то, что является программой. Для запуска java-программ указывается файл без расширения .class.
  • DIR_SRC — каталог исходных файлов. Именно он является «точкой отсчёта» для всех java-файлов.
  • DIR_BIN — в этот каталог складываем готовые файлы. Он может использоваться и для генерации jar-файла.

Разделение на MAIN_PACKAGE_DIR и MAIN_PACKAGE требуется, если у вас «длинный» пакет. Например для org.maxsite.java

set MAIN_PACKAGE_DIR=org\maxsite\java set MAIN_PACKAGE=org.maxsite.java

Файл compiling_and_run.bat я сделал так, чтобы он работал в «правильной» кодировке, а также отслеживал ошибки компиляции. А цветовая дифференциация штанов раскраска немного упрощает отладку.

Учитывайте, что для java регистр файлов и каталогов имеет значение!

Файл start.bat используется для тех случаев, если нужно просто запустить программу без компиляции. Поскольку там одна строчка для Java, то просто укажите свой package и main-класс.

Порядок создания java-проекта

Схема простая: создать каталог проекта, скопировать структуру каталогов и bat-файлы. Поправить в них package и main-класс. Файл compiling_and_run.bat можно вообще переименовать под имя проекта (например HelloAlpha.bat).

Работа в Notepad++ с Java

Уж коли я затронул Notepad++, то покажу как настроить в нём компиляцию. В программе есть меню Запуск: Меню Запуск в Notepad++Здесь нужно выбрать compiling_and_run.bat. Можно нажать Сохранить. и указать название команды и горячую клавишу, например F9 . Сохранение команды запускаЕсли будет конфликт, то выскочит подсказка. После этого появится пункт меню, по которой и происходит запуск bat-файла. Свой пункт в меню Notepad++Существует ещё один способ: использование плагина NppExec. Но с ним довольно сложно, поскольку каждый проект потребует отдельной настройки, которую всё-таки проще сделать один раз в bat-файле.

Файл HelloAlpha.java

Изучение самого проекта HelloAlpha.java немного выходит за рамки этой статьи. Я её написал только для изучения команд package и import. Научной ценности она, естественно, не имеет. 🙂 Поэтому для каркаса своих java-программ вы можете придумать свою структуру. Главное, пожалуй оставить каталог mypackage (или свой вариант), поскольку хоть какой-то должен указываться в package исходных файлов.

Как скомпилировать java в class

Статья помогла понять самые основы, что происходит при сборке программы (и почему у меня постоянно ломалось). Но! Мне как новичку пришлось гуглить ещё 100500 статей как с JavaRush так и с других сайтов, чтобы выполнить инструкции по компиляции и сборке через Maven (Ant и Gradle не пробовала). Основные замечания: 1) Здесь опечатка в команде java -classpath ./bin BoxMachine. Правильно указать, что выполняется пакет : java -classpath ./bin src.BoxMachine 2) Не хватает краткого прямого указания, в каком редакторе можно составлять и редактировать файлы (тот же NotePad, я вообще делала в терминальном редакторе nano) — вроде бы и понятно, но все-таки. Для полноты текста и возможно у автора будет для новичков полезный совет. 3) В каком редакторе можно посмотреть байт-код? Для образовательных целей. Раз залезаем под капот и разбираем по кирпичикам, то почему бы и нет? Jetbrains декомпилирует обратно и это уже не так интересно 4) ! Для выполнения инструкций в этой статье (чтобы по чесноку, без IDE) Ant, Maven, Gradle должны устанавливаться и настраиваться отдельно. Не хватает хотя бы прямого указания на этот факт и ссылки на статью с инструкцией установки 5) pom.xml, который предлагает статья — неполный. Вот совсем. Мне пришлось добавлять properties и то проект скомпилировался, но правильно в jar не собрался.

5 сентября 2022

Доброго времени суток, комрады! Возник вопрос выполнение программы происходит через следующую команду: «java hello.java», Когда пишу «java hello», получаю сообщение «Error: Could not find or load main class hello» «Caused by: java.lang.ClassNotFoundException: hello»

3 сентября 2022

Почему-то IDE IntelliJ при выполнении пишет java -javaagent . «. App» типа того что-то и всё у него выходит хорошо в IDE, а вот вручную когда в командной строке наберёшь %JAVA_HOME%java «. App» не выполняет, пишет не может main класс выполнить. Может кто ни будь объяснить?

Компилирование и исполнение Java-кода в Runtime

Привет Хабр! Сегодня я хотел бы поговорить про динамическое компилирование и исполнение Java-кода, подобно скриптовым языкам программирования. В этой статье вы найдете пошаговое руководство как скомпилировать Java в Bytecode и загрузить новые классы в ClassLoader на лету.

Зачем?

В разработке все чаще возникают типовые задачи, которые можно было бы закрыть простой генерацией кода. Например, сгенерировать DTO классы по имеющейся спецификации по стандартам OpenAPI или AsyncAPI. В целом, для генерации кода нет необходимости компилировать и выполнять код в runtime, ведь можно сгенерировать исходники классов, а собрать уже вместе с проектом. Однако при написании инструментов для генерации кода, было бы не плохо покрыть это тестами. А при проверке самый очевидный сценарий: сгенерировал-скомпилировал-загрузил-проверил-удалил. И вот тут-то и возникает задача генерации и проверки кода «на лету».

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

Последовательность действий

Для выполнения Java-кода в Runtime нам потребуется:

  1. Динамически создать и сохранить наш код в .java файл.
  2. Скомпилировать исходники в Bytecode (файлы .class).
  3. Загрузить скомпилированные классы в ClassLoader.
  4. Использовать reflection api для получения методов и выполнения их.

Шаг 1. Генерация кода

Вообще для генерации исходников можно конечно просто написать текст через StringBuider в файл и быть довольным. Но мне хотелось бы показать более прикладные решения, поэтому рассмотрим вариант генерации кода с использованием пакета com.sun.codemodel, а вот тут есть неплохой туториал по этому пакету. Так же на его основе есть библиотека jsonschema2pojo для генерации кода на основе jsonschema. Итак к коду:

public void generateTestClass() throws JClassAlreadyExistsException, IOException < //создаем модель, это своего рода корень вашего дерева кода JCodeModel codeModel = new JCodeModel(); //определяем наш класс Habr в пакете hello JDefinedClass testClass = codeModel._class("hello.Habr"); // определяем метод helloHabr JMethod method = testClass.method(JMod.PUBLIC + JMod.STATIC, codeModel.VOID, "helloHabr"); // в теле метода выводим строку "Hello Habr!" method.body().directStatement("System.out.println(\"Hello Habr!\");"); //собираем модель и пишем пакеты в currentDirectory codeModel.build(Paths.get(".").toAbsolutePath().toFile()); >

Пример выше сгенерирует класс Habr.java с одним методом:

package hello; public class Habr < public static void helloHabr() < System.out.println("Hello Habr!"); >>

Шаг 2. Компиляция кода

Для компиляции в Bytecode обычно используется javac и выполняется он простой командой:

javac -sourcepath src -d build\classes hello\Habr.java

Однако, нам надо скомпилировать наш класс прямо из кода. И для этого есть библиотека компилятора, до которой можно достучаться через javax/tools/JavaCompiler. Это реализация javax/tools/Tool (которая лежит в /lib/tools.jar). Выглядеть это будет как-то так:

Path srcPath = Paths.get("hello"); List files = Files.list(srcPath) .map(Path::toFile) .collect(Collectors.toList()); //получаем компилятор JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); //получаем новый инстанс fileManager для нашего компилятора try(StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) < //получаем список всех файлов описывающих исходники IterablejavaFiles = fileManager.getJavaFileObjectsFromFiles(files); DiagnosticCollector diagnostics = new DiagnosticCollector<>(); //заводим задачу на компиляцию JavaCompiler.CompilationTask task = compiler.getTask( null, fileManager, diagnostics, null, null, javaFiles ); //выполняем задачу task.call(); //выводим ошибки, возникшие в процессе компиляции for (Diagnostic diagnostic : diagnostics.getDiagnostics()) < System.out.format("Error on line %d in %s%n", diagnostic.getLineNumber(), diagnostic.getSource()); >>

Шаг 3. Загрузка и выполнение кода

Для выполнения кода нам надо загрузить его через ClassLoader и через reflection api вызвать наш метод.

//получаем ClassLoader, лучше получать лоадер от текущего класса, //я сделал от System только чтоб пример был рабочий ClassLoader classLoader = System.class.getClassLoader(); //получаем путь до нашей папки со сгенерированным кодом URLClassLoader urlClassLoader = new URLClassLoader( new URL[], classLoader); //загружаем наш класс Class helloHabrClass = urlClassLoader.loadClass("hello.Habr"); //находим и вызываем метод helloHabr Method methodHelloHabr = helloHabrClass.getMethod("helloHabr"); //в параметре передается ссылка на экземпляр класса для вызова метода //либо null при вызове статического метода methodHelloHabr.invoke(null);

Итог

В этой статье я постарался показать полноценный сценарий генерации и выполнения кода в Runtime. Самому мне это пригодилось при написании unit-тестов для библиотеки по генерации DTO классов на базе документации сгенерированной библиотекой springwolf. Реализацию тестов в моем проекте можно посмотреть тут.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *