Пакеты и интерфейсы


Содержание

Программирование на языке JAVA — Пакеты и интерфейсы

Пакет (package) — это некий контейнер, используется который для того, чтобы изолировать классов имена. Например, вы можете создать класс заключить, List его в пакет и не думать после возможных о этого конфликтах, которые могли бы возникнуть кто бы если-нибудь еще создал класс с List именем.

Интерфейс это явно указанная набора спецификация методов, которые должны быть классе в представлены, который реализует эту спецификацию. этих же Реализация методов в интерфейсе отсутствует. Подобно классам абстрактным интерфейсы обладают замечательным дополнительным можно — их свойством многократно наследовать. Конкретный класс быть может наследником лишь одного суперкласса, но нем в зато может быть реализовано неограниченное интерфейсов число.

Все идентификаторы, которые мы до пор сих использовали в наших примерах, располагались в том и одном же пространстве имен (name space). означает Это, что нам во избежание конфликтных приходилось ситуаций заботиться о том, чтобы у каждого было класса свое уникальное имя. Пакеты — механизм это, который служит как для пространством с работы имен, так и для ограничения каждого. У видимости файла .java есть 4 одинаковых части внутренних, из которых мы до сих пор в наших использовали примерах только одну. Ниже приведена форма общая исходного файла Java.

одиночный package оператор (необязателен)

любое количество операторов необязательны (import)

одиночное объявление открытого (public) любое

класса количество закрытых (private) классов необязательны (пакета)

Первое, что появиться может в исходном файле Java — это package оператор, который сообщает транслятору, в каком должны пакете определяться содержащиеся в данном файле Пакеты. классы задают набор раздельных пространств которых, в имен хранятся имена классов. Если package оператор не указан, классы попадают в безымянное имен пространство, используемое по умолчанию. Если вы объявляете как, класс принадлежащий определенному пакету, например,

то и исходный код класса этого должен храниться в каталоге java/image/awt.

Каталог, который транслятор будет Java рассматривать, как корневой для пакетов иерархии, можно задавать с помощью переменной СLASSPATH окружения. С помощью этой переменной можно несколько задать корневых каталогов для иерархии через (пакетов ; как в обычном PATH).

Трансляция пакетах в классов

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

Представьте себе, написали вы что класс с именем PackTest в пакете создаете. Вы test каталог test, помещаете в этот файл каталог PackTest.Java и транслируете. Пока — порядке в все. Однако при попытке запустить получаете вы его от интерпретатора сообщение «can’t find PackTest class» («He могу найти класс PackTest»). новый Ваш класс теперь хранится в пакете с test именем, так что теперь надо всю указывать иерархию пакетов, разделяя их имена test — точками.PackTest. Кроме того Вам либо надо подняться на уровень выше в иерархии снова и каталогов набрать «java test.PackTest», внести либо в переменную CLASSPATH каталог, который вершиной является иерархии разрабатываемых вами классов.

После оператора package, но до любого классов определения в исходном Java-файле, может список присутствовать операторов import. Пакеты являются механизмом хорошим для отделения классов друг от поэтому, друга все встроенные в Java классы пакетах в хранятся. Общая форма оператора import import:

такова пакет1 [.пакет2].(имякласса|*);

Здесь имя — пакет1 пакета верхнего уровня, пакет2 — необязательное это имя пакета, вложенного в первый отделенное и пакет точкой. И, наконец, после указания иерархии в пути пакетов, указывается либо имя либо, класса метасимвол звездочка. Звездочка означает, если, что Java-транслятору потребуется какой-класс либо, для которого пакет не указан должен, он явно просмотреть все содержимое пакета со вместо звездочкой имени класса. В приведенном ниже кода фрагменте показаны обе формы использования import оператора :

Но использовать без нужды записи форму оператора import с использованием звездочки не это, т.к. рекомендуется может значительно увеличить время кода трансляции (на скорость работы и размер программы влияет не это).

Все встроенные в Java классы, входят которые в комплект поставки, хранятся в пакете с java именем. Базовые функции языка хранятся во пакете вложенном java.lang. Весь этот автоматически пакет импортируется транслятором во все программы. эквивалентно Это размещению в начале каждой программы import

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

class MyDate extends Java.Date.util

Java предоставляет уровней несколько защиты, обеспечивающих возможность тонкой области настройки видимости данных и методов. Из-за наличия Java пакетов должна уметь работать еще с категориями четырьмя видимости между элементами классов :

том в Подклассы же пакете.

Не подклассы в том же пакете.

различных в Подклассы пакетах.

Классы, которые не являются входят и не подклассами в тот же пакет.

В языке Java три имеется уровня доступа, определяемых ключевыми private: словами (закрытый), public (открытый) и protected (которые), защищенный употребляются в различных комбинациях. Содержимое таблицы ячеек определяет доступность переменной с данной модификаторов комбинацией (столбец) из указанного места (строка).

На взгляд первый все это может показаться сложным чрезмерно, но есть несколько правил, которые вам помогут разобраться. Элемент, объявленный public, любого из доступен места. Все, что объявлено доступно, private только внутри класса, и нигде Если. больше у элемента вообще не указан модификатор доступа уровня, то такой элемент будет виден из классов и подклассов того же пакета. Именно такой доступа уровень используется в языке Java по умолчанию. хотите же вы Если, чтобы элемент был доступен пакета извне, но только подклассам того класса, принадлежит он которому, вам нужно объявить такой protected элемент. И наконец, если вы хотите, чтобы был элемент доступен только подклассам, причем того от независимо, находятся ли они в данном пакете нет или — используйте комбинацию private protected.

