In Java, un EnumSet memorizza gli elementi in esso contenuti in una maschera di bit/vettore di bit utilizzando un long
(RegularEnumSet
) o long[]
(JumboEnumSet
). Ora ho trovato un caso d'uso in cui ho molti oggetti di dominio (chiamiamoli Node
), ognuno dei quali mostrerà tutti gli elementi di un enum (chiamiamolo Flag
) in un ordine che varierà per Oggetto.Conservare un ordinamento di enumerazioni in Java
Attualmente sto memorizzando l'ordine come Guava ImmutableSet
, perché ciò garantisce di mantenere l'ordine di inserimento. Tuttavia, ho utilizzato the methods explained on this page per confrontare l'utilizzo della memoria in uno EnumSet<Flag>
, uno ImmutableSet<Flag>
e uno Flag[]
. Qui sono i risultati quando a) Flag ha 64 elementi enum e b) tutte e tre le varianti contiene tutti i 64 articoli:
EnumSet: 32 byte
ImmutableSet: 832 bytes
Array: 272 bytes
Quindi la mia domanda è: esiste un modo intelligente per impacchettare l'enumerazione in un valore numerico per ottenere un ingombro di memoria inferiore a quello dell'array? Se fa la differenza: nel mio caso d'uso suppongo che l'ordine contenga sempre tutti gli oggetti Enum.
Per chiarire: il mio enum è molto più piccolo di quello e non ho alcun problema di memoria al momento, né è probabile che questa situazione mi darà mai problemi di memoria. È solo che questa inefficienza mi infastidisce, anche a questo livello microscopico.
Aggiornamento:
Dopo i suggerimenti delle varie risposte e commenti mi si avvicinò con questa struttura dati che utilizza un array di byte. Avvertenza: non implementa l'interfaccia Set (non controlla i valori univoci) e non ridimensiona le enumerazioni di grandi dimensioni oltre ciò che un byte può contenere. Inoltre, la complessità è abbastanza terribile, perché Enum.values () deve essere interrogato ripetutamente (see here for a discussion of this problem), ma qui va:
public class EnumOrdering<E extends Enum<E>> implements Iterable<E> {
private final Class<E> type;
private final byte[] order;
public EnumOrdering(final Class<E> type, final Collection<E> order) {
this.type = type;
this.order = new byte[order.size()];
int offset = 0;
for (final E item : order) {
this.order[offset++] = (byte) item.ordinal();
}
}
@Override
public Iterator<E> iterator() {
return new AbstractIterator<E>() {
private int offset = -1;
private final E[] enumConstants = type.getEnumConstants();
@Override
protected E computeNext() {
if (offset < order.length - 1) {
return enumConstants[order[++offset]];
}
return endOfData();
}
};
}
}
L'occupazione di memoria è:
EnumOrdering: 104
Questo è un buon risultato finora, grazie a bestsss e JB Nizet!
Aggiornamento: ho cambiato il codice per implementare solo Iterable, perché qualsiasi altra cosa richiederebbe implementazioni ragionevoli per equals/hashCode/contiene ecc
semplice array di byte [], byte [] contiene l'enum.ordinale. se hai più di 256 elementi puoi usare short []/int []. In alternativa puoi imballare gli articoli in meno di 8 bit. Potrebbe essere necessario fare molta attenzione alla serializzazione, in entrambi i casi il codice sarà inferiore a 200 linee ed è piuttosto banale. – bestsss
se non è necessario l'ordine di inserzione, basta usare un singolo lungo - può contenere fino a enum w/64 elementi, proprio come è fatto in C. – bestsss
@bestsss se non ho avuto bisogno dell'ordine di inserzione, io userei un EnumSet, che fa esattamente quello –