如何对包含多属性的Java Enum进行编码与解码以实现跨端同步
枚举编码与解码实现方案
前置修正:原枚举类语法问题修复
原枚举存在变量未声明类型、引号为中文的语法错误,先修正基础代码:
public enum LettersEnum{ A(0, "Letter A"), B(1, "Letter B"), C(2, "Letter C"); private final int id; private final String letter; LettersEnum(int id, String letter) { this.id = id; this.letter = letter; } public int getId() { return this.id; } public String getLetter() { return this.letter; } }
可选实现方案
方案1:基于枚举名称编码(实现最简单)
- 编码逻辑:直接调用枚举实例的
name()方法,得到对应常量名称的字符串(如A/B/C) - 解码逻辑:调用JDK自带的
LettersEnum.valueOf(String name)方法,传入编码得到的字符串即可还原枚举实例 - 使用示例:
// 编码 LettersEnum enumVal = LettersEnum.B; String encoded = enumVal.name(); // 得到字符串"B" // 解码 LettersEnum decoded; try { decoded = LettersEnum.valueOf(encoded); } catch (IllegalArgumentException e) { // 非法值返回默认值 decoded = LettersEnum.A; }
方案2:基于自定义ID编码(更适合游戏场景,省带宽)
游戏传输优先选择更小的报文体积,int类型比字符串占用空间小、编解码效率更高,推荐使用该方案。需要在枚举类中新增ID映射缓存与解码方法,修改后的完整枚举代码如下:
import java.util.Arrays; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; public enum LettersEnum{ A(0, "Letter A"), B(1, "Letter B"), C(2, "Letter C"); private final int id; private final String letter; // ID与枚举实例的映射缓存,用于快速解码 private static final Map<Integer, LettersEnum> ID_MAPPING = Arrays.stream(values()) .collect(Collectors.toMap(LettersEnum::getId, Function.identity())); // 解码失败返回的默认值 private static final LettersEnum DEFAULT = A; LettersEnum(int id, String letter) { this.id = id; this.letter = letter; } public int getId() { return this.id; } public String getLetter() { return this.letter; } // 解码方法:传入ID得到枚举实例 public static LettersEnum getById(int id) { return ID_MAPPING.getOrDefault(id, DEFAULT); } }
- 编码逻辑:调用枚举实例的
getId()方法,得到int类型的编码值 - 解码逻辑:调用静态方法
LettersEnum.getById(int id),传入收到的ID即可还原 - 使用示例:
// 客户端编码 LettersEnum current = LettersEnum.B; int encoded = current.getId(); // 得到int值1,放入报文传输 // 服务端解码 int receivedId = 1; // 从报文中解析得到 LettersEnum decoded = LettersEnum.getById(receivedId); // 得到LettersEnum.B
注意事项
- 不要使用枚举自带的
ordinal()方法作为编码值,后续新增枚举常量时ordinal值会自动变化,会导致旧版本客户端/服务端解析异常 - 解码逻辑必须增加容错处理,收到非法编码值时返回默认值,避免异常导致程序崩溃
- 如果坚持要使用
toString()实现,可重写toString()方法返回ID的字符串形式,解码时先将字符串转成int再调用getById方法即可。
内容的提问来源于stack exchange,提问作者LK1905
相关产品推荐
相关产品推荐