приведен Ниже довольно длинный пример, в котором все представлены допустимые комбинации модификаторов уровня исходном. В доступа коде первого пакета определяется класса три: Protection, Derived и SamePackage. В первом из классов этих определено пять целых переменных — по каждую на одной из возможных комбинаций уровня доступа. приписан n Переменной уровень доступа по умолчанию, n_pri — private уровень, n_pro — protected, n_pripro — private pub и n_protected — public. Во всех остальных классах мы использовать пытаемся переменные первого класса. Те строки которые, кода из-за ограничения доступа привели бы к ошибкам трансляции при, закомментированы с помощью однострочных комментариев (//) — каждой перед указано, откуда доступ при комбинации такой модификаторов был бы возможен. Второй Derived — класс — является подклассом класса Protection и том в расположен же пакете р1. Поэтому ему доступны перечисленные все переменные за исключением n_pri. Третий SamePackage, класс, расположен в том же пакете, но при является не этом подклассом Protection. По этой причине него для недоступна не только переменная n_pri, но и n_уровень, pripro доступа которой — private protected.

package class Protection <

private pri n_int = 2;

protected int n_pro = 3;

private int protected n_pripro = 4;

Интерфейсы в Java и немного о полиморфизме

Интерфейс – это контракт, в рамках которого части программы, зачастую написанные разными людьми, взаимодействуют между собой и со внешними приложениями. Интерфейсы работают со слоями сервисов, безопасности, DAO и т.д. Это позволяет создавать модульные конструкции, в которых для изменения одного элемента не нужно трогать остальные.

Новички часто спрашивают, чем интерфейс отличается от абстрактного класса. Интерфейсы в Java компенсируют отсутствие множественного наследования классов. У класса-потомка может быть только один абстрактный класс-родитель, а вот интерфейсов класс может применять (имплементировать) сколько угодно.

Интерфейс на Java объявляют примерно так же, как и класс:

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

Методы по умолчанию впервые появились в Java 8. Их обозначают модификатором default. В нашем примере это метод say_goodbye, реализация которого прописана прямо в интерфейсе. Дефолтные методы изначально готовы к использованию, но при необходимости их можно переопределять в применяющих интерфейс классах.

Функциональный интерфейс Java

Если у интерфейса только один абстрактный метод, перед нами функциональный интерфейс. Его принято помечать аннотацией @FunctionalInterface, которая указывает компилятору, что при обнаружении второго абстрактного метода в этом интерфейсе нужно сообщить об ошибке. Стандартных (default) методов у интерфейса может быть множество – в том числе принадлежащих классу java.lang.Object.

Как выглядит функциональный интерфейс на Java:

Функциональные интерфейсы появились в Java 8. Они обеспечили поддержку лямбда-выражений, использование которых делает код лаконичным и понятным:

В той же версии появились пакеты встроенных интерфейсов: java.util.function и java.util.stream.

Реализация интерфейсов классами Java

Допустим, есть интерфейс Edible, которым пользуются классы Fruit, Vegetable, Fish. Экземпляры этих классов можно создавать так:

Хорошим тоном считается давать интерфейсам названия с окончанием -able/-ible — это показывает, что с объектами, имплементирующими интерфейс, можно что-то делать: Edible (можно есть), Moveable (можно двигать), Clickable (реагирует на клик) и т.д.

Обратите внимание на разницу в конструкторах: для фруктов задаём название и сорт, для рыбы – название, район вылова и вес порции в граммах. Но ссылки на оба объекта храним в переменных одного типа – «Съестное».

Интерфейсы и полиморфизм

Пример выше иллюстрирует один из трех основополагающих принципов ООП — полиморфизм. Мы раскрыли одно и то же явление — съедобность — через несколько классов, свойства и методы которых частично отличаются. Представление разных форм одного явления — это и есть полиморфизм. Если нужно, такую систему всегда можно расширить и скорректировать. В нашем случае — добавить новые виды съестного и методы их приготовления.

В Java полиморфизм можно реализовать через:

  • наследование — с переопределением параметров и методов базового класса;
  • абстрактные классы — шаблоны для раздельной реализации в разных классах;
  • интерфейсы — для имплементации классами.

Интерфейс выручает в ситуации, когда при создании переменной мы не знаем, объект какого класса ей будет присвоен.

Интерфейс – это контракт, в рамках которого части программы, зачастую написанные разными людьми, взаимодействуют между собой и со внешними приложениями. Интерфейсы работают со слоями сервисов, безопасности, DAO и т.д. Это позволяет создавать модульные конструкции, в которых для изменения одного элемента не нужно трогать остальные.

Новички часто спрашивают, чем интерфейс отличается от абстрактного класса. Интерфейсы в Java компенсируют отсутствие множественного наследования классов. У класса-потомка может быть только один абстрактный класс-родитель, а вот интерфейсов класс может применять (имплементировать) сколько угодно.

Интерфейс на Java объявляют примерно так же, как и класс:

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

Методы по умолчанию впервые появились в Java 8. Их обозначают модификатором default. В нашем примере это метод say_goodbye, реализация которого прописана прямо в интерфейсе. Дефолтные методы изначально готовы к использованию, но при необходимости их можно переопределять в применяющих интерфейс классах.

Функциональный интерфейс Java

Если у интерфейса только один абстрактный метод, перед нами функциональный интерфейс. Его принято помечать аннотацией @FunctionalInterface, которая указывает компилятору, что при обнаружении второго абстрактного метода в этом интерфейсе нужно сообщить об ошибке. Стандартных (default) методов у интерфейса может быть множество – в том числе принадлежащих классу java.lang.Object.

Как выглядит функциональный интерфейс на Java:

Функциональные интерфейсы появились в Java 8. Они обеспечили поддержку лямбда-выражений, использование которых делает код лаконичным и понятным:

В той же версии появились пакеты встроенных интерфейсов: java.util.function и java.util.stream.

Реализация интерфейсов классами Java

Допустим, есть интерфейс Edible, которым пользуются классы Fruit, Vegetable, Fish. Экземпляры этих классов можно создавать так:

Хорошим тоном считается давать интерфейсам названия с окончанием -able/-ible — это показывает, что с объектами, имплементирующими интерфейс, можно что-то делать: Edible (можно есть), Moveable (можно двигать), Clickable (реагирует на клик) и т.д.

Обратите внимание на разницу в конструкторах: для фруктов задаём название и сорт, для рыбы – название, район вылова и вес порции в граммах. Но ссылки на оба объекта храним в переменных одного типа – «Съестное».

Интерфейсы и полиморфизм

Пример выше иллюстрирует один из трех основополагающих принципов ООП — полиморфизм. Мы раскрыли одно и то же явление — съедобность — через несколько классов, свойства и методы которых частично отличаются. Представление разных форм одного явления — это и есть полиморфизм. Если нужно, такую систему всегда можно расширить и скорректировать. В нашем случае — добавить новые виды съестного и методы их приготовления.

В Java полиморфизм можно реализовать через:

  • наследование — с переопределением параметров и методов базового класса;
  • абстрактные классы — шаблоны для раздельной реализации в разных классах;
  • интерфейсы — для имплементации классами.

Интерфейс выручает в ситуации, когда при создании переменной мы не знаем, объект какого класса ей будет присвоен.

Пакеты и интерфейсы

Здесь, очевидно, есть 3 вопроса, поэтому они могут решать их по очереди:

  1. Как именно я ожидаю, что методы списка будут работать, когда я ожидаю список Integer и получаю список int []?

Ну, методы будут работать точно так, как ожидалось, — это список типов . Здесь является , поэтому будет содержать массивы как каждый элемент:

Таким образом, вернет элемент . В случае содержит один элемент, а именно so:

В случае строк тип возврата — это List of String, а не List of String []. Какие существуют различия в реализации?

— это , не примитивный тип. Отсюда следует различие.

  1. Что хорошего в этом методе для примитивов, если все так неопределенно?


Вещи не неопределенные . Этот метод приводит к определенному и прогнозируемому поведению. Это просто не очень полезно для примитивов. Это (еще один) побочный эффект объединения системы типов Java с дженериками.

Обратите внимание, что с Java 8 преобразование в очень просто:

Если вспомнить, что пакеты предлагают эффективный механизм изоляции различных классов друг от друга, становится понятно, почему все встроенные классы Java хранятся в пакетах. Ни один из основных классов Java не хранится в неименованном пакете, используемом по умолчанию. Все стандартные классы хранятся в каком-либо именованном пакете. Поскольку внутри пакетов классы должны быть полностью определены именем или именами их пакетов, длинное, разделенное точками имя пути пакета каждого используемого класса может оказаться слишком громоздким. Поэтому, чтобы определенные классы или весь пакет можно было сделать видимыми, в Java включен оператор import. После того как класс импортирован, на него можно ссылаться непосредственно, используя только его имя. Оператор import служит только для удобства программистов и не является обязательным с технической точки зрения для создания завершенной Java-программы. Однако если в приложении придется ссылаться на несколько десятков классов, оператор import значительно уменьшит объем вводимого кода.

В исходном файле Java-программы операторы import должны следовать непосредственно за оператором package (если таковой имеется) перед любыми определениями классов. Оператор import имеет следующую общую форму:

В этой форме пакет! — имя пакета верхнего уровня, па кет 2 — имя подчиненного пакета внутри внешнего пакета, отделенное символом точки (.). Глубина вложенности пакетов практически не ограничена ничем, кроме файловой системы. И, наконец, имя_ класса может быть задано либо явно, либо с помощью символа звездочки (*), который указывает компилятору Java о необходимости импорта всего пакета. Следующий фрагмент демонстрирует применение обеих форм оператора:

Внимание!Использование формы с применением символа звездочки может привести к увеличению времени компиляции — особенно при импорте нескольких больших пакетов. Поэтому советуем явно указывать имена классов, которые нужно использовать, а не импортировать пакеты полностью. Однако использование формы с применением звездочки никак не влияет на производительность системы времени выполнения или на размеры классов.

Все стандартные классы, поставляемые с системой Java, хранятся в пакете j ava.

Основные функции языка хранятся в пакете j ava. lang внутри пакета j ava. Обычно каждый пакет или класс, который нужно использовать, приходится импортировать. Но поскольку система Java бесполезна без многих функций, определенных в пакете java. lang, компилятор неявно импортирует его для всех программ. Это эквивалентно присутствию следующей строки в каждой из программ:

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

Полностью определенное имя класса с указанием полной иерархии пакетов можно использовать везде, где можно допускается имя класса. Например, в следующем фрагменте кода присутствует оператор импорта:

Этот же пример без оператора import выглядит следующим образом:

В этой версии объект Date полностью определен.

Java.util.Arrays.asList() Method

При импорте пакета в импортирующем коде классам, не являющимся подклассами классов пакета, будут доступны только те элементы пакета, которые объявлены как public. Например, если нужно, чтобы приведенный ранее класс Balance пакета МуРаск был доступен в качестве самостоятельного класса вне пакета МуРаск, его необходимо объявить как public и поместить в отдельный файл, как показано в следующем примере:

Как видите, теперь класс Balance объявлен как public. Его конструктор и метод show () также объявлены как public. Это означает, что они доступны любому коду вне пакета МуРаск. Например, класс TestBalance импортирует пакет МуРаск и поэтому может использовать класс Balance:

В качестве эксперимента удалите спецификатор public из класса Balance, а затем попытайтесь выполнить компиляцию класса TestBalance. Как уже было сказано, это приведет к возникновению ошибок.

Коллекции (Collections) в Java. List

Javalock8 августа 2012 г. 12:37

В этой статье речь пойдет о, пожалуй, наиболее часто используемых коллекциях List, а именно о таких классах как AbstractList, ArrayList, LinkedList.

List — упорядоченная коллекция иногда называемая списком или последовательностью. Список может содержать повторяющиеся элементы. Разработчик имеет абсолютный контроль над тем, в каком месте списка будет вставлен каждый элемент. Также пользователь может получить доступ к элементам списка по индексу. В дополнение к стандартным операциям интерфейса Collection, List содержит следующие:

  • Доступ по позиции;
  • Поиск;
  • Специальный итератор ListIterator;
  • Диапазон элементов (sublist).

Доступ по позиции — манипулирует элементами на основе их индексной позиции в списке.

Не взирая на то, что в интерфейсе List присутствуют методы для доступа к элементу по позиции (индексу), делать это не рекоммендуется. В некоторых реализациях списка (например, LinkedList), эти операции могут выполнятся за время, пропорциональное значению индекса.

Поиск — находит указанный элемент и возвращает его позицию в списке. Для этого служит два метода: indexOf() и lastIndexOf().

Специальный итератор ListIterator — содержит усовершенствованный итератор ListIterator для обработки последовательных свойств списка.

ListIterator позволяет вставлять и заменять элементы и производить перебор элементов в двух направлениях. Ниже приведено объявление интерфейса ListIterator:

Как видно из вышеприведенного кода, в ListIterator появились методы для управления итератором в обратном порядке: hasPrevious(), previous(), previousIndex().

Диапазон элементов (sublist) — позволяет манипулировать произвольным диапазоном в списке. Это выполняется с помощью метода subList(). Например так:

Метод subList() принимает два значения: стартовый индекс и конечный индекс подсписка.

Similar Threads

Обратите внимание, что диапазон элементов (список) не создается дублированием элементов из родительского списка. Этот список является частью родительского списка из-за чего все манипуляции над ним отражаются на родительском списке. Вышеприведенный пример это хорошо демонстрирует.

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

На Рис.1 приведена иерархия классов List.

Рис 1. Иерархия List во фреймворке Collections

Интерфейсу List также принадлежит два устаревших класса: Vector и Stack, о которых упоминалось в предыдущей статье.

В отличие от Set, List может содержать повторяющиеся элементы. Также может содержать null-элементы.

Некоторые реализации списков имеют ограничения на элементы, которые они могут содержать. Например, в некоторых реализациях запрещено использовать null в качестве элемента для вставки (на ArrayList и LinkedList это правило не распространяется).

Два объекта типа List одинаковы (т.е., метод equals() возвращает true) только в том случае, когда они содержат одинаковые элементы в одном и том же порядке.

ArrayList — наиболее широко используемая реализация List. ArrayList обладает наибольшей производительностью в плане доступа к случайному элементу в массиве.

LinkedList — еще одна реализация интерфейса List. В отличие от ArrayList, LinkedList обладает большей скоростью вставки элемента в произвольное место в списке, однако доступ к элементу прямо пропорциональный его позиции относительно начала последовательности.

Комментарии (1)

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

ПАКЕТЫ И ИНТЕРФЕЙСЫ презентация, доклад

Презентация на тему ПАКЕТЫ И ИНТЕРФЕЙСЫ из раздела Разное. Доклад-презентацию можно скачать по ссылке внизу страницы. Эта презентация для класса содержит 29 слайдов. Для просмотра воспользуйтесь удобным проигрывателем, если материал оказался полезным для Вас — поделитесь им с друзьями с помощью социальных кнопок и добавьте наш сайт презентаций TheSlide.ru в закладки!

Илон Маск рекомендует:  Что такое код sesam_rollback

ПАКЕТЫ И ИНТЕРФЕЙСЫ

Пакеты. Определение пакета

Пакеты — это контейнеры для классов, которые используются для сохранения пространства имен классов разделенным на именованные области.
Например, вы имеете возможность создать класс с именем List, который можно хранить в вашем собственном пакете, не опасаясь, что он столкнется с некоторым другим классом с именем List, хранящимся где-то в другом месте.
Пакеты сохраняются иерархическим способом и явно импортируются в определения новых классов.

Пакет и подпакет

Разработчики Java включили в язык дополнительную конструкцию — пакеты (packages). Все классы Java распределяются по пакетам. Кроме классов пакеты могут включать в себя интерфейсы и вложенные подпакеты (subpackages). Образуется древовидная структура пакетов и подпакетов.
Эта структура в точности отображается на структуру файловой системы. Все файлы с расширением class (содержащие байт-коды), образующие пакет, хранятся в одном каталоге файловой системы. Подпакеты собраны в подкаталоги этого каталога.
Каждый пакет образует одно пространство имен (namespace). Это означает, что все имена классов, интерфейсов и подпакетов в пакете должны быть уникальны. Имена в разных пакетах могут совпадать, но это будут разные программные единицы.

Пакет и подпакет

Таким образом, ни один класс, интерфейс или подпакет не может оказаться сразу в двух пакетах. Если надо использовать два класса с одинаковыми именами из разных пакетов, то имя класса уточняется именем пакета: пакет.класс . Такое уточненное имя называется полным именем класса (fully qualified name).
Все эти правила совпадают с правилами хранения файлов и подкаталогов в каталогах.
Пакетами пользуются еще и для того, чтобы добавить к уже имеющимся правам доступа к членам класса private, protected и public еще один, «пакетный» уровень доступа.
Если член класса не отмечен ни одним из модификаторов private, protected, public, то, по умолчанию, к нему осуществляется пакетный доступ (default access), а именно, к такому члену может обратиться любой метод любого класса из того же пакета. Пакеты ограничивают и доступ к классу целиком — если класс не помечен модификатором public , то все его члены, даже открытые, public , не будут видны из других пакетов.

В общем случае исходный файл Java может содержать любую (или все) из следующих четырех внутренних частей:
одиночный package-оператор (не обязательно);
любое число import-операторов (не обязательно);
одиночное объявление общего класса (требуется);
любое число частных классов пакета (не обязательно).

Создать пакет очень легко: просто включите оператор package в начало исходного файла Java. Любые классы, объявленные в пределах того файла, будут принадлежать указанному пакету. Оператор package определяет пространство имен, в котором сохраняются классы. Если вы опускаете инструкцию package, имена класса помещаются в пакет по умолчанию (default package), который не имеет никакого имени. (Поэтому-то вы и не должны были волноваться относительно пакетов до настоящего времени.) В то время как пакет по умолчанию хорош для коротких примеров программ, он неадекватен для реальных приложений. В большинстве случаев вы сами будете определять пакет для своего кода.
Общая форма ИНСТРУКЦИИ package
package pkg;
Здесь pkg — имя пакета. Например, следующая инструкция создает пакет с именем MyPackage.
package MyPackage;
Чтобы хранить пакеты, Java использует каталоги файловой системы. Например, class-файлы для любых классов, которые вы объявляете как часть пакета MyPackage, должны быть сохранены в каталоге с именем MyPackage.
Помните, что регистр существенен, и имя каталога должно точно соответствовать имени пакета.
Одну и ту же package-инструкцию могут включать несколько файлов. Она просто указывает, какому пакету принадлежат классы, определенные в файле. Это не исключает принадлежности других классов в других файлах к тому же самому пакету. Большинство реальных пакетов содержат много файлов.

Можно создавать иерархию пакетов. Для этого необходимо просто отделить каждое имя пакета от стоящего выше при помощи операции «точка». Общая форма инструкции многоуровневого пакета:
package pkg1 [ .pkg2[ .рkgЗ] ] ;
Иерархия пакетов должна быть отражена в файловой системе вашей системы разработки Java-программ. Например, пакет, объявленный как
package java.awt.image;
должен быть сохранен в каталоге java/awt/image, java\awt\image или java:awt:image файловой системы UNIX, Windows или Macintosh, соответственно.
Старайтесь тщательно выбирать имена пакетов.
Нельзя переименовывать пакет без переименования каталога, в котором хранятся классы.

Размещением корня любой иерархии пакетов в файловой системе компьютера управляет специальная переменная окружения CLASSPATH.
При сохранении всех классы в одном и том же неименованном пакете, который используется по умолчанию, позволяет просто компилировать исходный код и запускать интерпретатор Java, указывая (в качестве его параметра) имя класса на командной строке.
Данный механизм работал, потому что заданный по умолчанию текущий рабочий каталог обычно указывается в переменной окружения CLASSPATH, определяемой для исполнительной (run-time) системы Java по умолчанию.
Однако все становится не так просто, когда включаются пакеты.

Предположим, что вы создаете класс с именем packTest в пакете с именем test. Так как ваша структура каталогов должна соответствовать вашим пакетам, вы создаете каталог с именем test и размещаете исходный файл PackTest.java внутри этого каталога.
Затем вы назначаете test текущим каталогом и компилируете PackTest.java. Это приводит к сохранению результата компиляции (файла PackTest.class) в каталоге test, как это и должно быть.
Когда вы попробуете выполнить этот файл с помощью интерпретатора Java, то он выведет сообщение об ошибке «can’t find class PackTest» (не возможно найти класс PackTest).
Это происходит потому, что класс теперь сохранен в пакете с именем test. Вы больше не можете обратиться к нему просто как к PackTest.

Вы должны обратиться к классу, перечисляя иерархию его пакетов и разделяя пакеты точками. Этот класс должен теперь назваться test. PackTest. Однако если вы попробуете использовать test.PackTest, то будете все еще получать сообщение об ошибке «can’t find class test/PackTest» (не возможно найти класс test/PackTest).
Причина того, что вы все еще принимаете сообщение об ошибках, скрыта в вашей переменной CLASSPATH. Вершину иерархии классов устанавливает CLASSPATH. Проблема в том, что, хотя вы сами находитесь непосредственно в каталоге test, в CLASSPATH ни он, ни, возможно, вершина иерархии классов, не установлены.
В этот момент у вас имеется две возможности: перейти по каталогам вверх на один уровень и испытать команду Java test.PackTest или добавить вершину иерархии классов в переменную окружения CLASSPATH. Тогда вы будете способны использовать команду Java test.PackTest из любого каталога, и Java найдет правильный class-файл.
Например, если вы работаете над вашим исходным кодом в каталоге C:\myjava, то установите в CLASSPATH следующие пути:
.;С:\myjava;C:\java\classes

Защита и управление доступом

Пакеты добавляют еще одно измерение к управлению доступом. Java обеспечивает достаточно уровней защиты, чтобы допустить хорошо разветвленный контроль над видимостью переменных и методов в пределах классов, подклассов и пакетов.
Классы и пакеты, с одной стороны, обеспечивают инкапсуляцию, а с другой — поддерживают пространство имен и области видимости переменных и методов.
Пакеты действуют как контейнеры для классов и других зависимых пакетов. Классы действуют как контейнеры для данных и кода. Класс — самый мелкий модуль абстракции языка Java.
Из-за взаимодействия между классами и пакетами, Java адресует четыре категории видимости для элементов класса:
подклассы в том же пакете;
неподклассы в том же пакете;
подклассы в различных пакетах;
классы, которые не находятся в том же пакете и не являются подклассами.

Защита и управление доступом

Доступ к членам классов

В неименованном пакете умолчания нет классов ядра Java, все стандартные классы хранятся в нескольких именованных пакетах.
Чтобы обеспечить видимость некоторых классов или полных пакетов Java, используется оператор import. После импортирования на класс можно ссылаться прямо, используя только его имя.
В исходном файле Java оператор import следует немедленно после оператора и package (если он используется) и перед любыми определениями класса. Общая форма оператора import:
import pkgl[.pkg2].(classname | *);
Здесь pkgi — имя пакета верхнего уровня, pkg2 — имя подчиненного пакета внутри внешнего пакета (имена разделяются точкой). Наконец, вы определяете или явное имя класса, или звездочку (*), которая указывает, что компилятор Java должен импортировать полный пакет.
Следующий кодовый фрагмент показывает использование обеих форм:
import java.util.Date; import java.io.*;

Создатели языка Java поступили радикально — запретили множественное наследование вообще. При расширении класса после слова extends можно написать только одно имя суперкласса. С помощью уточнения super можно обратиться только к членам непосредственного суперкласса.
Но что делать, если все-таки при порождении надо использовать несколько предков?
В таких случаях используется еще одна конструкция языка Java— интерфейс.
Интерфейс (interface), в отличие от класса, содержит только константы и заголовки методов, без их реализации.
Интерфейсы размещаются в тех же пакетах и подпакетах, что и классы, и компилируются тоже в class-файлы.

Интерфейсы. Определение интерфейса

С помощью ключевого слова interface Java позволяет полностью отделить интерфейс от его реализации.
Используя интерфейс, можно определить набор методов, которые могут быть реализованы одним или несколькими классами.
Сам интерфейс в действительности не определяет никакой реализации.
Хотя интерфейсы подобны абстрактным классам, они имеют дополнительную возможность: класс может реализовывать больше одного интерфейса.
В противоположность этому класс может наследовать только один суперкласс (абстрактный или другой).

Интерфейсы разработаны для поддержки динамического вызова методов во время выполнения.
Обычно для вызова метода одного класса из другого нужно, чтобы оба класса присутствовали во время компиляции и компилятор Java мог проверить совместимость сигнатур методов.
В иерархической же многоуровневой системе, где функциональные возможности обеспечиваются длинными цепочками связанных в иерархию классов, этот механизм неизбежно используется все большим и большим числом подклассов.
Интерфейсы исключают определение метода или набора методов из иерархии наследования.
Так как интерфейсы находятся вне иерархии классов, то для несвязанных в этой иерархии классов появляется иная, более эффективная возможность реализации интерфейсов.

Общая форма интерфейса выглядит так:
access interface name <
return-type method-name1(parameter-list) ;
return-type method-name2(parameter-list) ;
type final-varname1 = value;
type final-varname2 = value;
return-type method-nameN (parameter-list) ;
type final-vaxnameN = value;
access — спецификатор доступа (или public или не используется). Если никакой спецификатор доступа не включен, тогда используется доступ по умолчанию, и интерфейс доступен только другим членам пакета, в котором он объявлен.
При объявлении с public интерфейс может использоваться любым другим кодом, паше — имя интерфейса, им может быть любой допустимый идентификатор.
Объявленные методы не имеют тел. Они заканчиваются точкой с запятой после списка параметров.
Каждый класс, который включает интерфейс, должен реализовать все его методы.

Пример определения интерфейса

interface Callback <
void callback(int param);
>
Здесь объявлен простой интерфейс, содержащий один метод с именем callback(), который имеет единственный целый параметр.

Общая форма класса, который включает implements предложение, выглядит примерно так:
access class classname [extends superclass]
[implements interface [,interface. ]] < // тело-класса >
Здесь access — спецификатор доступа (public или не используется). Если класс реализует более одного интерфейса, они разделяются запятой. Если класс реализует два интерфейса, которые объявляют один и тот же метод, то клиенты любого интерфейса будут использовать один и тот же метод.
Методы, которые реализуют интерфейс, должны быть объявлены как public.

Пример класса, который реализует интерфейс

class Client implements Callback <
// Реализация Callback-интерфейса
public void callback(int p) <
System.out.println
(«callback вызван с аргументом “+p);
> >
Обратите внимание, что callback() объявлен со спецификатором доступа public.

Реализации доступа через интерфейсные ссылки

Можно объявлять переменные как объектные ссылки, которые используют интерфейсный тип, а не тип класса.
В такой переменной можно сохранять всякий экземпляр любого класса, который реализует объявленный интерфейс.
Когда вы вызываете метод через ссылку такого рода, будет вызываться его правильная версия, основанная на актуальном экземпляре интерфейса. Выполняемый метод отыскивается динамически (во время выполнения), что позволяет создавать классы позже кода, который вызывает их методы.
Кодом вызова можно управлять через интерфейс, ничего не зная об объекте вызова.

Пример вызова метода

class Testlface <
public static void main(String args[]) <
Callback с = new Client();
с callback(42);
Вывод этой программы:
callback вызван с аргументом 42
Обратите внимание, что переменной с, объявленной с типом интерфейса Callback, был назначен экземпляр класса client.
Хотя разрешается использовать с для обращения к методу callback(), она не может обращаться к любым другим членам класса client. Переменная интерфейсной ссылки обладает знаниями только методов, объявленных в соответствующей интерфейсной декларации.

Если класс включает интерфейс, но полностью не реализует методы, определенные этим интерфейсом, то этот класс должен быть объявлен как abstract (абстрактный).
abstract class Incomplete implements Callback <
int a, b;
void show() <
System.out.println(a + » » + b) ;
>
// .
Здесь класс incomplete не реализует callback() и должен быть объявлен как абстрактный.
Любой класс, который наследует incomplete, должен реализовать callback() или объявить себя как abstract.

Стек может иметь фиксированный размер, или быть «растущим».
Стек может также содержаться в массиве, связном списке, двоичном дереве и т. д.
Независимо от того, как стек реализован, интерфейс стека остается тем же самым.
Методы push() и pop() определяют интерфейс к стеку независимо от подробностей реализации.
Ниже показан интерфейс, определяющий целый стек.
// Определение интерфейса целого стека,
interface IntStack <
void push(int item); // запомнить элемент
int pop(); // извлечь элемент
>

Переменные в интерфейсах

Можно использовать интерфейсы для импорта разделяемых констант во множественные классы просто объявлением интерфейса, который содержит переменные, инициализированные желательными значениями. Когда вы включаете этот интерфейс в класс (т. е. «реализуете» интерфейс), все имена указанных переменных окажутся в области их видимости как константы.
Если интерфейс не содержит методов, то любой класс, который включает такой интерфейс, фактически не реализует ничего.

import java.util.Random;
interface SharedConstants <
int N0=0;
int YES = 1;
int MAYBE = 2;
int LATER = 3;
int SOON = 4;
int NEVER = 5; >


>int ask() <
int prob = (int’) (100 * rand.nextDoubleO ) ;
if (prob

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

8. ПАКЕТЫ И ИНТЕРФЕЙСЫ

Похожие главы из других книг

3.3. Пакеты в языке UML

3.3. Пакеты в языке UML Пакет – основной способ организации элементов модели в языке UML. Каждый пакет владеет всеми своими элементами, т. е. теми элементами, которые включены в него. Про соответствующие элементы пакета говорят, что они принадлежат пакету или входят в него. При

Необходимые пакеты

Необходимые пакеты Сервер FTP: ftp://ftp.linuxfromscratch.org/ Сервер HTTP: http://ftp.linuxfromscratch.org/ Загрузите все необходимые пакеты для компиляции системы LFS в одном tar-архиве: Все пакеты LFS – 105,560 KB: ftp://ftp.linuxfromscratch.org/lfs-packages/4.0/lfs-packages-4.0.tar http://ftp.linuxfromscratch.org/lfs-packages/4.0/lfs-packages-4.0.tar Или все пакеты по

B.3. SYN/ACK – пакеты и пакеты со статусом NEW

B.3. SYN/ACK – пакеты и пакеты со статусом NEW Существует одна из разновидностей спуфинг-атак (от англ. spoofing – мистификация, подмена. прим. перев.), которая называется «Предсказание номера TCP-последовательности» (Sequence Number Prediction). Смысл атак такого рода заключается в использовании

Собираем пакеты

Собираем пакеты Ну что ж, от теории плавно перейдем к практике. Ведь чтобы научится что-то хорошо защищать, необходимо взломать это. Нижеследующий текст никоим образом нельзя расценивать как руководство к действию. Материал приведен исключительно в ознакомительных

14.3.1. Пакеты SYN

14.3.1. Пакеты SYN Пакеты SYN используются для запроса на установку соединения. Вы можете отвергать эти пакеты для того, чтобы прервать попытки установить соединение.Иногда это необходимо, если вы хотите получать пакеты только в одном направлении, например, рабочая станция

19.2.4.5. В Linux создавайте RPM-пакеты

19.2.4.5. В Linux создавайте RPM-пакеты Де-факто стандартным форматом для устанавливаемых бинарных пакетов в Linux является формат, используемый диспетчером пакетов Red Hat Linux, RPM (Red Hat Package manager). Он имеется в большинстве популярных дистрибутивов Linux и поддерживается фактически всеми

Офисные пакеты

Пакеты

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

Пакеты: оценка

Пакеты: оценка По сравнению с подпрограммами, механизм пакетов приводит к существенному совершенствованию разбиения системы ПО на абстрактные модули. Собрать нужные компоненты «под одной крышей» крайне полезно как для поставщиков, так и для клиентов:[x]. Автор

4.20.7 Пакеты или PDU?

4.20.7 Пакеты или PDU? Существует незначительная сложность в способе пересылки информации по Х.25. Некоторые сети X.25 передают пакеты очень маленького размера. Однако передать весь высокоуровневый PDU (например, датаграмму IP) можно через непрерывную последовательность пакетов

Тестовые пакеты

4.4. Офисные пакеты

4.4. Офисные пакеты Open Office и К OfficeВ среде Linux наибольшее распространение получили два офисных пакета: K Office и Open Office, оба — свободно распространяемые. В большинство дистрибутивов включены они оба, так что вы можете выбирать инструмент, исходя из конкретной задачи.Пакет Open

9.1.1. Пакеты и зависимости

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

5. Лекция: Имена. Пакеты

5. Лекция: Имена. Пакеты В этой лекции рассматриваются две темы – система именования элементов языка в Java и пакеты (packages), которые являются аналогами библиотек из других языков. Почти все конструкции в Java имеют имя для обращения к ним из других частей программы. По ходу

Пакеты и репозитории

Пакеты и репозитории Все дистрибутивы Linux, и Mint тут не исключение, организованы по пакетному принципу. Точно также, в виде пакетов, распространяются и любые дополнительные программы для них, создаваемые независимыми разработчиками. И потому одна из важных задач

Занятие 4

Интерфейсы

Абстрактные классы

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

Например, классы Point (точка), Circle (круг) и Rectangle (прямоугольник) унаследованы от класса Figure (фигура). В классе Figure есть метод paint() , общий для всех подклассов — он нужен, чтобы нарисовать фигуру. Но между рисованием круга, точки и прямоугольника нет ничего общего, поэтому бессмысленно программировать этот метод в классе Figure .

В таких случаях после заголовка метода и списка параметров вместо фигурных скобок ставится точка с запятой, а перед объявлением метода указывается ключевое слово abstract . Такой метод называется абстрактным, т.е. лишенным реализации.

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

Создать объект абстрактного класса нельзя. Можно только унаследовать от этого класса другие классы, переопределить в них абстрактные методы (наполнив их конкретным содержимым) и создавать объекты уже этих классов. *

Множественное наследование

Множественным наследованием называется ситуация, когда класс наследует от двух или более классов.

Пусть, например, уже разработаны классы Clock (часы) и Phone (телефон) и возникает необходимость написать новый класс Cellurar (сотовый телефон), который совмещает в себе структуру и поведение обоих этих классов (его можно использовать как телефон, но он обладает также всей функциональностью часов). Очень удобно просто унаследовать класс Cellular от классов Clock и Phone . Во-первых, программисту не приходится заново переписывать многочисленные методы. Во-вторых, сохраняются все преимущества полиморфизма: объект класса Cellular можно использовать в программе и в качестве часов (как объект класса Clock ) и в качестве телефона (как объект класса Phone ).

Однако множественное наследование потенциально способно породить трудноразрешимые проблемы. Они начинаются, когда у классов-предков есть методы с одинаковыми сигнатурами (т.е. именем и числом параметров).

Например, в классе Clock есть метод ring() , который вызывается, когда срабатывает таймер будильника. Но в классе Phone тоже есть метод ring() , который вызывается, когда кто-то звонит по телефону и надо оповестить об этом владельца. Когда класс Cellular наследует от классов Clock и Phone , он получает метод ring() . Но какой из его вариантов? *

У этой ситуации нет безупречного решения. Поэтому многие языки программирования запрещают множественное наследование.

Java множественное наследование не поддерживает.

Заметим, однако, что если метод ring() хотя бы в одном из классов Clock и Phone является абстрактным, то конфликта возникнуть не может. Абстрактный метод не имеет реализации, а следовательно «побеждает» тот метод, который абстрактным не является. Если же метод является абстрактным в обоих классах, он останется таким же и в их потомке.

Используя эту особенность абстрактных классов, авторы языка Java ввели в него особенную конструкцию — интерфейсы, позволяющие сохранить часть преимуществ множественного наследования (а именно преимущества полиморфизма), избежав при этом главной проблемы множественного наследования.

Понятие интерфейса в Java. Описание интерфейса

представляет собой класс, в котором все поля — константы (т.е. статические — static и неизменяемые — final ), а все методы абстрактные.

При описании интерфейса вместо ключевого слова class используется ключевое слово interface , после которого указывается имя интерфейса, а затем, в фигурных скобках список полей-констант и методов. Никаких модификаторов перед объявлением полей и методов ставить не надо: все поля автоматически становятся public static final , а методы — public abstract . Методы не могут иметь реализации, т.е. после закрывающей круглой скобки сразу ставится точка с запятой.

Опишем, например, интерфейс для объекта, который «умеет» сообщать информацию о себе в формате прайс-листа (т.е. сообщать свое название, цену, и краткое описание).

Для разнообразия метод getPrice() в этом примере требует один целочисленный параметр (количество единиц товара).

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

Реализация интерфейса

Класс может реализовывать интерфейс, т.е. перенимать его поведение. Эта процедура аналогична наследованию, только вместо ключевого слова extends используется ключевое слово implements . Но если после extends может быть указан только один класс, то после implements можно перечислить через запятую произвольное количество интерфейсов. Класс может одновременно наследовать от другого класса и реализовывать интерфейсы.

Мы можем взять любой существующий в программе класс и «научить» его сообщать о себе все необходимые сведения. Например, класс Dog , с которым мы работали на прошлом занятии. Можно изменить этот класс, заставив его реализовывать наш интерфейс, а можно оставить в неприкосновенности * и создать на его базе новый класс. В новом классе обязательно требуется переопределить абстрактные методы интерфейса.

Илон Маск рекомендует:  Common controls (индикатор прогресса)

Класс Dog2 «умеет» то же самое, что и старый класс Dog , но помимо этого его можно использовать в программе Интернет-магазина для формирования прайса. Обратите внимание, класс Dog ничего не знал о цене, поэтому понадобилось добавить метод setPrice() и поле price , чтобы эту цену можно было бы изменять. А изменять описание собаки не понадобится, поэтому метод getDescription() просто выводит одну и ту же сроку.

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

Переменные интерфейсного типа

Переменные интерфейсного типа могут ссылаться на объект любого класса, реализующего данный интерфейс.

PriceItem pi; // переменная интерфейсного типа Dog2 dog = new Dog2(); // создается объект класса Dog2, на него ссылается переменная dog dog.voice(); // можно вызвать метод лая System.out.println(dog.getTitle()); // можно вывести название товара Dog oldDog = dog; // переменная oldDog ссылается на тот же самый объект oldDog.voice(); // можно работать с объектом нового класса по-старому pi = dog; // переменная pi рассматривает тот же самый объект как товар для прайса pi.voice(); // НЕ ПОЛУЧИТСЯ. Этого метода нет в интерфейсе PriceItem *

Мы можем поместить собак, велосипеды и компьютеры в один массив goods (товары) и в цикле сформировать прайс:

PriceItem[] goods; . // создание и заполнение массива элементами, // поддерживающими интерфейс PriceItem for ( int i = 0; i System.out.println( «Название: » + goods[i].getTitle() + «, цена за единицу товара: » + goods[i].getPrice(1) + «, описание: » + goods[i].getDescription() + «.» ); >

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

Приемы программирования: пример применения интерфейсов

Предположим, в нашей программе есть объект, который следит за текущим временем и каждую минуту (когда время меняется) «сообщает» об этом другим объектам. Это очень логичный и удобный способ организации программы, в которой объекты должны что-то делать при наступлении определенного времени (или события). Гораздо лучше, чем учить каждый объект следить за временем.

Один объект может «сообщить» что-то другому объекту, вызвав его метод. Пусть информацию о времени обрабатывает метод sayTime(int hours, int minutes) . Для того, чтобы вызвать этот метод у какого-то объекта, надо быть уверенным, что такой метод описан в классе этого объекта. Можно определить интерфейс, скажем TimeListener , и реализовать его во всех классах, которым нужно следить за временем, не вмешиваясь в основную иерархию этих классов. И тогда у нас может быть разновидность умной собаки, которая лает ровно в полночь и разновидность кнопки, которая может автоматически срабатывать через заданный промежуток времени.

Класс, следящий за временем будет иметь внутренний список объектов типа TimeListener , методы для добавления и удаления объектов в этот список (те объекты, которые «захотят» следить за временем, вызовут этот метод) и каждую минуту объект этого класса (достаточно одного такого объекта на всю программу) будет вызывать метод sayTime(int hours, int minutes) для каждого из объектов в этом списке.

Пакеты и области видимости

Пакеты

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

Каждый пакет имеет имя. Имя представляет собой обычный идентификатор Java. Особенность заключается в том, что это имя одновременно является названием папки, в которой хранятся файлы классов, входящие в пакет. А точка в имени преобразуется в разделитель имен файловой системы. То есть пакет с именем java.util будет представлен папкой util , находящейся внутри папки java .

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

Импортирование пакетов

Полное имя класса состоит из идентификатора, указанного после ключевого слова class и предшествующего ему имени пакета, в котором этот класс находится. Классы ClassA и ClassB , описанные в пакете package1 , имеют полные имена package1.ClassA и package1.ClassB .

Классы, находящиеся внутри одного пакета могут пользоваться сокращенными именами друг друга (что мы до сих пор всегда и делали). В одном из методов класса ClassA можно определить переменную класса ClassB , создать объект класса ClassB и вызвать его метод (например, f() ) командами:

>new ClassB(); varb.f();

package1. >new package1.ClassB(); varb.f();

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

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

Для импортирования класса используется ключевое слово import , после которого указывается его полное имя. Например, можно импортировать класс Vector из пакета java.util :


Теперь можно пользоваться именем Vector вместо java.util.Vector .

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

импортирует все файлы из пакета java.util . Но таким способом пользоваться не рекомендуется, так как при этом из разных пакетов могут импортироваться файлы с одинаковыми именами. *

Eclipse позволяет облегчить жизнь разработчику. Если в программе используется класс с неизвестным именем, на полях редактора кода появляется значок предупреждения об ошибке. Щелчок по этому значку выводит варианты решения проблемы. Например, создать новый класс. Или импортировать существующий (при этом выводится список всех доступных пакетов, содержащих класс с таким именем). Если выбрать вариант «Import» соответствующая директива import будет автоматически добавлена в начало пакета.

Все классы, находящиеся в одном пакете, должны иметь разные имена, иначе возникнет ошибка. К классам, которые находятся в разных пакетах, такого требования предъявить, очевидно, невозможно (поскольку пакеты могут разрабатываться совершенно разными людьми).

Поэтому при импортировании нескольких пакетов, в которых содержатся классы с одинаковыми именами, может возникнуть путаница в этих именах. Однако Java справляется с этой проблемой, «отдавая» сокращенное имя первому из импортированных классов. К другому классу можно обратиться с помощью его полного имени.

Если же совпадут и имена пакетов и имена классов, проблема окажется неразрешимой. А поскольку программист может пользоваться множеством пакетов разных разработчиков, такая ситуация вполне вероятна, если разработчики не договорятся. Поэтому существует соглашение об именовании пакетов (особенно тех, которые впоследствии могут распространяться).

Рекомендуется для названия пакета использовать адрес сайта фирмы-разработчика. Адреса сайтов есть практически у всех серьезных разработчиков программ (и, что самое главное, адреса сайтов не могут совпадать). Адрес сайта рекомендуется записывать наоборот. То есть, если адрес — sun.com, то имя пакета должно начинаться с com.sun. Кстати, таких пакетов довольно много в вашей системе, их поставляет фирма Sun Microsystems, разработчик языка Java.

Файловая структура Java-проекта

Итак, Java-проект может состоять из нескольких пакетов. Каждому пакету в файловой структуре операционной системы соответствует одна папка.

В пакете могут содержаться классы и интерфейсы. Они хранятся в файлах с расширением .java.

В каждом файле с расширением .java обязательно описывается один класс или интерфейс, название которого совпадает с названием этого файла. Он должен быть объявлен как открытый (перед объявлением класса указывается ключевое слово public ). Все остальные классы и интерфейсы из этого файла являются закрытыми — их нельзя использовать за пределами этого пакета (ни с помощью длинного, ни с помощью короткого имени). Поэтому с классом Dog , который мы разрабатывали на прошлом занятии, можно работать исключительно в пределах его пакета.

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

Eclipse создает новый файл с расширением .java автоматически, если выполнить команду New Class или New Interface .

Файл с расширением .java — это обычный текстовый файл. Его можно открывать и редактировать как с помощью Eclipse, так и в любом другом текстовом редакторе (даже в Блокноте).

Для каждого класса (открытого или закрытого) Java создает файл с расширением .class . Это двоичный файл, в котором хранятся команды на внутреннем языке Java. Эти файлы недоступны для редактирования в Eclipse (если попытаться их открыть, Eclipse на самом деле откроет соответствующий .java -файл). Чтобы они не мешали, их можно скрыть с помощью фильтра. Для этого в представлении Navigator нажмите маленькую треугольную кнопку справа ( menu ) и выберите команду Filters. В открывшемся окне поставьте галочку напротив расширения .class , чтобы скрыть из панели Navigator соответствующие файлы.

Области видимости классов

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

Объект, созданный в области видимости своего класса, может продолжать свое существование и за ее пределами. Но переменные типа «невидимого» класса объявить нельзя, поэтому обращаться к такому объекту можно только с помощью переменных типов «видимых» классов-предков. Следовательно, и вызывать можно лишь те методы объекта, которые его класс унаследовал от соответствующего предка.

Обычный класс всегда виден в пределах своего пакета. Если класс является открытым, он виден также из других пакетов (в этом случае к нему надо обращаться, используя полное имя или, если предварительно импортировать пакет, сокращенное).

Вложенные классы, объявленные без модификатора public , видны только в методах содержащего их класса. Классы, описанные в методах, видны только в пределах этих методов.

Анонимные классы видны лишь в пределах команды, которой они создаются.

Области видимости членов класса

Члены класса (методы и атрибуты), объявленные как public , видны везде, где виден сам класс.

Члены класса, объявленные как protected видны в самом классе и его потомках.

Члены класса, объявленные как private , видны только в пределах класса.

Если к члену класса не применяется ни один из модификаторов public , private , protected , он виден в пределах текущего пакета.

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

«Видимость» метода означает возможность его вызова.

Для обращения к полям и методам класса используется полное имя, состоящее из имени объекта соответствующего класса и собственно имени атрибута или метода. В теле метода того же класса имя объекта можно опускать (если подразумевается this — объект, для которого вызван данный метод).

Области видимости переменных

Переменные, объявленные в теле метода, видны от места объявления до конца блока, в котором это объявление находится. Границы блока задаются фигурными скобками <> . Поэтому в следующем примере:

используются две разные переменные x (первая переменная, равная 0, перестает существовать за границами своего блока).

Переменные, являющимися параметрами метода, видны во всем теле метода.

Перечисленные переменные называются локальными переменными. Двух локальных переменных с одинаковыми именами и перекрывающимися областями видимости быть не должно. Нельзя, например, объявить две переменных следующим образом:

Нельзя, в частности, объявлять в теле метода переменную, совпадающую (по имени) с одним из параметров метода.

Конфликты имен

Конфликт имен возникает, если в одной области видимости оказываются два объекта с одинаковыми именами, причем такая ситуация является в языке разрешенной (в противном случае это не конфликт имен, а ошибка в программе).

Конфликт имен возникает, когда импортируются два пакета, содержащие классы с одинаковыми именами.

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

Java «просматривает» имена классов в следующем порядке. Сначала — классы, импортированные поодиночке. Потом — классы, определенные в данном пакете. В последнюю очередь классы из пакетов, импортируемых полностью в порядке следования команд import .

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

Такой заголовок метода setAge(int age) лучше, чем использовавшийся нами на прошлом занятии setAge(int a) , поскольку сразу позволяет судить о назначении параметра. Однако возникает вопрос: к чему будет относиться имя age в теле этого метода — к атрибуту или к параметру.

Ответ: к параметру. Имя параметра «перекрывает» имя атрибута.

Для того, чтобы обратиться к атрибуту, следует использовать полное имя (т.е. указатель на объект this ).

Реализация метода должна выглядеть следующим образом:

Дополнительная литература

1. Вязовик Н.А. Программирование на Java. (глава 8)

2. Хабибуллин И.Ш. Самоучитель Java 2. (глава 3)

8. Пакеты и интерфейсы

    Алина Магалова 2 лет назад Просмотров:

1 8. Пакеты и интерфейсы Пакеты это контейнеры для классов, которые используются для сохранения пространства имен классов. Например, класс с именем List, можно хранить в отдельном пакете, не опасаясь, что он столкнется с некоторым другим классом с именем List, хранящимся где-то в другом месте. Пакеты сохраняются иерархическим способом и явно импортируются в определения новых классов. Методы класса определяют интерфейс к данным в классе. С помощью ключевого слова interface Java позволяет полностью отделить интерфейс от его реализации. Используя интерфейс, можно определить набор методов, которые могут быть реализованы одним или несколькими классами. Сам интерфейс в действительности не определяет никакой реализации. Хотя интерфейсы подобны абстрактным классам, они имеют дополнительную возможность: класс может реализовывать более одного интерфейса. В противоположность этому класс может наследовать только один суперкласс (абстрактный или другой). Пакеты и интерфейсы это два основных компонента Javaпрограммы. В общем случае исходный файл Java может содержать любую (или все) из следующих четырех внутренних частей: одиночный package-оператор (не обязательно); любое число import-операторов (не обязательно); одиночное объявление общего класса (требуется); любое число частных классов пакета (не обязательно). До сих пор в примерах использовалась только одна из этих частей одиночное объявление класса public. В этой главе рассмотрим остальные части Пакеты В примерах предшествующих глав имя каждого класса выбиралось из одного и того же пространства имен. Это означает, что во избежание коллизии имен для каждого класса нужно использовать уникальное имя. Кроме того, без некоторого способа управления пространством имен, можно быстро исчерпать удобные, дескриптивные имена для индивидуальных классов. Нужно также позаботиться, чтобы выбранное для класса имя было разумно уникально и не вступало в противоречие с именами классов, выбранными другими программистами. (Вообразите небольшую группу программистов, борющихся за право использования имени «Foobar» в качестве имени класса. Или вообразите все Internetсообщество, спорящее, кто первым назвал класс «Espresso».) Java

2 обеспечивает специальный механизм для разделения пространства имен классов на управляемые части. Этот механизм называется «пакеты» (packages). Пакет является механизмом как именования, так и управления видимостью. Можно определять внутри пакета классы, которые недоступны кодам вне этого пакета. Возможно также определять члены класса, доступные только другим членам того же самого пакета. Это позволяет классам близко знать друг друга, но не предъявлять это знание остальной части мира. Определение пакета Пакет создается включением оператора package в начало исходного файла Java. Любые классы, объявленные в пределах этого файла, будут принадлежать указанному пакету. Оператор package определяет пространство имен, в котором сохраняются классы. Если опустить инструкцию package, имена класса помещаются в пакет по умолчанию (default package), который не имеет никакого имени. В то время как пакет по умолчанию хорош для коротких примеров программ, он неадекватен для реальных приложений. Общая форма инструкции package: package pkg; Здесь pkg имя пакета. Например, следующая инструкция создает пакет c именем MyPackage. package MyPackage; Чтобы хранить пакеты, Java использует каталоги файловой системы. Например, class-файлы для любых классов, которые объявляются как часть пакета MyPackage, должны быть сохранены в каталоге с именем MyPackage. Регистр букв в названии папки существенен, то есть имя каталога должно точно соответствовать имени пакета. Одну и ту же package-инструкцию могут включать несколько файлов. Она просто указывает, какому пакету принадлежат классы, определенные в файле. Это не исключает принадлежности других классов в других файлах к тому же самому пакету. Большинство реальных пакетов содержат много файлов. Можно создавать иерархию пакетов. Для этого необходимо просто отделить каждое имя пакета от стоящего выше при помощи операции «точка». Общая форма инструкции многоуровневого пакета: package pkg1[.pkg2[.pk3]]; Иерархия пакетов должна быть отражена в файловой системе системы разработки Java-программ. Например, пакет, объявленный как

3 package java.awt.image; должен быть сохранен в каталоге java/awt/image, java\awt\image или java:awt:image файловой системы UNIX, Windows или Macintosh, соответственно. Следует тщательно выбирать имена пакетов. Нельзя переименовывать пакет без переименования каталога, в котором хранятся классы. Использование CLASSPATH Обсудим переменную окружения (environmental variable) CLASSPATH. Происходит это потому, что размещением корня любой иерархии пакетов в файловой системе компьютера управляет специальная переменная окружения CLASSPATH. До сих пор мы сохраняли все классы в одном и том же неименованном пакете (который используется по умолчанию). Это позволяет просто компилировать исходный код и запускать интерпретатор Java, указывая (в качестве его параметра) имя класса на командной строке. Данный механизм работал, потому что заданный по умолчанию текущий рабочий каталог (.) обычно указывается в переменной окружения CLASSPATH, определяемой для исполнительной (run-time) системы Java по умолчанию. Однако все становится не так просто, когда включаются пакеты. Предположим, что создается класс с именем PackTest в пакете с именем test. Так как структура каталогов должна соответствовать пакетам, следует создать каталог с именем test и разместить исходный файл PackTest.java внутри этого каталога. Затем назначаем test текущим каталогом и компилируем PackTest.java. Это приводит к сохранению результата компиляции (файла PackTest.class) в каталоге test, как это и должно быть. Когда мы попробуем выполнить этот файл с помощью интерпретатора Java, то он выведет сообщение об ошибке «can’t find class PackTest» (невозможно найти класс PackTest). Это происходит потому, что класс теперь сохранен в пакете с именем test. Мы больше не можем обратиться к нему просто как к PackTest. Нужно обращаться к классу, перечисляя иерархию его пакетов и разделяя пакеты точками. Этот класс должен теперь назваться test.packtest. Однако если мы попробуем использовать test.packtest, то будем все еще получать сообщение об ошибке «can’t find class test/packtest» (невозможно найти класс test/packtest). Причина этого скрыта в переменной CLASSPATH, которая устанавливает вершину иерархии классов. Проблема в том, что, хотя мы находимся непосредственно в каталоге test, в CLASSPATH ни он, ни, возможно, вершина иерархии классов, не установлены. В этот момент у нас имеется две возможности: перейти по каталогам вверх на один уровень и испытать команду java test.packtest

4 или добавить вершину иерархии классов в переменную окружения CLASSPATH. Тогда будет возможно использовать команду java test.packtest из любого каталога, и Java найдет правильный class-файл. Например, если мы работаем над исходным кодом в каталоге C:\myjava, то в CLASSPATH надо установить следующие пути:.;с:\myjava;c:\java\classes Создание пакета в среде Eclipse Создадим в среде Eclipse новый проект с именем, например, Progr38_AccountBalance. Выполнив команду File, New, Package, создадим в составе этого проекта пакет MyPack (рис.1). Рис. 1. Ввод имени пакета Затем создадим новый класс AccountBalance (рис.2). Чтобы класс вошел в состав пакета, в поле Package должно быть указано имя пакета.

5 Рис. 2. Создание класса в составе пакета В файле AccountBalance.java наберем код, приведенный в следующей программе. Программа 38. Пример пакета // Простой пакет package MyPack; >

6 System.out.print («> «) ; System.out.println(name + «: $ » + bal); , ); for(int i = 0; i 7 В параметре >

8 Рис. 7. Запуск класса из пакета из охватывающей папки Защита доступа Как уже известно, доступ к private-члену класса предоставляется только другим членам того же класса. Пакеты добавляют еще одно измерение к управлению доступом. Классы и пакеты, с одной стороны, обеспечивают инкапсуляцию, а с другой поддерживают пространство имен и области видимости переменных и методов. Пакеты действуют как контейнеры для классов и других зависимых пакетов. Классы действуют как контейнеры для данных и кода. Класс самый мелкий модуль абстракции языка Java. Из-за взаимодействия между классами и пакетами, Java адресует четыре категории видимости для элементов класса: подклассы в том же пакете; неподклассы в том же пакете; подклассы в различных пакетах; классы, которые не находятся в том же пакете и не являются подклассами. Большое разнообразие уровней защиты доступа для этих категорий обеспечивают три спецификатора доступа: private, public и protected. Табл. 9 подводит итог соответствующим взаимодействиям. Таблица 9. Доступ к членам классов Private Без модификатора Protected Public Тот же класс Yes Yes Yes Yes Подкласс того же пакета No Yes Yes Yes Неподкласс того же пакета Другой подкласс другого пакета No Yes Yes Yes No No Yes Yes

9 Другой неподкласс No No No Yes другого пакета Хотя механизм управления доступом Java может показаться сложным, мы можем упростить его следующим образом. Все, объявленное как public, может быть доступно отовсюду. Все, объявленное как private, не может быть видимо извне своего класса. Когда элемент не имеет явных спецификаций доступа, он видим в подклассах, также как в других классах в том же самом пакете. Это доступ, заданный по умолчанию. Если нужно позволить элементу быть видимым извне текущего пакета, но только в классах, являющихся прямыми подклассами класса, то этот элемент объявляется protected. Табл. 9 применяется только к членам классов. Сам класс имеет лишь два возможных уровня доступа по умолчанию и общий (public). Когда класс объявлен как public, он доступен из любых других кодов. Если класс имеет доступ по умолчанию, то к нему возможен доступ только из кодов того же пакета. Программа 39. Пример управления доступом Следующий пример показывает все комбинации модификаторов управления доступом, используя два пакета и пять классов. Помните, что классы для двух различных пакетов нужно сохранять в каталогах, названных именами соответствующих им пакетов в данном случае p1 и р2. В первом исходном пакете определено три класса: Protection, Derived и samepackage. В первом классе определено четыре переменных int в каждом из допустимых режимов защиты. Переменная n объявлена с защитой, заданной по умолчанию, n_pri объявлена как private, njoro как protected и n_pub — как public. Каждый последующий класс в этом примере будет пытаться обратиться к переменным в экземпляре этого класса. Строки, которые не будут компилироваться из-за ограничений доступа, прокомментированы при помощи однострочного комментария (//. ). Перед каждой из этих строк есть комментарий, перечисляющий области, где данный уровень защиты разрешил бы доступ. Второй класс, Derived, является подклассом Protection в том же пакете pi. Это предоставляет Derived доступ к каждой переменной в Protection за исключением n_pri, поскольку она private. Третий класс, Same- Package, не подкласс Protection, но он находится в том же пакете и также имеет доступ ко всем переменным суперкласса, кроме n_pri. Итак, файл Protection.java:

Илон Маск рекомендует:  Урок 1. PHP - Синтаксис

10 package p1; // Тот же класс public + p.n_pub);

11 Далее следует исходный код (текст) для пакета р2. Два класса, определенных в р2, охватывают два других условия, на которые влияет управление доступом. Первый класс, Protection2, является подклассом p1.protection. Он предоставляет доступ ко всем переменным класса p1.protection, кроме n_pri (потому что она private) и n (т. к. она объявлена с защитой, заданной по умолчанию). Помните, умолчание разрешает доступ только изнутри класса или пакета, не из подклассов внешних пакетов. Наконец, класс OtherPackage имеет доступ только к одной переменной, n_pub, которая была объявлена как public. Файл Protection2.java: package p2; // Другой подкласс другого пакета + p.n_pub); Для тестирования пакета p1 создадим класс Demo_p1 (рис.8)

12 Рис. 8. Создание тестирующего класса для пакета p1 // Файл Demo_p1.java // Тестирование пакета p1. package p1; public ); SamePackage ob3 = new SamePackage();

13 Данная программа выводит: main(). Тестирование пакета p1 main(). Создание объекта класса Protection Конструктор Protection n = 1 n_pri = 2 n_pro = 3 n_pub = 4 main(). Создание объекта класса Derived Конструктор Protection n = 1 n_pri = 2 n_pro = 3 n_pub = 4 Конструктор Derived n = 1 n_pro = 3 n_pub = 4 main(). Создание объекта класса SamePackage из пакета p1 Конструктор класса SamePackage из пакета p1. Создаю объект класса Protection Конструктор Protection n = 1 n_pri = 2 n_pro = 3 n_pub = 4 Продолжение работы конструктора SamePackage. Работаю с объектом класса Protection n = 1 n_pro = 3 n_pub = 4 Для тестирования пакета p2 создадим следующий файл Demo_p2.java: // Файл Demo_p2.java // Тестирование пакета p2 package p2; //Создает объекты различных классов из р2. public ); OtherPackage ob2 = new OtherPackage(); Состав созданного проекта показан в окне Package Explorer на рис.9. Для запуска нужного класса нужно выбрать его в окне Project Explorer и выполнить команду меню Run, Run (комбинация клавиш Ctrl+F11).

14 Рис. 9. Состав проекта с двумя пакетами Программа из класса Demo_p2 выводит: main(). Тестирование пакета p2 main(). Создание объекта класса Protection2 Конструктор Protection n = 1 n_pri = 2 n_pro = 3 n_pub = 4 Конструктор Protection2, производного от Protection n_pro = 3 n_pub = 4 main(). Создание объекта OtherPackage пакета p2 Конструктор класса OtherPackage пакета p2 Создаю объект класса Protection Конструктор Protection n = 1 n_pri = 2 n_pro = 3 n_pub = 4 Работаю с объектом класса Protection n_pub = Импорт пакетов Все встроенные классы Java хранятся в пакетах. В неименованном пакете умолчания нет классов ядра Java, все стандартные классы хранятся в нескольких именованных пакетах. Так как классы в пакетах должны быть полностью квалифицированы именем (или именами) их пакета, весьма утомительно печатать длинное, разделенное точками полное пакетное имя каждого класса, который нужно использовать.

15 Чтобы обеспечить видимость некоторых классов или полных пакетов Java, используется оператор import. После импортирования на класс можно ссылаться прямо, используя только его имя. Для записи законченной программы в операторе import нет технической необходимости, но он удобен для программиста. Если программа обращается к нескольким десяткам классов, оператор import сохранит массу усилий и времени при вводе кода. В исходном файле Java оператор import следует после оператора package (если он используется) и перед любыми определениями класса. Общая форма оператора import: import pkg1[.ркд2].(classname *) ; Здесь pkg1 имя пакета верхнего уровня, pkg2 имя подчиненного пакета внутри внешнего пакета (имена разделяются точкой). Нет никакого практического предела глубине пакетной иерархии, за исключением того, что обусловлен файловой системой. Наконец, определяется или явное имя класса, или звездочка (*), которая указывает, что компилятор Java должен импортировать полный пакет. Следующий кодовый фрагмент показывает использование обеих форм: import java.util.date; import java.io.*; // Импорт класса Date // Импорт всех классов пакета io Форма со звездочкой может увеличить время компиляции особенно если импортируется несколько больших пакетов. По этой причине лучше явно называть классы, которые нужно использовать, а не импортировать целые пакеты. Однако такая форма не имеет абсолютно никакого влияния на эффективность времени выполнения или на размер классов. Все стандартные классы Java хранятся в пакете с именем Java. Основные функции языка размещаются во внутреннем пакете Java с именем java.lang. Обычно нужно импортировать каждый пакет или класс, который требуется использовать, но, так как Java бесполезен без многих функциональных возможностей java.lang, указанный пакет неявно импортируется компилятором для всех программ. Это эквивалентно появлению следующей строки в начале всех программ: import java.lang.*; Если класс с тем же именем существует в двух различных импортируемых пакетах, компилятор никак не реагирует, пока не последует попытка использовать один из этих классов. В том случае возникнет ошибка времени компиляции, которая устраняется путем явного именования класса с указанием его пакета.

16 Везде, где мы используем имя класса, можно применять полное составное имя, включающее всю иерархию его пакетов. Например, следующий фрагмент использует оператор import: import java.util.*; >> «); else System.out.println(name + «: $» + bal);

17 Теперь класс Balance с общим (public) доступом. То же можно сказать о его конструкторе и методе show (). Это означает, что они доступны любым типам кода вне пакета МуРаск. Например, в следующей программе класс TestBalance импортирует пакет МуРаск и получает возможность использовать класс Balance: // Файл TestBalance.java import MyPack.*; . Интерфейсы разработаны для поддержки динамического вызова методов во время выполнения. Обычно для вызова метода одного класса из другого нужно, чтобы оба класса присутствовали во время компиляции и компилятор Java мог проверить совместимость сигнатур методов. Само по себе это требование предъявляется к статической и нерасширяемой среде классификации. В иерархической же многоуровневой системе, где функциональные возможности обеспечиваются длинными цепочками связанных в иерархию классов, этот механизм неизбежно используется все большим и большим числом

20 System.out.println(«Классы, реализующие интерфейсы » + «могут также определять другие члены.»); Реализации доступа через интерфейсные ссылки Можно объявлять переменные как объектные ссылки, которые используют интерфейсный тип, а не тип класса. В такой переменной можно сохранять всякий экземпляр любого класса, который реализует объявленный интерфейс. Когда мы вызываем метод через ссылку такого рода, будет вызываться его правильная версия, основанная на актуальном экземпляре интерфейса. Это одно из ключевых свойств интерфейсов. Выполняемый метод отыскивается динамически (во время выполнения), что позволяет создавать классы позже кода, который вызывает их методы. Кодом вызова можно управлять через интерфейс, ничего не зная об объекте вызова. Этот процесс подобен использованию ссылки суперкласса для доступа к объекту подкласса. Поскольку динамический поиск метода во время выполнения приводит к существенной потере производительности по сравнению с нормальным вызовом, следует проявлять осторожность и беспричинно не использовать интерфейсы там, где нужна повышенная эффективность. В следующем примере вызов метода callback() выполняется через ссылочную переменную интерфейса: >

22 + (p * p)); Второй класс выполняет тестирование двух реализаций интерфайса: // Файл TestIface2.java >

24 vo ); for(int i = 0; i 25 Стек в mystack1: Стек в mystack2: Теперь создадим другую реализацию интерфейса IntStack, которая создает динамический стек. В ней каждый стек создается в виде массива с некоторой исходной длиной. Если эта исходная длина превышена, то стек увеличивается в размере в два раза. // Файл DynStack.java // Реализует «растущий» стек. ); return 0; else return stck[tos—];

26 ); В данной программе, как и в программа 42, есть два класса, включающие метод main(), которые, следовательно, можно направлять на выполнение. В программе 42 классы с методом main() находятся в файлах названия которых (TestIface и TestIface2) совпадают с именами классов (рис. 11), поэтому для их запуска нужно выбрать в окне Package Explorer соответствующий файл и выполнить команду Run, Run или нажать Ctrl + F11.

