Ogólna metoda z parametrami a nie generyczna metoda z symbolami wieloznacznymi
Wedługten wpis w FAQ Java Generics, istnieją pewne okoliczności, w których ogólna metoda nie ma równoważnej nie generycznej metody, która używa typów wieloznacznych. Zgodnie z tą odpowiedzią
Jeśli podpis metody używa wielopoziomowych typów wieloznacznych, zawsze istnieje różnica między sygnaturą metody ogólnej a jej wersją wieloznaczną.
Podają przykład metody<T> void print1( List <Box<T>> list)
, który „wymaga listy pudeł tego samego typu”. Wersja wieloznaczna,void print2( List <Box<?>> list)
, „akceptuje heterogeniczną listę skrzynek różnych typów”, a zatem nie jest równoważny.
Jak interpretujesz różnice między dwoma następującymi podpisami metod:
<T extends Iterable<?>> void f(Class<T> x) {}
void g(Class<? extends Iterable<?>> x) {}
Intuicyjnie wydaje się, że te definicje powinny być równoważne. Jednak połączenief(ArrayList.class)
kompiluje za pomocą pierwszej metody, ale wywołanieg(ArrayList.class)
użycie drugiej metody powoduje błąd podczas kompilacji:
g(java.lang.Class<? extends java.lang.Iterable<?>>) in Test
cannot be applied to (java.lang.Class<java.util.ArrayList>)
Co ciekawe, obie funkcje można nazwać argumentami innych, ponieważ następujące kompilują:
class Test {
<T extends Iterable<?>> void f(Class<T> x) {
g(x);
}
void g(Class<? extends Iterable<?>> x) {
f(x);
}
}
Za pomocąjavap -verbose Test
, Rozumiemf()
ma ogólny podpis
<T::Ljava/lang/Iterable<*>;>(Ljava/lang/Class<TT;>;)V;
ig()
ma ogólny podpis
(Ljava/lang/Class<+Ljava/lang/Iterable<*>;>;)V;
Co wyjaśnia to zachowanie? Jak mam interpretować różnice między podpisami tych metod?