2013-07-19 14 views
12

Rozważmy kod:Wnioskowany typ nie jest prawidłową substytut dla porównywalnego typu rodzajowego

public abstract class Item<T> implements Comparable<T> 
{ 
    protected T item; 

    public int compareTo(T o) 
    { 
     return 0; // this doesn't matter for the time being 
    } 
} 

public class MyItem<T> extends Item<String> 
{ 
    T object; 
} 

public class Foo<T> 
{ 
    protected ArrayList<T> list; 
} 

public class Bar<V> extends Foo<MyItem<V>> 
{ 
    public void sort() 
    { 
     Collections.sort(list); 
    } 
} 


Wezwanie sort daje błąd:

Bound mismatch: The generic method sort(List< T >) of type Collections is not applicable for the arguments (ArrayList< MyItem< T > >). The inferred type MyItem< T > is not a valid substitute for the bounded parameter < T extends Comparable< ? super T > >


dlaczego tak się stało?

Jeśli MyItem<V> implementuje Comparable, dlaczego nie jest substytutem?

Przepraszam, jeśli zostało to zadane, ale uważam, że to pytanie jest dość szczegółowe.

Odpowiedz

11

Właściwie bardziej szczegółowe wyjaśnienie tego błędu daje swój javac sama:

java: no suitable method found for sort(java.util.ArrayList<MyItem<V>>)

method java.util.Collections.<T>sort(java.util.List<T>,java.util.Comparator<? super T>) is not applicable (cannot instantiate from arguments because actual and formal argument lists differ in length)

method java.util.Collections.<T>sort(java.util.List<T>) is not applicable (inferred type does not conform to declared bound(s) inferred: MyItem<V> bound(s): java.lang.Comparable<? super MyItem<V>>)

Tak, główne pytanie brzmi:
dlaczego jest metoda Collections.<T>sort(java.util.List<T>)) nie dotyczy?

Odpowiedź jest:
ponieważ w Collections.<T>sort(java.util.List<T>) deklaracji metody istnieją granice parametru T: <T extends Comparable<? super T>>.

Innymi słowy, T musi implementować na sobie interfejs Comparable. Na przykład klasa String implementuje taki interfejs: ...implements ... Comparable<String>.

W swojej klasie sprawa Item nie realizuje takiego interfejsu:

Item<T> implements Comparable<T> nie jest to samo, co Item<T> implements Comparable<Item<T>>.

Tak, dla rozwiązania tego problemu, twój powinna zmienić profesję Item do tego:

public abstract class Item<T> implements Comparable<Item<T>> 
{ 
    protected T item; 

    public int compareTo(Item<T> o) 
    { 
     return 0; // this doesn't matter for the time being 
    } 
} 
+1

To było na miejscu. Twoje zdrowie! Dla wyjaśnienia uwzględniłem dodatkowe klasy, ponieważ podany przeze mnie kod jest znacznie bardziej uproszczoną wersją mojego rzeczywistego kodu i nie byłem pewien, gdzie jest problem. Całkowicie przegapiłem to, że mogłem po prostu zmienić samo porównanie. Dzięki jeszcze raz. – terrorcell

+0

Lepiej: 'public abstract class Item implementuje porównywalne > '- nie? –

0

Nie trzeba mieć klasę MyItem generified żeby zobaczyć efekt. Poniższa klasa jest wystarczająco, aby zobaczyć, co się dzieje:

public class MyItem extends Item<String> {} 

Teraz masz następujące połączenia:

Collections.sort(list); 

Jak Morgano słusznie stwierdził, metoda sortowania odbędzie zbiór, który jest parametryzowane z typu T to musi być porównywalne z T. Twoja klasa MyItem rozszerza się o Item<String>, co powoduje, że MyItem jest porównywalna z MyItem s porównywalną z .

Przy odrobinie przełącznika, w którym klasa implementuje interfejs Comparable, otrzymasz oczekiwany rezultat:

public abstract class Item<T> { 
    protected T item; 
} 

public class MyItem extends Item<String> implements Comparable<MyItem> { 
    @Override 
    public int compareTo(MyItem o) { 
     return item.compareTo(o.item); // just an example 
    } 
} 

a teraz wezwanie do Collections.sort(list) zadziała.

1

Wystarczy zmienić klasę jak następuje:

 public class MyItem<T> extends Item<String> implement Comparable<MyItem<T>> 
    { 
     T object; 
    } 

Albo

 public abstract class Item<T> implements Comparable<MyItem<T>> 
     { 
      protected T item; 

      public int compareTo(MyItem<T> o) 
      { 
       return 0; // this doesn't matter for the time being 
     } 

}

Końcówki błędów wykazał us.Hope to pomocne.

2

Aby obiekty typu X były porównywalne ze sobą, klasa X musi zaimplementować dokładnie Comparable<X>.

To nie jest to, co robi twój kod, masz klasę Item<T> i implementujesz Comparable<T> zamiast Comparable<Item<T>>. Oznacza to, że Item<T> można porównać z T, ale nie z Item<T>, która jest wymagana.

Zmień swoją klasę Item<T> do:

public abstract class Item<T> implements Comparable<Item<T>> 
{ 
    protected T item; 

    @Override 
    public int compareTo(Item<T> o) 
    { 
     return 0; // this doesn't matter for the time being 
    } 
} 
+0

"Aby obiekty typu X były porównywalne ze sobą, klasa X musi implementować dokładnie Porównywalne ." Niekoniecznie dokładnie. X może implementować 'Porównywalne ' – newacct

+0

@newacct Oczywiście, oczywiście. – Dukeling

Powiązane problemy