27 Рис. 11. Состав проектов В рассматриваемой программе имена классов с методом main() отличаются от имен соответствующих файлов, поэтому для запуска нужного класса нужно выделить в окне Package Explorer не файл, а сам класс, затем в контекстном меню, вызываемом правой кнопкой мыши, выбрать команду Run As, Java Application (рис 12).

28 Рис. 12. Запуск класса из файла с отличающимся именем При запуске класса IFTest2 получаем вывод: Стек в mystack1: Стек в mystack2: Следующий класс использует обе реализации. DynStack и FixedStack через интерфейсную ссылку. Это означает, что обращение к push() и pop() осуществляется во время выполнения, а не во время компиляции. // Файл IFTest3.java /* Создать интерфейсную переменную и обратиться к стекам через нее. */ ); Программа выводит: Значения динамического стека:

Пакеты в Java (Packages in Java)

Пакет (Package) в Java это механизм для инкапсуляции группы классов, под пакетов и интерфейсов. Пакеты используются для:

  • Чтобы не было конфликтов в названиях классов. Например может быть два класса, которые называются Employee, но в двух разных пакетах.
  • Делает поиск и использование классов, интерфейсов, нумераций и аннотаций более удобным.
  • Предоставляет управляемый доступ: protected и default классы доступны только в пакете. protected классы доступны только классам, которые находятся в этом же пакете и наследникам этого класса. Default классы доступны только классам из того же пакета.
  • Пакеты могут быть использованы как инкапсуляция данных или же для того чтобы прятать данные. Все что нужно это добавить классы в пакет. После этого мы можем использовать в своей программе эти классы, используя директиву import. Пакеты — это контейнер для группы классов где некоторые классы могут быть доступны из вне, а другие для внутреннего использования в пакете.

