2017-07-10 11 views
9

Dla mojego zrozumienia, <? extends Object> i <?> są takie same.Ogólna notacja <?> i <? rozszerza Object> zachowując się inaczej

Jednak po uruchomieniu następującego kodu <? extends Object> nie jest kompilowany i działa zgodnie z oczekiwaniami, ale <?> kompiluje się pomyślnie.

public class Test1 
{ 
    interface I1 
    { 
    } 

    interface I2<T extends I1> extends Comparable<I2<?>> 
    { 
     Comparator<I2<? extends I1>> A = null; 
     //Comparator<I2<? extends Object>> B = A; // expected compilation fail 
     Comparator<I2<?>> B = A; // compiling successfully.This shouldn't get compile 
    } 
} 

Czy ktoś może mi pomóc zrozumieć to zachowanie.

+0

@ ajb- mój problem jest oświadczenie 2 jest uzyskiwanie skompilowany, choć nie powinien być.Sprawdź mój kod –

+0

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

+0

"Komparator > B = A" nie kompiluje się dla mnie: "Niezgodność typu: nie można przekonwertować z Komparatora > do Komparatora > " – efekctive

Odpowiedz

7

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)

+1

Najbliższe, jakie mogę znaleźć w JLS, to (Java 7, sekcja 4.5.1): "Relacja symboli wieloznacznych do ustalonych Teoria typów jest interesująca, o czym pokrótce tutaj wspominamy. Symbole wieloznaczne są ograniczoną formą typów egzystencjalnych. Biorąc pod uwagę ogólną deklarację typu G , G jest z grubsza analogiczna do części X <: B. G. ' –

+0

@ Adrian - w końcu ktoś to rozumie ... bardzo dziękuję za analizę :) –

2

Pozwól mi wyjaśnić w prosty przykład:

List<String> list = new ArrayList<>(); 
List<Object> listObject = new ArrayList<>(); 
listObject = list; 

Tutaj Object klasa Super klasa String klasy, mimo otrzymasz poniżej określonego błąd kompilacji, ponieważ podałeś swoją listę do zaakceptowania określony typ obiektów, tj. "Obiekt" dla listObject i "Ciąg" do list.

Type mismatch: cannot convert from List<String> to List<Object> 

Na podobny wyjaśnienie poniżej

//Comparator<I2<? extends Object>> B = A; // expected compilation fail 

Powyższa linia się niepowodzeniem, ponieważ starają się typecast dwa rodzaje niedopasowane:

Type mismatch: cannot convert from Comparator<Test1.I2<? extends Test1.I1>> to Comparator<Test1.I2<? extends Object>>