Java序列化源码概况

Java序列化原理

概念

  1. Java序列化是把Java对象转换为字节序列的过程。
  2. Java反序列化是指把字节序列恢复为Java对象的过程。

实现

  1. 借助Java提供的API:java.io.ObjectOutputStream(对象输出流)和java.io.ObjectInputStream(对象输入流)。
  2. 待序列化的实体类要实现Serializable或Externalizable接口。
 try {
            // serializable为文件名称
            FileOutputStream fileOutputStream = new FileOutputStream("serializable");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            // 待序列化的对象
            Student student = new Student(18, 0);
            // 写入文件
            objectOutputStream.writeObject(student);
            objectOutputStream.flush();
            objectOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            FileInputStream fileInputStream = new FileInputStream("serializable");
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            Student student = (Student) objectInputStream.readObject();
            System.out.println(student.toString());
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

原理

以序列化为例,从实现入手,首先我们需要构造一个对象输出流:

ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);

ObjectOutputStream

public ObjectOutputStream(OutputStream out) throws IOException {
        // 验证是否是ObjectInputStream的子类
        verifySubclass();
        // BlockDataOutputStream内部类, 存放数据字节的容器
        bout = new BlockDataOutputStream(out);
        // HandleTable是Serializable中的缓存池,在序列化或者反序列化是,当遇到同一种信息时,如果缓存池中有缓存信息,则可以减少很多不必要的解析,引用到缓存池的那个信息即可
        handles = new HandleTable(10, (float) 3.00);
        subs = new ReplaceTable(10, (float) 3.00);
        enableOverride = false;
        // 写入序列化文件头, 即序列化的标识和版本
        writeStreamHeader();
        bout.setBlockDataMode(true);
        if (extendedDebugInfo) {
            debugInfoStack = new DebugTraceInfoStack();
        } else {
            debugInfoStack = null;
        }
    }

接着,我们使用objectOutputStream.writeObject(student)输出待序列化的对象,关于其源码如下:

public final void writeObject(Object obj) throws IOException {
        // 当实例化ObjectOutputStream对象时, 采用的是ObjectOutputStream的无参构造方法
        // enableOverride会被设置为true, writeObjectOverride方法在ObjectOutputStream中
        // 没有提供具体实现, 需要我们通过继承然后重写这个方法
        if (enableOverride) {
            writeObjectOverride(obj);
            return;
        }
        try {
            // 以本文new ObjectOutputStream(fileOutputStream)为例子, 会执行这个方法进行输出
            writeObject0(obj, false);
        } catch (IOException ex) {
            if (depth == 0) {
                writeFatalException(ex);
            }
            throw ex;
        }
    }

writeObjectOverride方法如下:

protected void writeObjectOverride(Object obj) throws IOException {
    }

writeObject0

writeObject0方法如下:

private void writeObject0(Object obj, boolean unshared)
        throws IOException
    {
        boolean oldMode = bout.setBlockDataMode(false);
        depth++;
        try {
            // handle previously written and non-replaceable objects
            int h;
            if ((obj = subs.lookup(obj)) == null) {
                writeNull();
                return;
            } else if (!unshared && (h = handles.lookup(obj)) != -1) {
                // handles为HandleTable对象, 存放缓存信息
                // 如果handles找到obj,说明已经被解析过,不需要重复解析
                writeHandle(h);
                return;
            } else if (obj instanceof Class) {
                // Class类型的处理方式
                writeClass((Class) obj, unshared);
                return;
            } else if (obj instanceof ObjectStreamClass) {
                // ObjectStreamClass类型的处理方式
                writeClassDesc((ObjectStreamClass) obj, unshared);
                return;
            }

            // check for replacement object
            Object orig = obj;
            Class<?> cl = obj.getClass();
            ObjectStreamClass desc;
            for (;;) {
                // REMIND: skip this check for strings/arrays?
                Class<?> repCl;
                // 通过ObjectStreamClass.lookup拿到类型描述信息
                desc = ObjectStreamClass.lookup(cl, true);
                if (!desc.hasWriteReplaceMethod() ||
                    (obj = desc.invokeWriteReplace(obj)) == null ||
                    (repCl = obj.getClass()) == cl)
                {
                    // 如果描述信息中没有实现writeReplace()方法
                    // 或者实现了writeReplace()替换对象的方法,但返回了空对象
                    // 或者实现了writeReplace()替换对象的方法, 但返回的类型实际和待序列化的类 类型一样
                    break;
                }
                // 继续循环, 拿到真正的对象的类信息
                cl = repCl;
            }

            if (enableReplace) {
                // 如果允许替换对象会通过replaceObject方法拿到真正的对象
                // replaceObject方法默认返回obj, 如果想要替换该对象, 可重写该方法
                Object rep = replaceObject(obj);
                if (rep != obj && rep != null) {
                    cl = rep.getClass();
                    desc = ObjectStreamClass.lookup(cl, true);
                }
                obj = rep;
            }

            // if object replaced, run through original checks a second time
            // 如果发生替换, 和前面代码一样, 再做一次检查
            if (obj != orig) {
                subs.assign(orig, obj);
                if (obj == null) {
                    writeNull();
                    return;
                } else if (!unshared && (h = handles.lookup(obj)) != -1) {
                    writeHandle(h);
                    return;
                } else if (obj instanceof Class) {
                    writeClass((Class) obj, unshared);
                    return;
                } else if (obj instanceof ObjectStreamClass) {
                    writeClassDesc((ObjectStreamClass) obj, unshared);
                    return;
                }
            }

            // remaining cases
            // 根据对象的不同情况开始序列化
            if (obj instanceof String) {
                writeString((String) obj, unshared);
            } else if (cl.isArray()) {
                writeArray(obj, desc, unshared);
            } else if (obj instanceof Enum) {
                writeEnum((Enum<?>) obj, desc, unshared);
            } else if (obj instanceof Serializable) {
                // 以本文为例, 待序列化的实体是一个学生实体, 会进入此方法
                writeOrdinaryObject(obj, desc, unshared);
            } else {
                if (extendedDebugInfo) {
                    throw new NotSerializableException(
                        cl.getName() + "\n" + debugInfoStack.toString());
                } else {
                    throw new NotSerializableException(cl.getName());
                }
            }
        } finally {
            depth--;
            bout.setBlockDataMode(oldMode);
        }
    }

