Ошибки неоднозначности
Включение в язык обобщений породило новый тип ошибок, от которых вам нужно защищаться: неоднозначность (ambiquity). Ошибки неоднозначности случаются, когда очистка порождает два внешне разных обобщенных объявления, разрешаемых в виде одного очищенного типа, что вызывает конфликт. Вот пример, который включает перегрузку методов:
// Неоднозначность порождается очисткой перегруженных методов.
class MyGenClass
Т obi;
V ob2;
// ...
// Эти два перегруженных метода неоднозначны
// и не скомпилируются.
void set(Т о) {
obi = о;
}
void set(V о) {
ob2 = о;
}
}
Обратите внимание, что MyGenClass объявляет два обобщенных типа: Т и V. Внутри MyGenClass предпринимается попытка перегрузить set () на основе параметров Т и V. Это выглядит резонным, потому что кажется, что Т и V — разные типы. Однако здесь возникают две проблемы неоднозначности.
Первая — судя по тому, как написан MyGenClass, нет требования, чтобы Т и V были разными типами. Например, в принципе совершенно корректно сконструировать объект MyGenClass следующим образом:
MyGenClass
В этом случае T и V будут заменены String. Это делает обе версии set () идентичными, что, конечно же, представляет собой ошибку.
Вторая, более фундаментальная проблема состоит в том, что очистка типов приводит обе версии метода к следующему виду:
void set(Object о) {
//...
То есть перегрузка set (), как пытается сделать MyGenClass, в действительности неоднозначна.
Ошибки неоднозначности бывает трудно исправить. Например, если вы знаете, что V всегда будет неким подтипом String, то можете попытаться исправить MyGenClass, переписав его объявление следующим образом:
class MyGenClass
// почти OK!
Это позволит скомпилировать MyGenClass, и вы даже сможете создавать экземпляры объектов этого класса примерно так:
MyGenClass
Это работает, потому что Java может аккуратно определить, когда какой метод должен быть вызван. Однако неоднозначность возникнет, когда вы попытаетесь выполнить строку:
MyGenClass
В этом случае, поскольку и Т, и V являются String, то какую версию set () нужно вызвать?
Честно говоря, в предыдущем примере было бы лучше использовать два метода с разными именами, вместо того чтобы перегружать set (). Часто разрешение неоднозначности требует реструктуризации кода, потому что неоднозначность свидетельствует о концептуальной ошибке в дизайне.