java 匿名初始化_Java 匿名内部类初始化法的序列化副作用

在Java开发中,使用匿名内部类初始化对象并序列化时可能会遇到问题,FastJson报错找不到默认构造器。即使添加无参构造器也无法解决。原因在于匿名内部类创建的对象序列化后类型会变成内部类,导致反序列化失败。因此,建议避免使用匿名内部类初始化以防止性能和序列化问题。
摘要由CSDN通过智能技术生成

最近在开发过程中遇到一个超预期的问题,经过详细调试研究后找到了问题根源,现形成文字以示众人,方便遇到此问题的同仁们快速过坑。

问题现象

问题发生的场景是这样的,有个查询方法从DB中查询出数据缓存到Redis中。方法返回的的Pojo对象,那么在存Redis时,就要进行序列化,此时应用了FastJson。当在缓存进Redis时一切正常,当我第二次查询时,当然去Redis中取出序列化的数据还原成我想要的Pojo类,在这时FastJson发生了异常,见下图:

4597822f904a633d5767bbf90de25d8d.png

从异常字面上看是未找到默认构造器,于是乎我给Service实现类加了个无参构造器以验证这一异常,结果是没有生效,依然报上图的异常。我只是期望把对象正常的存取,何必让我做些不相关的事务呢,难道我每创建一个对象就必须重写构造器吗,这不合理呀,我太不自由了,而且我创建了构造器也没有生效。于是乎写下代码模拟发生的问题,深究其发生的原因。

创建User类

package doublebraceinit;

public class User {

private String name = "";

private String sex = "";

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getSex() {

return sex;

}

public void setSex(String sex) {

this.sex = sex;

}

public void print(){

System.out.printf("name:%s,age:%s\n", this.name, this.sex);

}

}

创建Role类

package doublebraceinit;

public class Role {

private String code = "";

public String getCode() {

return code;

}

public void setCode(String code) {

this.code = code;

}

}

创建UserTest类

package doublebraceinit;

import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.serializer.SerializerFeature;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import org.gzsw.common.exception.BusiException;

import org.gzsw.modules.api.config.EtaxConfig;

import org.gzsw.modules.api.entity.Region;

import org.gzsw.modules.api.mapper.RegionMapper;

import org.gzsw.modules.api.service.IRegionService;

import org.gzsw.modules.api.vo.RegionTreeVO;

import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

public class UserTest {

private Role role;

public Role getRole() {

return role;

}

public void setRole(Role role) {

this.role = role;

}

public static void main(String[] args){

User zhangsan = new User();

zhangsan.setName("张三");

zhangsan.setSex("男");

zhangsan.print();

String zhangsanJson = JSON.toJSONString(zhangsan, SerializerFeature.WriteClassName);

System.out.println("zhangsanJson = " + zhangsanJson);

User lisi = new User(){{

setName("李四");

setSex("女");

}};

lisi.print();

String lisiJson = JSON.toJSONString(lisi, SerializerFeature.WriteClassName);

System.out.println("lisiJson = " + lisiJson);

}

}

这里用FastJosn转成字符串时,要用SerializerFeature.WriteClassName模式,因为我们要保留类类型,期望反序列化时转回原类型。

问题根源

我们执行一个main方法,结果见下图:

4551aa678cd1be367a2a00750030d576.png

看到了差异:

在未使用匿名内部类初始化时,序列化后的字符串中类类型是正确的类型,即User;

在使用了匿名内部类初始化时,序列化后的字符串中类类型是一个继续了原类类型的匿名内部类,即UserTest$1。

虽然在大部分情况下能够还原成User对象,毕竟UserTest$1继承于User。但是在有些情况下会发生错误,比如在我的项目中,在Service层实现类中使用了此方式,导致了本文前面出现的异常。于是我们得出的结论是用匿名内部类初始化的对象,并用FastJson序列化时会发生序列化问题,原类类型序列化错误。

最后忠告

不建议使用匿名内部类初始化法,一是性能问题,二是序列化问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值