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

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

// Неоднозначность порождается очисткой перегруженных методов.
class MyGenClass {
Т obi;
V ob2;
// ...
// Эти два перегруженных метода неоднозначны
// и не скомпилируются.
void set(Т о) {
obi = о;
}
void set(V о) {
ob2 = о;
}
}

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

Первая — судя по тому, как написан MyGenClass, нет требования, чтобы Т и V были разными типами. Например, в принципе совершенно корректно сконструировать объект MyGenClass следующим образом:

MyGenClass obj = new MyGenClass()

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

Вторая, более фундаментальная проблема состоит в том, что очистка типов приводит обе версии метода к следующему виду:

void set(Object о) {
//...

То есть перегрузка set (), как пытается сделать MyGenClass, в действительности неоднозначна.

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

class MyGenClass {
// почти OK!

Это позволит скомпилировать MyGenClass, и вы даже сможете создавать экземпляры объектов этого класса примерно так:

MyGenClass х = new MyGenClass();

Это работает, потому что Java может аккуратно определить, когда какой метод должен быть вызван. Однако неоднозначность возникнет, когда вы попытаетесь выполнить строку:

MyGenClass х = new MyGenClass();

В этом случае, поскольку и Т, и V являются String, то какую версию set () нужно вызвать?

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