Spec-Zone .ru
спецификации, руководства, описания, API
Содержание | Предыдущий | Следующий | Индекс Спецификация языка Java
Третий Выпуск


ГЛАВА 9

Интерфейсы


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

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

Мы различаем два вида интерфейсов - нормальные интерфейсы и типы аннотации.

Эта глава обсуждает общую семантику всех нормальных интерфейсами интерфейсов и типов аннотации (§9.6), верхний уровень (§7.6) и вложенный (§8.5, §9.5). Детали, которые являются определенными для определенных видов интерфейсов, обсуждаются в разделах, выделенных этим конструкциям.

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

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

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

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

9.1 Интерфейсные Объявления

Интерфейсное объявление определяет новый именованный ссылочный тип. Есть два вида интерфейсных объявлений - нормальные интерфейсные объявления и описания типа аннотации:

InterfaceDeclaration: NormalInterfaceDeclaration AnnotationTypeDeclaration

Типы аннотации описываются далее в §9.6.


NormalInterfaceDeclaration:
        InterfaceModifiersopt interface Identifier TypeParametersopt
                ExtendsInterfacesopt InterfaceBody
                
Идентификатор в интерфейсном объявлении определяет имя интерфейса. Ошибка времени компиляции происходит, если у интерфейса есть то же самое простое имя как какой-либо из его классов включения или интерфейсов.

9.1.1 Интерфейсные Модификаторы

Интерфейсное объявление может включать интерфейсные модификаторы:


InterfaceModifiers:
        InterfaceModifier
        InterfaceModifiers InterfaceModifier

InterfaceModifier: one of
         Annotation public protected private
        abstract static strictfp
Модификатор доступа public обсуждается в §6.6. Не все модификаторы применимы ко всем видам интерфейсных объявлений. Модификаторы доступа protected и private принадлежите только задействованным интерфейсам в пределах непосредственно объявления класса включения (§8.5), и обсуждаются в §8.5.1. Модификатор доступа static принадлежит только задействованным интерфейсам (§8.5, §9.5). Ошибка времени компиляции происходит, если тот же самый модификатор появляется не раз в интерфейсном объявлении. Если аннотация на интерфейсном объявлении соответствует типу T аннотации, и T имеет (мета-) аннотация м., который соответствует annotation.Target, тогда у м. должен быть элемент, значение которого annotation.ElementType.TYPE, или ошибка времени компиляции происходит. Модификаторы аннотации описываются далее в §9.7.

9.1.1.1 абстрактные Интерфейсы

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

9.1.1.2 Интерфейсы strictfp

Эффект strictfp модификатор должен сделать все float или double выражения в пределах интерфейсного объявления быть явно строгим FP (§15.4).

Это подразумевает, что все вложенные типы, объявленные в интерфейсе, неявно strictfp.

9.1.2 Универсальные Интерфейсы и Параметры Типа

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

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

Это - ошибка времени компиляции, чтобы обратиться к параметру типа интерфейса I где угодно в объявлении поля или элементе типа меня.

9.1.3 Суперинтерфейсы и Подынтерфейсы

Если extends пункт обеспечивается, тогда объявляемый интерфейс расширяет каждый из других именованных интерфейсов и поэтому наследовал типы элемента, методы, и константы каждого из других именованных интерфейсов. Эти другие именованные интерфейсы являются прямыми суперинтерфейсами объявляемого интерфейса. Любой класс это implements объявленный интерфейс, как также полагают, реализует все интерфейсы что этот интерфейс extends.


ExtendsInterfaces:
        extends InterfaceType
        ExtendsInterfaces , InterfaceType

Следующее повторяется от §4.3, чтобы сделать представление здесь более четким:


InterfaceType:
        TypeDeclSpecifier TypeArgumentsopt
        
Данный (возможно универсальный) соединяют интерфейсом с объявлением, поскольку я <F1..., Fn>, n0, прямые суперинтерфейсы интерфейсного типа (§4.5) я <F1..., Fn> являются типами, поданными, расширяет пункт объявления меня, если расширяется, пункт присутствует.

