Текст книги "Java: руководство для начинающих (ЛП)"
Автор книги: Герберт Шилдт
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 17 (всего у книги 36 страниц)
Как показывает представленный выше пример программы, во всех подклассах, производных от класса TwoDShape, метод area () должен быть непременно переопределен. Убедитесь в этом сами, попробовав создать подкласс, в котором не переопределен метод area (). В итоге вы получите сообщение об ошибке во время компиляции. Конечно, возможность создавать ссылки на объекты типа TwoDShape по-прежнему существует, и это было сделано в приведенном выше примере программы, но объявлять объекты типа TwoDShape уже нельзя. Именно поэтому массив shapes сокращен в методе main () до 4 элементов, а объект типа TwoDShape для общей двумерной геометрической формы больше не создается.
И еще одно, последнее замечание. Обратите внимание на то, что в классе TwoDShape по-прежнему присутствуют определения методов showDim () и getName () и перед их именами нет модификатора abstract. В абстрактные классы вполне допускается (и часто практикуется) включать конкретные методы, которые могут быть использованы в своем исходном виде в подклассе. А переопределению в подклассах подлежат только те методы, которые объявлены как abstract. Использование ключевого слова final
Какие бы богатые возможности ни представляли механизмы наследования и переопределения методов, иногда требуется запретить их действие. Допустим, создается класс, в котором инкапсулированы средства управления некоторым устройством. Кроме того, в этом классе пользователю может быть разрешено инициализировать устройство, чтобы воспользоваться некоторой секретной информацией. В таком случае пользователи данного класса не должны иметь возможность переопределять метод инициализации устройства. Для этой цели в Java предоставляется ключевое слово final, позволяющее без труда запретить переопределение метода или наследование класса. Предотвращение переопределения методов
Для того чтобы предотвратить переопределение метода, в начале его объявления нужно указать модификатор доступа final. Переопределять объявленные подобным образом методы нельзя. Ниже приведен фрагмент кода, демонстрирующий использование ключевого слова final для подобных целей. class А { final void meth() { System.out.println("This is a final method."); } } class В extends А { void meth() { // Ошибка! Переопределить метод нельзя. System.out.println("Illegal!") ; } }
Поскольку метод meth () объявлен как final, его нельзя переопределить в классе В. Если вы попытаетесь сделать это, возникнет ошибка при компиляции программы. Предотвращение наследования
Предотвратить наследование класса можно, указав в определении класса ключевое слово final. В этом случае считается, что данное ключевое слово применяется ко всем методам класса. Очевидно, что не имеет никакого смысла применять ключевое слово final к абстрактным классам. Ведь абстрактный класс не завершен по определению, и объявленные в нем методы должны быть реализованы в подклассах.
Ниже приведен пример класса, подклассы которого создавать запрещено. final class А { // ... } // Следующее определение класса недопустимо. class В extends А { // Ошибка! Создать подкласс от класса А нельзя. // . . . }
Как следует из комментариев к данному примеру, недопустимо, чтобы класс В наследовал от класса А, так как последний определен как final. Применение ключевого слова final к переменным экземпляра
Помимо рассмотренных ранее примеров использования, ключевое слово final можно применять и к переменным экземпляра. Подобным способом создаются именованные константы. Если имени переменной предшествует модификатор final, то значение этой переменной не может быть изменено на протяжении всего времени выполнения программы. Очевидно, что подобным переменным нужно присваивать начальные значения. В главе 6 был рассмотрен простой класс ErrorMsg для обработки ошибок. В нем устанавливается соответствие между кодами ошибок и символьными строками сообщений об ошибках. Ниже приведен усовершенствованный вариант этого класса, в котором для создания именованных констант применяется модификатор final. Теперь, вместо того чтобы передавать методу getErrorMsg () числовое значение, например 2, достаточно указать при его вызове именованную целочисленную константу DISKERR. // Возврат объекта типа String, class ErrorMsg { // Коды ошибок. // Константы объявляются с помощью ключевого слова final. final int OUTERR = 0; final int INERR = 1; final int DISKERR = 2; final int INDEXERR = 3; String msgs[] = { "Output Error", "Input Error", "Disk Full", "Index Out-Of-Bounds" }; // возвратить сообщение об ошибке String getErrorMsg(int i) { if(i >=0 & i < msgs.length) return msgs[i]; else return "Invalid Error Code"; } } class FinalD { public static void main(String args[]) { ErrorMsg err = new ErrorMsg(); // При вызове метода используются константы, // объявленные с помощью ключевого слова final. System.out.println(err.getErrorMsg(err.OUTERR)); System.out.println(err.getErrorMsg(err.DISKERR)); } }
Обратите внимание на то, как используются константы в методе main (). Они являются членами класса ErrorMsg, и поэтому для доступа к ним требуется ссылка на объект этого класса. Разумеется, константы могут быть унаследованы подклассами и непосредственно доступными в них.
Многие программирующие на Java пользуются именами констант типа final, составленными полностью из прописных букв, как в предыдущем примере. Но это не строгое правило, а только принятый стиль программирования. Класс Object
В Java определен специальный класс Object. По умолчанию он считается суперклассом всех остальных классов. Иными словами, все классы являются подклассами, производными от класса Object. Это означает, что переменная ссылки на объект типа Object может ссылаться на объект любого класса. Более того, переменная ссылки на объект типа Object может также ссылаться на любой массив, поскольку массивы реализованы в виде классов.
В классе Object определены перечисленные ниже методы, доступные в любом объекте. Метод Назначение Object clone () Создает новый объект, аналогичный клонируемому объекту boolean equals (Object объект) Определяет равнозначность объектов void finalize () Вызывается перед тем, как неиспользуемый объект будет удален системой «сборки мусора» Class> getClass() Определяет класс объекта во время выполнения int hashCode () Возвращает хеш-код, связанный с вызывающим объектом void notify() Возобновляет работу потока, ожидающего уведомления от вызывающего объекта void notifyAll() Возобновляет работу всех потоков, ожидающих уведомления от вызывающего объекта String toString() Возвращает символьную строку, описывающую объект void wait () Ожидает исполнения другого потока void wait (long миллисекунды) Ожидает исполнения другого потока void wait (long миллисекунды, int наносекунды) Ожидает исполнения другого потока
Методы getClass(), notify(), notifyAll() и wait() объявлены как final, а остальные методы можно переопределять в подклассах. Некоторые из этих методов будут описаны далее в этой книге. Два из них – equals () и toString () – заслуживают особого внимания. Метод equals () сравнивает два объекта. Если объекты равнозначны, то он возвращает логическое значение true, иначе – логическое значение false. Метод toString () возвращает символьную строку, содержащую описание того объекта, которому принадлежит этот метод. Он автоматически вызывается в том случае, если объект передается методу println() в качестве параметра. Во многих классах этот метод переопределяется. В этом случае описание специально подбирается для конкретных типов объектов, которые в них создаются.
Обратите внимание на необычный синтаксис, описывающий значение, возвращаемое методом getClass (). Это обобщенный тип. С помощью обобщений в Java можно указывать в качестве параметра тип данных, используемый в классе или методе. Более подробно обобщения рассматриваются в главе 13. Упражнение для самопроверки по материалу главы 7
Имеет ли суперкласс доступ к членам подкласса? Имеет ли подкласс доступ к членам суперкласса?
Создайте подкласс Circle, производный от класса TwoDShape. В нем должен быть определен метод area (), вычисляющий площадь круга, а также конструктор с ключевым словом super для инициализации членов, унаследованных от класса TwoDShape.
Как предотвратить обращение к членам суперкласса из подкласса?
Опишите назначение и два варианта использования ключевого слова super.
Допустим, имеется следующая иерархия классов:class Alpha { ... class Beta extends Alpha { ... Class Gamma extends Beta { ... В каком порядке вызываются конструкторы этих классов при создании объекта класса Gamma?
Переменная ссылки на суперкласс может указывать на объект подкласса. Объясните, почему это важно и как это связано с переопределением методов?
Что такое абстрактный класс?
Как предотвратить переопределение метода? И как предотвратить наследование класса?
Объясните, каким образом механизмы наследования, переопределения методов и абстрактные классы используются для поддержки полиморфизма.
Какой класс является суперклассом всех остальных классов?
Класс, который содержит хотя бы один абстрактный метод, должен быть объявлен абстрактным. Верно или не верно?
Какое ключевое слово следует использовать для создания именованной константы?
Глава 8 Пакеты и интерфейсы
Основные навыки и понятия
Применение пакетов
Влияние пакетов на доступ к членам класса
Применение модификатора доступа protected
Импорт пакетов
Представление о стандартных пакетах Java
Основные положения об интерфейсах
Реализация интерфейсов
Применение интерфейсных ссылок
Представление о переменных интерфейса
Наследование интерфейсов
Эта глава посвящена рассмотрению двух очень важных, передовых языковых средств Java: пакетов и интерфейсов. Пакет – это группа логически связанных классов. Пакеты помогают лучше организовать код и обеспечивают дополнительный уровень инкапсуляции. Интерфейс определяет набор методов, которые должны присутствовать в классе. В самом интерфейсе эти методы не реализуются, поэтому он представляет собой чисто логическую конструкцию. Пакеты и интерфейсы предоставляют дополнительную возможность для более рациональной организации программ и контроля их структуры. Пакеты
Иногда взаимозависимые части программ оказывается удобно объединить в группу. В Java для этой цели предусмотрены пакеты. Во-первых, пакет предоставляет механизм объединения взаимосвязанных частей программы. При обращении к классам, входящим в пакет, указывается имя пакета. Таким образом, пакет предоставляет средства для именования коллекции классов. И во-вторых, пакет является частью механизма управления доступом в Java. Классы могут быть объявлены как закрытые для всех пакетов, кроме того, в который они входят. Следовательно, пакет предоставляет также средства для инкапсуляции классов. Рассмотрим все эти средства более подробно.
Как правило, при именовании класса для него выделяется имя в пространстве имен. Пространство имен определяет область объявлений. В Java нельзя присваивать двум классам одинаковые имена из одного и того же пространства имен. Иными словами, в пределах пространства имен каждый класс должен иметь уникальное имя. В примерах программ, представленных в предыдущих главах, по умолчанию использовалось глобальное пространство имен. Это удобно для небольших программ, но по мере увеличения объема кода могут возникнуть конфликты имен. В крупных программах бывает нелегко выбрать уникальное имя для класса. Более того, при использовании библиотек и кода, написанного другими программистами, приходится принимать специальные меры для предотвращения конфликтов имен. Для разрешения подобных затруднений служат пакеты, позволяющие разделить пространство имен на отдельные области. Если класс определен в пакете, то имя пакета присоединяется к имени класса, в результате чего исключается конфликт между двумя классами, имеющими одинаковые имена, но принадлежащими к разным пакетам.
Пакет обычно содержит логически связанные классы, и поэтому в Java определены специальные права доступа к содержимому пакета. Так, в пакете можно определить один код, доступный другому коду из того же самого пакета, но недоступный из других пакетов. Это позволяет создавать автономные группы связанных вместе классов и делать операции в них закрытыми. Определение пакета
Каждый класс в Java относится к тому или иному пакету. Если оператор package отсутствует в коде, то используется глобальный пакет, выбираемый по умолчанию. Пакет по умолчанию не имеет имени, что упрощает его применение. Именно поэтому в рассмотренных до сих пор примерах программ не нужно было беспокоиться о пакетах. Но если пакет по умолчанию подходит для очень простых программ, служащих в качестве примера, то для реальных приложений он малопригоден. Как правило, для разрабатываемого кода приходится определять один или несколько пакетов.
Для создания пакета достаточно поместить оператор package в начало файла с исходным кодом программы на Java. В результате классы, определенные в этом файле, будут принадлежать указанному пакету. А поскольку пакет определяет пространство имен, имена классов, содержащихся в файле, войдут в это пространство имен как составные его части.
Общая форма оператора package выглядит следующим образом: package имя_пакета;
Например, приведенная ниже строка кода определяет пакет mypack. package mypack;
Для управления пакетами в Java используется файловая система, в которой для хранения содержимого каждого пакета выделяется отдельный каталог. Например, файлы с расширением . class, содержащие классы и объявленные в пакете mypack, будут храниться в каталоге mypack.
Подобно другим именам в Java, имена пакетов зависят от регистра символов. Это означает, что каталог, предназначенный для хранения пакета, должен иметь имя, в точности совпадающее с именем пакета. Если у вас возникнут затруднения при опробовании примеров программ, представленных в этой главе, проверьте соответствие имен пакетов именам каталогов. Пакеты всегда именуются прописными буквами.
В разных файлах могут содержаться одинаковые операторы package. Этот оператор лишь определяет, какому именно пакету должны принадлежать классы, код которых содержится в данном файле, и не запрещает другим классам входить в состав того же самого пакета. Как правило, пакеты реальных программ распространяются на большое количество файлов.
В Java допускается создавать иерархию пакетов. Для этого достаточно разделить имена пакетов точками. Ниже приведена общая форма оператора package для определения многоуровневого пакета. package пакет_1. пакет_2. пакет_3. . . пакет_Ы;
Очевидно, что для поддержки иерархии пакетов следует создать аналогичную иерархию каталогов. Например: package alpha.beta.gamma;
Классы, содержащиеся в данном пакете, должны храниться в структуре каталогов . . . /alpha/beta/gamma, где многоточие обозначает путь к каталогу alpha. Поиск пакета и переменная окружения CLASSPATH
Как пояснялось выше, иерархия каталогов пакетов должна отражать иерархию пакетов. В связи с этим возникает важный вопрос: как исполняющая система Java узнает, где искать созданные пакеты? Ответ на этот вопрос следует разделить на три части. Во-первых, по умолчанию исполняющая система Java обращается к текущему рабочему каталогу. Так, если поместить пакет в подкаталоге текущего каталога, он будет там найден. Во-вторых, один или несколько путей к каталогам можно задать в качестве значения переменной окружения CLASSPATH. И в-третьих, при вызове интерпретатора java и компилятора j ava с из командной строки можно указать параметр -classpath, а также путь к каталогам с классами.
Рассмотрим в качестве примера следующее определение пакета: package mypack
Для того чтобы программа могла найти пакет mypack, должно быть выполнено одно из трех условий: программа должна быть запущена из каталога, содержащего пакет mypack; в переменной окружения CLASSPATH должен храниться полный путь к каталогу с пакетом mypack; либо при запуске программы интерпретатору java должен быть передан параметр -classpath и указан путь к каталогу с пакетом mypack.
Для опробования примеров программ, представленных далее в этой книге, проще всего создать в текущем каталоге, используемом для разработки программ, структуру каталогов, предназначенных для хранения пакетов, а затем разместить файлы с расширением . class в соответствующих каталогах и далее выполнять программы из каталога, выбранного для разработки.
Во избежание каких-либо осложнений все файлы с расширением .java и .class рекомендуется хранить в том каталоге, который выделен для содержащего их пакета. Кроме того, каждый исходный файл следует компилировать из того каталога, который находится по иерархии выше каталога с пакетом. Простой пример применения пакета
С учетом всего сказанного выше, попробуем сначала написать несложную программу, использующую пакет, а затем запустить ее на выполнение. Эта программа предназначена для создания простой базы данных книг. Классы этой программы будут содержаться в пакете bookpack. // Простая программа, демонстрирующая применение пакета. // Этот файл является частью пакета bookpack. package bookpack; // Класс Book принадлежит пакету bookpack. class Book { private String title; private String author; private int pubDate; Book(String t, String a, int d) { title = t; author = a; pubDate = d; } void show() { System.out.println(title); System.out.println(author); System.out.println(pubDate); System.out.println(); } } // Класс BookDemo принадлежит пакету bookpack. class BookDemo { public static void main(String args[]) { Book books[] = new Book[5]; books[0] = new Book("Java: A Beginner's Guide", "Schildt", 2011); books[1] = new Book("Java: The Complete Reference", "Schildt", 2011); books[2] = new Book("The Art of Java", "Schildt and Holmes", 2003); books[3] = new Book("Red Storm Rising", "Clancy", 1986); books[4] = new Book("On the Road", "Kerouac", 1955); for(int i=0; i < books.length; i++) books[i].show(); } }
Присвойте файлу с приведенным выше исходным кодом имя BookDemo. j ava и поместите его в каталог bookpack.
Скомпилируйте этот исходный файл из каталога, находящегося непосредственно над каталогом bookpack, указав в командной строке следующее: javac bookpack/BookDemo.j ava
После этого попробуйте выполнить скомпилированную программу, указав в командной строке следующее: java bookpack.BookDemo
Не забывайте, что для нормального выполнения указанных выше команд текущим должен быть каталог, являющийся родительским по отношению к каталогу bookpack. (Для компиляции и запуска программы из какого-нибудь другого каталога вам придется указать путь к каталогу bookpack, используя один из двух других описанных выше способов обращения к каталогам с пакетами.)
Теперь классы BookDemo и Book принадлежат пакету bookpack. Это означает, что при вызове интерпретатора нельзя ограничиваться передачей ему только имени класса BookDemo. Приведенная ниже команда не будет выполнена, java BookDemo
Перед именем класса BookDemo следует непременно указать имя его пакета, как показано выше. Пакеты и доступ к членам классов
В предыдущих главах были представлены основные механизмы управления доступом, в том числе модификаторы private и public. И теперь самое время продолжить обсуждение вопросов управления доступом к членам классов. Ведь и пакеты принимают участие в управлении доступом.
Область действия члена класса определяется указываемым модификатором доступа: private, public или protected, хотя модификатор может и отсутствовать. На формирование области действия оказывает также влияние принадлежность класса тому или иному пакету. Таким образом, область действия члена класса определяется его доступностью как в классе, так и в пакете. Столь сложный, многоуровневый подход к управлению доступом позволяет установить достаточно обширный набор прав доступа. В табл. 8.1 описаны разные уровни доступа к членам классов. Рассмотрим каждый из них в отдельности.
Таблица 8.1. Уровни доступа к членам классов Закрытый член Член, доступный по умолчанию Защищенный член Открытый член Доступен в том же классе Да Да Да Да Доступен из подкласса в том же пакете Нет Да Да Да Доступен из любого класса в том же пакете Нет Да Да Да Доступен из подкласса в любом пакете Нет Нет Да Да Доступен из всякого класса в любом пакете Нет Нет Нет Да
Если модификатор доступа явно не указан для члена класса, он доступен только в своем пакете, но не за его пределами. Следовательно, член класса, для которого не задан модификатор доступа, является открытым в текущем пакете и закрытым за его пределами.
Члены класса, объявленные как открытые (public), доступны из классов, принадлежащих любым пакетам. На доступ к ним никаких ограничений не накладывается. А члены класса, объявленные как закрытые (private), доступны только для членов того же самого класса. Другие классы, даже принадлежащие тому же самому пакету, не могут воздействовать на них. И наконец, члены класса, объявленные как защищенные (protected), доступны для классов, находящихся в том же самом пакете, а также для подклассов данного класса, независимо от того, каким пакетам эти подклассы принадлежат.
Правила доступа, приведенные в табл. 8.1, распространяются только на члены классов. Сами же классы могут быть объявлены как открытые или же доступные по умолчанию. Если в определении класса присутствует ключевое слово public, он доступен для других классов. Отсутствие модификатора доступа означает, что класс доступен только классам, находящимся в том же самом пакете. На классы, объявленные как открытые, накладывается следующее единственное ограничение: имя файла, в котором находится исходный код класса, должно совпадать с именем класса. Пример доступа к пакету
В рассмотренном выше примере классы Book и BookDemo находились в одном и том же пакете, поэтому при организации доступа из класса BookDemo к классу Book не возникало никаких затруднений. По умолчанию все члены класса имеют право обращаться к членам других классов из того же самого пакета. Если бы класс Book находился в одном пакете, а класс BookDemo – в другом, ситуация оказалась бы немного сложнее. В этом случае доступ к классу Book по умолчанию был бы запрещен. Для того чтобы сделать класс Book доступным для других пакетов, в код программы нужно внести три изменения. Во-первых, сам класс Book должен быть объявлен открытым (public). Это позволит обращаться к нему из-за пределов пакета bookpack. Во-вторых, конструктор класса должен быть также объявлен открытым. И наконец, модификатор доступа public следует указать перед методом show (). Благодаря этому конструктор и метод show () станут доступными за пределами пакета bookpack. Следовательно, для использования класса Book в классах, принадлежащих другим пакетам, его следует объявить так, как показано ниже. // Класс Book, видоизмененный для открытого доступа, package bookpack; // Класс Book и некоторые его члены должны быть объявлены открытыми, // чтобы ими можно было пользоваться в других пакетах. public class Book { private String title; private String author; private int pubDate; // Теперь конструктор объявлен открытым, public Book(String t, String a, int d) { title = t; author = a; pubDate = d; } // Теперь метод объявлен открытым, public void show() { System.out.println(title) ; System.out.println(author); System.out.println(pubDate); System.out.println() ; } }
Для того чтобы воспользоваться классом Book в другом пакете, нужно применить оператор import, который будет рассматриваться в следующем разделе, либо указать полностью определенное имя класса, т.е. предварять имя класса именем пакета. Ниже приведен пример класса UseBook, содержащегося в пакете bookpackext. Для обращения к классу Book в нем используется полностью определенное имя этого класса. // Этот класс принадлежит пакету bookpackext. package bookpackext; // использовать класс Book из пакета bookpack. class UseBook { public static void main(String args[]) { // Перед именем класса Book указывается имя пакета bookpack. bookpack.Book books[] = new bookpack.Book[5]; books[0] = new bookpack.Book("Java: A Beginner's Guide", "Schildt", 2011); books[1] = new bookpack.Book("Java: The Complete Reference", "Schildt", 20011); books[2] = new bookpack.Book("The Art of Java", "Schildt and Holmes", 2003); books[3] = new bookpack.Book("Red Storm Rising", "Clancy", 1986); books[4] = new bookpack.Book("On the Road", "Kerouac", 1955); for(int i=0; i < books.length; i++) books[i].show(); } }
Обратите внимание на то, что при каждом обращении к классу Book перед ним указывается имя пакета bookpack. Если бы здесь не использовалось полностью определенное имя, то при компиляции класса UseBook класс Book не был бы найден. Представление о защищенных членах классов
Начинающие программисты иногда неправильно пользуются модификатором доступа protected. Как пояснялось ранее, переменные и методы, объявленные защищенными (protected), доступны для классов, находящихся в том же самом пакете, а также для подклассов данного класса, независимо от того, каким пакетам эти подклассы принадлежат. Иными словами, член класса, объявленный как protected, доступен для подклассов, но защищен от доступа за пределами пакета.
Для того чтобы стало понятнее назначение модификатора доступа protected, рассмотрим следующий пример. Сначала изменим класс Book, объявив его переменные экземпляра защищенными, как показано ниже. // Объявление защищенными переменных экземпляра в классе Book, package BookPack; public class Book { // При объявлении этих переменных использован // модификатор доступа protected. protected String title; protected String author; protected int pubDate; public Book(String t, String a, int d) { title = t; author = a; pubDate = d; } public void show() { System.out.println(title); System.out.println(author); System.out.println(pubDate); System.out.println() ; } }
Теперь создадим подкласс ExtBook класса Book, а также класс ProtectDemo, в котором будет использоваться класс ExtBook. В классе ExtBook содержится поле, предназначенное для хранения названия издательства, а также несколько методов доступа. Оба эти класса принадлежат пакету bookpackext. Их исходный код приведен ниже. // Пример применения модификатора protected, package bookpackext; class ExtBook extends bookpack.Book { private String publisher; public ExtBook(String t, String a, int d, String p) { super(t, a, d); publisher = p; } public void show() { super.show(); System.out.println(publisher); System.out.println() ; } public String getPublisher() { return publisher; } public void setPublisher(String p) { publisher = p; } /* Следующие операторы допустимы, поскольку подклассы имеют право доступа к членам класса, объявленным защищенными. */ public String getTitle() { return title; } public void setTitle(String t) { title = t; } public String getAuthor() { return author; } public void setAuthor(String a) { author = a; } public int getPubDate() { return pubDate; } public void setPubDate(int d) { pubDate = d; } } class ProtectDemo { public static void main(String args[] ) { ExtBook books[] = new ExtBook[5]; books[0] = new ExtBook("Java: A Beginner's Guide", "Schildt", 2007, "Osborne/McGraw-Hill"); books[1] = new ExtBook("Java: The Complete Reference", "Schildt", 2007, "Osborne/McGraw-Hill"); books[2] = new ExtBook("The Art of Java", "Schildt and Holmes", 2003, "Osborne/McGraw-Hill"); books[3] = new ExtBook("Red Storm Rising", "Clancy", 1986, "Putnam"); books[4] = new ExtBook("On the Road", "Kerouac", 1955, "Viking"); for(int i=0; i < books.length; i++) books[i].show(); // искать книги по автору System.out.println("Showing all books by Schildt."); for(int i=0; i < books.length; i++) if(books[i].getAuthor() == "Schildt") System.out.println (books[i].getTitle()); // Доступ к защищенному полю эа пределами подклассов не разрешается. // books[0].title = "test title"; // Ошибка: доступ запрещен! } }
Обратите внимание на код класса ExtBook. В связи с тем что класс ExtBook является подклассом, производным от класса Book, он имеет доступ к защищенным членам класса Book. Это правило действует, несмотря на то, что класс ExtBook находится в другом пакете. Следовательно, он может обращаться непосредственно к переменным экземпляра title, author и pubDate, что и было использовано при написании методов доступа. В то же время доступ к этим переменным экземпляра из класса ProtectDemo запрещен, поскольку класс ProtectDemo не является подклассом, производным от класса Book. Так, если удалить комментарии в приведенной ниже строке кода, рассматриваемая здесь программа не будет скомпилирована. // books[0].title = "test title"; // Ошибка: доступ запрещен. Импорт пакетов
При использовании класса из другого пакета необходимо полностью определять его имя, т.е. указывать перед именем класса имя пакета. Такой подход был принят в предыдущем примере. Но его соблюдение очень быстро становится утомительным для программирования, и особенно это касается глубоко вложенных пакетов. Язык Java был разработан программистами для программистов, и поэтому не удивительно, что в нем было предусмотрено более удобное средство доступа к содержимому пакета: оператор import. Используя этот оператор, можно упростить обращение к одному или нескольким членам пакета, чтобы пользоваться ими непосредственно, не указывая явно имя пакета.
Ниже приведена общая форма оператора import, import имя_пакета.имя_класса;
Если требуется импортировать все содержимое пакета, вместо имени класса следует указать звездочку (*). Ниже приведены примеры обеих форм записи оператора import. import mypack.MyClass import mypack.*;
В первом случае из пакета mypack импортируется класс MyClass, а во втором – все классы из данного пакета. В исходном файле программы на Java операторы import должны следовать сразу же после оператора package (если таковой имеется) и перед определением классов.
С помощью оператора import можно организовать доступ к пакету bookpack и воспользоваться классом Book, не прибегая к полностью определенному имени. Оператор import, разрешающий данное затруднение, помещается в начало того файла, где требуется доступ к классу Book, в следующем виде: import bookpack.*;
Например, так будет выглядеть исходный код класса UseBook, в котором используется механизм импорта пакетов: // Использование ключевого слова import, package bookpackext; // Импорт пакета bookpack. import bookpack.*; // использовать класс Book из пакета bookpack class UseBook { public static void main(String args[]) { // Теперь к членам класса Book можно обращаться непосредственно, // не указывая полностью определенное имя. Book books[] = new Book[5]; books[0] = new Book("Java: A Beginner's Guide", "Schildt", 2007); books[1] = new Book("Java: The Complete Reference", "Schildt", 2007); books[2] = new Book("The Art of Java", "Schildt and Holmes", 2003); books[3] = new Book("Red Storm Rising", "Clancy", 1986); books[4] = new Book("On the Road", "Kerouac", 1955); for(int i=0; i < books.length; i++) books[i].show(); } }