我有一个枚举:
public enum Persons {
CHILD,
PARENT,
GRANDPARENT;
}
使用ordinal()
方法检查枚举成员之间的“层次结构”是否存在问题?我的意思是-使用它时,除了冗长之外,还有什么缺点吗?将来有人可能会意外更改顺序。
或者做这样的事更好:
public enum Persons {
CHILD(0),
PARENT(1),
GRANDPARENT(2);
private Integer hierarchy;
private Persons(final Integer hierarchy) {
this.hierarchy = hierarchy;
}
public Integer getHierarchy() {
return hierarchy;
}
}
TLDR:不,你不应该!
如果您在ordinal
中引用Javadoc的Enum.java
方法:
大多数程序员都不会使用此方法。它是设计供基于枚举的复杂数据结构使用,例如分别为
java.util.EnumSet
和java.util.EnumMap
。
首先-阅读手册(在这种情况下为Javadoc)。
第二-不要写易碎的代码。枚举值将来可能会更改,您的第二个代码示例将更多地[
PARENT
和GRANDPARENT
之间插入一个新的枚举值,则绝对不会为将来带来麻烦。第一种方法不容易理解,因为您必须阅读使用枚举来理解枚举顺序很重要的代码。这很容易出错。
public enum Persons {
CHILD,
PARENT,
GRANDPARENT;
}
更好,因为它是自我解释:第二种方式
CHILD(0),
PARENT(1),
GRANDPARENT(2);
private SourceType(final Integer hierarchy) {
this.hierarchy = hierarchy;
}
,因为枚举值和枚举构造函数的参数都传达了它们的层次结构。但是为什么会有问题?枚举旨在表示恒定且不经常更改的值。OP枚举用法很好地说明了良好的枚举用法:
当然,枚举值的顺序应与枚举构造函数参数提供的层次顺序一致。它引入了一种冗余
CHILD, PARENT, GRANDPARENT
枚举不是为了表示经常移动的值。在这种情况下,使用枚举可能不是最佳选择,因为它可能会频繁破坏使用该枚举的客户端代码,并且在每次修改枚举值时,它都会强制重新编译,重新打包和重新部署应用程序。
Effective Java中所建议的那样,从其序数派生与枚举关联的值不是一个好主意,因为更改枚举值的顺序可能会破坏您编码的逻辑。
您提到的第二种方法完全遵循作者的建议,即将值存储在单独的字段中。我想说,您建议的替代方案肯定更好,因为它在扩展枚举值的顺序和层次结构的概念时更加可扩展和可维护。
Comparable
是为Comparable
实现的。如果您
do由于某种原因需要数字顺序值,是的,您应该使用Enum<E>
。这就是它的用途。
Comparable<E>
的标准做法是按声明顺序排序,这就是ordinal()
实现Enums
的原因,以及为什么Enum<E>
是Comparable<E>
。如果您添加自己的不使用的非标准比较代码,Enum.compareTo()
并且不依赖于声明顺序,您只是会使其他试图使用您的代码的人感到困惑,包括你自己未来的自我。没有人会期望该代码存在。他们将期望final
为Comparable
。
如果自定义订单与声明订单不符,则任何人看着宣言会很困惑。如果
确实
(此刻正要)符合声明顺序,任何人看着它会期待这一点,他们将在某个将来的日期没有收到令人讨厌的震惊。 (如果您写代码(或测试)以确保定制订单与声明顺序,您只是在增强它的不必要性。)如果添加您自己的订单价值,您将在维护方面感到头疼为自己:Enum
值是唯一的总而言之,用Enum
的不朽字眼:
了解并使用库
hierarchy
时,请勿使用Item 47。 🙂Integer
,因为枚举声明中的更改可能会影响顺序值。UPDATE:
值得注意的是,枚举字段是常量,并且可以具有重复的值,即int
根据您打算对ordinal()
进行的处理,可能有害或有益。此外,例如,您可以使用枚举常量来构建自己的
enum Family { OFFSPRING(0), PARENT(1), GRANDPARENT(2), SIBLING(3), COUSING(4), UNCLE(4), AUNT(4); private final int hierarchy; private Family(int hierarchy) { this.hierarchy = hierarchy; } public int getHierarchy() { return hierarchy; } }
而不是使用hierarchy
其他枚举值:
EnumFlags
请注意,您只能使用在您要声明的值之前按词法声明的枚举值,因此,仅当您的关系形成一个无环有向图(并且声明它们的顺序是有效的拓扑排序)时,此方法才有效。
EnumSet
返回此枚举常数的序数(其在枚举声明,其中初始常量分配为的序数零)。大多数程序员都不会使用此方法。它是设计供基于枚举的复杂数据结构使用,例如EnumSet和EnumMap。
您可以通过更改枚举的顺序来控制序数,但是不能明确设置它。一种解决方法是在枚举中为所需的数字提供一个额外的方法。
public enum Person {
GRANDPARENT(null),
PARENT(GRANDPARENT),
CHILD(PARENT);
private final Person parent;
private Person(Person parent) {
this.parent = parent;
}
public final Parent getParent() {
return parent;
}
}
在这种情况下为doc,但为enum Mobile {
Samsung(400), Nokia(250),Motorola(325);
private final int val;
private Mobile (int v) { val = v; }
public int getVal() { return val; }
}
。
创建带有静态属性的类,它将模拟您的枚举:
Samsung.ordinal() = 0
然后像枚举一样使用:
Samsung.getVal() = 400
它将适用于大多数简单的用例。否则,您可能会缺少public class Persons { final public static int CHILD = 0; final public static int PARENT = 1; final public static int GRANDPARENT = 2; }
,Persons.CHILD
,valueOf()或EnumSet之类的选项。