Мы можем использовать классы из пакета столько раз сколько потребуется в программе.

Как работают пакеты?

Имя пакета и структура директорий в проекте зависимы (по сути пакеты это директории). Например, если имя пакет com.idurdyev.staff , то структура директорий будет следующая com/idurdyev/staff .

Соглашение о наименовании пакетов: Пакеты принято называть в обратном порядке, то есть com.idurdyev.test , ru.yourcompanydomain.projectname , etc.


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

Подпакеты: Пакеты, которые находятся внутри другого пакета называются подпакеты (subpackages). При этом классы в подпакете не имеют доступ к классам пакета, если классы объявлены как protected или default .

Пример :

util — это подпакет, который создан в пакете java.

Доступ к классам внутри пакетов

Рассмотрим следующие примеры :

Первое выражение необходимо для импорта класса Vector из пакета util, который находится в java. Второе выражение подключается все классы из пакета util.

Типы пакетов

Встроенные пакеты

Эти пакет содержат большое количество классов, которые являются частью Java API. Вот некоторые встроенные пакеты:

  1. java.lang : Содержит классы для использования самого языка (например классы с примитивными типами, класс для математических операций и т.д.). Этот пакет импортируется автоматически.
  2. java.io : Пакет содержит классы для операций ввода/вывода.
  3. java.util : Содержит утилитарные классы, что в общем-то понятно из названия пакета. Например, Linked List, Dictionary, а так же классы для работы с датой и временем.
  4. java.applet : Содержит классы для создания апплетов.
  5. java.awt : Содержит классы для работы с графическим интерфейсом.
  6. java.net : Содержит классы для работы с сетевыми операциями.

