Java中的嵌套枚举?

Java中的嵌套枚举?,java,enums,Java,Enums,我想为web应用程序中提供的各种ajax服务定义一些枚举,如: Enum Service { REGISTER, LOGIN, NEWS, FAQ } 但是,这些枚举中的每一个都有特定的状态,如失败、已加载等。因此,我希望能够使用REGISTER.Loaded、LOGIN.Loaded等在我的事件总线上触发事件。但是,每个状态枚举必须是唯一的。例如,Register.LOADED必须与FAQ.LOADED不同,依此类推 编辑:此外,我必须能够在同一个hashma

我想为web应用程序中提供的各种ajax服务定义一些枚举,如:

Enum Service
{
    REGISTER,
    LOGIN,
    NEWS,
    FAQ
}
但是,这些枚举中的每一个都有特定的状态,如失败、已加载等。因此,我希望能够使用
REGISTER.Loaded
LOGIN.Loaded
等在我的事件总线上触发事件。但是,每个状态枚举必须是唯一的。例如,
Register.LOADED
必须与
FAQ.LOADED
不同,依此类推

编辑:此外,我必须能够在同一个hashmap中存储所有状态,例如
Register.LOADED
Login.LOADED
必须存储在同一个hashmap中。父服务枚举,即
LOGIN、REGISTER
等,也必须可以存储在相同的hashmap中

实现这一点的最佳方法是什么?

只需将“外部”枚举转换为一个类,并用“内部”枚举填充它:


或者将其作为
public static
嵌套到handler类中,如果是这样的话。

在OP的一些注释之后,我更新了我的代码。用法语法变得难看,在
switch
块中可能无法很好地工作,但我相信这实现了OP的目标:

import java.util.*;

public class HelloWorld
{
    public static void main(String []args)
    {
        // Different services are not equal
        System.out.println(Service.REGISTER + "==" + Service.LOGIN + " :: " + Service.REGISTER.equals(Service.LOGIN));
        // Same service is equal
        System.out.println(Service.REGISTER + "==" + Service.REGISTER + " :: " + Service.REGISTER.equals(Service.REGISTER));
        // Even after changing the state
        Service tmp = Service.REGISTER;
        Service.REGISTER.setState(Service.ServiceState.State.FAILED);
        System.out.println(Service.REGISTER + "==" + tmp + " :: " + Service.REGISTER.equals(tmp));
        
        Service.REGISTER.setState(Service.ServiceState.State.LOADED);
        
        // Different service, same state is not equal
        System.out.println(Service.REGISTER + "." + Service.REGISTER.state + "==" + Service.LOGIN + "." + Service.LOGIN.state + " :: " + Service.REGISTER.state.equals(Service.LOGIN.state));
        
        // Same service, same state is equal (even when changing state around)
        Service.ServiceState.State temp = Service.REGISTER.getState();
        Service.REGISTER.setState(Service.ServiceState.State.LOADED);
        System.out.println(Service.REGISTER + "." + Service.REGISTER.state + "==" + tmp + "." + temp + " :: " + temp.equals(Service.REGISTER.getState()));
        
        // Same service, different state is not equal
        Service.REGISTER.setState(Service.ServiceState.State.FAILED);
        System.out.println(Service.REGISTER + "." + Service.REGISTER.state + "==" + tmp + "." + temp + " :: " + temp.equals(Service.REGISTER.getState()));
        
        // Both service and state can be used as map keys
        Map<Service, String> map = new HashMap<Service, String>();
        Map<Service.ServiceState.State, String> map2 = new HashMap<Service.ServiceState.State, String>();
    }
}

enum Service
{
    REGISTER(),
    LOGIN(),
    NEWS(),
    FAQ();

    public ServiceState state;

    Service()
    {
        this.state = new ServiceState();
    }
    
    public void setState(ServiceState.State s)
    {
        state.state = s;
    }
    
    public ServiceState.State getState() { return state.state; }

    public static class ServiceState
    {
        public enum State
        {
            LOADED,
            FAILED
        }
        
        public State state = State.LOADED;
        
        public ServiceState(){}
        
        public String toString() { return state.toString(); }
        
        public int hashCode()
        {
            return state.hashCode();
        }
        
        public boolean equals(Object obj)
        {
            return state.equals(obj);
        }
    }
}

原始答复: 使用您想要的语法不太可能,但Java枚举基本上只是另一个名称的类。(事实上,一旦编译,它们就是扩展
java.lang.Enum
的类)

输出:

REGISTER==LOGIN :: false
REGISTER==REGISTER :: true
REGISTER==REGISTER :: true
REGISTER.LOADED==LOGIN.LOADED :: false
REGISTER.LOADED==REGISTER.LOADED :: true
REGISTER.FAILED==REGISTER.LOADED :: false
寄存器已加载


另一个选项是创建几个枚举。其中一个列出了服务:

enum Service {
    REGISTER, LOGIN, NEWS, FAQ;
}
下一个列表列出了所有状态:

enum State { LOADED, FAILED }
现在,您可以拥有一个类,该类在构造函数中接受服务和状态,并重写equals()和hashCode()以区分它们:

