Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Герберт Шилдт. Java 2, v5.0 (Tiger). Новые возм...doc
Скачиваний:
5
Добавлен:
01.03.2025
Размер:
1.21 Mб
Скачать

Применение метасимвольных аргументов

Как ни полезна безопасность типов, иногда она может мешать формированию вполне приемлемых конструкций. Предположим, что в имеющийся класс Stats, описанный в предыдущем разделе, Вы хотите добавить метод sameAvg() который определяет, содержатся ли в двух объектах Stats массивы с одинаковым значением среднего арифметического, независимо от типа числовых данных массивов. Например, если один объект содержит значения 1.0, 2.0 и 3.0 типа double, а второй целые числа 1, 2 и 3, средние арифметические массивов будут одинаковы. Один из способов реализации метода sameAvg( ) — передача в класс Stats аргумента, последующее сравнение среднего арифметического этого аргумента со средним арифметическим объекта, вызвавшего метод, и возврат значения true, если средние арифметические одинаковы. Например, можно попытаться вызвать метод sameAvg(), как показано в следующем фрагменте кода:

Integer inums[] = {1, 2, 3, 4, 5 };

Double dnums[] = {1.1, 2.2, 3.3, 4.4, 5.5 };

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

Stats<Double> dob = new Stats<Double>(dnums);

if(iob.sameAvg(dob))

System.out.println("Averages are the same.");

else

System.out.println("Averages differ.");

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

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

// Этот пример не будет работать!

// Определяет, равны ли средние арифметические.

boolean sameAvg(Stats<T> ob) {

if ((average) == ob.average())

return true;

return false;

}

К сожалению, приведенный пример будет обрабатывать только те объекты класса Stats, у которых тип такой же, как у объекта, вызвавшего метод. Например, если метод вызывает объект типа Stats<Integer>, параметр ob должен тоже быть типа Stats<Integer>. Такой метод нельзя использовать для сравнения среднего арифметического объекта Stats<Double> со средним арифметическим объекта типа Stats<Short>. Следовательно, предложенный подход не будет работать, за исключением нескольких ситуаций, и не даст общего (т. е. универсального) решения.

Для создания универсального метода sameAvg() Вы должны использовать другую функциональную возможность средств настройки типов — мета символьный аргумент, или символьную маску (wildcard argument). Метасимвольный аргумент задается знаком ? и представляет неизвестный тип. Используя такую маску, можно описать метод sameAvg( ) так, как показано в следующем фрагменте кода:

// Определяет, равны ли средние арифметические.

// Обратите внимание на применение метасимвола.

boolean sameAvg(Stats<?> ob) {

if ((average) == ob.average())

return true;

return false;

}

В приведенном примере тип Stats<?> соответствует любому объекту типа Stats и позволяет сравнивать средние арифметические двух объектов типа Stats, как показано в листинге 3.6.

Листинг 3.6. Применение метасимвола, или символьной маски

class Stats<T extends Number> {

T[] nums;

// массив типа Number или его подкласса

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

// массив типа Number или его подкласса.

Stats(T[] o) {

nums = o;

}

// Всегда возвращает тип double.

double average() {

double sum = 0.0;

for(int i=0; i < nums.length; i++)

sum += nums[i].doubleValue();

return sum / nums.length;

}

// Определяет, равны ли два средних арифметических.

// Обратите внимание на использование метасимвола (или маски).

boolean sameAvg(Stats<?> ob) {

if(average() == ob.average())

return true;

return false;

}

}

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

class WildcardDemo {

public static void main(String args[]) {

Integer inums[] = { 1, 2, 3, 4, 5 };

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

double v = iob.average();

System.out.println("iob average is " + v);

Double dnums[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };

Stats<Double> dob = new Stats<Double>(dnums);

double w = dob.average();

System.out.println("dob average is " + w);

Float fnums[] = { 1.0F, 2.0F, 3.0F, 4.0F, 5.0F };

Stats<Float> fob = new Stats<Float>(fnums);

double x = fob.average();

System.out.println("fob average is " + x);

// Проверяет, у каких массивов одинаковые средние арифметические.

System.out.print("Averages of iob and dob ");

if(iob.sameAvg(dob))

System.out.println("are the same.");

else

System.out.println("differ.");

System.out.print("Averages of iob and dob ");

if(iob.sameAvg(fob))

System.out.println("are the same.");

else

System.out.println("differ.");

}

}

Далее приведен вывод программы из листинга 3.6:

iob average is 3.О

dob average is 3.3

fob average is 3.0

Averages of iob and dob differ.

Averages of iob and fob are the same.

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