Пользовательские пакеты

Это пакеты, которые создаются пользователями (пользователями языка java). Сначала мы создаем директорию пакета myPackage, затем в нем создает класс MyClass внутри этого пакета.

Теперь мы можем использовать класс MyClass в нашей программе

Заметка : MyClass.java должен быть сохранен внутри пакета myPackage.

Использование статического импорта

Статический импорт был представлен в Java в версии 5 и выше, эта возможность разрешает использовать поля и методы, которые объявлены как public static в других класс, без указании класса.

Следующий пример демонстрирует эту возможность:

Некоторые важные моменты:

  1. Каждый класс является частью какого-нибудь пакета.
  2. Если не указан пакет, то класс создается в специальном не именованном пакете.
  3. Все классы и интерфейсы в файле являются частью того же пакета. Множество файлов могут быть установлены в тот же пакет.
  4. Если задано имя пакета, то файл должен располагаться в той же директории, с именем как у заданного пакета. (то есть директория должна называться так же как и пакет)
  5. Мы можем получить доступ к публичным классам в любом другом пакете, используя выражение: package-name.class-name

Данный материал является переводом этой статьи.

Познаём Java. Вторая чашка: собираем классы в кучки. Пробуем апплеты

Чем обусловлена структура Java?

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

Как происходит загрузка классов?

