Читать книгу «Объектно-ориентированное программирование на Java. Платформа Java SE» онлайн полностью📖 — Тимура Машнина — MyBook.

Пакеты


Давайте рассмотрим концепцию пакета, которая позволяет программистам лучше структурировать свои программы, что облегчает их понимание и управление.

В большом приложении классов создается тысячи и десятки тысяч.

Поэтому возникает вопрос: Если классов много, их все в одном каталоге держать? И как потом с ними разбираться?

Конечно же необходим некий механизм упорядочивания.

И такой механизм создан.

Причем достаточно простой и очевидный – каталоги.

Мы уже привыкли, что на диске наши файлы лежат в разных каталогах, которые мы сами организовываем в удобном порядке.

В Java сделано тоже самое – физически класс кладется в определенный каталог файловой системы, представляющий собой пакет.

Существует даже некоторые правила именования этих каталогов или пакетов.



Например, для коммерческих проектов каталог должен начинаться сначала с префикса «com» а за ним следует название компании или доменное имя компании – например «mycompany».

Далее следует название проекта.

Потом уже идет более точное разделение по какому-либо признаку – чаще всего функциональному.

Пакет в Java представляет собой группу связанных классов и интерфейсов, которые имеют схожие свойства.

Это абстрактная концепция, и это ответственность программиста, чтобы правильно организовать различные классы в пакеты.

Обычно классы, сгруппированные в один и тот же пакет, имеют сходную семантику.

Например, представьте, что у вас есть класс Car.



И он может быть частью пакета с именем transport, который также может содержать другие классы, такие как самолет или поезд.

Пакеты можно подразделить на подпакеты в зависимости от степени абстракции, которую хочет программист, формирующий иерархию пакетов.

Таким образом, наш предыдущий пакет транспорт мог быть разделен на подпакеты наземного транспорта и воздушного транспорта для представления физической среды транспорта.



Подумайте о том, какие классы будут храниться в каждом подпакете.

Когда вы создаете новую программу, очень полезно организовать различные классы и интерфейсы в пакеты, чтобы упростить ваш проект.

Таким образом, вы упрощаете использование классов и интерфейсов.

Далее, мы рассмотрим стандартную библиотеку Java, которая хорошо структурирована на пакеты и подпакеты.

Хорошо, но когда мы пишем новый класс, как мы можем определить, какой класс принадлежит к какому пакету?

Это очень просто.

В верхней части исходного кода класса вы добавляете слово package, за которым следует имя пакета.

Помните, что определение пакета должно быть первым выражением в исходном файле.

Имя пакета определяется программистом.

Это имя должно быть в нижнем регистре, чтобы избежать конфликтов с именами классов и интерфейсов, и не может быть одним из слов, зарезервированных Java, таким как main, for или string.

И подпакеты задаются с использованием символа точки.

Таким образом, для создания пакета, нам нужно в файловой системе создать каталоги и подкаталоги, например, каталог transport и подкаталог air.



Затем поместить в них файлы классов и интерфейсов.

И затем указать в каждом классе и интерфейсе вверху директиву package с именами каталогов и подкаталогов, разделенными точками, то есть путем где находится файл класса или интерфейса.

При написании новых программ вам может потребоваться доступ к некоторым классам и интерфейсам из определенного пакета.

В этом случае вы должны заранее импортировать такие классы.

Этот импорт должен быть размещен сверху исходного кода класса, сразу после объявления пакета класса, используя слово импорт.



За оператором импорта должен следовать весь путь пакета, вместе с классом, который вы хотите импортировать.

И это будет полное квалифицированное имя класса – имя класса вместе с именем его пакета.

Если вы хотите импортировать все классы в пакете, вы можете использовать символ звездочки.

Таким образом, вы сможете получить доступ ко всем публичным полям и методам этих классов.

Полное имя класса – весьма важный момент.

Разделение классов по пакетам служит не только для удобства, но решает еще одну важную задачу – уникальность имен классов.

Наверняка в большом проекте будет участвовать много людей и каждый будет писать свои классы.

И наверняка имена этих классов нередко будут одинаковые.

И скорее всего вы будете подключать сторонние библиотеки и в них будут классы, которые будут называться так же как ваши.

