JDK源码(十三):ObjectInputStream

java.io.ObjectInputStream是实现反序列化的关键类,ObjectInputStream反序列化流,将之前使用 ObjectOutputStream 序列化的原始数据恢复为对象,以流的方式读取对象。其它的用途包括主机之间使用socket流传递对象、远程系统调用。

ObjectInputStream确保从流创建的所有对象的类型与Java虚拟机中的类匹配。类根据需要使用标准机制加载。只能从流中读取实现java.io.Serializable或java.io.Externalizable接口的对象。方法readObject用于从流中读取对象。在Java中,字符串和数组是对象,在序列化期间被视为对象。读取时,需要将它们转换为预期的类型。对象的默认反序列化机制将每个字段的内容还原为写入时的值和类型。反序列化过程将忽略声明为临时或静态的字段。对其他对象的引用会根据需要从流中读取这些对象。使用共享机制可以正确还原对象图。反序列化时总是分配新对象,这会防止现有对象被重写。

ObjectInputStream的构造函数也有两个,从构造函数中可以看出,同样需要验证类的安全性,同时在初始化时会自动读取Java序列化头部信息。跟输出流一样,预留了一个生成全空的类输入流初始化方法,用于继承ObjectInputStream的子类进行重写。安全验证和输出流中是相同的,而读取头部信息需要读取魔术数字和版本号并验证与当前JDK中的是否一致。当然,如果两端使用的JDK中这个类版本号不一致就会出现异常。

public ObjectInputStream(InputStream in) throws IOException {
        verifySubclass();
        bin = new BlockDataInputStream(in);
        handles = new HandleTable(10);
        vlist = new ValidationList();
        serialFilter = ObjectInputFilter.Config.getSerialFilter();
        enableOverride = false;
        readStreamHeader();
        bin.setBlockDataMode(true);
    }

    protected ObjectInputStream() throws IOException, SecurityException {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
        }
        bin = null;
        handles = null;
        vlist = null;
        serialFilter = ObjectInputFilter.Config.getSerialFilter();
        enableOverride = true;
    }

来看一下readObject,读和写一样也是final方法,所以子类要重写必须通过readObjectOverride方法来完成。如果类里面定义了非基本数据类型变量,需要进行嵌套读取,outerHandle用来存储上一层读取对象的句柄,然后调用readObject0读取生成对象。完成之后要记录句柄依赖,并检查有无异常产生。最上层读取完成之后要发起回调。

/**
     * 从ObjectInputStream读取对象。
	 * 读取对象的类、类的签名、类及其所有超类型的非瞬态和非静态字段的值。
	 * 类的默认反序列化可以使用writeObject和readObject方法重写。
	 * 此对象引用的对象是可传递读取的,以便由readObject重建对象的完整等效图.
     */
    public final Object readObject()
        throws IOException, ClassNotFoundException
    {
        if (enableOverride) {
			//需子类重写
            return readObjectOverride();
        }

        //如果嵌套读取,则passHandle包含封闭对象的句柄
        int outerHandle = passHandle;
        try {
            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;
        } finally {
            passHandle = outerHandle;
            if (closed && depth == 0) {
				//最上层调用退出时清除调用返回列表和句柄缓存
                clear();
            }
        }
    }
private Object readObject0(boolean unshared) throws IOException {
        boolean oldMode = bin.getBlockDataMode();
        if (oldMode) {
            int remain = bin.currentBlockRemaining();
            if (remain > 0) {
                throw new OptionalDataException(remain);
            } else if (defaultDataEnd) {
                /*
                 * Fix for 4360508: stream is currently at the end of a field
                 * value block written via default serialization; since there
                 * is no terminating TC_ENDBLOCKDATA tag, simulate
                 * end-of-custom-data behavior explicitly.
                 */
                throw new OptionalDataException(true);
            }
            bin.setBlockDataMode(false);
        }

        byte tc;
		// 读到流reset标志
        while ((tc = bin.peekByte()) == TC_RESET) {
			// 消耗缓存的字节
            bin.readByte();
			// depth为0时执行clear方法,否则抛出异常
            handleReset();
        }

        depth++; // 增加递归深度
        totalObjectRefs++; // 增加引用对象数
        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);
        }
    }

readObject0必须在块输入流内为空也就是上一次反序列化完全结束后才能开始,否则会抛出异常。首先,从流中读取一个标志位,判断当前下一个内容是什么类型,上次我们讲到过,输出的时候都会先输出TC_OBJECT,所以在默认情况下也是先读取到TC_OBJECT,也就是先执行readOrdinaryObject。readOrdinaryObject是读取一个自定义类最上层直接调用的方法。几个关键的点,首先是要读取类的描述信息,然后根据类描述符创建一个实例,将对象实例存储到句柄缓存中并将句柄存储到passHandle,然后读取内部变量数据,最后检查有没有替换对象。

更多精彩内容请关注微信公众号:

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

徐楠_01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值