我有许多枚举,每个枚举都有相同的字段和相同的方法。
public enum AddressSubType {
DOM("dom"), INTL("intl"), POSTAL("postal");
private final String keyword;
private AddressSubType(String keyword) {
this.keyword = keyword;
}
public String getKeyword() {
return keyword;
}
@Override
public String toString() {
return keyword;
}
}
public enum EmailSubType {
INTERNET("internet"), X400("x.400");
private final String keyword;
private EmailSubType(String keyword) {
this.keyword = keyword;
}
public String getKeyword() {
return keyword;
}
@Override
public String toString() {
return keyword;
}
}
这些枚举是否有办法共享字段和方法(如父类)?我知道it's not possible to extend enums。感谢。
答案 0 :(得分:1)
您可以声明他们都可以实施的interface
。这将允许您将枚举类型作为参数传递给仅关注该表面上的特定方法的方法。但是,这只允许您“共享”方法签名,而不是字段或方法实现。
如果你的枚举与给定的例子一样简单,你没有任何大量的代码重复,所以这可能不是问题。如果您发现您的方法具有更复杂,重复的代码,您应该考虑将该职责委托给单独的类。
如果您真的想要为继承模式建模(例如EmailAddress
“是”Address
),那么您需要远离enums
。您可以使用一些静态字段来模拟枚举模式,但每个都是特定类的实例。
答案 1 :(得分:1)
我可能会将它们组合成一个枚举对象,其中一些初始化为“Postal”标志设置为true,一些将“email”标志设置为true,因为这两者实际上只是地址的不同“类型”。
如果你想单独访问它们,你可以让它返回迭代器,或者你可以迭代整个事物。
您可能还会发现其他一些代码变得简化,例如只有一个“地址”集合,并在运行时检查给定的地址是电子邮件还是邮件。
但这取决于它们的真实程度。
答案 2 :(得分:1)
您可以创建一个Value类
public class Value {
private final String keyword;
private Value(String keyword) {
this.keyword = keyword;
}
public String getKeyword() {
return keyword;
}
@Override
public String toString() {
return keyword;
}
}
然后你可以创建具有公共静态最终值的类,如下所示:
public class AddressSubType extend Value {
public static final AddressSubType DOM = new AddressSubType("DOM");
public static final AddressSubType INTL = new AddressSubType("intl");
...
private AddressSubType(String keyword) {
super(keyword);
}
}
答案 3 :(得分:1)
我会成为那个人。这是一个糟糕的主意。
只要需要表示一组固定的常量,就应该使用枚举类型。这包括自然枚举类型,例如太阳系中的行星和数据集,您可以在编译时知道所有可能的值 - 例如,菜单上的选项,命令行标志等。 source
除了内部的硬编码值之外,枚举不关心任何其他内容。通常,当决定以面向对象的方式对事物进行分组时,它们会确保所有对象都是相关的。由于是枚举,这些文件与作为Object的子类型的两个类不再相关。如果您希望在域中的所有枚举之间具有共享功能,则需要查看一些静态函数或实用程序类,因为它经常被引用(在一天结束时它有一系列问题)。本质上,类将有一系列封装所有共享逻辑的函数,签名通常如下所示:
function foo(Enum enumeration)
答案 4 :(得分:1)
在这种情况下你无能为力,即使是在一个更复杂的例子中,放置公共代码的最佳位置可能是所有枚举可以使用的实用程序类,或者包含在单独的类中在枚举中通过组合(每个枚举都有一个该类的实例,可能称为关键字)。
如果toString
方法的代码很复杂,并且您不想在每个枚举中重述它,或者将其移动到包含的对象,那么Java 8就有一种可以使用的机制。在这个例子中它是矫枉过正的。您可以定义您的枚举将全部使用的接口。状态(关键字)必须仍然存在于您的枚举中,因为接口不能具有状态,但从Java 8开始,您可以提供方法的默认实现:
public interface Common {
String getKeyword();
String toString() default {
return getKeyword();
}
String toDescriptiveString() default {
char firstLetter = getKeyword().charAt(0);
boolean vowel =
firstLetter == 'a' || firstLetter == 'e' ||
firstLetter == 'i' || firstLetter == 'o' ||
firstLetter == 'u' || firstLetter == 'x';
// the letter x is pronounced with an initial vowel sound (eks)
return (vowel?"an ":"a ") + getKeyword() + " address";
}
}
您的枚举将实现此界面:
public enum AddressSubType implements Common {
DOM("dom"), INTL("intl"), POSTAL("postal");
private final String keyword;
private AddressSubType(String keyword) {
this.keyword = keyword;
}
@Override
public String getKeyword() {
return keyword;
}
@Override
public String toString() {
return Common.super.toString();
}
}
public enum EmailSubType implements Common {
INTERNET("internet"), X400("x.400");
private final String keyword;
private EmailSubType(String keyword) {
this.keyword = keyword;
}
@Override
public String getKeyword() {
return keyword;
}
@Override
public String toString() {
return Common.super.toString();
}
}
注意toString
方法中奇怪的新语法。接口中默认方法的规则是方法解析总是优先于接口上的类方法。因此,即使我们在toString
中提供Common
的默认实现,枚举中的一个将优先,而Object
中的那个将在枚举中没有。Object
。因此,如果您想使用取代toString
中某个方法的接口的默认方法(例如hashCode
,或equals
或interface.super.method()
),那么您有使用这种新的toDescriptiveString
语法显式调用它。
但是,我们不必为interface Common
方法跳过任何额外的箍。那个在public class Test {
public static void main(String[] args) {
for (AddressSubType a : AddressSubType.values()) {
System.out.println(a.toDescriptiveString());
}
for (EmailSubType e : EmailSubType.values()) {
System.out.println(e.toDescriptiveString());
}
}
}
中是全新的,并且我们的枚举不提供它,因此它们获得接口提供的默认实现。 (如果他们想用自己的方法覆盖它,就像任何其他继承的方法一样。)
我们可以使用默认方法,就像对象的任何其他方法一样:
toDescriptiveString
打印出来:
a dom address an intl address a postal address an internet address an x.400 address
但是,在这种情况下,如果它不适用于相当冗长的interface Common
方法,那么使用{{1}}的枚举类不会比它们没有那么短。在为现有接口添加新功能时,接口中的默认方法将真正发挥作用,这是不可能在不破坏以前Java版本中接口的所有实现者的情况下实现的。
所有这些都是基于尚未完成的Java SE 8 with Lambda。您可以下载预发布版本,但请注意它正在进行中。