序列化会阻止垃圾回收 |
每次对象被写入到一个对象输出流时,流会保存一个到对象的引用。然后,如果有相同的对象呗写入到相同的流,它就能被替换为对之前已写入的引用。但这样,对象会一直存活,阻止了垃圾回收,之后当流被reset或close之后,才能够被垃圾回收。 close:对同一个文件,只能用对象输出流写入一次(不能追加写入),如果调用了close方法,然后再重新构造(追加模式),读取时会出错。 reset:对同一个对象输出流,可以多次调用reset,此时,保存的引用被释放(也就可以垃圾回收),读取时和平常一样。但是如果写入同一个对象(之间调用了reset),则可能重复写入。 |
不可序列化的原因 | |
|
一些类实现了Serializable接口,但如果序列化会抛出NotSerializableException异常。 |
|
序列化存储对象的状态和类的名字,但不存储类的字节码。因此,可能序列化和反序列化所参照的类时不同的。 默认情况下:
通过在新类中指定和旧类相同的SerialVersionUID,可以使新类兼容旧类。但你必须负责它们的兼容性。 |
自定义序列化过程 | |
|
解析Class |
ObjectInputStream的readObject方法只从本地classpath中加载类,如果类找不到,则抛出异常。 可通过扩展ObjectOutputStream类并实现annotateClass方法以提供Class的信息(可以是类字节码或URL)。 并通过扩展ObjectInputStream类并实现resolveClass方法以提取Class的信息。(如果找不到相应类,则应抛出ClassNotFoundException异常)。 |
解析对象 |
仅仅可信任的ObjectInputStream/ObjectOutputStream子类可以替换对象。可信任的类表示它是从本地路径加载的。 ObjectOutputStream:
为了可以替换对象,必须在其子类中调用protected的enableReplaceObject方法,并传递参数true。
之后在读取对象之后,从writeObject返回之前调用replaceObject。 ObjectInputStream: 为了可以替换对象,必须在其子类中调用protected的enableResolveObject方法,并传递参数true。 之后在读取对象之后,从readObject返回之前调用resolveObject。 对于读取的每个对象,都会调用该方法,也就是说,如果每个对象o中引用了其他的对象(a,b,c),每个对象都会调用该方法,可通过instanceof来区分不同的对象,并根据不同的类型采取不同的动作。(因为它是一个流中方法) |
验证 |
通过调用ObjectInputStream的registerValidation方法,可注册对对象的验证类。在readObject方法返回之前,调用ObjectInputValidation的validateObject方法以验证。 |