Введение настраиваемых типов породило новую категорию ошибок, которых Вы должны беречься, ошибки неоднозначности (ambiguity errors). Такая ошибка возникает, когда механизм стирания вызывает два на вид отличающихся объявления настраиваемых типов для удаления информации об одном типе, порождая тем самым конфликт. В листинге 3.22 приведен пример, содержащий переопределение метода.
Листинг 3.22. Неоднозначность, вызванная стиранием в переопределенных методах
class MyGenClass {
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 obj = new MyGenClass()
В этом случае и T, и V замещаются типом String. Это делает обе версии метода set() одинаковыми, что, конечно же, является ошибкой.
Во-вторых, и это более существенно, стирание информации о типе превратит обе версии метода set () в следующую:
void set(Object о)
Таким образом, переопределение метода set (), которое делается в классе MyGenClass, — в основе своей неоднозначно.
Ошибки неоднозначности бывает трудно обнаружить. Например, если Вы знаете, что параметр типа V всегда будет некоторым типом String, можно попробовать переписать объявление класса MyGenClass следующим образом:
MyGenClass { //почти хорошо!
Это изменение позволит откомпилировать класс MyGenClass и Вы даже сможете создавать объекты класса, такие как приведенный в следующей строке:
MyGenClass x = new MyGenClass();
Это работающий вариант, потому что Java безошибочно определяет, какой метод следует вызывать. Но неоднозначность вернется, как только Вы попробуете ввести следующую строку:
MyGenClass< String, String> х = new MyGenClass< String, String>();
В данном случае, поскольку и у T, и у V — тип String, какую версию метода set() вызывать?
Откровенно говоря, в листинге 3.22 гораздо лучше использовать два метода с разными именами, чем пытаться переопределять метод set(). Часто разрешение неоднозначности приводит к переработке кода, поскольку неоднозначность или неопределенность зачастую свидетельствует о концептуальной ошибке в вашем проекте.
|