SerializerFeature在fastjson中扮演着一个极其重要的角色,通过它我们可以定制序列化,那么它本身是如何实现的呢?如此的设计有有何出彩之处呢?本篇文章将会重点围绕这些要素进行分析。
1. 认识SerializerFeature 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 public enum SerializerFeature { QuoteFieldNames, UseSingleQuotes, WriteMapNullValue, WriteEnumUsingToString, UseISO8601DateFormat, WriteNullListAsEmpty, WriteNullStringAsEmpty, WriteNullNumberAsZero, WriteNullBooleanAsFalse, SkipTransientField, SortField, @Deprecated WriteTabAsSpecial, PrettyFormat, WriteClassName, DisableCircularReferenceDetect, WriteSlashAsSpecial, BrowserCompatible, WriteDateUseDateFormat, NotWriteRootClassName, DisableCheckSpecialChar, BeanToArray, WriteNonStringKeyAsString, NotWriteDefaultValue ; private SerializerFeature () { mask = (1 << ordinal()); } private final int mask; public final int getMask () { return mask; } public static boolean isEnabled (int features, SerializerFeature feature) { return (features & feature.getMask()) != 0 ; } public static boolean isEnabled (int features, int fieaturesB, SerializerFeature feature) { int mask = feature.getMask(); return (features & mask) != 0 || (fieaturesB & mask) != 0 ; } public static int config (int features, SerializerFeature feature, boolean state) { if (state) { features |= feature.getMask(); } else { features &= ~feature.getMask(); } return features; }
SerializerFeature是一个枚举类型(为什么不使用常量呢?这个会在接下来的文章当中提到),其中定义了多个枚举(我们可以将其当成类来处理,只是这个类有点特殊而已),比如我们常用的BrowserCompatible(游览器兼容,使用它会使得json串中的key加上双引号)**以及 PrettyFormat(格式化)**,且提供了一个默认构造方法:
1 2 3 private SerializerFeature () { mask = (1 << ordinal()); }
每实例化一个Enum的时候就会调用一次构造方法,其中的1<<ordinal()是此次讲解的重中之重。
2. 认识SerializerFeature的构造方法 1 2 3 private SerializerFeature () { mask = (1 << ordinal()); }
ordinal()
方法根据枚举定义了的个数返回不同的数值,如果定义了五个枚举,那么该方法根据顺序依次返回0-4的五个数字。比如QuoteFieldNames,UseSingleQuotes,WriteMapNullValue依次返回的就是0,1,2这三个数字 ,所以根据这样定义枚举相对应的mask值就是1,2,4,8,16,32…(2的倍数,转换成2进制之后其特殊性就在于只有首位才为1 ) 比如4的二进制:100,4096的二进制:1000000000000
3. 注册或者移除SerializerFeature 1 2 3 4 5 6 7 8 public static int config (int features, SerializerFeature feature, boolean state) { if (state) { features |= feature.getMask(); } else { features &= ~feature.getMask(); } return features; }
第一个参数表示默认的SerializerFeature,fastjson在运行过程中加载了默认的SerializerFeature
1 2 3 4 5 6 7 8 9 10 static { int features = 0 ; features |= SerializerFeature.QuoteFieldNames.getMask(); features |= SerializerFeature.SkipTransientField.getMask(); features |= SerializerFeature.WriteEnumUsingToString.getMask(); features |= SerializerFeature.SortField.getMask(); DEFAULT_GENERATE_FEATURE = features; }
第二个参数表示需要注册/移除的特性
第三个参数表示是注册还是移除特性的状态
注册过程:
1 2 3 4 5 6 0000 0010 |(或) 0000 1000 |(或) 0010 0000 ---------------------------------------------------------------------------- 0010 1010 (此时表示已经注册了三个特性,有几个1 就有几个特性)
移除过程:
1 2 3 4 5 6 7 ~ 0000 0010 = 1111 1101 0010 1010 &(与) 1111 1101 ----------------------------------------------------------------------- 0010 1000 (此时已经只具有了两个特性,已经被移除了一个)
是不是觉得位运算很神奇呢?不得不让人感叹细微之处方见大智慧呀!
4. 验证是否存在该特性 1 2 3 4 5 6 7 8 9 10 public static boolean isEnabled (int features, SerializerFeature feature) { return (features & feature.getMask()) != 0 ; } public static boolean isEnabled (int features, int fieaturesB, SerializerFeature feature) { int mask = feature.getMask(); return (features & mask) != 0 || (fieaturesB & mask) != 0 ; }
和config使用的方法一致,不在做过多累述。
5. 为什么使用枚举 以前我们在代码中,定义使用过的常量,我们可能会这样定义
1 2 3 4 5 6 7 8 9 10 public class State { public static final int ON = 1 ; public static final int OFF= 0 ; } class test { public void showState (int state) { System.out.println("现在的状态是:" +state); } }
既然都用了这么久了,有什么不好的呢?
它不是类型安全的。你必须确保是int
你还要确保它的范围是0 和1
很多时候你打印出来的时候,你只看到1和0
导致阅读你代码的人并不知道你的意图。所以更多的时候我们应该使用枚举,而不是常量。