基于Java中的某个常量动态实例化类
我正在制作一个多人游戏,它大量使用可序列化的基于Java中的某个常量动态实例化类,java,reflection,instantiation,Java,Reflection,Instantiation,我正在制作一个多人游戏,它大量使用可序列化的事件类通过网络发送消息。我希望能够基于常量重构事件的适当子类 到目前为止,我选择了以下解决方案: public class EventFactory { public static Event getEvent(int eventId, ByteBuffer buf) { switch (eventId){ case Event.ID_A: return EventA.deseriali
事件
类通过网络发送消息。我希望能够基于常量重构事件
的适当子类
到目前为止,我选择了以下解决方案:
public class EventFactory {
public static Event getEvent(int eventId, ByteBuffer buf) {
switch (eventId){
case Event.ID_A:
return EventA.deserialise(buf);
case Event.ID_B:
return EventB.deserialise(buf);
case Event.ID_C:
return EventC.deserialise(buf);
default:
// Unknown Event ID
return null;
}
}
}
然而,这让我觉得非常冗长,每次创建新的事件
类型时都要添加一个新的“case”语句
我知道还有两种方法可以做到这一点,但这两种方法似乎都不好*:
*注意:在这种情况下,更好意味着更简单/更干净,但不会对速度造成太大影响。您可以使用
HashMap
为eventID获取正确的事件。添加或删除事件将很容易,而且随着代码的增长,与switch case解决方案相比,这很容易维护,而且速度方面也应该比switch case解决方案快
static
{
HashMap<Integer,Event> eventHandlerMap = new HashMap<>();
eventHandlerMap.put(eventId_A, new EventHandlerA());
eventHandlerMap.put(eventId_B, new EventHandlerB());
............
}
如果你不怕反思,你可以使用:
private static final Map<Integer, Method> EVENTID_METHOD_MAP = new LinkedHashMap<>();
static {
try {
for (Field field : Event.class.getFields())
if (field.getName().startsWith("ID_")) {
String classSuffix = field.getName().substring(3);
Class<?> cls = Class.forName("Event" + classSuffix);
Method method = cls.getMethod("deserialize", ByteBuffer.class);
EVENTID_METHOD_MAP.put(field.getInt(null), method);
}
} catch (IllegalAccessException|ClassNotFoundException|NoSuchMethodException e) {
throw new ExceptionInInitializerError(e);
}
}
public static Event getEvent(int eventId, ByteBuffer buf)
throws InvocationTargetException, IllegalAccessException {
return (Event) EVENTID_METHOD_MAP.get(eventId).invoke(null, buf);
}
private static final Map EVENTID_METHOD_Map=new LinkedHashMap();
静止的{
试一试{
for(字段:Event.class.getFields())
if(field.getName().startsWith(“ID_”)){
字符串classSuffix=field.getName().substring(3);
Class cls=Class.forName(“事件”+类后缀);
Method=cls.getMethod(“反序列化”,ByteBuffer.class);
EVENTID\u METHOD\u MAP.put(field.getInt(null),METHOD);
}
}捕获(IllegalAccessException | ClassNotFoundException | NoSuchMethodException){
抛出新异常初始化错误(e);
}
}
公共静态事件getEvent(int-eventId,ByteBuffer-buf)
抛出InvocationTargetException,IllegalAccessException{
return(Event)EVENTID\u METHOD\u MAP.get(EVENTID.invoke)(null,buf);
}
此解决方案要求int ID\u N
始终映射到class event N
,其中N
可以是方法java.lang.Character.isJavaIdentifierPart(c)
的所有字符返回true
的任何字符串。另外,class EventN
必须使用一个返回事件的ByteBuffer
参数定义一个名为反序列化
的静态方法
在尝试获取字段值之前,您还可以检查字段
是否是静态的。我现在忘了怎么做。有多少种活动?不使用一些标准wire格式(如JSON或XML)有什么特别的原因吗?为什么不实现事件,然后直接写入和读取事件对象?目前大约有20种事件类型,但我将继续添加更多。目前,我正在使用ByteBuffers手动序列化/反序列化事件,正如您在这里看到的,因为它速度快且非常小;我想发送尽可能少的字节。我不能使用Serializable,因为我是以数据包而不是流的形式发送数据的。但我对JSON很好奇——这与发送的速度和数据量相比如何?我喜欢使用映射的想法,但这依赖于提前创建每个事件的实例(我使用的“EventHandler”应该是“Event”),看起来就像占位符一样,并且依赖于空构造函数,使其与我建议的第一个备选方案类似。您可以使用eventid到类名的映射,然后通过反射创建类。但人们普遍认为反射速度很慢。顺便说一句,我正试图推动使用hashmap的想法。我对此持开放态度。这看起来不太吓人,但我不知道它的优点是否大于复杂性。这与switch语句的速度比较如何?
private static final Map<Integer, Method> EVENTID_METHOD_MAP = new LinkedHashMap<>();
static {
try {
for (Field field : Event.class.getFields())
if (field.getName().startsWith("ID_")) {
String classSuffix = field.getName().substring(3);
Class<?> cls = Class.forName("Event" + classSuffix);
Method method = cls.getMethod("deserialize", ByteBuffer.class);
EVENTID_METHOD_MAP.put(field.getInt(null), method);
}
} catch (IllegalAccessException|ClassNotFoundException|NoSuchMethodException e) {
throw new ExceptionInInitializerError(e);
}
}
public static Event getEvent(int eventId, ByteBuffer buf)
throws InvocationTargetException, IllegalAccessException {
return (Event) EVENTID_METHOD_MAP.get(eventId).invoke(null, buf);
}