Программу, написанную на языке, который компилируется в байт код виртуальной машины, можно скомпилировать однажды и потом запускать на любой платформе, где есть виртуальная машина.
Не каждая программа, написанная на языке с виртуальной машиной, переносима. Т.е. не любая программа, написанная на языке с виртуальной машиной, будет работать везде одинаково.
Элементы Java-приложения
Каждое объявление класса компилируется в отдельный .class файл содержащий Java байт-код. JDK предоставляет инструменты для компиляции и запуска программ. Классы из API для платформы Java SE уже скомпилированы и JDK знает, где их найти.
Термин приложение (application) является синонимом программы, т.е. скомпилированного исходного кода, который может выполняться напрямую. Чтобы создать Java-приложение в программе должен быть класс в котором определен публичный, статический, ничего не возвращающий метод с именем main — точка входа с которой начинается выполнение приложения. При старте приложения Java interpreter также называемый Java Virtual Machine (JVM) запускает метод main().
Как скомпилировать простую программу на Java? Первые шаги. Программирование на Java
// File: CharStack.java public class CharStack < // Instance variables: private char[] stackArray; // The array implementing the stack. private int topOfStack; // The top of the stack.
// Static variable private static int counter; // Constructor now increments the counter for each object created. public CharStack(int capacity) < stackArray = new char[capacity]; topOfStack = -1; counter++; > // Instance methods: public void push(char element) < stackArray[++topOfStack] = element; > public char pop() < return stackArray[topOfStack—]; > public char peek() < return stackArray[topOfStack]; > public boolean isEmpty() < return topOfStack == -1; > public boolean isFull() < return topOfStack == stackArray.
length — 1; > // Static method public static int getInstanceCount() < return counter; > >
// File: Client.java public class Client < public static void main(String[] args) < // Create a stack.
CharStack stack = new CharStack(40); // Create a string to push on the stack: String str = «!no tis ot nuf era skcatS»; System.out.println(«Original string: » + str); int length = str.length(); // Push the string char by char onto the stack: for (int i = 0; i length; i++) < stack.push(str.charAt(i)); >System.
out.print(«Reversed string: «); // Pop and print each char from the stack: while (!stack.isEmpty()) < // Check if the stack is not empty. System.out.print(stack.pop()); > System.
out.println(); > >
Компиляция и запуск Java-приложения
Эта команда создает файл Client.class содержащий Java байт-код для класса Client. Класс Client использует класс CharStack, и если файл CharStack.class не существует, то компилятор скомпилирует CharStack.java.
Скомпилированные классы могут быть исполнены Java интерпретатором java, который также является частью JDK.
Как компилировать Java программы / How to compile Java programs
Источник: progra-lang.blogspot.com
Как выполнить / скомпилировать программу Java в IDE Eclipse
В этой статье мы расскажем, как скомпилировать программу в IDE Eclipse. Этот программный продукт распространяется свободно, а загрузить его можно по адресу http://eclipse.org. IDE Eclipse написана на языке Java, но ее переносимость ограничена из-за применения в ней нестандартной библиотеки управления окнами. Тем не менее существуют версии Eclipse для операционных систем Linux, Mac OS X, Solaris и Windows.
Существуют и другие IDE, но в настоящее время Eclipse распространена наиболее широко. Для того чтобы приступить к работе в этой IDE, выполните следующие действия.
- После запуска Eclipse выберите из меню команду File=>New Project ( Файл=> Создать проект ).
- Выберите вариант Java Project (Проект Java) в диалоговом окне мастера проектов (рис. 1). Здесь и далее показаны моментальные снимки экрана из пользовательского интерфейса версии Eclipse 2. В вашей версии Eclipse элементы пользовательского интерфейса могут несколько отличаться.
- Щелкните на кнопке Next (Далее), укажите в качестве имени проекта Welcome и введите полный путь к каталогу, содержащему файл Welcome, java (рис. 2).
- Щелкните на кнопке-переключателе Create project from existing source (Создать проект из существующего источника).
- Щелкните на кнопке Finish (Готово). В итоге будет создан новый проект.
Рис 1. Диалоговое окно Eclipse для создания нового проекта
Рис. 2. Настройка проекта в Eclipse
- Щелкните на треугольной кнопке рядом с именем нового проекта на левой панели, а затем на треугольной кнопке слева от варианта (default package), т.е. пакет по умолчанию. Дважды щелкните на имени Welcome .java. Появится окно с исходным кодом программы, как показано на рис. 3.
Рис. 3. Редактирование исходного кода в Eclipse
- Щелкните правой кнопкой мыши на имени проекта (Welcome) на левой панели. Выберите в открывшемся контекстном меню команду Run=>Run As=>Java Application ( Выполнить => Выполнить как =>Приложение Java ). В нижней части окна появится окно для вывода результатов выполнения программы.
Выявление ошибок компиляции
Рассматриваемая здесь программа состоит из нескольких строк кол и поэтому в ней вряд ли имеются ошибки или даже опечатки. Но для того, чтобы продемонстрировать порядок обработки ошибок, допустим, что в имени String вместо прописной буквы набрана строчная:
String[] greeting = new string[3];
Снова попытайтесь скомпилировать программу. Вы получите сообщение об ошибке, уведомляющее о том, что в коде программы использован неизвестный тип string (рис. 4). Просто щелкните на сообщении.
Курсор автоматически перейдет на соответствующую строку кода в окне редактирования, где вы можете быстро исправить допущенную ошибку.
Рис. 4. Сообщение об ошибке, выводимое в Eclipse
СОВЕТ
Таким образом, на рассмотренном выше простом примере вы получили ясное представление о работе в IDE Eclipse.
Источник: oracle-patches.com
Компилирование и исполнение Java-кода в Runtime
Сегодня я хотел бы поговорить про динамическое компилирование и исполнение Java-кода, подобно скриптовым языкам программирования. В этой статье вы найдете пошаговое руководство как скомпилировать Java в Bytecode и загрузить новые классы в ClassLoader на лету.
Зачем?
В разработке все чаще возникают типовые задачи, которые можно было бы закрыть простой генерацией кода. Например, сгенерировать DTO классы по имеющейся спецификации по стандартам OpenAPI или AsyncAPI. В целом, для генерации кода нет необходимости компилировать и выполнять код в runtime, ведь можно сгенерировать исходники классов, а собрать уже вместе с проектом.
Однако при написании инструментов для генерации кода, было бы не плохо покрыть это тестами. А при проверке самый очевидный сценарий: сгенерировал-скомпилировал-загрузил-проверил-удалил. И вот тут-то и возникает задача генерации и проверки кода “на лету”.
Также иногда возникают потребности выполнять какой-то код удаленно. Как правило это какие-то распределенные облачные вычисления. В этом случае можно отправлять исходный код на вычислительный узел, а там уже происходит динамическая сборка и выполнение.
Последовательность действий
Для выполнения Java-кода в Runtime нам потребуется:
- Динамически создать и сохранить наш код в .java файл.
- Скомпилировать исходники в Bytecode (файлы .class).
- Загрузить скомпилированные классы в ClassLoader.
- Использовать 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 buildclasses helloHabr.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)) < //получаем список всех файлов описывающих исходники Iterable<? extends JavaFileObject>javaFiles = 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. Реализацию тестов в моем проекте можно посмотреть тут.
Источник: uproger.com