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

ГЛАВА 9

Интерфейсы


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

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

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

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

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

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

Интерфейсное объявление определяет новый ссылочный тип:

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


class Point { int x, y; }
interface Point { void move(int dx, int dy); }
ошибка времени компиляции происходит потому что a class и interface в том же самом пакете не может иметь того же самого имени.

9.1.1 Контекст Интерфейсного Имени типа

Идентификатор определяет имя интерфейса и имеет как его контекст весь пакет, в котором это объявляется. Это - то же самое правило обзора данных что касается имен типа класса; см. §8.1.1 для примера, включающего классы.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Контекст имени элемента, объявленного в интерфейсном типе, является всем телом интерфейсного описания типа.

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

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

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

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

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

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

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

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

Для интерфейса возможно наследовать больше чем одно поле с тем же самым именем (§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 непосредственно.

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

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

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 Абстрактные Объявления метода

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

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

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

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

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

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

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

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

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

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

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

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

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

9.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 BufferError extends Exception { BufferError() { super(); } BufferError(String s) { super(s); } }
public interface Buffer { char get() throws BufferEmpty, BufferError; }
public interface InfiniteBuffer extends Buffer { char get() throws BufferError; // 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 с тремя различными подписями, двумя из них объявленный и один наследованный. Любой класс, который реализует интерфейс RealPointInterface должен обеспечить реализации всех трех сигнатур методов.


Содержание | Предыдущий | Следующий | Индекс

Спецификация языка Java (HTML, сгенерированный Блинчиком "сюзет" Pelouch 24 февраля 1998)
Авторское право © Sun Microsystems, Inc 1996 года. Все права защищены
Пожалуйста, отправьте любые комментарии или исправления к doug.kramer@sun.com

free hit counter