![](/img/trans.png)
[英]Java enum : Refactoring switch statements 'constant expression required' compile error?
[英]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.