反序列化时,具体对象生成方式的探究

今天读《Effective Java》这本书时,读到第77条时,困惑了很久,对里面列举单例模式反序列化问题久久不能理解,因此特意探究了下,对反序列化的流程有了进一步的认识:

1)反序列化时,是根据序列化时写入流的类路径去加载类的,采用的方法如下:

ObjectInputStream—>resolveClass(ObjectStreamClass desc){
  String name = desc.getName();
        try {
            return Class.forName(name, false, latestUserDefinedLoader());
        } catch (ClassNotFoundException ex) {
            Class<?> cl = primClasses.get(name);
            if (cl != null) {
                return cl;
            } else {
                throw ex;
            }
        }
}

我们一般接触到了加载方式,都是class.forName(String name),这种方式默认是加载时初始化静态变量的,而反序列化加载类时是不执行初始化操作的;

2)反序列化时是不会调用类中的构造函数,这一点需要明确(java编程思想中有说到,但是看到这个地方时,没想起来,然后蒙了一段时间),至于具体怎么创建,研究了半天源码,但有一个关键的地方没有找到——Constructor类中的 constructorAccessor变量的初始化地方;通过单步调试,可以看到,反序列化调用的constructorAccessor 变量的实际内容是GeneratedSerializationConstructorAccseeor的一个实例,通过类名也能发现这个类的作用与平常类的实例化不同;然后由此产生一个相应类的实例。

因此,每次反序列化单例对象时,都是重新创建了一个实例,违背了单例模式的意义,所以需要重写readResolve()方法,返回新建对象共享的静态变量(在第一次引用时被初始化,之后就不会被改变了),保证对象引用同一个实例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值