序列化控制
-
当我们对序列化进行控制时,可能某个特定子对象不想让Java序列化机制自动保存与恢复。如果子对象表示的是我们不希望将其序列化的敏感信息(如密码),通常会面临这种情况。即使对象中的这些信息是private属性,一经序列化处理,人们就可以通过读取文件或者拦截网络传输的方式来访问到它。有两种办法可以防止对象的敏感部分被序列化:
-
实现
Externalizable
代替实现
Serializable
接口来对序列化过程进行控制,
Externalizable
继承了
Serializable
接口,同时增添了两个方法:
writeExternal()
和
readExternal()
。
两者在反序列化时的区别
:
– 对Serializable对象反序列化时,
由于Serializable对象完全以它存储的二进制位为基础来构造,因此并不会调用任何构造函数,
因此Serializable类无需默认构造函数,但是当Serializable类的父类没有实现Serializable接口时,反序列化过程会调用父类的默认构造函数,因此该父类必需有默认构造函数,否则会抛异常。
– 对Externalizable对象反序列化时,
会先调用类的不带参数的构造方法
,这是有别于默认反序列方式的
。如果把类的不带参数的构造方法删除,或者把该构造方法的访问权限设置为private、默认或protected级别,会抛出
java.io.InvalidException: no valid constructor
异常,因此
Externalizable对象必须有默认构造函数,而且必需是public的。
–
Externalizable
的替代方法:如果不是特别坚持实现Externalizable接口,那么还有另一种方法。我们可以实现
Serializable
接口,并添加
writeObject()
和
readObject()
的方法。一旦对象被序列化或者重新装配,就会分别调用那两个方法。也就是说,
只要提供了这两个方法,就会优先使用它们,而不考虑默认的序列化机制。
这些方法必须含有下列准确的签名:
private void writeObject(ObjectOutputStream stream) throws IOException; private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
– 可以用
transient
关键字逐个字段地关闭序列化,它的意思是“
不用麻烦你保存或恢复数据—我自己会处理的
”。由于Externalizable对象在默认情况下不保存它们的任何字段,所以
transient关键字只能和Serializable对象一起使用。
-
实现