Для того, чтобы найти класс по имени когда вы его вызываете, в Java существует стандартный загрузчик классов. Он оперирует понятием classpath. Список classpath — это набор путей, где следует искать файлы классов. Каждый classpath может указывать как на директорию, так и на так называемый jar-файл (зазипованная директория со скомпилированными .class’ами и разрешением .jar, типа «йА java-archive!»). По умолчанию в classpath входят файлы стандартных библиотек и директория, из которой вы вызвали саму Java. Именно таким образом был найден класс HelloWorld — java нашла файл HelloWorld.class и запустила в нём метод main. Собственно, так и работают большинство программ, даже самых сложных. Всё начинается с одного main’а…

Пакеты классов

Пакет (package) представляют собой набор классов, объединённых по смыслу. Пакеты обычно вкладываются друг в друга, образуя собо иерархию, дающую понять, что зачем. На файловой системе такая иерархия выглядит в виде вложенных друг в друга директорий с исходниками. Так, исходники пакета a лежат в папке a, исходники пакета a.b — в папке a/b и так далее. Типичный путь к пакету выглядит примерно так:
org.apache.commons.collectons . Видите, сразу ясно зачем он нужен. Чтобы использовать какой-то класс в коде другого класса, вы должны импортировать его, написав до объявления класса строку
import путь.к.классу.ИмяКласса;
Кроме того, если вы используете классы одного пакета часто, вы можете импортировать весь пакет:
import путь.к.классу.*;
Это относится ко всем пакетам, кроме java.lang — он импортирован по умолчанию, именно из него были в прошлом примере взяты классы System и String. На самом деле они лежат в некоем jar’е, в каталоге java/lang.

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