Позвольте мне <F1..., Fn>, n> 0, быть универсальным интерфейсным объявлением. Прямые суперинтерфейсы параметризованного интерфейсного типа I <T1..., Tn>, где Ti, 1 дюйм, является типом, являются всеми типами J <тета U1..., Британская тета>, где J <U1..., Великобритания> являются прямым суперинтерфейсом меня <F1..., Fn>, и тета является заменой [F1: = T1..., Fn: = Tn].

Каждый InterfaceType в extends пункт интерфейсного объявления должен назвать доступный интерфейсный тип; иначе ошибка времени компиляции происходит.

Интерфейс I непосредственно зависит от типа T, если T упоминается в extends пункт я или как суперинтерфейс или как спецификатор в пределах суперинтерфейсного имени. Интерфейс I зависит от ссылочного типа T, если какое-либо из следующих условий содержит:

Ошибка времени компиляции происходит, если интерфейс зависит от себя.

В то время как каждый класс является расширением класса Object, нет никакого единственного интерфейса, которого все интерфейсы являются расширениями.

Суперинтерфейсное отношение является переходным закрытием прямого суперинтерфейсного отношения. Интерфейсный K является суперинтерфейсом интерфейса I, если любое из следующего является истиной:

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

9.1.4 Интерфейсные Объявления Тела и Элемента

Тело интерфейса может объявить элементы интерфейса:


InterfaceBody:
        { InterfaceMemberDeclarationsopt }

InterfaceMemberDeclarations:
        InterfaceMemberDeclaration
        InterfaceMemberDeclarations InterfaceMemberDeclaration

InterfaceMemberDeclaration:
        ConstantDeclaration
        AbstractMethodDeclaration
        ClassDeclaration 
        InterfaceDeclaration
        ;                          
Контекст объявления элемента м. объявил в или наследовался интерфейсным типом, я - все тело меня, включая любые объявления вложенного типа.

9.1.5 Доступ, чтобы Соединить интерфейсом с Именами элемента

Все интерфейсные элементы неявно public. Они доступны вне пакета, где интерфейс объявляется, если интерфейс также объявляется public или protected, в соответствии с правилами §6.6.

9.2 Интерфейсные Элементы

Элементы интерфейса:

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

Интерфейс наследовался от интерфейсов, которые он расширяет, все элементы тех интерфейсов, за исключением полей, классов, и интерфейсов, которые он скрывает и методы, которые он переопределяет.

9.3 Поле (Постоянные) Объявления


ConstantDeclaration:
        ConstantModifiersopt Type VariableDeclarators ;

ConstantModifiers: 
        ConstantModifier
        ConstantModifier ConstantModifers 

ConstantModifier: one of
        Annotation public static final 
Каждое полевое объявление в теле интерфейса неявно public, static, и final. Разрешается избыточно определить любые из этих модификаторов для таких полей.

Если аннотация на полевом объявлении соответствует типу T аннотации, и T имеет (мета-) аннотация м., который соответствует annotation.Target, тогда у м. должен быть элемент, значение которого annotation.ElementType.FIELD, или ошибка времени компиляции происходит. Модификаторы аннотации описываются далее в §9.7.

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

Это - ошибка времени компиляции для тела интерфейсного объявления, чтобы объявить два поля с тем же самым именем.

Для интерфейса возможно наследовать больше чем одно поле с тем же самым именем (§8.3.3.3). Такая ситуация сам по себе не вызывает ошибку времени компиляции. Однако, любая попытка в пределах тела интерфейса, чтобы обратиться к любому полю его простым именем приведет к ошибке времени компиляции, потому что такая ссылка неоднозначна.

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

9.3.1 Инициализация Полей в Интерфейсах

У каждого поля в теле интерфейса должно быть выражение инициализации, которое не должно быть константным выражением. Переменный инициализатор оценивается и присвоение, выполняемое точно однажды, когда интерфейс инициализируется (§12.4).

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

Таким образом:

interface Test {
        float f = j;
        int j = 1;
        int k = k+1;
}
причины две ошибки времени компиляции, потому что j упоминается в инициализации f прежде j объявляется и потому что инициализация k обращается к k непосредственно.

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

Если ключевое слово this (§15.8.3) или ключевое слово super (15.11.2, 15.12), происходит в выражении инициализации для поля интерфейса, затем если возникновение не в пределах тела анонимного класса (§15.9.5), ошибка времени компиляции происходит.

