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

Ошибки неоднозначности

Введение настраиваемых типов породило новую категорию ошибок, которых Вы должны беречься, ошибки неоднозначности (ambiguity errors). Такая ошибка возникает, когда механизм стирания вызывает два на вид отличающихся объявления настраиваемых типов для удаления информации об одном типе, порождая тем самым конфликт. В листинге 3.22 приведен пример, содержащий переопределение метода.

Листинг 3.22. Неоднозначность, вызванная стиранием в переопределенных методах

class MyGenClass<T, V> {

T ob1;

V ob2;

// ...

// These two overloaded methods are ambiguous.

// and will not compile.

void set(T o) {

ob1 = o;

}

void set(V o) {

ob2 = o;

}

}

Обратите внимание на то, что класс MyGenClass содержит объявления двух настраиваемых типов: T и V. В классе MyGenClass делается попытка переопределения метода set(), основанного на параметрах типа T и V. Это выглядит разумным, так как кажется, что T и V — разные типы. Но при этом возникает два вида неоднозначности.

Во-первых (судя по описанию класса MyGenClass), не требуется, чтобы типы T и V всегда были разными. Например, приведенное далее создание объекта класса MyGenClass — совершенно правильно (в принципе):

MyGenClass<String, String> obj = new MyGenClass<String, String>()

В этом случае и T, и V замещаются типом String. Это делает обе версии метода set() одинаковыми, что, конечно же, является ошибкой.

Во-вторых, и это более существенно, стирание информации о типе превратит обе версии метода set () в следующую:

void set(Object о)

Таким образом, переопределение метода set (), которое делается в классе MyGenClass, — в основе своей неоднозначно.

Ошибки неоднозначности бывает трудно обнаружить. Например, если Вы знаете, что параметр типа V всегда будет некоторым типом String, можно попробовать переписать объявление класса MyGenClass следующим образом:

MyGenClass<T, V extends String> { //почти хорошо!

Это изменение позволит откомпилировать класс MyGenClass и Вы даже сможете создавать объекты класса, такие как приведенный в следующей строке:

MyGenClass<Integer, String> x = new MyGenClass<Integer, String>();

Это работающий вариант, потому что Java безошибочно определяет, какой метод следует вызывать. Но неоднозначность вернется, как только Вы попробуете ввести следующую строку:

MyGenClass< String, String> х = new MyGenClass< String, String>();

В данном случае, поскольку и у T, и у V — тип String, какую версию метода set() вызывать?

Откровенно говоря, в листинге 3.22 гораздо лучше использовать два метода с разными именами, чем пытаться переопределять метод set(). Часто разрешение неоднозначности приводит к переработке кода, поскольку неоднозначность или неопределенность зачастую свидетельствует о концептуальной ошибке в вашем проекте.

Некоторые ограничения применения настраиваемых типов

Существует несколько ограничений, которые Вам следует помнить при использовании настраиваемых типов. Они касаются создания объектов настраиваемого типа, статических членов класса, исключений и массивов. Рассмотрим каждое из них в отдельности.