Универсальный метод с параметрами против неуниверсального метода с подстановочными знаками
В соответствии сэта запись в FAQ по Generics JavaЕсть некоторые обстоятельства, когда универсальный метод не имеет эквивалентного неуниверсального метода, который использует подстановочные типы. Согласно этому ответу,
If a method signature uses multi-level wildcard types then there is always a difference between the generic method signature and the wildcard version of it.
Они дают пример метода<T> void print1( List <Box<T>> list)
, для которого "требуется список блоков одного типа." Версия с подстановочными знаками,void print2( List <Box<?>> list)
& quot; принимает разнородный список блоков разных типов & quot; и, следовательно, не эквивалентно.
Как вы интерпретируете различия между следующими двумя сигнатурами метода:
<T extends Iterable<?>> void f(Class<T> x) {}
void g(Class<? extends Iterable<?>> x) {}
Интуитивно кажется, что эти определения должны быть эквивалентны. Тем не менее, вызовf(ArrayList.class)
компилируется с использованием первого метода, но вызовg(ArrayList.class)
использование второго метода приводит к ошибке времени компиляции:
g(java.lang.Class<? extends java.lang.Iterable<?>>) in Test
cannot be applied to (java.lang.Class<java.util.ArrayList>)
Интересно, что обе функции можно вызывать друг с другом & apos; аргументы, потому что следующие компилирует:
class Test {
<T extends Iterable<?>> void f(Class<T> x) {
g(x);
}
void g(Class<? extends Iterable<?>> x) {
f(x);
}
}
С помощьюjavap -verbose Test
, Я могу увидеть этоf()
имеет общую подпись
<T::Ljava/lang/Iterable<*>;>(Ljava/lang/Class<TT;>;)V;
а такжеg()
имеет общую подпись
(Ljava/lang/Class<+Ljava/lang/Iterable<*>;>;)V;
Чем объясняется такое поведение? Как я должен интерпретировать различия между этими методами? подписи?