9.3.2 Примеры Полевых Объявлений

Следующий пример иллюстрирует некоторых (возможно тонкий) точки о полевых объявлениях.

9.3.2.1 Неоднозначные Наследованные Поля

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

Таким образом в примере:

interface BaseColors {
        int RED = 1, GREEN = 2, BLUE = 4;
}
interface RainbowColors extends BaseColors {
        int YELLOW = 3, ORANGE = 5, INDIGO = 6, VIOLET = 7;
}
interface PrintColors extends BaseColors {
        int YELLOW = 8, CYAN = 16, MAGENTA = 32;
}
interface LotsOfColors extends RainbowColors, PrintColors {
        int FUCHSIA = 17, VERMILION = 43, CHARTREUSE = RED+90;
}
интерфейс LotsOfColors наследовал два названные поля YELLOW. Это в порядке, пока интерфейс не содержит ссылки простым именем к полю YELLOW. (Такая ссылка могла произойти в пределах переменного инициализатора для поля.)

Даже если интерфейс PrintColors должны были дать значение 3 к YELLOW вместо значения 8, ссылка на поле YELLOW в пределах интерфейса LotsOfColors все еще считался бы неоднозначным.

9.3.2.2 Умножьте Наследованные Поля

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

В примере в предыдущем разделе, полях RED, GREEN, и BLUE наследованы интерфейсом LotsOfColors больше чем одним способом, через интерфейс RainbowColors и также через интерфейс PrintColors, но ссылка на поле RED в интерфейсе LotsOfColors не считается неоднозначным потому что только одно фактическое объявление поля RED включается.

9.4 Абстрактные Объявления метода


AbstractMethodDeclaration:
        AbstractMethodModifiersopt TypeParametersopt ResultType 
MethodDeclarator Throwsopt ;

AbstractMethodModifiers:
        AbstractMethodModifier
        AbstractMethodModifiers AbstractMethodModifier

AbstractMethodModifier: one of
        Annotation public abstract 
Модификатор доступа public обсуждается в §6.6. Ошибка времени компиляции происходит, если тот же самый модификатор появляется не раз в абстрактном объявлении метода.

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

Каждое объявление метода в теле интерфейса неявно public.

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

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

Отметьте, что метод, объявленный в интерфейсе, не должен быть объявлен static, или ошибка времени компиляции происходит, потому что static методы не могут быть abstract.

Отметьте, что метод, объявленный в интерфейсе, не должен быть объявлен strictfp или native или synchronized, или ошибка времени компиляции происходит, потому что те ключевые слова описывают свойства реализации, а не интерфейсные свойства. Однако, метод, объявленный в интерфейсе, может быть реализован методом, который объявляется strictfp или native или synchronized в классе, который реализует интерфейс.

Если аннотация на объявлении метода соответствует типу T аннотации, и T имеет (мета-) аннотация м., который соответствует annotation.Target, тогда у м. должен быть элемент, значение которого annotation.ElementType.METHOD, или ошибка времени компиляции происходит. Модификаторы аннотации описываются далее в §9.7.

Это - ошибка времени компиляции для тела интерфейса, чтобы объявить, явно или неявно, два метода с эквивалентными переопределению подписями (§8.4.2). Однако, интерфейс может наследовать несколько методов с такими подписями (§9.4.1).

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

Метод в интерфейсе может быть универсальным. Правила для формальных параметров типа универсального метода в интерфейсе являются тем же самым что касается универсального метода в классе (§8.4.4).

9.4.1 Наследование и Переопределение

Метод экземпляра m1, объявленный в интерфейсе I переопределений другой метод экземпляра, m2, объявленный в интерфейсе J эквивалентность оба из следующего, является истиной:

  1. Я - подынтерфейс J.
  2. Подпись m1 является подподписью (§8.4.2) подписи m2.
Если объявление метода d1 с типом R1 возврата переопределяет или скрывает объявление другого метода d2 с типом R2 возврата, то d1 должен быть return-type-substitutable (§8.4.5) для d2, или ошибка времени компиляции происходит. Кроме того, если R1 не является подтипом R2, предупреждение непроверенное должно быть выпущено.

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

Это - ошибка времени компиляции, если описание типа T имеет задействованный метод m1 и там существует метод m2, объявленный в T или супертипе T так, что, все следующие условия содержат:

