一.Java序列化方式
1.默认方式序列化
1)实现serializable接口
2)实现序列化的代价:
降低该类的灵活性
增加了错误和不安全的可能
增加测试负担
如果不可序列化类的子类要实现序列化,父类必须要提供一个无参的构造函数。
3)UID的作用,其实该字段除了可以在序列化过程中加速判断错误,其他时间毫无意义,比如即使UID一样,但是你增加一个字段还是不会报错,比如你减少一个字段,照样报错,当然在自定义序列化方式的时候,你需要兼容默认序列化方式。
2.自定义序列化方式
比如序列化一个List结构的类,就应该考虑是否使用自定义序列化方式
通过transient修饰,就可以从默认序列化方式中被忽略。
下面我们以ArrayList的自定义序列化方式来说明问题:
3.readobject方法安全性问题
当你在反序列化回来的时候,可以传2个引用过来,虽然引用时final类型的,但是某些final类型引用的值是可以改变的,比如Date类型,所以会造成不安全的事件发生。
解决方法:
1.在readobject的时候,将引用对象克隆
这样外部引用就失效了。
2.通过readResolve方法来解决
readResolve方法的作用是,抛弃反序列化回来的对象引用,将该对象垃圾收集,然后使用该方法返回的新对象引用,看起来比较酷。并且可以很好的解决单例模式无法反序列化的问题。
1.默认方式序列化
1)实现serializable接口
2)实现序列化的代价:
降低该类的灵活性
增加了错误和不安全的可能
增加测试负担
如果不可序列化类的子类要实现序列化,父类必须要提供一个无参的构造函数。
3)UID的作用,其实该字段除了可以在序列化过程中加速判断错误,其他时间毫无意义,比如即使UID一样,但是你增加一个字段还是不会报错,比如你减少一个字段,照样报错,当然在自定义序列化方式的时候,你需要兼容默认序列化方式。
2.自定义序列化方式
比如序列化一个List结构的类,就应该考虑是否使用自定义序列化方式
通过transient修饰,就可以从默认序列化方式中被忽略。
下面我们以ArrayList的自定义序列化方式来说明问题:
private transient E[] elementData;//将elementDate从默认序列化方式中忽略,优化性能,节省序列化空间
/**
* Save the state of the <tt>ArrayList</tt> instance to a stream (that
* is, serialize it).
*
* @serialData The length of the array backing the <tt>ArrayList</tt>
* instance is emitted (int), followed by all of its elements
* (each an <tt>Object</tt>) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
int expectedModCount = modCount;
// Write out element count, and any hidden stuff
s.defaultWriteObject();
// Write out array length
s.writeInt(elementData.length);
// Write out all elements in the proper order.
for (int i=0; i<size; i++)
s.writeObject(elementData[i]);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
/**
* Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
* deserialize it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in array length and allocate array
int arrayLength = s.readInt();
Object[] a = elementData = (E[])new Object[arrayLength];
// Read in all elements in the proper order.
for (int i=0; i<size; i++)
a[i] = s.readObject();
}
3.readobject方法安全性问题
当你在反序列化回来的时候,可以传2个引用过来,虽然引用时final类型的,但是某些final类型引用的值是可以改变的,比如Date类型,所以会造成不安全的事件发生。
解决方法:
1.在readobject的时候,将引用对象克隆
start = new Date(start.getTime());
这样外部引用就失效了。
2.通过readResolve方法来解决
readResolve方法的作用是,抛弃反序列化回来的对象引用,将该对象垃圾收集,然后使用该方法返回的新对象引用,看起来比较酷。并且可以很好的解决单例模式无法反序列化的问题。