 和 GsonBuilder().registerTypeAdapter(...).create() 得到的都是 Gson 对象,都可以调用 toJson ()。区别不是 “有参)
new Gson()和GsonBuilder().registerTypeAdapter(...).create()得到的都是 Gson 对象都可以调用 toJson ()。 区别不是 “有参 / 无参构造 Gson”区别是这个 Gson 实例有没有装上自定义的类型转换器ClassCodec。//版本A裸Gson没有注册Class类型适配器 Gson gson1 new Gson(); //版本BGsonBuilder构建注册了Class类型的自定义编解码器 Gson gson2 new GsonBuilder() .registerTypeAdapter(Class.class, new Serializer.ClassCodec()) .create();1. 普通对象两者完全一样如果你的对象里没有Class?类型的字段比如普通 DTOclass User{ Long id; String name; }gson1.toJson(user)和gson2.toJson(user)输出的 JSON 字符串一模一样。 这个时候你完全可以用简单的new Gson()。2.RPC 调用消息对象Invocation就不一样了RPC 的调用报文对象一定会携带Class类型成员class RpcInvocation{ private String methodName; private Class? interfaceClass; //❗这里是Class类型 private Class?[] paramTypes; //❗Class数组 private Object[] args; }原生 Gsonnew Gson ()处理Class字段直接翻车Gson 原生不知道怎么序列化UserApi.class这种Class对象。 直接new Gson().toJson(invocation)会把 Class 对象内部一堆 JVM 元属性全部序列化出来生成一大坨垃圾 JSON反序列化根本还原不回来。所以手写了ClassCodec适配器序列化时把Class?对象转为它的全类名字符串com.xxx.UserApi反序列化时拿到字符串Class.forName(全类名)重新加载出 Class 对象registerTypeAdapter(Class.class, new ClassCodec())就是告诉这个 Gson 实例只要遇到 Class 类型不要用原生逻辑用我写的这套编解码。⚠️重点这个适配器只属于 gson2 这个实例。new Gson()出来的 gson1 完全不知道这个自定义逻辑处理 Class 字段直接出错。3. 不是 toJson 需要 “特殊入参”是 Gson 实例需要提前装配适配器toJson(object)方法本身没有变传入的对象也没变。是 Gson 这个工具实例内部预装了处理 Class 类型的规则。流程用 GsonBuilder注册Class类型的自定义 Codec.create()生成一个带该规则的 Gson 对象调用gson.toJson(对象)当遍历对象字段碰到字段类型是Class自动执行我们写好的 ClassCodec 序列化逻辑输出全类名字符串。4. 反序列化那边也要同一个 Gson//反序列化也必须用注册过Codec的gson对象 return gson.fromJson(json,clazz);接收方 fromJson 的时候JSON 里面存的是全类名字符串Gson 看到目标字段是 Class 类型就会走 Codec 的反序列化逻辑调用 Class.forName 还原 Class 对象。如果接收方用裸new Gson()拿到字符串不知道要转 Class直接得到字符串类型不匹配直接报错。一句话总结普通 POJOnew Gson()完全够用。RPC 报文里面包含Class/Class[]字段必须用 GsonBuilder 注册自定义适配器生成装配好规则的 Gson 实例。不是 toJson 调用的时候传参数是构建 Gson 工具对象的时候提前装好特殊类型的处理逻辑。踩坑提醒很多新手会犯序列化用带 Codec 的 Gson反序列化写new Gson()两边 Gson 实例不一样反序列化直接报错。序列化、反序列化必须用同一个注册过适配器的 Gson 实例。优化小提示不要每次 serialize/deserialize 方法内部都 new 一遍 GsonBuilderGson 实例是线程安全的可以提为静态常量只构建一次。//只初始化一次 private static final Gson GSON new GsonBuilder() .registerTypeAdapter(Class.class, new Serializer.ClassCodec()) .create();