Методы переопределяются на основе подписи подписью. Если, например, интерфейс объявляет два public методы с тем же самым именем, и подынтерфейс переопределяют одного из них, подынтерфейс все еще наследовал другой метод.

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

Для интерфейса возможно наследовать несколько методов с эквивалентными переопределению подписями (§8.4.2). Такая ситуация сам по себе не вызывает ошибку времени компиляции. Интерфейс, как полагают, наследовал все методы. Однако, один из наследованных методов должен, должен быть тип возврата substitutable для любого другого наследованного метода; иначе, ошибка времени компиляции происходит ( throws пункты не вызывают ошибки в этом случае.)

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

9.4.2 Перегрузка

Если у двух методов интерфейса (ли оба объявленные в том же самом интерфейсе, или обоих наследованных интерфейсом, или один объявленный и один наследованный) есть то же самое имя, но различные подписи, которые не эквивалентны переопределению (§8.4.2), то имя метода, как говорят, перегружается. Этот факт не вызывает трудности и никогда себя результаты в ошибке времени компиляции. Нет никакого необходимого отношения между типами возврата или между throws пункты двух методов с тем же самым именем, но различными подписями, которые не эквивалентны переопределению.

9.4.3 Примеры Абстрактных Объявлений метода

Следующие примеры иллюстрируют некоторых (возможно тонкий) точки об абстрактных объявлениях метода.

9.4.3.1 Пример: Переопределение

Методы, объявленные в интерфейсах, abstract и таким образом не содержите реализацию. Обо все, что может быть выполнено объявлением метода переопределения, кроме подтвердить сигнатуру метода, должно совершенствовать тип возврата или ограничить исключения, которые могли бы быть выданы реализацией метода. Вот изменение примера, показанного в (§8.4.3.1):

class BufferEmpty extends Exception {
        BufferEmpty() { super(); }
        BufferEmpty(String s) { super(s); }
}
class BufferException extends Exception {
        BufferException() { super(); }
        BufferException(String s) { super(s); }
} 
public interface Buffer {
        char get() throws BufferEmpty, BufferException;
}
public interface InfiniteBuffer extends Buffer {
         char get() throws BufferException;                                                                                             // override
}

9.4.3.2 Пример: Перегрузка

В примере кода:

interface PointInterface {
        void move(int dx, int dy);
}
interface RealPointInterface extends PointInterface {
        void move(float dx, float dy);
        void move(double dx, double dy);
}
имя метода move перегружается в интерфейсе RealPointInterface с тремя различными подписями, двумя из них объявленный и один наследованный. Любой не -abstract класс, который реализует интерфейс RealPointInterface должен обеспечить реализации всех трех сигнатур методов.

9.5 Объявления Типа элемента

Интерфейсы могут содержать объявления типа элемента (§8.5). Объявление типа элемента в интерфейсе неявно static и общественность.

Если тип элемента, объявленный с простым именем C, непосредственно включается в пределах объявления интерфейса с полностью определенным именем N, то у типа элемента есть полностью определенное имя Северная Каролина.

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

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

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

9.6 Типы аннотации

Описание типа аннотации является специальным видом интерфейсного объявления. Отличать описание типа аннотации от обычного интерфейсного объявления, ключевого слова interface предшествуется знаком at sign (@).


Обсуждение

Отметьте что знак at sign (@) и ключевое слово interface два отличных маркера; технически возможно разделить их пробелом, но этому строго обескураживают как стиль.



    AnnotationTypeDeclaration:
        InterfaceModifiersopt @ interface Identifier AnnotationTypeBody

    AnnotationTypeBody:
        { AnnotationTypeElementDeclarationsopt }

    AnnotationTypeElementDeclarations:
        AnnotationTypeElementDeclaration
        AnnotationTypeElementDeclarations AnnotationTypeElementDeclaration

    AnnotationTypeElementDeclaration:
        AbstractMethodModifiersopt Type Identifier ( ) DefaultValueopt ;
        ConstantDeclaration
        ClassDeclaration
        InterfaceDeclaration
        EnumDeclaration
        AnnotationTypeDeclaration
        ;

    DefaultValue:
        default ElementValue
        
        


Обсуждение

