To pytanie jest rzeczywiście ciekawe, ale nie zapytał wyraźnie, co łatwo sprawia, że ludzie myślą, że jest duplikatem.
pierwsze, przykład, który myślę, że większość ludzi tutaj powinni zrozumieć, dlaczego to nie działa:
class Foo<T> {}
class Bar<T> {}
class Parent{}
public class Test1
{
public static void main(String[] args) {
Foo<Bar<? extends Parent>> a = null;
Foo<Bar<? extends Object>> b = a; // does not compile
Foo<Bar<?>> c = a; // does not compile
}
}
Jest oczywiste: a Foo<Bar<?>>
/Foo<Bar<? extends Object>>
nie jest wymienialny na Foo<Bar<? extends Parent>>
(po prostu: tak jak nie można przypisać List<Dog>
do List<Animal>
odniesienie.)
jednak w pytaniu widać przypadek Comparator<I2<?>> B = A;
skompilować, co jest sprzeczne w z tym, co widzimy powyżej.
Różnica, jak określono w moim przykładzie będzie:
class Foo<T> {}
class Bar<T extends Parent> {}
class Parent{}
public class Test1
{
public static void main(String[] args) {
Foo<Bar<? extends Parent>> a = null;
Foo<Bar<? extends Object>> b = a; // does not compile
Foo<Bar<?>> c = a; // COMPILE!!
}
}
Zmieniając class Bar<T>
do class Bar<T extends Parent>
stworzony różnicę. Szkoda, że nadal nie mogę znaleźć sekcji JLS, która jest odpowiedzialna za to, ale wierzę, że kiedy deklarujesz klasę ogólną z parametrem typu związanego, granica jest domyślnie przenoszona do dowolnego symbolu wieloznacznego, którego używasz przeciwko temu.
Dlatego przykład stać:
class Foo<T> {}
class Bar<T extends Parent> {}
class Parent{}
public class Test1
{
public static void main(String[] args) {
Foo<Bar<? extends Parent>> a = null;
//...
Foo<Bar<? extends Parent>> c = a;
}
}
które wyjaśniają, dlaczego to skompilować.
(Niestety nie mogę znaleźć dowody na to, w jaki sposób język jest przeznaczony. To będzie wielki, jeśli ktoś może znaleźć w JLS do tego)
@ ajb- mój problem jest oświadczenie 2 jest uzyskiwanie skompilowany, choć nie powinien być.Sprawdź mój kod –
Dlaczego nie powinno się kompilować instrukcji 2? Przynajmniej z intuicyjnego spojrzenia na polimorfizm, 'I2' z * czegoś * się rozszerza' I1' można nazwać 'I2' z * czegoś *. (Przeciwnie, 'I2' z * czegoś * rozszerza' I1' może być nazwane tylko 'I2' z * czegoś * rozszerza' Object', ponieważ wiemy, że 'I1' musi być podklasą' Object', która jest wniosek, który zgaduję, kompilator java nie chce przeskoczyć.) – Mshnik
"Komparator> B = A" nie kompiluje się dla mnie: "Niezgodność typu: nie można przekonwertować z Komparatora > do Komparatora > " –
efekctive