Это второй пост из серии, посвященной пониманию Java-проектов. Ранее мы рассмотрели, как Java на самом деле устанавливается в систему mac OS, а теперь мы собираемся создать базовое приложение. Затем мы перейдем к включению того же приложения с помощью Gradle, популярного инструмента сборки, и закончим включением нашего проекта в IDE IntelliJ.
Наша структура каталогов
Мы собираемся скомпилировать полностью обновленную версию Hello World, и в нашем раздутом примере будут использоваться пакеты, библиотеки и тесты, потому что это более показательно для проекта, который мы бы заметили в дикой природе. Этот проект предназначен для людей, которые немного поработали с Java и не собираются много останавливаться на синтаксисе вне инструментария.
Мы будем свободно следовать соглашениям Maven стандартная компоновка каталогов , что, по общему признанию, немного излишне для нашего крошечного приложения, но мы также будем продвигаться вперед, потому что это указывает на соглашения, с которыми мы обычно сталкиваемся при работе с Java. Вот как это выглядит:
. ├── bin ├── lib │ ├── jfiglet-0.0.8.jar │ └── junit-platform-console-standalone-1.4.2.jar └── src ├── main │ └── java │ └── space │ └── gaston │ ├── greeter │ │ └── Greeter.java │ ├── helloWorld │ │ └── HelloWorld.java │ └── textEffects │ └── Bubble.java └── test └── java └── space └── gaston ├── greeter │ └── GreeterTest.java └── textEffects └── BubbleTest.java
Давайте распакуем то, что у нас здесь есть:
bin
будет содержать наши скомпилированные файлы.class
lib
будет содержать наши сторонние библиотеки. В этом случае мы используем Figlet и тестовый запуск JUnit, к которому мы вернемся позже.src
будет содержать наш исходный код.java
. Внутриsrc
у вас есть подкаталогиглавная
иtest
, которые оба имеют подкаталогjava
для обозначения языка, и затем стандартная иерархия пакетов Java . В конце концов, после нескольких месяцев поисков, вы, наконец, наткнетесь на наши настоящие файлы.java
.
Просто небольшое предостережение: я не проверил папку lib
в Git, поэтому вам нужно будет захватить JFiglet и JUnit .банка
файлы из Maven, если вы хотите создать этот проект самостоятельно. Частично это делается для того, чтобы показать, насколько сложно управлять зависимостями вручную, и помочь нам понять, как позже, насколько здорово, что другие инструменты могут прийти нам на помощь.
.java, .класс и .банка
Ладно, тогда я перебрал довольно много типов файлов. Я думаю, что наша ИДЕЯ совершенно обычно скрывает многие из этих особенностей, поэтому вот краткое описание того, что делает каждый из этих типов:
- Файл
.java
представляет собой текстовый файл с читаемым человеком исходным кодом Java, хотя, по общему признанию, обозначение “читаемый”, гм, довольно спорно, когда дело доходит до определенных аспектов синтаксиса Java. По сути, файлы.java
– это файлы, в которые мы, мягкие монстры из человеческой плоти, помещаем наш код. - A
файл .class
представляет собой скомпилированный байт-код Java, который может быть выполнен виртуальной машиной Java, по общему признанию, шикарным инструментом, который запускает наши Java-программы. Эти холодные, механические файлы – это те, которые компьютер любит читать. - A
.банка
файл представляет собой архив файлов.class
(и других необходимых ресурсов), аккуратно заархивированных для удобства.
javac и java
Два наших двоичных файла JDK отвечают за компиляцию и запуск нашего кода: javac
и java
. Короче говоря, javac
отвечает за превращение наших .java
файлов в .class
файлы, которые java
может запускать.
Если мы соберем совершенно голые кости HelloWorld.java
, затем мы можем передать его в качестве аргумента в javac
и запустить его с java
:
public class HelloWorld { public static void main(String[] args) { System.out.println("Oh no, not another Hello World example..."); } }
Без множества файлов .java
, внешних библиотек или выходных каталогов, о которых нужно беспокоиться, компиляция и запуск этого так же просты, как отправка пути к файлу в javac
а затем запуск вывода:
$ javac HelloWorld.java $ java HelloWorld Oh no, not another Hello World example...
Обратите внимание, что файл .class
в настоящее время будет скомпилирован в тот же каталог, что и его сопутствующий исходный код, и что мы вызываем класс HelloWorld
напрямую с помощью java
без расширения .class
– последнее вызовет страшный java.lang. ClassNotFoundException
ошибка, но это история для другого дня. Оказывается, мы используем java
для запуска классов Java, а не Java .класс
файлы.
Путь к классу
Еще одна потенциальная ошибка, которую мы можем увидеть прямо сейчас, – это файл java.lang. NoClassDefFoundError
, который обычно возникает из- за наличия файла .class
, который был создан во время компиляции (с помощью javac
) , но где- то потерялся , когда мы пытаемся запустить его с помощью java
.
Имейте в виду тех, у кого хрупкое телосложение, следующего слова достаточно, чтобы у вас поднялся пар. Эта ужасная концепция разрушила надежды и мечты даже самых сильных умов, искателей приключений. Оставьте всякую надежду, все, кто входит… путь к классу .
Давайте увеличим масштаб наших основных файлов .java
:
. ├── greeter │ └── Greeter.java ├── helloWorld │ └── HelloWorld.java └── textEffects └── Bubble.java
Наш Greeter.java
, Адский мир.java
и Bubble.java
все они хранятся в разных пакетах (что в Java также означает разные каталоги) и имеют свои собственные требования. Hello World
включает в себя как Больший
, так и Пузырь
, причем Пузырь
сам по себе является адаптером к стороннему классу шрифтов Figlet
из JFiglet .jar
в нашей папке lib
.
В нашей папке test
у нас есть тесты для Большего
и Bubble
, который включает классы из JUnit в lib
, а также требует фактического Большего
и Пузырь
классы для тестирования.
Добро пожаловать, друзья, в “Зависимости”.
Java, хотя и довольно умна, должна знать, куда идти, чтобы выполнить все эти требования – отсюда и путь к классам. Мы можем получить сенсацию прямо из лошадиных уст :
Значение пути к классу по умолчанию равно “.”, что означает, что выполняется поиск только в текущем каталоге. Указание либо переменной ПУТИ к классу, либо переключателя командной строки -cp
переопределяет это значение.
Также:
Установка ПУТИ к КЛАССУ
может быть сложной задачей, и ее следует выполнять с осторожностью.
Что просто очаровательно. По сути, ваш путь к классу должен содержать путь к нашему .jar
файлы на вершину нашей иерархии пакетов. Его можно установить либо с помощью переменной окружения, чего вам не следует делать, либо с помощью гораздо лучшего варианта флага -cp
.
Это также помогает объяснить распространенную ошибку Java, когда вы пытаетесь запустить java
без cd
сначала в каталог.
$ java bin.space.gaston.helloworld.HelloWorld Error: Could not find or load main class bin.space.gaston.helloworld.HelloWorld Caused by: java.lang.NoClassDefFoundError: space/gaston/helloworld/HelloWorld (wrong name: bin/space/gaston/helloworld/HelloWorld)
видите ли, bin
не является частью иерархии пакетов Java, но должен находиться на пути к классу, если вы находитесь за пределами папки. Таким образом, оба нижеперечисленных действия будут работать:
$ cd bin $ java space.gaston.helloworld.HelloWorld
$ java -cp bin space.gaston.helloworld.HelloWorld
Сводя все это воедино
Имея все это в виду, мы можем начать компилировать наши файлы в каталог bin
. Из верхней части нашего каталога проектов мы можем приступить к работе.
1. Составление нашей основной папки:
$ javac -d bin -cp lib/jfiglet-0.0.8.jar src/main/java/space/gaston/greeter/Greeter.java src/main/java/space/gaston/helloWorld/HelloWorld.java src/main/java/space/gaston/textEffects/Bubble.java
Теперь мы используем флаг -d
, чтобы указать, где должны находиться наши скомпилированные файлы. Мы вручную отправляем каждый из наших .java
файлов в явак
, поэтому нам не нужно добавлять их в путь к классам, но нам нужно добавить наш JFiglet .jar
файл так что Пузырь
может компилироваться.
2. Составление нашей тестовой папки:
$ javac -d bin -cp lib/junit-platform-console-standalone-1.4.2.jar:lib/jfiglet-0.0.8.jar src/main/java/space/gaston/textEffects/Bubble.java src/test/java/space/gaston/textEffects/BubbleTest.java src/main/java/space/gaston/greeter/Greeter.java src/test/java/space/gaston/greeter/GreeterTest.java
Нам нужно добавить как фиглет, так и JUnit .jar
|
Ваш файл bin теперь будет выглядеть следующим образом – обратите внимание, что структура каталогов наших файлов .class
должна поддерживать ту же иерархию пакетов, что и исходные файлы .java
:
. ├── BubbleTests.class ├── GreeterTests.class └── space └── gaston ├── greeter │ └── Greeter.class ├── helloworld │ └── HelloWorld.class └── textEffects └── Bubble.class
3. Запускаем наши тесты:
$ java -jar lib/junit-platform-console-standalone-1.4.2.jar -cp bin:lib/jfiglet-0.0.8.jar --scan-class-path
╷ ├─ JUnit Jupiter ✔ │ ├─ BubbleTests ✔ │ │ └─ helloReturnsAsciiHello() ✔ │ └─ GreeterTests ✔ │ ├─ greetWithArgumentSteveReturnsHelloSteve() ✔ │ └─ greetWithNoArgsReturnsHelloWorld() ✔ └─ JUnit Vintage ✔
Нашу версию JUnit можно запустить в командной строке. Мы передаем флаг --scanclasspath
, чтобы JUnit автоматически искал все тесты в вашем пути к классу, поэтому для этого требуется добавить папку bin
в путь к классу (потому что мы находимся в верхней части папки нашего проекта), а также JFIGLET, который по-прежнему требуется Bubble
.
Кроме того, ура, тесты пройдены.
4. Запуск нашего основного приложения:
$ java -cp bin:lib/jfiglet-0.0.8.jar space.gaston.helloworld.HelloWorld
_ _ _ _ ____ _ | | | | ___ | | | | ___ / ___| | |_ ___ __ __ ___ | |_| | / _ \ | | | | / _ \ \___ \ | __| / _ \ \ \ / / / _ \ | _ | | __/ | | | | | (_) | ___) | | |_ | __/ \ V / | __/ |_| |_| \___| |_| |_| \___/ |____/ \__| \___| \_/ \___|
Нет, я тоже понятия не имею, почему мы поручили ему вывести “Привет, Стив”.
Итак, отлично. У нас это работает. Но, черт возьми, разве это не многовато даже для простого, полностью надуманного приложения? Можете ли вы представить, что буквально каждый раз, когда вы вносите изменения в приложение и вам нужно перекомпилировать его? Не знаю, как вы, но если бы мне пришлось так работать больше недели, я бы навсегда застрял в том, чтобы выглядеть так, будто я играю роль в фильме Эдварда Мунка “Крик”.
В следующем посте кавалерия выступит, чтобы спасти нас от вечного ужаса строительства.
Был ли этот пост полезен для вас? Я был бы очень признателен за любые комментарии и отзывы о том, можно ли что-то прояснить или объяснить лучше. Я также был бы очень признателен за любые исправления!
Оригинал: “https://dev.to/martingaston/understanding-the-java-classpath-building-a-project-manually-3c3l”