Java 如何创建类似于“的常量分组”;“动态枚举”;在爪哇?
在Java中声明来自多个库的常量分组的选项有哪些 例如,我有一个网络消息协议。该协议有一些标准消息,并允许创建自定义消息。每封邮件都有一个唯一的ID号。我真的很想在我的应用程序中将所有这些唯一ID合并到一个枚举中。类似于Java 如何创建类似于“的常量分组”;“动态枚举”;在爪哇?,java,reflection,enums,Java,Reflection,Enums,在Java中声明来自多个库的常量分组的选项有哪些 例如,我有一个网络消息协议。该协议有一些标准消息,并允许创建自定义消息。每封邮件都有一个唯一的ID号。我真的很想在我的应用程序中将所有这些唯一ID合并到一个枚举中。类似于 public enum MessageType { //Standard messages in one library FooMsg(1), BarMsg(2), //Custom messages in another library
public enum MessageType
{
//Standard messages in one library
FooMsg(1),
BarMsg(2),
//Custom messages in another library
MyCustomMessage(100),
MyOthercustomMessage(101);
private long msgNumber;
public long getMessageNumber(long msgNumber) { return msgNumber;}
public static MessageType fromMessageNumber(long messageNumber)
{
//Reverse lookup code here...
}
//Few more utilities that don't matter for this question
private MessageType(long msgNumber)
{
this.msgNumber = msgNumber;
}
}
然后,我可以创建消息类型的通用方法
public void doStuff(MessageType msgType, MyMessageObject data)
{
switch(msgType)
{
case FooMsg: //Do stuff
break;
//Other stuff
}
}
但是,枚举要求我在编译时知道所有消息类型,但消息分布在多个库中。其中一些库是可选加载的,因此如果它们没有加载,我不想将它们包括在枚举中
有没有一种方法可以在运行时定义一个类似于枚举的“常量集合” 您不能使用
枚举
,但是有没有任何原因表明简单的映射
不能满足您的需要?或者,因为您有一些其他实用程序方法,所以是一个由映射支持的类?您可以只为已加载的库添加那些消息,如果在应用程序的加载阶段和运行阶段之间有明确的划分,您甚至可以使用构建器模式并将映射冻结为不可变映射,这样一旦应用程序运行,就无法对消息进行进一步的更改
(这可以通过Collections.unmodifiableMap()
或Guava中的一种不可变映射类型来完成。)
我不完全清楚的一件事是,是否可以保证不同库使用的消息不会发生冲突。这可能是一个问题
例如:
import java.util.HashMap;
import java.util.Map;
public class MessageType {
private final static Map<Long, MessageType> messageTypes = new HashMap<>();
// it isn't clear how the libraries would provide information on
// the message types they support; suppose that each library has a
// MessageInfo that implements Map<Long, String> with all its types:
public static void loadLibrary(MessageInfo messageInfo) {
// populate the map with each message type it supports
for (Map.Entry<Long, String> entry : messageInfo.entrySet()) {
MessageType messageType =
new MessageType(entry.getKey(), entry.getValue());
messageTypes.put(entry.getKey(), messageType);
}
}
// A MessageType has a name and a number
private final long number;
private final String name;
private MessageType(long number, String name) {
this.number = number;
this.name = name;
}
public long getMessageNumber() {
return number;
}
public String getMessageName() {
return name;
}
public static MessageType fromMessageNumber(long number) {
if (!messageTypes.containsKey(number)) {
throw new IllegalArgumentException("Unknown message: " + number);
}
return messageTypes.get(number);
}
}
或者您希望消息以何种方式显示以进行调试。请注意,由于每个消息类型只创建一个MessageType对象,因此将它们与
=
进行比较应该是安全的,尽管您没有从Java枚举
类型获得强大的保护。(仍然可以通过反射创建重复的MessageType
对象,或者,如果将它们设置为Serializable
,则可以通过序列化和反序列化来创建它们。)(您可能知道,这种方法只为每个不同的值创建一个实例,称为Flyweight设计模式。)也许可以使用某种类型的地图?Key=name,value=constant value?我不担心备份数据结构。是的,我保证不会在名字或消息ID号上发生冲突。我的目标是保留保持编译保护的能力,这样我就可以执行“void doStuff(MessageType msgType)”而不是“void doStuff(int msgType)”之类的操作。好吧,您可以使用映射支持的值类来实现这一点。value类将是您用作参数的类型,映射将通过其valueOf
方法使用,该方法将数字解析为value类的实例。我给你举个例子来说明我的意思。不需要举个例子,我知道你的意思。谢谢
@Override
public String toString() {
return "message:" + name + "<" + number + ">";
}