Следующие ограничения вводятся для описаний типа аннотации на основании их контекста свободный синтаксис:


Если явно не изменено здесь, все правила, которые применяются к обычным интерфейсным объявлениям, применяются к описаниям типа аннотации.


Обсуждение

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

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


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

Если аннотация на описании типа аннотации соответствует типу T аннотации, и T имеет (мета-) аннотация м., который соответствует annotation.Target, тогда у м. должен быть любой элемент, значение которого annotation.ElementType.ANNOTATION_TYPE, или элемент, значение которого annotation.ElementType.TYPE, или ошибка времени компиляции происходит.


Обсуждение

Условно, никакой AbstractMethodModifiers не должен присутствовать за исключением аннотаций.


Прямой суперинтерфейс типа аннотации всегда annotation.Annotation.


Обсуждение

Последствие факта, что тип аннотации не может явно объявить суперкласс или суперинтерфейс, - то, что подкласс или подынтерфейс типа аннотации никогда не являются самостоятельно типом аннотации. Точно так же annotation.Annotation не самостоятельно тип аннотации.


Это - ошибка времени компиляции, если тип возврата метода, объявленного в типе аннотации, является каким-либо типом кроме одного из следующего: одни из типов примитивов, String, Class и любой вызов Class, перечислимый тип (§8.9), тип аннотации, или массив (§10) одного из предыдущих типов. Это - также ошибка времени компиляции, если у какого-либо метода, объявленного в типе аннотации, есть подпись, которая эквивалентна переопределению тому из любого public или protected метод объявляется в классе Object или в интерфейсе annotation.Annotation.


Обсуждение

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


Каждое объявление метода в описании типа аннотации определяет элемент типа аннотации. У типов аннотации могут быть нуль или больше элементов. У типа аннотации нет никаких элементов кроме определенных методами, которые он явно объявляет.


Обсуждение

Таким образом описание типа аннотации наследовало несколько элементов от annotation.Annotation, включая неявно объявленные методы, соответствующие методам экземпляра в Object, все же эти методы не определяют элементы типа аннотации, и это недопустимо, чтобы использовать их в аннотациях.

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


Это - ошибка времени компиляции, если тип T аннотации содержит элемент типа T, любой прямо или косвенно.


Обсуждение

Например, это недопустимо:

// Illegal self-reference!!
@interface SelfRef {
    SelfRef value();
}
и так это:

// Illegal circularity!!
@interface Ping {
    Pong value();
}
@interface Pong {
    Ping value();
}
Отметьте также, что эта спецификация устраняет элементы, типы которых вкладываются массивы. Например, это описание типа аннотации недопустимо:

// Illegal nested array!!
@interface Verboten {
    String[][] value();
}


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

Значения по умолчанию применяются динамически в то время, когда аннотации читаются; значения по умолчанию не компилируются в аннотации. Таким образом изменение значения по умолчанию влияет на аннотации даже в классах, которые были скомпилированы прежде, чем изменение было произведено (предположение, что эти аннотации испытывают недостаток в явном значении принятого значение по умолчанию элемента).

ElementValue используется, чтобы определить значение по умолчанию. Это - ошибка времени компиляции, если тип элемента не соразмерен (§9.7) с определенным значением по умолчанию. ElementValue всегда строг FP (§15.4).


Обсуждение

Следующее описание типа аннотации определяет тип аннотации с помощью нескольких элементов:

// Normal annotation type declaration with several elements

/**
        * Describes the "request-for-enhancement" (RFE) 
        * that led to the presence of 
        * the annotated API element.
 */
public @interface RequestForEnhancement {
    int    id();        // Unique ID number associated with RFE
    String synopsis();  // Synopsis of RFE
    String engineer();  // Name of engineer who implemented RFE
    String date();      // Date RFE was implemented
}
Следующее описание типа аннотации определяет тип аннотации без элементов, назвал тип аннотации маркера:

// Marker annotation type declaration

/**
 * Annotation with this type indicates that the specification of the
 * annotated API element is preliminary and subject to change.
 */
public @interface Preliminary { }


Условно, имя единственного элемента в одноэлементном типе аннотации value.


Обсуждение

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



Обсуждение

Соглашение иллюстрируется в следующем описании типа аннотации:

// Single-element annotation type declaration