Организация кода

Если вы пишете свои первые маленькие примерчики и вам лень создавать иерархию классов — пусть, это ваше право. Но помните, в серьёзном проекте вы всегда должны будете разложить свои классы по пакетам. Обычно корневые пакеты создаются такими, чтобы ясно давать понять кто автор кода, и к чему он относится.
Например:
ru.vasiapupkin.photomaker выбирается корневым пакетом
ru.vasiapupkin.photomaker.core сюда мы пишем классы отвечающие за логику
ru.vasiapupkin.photomaker.visual сюда, допустим, все наши окошки приложения

и так далее.
Чтобы создать класс
ru.vasiapupkin.photomaker.Starter
вы должны:
создать файл Starter.java в папке ru/vasiapupkin/photomaker/
прописать в нём первой строчкой (точнее говоря, до импортов)
package ru.vasiapupkin.photomaker;

Коллижн

«А что будет, если у нас будет два класса с одним именем?», — спросите вы. «Смотрите», — отвечу я.
Допустим вы решили что вы умнее джавы и создали свой класс строки — String. Но вот проблема, у нас же уже есть такой!
Значит, вам придётся положить свой класс в пакет, скажем ru.vp.stuff и обращаться к нему так: ru.vp.stuff.String.
Именно поэтому не рекомендуется класть классы прямо в корень classpath — таким образом вы роете себе дорогу к несовместимости, ведь Java требует, чтобы каждый класс определялся однозначно. Именно поэтому нельзя написать так:
import ru.vp.SuperClass;
import ru.mashka.SuperClass;
За это вас накажет компилятор, потому что он не будет знать, какой из них использовать.
Мораль: правильно выбирайте и имя класс и имя пакета.