new ServiceState(REGISTER, LOADED)
或者创建另一个列出有效组合的枚举:

enum ServiceState {
    REGISTER_LOADED(REGISTER, LOADED), ...
}
但是这个枚举将非常大,要键入的数量将很快变得非常大(如果将一个值添加到其他枚举,则需要将N个枚举添加到
ServiceState

一个解决方案是

enum Service {
  REGISTER, LOGIN, NEWS, FAQ;

  public final class State {
    final ServiceState state;
    private State(ServiceState st) {
      state=st;
    }
    @Override
    public String toString() {
      return Service.this+"."+state;
    }
  }
  final EnumMap<ServiceState, State> map=new EnumMap<>(ServiceState.class);
  Service() {
    for(ServiceState s:ServiceState.values()) map.put(s,new State(s));
  }
  public State state(ServiceState s) { return map.get(s); }
}
enum ServiceState { LOADED, FAILED }

另一种选择是:

enum Service {
  REGISTER, LOGIN, NEWS, FAQ;

  public final class State {
    final ServiceState state;
    private State(ServiceState st) {
      state=st;
    }
    @Override
    public String toString() {
      return Service.this+"."+state;
    }
  }
  public final State LOADED=new State(ServiceState.LOADED);
  public final State FAILED=new State(ServiceState.FAILED);
}
enum ServiceState { LOADED, FAILED }
这需要在更改可能的
ServiceState
s时手动更新字段,但在使用这些字段时,它的语法更具吸引力:

Service.State ss=Service.LOGIN.LOADED;
您还可以将
服务状态
枚举
替换为
字符串
s
“已加载”
“失败”
等。因此,您不需要保持
枚举
服务
中的字段同步



请注意,这两种解决方案都依赖于这样一个事实,即
Service.State
的构造函数是
private
,因此只有在
enum
中创建的规范实例才存在。因此,您不需要覆盖
equals
hashCode
。如果您决定将类
序列化
,还应添加一个
readResolve
方法,该方法返回反序列化实例的规范表示。

虽然有一些很好的答案,可能适用于其他情况,我决定采用以下解决方案,因为它最适合我的情况:

public enum Service
{
    LOGIN,
    REGISTER,
    NEWS;

    private final long LOADED, FAILED;

    private RequestType()
    {
        LOADED  = strToAscii(this.name() + "_LOADED"  );
        FAILED = strToAscii(this.name() + "_FAILED"  );            
    }

    public static long strToAscii(String str)
    {
       StringBuilder sb = new StringBuilder();

       for (char c: str.toCharArray() )
       {
           sb.append( (int) c );
       }

      return Long.parseLong( sb.toString() );
   }
}

这对我来说效果很好,因为我现在可以按我最初想要的那样执行
RequestType.LOGIN.LOADED==RequestType.REGISTER.LOADED
。如果有人有任何改进建议,请随时提出。

这只有一个问题,我无法将
Login.LOADED
Register.LOADED
进行比较。我需要所有枚举的状态都是相同的类型,这样我就可以将它们都存储在同一个hashmap中。@ClickUpvote:你错了。使用这种设计,所有枚举的状态都是相同的。@Aarondigula如果我想比较
Register.LOADED
Login.LOADED
,我会得到不同的值吗?@ClickUpvote,试试看
System.out.println(Service.REGISTER.state==Service.LOGIN.state)
生成
true
(假设您没有更改任何一个上的
state
的值)。@BrianS那么这并不能解决我的问题,我需要每个服务类型的状态都是唯一的,否则,
的所有侦听器都要注册.LOADED,Login.LOADED,常见问题解答。任何服务的状态设置为
LOADED
时,都会触发LOADED
等。如果这样做,我是否能够将
注册、登录
等存储在同一哈希映射中?在同一个hashmap中存储
Register.LOADED
Login.LOADED
怎么样?如果没有其他解决方案,
ServiceState
类而不是枚举,我宁愿在每个实例化为
this.name()+“_LOADED”
的服务上都有公共字符串?
enum Service {
  REGISTER, LOGIN, NEWS, FAQ;

  public final class State {
    final ServiceState state;
    private State(ServiceState st) {
      state=st;
    }
    @Override
    public String toString() {
      return Service.this+"."+state;
    }
  }
  public final State LOADED=new State(ServiceState.LOADED);
  public final State FAILED=new State(ServiceState.FAILED);
}
enum ServiceState { LOADED, FAILED }
Service.State ss=Service.LOGIN.LOADED;
public enum Service
{
    LOGIN,
    REGISTER,
    NEWS;

    private final long LOADED, FAILED;

    private RequestType()
    {
        LOADED  = strToAscii(this.name() + "_LOADED"  );
        FAILED = strToAscii(this.name() + "_FAILED"  );            
    }

    public static long strToAscii(String str)
    {
       StringBuilder sb = new StringBuilder();

       for (char c: str.toCharArray() )
       {
           sb.append( (int) c );
       }

      return Long.parseLong( sb.toString() );
   }
}