/**
 * Associates a copyright notice with the annotated API element.
 */
public @interface Copyright {
    String value();
}
Следующее описание типа аннотации определяет одноэлементный тип аннотации, единственный элемент которого сделал, чтобы массив ввел:

// Single-element annotation type declaration with array-typed 
// element

/**
 * Associates a list of endorsers with the annotated class.
 */
public @interface Endorsers {
    String[] value();
}
Вот пример сложных типов аннотации, типы аннотации, которые содержат один или более элементов, типы которых являются также типами аннотации.

// Complex Annotation Type

/**
 * A person's name.  This annotation type is not designed to be used
 * directly to annotate program elements, but to define elements
 * of other annotation types.
 */
public @interface Name {
    String first();
    String last();
}

/**
 * Indicates the author of the annotated program element.
 */
public @interface Author {
    Name value();
}

/**
 * Indicates the reviewer of the annotated program element.
 */
public @interface Reviewer {
    Name value();
}
Следующее описание типа аннотации обеспечивает значения по умолчанию для двух из его четырех элементов:

// Annotation type declaration with defaults on some elements
public @interface RequestForEnhancement {
    int    id();       // No default - must be specified in 
                                                        // each annotation
    String synopsis(); // No default - must be specified in 
                                                        // each annotation
    String engineer()  default "[unassigned]";
    String date()      default "[unimplemented]";
}
Следующее описание типа аннотации показывает a Class аннотация, значение которой ограничивается ограниченным подстановочным знаком.

// Annotation type declaration with bounded wildcard to 
//      restrict Class annotation
// The annotation type declaration below presumes the existence 
// of this interface, which describes a formatter for Java 
// programming language source code
public interface Formatter { ... }

// Designates a formatter to pretty-print the annotated class.
public @interface PrettyPrinter {
    Class<? extends Formatter> value();
}
Отметьте, что грамматика для описаний типа аннотации разрешает другие объявления элемента помимо объявлений метода. Например, можно было бы хотеть объявлять вложенное перечисление для использования в соединении с типом аннотации:

// Annotation type declaration with nested enum type declaration
public @interface Quality {
    enum Level { BAD, INDIFFERENT, GOOD }

    Level value();
}


9.6.1 Предопределенные Типы Аннотации

Несколько типов аннотации предопределяются в библиотеках платформы Java. У некоторых из этих предопределенных типов аннотации есть специальная семантика. Они семантика определяются в этом разделе. Этот раздел не обеспечивает полную спецификацию для предопределенных аннотаций, содержавшихся здесь в; это - роль соответствующих спецификаций API. Только те семантика, которые требуют специального поведения со стороны компилятора Java или виртуальной машины, определяются здесь.

9.6.1.1 Цель

Тип аннотации annotation.Target предназначается, чтобы использоваться в метааннотациях, которые указывают на вид элемента программы, к которому тип аннотации применим. Target имеет один элемент, типа annotation.ElementType[]. Это - ошибка времени компиляции, если данная перечислимая константа появляется не раз в аннотации, соответствующий тип которой annotation.Target. См. разделы §7.4.1, §8.1.1, §8.3.1, §8.4.1, §8.4.3, §8.8.3, §8.9, §9.1.1, §9.3, §9.4, §9.6 и §14.4 для других эффектов @annotation.Target аннотации.

9.6.1.2 Задержание

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

Тип аннотации annotation.Retention используется, чтобы выбрать среди вышеупомянутых возможностей. Если аннотация, которую соответствование типу T, и T имеют (мета-) аннотация м., который соответствует annotation.Retention, тогда:

Если T не имеет (мета-) аннотация м., который соответствует annotation.Retention, тогда компилятор Java должен обработать T, как будто у этого действительно есть такая метааннотация м. с элементом, значение которого annotation.RetentionPolicy.CLASS.


Обсуждение

Если у м. есть элемент, значение которого annotation.RetentionPolicy.RUNTIME, отражающие библиотеки платформы Java сделают доступное во время выполнения также.


9.6.1.3 Наследованный

Тип аннотации annotation.Inherited используется, чтобы указать, что аннотации на класс C, соответствующий данному типу аннотации, наследованы подклассами C.

9.6.1.4 Переопределение

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


Обсуждение

Классический пример касается, равняется методу. Программисты пишут следующее:

    public boolean equals(Foo that) { ... }
когда они означают писать:

    public boolean equals(Object that) { ... }
Это является совершенно законным, но класс Foo наследовался equals реализация от Object, который может вызвать некоторые очень тонкие ошибки.


Тип аннотации Override поддерживает раннее обнаружение таких проблем. Если объявление метода аннотируется аннотацией @Override, но метод фактически не переопределяет метода, объявленного в суперклассе, ошибка времени компиляции произойдет.


Обсуждение

Отметьте это, если метод переопределяет метод от суперинтерфейса, но не от суперкласса, используя @Override вызовет ошибку времени компиляции.

Объяснение для этого - то, что реальный класс, который реализует интерфейс, обязательно переопределит методы всего интерфейса независимо от @Override аннотация, и таким образом, сбило бы с толку иметь семантику этой аннотации, взаимодействует с правилами для того, чтобы реализовать интерфейсы.

Продуктом этого правила то, что никогда не возможно использовать @Override аннотация в интерфейсном объявлении.


9.6.1.5 SuppressWarnings

Тип аннотации SuppressWarnings поддерживает управление программиста предупреждениями, иначе выпущенными компилятором Java. Это содержит единственный элемент, который является массивом String. Если объявление программы аннотируется аннотацией @SuppressWarnings(value = {S1..., Sk}), затем компилятор Java не должен сообщить ни о каком предупреждении, идентифицированном одним из S1..., Sk, если то предупреждение было бы сгенерировано в результате аннотируемого объявления или какой-либо из его частей.

Предупреждения непроверенные идентифицируются строкой "unchecked".


Обсуждение

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



Обсуждение

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


9.6.1.6 Осуждаемый

Элемент программы аннотируется @Deprecated тот, который программисты отговариваются использовать, обычно потому что это опасно, или потому что существует лучшая альтернатива. Компилятор Java должен произвести предупреждение, когда осуждаемый тип, метод, поле, или конструктор используются (переопределенный, вызванный, или ссылался по имени), если:

Использование аннотации @Deprecated на объявлении локальной переменной или на объявлении параметра не имеет никакого эффекта.

9.7 Аннотации

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

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

Аннотации могут использоваться в качестве модификаторов в любом объявлении, ли пакет (§7.4), класс (§8), интерфейс, поле (§8.3, §9.3), метод (§8.4, §9.4), параметр, конструктор (§8.8), или локальная переменная (§14.4).


Обсуждение

Отметьте, что классы включают перечисления (§8.9), и интерфейсы включают типы аннотации (§9.6)


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

Это - ошибка времени компиляции, если объявление аннотируется больше чем одной аннотацией для данного типа аннотации.


Обсуждение

Аннотации традиционно помещаются перед всеми другими модификаторами, но это не требование; они могут быть свободно смешаны с другими модификаторами.


Есть три вида аннотаций. Первое (нормальная аннотация) является полностью общим. Другие (аннотация маркера и одноэлементная аннотация) являются просто сокращениями.


Annotations:
        Annotation
        Annotations Annotation

    Annotation:
        NormalAnnotation
        MarkerAnnotation
        SingleElementAnnotation
        
Нормальная аннотация используется, чтобы аннотировать элемент программы:

    NormalAnnotation:
        @ TypeName ( ElementValuePairsopt )

    ElementValuePairs:
        ElementValuePair
        ElementValuePairs , ElementValuePair

    ElementValuePair:
        Identifier = ElementValue

    ElementValue:
        ConditionalExpression
        Annotation
        ElementValueArrayInitializer

    ElementValueArrayInitializer:
        { ElementValuesopt ,opt }

    ElementValues:
        ElementValue
        ElementValues , ElementValue
        
        


Обсуждение

Отметьте, что знак at-sign является маркером к себе. Технически возможно поместить пробел промежуточный знак at-sign и TypeName, но этому обескураживают.


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

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

Тип возврата этого метода определяет тип элемента пары значения элемента. ElementValueArrayInitializer подобен нормальному инициализатору массива (§10.6), за исключением того, что аннотации разрешаются вместо выражений.

Тип T элемента соразмерен со значением элемента V, если и только если одно из следующих условий является истиной:

Это - ошибка времени компиляции, если тип элемента не соразмерен с ElementValue.

Если тип элемента не является типом аннотации или типом массива, ElementValue должен быть ConditionalExpression (§15.25).


Обсуждение

Отметьте это null не юридическое значение элемента для любого типа элемента.


Если тип элемента является типом массива, и соответствующим ElementValue не является ElementValueArrayInitializer, значение массива, единственный элемент которого является значением, представленным ElementValue, связывается с элементом. Иначе, значение, представленное ElementValue, связывается с элементом.


Обсуждение

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

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


Аннотация на описание типа аннотации известна как метааннотация. Тип аннотации может использоваться, чтобы аннотировать его собственное объявление. Более широко зацикливания в переходном закрытии "аннотируют" отношение, разрешаются. Например, законно аннотировать описание типа аннотации другим типом аннотации, и аннотировать объявление последнего типа прежним типом. (Предопределенные типы метааннотации содержат несколько таких зацикливаний.)


Обсуждение

Вот пример нормальной аннотации:

// Normal annotation
@RequestForEnhancement(
    id       = 2868724,
    synopsis = "Provide time-travel functionality",
    engineer = "Mr. Peabody",
    date     = "4/1/2004"
)
public static void travelThroughTime(Date destination) { ... }

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


Вторая форма аннотации, аннотации маркера, является сокращением, разработанным для использования с типами аннотации маркера:


    MarkerAnnotation:
        @ TypeName
        
Это - просто сокращение для нормальной аннотации:

        @TypeName()


Обсуждение

Пример:

// Marker annotation
@Preliminary public class TimeTravel { ... }

Отметьте, что законно использовать аннотации маркера для типов аннотации с элементами, пока у всех элементов есть значения по умолчанию.


Третья форма аннотации, одноэлементной аннотации, является сокращением, разработанным для использования с одноэлементными типами аннотации:


    SingleElementAnnotation:
        @ TypeName ( ElementValue )

Это - сокращение для нормальной аннотации:

@TypeName ( value = ElementValue )


Обсуждение

Пример:

// Single-element annotation
@Copyright("2002 Yoyodyne Propulsion Systems, Inc., All rights reserved.")
public class OscillationOverthruster { ... }
Пример с оцененной массивом одноэлементной аннотацией:

// Array-valued single-element annotation
@Endorsers({"Children", "Unscrupulous dentists"})
public class Lollipop { ... }
Пример с одноэлементной оцененной массивом одноэлементной аннотацией (отмечают, что изогнутые фигурные скобки опускаются):

// Single-element array-valued single-element annotation
@Endorsers("Epicurus")
public class Pleasure { ... }
Пример со сложной аннотацией:

// Single-element complex annotation
@Author(@Name(first = "Joe", last = "Hacker"))
public class BitTwiddle { ... }

Отметьте, что законно использовать одноэлементные аннотации для типов аннотации с многократными элементами, пока один элемент называют значением, и у всех других элементов есть значения по умолчанию.

Вот пример аннотации, которая использует в своих интересах значения по умолчанию:

// Normal annotation with default values
@RequestForEnhancement(
    id       = 4561414,
    synopsis = "Balance the federal budget"
)
public static void balanceFederalBudget() {
    throw new UnsupportedOperationException("Not implemented");
}
Вот пример аннотации с элементом Класса, значение которого ограничивается при помощи ограниченного подстановочного знака.

// Single-element annotation with Class element restricted by bounded wildcard
// The annotation presumes the existence of this class.
class GorgeousFormatter implements Formatter { ... }
@PrettyPrinter(GorgeousFormatter.class) public class Petunia {...}
// This annotation is illegal, as String is not a subtype of Formatter!!
@PrettyPrinter(String.class) public class Begonia { ... }
Вот пример аннотации, используя перечислимый тип, определенный в типе аннотации:

// Annotation using enum type declared inside the annotation type
@Quality(Quality.Level.GOOD)
public class Karma {
   ...
}


Содержание | Предыдущий | Следующий | Индекс Спецификация языка Java
Третий Выпуск

Авторское право © 1996-2005 Sun Microsystems, Inc. Все права защищены
Пожалуйста, отправьте любые комментарии или исправления через нашу форму обратной связи

free hit counter