2009-02-06 4 views
72

Un enum in Java implementa l'interfaccia Comparable. Sarebbe stato bello sovrascrivere il metodo compareTo di, ma qui è contrassegnato come finale. L'ordine naturale predefinito su è l'ordine elencato.Perché compare su un finale Enum in Java?

Qualcuno sa perché un'enumerazione di Java ha questa restrizione?

risposta

98

Per coerenza immagino ... quando si vede un tipo enum, si sa per certo che il suo ordinamento naturale è l'ordine in cui sono dichiarate le costanti.

Per risolvere questo, si può facilmente creare il proprio Comparator<MyEnum> e utilizzarlo ogni volta che avete bisogno di un ordine diverso:

enum MyEnum 
{ 
    DOG("woof"), 
    CAT("meow"); 

    String sound;  
    MyEnum(String s) { sound = s; } 
} 

class MyEnumComparator implements Comparator<MyEnum> 
{ 
    public int compare(MyEnum o1, MyEnum o2) 
    { 
     return -o1.compareTo(o2); // this flips the order 
     return o1.sound.length() - o2.sound.length(); // this compares length 
    } 
} 

È possibile utilizzare il Comparator direttamente:

MyEnumComparator c = new MyEnumComparator(); 
int order = c.compare(MyEnum.CAT, MyEnum.DOG); 

e non utilizzarlo in collezioni o array:

NavigableSet<MyEnum> set = new TreeSet<MyEnum>(c); 
MyEnum[] array = MyEnum.values(); 
Arrays.sort(array, c);  

Furth er informazioni:

+0

I comparatori personalizzati sono efficaci solo quando si fornisce l'Enum a una raccolta. Non aiuta tanto se vuoi fare un confronto diretto. –

+5

Sì, lo fa. nuovo MyEnumComparator.compare (enum1, enum2). Et voilà. – Bombe

+0

@martinoconnor & Bombe: ho inserito i tuoi commenti nella risposta. Grazie! –

-2

Se si desidera modificare l'ordine naturale degli elementi dell'enumerazione, modificare l'ordine nel codice sorgente.

+0

Sì, questo è quello che ho scritto nella voce originale :) – neu242

+0

Sì, ma non si spiega in realtà perché si vorrà sovrascrivere compareTo(). Quindi la mia conclusione è stata che stai cercando di fare Something Bad ™ e stavo cercando di mostrarti un modo più corretto. – Bombe

+0

Non vedo perché dovrei dover ordinare le voci manualmente quando i computer lo fanno molto meglio di me. – neu242

5

valori di enumerazione sono proprio ordine logico secondo l'ordine in cui vengono dichiarati. Questo fa parte delle specifiche del linguaggio Java. Pertanto, ne consegue che i valori di enumerazione possono essere confrontati solo se sono membri della stessa Enum. La specifica vuole garantire ulteriormente che l'ordine comparabile restituito da compareTo() sia uguale all'ordine in cui sono stati dichiarati i valori. Questa è la definizione stessa di un'enumerazione.

+0

Come ha indicato Thomas Paine nel suo esempio, la lingua può solo ordinare per sintattica, non per semantica. Voi dite, gli oggetti sono _ordinati_ logicamente, ma il modo in cui capisco enum, gli elementi sono _incapsulati_ con mezzi logici. – Bondax

28

Fornire un'implementazione predefinita di compareTo che utilizza l'ordinamento del codice sorgente va bene; renderlo definitivo è stato un passo falso da parte di Sun. L'ordinale rappresenta già l'ordine di dichiarazione. Sono d'accordo che nella maggior parte delle situazioni uno sviluppatore può semplicemente ordinare logicamente i propri elementi, ma a volte si vuole che il codice sorgente sia organizzato in modo da rendere la leggibilità e la manutenzione fondamentali. Per esempio:


    //===== SI BYTES (10^n) =====// 

    /** 1,000 bytes. */ KILOBYTE (false, true, 3, "kB"), 
    /** 106 bytes. */ MEGABYTE (false, true, 6, "MB"), 
    /** 109 bytes. */ GIGABYTE (false, true, 9, "GB"), 
    /** 1012 bytes. */ TERABYTE (false, true, 12, "TB"), 
    /** 1015 bytes. */ PETABYTE (false, true, 15, "PB"), 
    /** 1018 bytes. */ EXABYTE (false, true, 18, "EB"), 
    /** 1021 bytes. */ ZETTABYTE(false, true, 21, "ZB"), 
    /** 1024 bytes. */ YOTTABYTE(false, true, 24, "YB"), 

    //===== IEC BYTES (2^n) =====// 

    /** 1,024 bytes. */ KIBIBYTE(false, false, 10, "KiB"), 
    /** 220 bytes. */ MEBIBYTE(false, false, 20, "MiB"), 
    /** 230 bytes. */ GIBIBYTE(false, false, 30, "GiB"), 
    /** 240 bytes. */ TEBIBYTE(false, false, 40, "TiB"), 
    /** 250 bytes. */ PEBIBYTE(false, false, 50, "PiB"), 
    /** 260 bytes. */ EXBIBYTE(false, false, 60, "EiB"), 
    /** 270 bytes. */ ZEBIBYTE(false, false, 70, "ZiB"), 
    /** 280 bytes. */ YOBIBYTE(false, false, 80, "YiB"); 

È possibile che questo ordinamento guarda bene nel codice sorgente, ma non è come l'autore ritiene che il compareTo dovrebbe funzionare. Il paragone desiderato per il comportamento è avere un ordinamento in base al numero di byte. L'ordinamento del codice sorgente che farebbe accadere ciò degraderebbe l'organizzazione del codice.

Come cliente di un'enumerazione non mi importava meno come l'autore ha organizzato il proprio codice sorgente. Voglio però che il loro algoritmo di confronto abbia un qualche senso, comunque. Sun ha inutilmente messo i writer del codice sorgente in un vincolo.

+3

D'accordo, voglio che il mio enum sia in grado di avere un algoritmo simile a quello degli affari invece di un ordine che può essere rotto se qualcuno non presta attenzione. – TheBakker

2

Una possibile spiegazione è che compareTo deve essere coerente con equals.

E equals per le enumerazioni devono essere coerenti con l'uguaglianza di identità (==).

Se compareTo dove non-finale, sarebbe possibile sovrascriverlo con un comportamento che non era coerente con equals, che sarebbe molto contro-intuitivo.