long
Javaでは、EnumSetは、 (RegularEnumSet
)またはlong[]
( )を使用して、含まれるアイテムをビットマスク/ビットベクトルに格納しますJumboEnumSet
。私は今、何千ものドメインオブジェクト(それらを呼びましょう)を持っているユースケースに出くわしました。それぞれがオブジェクトごとに異なる順序でNode
列挙型のすべてのアイテムを表示します(それを呼びましょう)。Flag
現在、注文をGuavaとして保存していImmutableSet
ます。これは、挿入注文を保持することが保証されているためです。ただし、このページで説明されている方法EnumSet<Flag>
を使用して、、、ImmutableSet<Flag>
およびのメモリ使用量を比較しましたFlag[]
。a)フラグに64個の列挙型アイテムがあり、b)3つのバリアントすべてに64個のアイテムすべてが含まれている場合の結果は次のとおりです。
EnumSet:32バイト
ImmutableSet:832バイト
配列:272バイト
だから私の質問は:列挙型の順序を数値にパックして、配列のメモリフットプリントよりも小さいメモリフットプリントを取得する賢い方法はありますか?違いが生じる場合:私のユースケースでは、順序には常にすべての列挙型アイテムが含まれていると想定します。
明確にするために:私の列挙型はそれよりもはるかに小さく、現在のところメモリの問題はありません。また、この状況でメモリの問題が発生する可能性もありません。この非効率性は、この微視的なレベルでさえ、私を悩ませているだけです。
アップデート:
さまざまな回答やコメントからの提案の後、バイト配列を使用するこのデータ構造を思いつきました。警告:Setインターフェイスを実装しておらず(一意の値をチェックしません)、バイトが保持できる範囲を超える大きな列挙型にスケーリングされません。また、Enum.values()を繰り返しクエリする必要があるため(この問題の説明についてはここを参照)、複雑さはかなりひどいですが、ここでは次のようになります。
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();
}
};
}
}
メモリフットプリントは次のとおりです。
EnumOrdering:104
これまでのところ、bestsssとJB Nizetのおかげで、これはかなり良い結果です。
更新:コードを変更してIterableのみを実装しました。これは、equals / hashCode/containsなどに適切な実装が必要になるためです。