在 Java 中,EnumSet 使用long
( RegularEnumSet
) 或long[]
( JumboEnumSet
) 将其包含的项目存储在位掩码/位向量中。我现在遇到了一个用例,其中我有数千个域对象(让我们称之为它们),每个对象都将按照每个对象不同的顺序Node
显示枚举的所有项目(让我们称之为)。Flag
目前我将 Order 存储为 Guava ImmutableSet
,因为这样可以保证保留插入顺序。但是,我已使用此页面上解释的方法来比较 an EnumSet<Flag>
、 anImmutableSet<Flag>
和 a中的内存使用情况Flag[]
。以下是 a) Flag 有 64 个枚举项和 b) 所有三个变体都包含所有 64 个项时的结果:
EnumSet:32 字节
ImmutableSet:832 字节
数组:272 字节
所以我的问题是:有没有一种聪明的方法可以将枚举排序打包成一个数值,以获得小于数组的内存占用?如果它有所作为:在我的用例中,我会假设排序总是包含所有 Enum 项目。
澄清一下:我的枚举比那个小得多,到目前为止我没有任何内存问题,这种情况也不可能给我带来内存问题。只是这种低效率困扰着我,即使在这个微观层面上也是如此。
更新:
根据各种答案和评论的建议,我想出了这个使用字节数组的数据结构。警告:它没有实现 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();
}
};
}
}
内存占用为:
枚举排序:104
到目前为止,这是一个相当不错的结果,这要感谢 bestsss 和 JB Nizet!
更新:我已将代码更改为仅实现 Iterable,因为其他任何事情都需要对 equals / hashCode / contains 等进行合理的实现。