Погоняем?

Давайте улучшим первое приложение. Эх, классика интернета… Создадим апплет.

Эх, может быть апплетами.

import java.applet.Applet ;
import java.awt.Graphics ;

public class HelloWorld extends Applet<

public void paint( Graphics g) <
g.drawString( «Hello World» ,15,15);
>

>

* This source code was highlighted with Source Code Highlighter .

Так, что у нас тут? Импортировано 2 класса, один из них — стандартный пустой апплет, который мы будем расширять. Второй — Graphics. Graphics — это понятие из библиотеки AWT. Кстати, небольшой экскурс. AWT (Abstract Window Toolkit) входил ещё в первую Java и был предназначен для многих задач, связанных в основном с отображением.
Так вот, объект типа Graphics позволяет нам рисовать на себе всякую муру типа строк, линий, кружочков и прочего. В данном примере мы написали строчку с отступом.
Метод paint здесь написан не от балды — он перекрывает аналогичный метод класса Applet, и когда java будет перерисовывать этот конкретный апплет, она вызовет этот метод.

Посмотреть на наш апплет достаточно просто — пишем небольшой HTML:

body >
applet code =»HelloWorld.class» codebase =»file:///home/devgru/» width =»150″ height =»30″ > applet >
body >

* This source code was highlighted with Source Code Highlighter .

… а может приложением.

Давайте попробуем сделать HelloWorld в standalone-приложении.

import java.awt.* ;
import javax.swing.* ;
public class HelloWorld extends JFrame<

public static void main( String [] args) <
new HelloWorld();
>

<
add( new JLabel( «Hello world» ));
setSize(200,200);
setVisible( true );
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
>
>

* This source code was highlighted with Source Code Highlighter .

Здесь мы полностью импортируем основные классы пакетов Swing и AWT. Swing — более поздняя чем AWT библиотека, сейчас именно она обеспечивает отображение основной части графического интерфейса для Java-приложений.
Итак, в main мы просто создаём экземпляр класса HelloWorld.
Сейчас наш класс наследуется от класса JFrame. Это класс из Swing, он представляет собой окно, которое отображается пока не будет закрыто.
Блок <. >— это «общий конструктор». Он добавляется к любому конструктору нашего класса. Так как у нас нет ни одного — он добавляется к пустому конструктору без параметров, который создаётся на лету, если у класса нет ни одного.
Мы добавляем на окно новый объект типа JLabel (т.е. надпись), затем устанавливаем окну размеры и отображаем его. Последняя строчка нужна, чтобы выполнение приложения закончилось, когда будет закрыто окно. Таким образом, вы можете быть уверены что после закрытия окна у вас в памяти не останется висеть ваше приложение.
Запускать его нужно точно так же как и прошлое: пишем, компилируем, запускаем.

А может и сервлетами? Наверное, потом.

В этих двух статьях я постарался дать вам начальное представление о возможностях Java в общем. За рамками сегодняшней статьи (наверное, будут в завтрашней) остались сервлеты и прочие радости серверной части типа JSP-страниц, а также МИДлеты — приложения для мобилок. Я бы мог рассмотреть и то и то, но хотел бы знать, чего больше хотят читатели. Кроме того, возможно, нужно рассказать о самых основах языка. Примерно на том же уровне подробности, что и начало этой статьи. Напишите в комментариях, какую статью вы хотели бы видеть в следующий раз:
— классы и интерфейсы: ООП в джаве;
— буквы-цифры-строчки: работа с базовыми типами;
— создание оконных приложений с помощью Swing;
— от мала до велика: сервлеты, мидлеты и 2 слова о портлетах.

Когда отпишетесь — станет ясно, куда копать дальше. Всем спасибо за внимание.

Ссылка для тех, кому лень ждать завтра: основы языка (eng.).

Пакеты и интерфейсы

Интерфейсы Java созданы для поддержки динамического выбора (resolution) методов во время выполнения программы. Интерфейсы похожи на классы, но в отличие от последних у интер­фейсов нет переменных представителей, а в объявлениях методов отсут­ствует реализация. Класс может иметь любое количество интерфейсов. Все, что нужно сделать — это реализовать в классе полный набор методов всех интерфейсов. Сигнатуры таких методов класса должны точно совпадать с сигнатурами методов реализуемого в этом классе интерфейса. Интер­фейсы обладают своей собственной иерархией, не пересекающейся с классовой иерархией наследования. Это дает возможность реализовать один и тот же интерфейс в различных классах, никак не связанных по линии иерархии классового наследования. Именно в этом и проявляется главная сила интерфейсов. -Интерфейсы являются аналогом механизма множественного наследования в -C++, но использовать их намного легче.

Определение интерфейса сходно с определением класса, -отличие со­стоит в том, что в интерфейсе отсутствуют объявления данных и кон­структоров. Общая форма интерфейса приведена ниже:

тип_результата имя_метода1(список параметров)-

тип имя_final1-переменной = значение-

Обратите внимание — у объявляемых в интерфейсе ме­тодов отсутствуют операторы тела. Объявление методов завершается сим­волом — (точка с запятой). В интерфейсе можно объявлять и переменные, при этом они не­явно объявляются final — -переменными. Это означает, что класс реализа­ции не может изменять их значения. Кроме того, при объявлении переменных в интерфейсе их обязательно нужно инициализировать кон­стантными значениями. Ниже приведен пример определения интерфейса, содержащего единственный метод с именем callback и одним параметром типа int.

void callback(int param)-

Оператор implements — это дополнение к определению класса, реали­зующего некоторый интерфейс(ы).

class имя_класса [extends суперкласс]

[implements интерфейс0 [, интерфейс1…]]

Если в классе реализуется несколько интерфейсов, то их имена раз­деляются запятыми. Ниже приведен пример класса, в котором реализуется определенный нами интерфейс:

class Client implements Callback <

System.out.println(«callback called with » + p)-

В очередном примере метод callback интерфейса, определенного ранее, вызывается через переменную — -ссылку на интерфейс:

public static vo >

Ниже приведен результат работы программы:

С:&#92-&gt- Java TestIface

callback called with 42

Переменные в интерфейсах

Интерфейсы можно использовать для импорта в различные классы со­вместно используемых констант. В том случае, когда вы реализуете в классе какой-либо интерфейс, все имена переменных этого интерфейса будут видимы в классе как константы. Это аналогично использованию файлов-заголовков для задания в С и C++ констант с помощью директив #define или ключевого слова const -в -Pascal / Delphi.

Если интерфейс не включает в себя методы, то любой класс, объяв­ляемый реализацией этого интерфейса, может вообще ничего не реали­зовывать. Для импорта констант в пространство имен класса предпочти­тельнее использовать переменные с модификатором final. В приведенном ниже примере проиллюстрировано использование интерфейса для со­вместно используемых констант.

class Question implements SharedConstants <

Random rand = new Random()-

int prob = (int) (100 * rand.nextDouble())-

return NO- // 30% else if (prob &lt- 60)

return YES- // 30% else if (prob &lt- 75)

return LATER- // 15% else if (prob &lt- 98)

class AskMe implements SharedConstants <

static void answer(int result) <

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL