Как классы располагаться в пакете
Пакеты
1. Добавление класса в пакет
Обычно проект содержит большое количество классов и держать их в одном каталоге крайне неудобно. Кроме того, может возникнуть ситуация, когда два программиста создали класс с одинаковым названием. Для решения этих проблем в Java существует такой механизм как пакеты. Пакеты по своей сути очень похожи на каталоги файловой системы и должны совпадать с ней.
Существуют также правила для наименования пакетов. Для коммерческих проектов пакет должен начинаться с com, потом следует имя организации и название проекта. Потом пакеты обычно именуются по какому-то функциональному признаку. В примере 2 наименование пакета соответствует этому правилу.
Кроме разделения пространств имен классов, пакеты также служат для управления доступностью объектов. В пакете можно определить классы, недоступные для кода за пределами этого пакета. В нем можно также определить члены класса, доступные только другим членам этого же пакета. Благодаря такому механизму классы могут располагать полными сведениями друг о друге, но не предоставлять эти сведения остальному миру.
2. Импорт пакетов
Хорошей практикой считается добавлять классы в пакеты. Но так как полное имя класса включает в себя имя пакета, в коде это может привести к достаточно длинным строкам, что крайне неудобно. Для решения этой проблемы в Java придуман такой механизм как импорт. Оператор import позволяет импортировать класс, после чего к нему можно обращаться просто по имени.
2.1. Использование класса из другого пакета
2.2. Использование оператора import
Перепишем класс first.Example1 используя оператор import :
Разные варианты написания import:
Существует один пакет, классы которого импортируются в код по умолчанию. Это пакет jаva.lang, в котором находятся наиболее часто используемые классы.
28. Java – Пакеты
В Java пакеты (package) используются для предотвращения конфликтов с названиями, для контроля доступа, для облегчения поиска/нахождения и использования классов, интерфейсов, перечислений и аннотаций и т.д.
Пакеты можно определить как группировку связанных типов (классы, интерфейсы, перечисления и аннотации), предоставляющий защиту доступа и управление пространством имён.
Содержание
Некоторые из существующих пакетов в Java:
Программисты могут определять их пакеты для связывания групп классов/интерфейсов и т.д. Группировка связанных классов, реализованных вами, является хорошим практическим решением, т.к. программист сможет легко определить, что классы, интерфейсы, перечисления и аннотации связаны.
Так как пакет создаёт новое пространство имён, в нём не будет никаких конфликтов с именами в других пактах. Используя пакеты, легче предоставить управление доступом и легче найти связанные классы.
Создание пакета
Как создать пакет в Java? Во время создания пакета вы должны выбрать ему имя и включить оператор package вместе с этим именем поверх каждого исходного файла, который содержит классы, интерфейсы, перечисления и типы аннотаций, которые вы хотите включить в пакет.
Оператор package должен быть первой строкой в исходном файле. Может быть только один запрос package в каждом исходном файле, и он применяется ко всем типам в этом файле.
Если оператор package не использован, тогда классы, интерфейсы, перечисления и типы аннотаций будут помещены в текущий пакет по умолчанию.
Чтобы скомпилировать программы на Java с операторами package, то вам нужно использовать опцию –d, как показано ниже.
Затем в указанном месте назначения создается папка с указанным именем пакета, а файлы скомпилированных классов будут помещены в эту папку.
Пример 1
Давайте взглянем на пример, которые создаёт пакет под названием animals. Полезно использовать имена пакетов с маленькой буквы, чтобы избежать конфликтов с именами классов и интерфейсов.
В следующем примере пакета содержится интерфейс с названием animals.
Теперь давайте реализуем вышеприведённый интерфейс в этом же пакете animals:
А сейчас скомпилируем java-файлы, как показано ниже:
Теперь пакет/папка с именем animals будет создана в текущей директории, и файлы классов будут помещены в неё.
Вы можете запустить файл класса внутри пакета и получить результат, указанный ниже.
Ключевое слово import
Если класс хочет использовать другой класс в том же пакете, то не нужно использовать имя пакета. Классы в одном пакете могут найти друг друга без особого синтаксиса.
Пример 2
Итак, класс под названием Boss добавлен в пакет payroll, который уже содержит Employee. Boss может обратиться к классу Employee без использования префикса payroll, как показано в следующем классе Boss.
Что произойдёт, если класс Employee не будет включен в пакет payroll? Тогда класс Boss должен будет использовать одну из следующих техник для обращения к классу в другом пакете:
Примечание: Файл класса может содержать любое количество операторов импорта (import). Операторы импорта (import) должны появляться после оператора пакета (package) и перед объявлением класса.
Структура директории пакетов
Происходят два явления, когда класс помещён в пакет:
Есть лёгкий способ работы с вашими файлами в Java:
Теперь поместите исходный файл в директорию, имя которой отражает имя пакета, к которому принадлежит класс:
Полноценное имя класса и пути будет выглядеть так:
В общем, компания использует своё обратное доменное имя в Интернете для своих именований пакетов в Java.
Например: доменное имя компании называется apple.com, тогда все имена их пакетов будут начинаться с com.apple. Каждый компонент имени пакета соответствует поддиректории.
Например: у компании есть пакет com.apple.computers, в котором содержится исходный файл Dell.java, тогда он содержится в серии поддиректорий, как указано здесь:
Теперь скомпилируйте это, используя опцию –d:
Файлы скомпилируются следующим образом:
Вы можете импортировать все классы и интерфейсы, определённые в \com\apple\computers\ вот так:
Делая так, становится возможным предоставить доступ к директории классов другим программистам, не раскрывая ваши источники. Вам также нужно распределить файлы классов и источников таким образом, чтобы компилятор и Java Virtual Machine (JVM) могли найти все типы, которые использует ваша программа.
Полный путь к директории классов
Путь класса может включать несколько путей. Множество путей должны быть отделены точкой с запятой (Windows) или двоеточием (Unix). По умолчанию компилятор и JVM ищут текущую директорию и JAR-файл, содержащий классы платформы Java, чтобы эти директории были автоматически включены в путь класса.
Установить системную переменную CLASSPATH
Чтобы отобразить текущую CLASSPATH переменную, используйте следующие команды в Windows и UNIX (Bourne shell):
Чтобы удалить содержимое переменной CLASSPATH, используйте:
Чтобы установить системную переменную CLASSPATH:
Пакеты, модификаторы конструкторов и классов
На предыдущем занятии мы с вами рассмотрели модификаторы доступа у переменных класса и его методов, используя ключевые слова public и private. Но их также можно прописывать у классов и конструкторов. Давайте посмотрим как это повлияет на работу и объявление классов.
Начнем с конструкторов. Если не указан ни один из модификаторов, то, как мы говорили, используется модификатор по умолчанию и конструктор доступен из любого другого класса в пределах пакета (о пакетах мы еще будем говорить). Если же нам нужно описать класс так, чтобы его можно было создавать и в других пакетах, то перед его именем обязательно следует прописать модификатор public:
Здесь два конструктора с публичным уровнем доступа, поэтому экземпляры класса Rect можно создавать всюду без ограничений. Давайте теперь один из конструкторов сделаем приватным, закрытым и посмотрим что из этого получится:
Смотрите, теперь объект класса Rect можно создать только через второй публичный конструктор, передавая четыре аргумента. Первый конструктор больше недоступен и создать экземпляр класса без аргументов уже нельзя. Это часто используется на практике, когда один из конструкторов используется исключительно для начальной обработки данных и разработчик класса предполагает его вызов только из других конструкторов этого же класса. Например, так:
Вот так можно управлять способом создания объектов через модификаторы доступа у конструкторов.
Давайте теперь посмотрим, как влияют модификаторы при определении классов. Опять же, если перед классом нет никакого модификатора, то используется модификатор по умолчанию. И в нашем примере класс Rect имеет такой модификатор. Попробуем для начала прописать модификатор private. Смотрите, при выполнении программы выдается сообщение, что такой модификатор для внешнего класса недопустим. И действительно, ключевое слово private означает сокрытие данных внутри класса, а у нас класс записан как самостоятельная конструкция. Но, если бы класс был вложен в другой класс, например, вот так:
то такой модификатор бы уже имел смысл и обращение к Point было бы возможно только внутри класса Main.
Давайте теперь у класса Rect пропишем модификатор public:
Снова возникает ошибка. Она связана с тем, что согласно спецификации языка Java каждый публичный (открытый) класс должен быть объявлен в своем отдельном файле. Причем, название файла должно совпадать с названием класса. Создадим новый файл с именем Rect.java в том же каталоге javacourse, что и файл Main.java и перенесем туда определение класса Rect. Теперь, как видите, все работает без проблем. Вот это следует иметь в виду при объявлении новых классов. Как правило, каждый из них прописывается в своем отдельном файле с модификатором public, а затем, используется в любом другом классе текущего пакета. Кстати, в нашем случае, модификатор public у класса Rect можно убрать и все тоже будет работать, т.к. оба файла: Main.java и Rect.java находятся в одном пакете.
Пакеты
Я уже много раз произнес это слово «пакет» и пора конкретизировать, что это такое и как с ними работать. Как правило, пакет – это файловый каталог, где располагаются файлы с определениями классов языка Java. Например, текущая программа относительно каталога src расположена в подкаталоге:
Вот этот подкаталог и есть имя пакета, который на уровне языка Java принимает вид:
Именно это указывается после директивы package в каждом файле этого пакета:
То есть, эта строчка говорит компилятору, что текущий файл (и все что в нем определено) принадлежит пакету com.javacourse. Поэтому в нашем проекте оба класса Main и Rect относятся к одному и тому же пакету.
Ну, хорошо, но зачем все-таки нужны эти пакеты? Почему бы просто не хранить все файлы в одном каталоге проекта и не «заморачиваться» с этими пакетами? По сути, они решают одну важную задачу: устранения конфликтов имен между классами, интерфейсами и другими возможными конструкциями языка Java. Что это за конфликт имен? Смотрите, если какой-то большой проект выполняют несколько программистов независимо друг от друга, то с высокой вероятностью возможна ситуация, когда они будут использовать одинаковые имена классов. И потом, то привело бы к ошибке при сборке всего проекта. Но этого легко избежать, если каждый программист будет выполнять работу в рамках своего пакета, имя которого задаст ответственный исполнитель. Это основная причина применения пакетов в Java.
указывающая, что файл принадлежит пакету example.
Чтобы теперь воспользоваться классом MyClass из пакета example, в файле Main.java пакета com.javacourse следует воспользоваться директивой import:
Она разрешает использование всех классов, определенных в пакете example. И, далее, в функции main() мы можем создать экземпляр класса MyClass:
Если строчку с импортом поместить в комментарии, то доступ к классу MyClass возможен только с явным указанием пакета, в котором он расположен:
Фактически, директива import объединяет классы пакета example с текущим файлом Main.java. Если же нам нужно импортировать только какой-то один класс из пакета, то вместо звездочки следует прописать этот класс:
Другие классы (если они есть) импортированы не будут. Наконец, смотрите, если у класса MyClass убрать модификатор public, то будет применен модификатор доступа по умолчанию и это приведет к ошибке при импорте этого класса в другом пакете. А вот класс Rect без модификатора public импортируется без проблем, т.к. находится в том же пакете, что и класс Main. Вот в этом ключевое отличие модификатора public для классов от модификатора по умолчанию.
Подвиг 1. Объявите класс для хранения информации по телевизорам с полями: марка, размер диагонали, год производства, цена. Доступ к данным реализовать через сеттеры и геттеры. Определить минимум два конструктора: первый должен только инициализировать данные, другие – создавать новый объект с разными аргументами. Запретить создавать объект без аргументов.
Подвиг 2. В отдельном файле текущего пакета объявить класс для описания шкафов с полями: габариты, тип шкафа, цена, производитель, год производства. Прописать геттеры и сеттеры для доступа к полям класса. Добавить конструкторы для создания объектов. Запретить создавать объект без указания аргументов. Добавить метод для вычисления объема шкафа по его габаритам. В основном классе (в функции main()) создать несколько экземпляров класса шкафов и вывести в консоль их габариты и объемы.
Подвиг 3. Создать новый пакет и определить в нем класс Chair для описания стульев с полями: габариты, цена, производитель, год производства. Доступ к данным реализовать через сеттеры и геттеры. Добавить метод вычисления объема стула по его габаритам. В основном классе проекта (в функции main()) импортировать этот класс, создать несколько его экземпляров и вывести габариты и объемы стульев в консоль.
Видео по теме
#11 Концепция объектно-ориентированного программирования (ООП)
BestProg
Содержание
Поиск на других ресурсах:
1. Пакеты в Java
Пакеты могут иметь разнообразные уровни вложения (подкаталоги, подпапки). На разных уровнях вложения пакетов имена могут повторяться. Сохранение пакетов и файлов *.java в проекте осуществляется в виде древовидной структуры файловой системы.
2. Как подключить пакет к существующему проекту в Java Eclipse? Структура проекта, который содержит пакеты
В системе Java Eclipse подключение пакета есть стандартной командой. Предварительно может быть создан проект. В проекте может размещаться произвольное количество пакетов. В каждом пакете может быть произвольное количество классов.
Для создания пакета в некотором проекте используется команда
В результате откроется окно, изображенное на рисунке 1. В окне указывается имя проекта и пакета, который будет размещаться в этом проекте.
3. Какая общая форма вызова класса из пакета? Пример
Чтобы обратиться к имени класса из пакета используется следующая общая форма:
Подобным образом формируется доступ к классу в случае более более сложных уровней вложения.
4. Пример, который демонстрирует использование одного имени класса в разных пакетах и в разных каталогах (папках)
На рисунке 2 изображена иерархия, которую могут образовывать пакеты.
Директива import позволяет сократить весьма длинные строки обращений к классам (интерфейсам, перечислениям), которые реализованы в пакетах.
В простейшем случае общая форма директивы import следующая:
Чтобы из любого другого класса, который размещается в другом пакете данного проекта, иметь доступ к методам файла Circle.java из пакета Figures нужно в начале указать:
Ниже приводится пример подключения и использования класса Circle из другого пакета и другого класса.
Если в пакете OtherPackage убрать строку
то объект класса Circle нужно было бы создавать следующим образом
6. Как в директиве import указать, что могут быть использованы все классы из данного пакета?
Бывают случаи, когда в пакете реализованы несколько классов (файлов с расширениями *.java ) и возникает необходимость подключения всего множества классов. В этом случае общая форма директивы import может быть следующая:
8. Что такое компилированный модуль в Java?
Каждый компилированный модуль может содержать не большее одного открытого класса. Компилированный модуль входит в состав пакета. В пакете может быть любое количество компилированных модулей.
К реализации компилированного модуля предъявляются следующие требования:
10. Сколько классов могут быть реализованы в компилированном модуле?
Компилированный модуль может иметь любое количество классов. Однако, открытым ( public ) должен быть только один класс. Имя этого класса должно совпадать с именем компилированного модуля.
Использование ключевых слов package и import позволяет удобно поделить пространство имен таким образом, чтобы предотвратить возникновению конфликтов между разными разработчиками классов на Java.
13. Пример, который демонстрирует структуру проекта и размещение компилированных модулей
Рис. 3. Отображение структуры проекта Project03 в окне Package Explorer
таким образом, получается полное имя модуля Circle.java :
По желанию путь к каталогу (папке) по умолчанию можно изменить.
14. Пример подключения класса из стандартной библиотеки Java
Чтобы обратиться к имени класса из стандартной библиотеки Java используется один из двух способов:
Полная форма обращения к имени нужного класса в простейшем случае выглядит так
В вышеприведенном коде происходит обращение к классу Vector по полному имени:
Пакеты Java – назначение и использование
Пакеты Java – это механизм для группировки классов, которые связаны друг с другом, в одну и ту же «группу» (пакет). Когда проект становится больше, например, приложение или API, полезно разделить код на несколько классов, а классы – на несколько пакетов. Тогда становится легче выяснить, где находится определенный класс, который вы ищете.
Пакет подобен каталогу в файловой системе. На самом деле на диске он является каталогом. Все исходные файлы и файлы классов, принадлежащих одному и тому же пакету, находятся в одном каталоге.
Могут содержать подпакеты. Таким образом, могут составлять так называемую структуру пакета, похожую на структуру каталогов. Это дерево пакетов, подпакетов и классов внутри этих классов. Организована как каталоги на вашем жестком диске или как каталоги внутри zip-файла (JAR-файлы).
Вот скриншот примера структуры:
Вверху вы видите каталог с именем “src”. Это исходный корневой каталог. Это не сам пакет. Внутри этого каталога все подкаталоги соответствуют пакетам. Таким образом, «коллекции», «com», «параллелизм» и т. д. – это все пакеты (которые также являются каталогами на диске). На снимке экрана выше они показаны значком папки.
Расширено два пакета подуровня, чтобы вы могли видеть классы внутри. Классы проиллюстрированы с помощью маленького синего круга с буквой C внутри, на скриншоте выше.
Полный путь к подпакету – это его имя со всеми именами пакетов-предков, разделенных точками. Например, полный путь к «навигационному» подпакету:
Точно так же полное имя класса включает имя его пакета. Например, полное имя класса «Page»:
Создание структуры
Чтобы создать пакет, вы должны сначала создать корневой каталог на вашем жестком диске. Он сам по себе не является частью структуры пакета. Содержит все исходные коды, которые должны войти в структуру.
Создав исходный корневой каталог, вы можете начать добавлять в него подкаталоги. Каждый подкаталог соответствует пакету. Вы можете добавить подкаталоги в подкаталоги, чтобы создать более глубокую структуру.
Добавление классов
Чтобы добавить классы, вы должны сделать две вещи:
Первый пункт довольно прост. Создайте корневой каталог источника и внутри него создайте каталоги для каждого пакета и подпакета рекурсивно. Поместите файлы классов в каталог, соответствующий пакету, в который вы хотите добавить его.
Когда вы поместили свой исходный файл в правильный каталог (соответствующий пакету, к которому должен принадлежать класс), вы должны объявить внутри этого файла класса, что он принадлежит этому пакету:
Первая строка в приведенном выше коде – это то, что объявляет класс Page принадлежащим к com.blog.navigation.
Соглашения об именах
Пакеты всегда пишутся строчными буквами. В отличие от классов, где первая буква обычно является заглавной.
Чтобы избежать создания пакетов с такими же именами, как у других общедоступных, рекомендуется начинать иерархию с обратного доменного имени вашей компании. Например, поскольку доменное имя компании – blog.com, надо начать со структуры с именем com.blog. Другими словами, пакет верхнего уровня с именем com с подпакетом внутри называется blog.
Импорт
Если класс A должен использовать класс B, вы должны ссылаться на класс B внутри класса A. Если классы A и B находятся в одном и том же пакете, компилятор будет принимать ссылки между двумя классами:
Если классы A и B находятся в одном и том же пакете, проблем с кодом выше нет. Однако, если класс A и B находятся в разных, класс A должен импортировать класс B, чтобы использовать его:
Это первая строка в примере, которая импортирует класс B. В примере предполагается, что класс B находится в пакете с именем anotherpackage.
Если бы класс B находился в подпакете другого пакета, вам пришлось бы перечислить полный путь пакета и подпакета к классу B. Например, если бы класс B находился в пакете anotherpackage.util, то оператор import выглядел бы так:
Импорт всех классов из другого пакета
Если вам нужно использовать много классов из определенного пакета, их импорт по одному приводит к большому количеству операторов импорта. Можно импортировать все классы, используя символ * вместо имени класса:
Использование классов через определенное имя
Можно использовать класс из другого пакета, не импортируя его с помощью оператора импорта. Вы можете написать полное имя его, а не просто имя самого класса. Полное имя класса состоит из полного пути пакета до подкласса, содержащего класс, а также самого имени класса. Полное имя класса – это то, что вы написали бы в операторе импорта. Например:
Вы можете использовать это полное имя класса для ссылки на класс TimeUtil внутри другого класса, например так:
Пакетное разделение
Официального стандарта для этого нет, но есть два широко используемых метода.
Разделить на слои
Первый метод состоит в том, чтобы разделить классы после определения, к какому «слою» приложения они принадлежат. Например, ваше приложение может иметь слой базы данных. Тогда вы создадите пакет базы данных. Все классы, участвующие в обмене данными с базой данных, будут расположены в нем.
Разделить по функциональности приложения
Второй метод – разделить ваши классы в зависимости от того, к какой части функциональности приложения они принадлежат. Таким образом, если ваше приложение имеет функциональную область, которая рассчитывает пенсии, вы можете создать пакет с именем pension. Все классы, так или иначе участвующие в пенсионных расчетах, будут включены в него (или подпакеты, если число классов в пенсии станет большим).
В сочетании с доменным именем структура для пенсионного пакета будет:
Всего три пакета, два вложенных в другие.
Метод «деления по функциональности приложения» имеет тенденцию работать лучше, чем «деление по слоям», поскольку в вашем приложении растет число классов.
Вместо того, чтобы иметь фиксированное количество пакетов слоев, число которых продолжает расти, вы получаете растущее число пакетов функциональности приложения с меньшим количеством классов внутри.
Встроенные
Платформа поставляется с множеством встроенных пакетов. Они содержат классы для самых разных целей, которые часто нужны программистам, например, чтение и запись файлов с локального жесткого диска, отправка и получение данных по сетям и Интернету, подключение к базам данных и многое, многое другое.