Java. Полное руководство. 8-е издание. С. Н. Тригуб Перевод с английского и редакция
Скачать 25.04 Mb.
|
3 1 6 Часть I. Язык Ниже показан пример создания и использования одночленной аннотации Одночленная аннотация MySingle { int v a l u e (); // именем переменной должно быть value } class Single { // Аннотирование метода одночленной аннотацией static void m y M e t h () { Single ob = new Single(); try { Method m = o b .getClass().getMethod("myMeth"); MySingle anno = m.getAnnotation(MySingle.class); System.out.println(anno.value()); // отображает 100 } catch (NoSuchMethodException exc) Метод не найден static void main(String a r g s []) { my M e t h (Как и ожидалось, эта программа отображает значение 100. Здесь аннотация © M ySingle применяется для аннотирования метода myMeth ( ) , как показано ниже. ©MySingle(100) О б рати те внимание на то, что необязательно указывать Вы можете применять синтаксис одночленных аннотаций и при использовании аннотаций с другими членами, но все остальные члены должны иметь значения по умолчанию. Например, ниже добавляется член x y z со значением по умолчанию , равным В случаях, когда вы хотите использовать значение по умолчанию для членам ож ете применить аннотацию, как показано ниже, просто указав значение для v a l u e си спользованием синтаксиса одночленных аннотаций. ©SomeAnno(88) В этом случае член x y z по умолчанию принимает значение, а член v a l u e — 88. Конечно, чтобы задать другое значение для члена x y z , необходимо, чтобы оба члена были инициированы явно = 88, xyz = Помните, что когда выпри меняете одночленные аннотации, именем члена должно быть Глава 12. Перечисления, автоупаковка и аннотации (метаданные) 3 1 Встроенные аннотации В Java определено очень много встроенных аннотаций. Большинство из них специализированы , но восемь имеют общее назначение. Четыре из них импортируются из пакета java.lang.annotation: ©Retention, ©Documented, ©Target и ©Inherited. Четыре другие аннотации и ©SuppressWarnings — включены в пакет java. lang. Каждая из них описана ниже. А ннотация Эта аннотация предназначена для применения только в качестве аннотации к другим аннотациям . Определяет политику удержания, как было описано в настоящей главе. А ннотация Это — маркер-интерф ейс, который сообщает инструменту, что аннотация должна быть документирована. Он предназначен для использования только в качестве аннотации к объявлению аннотации. Аннотация Эта аннотация задает типы объявлений, к которым может быть применима аннотация. Предназначена для использования только в качестве аннотации к другим аннотациям . Аннотация принимает один аргумент, который должен быть константой из перечисления Туре. Этот аргумент задает типы объявлений, к которым может быть применена аннотация. Эти константы описаны в табл. 12.1 вместе с типами объявлений, к которым они относятся. Таблица 12.1. Константы из перечисления Целевая константа Аннотация может быть применена к ТATION_TYРЕ Другой аннотации CONSTRUCTOR Конструктору FIELD Полю LOCAL_VARIABLE Локальной переменной METHOD Методу PACKAGE Пакету PARAMETER Параметру TYPE Классу, интерфейсу или перечислению Вы можете задать одно или несколько этих значений ванн отац ии ©Target. Чтобы указать множественные значения, следует поместить их внутрь ограниченного фигурными скобками списка. Например, чтобы указать, что аннотация применима только к полями локальным переменным, нужно использовать следующую аннотацию ©Target. ©Target( { ElementType.FIELD, ElementType.LOCAL_VARIABLE } Аннотация Это — аннотация-маркер, которая может применяться в другом объявлении аннотации. Более того, она касается только тех аннотаций, что будут использоваться в объявлениях классов. Аннотация ©Inherited позволяет аннотации суперкласса быть 3 1 Часть I. Язык унаследованной в подклассе. Таким образом, когда осуществляется запрос к подклассу на предмет специфической аннотации, то, если этой аннотации в подклассе нет, проверяется суперкласс. Если запрошенная аннотация присутствует у суперкласса иона аннотирована как ©Inherited, то эта аннотация будет возвращена. А ннотация Аннотация ©Override — аннотация-маркер, которая может применяться только в методах. Метод, аннотированный как ©Override, должен переопределять метод суперкласса. Если он этого не делает, в результате происходит ошибка времени компиляции. Она используется для обеспечения того, что метод суперкласса будет действительно переопределена непросто перегружен. А ннотация Эта аннотация-маркер указывает, что объявление устарело и должно быть заменено более новой формой. А ннотация @Saf Аннотация ©Saf eVarargs — аннотация-маркер, применяемая к методами конструкторам. Она указывает, что никакие небезопасные действия, связанные с параметром переменного количества аргументов, недопустимы. Она используется для подавления неотмеченных предупреждений в остальном безопасном коде относительно нессылочных типов с переменным количеством аргументов и параметрическим созданием экземпляра массива. (Нессылочный тип — это, по существу, обобщенный тип, описанный в главе 14.) Применяется только к методам или конструкторам с переменным количеством аргументов, которые объявлены как static или final. Добавлено bJDK Аннотация Эта аннотация указывает, что одно или более предупреждений, которые могут быть выданы компилятором, следует подавить. Подавляемые предупреждения задаются именами в строковой форме. Эта аннотация может быть применима к объявлениям любого типа. Некоторые ограничения Существует некоторое количество ограничений, касающихся объявления аннотаций. Во-первых, одна аннотация не может наследовать другую. Во-вторых, все методы, объявленные в аннотации, не должны принимать параметров. Более того, они должны возвращать один из перечисленных ниже типов: • элементарный тип, такой как int или объект класса String или тип перечисления; • тип другой аннотации; • массив одного из предыдущих типов. Аннотации не могут быть обобщенными. Другими словами, они не могут принимать параметры типа. (Обобщения рассматриваются в главе 14.) И наконец, в методах аннотации не может быть указана конструкция throws. Ввод-вывод, аплеты и другие темы Настоящая глава посвящена двум наиболее важным пакетами. Пакет i o поддерживает базовую систему ввода-вывода Java, включая файловый ввод- вывод. Пакет a p p l e t поддерживает аплеты. Поддержка ввода-вывода и аплетов осуществляется ядром библиотек программного интерфейса (API), а не ключевыми словами языка. По этой причине углубленное обсуждение этих тем содержится в части II, где рассматриваются классы API. В этой главе описаны основы этих двух подсистем, чтобы вы смогли увидеть, как они интегрированы в языки встроены в общий контекст программирования на языке Java и его исполняющей системы. В этой главе также рассматриваются новый оператор JDK 7 t r y с - ресурсами и последние из ключевых слов Java: t r a n s i e n t , v o l a t i l e , i n s t a n c e o f , n a t i v e , s t r i c t f p и a s s e r t . Завершает главу описание статического импорта и применения ключевого слова t h i s Основы ввода-вывода Как вы могли заметить, читая главу 12, до сих пор в примерах программ было задействовано не так много операций ввода-вывода. Фактически, помимо методов p r i n t () и p r i n t l n ( ), никаких методов ввода-вывода, в общем-то, и не применялось. Причина этого проста большинство реальных приложений Java не являются текстовыми консольными программами. Вместо этого они являются программами с графическим пользовательским интерфейсом на базе библиотеки или веб-приложениями. Хотя текстовые, консольные программы великолепны в качестве учебных примеров, они не занимают сколько-нибудь значительную часть в мире реальных программ. К тому же, поддержка консольного ввода-вывода в Java ограничена и не слишком удобна вис пользовании — даже для простейших программ. Тем не менее текстовый консольный ввод-вывод вполне применим в реальном программировании на языке Язык Java обеспечивает мощную и гибкую поддержку ввода-вывода, когда это касается файлов и сетей. Система ввода-вывода Java целостна и последовательна. Фактически, если однажды разобраться с ее базовыми принципами, все остальное для профессионала становится простым. Здесь представлен лишь общий обзор ввода и вывода. Подробное описание находится в главах 19 и 20. Потоки Программы Java создают потоки ввода-вывода. Поток (stream) — это абстракция, которая либо порождает, либо принимает информацию. Поток связан с физическим устройством при помощи системы ввода-вывода Java. Все потоки ведут себя на 3 1 Часть I. Язык один манер, даже несмотря на то, что реальные физические устройства, к которым они подключены, отличаются друг от друга. Таким образом, одни и те же классы и методы ввода-вывода применимы к устройствам разного типа. Это означает, что абстракция входного потока может охватить разные типы ввода из дискового файла, клавиатуры или сетевого сокета. Аналогично выходной поток может ссылаться на консоль, дисковый файл или сетевое подключение. Потоки — это ясный способ обращения с вводом-выводом без необходимости для вашего кода разбираться враз личиях, например, между клавиатурой и сетью. Язык Java реализует потоки внутри иерархии классов, определенных в пакете j ava. На заметку В дополнение к потоковому вводу-выводу, определенному в пакете j ava. io, язык Java предоставляет также буферы и канальный ввод-вывод, определенные в пакете j ava. nio и его вложенных пакетах. Они описаны в главе Байтовые и символьные потоки определяет два типа потоков байтовые и символьные. Байтовые потоки предоставляют удобные средства для управления вводом и выводом байтов. Эти потоки используются, например, при чтении и записи бинарных данных. Символьные потоки предлагают удобные средства управления вводом и выводом символов. Они используют кодировку Unicode и, таким образом, могут быть интернационализиро ваны. Кроме того, в некоторых случаях символьные потоки более эффективны, чем байтовые. Исходная версия Java (Java 1.0) не включала символьных потоков, и потому весь ввод-вывод был ориентированна код виртуальной машины. Символьные потоки были добавлены в Java 1.1, и при этом некоторые ориентированные на код виртуальной машины классы и методы устарели. Хотя старый код, в котором не используются символьные потоки, встречается все реже, он все еще время от времени применяется. Как правило, старый код должен быть, по возможности, обновлен, чтобы воспользоваться преимуществами символьных потоков. Еще один момент на самом низком уровне весь ввод-вывод по-прежнему ориентированна код виртуальной машины. Символьные потоки просто предлагают удобные и эффективные средства управления символами. Обзор потоков, ориентированных на код виртуальной машины и символы, представлен в следующих разделах. Классы байтовых потоков Байтовые потоки определены в двух иерархиях классов. На вершине находятся абстрактные классы Input St ream и Output St ream. Каждый из этих абстрактных классов имеет несколько реальных подклассов, которые контролируют различия между разными устройствами, такими как дисковые файлы, сетевые подключения и даже буферы памяти. Классы байтовых потоков из пакета j ava . io перечислены в табл. 13.1. Некоторые из этих классов описываются ниже, а другие — в части II. Помните, что для использования потоковых классов необходимо импортировать пакет j ava. Таблица 13.1. Классы байтовых потоков из пакета Потоковый класс OutputStream_Буферизированный_входной_поток_Буферизированный_выходной_поток_Глава_13._Ввод-вывод,_аплеты_и_другие_темы'>Назначение BufferedlnputStream BufferedOutputStream Буферизированный входной поток Буферизированный выходной поток Глава 13. Ввод-вывод, аплеты и другие темы 3 1 Окончание табл. Потоковый класс Назначение ByteArrayInputStream Входной поток, читающий из массива байт eArrayOutput St Выходной поток, записывающий в массив байт DatalnputStream Входной поток, включающий методы для чтения стандартных типов данных Выходной поток, включающий методы для записи стандартных типов данных Входной поток, читающий из файла FileOutputStream Выходной поток, записывающий в файл FilterInputStream Реализация класса Реализация класса Абстрактный класс, описывающий поток ввода ObjectlnputStream Входной поток для объектов Выходной поток для объектов OutputStream Абстрактный класс, описывающий поток вывода PipedlnputStream Входной канал (например, межпрограммный) PipedOutputStream Выходной канал PrintStream Выходной поток, включающий методы print () и p r i n t l n (Входной поток, поддерживающий однобайтовый возврат во входной поток SequenceInputStream Входной поток, представляющий собой комбинацию двух и более входных потоков, которые читаются совместно, — один после другого Абстрактные классы Input St ream и Output St ream определяют несколько ключевых методов, которые реализуют другие потоковые классы. Два наиболее важных — это методы read () и write ( ), которые, соответственно, читают и пишут байты данных. Оба метода объявлены как абстрактные внутри классов Input St ream и Output St ream. В наследующих классах они переопределяются. Классы символьных потоков Символьные потоки также определены в двух иерархиях классов. На их вершине находятся два абстрактных класса Reader и Writer. Эти абстрактные классы управляют потоками символов Unicode. В языке Java предусмотрено несколько конкретных подклассов для каждого из них. Классы символьных потоков перечислены в табл. Таблица 13.2. Классы символьных потоков из пакета j a v a . i Потоковый класс Назначение ^__________ Buf f eredReader Буферизированный входной символьный поток f eredWriter Буферизированный выходной символьный поток Входной поток, который читает из символьного массива 3 2 0 Часть I. Язык Окончание табл. Потоковый класс Назначение Выходной поток, который пишет в символьный массив FileReader Входной поток, читающий файл FileWriter Выходной поток, пишущий в файл FilterReader Фильтрующий читатель FilterWriter Фильтрующий писатель InputStreamReader Входной поток, транслирующий байты в символы LineNumberReader Входной поток, подсчитывающий строки OutputStreamWriter Выходной поток, транслирующий байты в символы PipedReader Входной канал PipedWriter Выходной канал PrintWriter Выходной поток, включающий методы () и println (Входной поток, позволяющий возвращать символы обратно в поток Reader Абстрактный класс, описывающий символьный ввод StringReader Входной поток, читающий из строки StringWriter Выходной поток, пишущий в строку Writer Абстрактный класс, описывающий символьный вывод Абстрактные классы Reader и Writer определяют несколько ключевых методов, которые реализуют другие потоковые классы. Два наиболее важных — это методы read () и write ( ), которые, соответственно читают и пишут символьные данные. Эти методы переопределяются в производных потоковых классах. Предопределенны е потоки Как вызнаете, все программы Java автоматически импортируют пакет java. lang. В этом пакете определен класс System, инкапсулирующий некоторые аспекты среды времени выполнения. Например, используя некоторые из его методов, можно получить текущее время и настройки различных параметров, ассоциированных с системой. Класс System также содержит три предопределенные потоковые переменные-чЛена: in, out и err. Эти переменные объявлены в классе System как public, static и final. Это значит, что они могут быть использованы любой другой частью вашей программы без обращения к специфическому объекту класса Переменная Sys t em . out ссылается на стандартный выходной поток. По умолчанию это консоль. Переменная System, in ссылается на стандартный входной поток, который также по умолчанию является консолью. Переменная System, err ссылается на стандартный поток ошибок, который также по умолчанию связан с консолью. Однако эти потоки могут быть перенаправлены на любое совместимое устройство ввода-вывода. Переменная System, in — это объект класса Input St ream, а переменные System, out и System, err — объекты класса PrintStream. Это байтовые потоки, хотя обычно они используются для чтения и записи символов с консоли и Глава 13. Ввод-вывод, аплеты и другие темы 2 на консоль. Как вы увидите, при необходимости их можно поместить в оболочки символьных потоков. В примерах, приведенных в предыдущих главах, использовался поток System, out. Вы можете почти таким же образом применять поток System, err. Как будет показано в следующем разделе, использование потока System. in немного сложнее. Чтение консольного ввода В языке Java 1.0 единственным способом выполнения консольного ввода было использование байтового потока. Сегодня применение байтового потока для чтения консольного ввода по-прежнему возможно. Однако для коммерческих приложений предпочтительный метод чтения консольного ввода — это использовать символьный поток. Это значительно упрощает возможности интернационализации и поддержки разрабатываемых программ. В языке Java консольный ввод осуществляется чтением потока System, in. Чтобы получить символьный поток, присоединенный к консоли, следует поместить поток System, in в оболочку объекта класса Buf f eredReader. Объект класса Buf f eredReader поддерживает буферизованный входной поток. Его наиболее часто используемый конструктор выглядит так считывательВвода) Здесь считывательВвода — это поток, который связывается с создаваемым экземпляром класса Buf f eredReader. Класс Reader — абстрактный класс. Одним из его конкретных наследников является класс Input St reamReader, который преобразует байты в символы. Для получения объекта класса Input St reamReader, который присоединен к потоку System, in, служит следующий конструктор. |