fastjson-EnumDeserializer类及源码分析
本文以fastjson-1.2.83版本中EnumDeserializer类的源码来解释其工作原理和实现细节。 类结构概览EnumDeserializer是 FastJSON 用于将 JSON 反序列化为枚举类型的核心类。它支持通过枚举名称(Enum.name())反序列化通过枚举序号(Enum.ordinal())反序列化通过JSONField注解指定的别名反序列化大小写不敏感匹配高性能的哈希查找 核心成员变量protected final Class? enumClass; // 枚举类 protected final Enum[] enums; // 按哈希值排序的枚举数组 protected final Enum[] ordinalEnums; // 按序号排序的枚举数组 protected long[] enumNameHashCodes; // 枚举名称哈希值数组(已排序) 构造函数初始化流程构造函数是整个类的核心它预先计算了所有枚举常量的哈希值1. 获取所有枚举常量ordinalEnums (Enum[]) enumClass.getEnumConstants();2. 为每个枚举计算哈希值MapLong, Enum enumMap new HashMapLong, Enum(); for (int i 0; i ordinalEnums.length; i) { Enum e ordinalEnums[i]; String name e.name(); // 检查 JSONField 注解 JSONField jsonField null; try { Field field enumClass.getField(name); jsonField TypeUtils.getAnnotation(field, JSONField.class); if (jsonField ! null) { String jsonFieldName jsonField.name(); if (jsonFieldName ! null jsonFieldName.length() 0) { name jsonFieldName; // 使用注解指定的名称 } } } catch (Exception ex) { // skip } // 计算原始名称的哈希 long hash fnv1a_64_magic_hashcode; for (int j 0; j name.length(); j) { char ch name.charAt(j); hash ^ ch; hash * fnv1a_64_magic_prime; } enumMap.put(hash, e); // 计算小写名称的哈希(用于大小写不敏感匹配) long hash_lower fnv1a_64_magic_hashcode; for (int j 0; j name.length(); j) { char ch name.charAt(j); char lowerCh (ch A ch Z) ? (char)(ch 32) : ch; hash_lower ^ lowerCh; hash_lower * fnv1a_64_magic_prime; } if (hash ! hash_lower) { enumMap.put(hash_lower, e); } // 处理 JSONField.alternateNames() 备选名称 if (jsonField ! null) { for (String alterName : jsonField.alternateNames()) { long alterNameHash fnv1a_64_magic_hashcode; for (int j 0; j alterName.length(); j) { char ch alterName.charAt(j); alterNameHash ^ ch; alterNameHash * fnv1a_64_magic_prime; } if (alterNameHash ! hash alterNameHash ! hash_lower) { enumMap.put(alterNameHash, e); } } } }3. 存储和排序// 提取所有哈希值并排序 this.enumNameHashCodes new long[enumMap.size()]; int i 0; for (Long h : enumMap.keySet()) { enumNameHashCodes[i] h; } Arrays.sort(this.enumNameHashCodes); // 按排序后的哈希值顺序存储枚举 this.enums new Enum[enumNameHashCodes.length]; for (int j 0; j this.enumNameHashCodes.length; j) { long hash enumNameHashCodes[j]; Enum e enumMap.get(hash); this.enums[j] e; } 反序列化流程deserialze方法是实际执行反序列化的入口1. 处理整数类型(枚举序号)if (token JSONToken.LITERAL_INT) { int intValue lexer.intValue(); lexer.nextToken(JSONToken.COMMA); if (intValue 0 || intValue ordinalEnums.length) { throw new JSONException(parse enum enumClass.getName() error, value : intValue); } return (T) ordinalEnums[intValue]; }2. 处理字符串类型(主要场景)else if (token JSONToken.LITERAL_STRING) { String name lexer.stringVal(); lexer.nextToken(JSONToken.COMMA); if (name.length() 0) { return (T) null; // 空字符串返回 null } // 计算输入字符串的哈希 long hash fnv1a_64_magic_hashcode; long hash_lower fnv1a_64_magic_hashcode; for (int j 0; j name.length(); j) { char ch name.charAt(j); hash ^ ch; hash_lower ^ ((ch A ch Z) ? (ch 32) : ch); hash * fnv1a_64_magic_prime; hash_lower * fnv1a_64_magic_prime; } // 首先尝试原始哈希 Enum e getEnumByHashCode(hash); // 如果没找到尝试小写哈希 if (e null hash_lower ! hash) { e getEnumByHashCode(hash_lower); } if (e null lexer.isEnabled(Feature.ErrorOnEnumNotMatch)) { throw new JSONException(not match enum value, enumClass.getName() : name); } return (T) e; }3. 哈希查找方法public Enum getEnumByHashCode(long hashCode) { if (enums null) { return null; } // 二分查找已排序的哈希数组 int enumIndex Arrays.binarySearch(this.enumNameHashCodes, hashCode); if (enumIndex 0) { return null; // 没找到 } return enums[enumIndex]; } 关键设计决策1. 为什么使用 FNV-1a 哈希算法高性能FNV-1a 计算速度快适合频繁调用低碰撞在枚举名称这种短字符串上碰撞概率低确定性相同的输入总是产生相同的哈希值2. 为什么使用二分查找枚举常量数量通常很少(几十个)排序后的数组查找时间复杂度 O(log n)比 HashMap 有更好的局部性可能更快3. 为什么计算两种哈希(大小写敏感/不敏感)// 原始大小写 hash ^ ch; hash * fnv1a_64_magic_prime; // 转换为小写(如果是大写字母) hash_lower ^ ((ch A ch Z) ? (ch 32) : ch); hash_lower * fnv1a_64_magic_prime;这样实现了大小写不敏感的枚举匹配用户输入 YCX 或 ycx 都能匹配到YCX枚举。 性能优化策略1. 预先计算在构造函数中计算所有可能的哈希值避免了每次反序列化时的重复计算2. 内存布局优化使用两个并行数组enumNameHashCodes[]和enums[]保持相同索引便于二分查找后快速获取枚举3. 哈希复用// 初始化哈希值 long hash fnv1a_64_magic_hashcode; // 迭代计算 for (int j 0; j name.length(); j) { char ch name.charAt(j); hash ^ ch; // XOR hash * fnv1a_64_magic_prime; // 乘以质数 } 使用示例枚举定义public enum Status { JSONField(name success, alternateNames {ok, good}) SUCCESS, JSONField(name failed, alternateNames {error, bad}) FAILED, PENDING }可匹配的输入通过序号0→SUCCESS通过名称SUCCESS→SUCCESS通过注解名称success→SUCCESS通过备选名称ok或good→SUCCESS大小写不敏感Success或success→SUCCESS⚠️ 异常处理无效序号intValue 0 || intValue ordinalEnums.length→ 抛出异常无效字符串哈希查找返回 null → 可能返回 null 或抛出异常(取决于Feature.ErrorOnEnumNotMatch)空字符串返回 nullnull 值返回 null 设计模式应用策略模式根据输入类型(整数/字符串)选择不同的反序列化策略字符串又分为大小写敏感/不敏感两种策略缓存模式预计算并缓存所有枚举的哈希值避免运行时重复计算工厂模式通过getEnumByHashCode方法生产枚举实例 与其他反序列化器的对比特性FastJSON EnumDeserializerJacksonGson哈希算法FNV-1a 64位无无查找方式二分查找线性查找/HashMap线性查找大小写不敏感支持配置支持配置支持注解支持JSONFieldJsonCreatorSerializedName性能高中中 性能分析时间复杂度构造函数O(n * m)其中 n 是枚举数量m 是名称平均长度哈希计算O(m)每次反序列化哈希查找O(log k)其中 k 是哈希值数量(包括备选名称)空间复杂度存储所有哈希值和枚举引用O(k)通常 k 接近 n(枚举数量) 总结EnumDeserializer的设计体现了 FastJSON 在性能优化上的追求预计算策略在初始化时计算所有可能的哈希值高效的哈希算法FNV-1a 适合短字符串计算快速优化查找排序数组 二分查找比 HashMap 更快灵活匹配支持大小写不敏感、注解别名、备选名称健壮性完善的异常处理和边界条件检查这个实现平衡了性能、功能和内存使用是 FastJSON 高效反序列化的一个典型代表。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2422588.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!