好奇是否有人考虑过使用 EnumMap 代替 Java bean,尤其是“值对象”(没有行为)?在我看来,一个优势似乎是“属性”的名称可以直接从支持的 Enum 访问,无需反射,因此我认为它会更快。
5 回答
一个 bean 意味着是可变的,因此 setter 方法。EnumMap 在速度上与使用整数作为 Key 的 HashMap 相当,但 Key 是不可变的。Beans 和 EnumMaps 有两种不同的用途。如果所有的 Key 在设计时都是已知的并且保证永远不会改变,那么使用 EnumMap 就可以了。
更新 bean 比更改 EnumMap 的支持 Enum 要简单得多,而且在下游代码中创建错误的可能性要小得多。
它可能比使用反射快一点(我没有测量它,也没有在谷歌中找到任何指标);但是这种方法有很大的缺点:
您正在失去类型安全性。而不是
int getAge()
和String getName()
一切都是Object get(MyEnum.FIELD_NAME)
。这将提供一些丑陋的代码和运行时错误。我们喜欢和喜欢的所有 javabean 细节(例如,属性级注释)都消失了。
由于您根本没有任何行为,因此这种方法的适用性似乎相当有限。
底线是 - 如果你真的需要所谓的:-) 性能提升(你必须测量它以证明它存在),这在非常特定的情况下可能是一种可行的方法。它是整个 javabean 的可行替代方案吗?绝对不是。
我编写了一个 Record 类,它将键映射到值,并通过委托给一个完全同步的 EnumMap 来工作。这个想法是 Record 可以在运行时获取新字段,而 Bean 不能。我的结论是,有了这种灵活性,性能就会受到影响。这是一个将 Record 类与完全同步的 Bean 进行比较的运行。对于 1000 万次操作:
Record set(Thing, a) 458 ms
Bean setThing(a) 278 ms
Record get(Thing) 398 ms
Bean getThing 248 ms
因此,了解您的数据对象并编写一个静态建模它们的类会有所收获。如果您想在运行时将新字段填充到您的数据中,那么您将付出代价。
我之前没有指定这个,但我正在使用 ResultSet。因此,为了完整起见,我想提供这个答案。
Commons/BeanUtil 的“RowSetDynaClass”可能是与具体 bean 相关的过多样板和 EnumMap 的限制之间的快乐媒介
I don't understand how you can remove 'class profileration' with EnumMaps. Unless you have a generic enum with 20-odd properties to reuse for every 'bean', you're still inventing an enum to use for each enum map, e.g.
public enum PersonDTOEnum {
A, S, L;
}
as opposed to
class Person {
int a;
int s;
String l;
// getters + setters elided
}
Not to mention that everything is a String now.