Это второй пост из серии, посвященной пониманию 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будет содержать наши скомпилированные файлы.classlibбудет содержать наши сторонние библиотеки. В этом случае мы используем 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”