Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Обобщенные интерфейсы. Иерархии обобщенных классов




Обобщенные интерфейсы

В дополнение к обобщенным классам и методам вы можете объявлять обобщенные интерфейсы. Обобщенные интерфейсы специфицируются так же, как и обобщенные классы. Ниже показан пример. В нем создается интерфейс MinMax, объявляющий методы min() и max(), которые, как ожидается, должны возвращать минимальное и максимальное значения из некоторого множества объектов.

// Пример обобщенного интерфейса.

// Интерфейс Min/Max.

interface MinMax< T extends Comparable< T> > {

T min();

T max();

}

// Реализация MinMax

class MyClass< T extends Comparable< T> > implements MinMax< T> {

T[] vals;

MyClass(T[] o) { vals = o; }

// Возвращает минимальное значение из vals.

public T min() {

T v = vals[0];

for(int i=1; i < vals. length; i++)

if(vals[i]. compareTo(v) < 0) v = vals[i];

return v;

}

// Возвращает максимальное значение из vals.

public T max() {

T v = vals[0];

for(int i=1; i < vals. length; i++)

if(vals[i]. compareTo(v) > 0) v = vals[i];

return v;

}}

class GenIFDemo {

public static void main(String args[]) {

Integer inums[] = {3, 6, 2, 8, 6 };

Character chs[] = {'b', 'r', 'p', 'w' };

MyClass< Integer> iob = new MyClass< Integer> (inums);

MyClass< Character> cob = new MyClass< Character> (chs);

System. out. println(" Максимальное значение в inums: " + iob. max());

System. out. println(" Минимальное значение в inums: " + iob. min());

System. out. println(" Максимальное значение в chs: " + cob. max());

System. out. println(" Минимальное значение в chs: " + cob. min());

}}

Результат работы этой программы:

Максимальное значение в inums: 8

Минимальное значение в inums: 2

Максимальное значение в chs: w

Минимальное значение в chs: b

Хотя большинство аспектов этой программы просты для понимания, некоторые ключевые моменты следует пояснить. Во-первых, обратите внимание на то, как объявлен MinMax:

interface MinMax< T extends Comparable< T> > {

В общем случае, обобщенный интерфейс объявляется так же, как и обобщенный класс. В этом случае тип параметра T имеет верхнюю границу Comparable — интерфейс, определенный в java. lang. Класс, который реализует Comparable, определяет объекты, которые могут быть упорядочены. То есть требование, чтобы T был ограничен сверху Comparable, гарантирует, что MinMax может быть использован только с объектами, которые могут сравниваться между собой. (Более подробную информацию о Comparable можно найти в главе 16. ) Отметим, что Comparable сам по себе также является обобщенным интерфейсом (он был преобразован в обобщенную форму в JDK 5). Он принимает параметр типа объектов, которые должны сравниваться.

Далее MinMax реализует класс MyClass. Вот как выглядит объявление класса MyClass:

class MyClass< T extends Comparable< T> > implements MinMax< T> {

Обратите особое внимание на способ, которым параметр типа T объявлен в MyClass и затем передан MinMax. Поскольку MinMax требует типа, который реализует Comparable, реализующий класс (в данном случае — MinMax) должен специфицировать то же ограничение. Более того, однажды установленное, это ограничение уже не нужно повторять в операторе implements. Фактически так поступать некорректно. Например, следующая строка неверна и не может быть скомпилирована:

// Это не правильно!

class MyClass< T extends Comparable< T> >

implements MinMax< T extends Comparable< T> > {

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

class MyClass implements MinMax< T> { // Неверно!

Поскольку MyClass не объявляет параметра, нет способа передать его MinMax. В этом случае идентификатор T просто неизвестен, и компилятор выдаст ошибку. Конечно, если класс реализует специфический тип обобщенного интерфейса, как показано ниже:

class MyClass implements MinMax< Integer> { // OK

, то реализующий класс не обязан быть обобщенным.

Обобщенный интерфейс представляет два преимущества. Во-первых, он может быть реализован для разных типов данных. Во-вторых, он позволяет включить ограничения на типы данных, для которых он может быть реализован. В примере MinMax вместо T могут быть подставлены только типы, совместимые с Comparable.

Вот общий синтаксис обобщенного интерфейса:

interface имя_интерфейса< список_параметров_типов> { //...

Здесь список_параметров_типов — разделенный запятыми список параметров типов. Когда реализуется обобщенный интерфейс, вы должны специфицировать аргументы типов, как показано ниже:

class имя_класса< список_параметров_типов>

implements имя_интерфейса< список_аргументов_типов> {

Иерархии обобщенных классов

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

Это похоже на способ, которым аргументы конструкторов передаются по иерархии.

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

// Простая иерархия обобщенных классов.

class Gen< T> {

T ob;

Gen(T o) {

ob = o;

}

// Возвращает ob.

T getob() {

return ob;

}

}

// Подкласс Gen.

class Gen2< T> extends Gen< T> {

Gen2(T o) {

super(o);

}

}

В этой иерархии Gen2 расширяет обобщенный класс Gen. Обратите внимание на то, как в следующей строке объявлен Gen2:

class Gen2< T> extends Gen< T> {

Параметр типа T специфицирован в Gen2 и также передается Gen в операторе extends. Это значит, что тип, переданный Gen2, будет также передан Gen. Например, следующее объявление

Gen2< Integer> num = new Gen2< Integer> (100);

, передает Integer как параметр типа классу Gen. То есть ob внутри части Gen класса Gen2 будет иметь тип Integer. Отметим также, что Gen2 никак не использует параметр типа T, кроме того, что передает его суперклассу Gen. Даже если подкласс обобщенного суперкласса никак не нуждается в том, чтобы быть обобщенным, несмотря на это он все же должен специфицировать параметры типа, необходимые его обобщенному суперклассу.

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

// Подкласс может добавлять свои собственные параметры типа.

class Gen< T> {

T ob; // Объявление объекта типа T

// Передача конструктору

// ссылки на объект типа T.

Gen(T o) {

ob = o;

}

// Возвращает ob.

T getob() {

return ob;

}}

// Подкласс Gen, который определяет

// второй параметр типа по имени V.

class Gen2< T, V> extends Gen< T> {

V ob2;

Gen2(T o, V o2) {

super(o);

ob2 = o2;

}

V getob2() {

return ob2;

}}

// Создание объекта типа Gen2.

class HierDemo {

public static void main(String args[]) {

// Создание объектов Gen2 для String и Integer.

Gen2< String, Integer> x =

new Gen2< String, Integer> (" Значение равно: ", 99);

System. out. print(x. getob());

System. out. println(x. getob2());

}}

Обратите внимание на объявление Gen2, показанное в следующей строке:

class Gen2< T, V> extends Gen< T> {

Здесь T — тип, переданный Gen, а V — тип, специфичный для Gen2. V используется для объявления объекта, названного ob2, а также в качестве типа возврата метода getob2(). В main() создается объект Gen2 с типом String для параметра T и типом Integer для параметра V.

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...