我想采用现有的枚举并添加更多元素,如下所示:
enum A {a,b,c}
enum B extends A {d}
/*B is {a,b,c,d}*/
Run Code Online (Sandbox Code Playgroud)
这在Java中可行吗?
Jon*_*eet 432
不,你不能用Java做到这一点.除了其他任何东西之外,d大概可能是A(给出"扩展"的正常概念)的一个实例,但是只知道A它的用户不会知道它 - 这会使枚举点成为一个众所周知的集合值.
如果您可以告诉我们更多关于您希望如何使用它的信息,我们可以建议其他解决方案.
Tom*_*ine 307
枚举代表可能值的完整枚举.所以(无益的)答案是否定的.
作为一个真实问题的一个例子,需要工作日,周末和工会,一周中的几天.我们可以定义星期几内的所有日期,但是我们无法在工作日和周末日表示特殊属性.
我们可以做的是,有三种枚举类型,在工作日/周末 - 日和星期几之间进行映射.
public enum Weekday {
MON, TUE, WED, THU, FRI;
public DayOfWeek toDayOfWeek() { ... }
}
public enum WeekendDay {
SAT, SUN;
public DayOfWeek toDayOfWeek() { ... }
}
public enum DayOfWeek {
MON, TUE, WED, THU, FRI, SAT, SUN;
}
Run Code Online (Sandbox Code Playgroud)
或者,我们可以为星期几开放一个开放式界面:
interface Day {
...
}
public enum Weekday implements Day {
MON, TUE, WED, THU, FRI;
}
public enum WeekendDay implements Day {
SAT, SUN;
}
Run Code Online (Sandbox Code Playgroud)
或者我们可以将两种方法结合起来:
interface Day {
...
}
public enum Weekday implements Day {
MON, TUE, WED, THU, FRI;
public DayOfWeek toDayOfWeek() { ... }
}
public enum WeekendDay implements Day {
SAT, SUN;
public DayOfWeek toDayOfWeek() { ... }
}
public enum DayOfWeek {
MON, TUE, WED, THU, FRI, SAT, SUN;
public Day toDay() { ... }
}
Run Code Online (Sandbox Code Playgroud)
Chr*_*ell 52
在封面下,您的ENUM只是编译器生成的常规类.生成的类扩展了java.lang.Enum.您无法扩展生成的类的技术原因是生成的类是final.本主题讨论了它最终的概念性原因.但我会在讨论中添加机制.
这是一个测试枚举:
public enum TEST {
ONE, TWO, THREE;
}
Run Code Online (Sandbox Code Playgroud)
来自javap的结果代码:
public final class TEST extends java.lang.Enum<TEST> {
public static final TEST ONE;
public static final TEST TWO;
public static final TEST THREE;
static {};
public static TEST[] values();
public static TEST valueOf(java.lang.String);
}
Run Code Online (Sandbox Code Playgroud)
可以想象,您可以自己键入此类并删除"最终".但编译器会阻止您直接扩展"java.lang.Enum".您可以决定不扩展java.lang.Enum,但是您的类及其派生类将不是java.lang.Enum的实例......这对您来说可能并不重要!
Wal*_*ski 26
enum A {a,b,c}
enum B extends A {d}
/*B is {a,b,c,d}*/
Run Code Online (Sandbox Code Playgroud)
可以写成:
public enum All {
a (ClassGroup.A,ClassGroup.B),
b (ClassGroup.A,ClassGroup.B),
c (ClassGroup.A,ClassGroup.B),
d (ClassGroup.B)
...
Run Code Online (Sandbox Code Playgroud)
它是如何有用的:让我们说我们想要的东西:我们有事件,我们正在使用枚举.这些枚举可以通过类似的处理进行分组.如果我们有许多元素的操作,那么一些事件开始操作,一些事件只是步骤而另一个事件结束操作.要收集此类操作并避免长时间切换,我们可以按照示例对它们进行分组并使用:
if(myEvent.is(State_StatusGroup.START)) makeNewOperationObject()..
if(myEnum.is(State_StatusGroup.STEP)) makeSomeSeriousChanges()..
if(myEnum.is(State_StatusGroup.FINISH)) closeTransactionOrSomething()..
Run Code Online (Sandbox Code Playgroud)
例:
public enum AtmOperationStatus {
STARTED_BY_SERVER (State_StatusGroup.START),
SUCCESS (State_StatusGroup.FINISH),
FAIL_TOKEN_TIMEOUT (State_StatusGroup.FAIL,
State_StatusGroup.FINISH),
FAIL_NOT_COMPLETE (State_StatusGroup.FAIL,
State_StatusGroup.STEP),
FAIL_UNKNOWN (State_StatusGroup.FAIL,
State_StatusGroup.FINISH),
(...)
private AtmOperationStatus(StatusGroupInterface ... pList){
for (StatusGroupInterface group : pList){
group.addMember(this);
}
}
public boolean is(StatusGroupInterface with){
for (AtmOperationStatus eT : with.getMembers()){
if( eT .equals(this)) return true;
}
return false;
}
// Each group must implement this interface
private interface StatusGroupInterface{
EnumSet<AtmOperationStatus> getMembers();
void addMember(AtmOperationStatus pE);
}
// DEFINING GROUPS
public enum State_StatusGroup implements StatusGroupInterface{
START, STEP, FAIL, FINISH;
private List<AtmOperationStatus> members = new LinkedList<AtmOperationStatus>();
@Override
public EnumSet<AtmOperationStatus> getMembers() {
return EnumSet.copyOf(members);
}
@Override
public void addMember(AtmOperationStatus pE) {
members.add(pE);
}
static { // forcing initiation of dependent enum
try {
Class.forName(AtmOperationStatus.class.getName());
} catch (ClassNotFoundException ex) {
throw new RuntimeException("Class AtmEventType not found", ex);
}
}
}
}
//Some use of upper code:
if (p.getStatus().is(AtmOperationStatus.State_StatusGroup.FINISH)) {
//do something
}else if (p.getStatus().is(AtmOperationStatus.State_StatusGroup.START)) {
//do something
}
Run Code Online (Sandbox Code Playgroud)
添加一些更高级的:
public enum AtmEventType {
USER_DEPOSIT (Status_EventsGroup.WITH_STATUS,
Authorization_EventsGroup.USER_AUTHORIZED,
ChangedMoneyAccountState_EventsGroup.CHANGED,
OperationType_EventsGroup.DEPOSIT,
ApplyTo_EventsGroup.CHANNEL),
SERVICE_DEPOSIT (Status_EventsGroup.WITH_STATUS,
Authorization_EventsGroup.TERMINAL_AUTHORIZATION,
ChangedMoneyAccountState_EventsGroup.CHANGED,
OperationType_EventsGroup.DEPOSIT,
ApplyTo_EventsGroup.CHANNEL),
DEVICE_MALFUNCTION (Status_EventsGroup.WITHOUT_STATUS,
Authorization_EventsGroup.TERMINAL_AUTHORIZATION,
ChangedMoneyAccountState_EventsGroup.DID_NOT_CHANGED,
ApplyTo_EventsGroup.DEVICE),
CONFIGURATION_4_C_CHANGED(Status_EventsGroup.WITHOUT_STATUS,
ApplyTo_EventsGroup.TERMINAL,
ChangedMoneyAccountState_EventsGroup.DID_NOT_CHANGED),
(...)
Run Code Online (Sandbox Code Playgroud)
在上面,如果我们有一些失败(myEvent.is(State_StatusGroup.FAIL))然后迭代前面的事件,我们可以很容易地检查我们是否必须通过以下方式恢复汇款:
if(myEvent2.is(ChangedMoneyAccountState_EventsGroup.CHANGED)) rollBack()..
Run Code Online (Sandbox Code Playgroud)
它可用于:
- 包括有关处理逻辑的明确的元数据,少记住
- 实现一些多继承
- 我们不想使用类结构,例如.用于发送短消息
Jua*_*o G 13
这是我如何找到如何将枚举扩展到其他枚举的方法,这是一种非常直接的方法:
你有一个常见常量的枚举:
public interface ICommonInterface {
String getName();
}
public enum CommonEnum implements ICommonInterface {
P_EDITABLE("editable"),
P_ACTIVE("active"),
P_ID("id");
private final String name;
EnumCriteriaComun(String name) {
name= name;
}
@Override
public String getName() {
return this.name;
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以尝试以这种方式进行手动扩展:
public enum SubEnum implements ICommonInterface {
P_EDITABLE(CommonEnum.P_EDITABLE ),
P_ACTIVE(CommonEnum.P_ACTIVE),
P_ID(CommonEnum.P_ID),
P_NEW_CONSTANT("new_constant");
private final String name;
EnumCriteriaComun(CommonEnum commonEnum) {
name= commonEnum.name;
}
EnumCriteriaComun(String name) {
name= name;
}
@Override
public String getName() {
return this.name;
}
}
Run Code Online (Sandbox Code Playgroud)
当然,每次需要扩展常量时,都必须修改SubEnum文件.
Gui*_*sta 10
如果你错过了它,那么优秀的Joshua Bloch的书" Java Effective,2nd edition "中有一章.
在这里提取.
只是结论:
使用接口来模拟可扩展枚举的一个小缺点是,实现不能从一个枚举类型继承到另一个枚举类型.在我们的操作示例中,存储和检索与操作关联的符号的逻辑在BasicOperation和ExtendedOperation中重复.在这种情况下,它并不重要,因为很少的代码是重复的.如果存在大量共享功能,则可以将其封装在辅助类或静态帮助程序方法中以消除代码重复.
总之,虽然您无法编写可扩展的枚举类型,但您可以通过编写接口来使用实现接口的基本枚举类型来模拟它.这允许客户端编写自己的实现接口的枚举.然后可以在可以使用基本枚举类型的任何地方使用这些枚举,假设API是根据接口编写的.
我倾向于避免使用枚举,因为它们不可扩展.要继续使用OP的示例,如果A在库中而B在您自己的代码中,则如果它是枚举,则不能扩展A. 这就是我有时会替换枚举的方式:
// access like enum: A.a
public class A {
public static final A a = new A();
public static final A b = new A();
public static final A c = new A();
/*
* In case you need to identify your constant
* in different JVMs, you need an id. This is the case if
* your object is transfered between
* different JVM instances (eg. save/load, or network).
* Also, switch statements don't work with
* Objects, but work with int.
*/
public static int maxId=0;
public int id = maxId++;
public int getId() { return id; }
}
public class B extends A {
/*
* good: you can do like
* A x = getYourEnumFromSomeWhere();
* if(x instanceof B) ...;
* to identify which enum x
* is of.
*/
public static final A d = new A();
}
public class C extends A {
/* Good: e.getId() != d.getId()
* Bad: in different JVMs, C and B
* might be initialized in different order,
* resulting in different IDs.
* Workaround: use a fixed int, or hash code.
*/
public static final A e = new A();
public int getId() { return -32489132; };
}
Run Code Online (Sandbox Code Playgroud)
有一些要避免的坑,请参阅代码中的注释.根据您的需要,这是枚举的可靠,可扩展的替代方案.
这是我在静态初始化程序中使用运行时检查来增强枚举继承模式的方法.BaseKind#checkEnumExtender"扩展"枚举的检查以完全相同的方式声明基本枚举的所有值,#name()并#ordinal()保持完全兼容.
仍然有复制粘贴用于声明值,但如果有人在基类中添加或修改了一个值而没有更新扩展值,程序就会快速失败.
相互扩展的不同枚举的常见行为:
public interface Kind {
/**
* Let's say we want some additional member.
*/
String description() ;
/**
* Standard {@code Enum} method.
*/
String name() ;
/**
* Standard {@code Enum} method.
*/
int ordinal() ;
}
Run Code Online (Sandbox Code Playgroud)
基本枚举,带验证方法:
public enum BaseKind implements Kind {
FIRST( "First" ),
SECOND( "Second" ),
;
private final String description ;
public String description() {
return description ;
}
private BaseKind( final String description ) {
this.description = description ;
}
public static void checkEnumExtender(
final Kind[] baseValues,
final Kind[] extendingValues
) {
if( extendingValues.length < baseValues.length ) {
throw new IncorrectExtensionError( "Only " + extendingValues.length + " values against "
+ baseValues.length + " base values" ) ;
}
for( int i = 0 ; i < baseValues.length ; i ++ ) {
final Kind baseValue = baseValues[ i ] ;
final Kind extendingValue = extendingValues[ i ] ;
if( baseValue.ordinal() != extendingValue.ordinal() ) {
throw new IncorrectExtensionError( "Base ordinal " + baseValue.ordinal()
+ " doesn't match with " + extendingValue.ordinal() ) ;
}
if( ! baseValue.name().equals( extendingValue.name() ) ) {
throw new IncorrectExtensionError( "Base name[ " + i + "] " + baseValue.name()
+ " doesn't match with " + extendingValue.name() ) ;
}
if( ! baseValue.description().equals( extendingValue.description() ) ) {
throw new IncorrectExtensionError( "Description[ " + i + "] " + baseValue.description()
+ " doesn't match with " + extendingValue.description() ) ;
}
}
}
public static class IncorrectExtensionError extends Error {
public IncorrectExtensionError( final String s ) {
super( s ) ;
}
}
}
Run Code Online (Sandbox Code Playgroud)
扩展样本:
public enum ExtendingKind implements Kind {
FIRST( BaseKind.FIRST ),
SECOND( BaseKind.SECOND ),
THIRD( "Third" ),
;
private final String description ;
public String description() {
return description ;
}
ExtendingKind( final BaseKind baseKind ) {
this.description = baseKind.description() ;
}
ExtendingKind( final String description ) {
this.description = description ;
}
}
Run Code Online (Sandbox Code Playgroud)
基于@Tom Hawtin -我们添加了切换支持,
interface Day<T> {
...
T valueOf();
}
public enum Weekday implements Day<Weekday> {
MON, TUE, WED, THU, FRI;
Weekday valueOf(){
return valueOf(name());
}
}
public enum WeekendDay implements Day<WeekendDay> {
SAT, SUN;
WeekendDay valueOf(){
return valueOf(name());
}
}
Day<Weekday> wds = Weekday.MON;
Day<WeekendDay> wends = WeekendDay.SUN;
switch(wds.valueOf()){
case MON:
case TUE:
case WED:
case THU:
case FRI:
}
switch(wends.valueOf()){
case SAT:
case SUN:
}
Run Code Online (Sandbox Code Playgroud)