序列化学习(2)

参考Java对象的序列化与反序列化深入分析Java的序列化与反序列化

序列化 和 反序列化 的细节

  1. 在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化。

  2. 通过ObjectOutputStream和ObjectInputStream对对象进行序列化及反序列化

  3. 虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID)

  4. 序列化并不保存静态变量。

  5. 要想将父类对象也序列化,就需要让父类也实现Serializable 接口。

  6. Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。(需要注意和 静态变量的差别,静态变量是字段都不存在

  7. 如果一个类想被序列化,需要实现Serializable接口。否则将抛出NotSerializableException异常,这是因为,在序列化操作过程中会对类型进行检查,要求被序列化的类必须属于Enum、Array和Serializable类型其中的任何一种

  8. 对于实现Serializable接口的类,并不要求该类具有一个无参的构造方法, 因为在反序列化的过程中实际上是去其继承树上找到一个没有实现Serializable接口的父类(最终会找到Object), 然后构造该类的对象, 再逐层往下的去设置各个可以反序列化的属性(也就是没有被transient修饰的非静态属性).

  9. 对于实现Externalizable接口的类,需要其拥有一个public的无参构造器,因为对该类对象进行反序列化先走构造方法得到控对象,然后调用readExternal方法读取序列化文件中的内容给对应的属性赋值。否则会报 java.io.InvalidClassException的异常,反序列化先调用构造器,这会破坏单例模式
    化。

serialVersionUID 有何用途?

虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致,即serialVersionUID要求一致。

在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException。这样做是为了保证安全,因为文件存储中的内容可能被篡改。

当实现java.io.Serializable接口的类没有显式地定义一个serialVersionUID变量时候,Java序列化机制会根据编译的Class自动生成一个serialVersionUID作序列化版本比较用,这种情况下,如果Class文件没有发生变化,就算再编译多次,serialVersionUID也不会变化的。但是,如果发生了变化,那么这个文件对应的serialVersionUID也就会发生变化。

基于以上原理,我们序列化某个类。在序列化之后,由于某些原因,我们对该类做了变更,重新启动应用后,会出现以下两种情况:

  • 指定了id的情况之下,新增属性字段为空或者默认值。
  • 如果没有指定id,则会报错说id不匹配的

如何反序列化破坏单例

  • 以通过在单例里定义readResolve()方法
public class Singleton implements Serializable{
    private volatile static Singleton singleton;
    private Singleton (){}
    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }

    private Object readResolve() {
        return singleton;
    }
}
  • 通过枚举实现单例,天生防序列化的破话
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值