网站域名自动跳转,天猫淘宝旗舰店,网站营销建设策划案,wordpress 前台优酷视频自适应前言
序列化和反序列化是日常工作中经常使用的工具#xff0c;一般用于对象的持久化保存或者对象的网络传输#xff0c;一般有两种情况#xff0c;一种是对象本身实现了Serializable接口#xff0c;这种情况下可以利用jdk自带的功能或者Kryo等这种封装好的序列化反序列化工…前言
序列化和反序列化是日常工作中经常使用的工具一般用于对象的持久化保存或者对象的网络传输一般有两种情况一种是对象本身实现了Serializable接口这种情况下可以利用jdk自带的功能或者Kryo等这种封装好的序列化反序列化工具还有一种情况就是对象本身并没有实现Serializable接口那么这个时候开发者们就会考虑将对象序列化为字符串来进行持久化保存或传输。
笔者在日常开发中常用到的序列化工具就是谷歌的Gson和阿里巴巴的FastJson这两种的区别在上一篇博客中通过实验的方式做了一个简单对比。那么本篇来着重探究一下Gson是如何反序列化对象的。
Gson反序列化对象实现的实现原理
我们先来考虑一个问题如果有这样一个json字符串{“name”:“cz”,“age”:18}在没有现成的反序列化工具时我们要如何将该json字符串中的内容映射到对象中呢 对象的结构如下
public class Student {public String name; // 特别注意这里修饰符为publicpublic String home;public Integer age;public String getName() {return name;}public void setName(String name) {this.name name;}public String getHome() {return home;}public void setHome(String home) {this.home home;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age age;}
}方法一
通过反射调用set方法来设置值。 代码如下
/**
* author Chengzhi
* date 2023-08-23
* 测试目的测试通过set方法来反序列化对象
* 预期结果:
*/
Test
public void test2() throws IllegalAccessException, InstantiationException, InvocationTargetException {String json {name:cz,age:18};String[] fields json.substring(1,json.length()-1).split(,);MapString, Object map new HashMapString, Object();for (String field : fields) {String[] split field.split(:);String key split[0];String value split[1];if (key.startsWith() key.endsWith()) {key split[0].substring(1,split[0].length()-1);}if (value.startsWith() value.endsWith()) {value split[1].substring(1,split[1].length()-1);}map.put(key.toUpperCase(), value);}ClassStudent studentClass Student.class;Student o studentClass.newInstance();Method[] methods studentClass.getMethods();for (Method method : methods) {String methodName method.getName();if (methodName.startsWith(set)) {String key methodName.substring(3, methodName.length()).toUpperCase();Class? parameterType method.getParameterTypes()[0];Object value map.get(key);if (java.lang.Integer.equals(parameterType.getName())) {value Integer.valueOf((String) value);}method.invoke(o, value);}}System.out.println(o.getName());
}方法二
在本案例中由于对象的变量是使用public修饰的那么同样的我可以通过反射直接赋值。 代码如下
/*** author Chengzhi* date 2023-08-24* 测试目的 通过反射直接给对象的变量赋值* 预期结果:*/
Test
public void test3() throws IllegalAccessException, InstantiationException {String json {name:cz,age:18};String[] jsonFields json.substring(1,json.length()-1).split(,);MapString, Object map new HashMapString, Object();for (String field : jsonFields) {String[] split field.split(:);String key split[0];String value split[1];if (key.startsWith() key.endsWith()) {key split[0].substring(1,split[0].length()-1);}if (value.startsWith() value.endsWith()) {value split[1].substring(1,split[1].length()-1);}map.put(key.toUpperCase(), value);}ClassStudent studentClass Student.class;Student o studentClass.newInstance();Field[] fields studentClass.getFields();for (Field field : fields) {String name field.getName();Object value map.get(name.toUpperCase());if (java.lang.Integer.equals(field.getGenericType().getTypeName())) {value Integer.valueOf((String) value);}field.set(o, value);}System.out.println(o.getName());
}上述方式存在的问题
上述方式一其实就是阿里巴巴的FastJson实现原理而第二种实现方式由于示例POJO类中的变量都是使用public修饰的可以直接反射赋值但是正常的对象都是不允许使用public修饰因为这样值很容易被改变。如果pojo类中的变量使用private修饰由于访问权限的约束Field[] fields studentClass.getFields();这里会获取不到参数值。最终不会赋值成功。
Gson反序列化原理
其实Gson反序列化原理和方式二思路很接近都是直接去操作POJO类的全局变量而不是去调用set方法那么Gson是如何绕过变量修饰符的权限约束呢。从源码可以发现Gson是利用Unsafe类的putObject方法。
//为给定地址设置值忽略修饰限定符的访问限制与此类似操作还有: putInt,putDoubleputLongputChar等
public native void putObject(Object o, long offset, Object x);该方法可以忽略修饰符的权限约束。 总结
Gson利用反射的思想结合强大的Unsafe类通过直接改变类的变量值来达到反序列化的目的。