一、大家先看个例子:
以上代码的setter/getter是使用Intellij IDEA自动生成的,仔细观察以上代码,你会发现以下规律:
- 基本类型自动生成的getter和setter方法,名称都是isXXX()和setXXX()形式的。
- 包装类型自动生成的getter和setter方法,名称都是getXXX()和setXXX()形式的。
我们可以发现,虽然Bean1和Bean2中的成员变量的名称不同,一个是success,另外一个是isSuccess,但是他们自动生成的getter和setter方法名称都是isSuccess和setSuccess。
为什么会这样呢?
Java Bean中关于setter/getter的规范
关于Java Bean中的getter/setter方法的定义其实是有明确的规定的,根据JavaBeans(TM) Specificationttps://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/)规定,
如果是普通的参数propertyName,要以以下方式定义其setter/getter:
- public \<PropertyType> get\<PropertyName>();
- public void set\<PropertyName>(\<PropertyType> a);
但是,布尔类型的变量propertyName则是单独定义的:
- public boolean is\<PropertyName>();
- public void set\<PropertyName>(boolean m);
通过对照这份JavaBeans规范,我们发现,在Bean1中,变量名为isSuccess,如果严格按照规范定义的话,他的getter方法应该叫isIsSuccess。但是很多IDE都会默认生成为isSuccess。
那这样做会带来什么问题呢。
在一般情况下,其实是没有影响的。但是有一种特殊情况就会有问题,那就是发生序列化的时候。
序列化带来的影响
关于序列化和反序列化请参考Java对象的序列化与反序列化(https://www.hollischuang.com/archives/1150)。
我们这里拿比较常用的JSON序列化来举例,看看看常用的fastJson和Gson之间有何区别:
以上代码的Bean1中,只有一个成员变量即isSuccess,四个方法,分别是IDE帮我们自动生成的isSuccess和setSuccess,
另外一个是增加的一个符合getter命名规范的方法,最后一个增加的一个布符合getter命名规范的方法。
以上代码输出结果:
在fastjson的结果中,原来类中的isSuccess字段被序列化成success,并且其中还包含hello值。而Gson中只有isSuccess字段。
我们可以得出结论:
- fastjson在把对象序列化成json字符串的时候,是通过反射遍历出该类中的所有getter方法**,得到getHello和isSuccess,然后根据JavaBeans规则,他会认为这是两个属性hello和success的值。直接序列化成json:{"hello":"hello","success":true}
- 但是Gson并不是这么做的,他是通过反射遍历该类中的所有属性,并把其值序列化成json:{“isSuccess”:true}
可以看到,由于不同的序列化工具,在进行序列化的时候使用到的策略是不一样的,所以,对于同一个类的同一个对象的序列化结果可能是不同的。
结论只知道了,但是我更感兴趣的是他们是如何处理的呢?分析源码后可知:
下图是fsonjson的处理流程图:
fastjson通过getter获取名字的方法:
Gson的处理流程图
Gson通过属性获取名字的方法
看到这里大家是不是豁然开朗了,也印证了上面提到的结论;
接下来,那么如果对于同一个对象,我使用fastjson进行序列化,再使用Gson反序列化会发生什么?
这和我们预期的结果完全相反,原因是因为JSON框架通过扫描所有的getter后发现有一个isSuccess方法,然后根据JavaBeans的规范,解析出变量名为success,把Bean3对象序列化城字符串后内容为{"success":true}。
根据{"success":true}这个json串,Gson框架在通过解析后,通过反射寻找Bean3类中的success属性,但是Bean3类中只有isSuccess属性,所以,最终反序列化后的Bean类的对象中,isSuccess则会使用默认值false。
但是,一旦以上代码发生在生产环境,这绝对是一个致命的问题。
Gson的反序列化处理流程图:
总结:
如果我们用的是阿里的fastjson序列化工具那么我们就要按照阿里的手册来
在阿里巴巴Java开发手册中关于这一点,有过一个『强制性』规定:
但是看过fastjson源码之后之后你会发现,
原因在于fastjson源码是这样处理的,如下图:
上面举例都是不规范的只是为了说明存在的问题,
但是在平时开发过程中定义POJO变量时要符合JavaBeans的规范。这样无论永哪一种序列化框架,执行结果都一样。就从源头避免了这个问题。
学习链接:
https://maimai.cn/article/detail?fid=987324269&efid=TFCN35SpHSKgL7zwmyVneg