2012-06-11 4 views
3

У меня есть класс, который имеет собственный ссылочный общий параметр и параметр, который имеет тот же суперкласс. Статическая функция имеет одинаковые границы как класс.Java-вложенный self referential generic

public class Bar<T extends Bar<T, C>, C extends Bar<C, ?>> { 

    Bar() { 
     foo((T) null); 
     foo((C) null);//compile error 
    } 

    static <S_T extends Bar<S_T, S_C>, S_C extends Bar<S_C, ?>> void foo(S_T t) { 
    } 
} 

Это сообщение выдаст следующую ошибку.

Bound Несоответствие: Общий метод Foo (S_T) типа Bar < T, C> не применимо для аргументов (C). Выведенный типа C не является допустимой замены для ограниченного параметра < S_T расширяет Бар < S_T, S_C >>

Я не могу понять, почему C не может быть принят, чтобы foo() поскольку C является Bar<C,?> и подстановочный знак - Bar, потому что второй параметр в объявлении говорит, что он расширяет Bar.

Я знаю, что это, вероятно, плохая идея и создает код, который трудно понять, но я действительно хочу знать, почему это не компилируется.

+0

возможно связано с моим вопросом http://stackoverflow.com/questions/9937422/a-bad-interaction-between-self-referential-types- и-bounded-wildcards –

+0

@JudgeMental несколько похожа; но из того, что я собрал из вашего вопроса, это иерархия классов, которая не удалось скомпилировать, тогда как моя иерархия классов компилируется, но терпит неудачу при ограничении аргумента для этой функции. – dege

ответ

0

Я не трещина с обобщениями, но я думаю, что проблема в том, что вы объявляете тип Foo(), чтобы быть

<S_T extends Bar<S_T,S_C> > void foo(S_T) 

, а затем вызвать его в двух разных контекстах, которые требуют различных статических тип для foo().

В первом контексте S_T имеет тип T, а во втором - тип C. Но T и C объявлены как Bar<T,?> и Bar<C,?>, которые являются несовместимыми типами статически. Я бы предположил, что компилятор вычисляет тип foo() в первом вызове и затем предполагает, что тип должен оставаться неизменным во всем, чего нет.

+0

Переключение порядка двух вызовов foo() все еще дает ошибку в строке с C. – dege

+0

ОК, попробуйте изменить порядок C и T в объявлении класса, т.е.do Bar , T extends Bar . Если ошибка сбрасывается тогда, это означает, что привязки типов также зависят от порядка типов в объявлении класса. Но в любом случае C и T имеют разные несовместимые типы, и вы не можете передавать оба в foo(). – Jochen

+0

Я попробовал изменения, которые вы предложили, и ошибка изменилась на T, но я думаю, что это просто потому, что все, что было сделано, это переименование параметров, а не изменение какого-либо значения. Я попробовал несколько разных способов записи параметров, и ошибка остается на параметре, который имеет подстановочный знак. Также я считаю, что хотя C и T несовместимы с eachother, оба должны быть совместимы со статической функцией, поскольку AFAIK его общие параметры основаны на вводе, который он получает каждый вызов. – dege

2

Короткий ответ заключается в том, что вывод типа Java на самом деле довольно хромой.

Java не выполняет какой-либо интеллектуальный логический вывод на ? шаблона в объявлении Bar сделать вывод, что она логически ограничена Bar< ?, ? > (ни что ? s в том, что границе сам ограничены, и так далее). Как только вы положили ?, это все, что знает Java. Хотя ничто не мешает вам помещать эту привязку в подстановочный знак в объявлении Bar, даже это не помогает Java; Java никогда не предполагает, что два отдельных файла ? s относятся к одному типу, даже если более глубокий анализ будет означать, что они должны быть. Другими словами, ошибка компиляции сохраняется даже с этим кодом:

public class Bar<T extends Bar<T, C>, C extends Bar<C, ? extends Bar<?, ? extends Bar<?, ?>>>> { 

    Bar() { 
     foo((T) null); 
     foo((C) null);//compile error 
    } 

    static <S_T extends Bar<S_T, S_C>, S_C extends Bar<S_C, ? extends Bar<?, ? extends Bar<?, ?>>>> void foo(S_T t) { 
    } 
} 
+0

Да, я начал подозревать, что java не смог обнаружить связь между границами шаблона. Я начал экспериментировать с поставкой класса: 'Pie extends Bar ' вместо шаблона. Тогда функция будет иметь ', S_C расширяет Bar ' и все еще могут быть методы на баре, которые вернут S_C .... Но я мог бы быть полностью недоступен цели (почти 3am здесь) – dege

+0

что бы было неправильно с 'Bar < S_T, S_C >' в качестве аргумента типа 'foo'? Единственная информация, которую вы можете использовать о 'S_T' в' foo', состоит в том, что она 'Bar < S_T, S_C >' в любом случае. Плюс, что делает 'foo' (теоретически, по крайней мере) более общим. –

+0

Какими будут общие параметры для функции? Вы имеете в виду только определение S_T и S_C без каких-либо ограничений, потому что тогда бар в аргументе не будет соответствовать границам класса Bar – dege

Смежные вопросы