繁体   English   中英

Java Switch Statememt - 使用抽象类的公共枚举所需的常量表达式

[英]Java Switch Statememt - Constant Expression Required Using Public Enum from Abstract Class

我编写的代码使用了我在webockets上设计的协议,用于创建Android应用程序的项目。

我有一个使用Autobahn库weCommunicationManager处理websocket通信的类。

我有许多变量和标签,用于处理从我的服务器通过websockets到应用程序的收到的JSON消息。

为了使事物分离并在一个地方,我创建了一个抽象类ExICSProtocol ,它将标记保存为公共静态成员,以便可以在必要时引用它们。

在收到的消息中是消息类型的整数值,我需要能够打开它来定义如何处理该特定的接收消息。

为此,我在ExICSProtocol类中实现了一个公共枚举,如下所示,

public static enum MESSAGE_TYPE{
    PROTOCOL_HANDSHAKE(0),
    USER_CONNECTED(1),
    USER_DISCONNECTED(2),
    SYSTEM_STATE(3),
    CHANGE_ROOM(4),
    EXAM_START(5),
    EXAM_PAUSE(6),
    EXAM_STOP(7),
    EXAM_XTIME(8),
    SEND_MESSAGE(9),
    SUCCESS(69),
    FAILURE(-1),
    TERMINATE_CONNECTION(-2);

    private int code;

    MESSAGE_TYPE(int code){
        this.code = code;
    }

    public int getCode(){
        return this.code;
    }
}

我试图在wsCommunicationManager代码中使用它,如下所示,

private static void handleMessage(String message){
    try{
        JSONObject messageObject = new JSONObject(message);
        JSONObject messageHeader = messageObject.getJSONObject(ExICSProtocol.TAG_HEADER);
        JSONObject messagePayload = messageObject.getJSONObject(ExICSProtocol.TAG_PAYLOAD);

        int messageType = messageHeader.getInt(ExICSProtocol.TAG_MESSAGE_TYPE);


        switch(messageType){
            case ExICSProtocol.MESSAGE_TYPE.PROTOCOL_HANDSHAKE.getCode():
                //DO SOMETHING HERE
                break;

            ...

            default:
                throw new ExICSException("Unknown Message Type Received");
                break;
        }
    }catch (JSONException e){
        Log.e(TAG, "Failed to parse received message " + message, e);
    }catch (ExICSException e){
        Log.e(TAG, "Excaption Handling Message Occurred", e);
    }
}

我在ExICSProtocol.MESSAGE_TYPE.PROTOCOL_HANDSHAKE.getCode():下标记错误ExICSProtocol.MESSAGE_TYPE.PROTOCOL_HANDSHAKE.getCode():说需要一个常量表达式。 然而,这应该是不变的?

我尝试了一些不同的东西,将枚举移动到正在使用它的类中; 同样的问题。 使enum公共持有私有int,以便可以直接访问; 同样的问题。

我已经看到很多在switch语句中使用枚举的例子,但非常像我。 我在声明或初始化中遗漏了什么,或者我正在尝试做一些无效的事情。

我知道有相对简单的解决方法,例如将数字类型代码定义为公共静态最终整数,但我希望在可能的情况下将类型代码保存在MESSAGE_TYPE下。

正如您所见,调用方法不算作常量表达式

更清洁的解决方案(IMO)是在枚举中使用静态方法:

// Enum renamed to comply with conventions
public enum MessageType {

    private static final Map<Integer, MessageType> codeMap = new HashMap<>();
    // Can't do this in the constructor, as the codeMap variable won't have been
    // initialized
    static {
        for (MessageType type : MessageType.values()) {
            codeMap.put(type.getCode(), type);
        }
    }

    public static MessageType fromCode(int code) {
        return codeMap.get(code);
    }
}

然后在你的wsCommunicationManager代码中:

int messageCode = messageHeader.getInt(ExICSProtocol.TAG_MESSAGE_TYPE);
MessageType messageType = MessageType.fromCode(messageCode);
if (messageType == null) {
    // Unknown message code. Do whatever...
}

switch(messageType) {
    case MessageType.PROTOCOL_HANDSHAKE:
        ...
}

基本上,尽早从“面向整数”转向“面向对象”的世界。 这有点像早期解析基于数字和日期的用户输入而不是传递字符串 - 在你的情况下,代理表示是一个int

你可以在你的MESSAGE_TYPE枚举中添加一个getFromCode(int code)静态方法,如下所示:

public static MESSAGE_TYPE getFromCode(int code) {
    for(MESSAGE_TYPE mt : MESSAGE_TYPE.values())
        if(mt.code == code)
            return mt;

    throw new IllegalArgumentException();
}

然后在你的handleMessage中:

MESSAGE_TYPE messageType = MESSAGE_TYPE.getByCode(messageHeader.getInt(ExICSProtocol.TAG_MESSAGE_TYPE));


switch(messageType){
    case PROTOCOL_HANDSHAKE:
        //handle handshake...

除非你的枚举做了一些你没有告诉我们的内容,否则这不是一个很好用的枚举。 对于这种特殊情况,静态类可能更有用(和可读):

public class MessageType {
    public static final int PROTOCOL_HANDSHAKE = 0;
    public static final int USER_CONNECTED = 1;
    ....
}

然后在你的switch语句中,你可以使用

switch( messageType ) {
    case MessageType.PROTOCOL_HANDSHAKE:
        ....
        break;

这基本上是Android在其他领域(例如ContentResolver,Database等)提倡的合同类模式。

您正在使用在运行时评估的函数。 将相同的值放在int中也不起作用,因为它也在运行时进行评估。 将值放在private final static int会起作用,因为它是在编译时计算的,因此是一个常量表达式。

尝试类似的东西

private final static int PROTOCOL_HANDSHAKE = 0;

并在您的switch语句中执行此操作

case PROTOCOL_HANDSHAKE:
//Do something

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM