Что такое пакет Примеры пакетов Назначение пакетов Правила создания пакетов Импорт классов Компиляция и запуск Возможные ошибки и их решение Пакеты в Java появились с самого начала, во времена, когда язык еще назывался Oak. Их описание уже присутствует в его ранних спецификациях. Java-пакеты реализуют так называемое пространство имен (namespace), позволяющее использовать в проекте файлы с одинаковыми именами. Такой подход существует с давних времен во многих языках. Также с помощью пакетов разработчики структурируют файлы удобным и понятным для себя способом, т. к. чем их больше используется в программе, тем в них сложнее становится ориентироваться. Если они будут размещаться бессистемно, то это рано или поздно приведет к полному запутыванию кодовой базы и дезориентации программистов. И наконец, с помощью пакетов можно ограничивать доступ (из других пакетов) как целиком к классам, так и к их отдельным элементам. Об этом и многом другом и пойдет речь в данной статье. Пакетом (пространством имен) в Java называется структура вложенных по какому-то признаку папок с размещенными в них классами (интерфейсами, перечислениями, аннотациями), необходимыми проекту. Вы можете думать о пакетах как о папках на вашем компьютере, в которых хранятся файлы, сгруппированные в соответствии с их функциональностью (назначением). Поскольку проект может состоять из сотен или тысяч классов, имеет смысл поддерживать порядок, помещая их в пакеты. Например, если какие-то классы размещаются в папке calculator по адресу: , то с точки зрения Java они будут храниться в следующем пакете (в качестве разделителя уже используется точка вместо слеша): При этом в начале каждого из классов необходимо разместить строку, указывающую на его принадлежность к конкретному пакету, используя ключевое слово package и имя пакета (точка с запятой в конце — обязательна): Если подобная строка не будет присутствовать в классах, то они автоматически добавятся в безымянный пакет (unnamed package). Имя пакета ru.topjava.startjava.calculator означает следующее (подробно правила именования пакетов рассматриваются в последующих главах): ru.topjava — доменное имя разработчика кода, записанное в реверсивном виде startjava — код пишется для проекта под названием StartJava calculator — подпроект, реализуемый в рамках проекта StartJava Создадим структуру из вложенных папок и файл CalculatorMain.java, отобразив ее в консоли с помощью консольной команды tree: Напишем простую реализацию класса CalculatorMain, указав имя его пакета: На примере Java API вы можете ознакомиться со структурой стандартных пакетов. Например, берем java.io — это пакет. Именно так, с использованием точки в качестве разделителя, он используется в Java. Но с точки зрения файловой системы, эта запись трактуется как: в папку под названием java вложена папка с именем io. Вы можете самостоятельно в этом убедиться. Для этого откройте архив src.zip, найдя его расположение у себя на компьютере, например, с помощью консольной команды where. В нем хранится множество вложенных папок с исходниками. Таких архивов может найтись несколько: все зависит от количества установленных JDK от разных вендоров — выбирайте любой. Открыв данный архив и перейдя к месту хранения, например, класса String, вы увидите, что пакеты — это обычные вложенные папки с классами (путь к классу с определенного момента совпадает с именем пакета): Класс String как раз хранится в пакете java.lang. И таких классов в Java — тысячи (1, 2). Если бы они все размещались бессистемно, то разобраться в них было бы крайне тяжело. Классы в пакетах обычно группируются исходя из их функциональности, а не разбрасываются хаотично по всему приложению. Разработчики стараются размещать все элементы, относящиеся к одной функции, в один пакет. Например: java.io содержит классы, отвечающие за ввод/вывод java.math содержит классы, обеспечивающие математические операции java.time содержит классы для работы с датой и временем и т. д. Тут стоит оговориться, что классы группируются в пакеты не всегда исходя из их назначения, т. к. на конкретных проектах все может быть иначе в силу их структуры и масштабности. Это всегда дискуссионный вопрос, который решается "на месте". Но начинающим программистам можно руководствоваться этим простым правилом. Кроме того, в отдельных папках рекомендуется хранить class-файлы, сторонние библиотеки, изображения, документацию и т. д. Все эти меры упрощают понимание и сопровождение приложения. Рассмотрим еще примеры. На картинке ниже изображены два пакета: java.lang и java.util. Важно отметить, что папка src (сокр. от source) не считается за пакет, т. к. является общей (по соглашению) для всех исходников и размещается в корне проекта. По этой причине src не указывается в именах пакетов. В своих проектах вам тоже не нужно это делать. Обратимся теперь за примером к Spring Framework. Данный фреймворк содержит тысячи классов, разложенных по пакетам. Например, класс BeanFactory.java размещается в пакете: ApplicationContext.java — в другом пакете: Из структуры репозитория и имен пакетов видно, что у этих классов корневой папкой для исходников является уже не src, a группа вложенных папок. При этом часть пути до org не будет входить в имя пакетов. Такая структура характерна для больших проектов с множеством классов, языков программирования, наличием Unit-тестов и т. д. Данная структура является стандартом для приложений, использующих систему сборки проекта под названием Maven (Gradle). На данном этапе достаточно просто об этом знать, не вдаваясь в подробности про системы сборок. На картинке ниже java-файлы беспорядочно свалены в одну папку. Вместо этого исходники могли бы быть разложены по смыслу в разные папки, например, со следующими названиями: При этом папки могут содержать подпапки (подпакеты), еще более структурирующие файлы. В итоге классы можно было бы разложить, например, в следующие пакеты, группируя исходя из их назначения: Подобное разделение, безусловно, упрощает поддержку и понимание проекта в целом, а также назначение каждого его класса. В Java существует четыре модификатора доступа, одним из которых является package private (его еще называют default или no modifier). У него нет своего ключевого слова. Данный вид доступа применяется по умолчанию, когда никакой из модификаторов не указан явно. Он предназначен для управления доступностью содержимого пакетов. В пакете можно определить классы, которые будут недоступны за его пределами. Например, этот класс виден только в пакете, в котором находится сам: Такой подход зачастую используется для классов, которые являются частью внутренней реализации какой-то библиотеки и не предназначены для использования сторонними разработчиками. Это просто способ сокрытия того, что не должно быть доступно внешнему коду. Хоть и нельзя утверждать со 100% уверенностью (зависит от страны, команды и т. д.), но зачастую в коммерческой разработке этот модификатор не используют (хотя в JDK он применяется повсеместно), руководствуясь принципом, что если что-то не написано, то оно забыто. Системы, проверяющие код в автоматическом режиме на соответствие стандартам, его не пропустят.  Повторяющиеся имена классов в Java в рамках одного проекта — обычное явление, которое не приводит к конфликтам имен только потому, что они хранятся в разных пакетах. Для того, чтобы обратиться к нужному классу и избежать коллизии при совпадении имен, когда компилятор не может выбрать нужный тип, необходимо указать его полное имя. Оно включает в себя название пакета, где размещается класс, и его непосредственное имя. Например, полное имя класса Random из стандартного пакета будет java.util.Random. А полное имя вашего класса может быть ru.topjava.startjava.Random. При этом возможности данных типов могут использоваться даже в рамках одного класса без каких-либо проблем. В Java есть два стандартных класса под названием Date: один хранится в пакете java.sql, а второй — в java.util. Из-за того, что пакеты у них разные, и к каждому классу можно обратиться через его полное имя, ошибок при компиляции не возникнет. Возможность сослаться через имя пакета на конкретный тип данных и позволяет иметь в одном проекте классы с одинаковыми именами. Пример использования классов с одинаковыми именами рассматривается в другой главе. Когда Java набирала свою популярность во времена развития веба, то появилось универсальное правило, смысл которого заключался в следующем: если какая-то компания разрабатывает библиотеки или целое приложение, то у нее наверняка есть свой сайт с доменным именем, например, topjava.ru. А как мы знаем, доменные имена повторяться не могут. В итоге решили, что для обеспечения уникальности пакетов их имена следует начинать с префикса в виде доменных имен второго уровня их разработчиков, записанных в обратном порядке. Если сайт называется topjava.ru, то пакет будет начинаться с имени ru.topjava. Такой подход можно объяснить тем, что более информативные и значимые составляющие пакета должны размещаться ближе к классу, который в нем находится. Значимость папок, хранящих класс тем выше, чем они к нему ближе. А в доменных именах — все наоборот, вот и пришлось пойти на такой реверс в именовании пакетов. Если у вас нет собственного доменного имени, то для создания уникальных имен пакетов придется придумать комбинацию с малой вероятностью повторения (например, название аккаунта на GitHub). Но для серьезных проектов все же стоит потратиться для приобретения собственного доменного имени. В некоторых ситуациях имя домена может быть недопустимым для пакета. В таком случае, если оно содержит символы, не разрешенные для именования, или ключевое слово Java, то его необходимо преобразовать в символ подчеркивания. Например: Общие правила: имя пакета должно быть простым и отражать общий смысл объединенных в нем классов все слова, входящие в имя пакета, должны писаться строчными буквами без использования camelCase или подчеркиваний, а также в единственном числе: Имена пакетов пишутся строчными буквами, чтобы избежать конфликта с именами классов или интерфейсов. Если какая-либо из частей имени пакета является ключевым словом, начинается с цифры или любого другого символа, который не разрешен в качестве начального символа идентификатора, добавьте к нему префикс в виде символа подчеркивания В Java все стандартные пакеты начинаются с зарезервированных слов java или javax. Это означает, что имена ваших пакетов не могут начинаться с этих слов Для именования пакета желательно использовать короткие слова или сокращения, например, util вместо utilities, lang вместо language или аббревиатуры — awt, http и проч. Только не придумываете свои собственные сокращения, используйте общепринятые Следует избегать более одного слова подряд в элементах имени пакета. Если все же этого не удастся сделать, то они записываются слитно: Имя пакета необходимо отделить от последующего кода пустой строкой Точка с запятой в конце имени пакета — обязательна Пакет объявляется без переноса строки. Ограничение на длину строки на объявление пакета (как и импортов) не распространяется В одном файле может располагаться только один package Нельзя переименовывать пакет, не переименовав папку, в котором хранятся его классы (и наоборот) Если в классе явно не указывается принадлежность к какому-либо пакету, то такой класс попадает в безымянный пакет. При этом безымянная папка не создается. Такие пакеты предназначены только для небольших приложений или когда вы только начинаете процесс разработки. В реальных проектах классы вне пакетов не создаются Классы из безымянного пакета не могут быть импортированы Для маленьких приложений вы можете помещать свои исходные файлы в папку src без создания пакетов Указывать все время полное имя класса — достаточно утомительное занятие, захламляющее код (хотя без этого, бывает, не обойтись). Для облегчения этого процесса в Java существует возможность подключения нужного функционала с помощью оператора import. Для того, чтобы использовать в своей программе методы или поля из любого класса, который не располагается в том же пакете, что и ваш класс, необходимо делать импорт. Например, чтобы воспользоваться методами класса Scanner, следует перед объявлением класса прописать следующее: Данная запись состоит из ключевого слова import, имени пакета и класса, возможности которого вам требуются (точка с запятой в конце — обязательна). Если бы данный способ импорта не был внедрен в Java, то его отсутствие сильно бы захламило код, т. к. пришлось бы каждый раз указывать относительный путь в виде пакета до нужного класса. В этом случае создание объекта выглядело бы следующим образом: Это очень громоздко. А с учетом всего сказанного, эту строку можно переписать так: Хочу акцентировать ваше внимание на том, что import нужен для того, чтобы Java-программистам было проще использовать классы из других пакетов, не вводя все время их полные имена, например, String вместо java.lang.String. Данный оператор просто делает код короче и читабельней. Это синтаксический сахар, уменьшающий количество печатаемых вами символов. Технически import требуется компилятору, чтобы он знал, по какому адресу (в каком пакете) искать используемые в вашей программе классы. Импортировать нужный функционал можно следующими способами: импорт конкретного класса импорт конкретного метода/поля класса импорт всего пакета целиком Импорт конкретного класса представляет собой наиболее распространенный способ подключения: Импорт конкретного метода/поля (появился в Java 5) используется для импорта статических членов класса (статический импорт): Последний способ — подключение всего пакета со всем содержимым. Для этого используется * (символ подстановки): Если взглянуть на примеры из реальных проектов (1, 2), то видно, что какое бы количество классов не импортировалось, в коде не используется импорт всего пакета, а статический импорт применяется преимущественно в классах с тестами. Учитывайте это! Рассмотрим причины, по которым многие программисты используют импорт конкретного класса, а не всего пакета. Это связано с тем, что явный импорт: показывает, какие внешние классы используются в коде снижает вероятность возникновения коллизий имен, возникающих при импорте пакетов, содержащих классы с одинаковыми именами позволяет избежать проблем, когда в какой-либо пакет разработчик добавляет новый класс (например, в последнюю версию сторонней библиотеки был добавлен новый функционал), а вы при этом использовали *. Это внезапно для вас может привести к ошибкам компиляции из-за конфликта имён, которых раньше не было Если классы находятся в одном пакете и используют возможности друг друга, то выполнять import не нужно, т. к. они смогут найти друг друга без каких-либо сложностей. Это связано с тем, что в каждый класс автоматически импортируются все классы из текущего пакета. Текущий пакет — это пакет, в котором лежит текущий класс. Кроме того, возможно, вы заметили, что класс String никогда не приходится импортировать. Вы его просто используете, как есть. Все дело в том, что он, да и все остальные классы из пакета java.lang, являются фундаментальными классами и также импортируются компилятором автоматически. Получается, что в любой класс Java сама импортирует два пакета: текущий и java.lang. С учетом всего сказанного, импорты класса CalculatorMain, описанного ранее, будут выглядеть так (хоть мы этого и не видим): Обратите внимание на строку 9. Вам не приходится делать импорт, чтобы использовать возможности вывода текста на консоль, т. к. класс System входит в пакет java.lang. Это очень полезная магия! Пакеты, находящиеся внутри другого пакета, называются подпакетами. Например, java.util.concurrent и java.util.function — это подпакеты пакета java.util. Они не импортируются рекурсивно, например, при помощи import java.util.*. Их нужно импортировать явно. Несмотря на то, что пакеты хоть и выглядят вложенными, на самом деле вы должны рассматривать java.util, java.util.concurrent, java.util.function и т. п., как три разных, не связанных между собой пакета, имена которых имеют общую часть. Очень часто начинающие программисты задаются рядом вопросов, связанных с импортом. На некоторые из них я подготовил ответы: import работает так же, как директива #include в языках C/C++?Нет, у них разный механизм работы: import не помещает код импортируемого класса в ваш класс, как это делает #include. В C/C++ же данная директива заменяется перед компиляцией на содержимое файла, на который указывает — происходит обычный копипаст. Затем класс передается компилятору со всеми включенными в него другими файлами, как если бы это был один файл. Например, на место #include <stdio.h> копируется содержимое файла stdio.h, в то время, как import java.util.Arrays означает, что если в вашем файле нет данного класса, то его необходимо искать по полному имени, указанном в импорте. влияет ли работа import на производительность (скорость выполнения) программы?Работа import (сколько бы их не было) никак не влияет на производительность, т. к. он используется только на этапе компиляции. В class-файлах никаких импортов просто физически нет. увеличивает ли import размер class-файлов?Импорт не увеличивает размер байт-кода, т. к. в процессе компиляции компилятор заменяет каждое имя класса на полное имя, а затем удаляет оператор импорта. Таким образом, оператор не присутствует в байт-коде и не включат в место своего объявления код импортируемых классов. Он существует только в исходниках для поиска классов. есть ли какая-либо разница между class-файлами при использовании import или при написании полного имени классов?Class-файлы с использованием импорта или без будут идентичными как по размеру, так и по содержанию. Вы можете посмотреть байт-код class-файлов, используй javap -c  — никакой разницы между ними не будет. В обоих случаях байт-код будет иметь полные имена, помещенные туда компилятором. влияет ли import на время компиляции?Если в классе много импортов, то при компиляции могут возникнуть небольшие задержки, которые будут настолько малы, что о них не стоит беспокоиться. Из данного раздела вы узнаете, как компилировать и запускать классы, находящиеся в именованных пакетах, из консоли. Взглянем еще раз на картинку, которую мы уже видели ранее, где свалены в одну папку множество файлов: Обратите внимание, что на ней class-файлы размещаются совместно с java-файлам, чего быть не должно. Обычно class-файлы хранятся в отдельной папке под названием out (bin или classes). В корне вашего проекта всегда должна находиться отдельная папка для хранения сгенерированных компилятором файлов. Ее создание может выглядеть так: На самом деле ее можно не создавать вручную, т. к. при первой же компиляции она (со всеми подпапками) создастся автоматически (либо ее сгенерирует ваша среда разработки). Компиляция выполняется по следующей схеме: , где  обозначает параметры javac, а  указывает на исходные файлы, которые требуется скомпилировать. Подробнее это выглядит так: консоль необходимо открыть в корне вашего проекта (где находится папка src) в ней напишите через пробел:  команду javac опцию -d (сокр. от destination), указывающую на папку для размещения сгенерированных class-файлов имя этой папки. В нашем случае — out  опцию -verbose (необязательно), если вы хотите видеть, что происходит в процессе компиляции: время компиляции, какие файлы компилируются и т. д. относительный путь до папки с классами и маску вида *.java, чтобы не перечислять каждый класс Пример компиляции всех классов в пакете: Пример компиляции конкретного класса После выполнения команды, благодаря ключу -d, в папке out (как и сама папка, если на момент компиляции ее еще не было) будет создана иерархия папок, повторяющая иерархию для компилируемых классов. При этом class-файлы появятся не в корне out, а по адресу /out/ru/topjava/startjava/calculator/. Если программа содержит несколько классов, которые при этом размещаются в разных пакетах, то процесс компиляции несколько изменится. Рассмотрим пример из трех простых классов, описывающих собаку, ее хозяина и класс запуска. Все эти классы лежат в разных пакетах. Взглянем на получившуюся иерархию: Выполним компиляцию: Как видно, нам пришлось вручную указать все используемые классы и пути до них, что не всегда бывает удобно. Можно воспользоваться вариантом короче, указав параметр ‑sourcepath, говорящий компилятору, что все необходимые исходники нужно искать в папке src. При этом обязательно нужно указать путь до класса с методом main(). Компилятор заглянет в класс Main, чтобы узнать, какие зависимости (другие классы) в нем используются, и будет искать их, начиная с папки src и во всех ее подпапках: Если не указать -sourcepath, то возникнет ошибка компиляции. Запуск классов выполняется по следующей схеме: , где  обозначает параметры команды java, а  указывает на полное имя запускаемого класса (не путать с именем файла), содержащего метод main(). Подробнее это выглядит так: консоль по прежнему должна быть открыта в корне вашего проекта в ней напишите через пробел: команду java опцию -verbose (необязательно) опцию -cp (или -classpath), указывающую на папку с сгенерированными class-файлами и внешними библиотеками (обычно в виде отдельных файлов с расширением .jar), к которым программа должна получить доступ во время выполнения имя этой папки. В нашем случае — out полное имя класса (пакет + имя), содержащего метод main (без указания  расширения файла .class). Имя пакета необходимо записывать, используя точки Пример: Вывод: Запуск программы, состоящей из нескольких классов, ничем не будет отличаться, т. к. нужно указывать только класс, содержащий метод main(). Остальные зависимости будут найдены в папке out автоматически. Пример: Вывод: Если вы работаете над какой-то программой, и вам надоело все время прописывать пути до классов, а также параметры компиляции и запуска, то есть решение, облегчающее эту работу. Кроме того, данный способ подойдет для компиляции множества классов, когда использование * невозможно, т. к. компилировать требуется не все файлы в папке, а выборочно. Идея заключается в создании специальных файлов-аргументов, как для компиляции, так и для запуска, содержащих весь необходимый набор параметров и файлов. Компиляция выполняется по следующей схеме: , где @argfile — имя файла аргументов, которое обязательно должно начинаться с @. Обычно данный файл, предназначенный для компиляции, называют options, не указывая у него никакого расширения. В нем можно размещать любое количество имен файлов и параметров, используя как абсолютный, так и относительный путь. При этом символ подстановки * такими файлами не поддерживается. Абсолютный путь — это путь до ваших классов, начинающийся от корня файловой системы. Например, D:\Java\StartJava\src\ru\topjava\clinic\animal\Dog.java. А относительный путь — это путь до классов, начинающийся от корня проекта. В данном случае src\ru\topjava\clinic\animal\Dog.java. Если вы размещаете options-файлы в папке с java-файлами (а не в корне), то для указания адреса, например, для папки out, при использовании относительного пути, необходимо использовать следующий синтаксис ..\..\, который позволит подняться до корня проекта. Например, ..\..\..\..\out, где каждый ..\ переносит на одну папку выше в иерархии папок. Какой способ выбрать — зависит от ситуации: если предполагается, что options-файлами будут пользоваться и другие люди, то лучше использовать относительный путь. А если только вы — абсолютный. Создать options можно в любом текстовом редакторе, а размещать в папке с компилируемыми классами или в корне проекта — все зависит от необходимости и удобства. Разберем пример использования options-файла при компиляции. Например, пусть классы Dog, Person и Main, разбираемые ранее, хранятся в одной папке src/ru/topjava/animal/ Необходимо их скомпилировать, указав при этом папку для class-файлов. С использованием относительного пути: С использованием абсолютного пути: Компиляция (консоль должна быть открыта в папке с компилируемыми классами, а не в корне проекта): Можно и так (тогда в options уже не нужно перечислять файлы): Если вы работаете с терминалом, для которого символ @ является ключевым словом, например, с Windows PowerShell, то его необходимо экранировать (включая название файла), используя одинарные кавычки: Можно использовать другой вариант, поместив компилируемые классы и параметры в разные файлы (sources и options). Это позволит не писать руками компилируемые файлы, например, если их много, или они хранятся в разных пакетах, а генерировать их содержимое с помощью командной строки. При этом удобнее sources и options размещать уже в корне проекта. Для разных платформ генерация может быть следующей: Для macOS/Linux (вы можете использовать этот способ и в Windows, например, в Git Bash): Данную запись можно расшифровать так: найди (find) в папке ./src/ (и в подпапках) среди файлов (-type f) только те, которые имеют расширение .java (-name ".java"). Все, что будет найдено, помести (>) в файл sources. Посмотрим содержимое файла sources: Если вам не нужны все классы, которые хранятся в src, то следует указать путь до конкретной папки. Для Windows: Получи (dir) из папки src и из всех ее подпапок (/S) имена файлов без дополнительной информации (/B), которые имеют расширение *.java. Все что было найдено, помести (>) в файл sources. При таком подходе каждый раз, когда мы добавляем новый или удаляем существующий исходный файл, нужно перегенерировать содержимое sources. В итоге компиляция будет следующей: В Bash существует опция под названием globstar, позволяющая использовать двойной подстановочный знак ** в качестве команды для рекурсивной обработки. В Windows вы можете попробовать globstar в Git Bash. Для того чтобы посмотреть, включен ли globstar (по умолчанию он выключен), выполните следующую команду: , где shopt — это сокращение от shell options (параметры оболочки). Для его включения используйте команду: Для отключения используйте команду: После включения этой опции компиляция будет выглядеть так: Эта запись означает: пройдись по всем подпапкам в src и скомпилируй там все java-файлы. Если классы в папке src зависят друг от друга (код одной программы размещается в разных пакетах), то компилировать нужно так: Pipe (канал) — это механизм объединения нескольких команд для получения конечного результата. Для компиляции можно объединить команды find и javac: Запуск с помощью файлов-аргументов выполняется по следующей схеме: , где @argfile — имя файла аргументов, которое должно начинаться с символа @. Обычно данный файл, предназначенный для запуска, называют optionsj. Пример содержимое такого файла с использованием относительного пути: С использованием абсолютного пути: Пример запуска (консоль должна быть открыта в папке с компилируемыми классами, а не в корне проекта): При использовании пакетов на первых порах могут возникать ошибки, на поиск решения которых может уходить значительное время. Для его экономии и облегчения освоения данной темы была написана эта глава в формате “вопрос-ответ”. Общее правило: если при компиляции или запуске у вас возникают ошибки, которые не связаны с кодом, то попробуйте закомментировать строку с оператором package и повторить свои действия. Если после этого ошибка уйдет, то поиск проблемы необходимо сосредоточить на пакетах и всём, что с ними связано. А теперь перейдем к обсуждению конкретных проблем и их решению. Для разнообразия буду использовать globstar, описанный ранее. При компиляции исходников сгенерированные классы появляются в корне папки outЭто связано с тем, что вы забыли указать принадлежность классов к пакету. Напишите в начале классов package и имя пакета. Генерируемые классы появляются не в папке out, а в папке с исходникамиПричина в том, что при компиляции не была указана папка для генерируемых компилятором файлов. Необходимо использовать параметр -d и путь до папки out. При запуске выдается ошибка, что не был найден класс с main-методом (Could not find or load main class)Причиной может быть все что угодно: не указанно (или указано с опечатками) полное имя класса при запуске при запуске указывается имя class-файла (с расширением class), а не имя класса (без расширения). Компилятор будет думать, что class является частью имени класса, что не верно. Удалите class у имени файла в аргументе неверно указан путь до папки out попробуйте вместо относительного пути до классов (если используете options-файлы) использовать абсолютный. Если это сработает, то ищите проблему в относительном пути Больше подробностей по ссылке. При компиляции появляется ошибка error: <identifier> expectedДанная ошибка связана с тем, что в имени вашего пакета используются зарезервированные Java слова. Решение этого вопроса разбиралось ранее. Во время компиляции выдается ошибка error: reference to ClassName is ambiguousДанная ошибка связана с конфликтом имен, когда в рамках одного класса используются другие классы с одинаковыми именами. Из-за того, что имена одинаковые, компилятор не может понять, какой из них следует создать и использовать. В этом случае нужно явно указать полное имя класса. Рассмотрим в качестве примера три простых класса, находящихся в разных пакетах:ru.topjava.abcru.topjava.defru.topjava.ghi При этом два класса имеют одинаковое имя Message и метод print().  Скомпилируем классы из корня проекта, используя globstar: Вы можете сделать тоже самое, используя -sourcepath, если не работает globstar: Компилятор выдаст ошибку о том, что в классе импортируются два класса с одинаковыми именами, но из разных пакетов; а также что ссылка на Message неоднозначна Первая ошибка связана с тем, что в Java вы не можете импортировать два класса с одним и тем же именем. Но если мы не будем импортировать нужный нам класс, то как тогда использовать его возможности? Внимательный читатель скажет, что в одной из предыдущих глав мы рассматривали способ обращения к классам через указание его полного имени. В итоге нам нужно импортировать один любой класс (обычно, который используется чаще всего), а ко второму обращаться через его полное имя. Либо (что лучше) использовать для обоих классов полные имена, чтобы все были осведомлены, что классы с одинаковыми именами определены в разных пакетах. В итоге измененный класс будет выглядеть так: Компиляция и запуск программы на этот раз пройдет без ошибок: Существуют и другие рекомендации, позволяющие избежать этих ошибок: если повторяющиеся имена классов являются вашими, а не частью внешних библиотек, к которым у вас нет доступа, то просто переименуйте один из своих классов можно создавать промежуточные классы-обертки, которые не будут ничего делать, кроме как содержать поле экземпляра класса, имя которого дублируется В данной публикации мы подробно обсудили пакеты языка Java, процесс компиляции и запуска программ при их использовании. Надеюсь, что из статьи вы подчерпнули для себя достаточно полезной информацию по данным темам.  Java-программисты