JDK 1.7 java.io 源码学习之ObjectInputStream和ObjectOutputStream

来源:互联网 发布:sql数据库软件下载 编辑:程序博客网 时间:2024/05/16 07:38

上一篇Serializable接口,描述了序列化和反序列化机制,其操作均是基于ObjectInputStream和ObjectOutputStream。

根据ObjectInputStream和ObjectOutputStrema类结构,需先了解两个接口:
DataInput和DataOutput
DataInput和DataOutput 用于从字节流中读取/写入Java基本类型数据或UTF编码的字符串,比较特殊的是,到达流末尾时通过抛出EOFException的方式来表示的

ObjectInput和ObjectOutput分别扩展了DataInput和DataOutput:
ObjectInput扩展了DataInput,使其支持读取对象,并缓存到一个字节数组中
ObjectOutput扩展了DataOutpu,使其可以直接将对象写入流,货主写入字节数组中

ObjectInputStream和ObjectOutputStream是比较复杂,这次主要是学习其在序列化和反序列化上的使用,以及通过readObject和writeObject实现自定义序列化的原理。

在实例化ObjectInputStream和ObjectOutputStream时,均是通过其有参构造函数实例化,传递一个FileInputStream或FileOutputStream对象。

ObjectInputStream的readObject方法:

public final Object readObject() throws IOException, ClassNotFoundException {    if(enableOverrid) {        return readObjectOverride();    }    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.doCallback();        }        return obj;    } finally {        passHandle = outerHandle;        if (closed && depth == 0) {            clear();        }    }}

readObject方法是final的,表示不可被Override,但是其已经通过enableOverrid标记实现了扩展,若想自定义实现,可以Override这个方法:

protected Object readObjectOverride() throws IOException, ClassNotFoundException {    return null;}

该方式非常精妙,从另一种角度,实现了final修饰的方法的Override!而且将真正的处理方法封装到readObject0中

readObject方法核心的就是调用了readObject0方法:

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);}

很明显的就是不同类型的调用不同的处理方法,这边主要看Object类型的:
checkResolve(readOrdinaryObject(unshared))

private Object readOrdinaryObject(boolean unshared)        throws IOException    {        if (bin.readByte() != TC_OBJECT) {            throw new InternalError();        }        ObjectStreamClass desc = readClassDesc(false);        desc.checkDeserialize();        Class<?> cl = desc.forClass();        if (cl == String.class || cl == Class.class                || cl == ObjectStreamClass.class) {            throw new InvalidClassException("invalid class descriptor");        }        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);        }        passHandle = handles.assign(unshared ? unsharedMarker : obj);        ClassNotFoundException resolveEx = desc.getResolveException();        if (resolveEx != null) {            handles.markException(passHandle, resolveEx);        }        if (desc.isExternalizable()) {            readExternalData((Externalizable) obj, desc);        } else {            readSerialData(obj, desc);        }        handles.finish(passHandle);        if (obj != null &&            handles.lookupException(passHandle) == null &&            desc.hasReadResolveMethod())        {            Object rep = desc.invokeReadResolve(obj);            if (unshared && rep.getClass().isArray()) {                rep = cloneArray(rep);            }            if (rep != obj) {                handles.setObject(passHandle, obj = rep);            }        }        return obj;    }

里面这两句表示了不同的处理方式:

if (desc.isExternalizable()) {      readExternalData((Externalizable) obj, desc);} else {      readSerialData(obj, desc);}

即实现Serializable接口的调用readSerialData(obj, desc),实现Externalizable接口的调用readExternalData((Externalizable) obj, desc),以readSerialData为例:

private void readSerialData(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 (slots[i].hasData) {                if (obj != null &&                    slotDesc.hasReadObjectMethod() &&                    handles.lookupException(passHandle) == null)                {                    SerialCallbackContext oldContext = curContext;                    try {                        curContext = new SerialCallbackContext(obj, slotDesc);                        bin.setBlockDataMode(true);                        slotDesc.invokeReadObject(obj, this);                    } catch (ClassNotFoundException ex) {                        /*                         * In most cases, the handle table has already                         * propagated a CNFException to passHandle at this                         * point; this mark call is included to address cases                         * where the custom readObject method has cons'ed and                         * thrown a new CNFException of its own.                         */                        handles.markException(passHandle, ex);                    } finally {                        curContext.setUsed();                        curContext = oldContext;                    }                    /*                     * defaultDataEnd may have been set indirectly by custom                     * readObject() method when calling defaultReadObject() or                     * readFields(); clear it to restore normal read behavior.                     */                    defaultDataEnd = false;                } else {                    defaultReadFields(obj, slotDesc);                }                if (slotDesc.hasWriteObjectData()) {                    skipCustomData();                } else {                    bin.setBlockDataMode(false);                }            } else {                if (obj != null &&                    slotDesc.hasReadObjectNoDataMethod() &&                    handles.lookupException(passHandle) == null)                {                    slotDesc.invokeReadObjectNoData(obj);                }            }        }    }

里面进行了判断,slotDesc.hasReadObjectMethod即类里面有如果含有ReadObjectMethod,最终是执行了slotDesc.invokeReadObject(obj, this)。而invokeReadObject即通过反射的方式调用了该方法:

 void invokeReadObject(Object obj, ObjectInputStream in)        throws ClassNotFoundException, IOException,               UnsupportedOperationException    {        if (readObjectMethod != null) {            try {                readObjectMethod.invoke(obj, new Object[]{ in });            } catch (InvocationTargetException ex) {                Throwable th = ex.getTargetException();                if (th instanceof ClassNotFoundException) {                    throw (ClassNotFoundException) th;                } else if (th instanceof IOException) {                    throw (IOException) th;                } else {                    throwMiscException(th);                }            } catch (IllegalAccessException ex) {                // should not occur, as access checks have been suppressed                throw new InternalError();            }        } else {            throw new UnsupportedOperationException();        }    }

invoke方法即是通过反射机制调用,故readObject方法private也是可以的,而且用private修饰以后,还能防止子类Override

ObjectOutputStream 与ObjectInputStream类似:

public final void writeObject(Object obj) throws IOException {        if (enableOverride) {            writeObjectOverride(obj);            return;        }        try {            writeObject0(obj, false);        } catch (IOException ex) {            if (depth == 0) {                writeFatalException(ex);            }            throw ex;        }}

writeObject也支持通过enableOverride方式扩展,被Override,也是调用的writeObject0方法,writeObject0方法里也有一个条件判断语句:

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());       }}

也是根据类型调用不同的处理方法,以实现Serializable接口的为例:

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);            handles.assign(unshared ? null : obj);            if (desc.isExternalizable() && !desc.isProxy()) {                writeExternalData((Externalizable) obj);            } else {                writeSerialData(obj, desc);            }        } finally {            if (extendedDebugInfo) {                debugInfoStack.pop();            }        }    }

也是根据Serializable和Externalizable接口的不同调用不同的方法,具体就不贴出源码了

看的比较粗糙,后面继续完善

0 0
原创粉丝点击