Единственным спасением различать их – это поместить в разные пакеты.

Таким образом, как правило, программа состоит из нескольких пакетов.

И каждый пакет имеет собственное пространство имен для классов и интерфейсов, объявленных в пакете.

И пакеты образуют иерархическую структуру имен.

При этом полные имена классов и интерфейсов, то есть их имена с учетом пакетов, должны быть уникальными.

И для доступа из одного пакета к другим пакетам используется ключевое слово import.

Также пакеты могут быть безымянными.

Классы и интерфейсы безымянного пакета не содержат объявления пакета.

И безымянные пакеты следует использовать только в небольших тестовых программах.

Также в Java можно использовать статический импорт для доступа к статическим методам и полям класса.



Например, в этом выражении, методы pow и sqrt являются статическими, поэтому они должны быть вызваны с указанием имени их класса – Маth.

И это приводит к достаточно громоздкому коду.

Этих неудобств можно избежать, если воспользоваться статическим импортом.

При этом имена методов sqrt и pow становятся видимыми благодаря оператору статического импорта.

Также, с помощью звездочки, можно импортировать все остальные статические члены класса Math, не указывая их по одному.

Каким бы удобным ни был статический импорт, очень важно не злоупотреблять им, чтобы избежать конфликта имен, например, если вы определите в своем классе свой метод pow.

Теперь, когда мы узнали, что классы группируются в пакеты, и мы знаем, что методы и поля класса могут быть публичными и приватными, пора сказать, что методы и поля класса также могут быть защищенными, это ключевое слово protected, и приватными в пакете, это отсутствие всякого ключевого слова.



Публичный член класса виден везде без ограничений.

Защищенный член класса, protected, виден в пределах своего пакета, а также подклассом класса, даже если подкласс принадлежит другому пакету.

Если нет никакого ключевого слова, член класса виден только в пределах своего пакета.

И приватный член класса виден только в пределах своего класса.

Абстрактные классы vs Интерфейсы


Теперь давайте вернемся немного назад и рассмотрим наследование разных объектов.

Предположим у нас есть эта иерархия.



Вверху иерархии у вас есть что-то более общее, например, позвоночные, а затем, когда вы спускаетесь вниз, все становится более конкретным.

Таким образом, в самом низу у вас есть наиболее специфический уровень.

В некоторых деревьях наследования, поскольку все становится более общим, объекты как бы перестают восприниматься как реальные экземпляры.

Как что такое объект рыбы?

Существует много разных видов рыб, и это слишком общее, чтобы действительно существовало в природе.

Поэтому, для представления таких объектов и вводится понятие абстрактный.

Абстрактные методы – это определение метода в суперклассе, но они не имеют реальной реализации.

Это только заголовок метода.

Что это такое, так это контракт между суперклассом и подклассом.

Как суперкласс, я диктую, что должен реализовывать подкласс.

Чтобы сделать это, вы помещаете ключевое слово abstract и затем заголовок метода с типом возврата и параметрами.

Вам также не нужно устанавливать видимость метода – публичный он или приватный, потому что вы решите это в подклассе.

Как только у вас появятся абстрактные методы в определении класса, значит вы создали абстрактный класс.

Теперь, если у вас есть ключевое слово abstract где угодно, внутри этого класса, вы должны добавить слово abstract в заголовок класса.

Теперь, когда вы используете абстрактный класс и когда вы используете интерфейс?



В конечном счете, абстрактный класс – это просто обычный суперкласс, к которому вы добавляете некоторое поведение.

Это похоже на добавление интерфейса к существующему суперклассу.

Итак, вы используете абстрактный класс, когда вам нужно совместно использовать код и гарантировать поведение в близко связанных классах.

Так как абстрактный класс объявляет общую функциональность для семейства связанных классов.

Вы также используете абстрактный класс, если у вас есть специфические подклассы, которые должны расширять общие классы.

Вы будете использовать интерфейс, когда вы хотите гарантировать поведение несвязанные классов.

С помощью интерфейсов вы также можете использовать дополнительное наследование, если у вас уже есть расширение класса и вы уже использовали ваше основное наследование.

Конец ознакомительного фрагмента.