0

我有 2 个枚举值表示到对象的映射,我(当前)使用 HashMap 建模,其中 2 个枚举值用作键,对象是值。

这是低效的,因为我正在为 Enum1.values() x Enum2.values() 的每个组合创建一个新的 CompositeKey(Enum1 enum1, Enum2 enum2)。

我想跳过新的 CompositeKey() 问题。

我目前想到的解决方案是计算来自 2 个枚举的数字表示,类似于int numericKey = enum1.ordinal() * 0xFFFF + enum2.ordinal();但当我这样做时,map.get(numricKey)我仍然会自动装箱到 Integer - 因此创建新实例。

一个完美的解决方案(IMO)将是 Map 实现(不必是通用的......)但我认为 java 不存在这样的解决方案。

另一个选项可能mapping = new Object[Enum1.values().length][Enum2.values().length]是我将使用它进行查找,Object = mapping[enum1.ordinal()][enum2.ordinal()]但这似乎有点过于“C'ish”。

无论如何,运行时性能是这里最重要的方面。

欢迎评论。

谢谢,马克西姆。

4

4 回答 4

5

使用 an 的序数enum是一个非常糟糕的主意,因为序数是枚举的内部表示,永远不应该在外部代码中使用。Enum 规范对序数有这样的说法:

大多数程序员不会使用这种方法。它设计用于复杂的基于枚举的数据结构,例如 EnumSet 和 EnumMap。

我建议使用EnumMap专门设计的用途,例如您所拥有的用途。EnumMap<Enum1,EnumMap<Enum2,V>>使用枚举的值创建并填充它:

for (Enum1 e1: Enum1.values()) {
    map.put(e1, new EnumMap<Enum2,V>());
    for (Enum2 e2 : Enum2.values()) {
        map.get(e1).put(e2, getSomeValue(e1, e2));
    }
}
于 2010-09-16T20:12:48.893 回答
1

我不同意 Sarkar 关于使用 Enum.ordinal() 方法的观点。使用有效且有效。当然,这完全取决于使用范围。如果您可以在代码中应用 EnumMap 或 EnumSet,那么您设计的任何解决方案都将具有相同的运行时范围。您应该避免在当前运行的 VM 之外使用 ordinal() 方法,例如序列化、外部化或持久值。

最快的解决方案仍然是数组中的计算偏移量,但可能会使用大量内存。但是,如果您有大量的枚举(这真的会让人怀疑 Enum 的适当使用),组合很少,导致数组很大但稀疏,那么您原来的“复合”键是非常接近的第二个。

最后,纯粹出于性能考虑,如果您要形成示例中给出的复合键,请int numericKey = enum1.ordinal() * 0xFFFF + enum2.ordinal(); 使用更快的移位运算符和 OR 运算符,而不是乘法和加法运算符:int numericKey = (enum1.ordinal() << 16) | enum2.ordinal();

于 2011-09-01T17:18:49.940 回答
1

我认为CompositeKey从维护的角度来看,这种方法是最好的,因为它可以让您不加改变地使用现有的集合。创建该对象的实例的开销实际上并没有那么高——大多数实例将是短暂的,并且永远不会离开 Eden 空间(分配和收集都非常迅速)。

您还可以实现Map<Enum1,Map<Enum2,?>>, withEnumMap作为您的实现类型。但是,您必须预先填充“外部”地图,或者编写代码以延迟填充它。

但是,如果运行时性能是您的首要任务,那么使用数组的想法是最好的。但是,我不会将它实现为二维数组。相反,使用一维数组和索引,如下所示:

int index = enum1.ordinal() * _enum1Size + enum2.ordinal;

把它包在一个类中,你就完成了。

于 2010-09-16T20:03:48.457 回答
0

我有一个名为标签的 HashMap,其键类型为 Key,其中两个枚举作为成员。我注意到使用相同值创建的两个 Key 实例具有不同的哈希码。覆盖 hashCode() 我能够得到相应的值,否则我总是得到空值。

这是代码:

public static String getMeasureLabel(MeasureSerie measure, TwampMeasure traffic) {
        Key key = new Key(traffic, measure);
        //Key key1 = new Key(traffic, measure); //key.hashCode() != key1.hashCode()
        return labels.get(key); // always returned null
    }

这是关键

public static class Key {

        public TwampMeasure trafficType;
        public MeasureSerie measureType;


        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result
                    + ((measureType == null) ? 0 : measureType.getValue().hashCode());
            result = prime * result
                    + ((trafficType == null) ? 0 : trafficType.getValue().hashCode());
            return result;
        }

    }
于 2013-12-04T10:35:59.367 回答