writeOrdinaryObject

writeOrdinaryObject 方法如下:

private void writeOrdinaryObject(Object obj,
                                     ObjectStreamClass desc,
                                     boolean unshared)
        throws IOException
    {
        if (extendedDebugInfo) {
            debugInfoStack.push(
                (depth == 1 ? "root " : "") + "object (class \"" +
                obj.getClass().getName() + "\", " + obj.toString() + ")");
        }
        try {
            // 检查是否可以序列化
            desc.checkSerialize();
            // 表示要写入一个新对象
            bout.writeByte(TC_OBJECT);
            // 写入对象的描述信息
            writeClassDesc(desc, false);
            // 默认情况为false, 表示对象描述可以被缓存复用
            handles.assign(unshared ? null : obj);
            if (desc.isExternalizable() && !desc.isProxy()) {
                // 实现了Externalizable时的序列化方式
                writeExternalData((Externalizable) obj);
            } else {
                // 实现了Serializable的序列化方式
                writeSerialData(obj, desc);
            }
        } finally {
            if (extendedDebugInfo) {
                debugInfoStack.pop();
            }
        }
    }

writeSerialData

 private void writeSerialData(Object obj, ObjectStreamClass desc)
        throws IOException
    {
        ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
        for (int i = 0; i < slots.length; i++) {
            ObjectStreamClass slotDesc = slots[i].desc;
            if (slotDesc.hasWriteObjectMethod()) {
                // 如果对象重写了writeObject()方法则进入到这里
              //  ......
            } else {
                // 默认走这里进行序列化
                defaultWriteFields(obj, slotDesc);
            }
        }
    }

defaultWriteFields

private void defaultWriteFields(Object obj, ObjectStreamClass desc)
        throws IOException
    {
        Class<?> cl = desc.forClass();
        // 做类型校验,保证从Obj获得的对象描述正确
        if (cl != null && obj != null && !cl.isInstance(obj)) {
            throw new ClassCastException();
        }

        desc.checkDefaultSerialize();
        int primDataSize = desc.getPrimDataSize();
        if (primVals == null || primVals.length < primDataSize) {
            primVals = new byte[primDataSize];
        }
        // 反射获取属性值
        desc.getPrimFieldValues(obj, primVals);
        bout.write(primVals, 0, primDataSize, false);

        ObjectStreamField[] fields = desc.getFields(false);
        Object[] objVals = new Object[desc.getNumObjFields()];
        int numPrimFields = fields.length - objVals.length;
        desc.getObjFieldValues(obj, objVals);
        // 只有对象类型才会被遍历解析
        for (int i = 0; i < objVals.length; i++) {
            if (extendedDebugInfo) {
                debugInfoStack.push(
                    "field (class \"" + desc.getName() + "\", name: \"" +
                    fields[numPrimFields + i].getName() + "\", type: \"" +
                    fields[numPrimFields + i].getType() + "\")");
            }
            try {
                // 再次执行writeObject0方法
                writeObject0(objVals[i],
                             fields[numPrimFields + i].isUnshared());
            } finally {
                if (extendedDebugInfo) {
                    debugInfoStack.pop();
                }
            }
        }
    }

总结

其实整个序列化过程,就是一个递归的过程,在defaultWriteFields方法中,通过反射的方式解析出对象、属性等的描述,如果属性为对象,继续writeObject0调用。

上一篇:Vue项目首页-图标区域逻辑实现(7-5)


下一篇:2.5 Git 基础 - 远程仓库的使用