龙空技术网

面试官:“聊聊Java序列化”

程序员前沿 5399

前言:

今天你们对“java序列化list”大致比较关切,同学们都需要了解一些“java序列化list”的相关内容。那么小编也在网络上汇集了一些有关“java序列化list””的相关资讯,希望同学们能喜欢,大家一起来了解一下吧!

前言

java 的序列化大家肯定并不陌生, 在使用一些开源开源框架比如 dubbo 的时候,肯定踩过实体类没有实现序列化接口(java.io.Serializable)而报错的情况, 那大家有没有想过为什么要序列化实体类?如果实体类引用了一个不能序列化的类该怎么做呢?下面就给大家讲下我所探索的Java序列化以及他的使用场景。

如何序列化首先实体类要实现 Serializable 接口

public class Student implements java.io.Serializable {    private String name;    private int age;    // getter setter    ...}
然后可以使用 ObjectOutStream 序列化到本地文件
// 创建输出流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 关键字 transient方法上面用注解 @Transient如果条件允许还可以改为静态属性

因为静态数据不在堆内存中,而是在静态方法区中

完整的例子

我们看下我们很常用的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();            }        }    }
他实现了 java.io.Serializable他在字段 elementData 数组上面用了 transient 关键字他还写了writeObject 和 readObject 方法

你如果用IDE查询的话发现这两个方法没实现任何接口,那是再什么时候调用的呢? 经过一番查阅资料发现 java.io.Serializable 的注释里面有写道

Classes that require special handling during the serialization anddeserialization process must implement special methods with these exactsignatures:<PRE>private void writeObject(java.io.ObjectOutputStream out)    throws IOExceptionprivate 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 anddeserialization process must implement special methods with these exactsignatures:<PRE>private void writeObject(java.io.ObjectOutputStream out)    throws IOExceptionprivate 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 来手动序列化(不受关键字修饰的影响)

序列化的使用场景比如常见的Java对象的网络传输java小游戏开发存放游戏数据的时候比xml更方便存储复杂的关系

他是一种存储方式,只要你需要你就可以去用

总结序列化使用 java.io.Serializable 接口静态字段不会被序列化字段屏蔽用 transient 关键字自定义序列化编写 readObject 和 writeObject 方法写入顺序和读取顺序要一致,就算不用也需要read一下

标签: #java序列化list