栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java序列化(3)---- Serializable反序列化原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java序列化(3)---- Serializable反序列化原理

反序列化过程

        调用ObjectInputSream类的readObject方法对实现了Serializable的对象进行反序列化。

public SerialObject inputObj(String path) throws Exception {
    ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(path));
    SerialObject obj = (SerialObject) inputStream.readObject();
    inputStream.close();
    return obj;
}

        ObjectInputSream的readObject方法,实际调用了readObject0(false)方法:

public final Object readObject()
        throws IOException, ClassNotFoundException {
    ...
        Object obj = readObject0(false);
        handles.markDependency(outerHandle, passHandle);
        ClassNotFoundException ex = handles.lookupException(passHandle);
        if (ex != null) {
            throw ex;
        }
        if (depth == 0) {
            vlist.doCallbacks();
        }
        return obj;
    ...
}

        可以看到readObject0中会根据不同的对象类型,执行不同反序列化过程。这里只看对象类型的反序列化过程,即TC_OBJECT的情形。此时调用readOrdinaryObject方法进行反序列化。

private Object readObject0(boolean unshared) throws IOException {
    ...
    byte tc;
    while ((tc = bin.peekByte()) == TC_RESET) {
        bin.readByte();
        handleReset();
    }
    depth++;
    try {
        switch (tc) {
            case TC_NULL:
                return readNull();
            case TC_REFERENCE:
                return readHandle(unshared);
            case TC_CLASS:
                return readClass(unshared);
            case TC_CLASSDESC:
            case TC_PROXYCLASSDESC:
                return readClassDesc(unshared);
            case TC_STRING:
            case TC_LONGSTRING:
                return checkResolve(readString(unshared));
            case TC_ARRAY:
                return checkResolve(readArray(unshared));
            case TC_ENUM:
                return checkResolve(readEnum(unshared));
            case TC_OBJECT:
                return checkResolve(readOrdinaryObject(unshared));
            case TC_EXCEPTION:
                IOException ex = readFatalException();
                    throw new WriteAbortedException("writing aborted", ex);
            case TC_BLOCKDATA:
            case TC_BLOCKDATALONG:
                if (oldMode) {
                    bin.setBlockDataMode(true);
                    bin.peek();             // force header read
                    throw new OptionalDataException(
                            bin.currentBlockRemaining());
                } else {
                    throw new StreamCorruptedException(
                            "unexpected block data");
                }
            case TC_ENDBLOCKDATA:
                if (oldMode) {
                    throw new OptionalDataException(true);
                } else {
                    throw new StreamCorruptedException(
                            "unexpected end of block data");
                }
            default:
                throw new StreamCorruptedException(
                        String.format("invalid type code: %02X", tc));
        }
    } finally {
        depth--;
        bin.setBlockDataMode(oldMode);
    }
    ...
}

        readOrdinaryObject方法,会通过反射调用对象的无参构造函数创建对象。这就是为什么说,“序列化的类需要提供能够被访问的无参构造函数,否则会报错”的原因。

        根据序列化类实现了Externalizable或Serializable的接口,分别调用不同的方法。这里先讨论实现Serializable接口的情形。此时调用readSerialData方法。

private Object readOrdinaryObject(boolean unshared)
        throws IOException {
    ...
    Object obj;
    try {
        obj = desc.isInstantiable() ? desc.newInstance() : null;
    } catch (Exception ex) {
        throw (IOException) new InvalidClassException(
                desc.forClass().getName(),
                "unable to create instance").initCause(ex);
    }
    ...
    if (desc.isExternalizable()) {
        readExternalData((Externalizable) obj, desc);
    } else {
        readSerialData(obj, desc);
    }
    ...
    return obj;
}

        readSerialData方法,判断是否有自定义的反序列化函数,有的话,执行自定义的反序列化方法;否则执行defaultReadFields。

private void readSerialData(Object obj, ObjectStreamClass desc)
        throws IOException {
    ...
    if (obj == null || handles.lookupException(passHandle) != null) {
        defaultReadFields(null, slotDesc); // skip field values
    } else if (slotDesc.hasReadObjectMethod()) {
        ...
        slotDesc.invokeReadObject(obj, this);
        ...
    } else {
        defaultReadFields(obj, slotDesc);
    }
    ...
}

        自定义的反序列方法有readObject和readResolve方法。在初始化ObjectStreamClass的时候,通过反射查找是否存在这两个方法。

        可以看到只有实现Serializable接口,并提供readObject / readResolve方法才起作用。实现Externalizable接口是无效的。并且若同时提供readResolve和readObject方法,前者会覆盖后者。

private ObjectStreamClass(final Class cl) {
    // 是否实现Externalizable接口的方式
    if (externalizable) {
        cons = getExternalizableConstructor(cl);
    } else {
        cons = getSerializableConstructor(cl);
        writeObjectMethod = getPrivateMethod(cl, "writeObject",
                 new Class[] { ObjectOutputStream.class },
                 Void.TYPE);
        readObjectMethod = getPrivateMethod(cl, "readObject",
                 new Class[] { ObjectInputStream.class },
                 Void.TYPE);
        readObjectNoDataMethod = getPrivateMethod(
                 cl, "readObjectNoData", null, Void.TYPE);
        hasWriteObjectData = (writeObjectMethod != null);
    }
    writeReplaceMethod = getInheritableMethod(
                        cl, "writeReplace", null, Object.class);
    readResolveMethod = getInheritableMethod(
                        cl, "readResolve", null, Object.class);
    ...
}

        若是实现了自定义序列化的方法(readObject / readResolve),则直接反射调用对象的方法完成反序列化。

void invokeReadObject(Object obj, ObjectInputStream in)
        throws ClassNotFoundException, IOException,
               UnsupportedOperationException {
    requireInitialized();
    if (readObjectMethod != null) {
        try {
            readObjectMethod.invoke(obj, new Object[]{ in });
        ...
    }
    ...
}

        系统默认反序列化过程,调用defaultReadFields完成,首先反序列化基本数据类型,填充到obj。然后针对对象类型,遍历循环调用readObject0进行反序列化。

private void defaultReadFields(Object obj, ObjectStreamClass desc)
        throws IOException {
    ...
    int primDataSize = desc.getPrimDataSize();
    if (primVals == null || primVals.length < primDataSize) {
        primVals = new byte[primDataSize];
    }
    bin.readFully(primVals, 0, primDataSize, false);
    if (obj != null) {
        desc.setPrimFieldValues(obj, primVals);
    }
    ...
    for (int i = 0; i < objVals.length; i++) {
        ObjectStreamField f = fields[numPrimFields + i];
        objVals[i] = readObject0(f.isUnshared());
    }
    ...
}
实现Externalizable接口的反序列化

        在readOrdinaryObject方法,若序列化类实现了Externalizable接口,则调用readExternalData完成反序列化过程。

        这里既是调用序列化类实现的readExternal方法完成反序列化。

private void readExternalData(Externalizable obj, ObjectStreamClass desc)
        throws IOException {
    ...
    if (obj != null) {
        try {
            obj.readExternal(this);
        } catch (ClassNotFoundException ex) {
    ...
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/821535.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号