2011-06-09 17 views
8

Mam mały program, który ma sortować mapę na podstawie jej wartości. Oto co mam do tej pory:Ogólna metoda sortowania mapy na wartości

public static <K, V extends Comparable< ? extends V>> Map<K, V> 
    sortByValues(final Map <K, V> mapToSort) 
    { 
     List<Map.Entry<K, V>> entries = 
      new ArrayList<Map.Entry<K, V>>(mapToSort.size()); 

     entries.addAll(mapToSort.entrySet()); 

     Collections.sort(entries, new Comparator<Map.Entry<K, V>>() 
     { 
      public int compare(
           final Map.Entry<K, V> entry1, 
           final Map.Entry<K, V> entry2) 
      { 
       return entry1.getValue().compareTo(entry2.getValue()); 
      } 
     }); 

     Map<K, V> sortedMap = new LinkedHashMap<K, V>(); 

     for (Map.Entry<K, V> entry : entries) 
     { 
      sortedMap.put(entry.getKey(), entry.getValue()); 
     } 

     return sortedMap; 
    } 

Chcę moja wartość generic V będzie porównywalny do niczego, co jest V lub jest przynajmniej podklasą V.

otrzymuję następujący błąd na kawałku kodu:

public static <K, V extends Comparable< ? extends V>> 

Związany niedopasowanie: Metoda compareTo (? rozciąga V) typu V nie ma zastosowania dla argumentów (v). Parametr wieloznaczny ? rozciąga V nie ma niższy związana, a może rzeczywiście być bardziej restrykcyjne niż argumentu V

Jak to może być bardziej restrykcyjne?

Jeśli zmienię deklarację:

public static <K, V extends Comparable< ? super V>> 

wtedy nie ma żadnego błędu. Ale tego nie chcę.

Jeden obejście mam to, że mogę zmienić deklarację:

public static <K, V extends Comparable<V>> 

ale robi to stracę elastyczność, że nie mogę przekazać Mapa którego wartość realizuje Porównywalne z podklasy sobie.

Przeprosiny za tak długie pytanie. Z góry dziękuję.

+0

Którą wersję JDK używasz? W JDK5 i JDK6 nie sądzę, żeby to był problem. Nie jestem pewien, jak JDK1.4 sobie z tym poradzi. Ale metoda compareTo nie wydaje się kompilować w ten sposób. Wygląda na to, że problem dotyczy sposobu, w jaki metoda compareTo jest obsługiwana wewnętrznie. Być może będziesz musiał zmienić go na 'return ((Porównywalne ) entry1.getValue()). CompareTo (entry2.getValue());' lub 'return ((Comparable) entry1.getValue()). CompareTo (entry2. getValue()); ' – Raze

+0

Myślę, że mam to, co miałeś na myśli. – Raze

+0

@Raze. Używam aktualizacji JDK 6 Update 21. Gdyby nie JDK 5 lub 6, generics nie skompilowałoby się poprawnie? :) –

Odpowiedz

4

Myślę, że druga opcja, a mianowicie

public static <K, V extends Comparable<? super V>> 

jest droga. Myślę, że to jest tak dlatego, że podczas pisania

public static <K, V extends Comparable<C extends V>> 

można w zasadzie powiedzieć, że chcesz być w stanie porównać każdą instancję V do każdej instancji C. Ale czego tu brakuje, to dlatego, że chcesz wewnętrznie wywołać Collections.sort(..), musisz także móc porównać każde wystąpienie C do dowolnego wystąpienia V. Ale generics nie wyrażają tego i słusznie kompilator narzeka.

Zasadniczo uporządkować pewne wartości (przynajmniej przy użyciu Collections.sort(..)) muszą być wzajemnie porównywalne, ale ogólne ograniczenia sobie wyobrazić jedynie zagwarantować, że można porównać w jednym kierunku.

3

implementuje się Porównywalne z podklasą samej siebie.

To jest "zły projekt": jako dobra ogólna zasada, klasy nie powinny wiedzieć o swoich podklasach.

Co masz na myśli?

Myślę, że public static <K, V extends Comparable<V>> jest w porządku.

0

Chyba chciałeś V będzie przedłużeniem jakiegoś typu T. Spróbuj dodać tymczasowy typu T, co następuje w deklaracji szablonu:

public static <K, T extends Comparable<T>, V extends T> Map<K, V> 
    sortByValues(final Map <K, V> mapToSort) 

wszystko inne pozostaje taka sama. Jeśli nie masz na myśli tego, że wszystkie twoje Komparamenty będą podtypem V, wtedy public static <K, V extends Comparable<V>> ma sens, ponieważ z punktu widzenia V, klasa potomna V, która nadpisuje compareTo, będzie nazywała metodę compareTo z tym samym podpisem co metoda compareTo, którą ma V. Tj. Metoda compareTo deklarowana przez V jest tym, co zostanie wywołane (ale może to być definicja przesłaniania w klasie potomnej V). I tak, V extends Comparable<V> jest wystarczająca i poprawna. Mam nadzieję, że wyraziłem się jasno.

Powiązane problemy