java 的序列化大家肯定并不陌生, 在使用一些开源开源框架比如 dubbo 的时候,肯定踩过实体类没有实现序列化接口(java.io.Serializable)而报错的情况, 那大家有没有想过为什么要序列化实体类?如果实体类引用了一个不能序列化的类该怎么做呢?下面就给大家讲下我所探索的Java序列化以及他的使用场景。
public class Student implements java.io.Serializable { private String name; private int age; // getter setter ... }
// 创建输出流 ObjectOutStream out = new ObjectOutputStream(new FileOutputStream("student.dat")) // 创建需要序列化的对象 Student jack = new Student("Jack", 21); Student jim = new Student("Jim", 20); // 写入流 out.writeObject(jack); out.writeObject(jim);
// 读回对象数据 ObjectInputStream in = new ObjectInputStream(new FileInputStream("student.dat")); // 然后用 readObject方法以这些对象写入的顺序获得他们 Student jack = (Student) in.readObject(); Student jim = (Student) in.readObject();
注意:序列化write顺序和反序列化read顺序要一致
例如:
writeInt(a), writeInt(b)
readInt(a), readInt(b)
很简单有几种方式
因为静态数据不在堆内存中,而是在静态方法区中
我们看下我们很常用的java ArrayList 的源码是怎么完成序列化的
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8683452581122892189L; /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. */ transient Object[] elementData; // non-private to simplify nested class access /** * The size of the ArrayList (the number of elements it contains). * * @serial */ private int size; ··· /** * 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{ // Write out element count, and any hidden stuff int expectedModCount = modCount; s.defaultWriteObject(); // Write out size as capacity for behavioural compatibility with clone() s.writeInt(size); // 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 { elementData = EMPTY_ELEMENTDATA; // Read in size, and any hidden stuff s.defaultReadObject(); // Read in capacity s.readInt(); // ignored if (size > 0) { // be like clone(), allocate array based upon size not capacity ensureCapacityInternal(size); Object[] a = elementData; // Read in all elements in the proper order. for (int i=0; i<size; i++) { a[i] = s.readObject(); } } }
你如果用IDE查询的话发现这两个方法没实现任何接口,那是再什么时候调用的呢? 经过一番查阅资料发现 java.io.Serializable 的注释里面有写道
Classes that require special handling during the serialization and deserialization process must implement special methods with these exact signatures: <PRE> private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; private void readObjectNoData() throws ObjectStreamException; </PRE> ··· @author unascribed @see java.io.ObjectOutputStream @see java.io.ObjectInputStream @see java.io.ObjectOutput @see java.io.ObjectInput @see java.io.Externalizable @since JDK1.1
也就是说这两个方法是特殊的回调方法, 当你的实体类很特殊需要手动序列化的时候就可以手动实现这两个方法
然后你可以返回去细品 ArrayList 是把 elementData 数组循环的writeObject 了
Serializable 接口支持的钩子方法
先看下jdk序列化接口的定义
Classes that require special handling during the serialization and deserialization process must implement special methods with these exact signatures: <PRE> private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; private void readObjectNoData() throws ObjectStreamException; </PRE> ··· @author unascribed @see java.io.ObjectOutputStream @see java.io.ObjectInputStream @see java.io.ObjectOutput @see java.io.ObjectInput @see java.io.Externalizable @since JDK1.1
就是告诉我们可以编写writeObject 和 readObject 来手动序列化(不受关键字修饰的影响)
他是一种存储方式,只要你需要你就可以去用