• java序列化


    1. java序列化的方式

      (1)实现Serializable接口,在方法中定义readObject()与wirteObject()方法(注意这两个方法是要去自己定义的而且固定格式,并不是Serializable接口中定义的方法)

      (2)实现Externalizable接口,并实现writeExternal()与readExternal()方法

    2. java序列化是在ObjectOutPutStream中实现的

    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;
        }
    }
    
    
    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) {
                writeHandle(h);
                return;
            } else if (obj instanceof Class) {
                writeClass((Class) obj, unshared);
                return;
            } else if (obj instanceof 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;
                desc = ObjectStreamClass.lookup(cl, true);
                if (!desc.hasWriteReplaceMethod() ||
                    (obj = desc.invokeWriteReplace(obj)) == null ||
                    (repCl = obj.getClass()) == cl)
                {
                    break;
                }
                cl = repCl;
            }
            if (enableReplace) {
                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) {  //如果对象实现了Serializable接口则调用下面方法进行序列化
                writeOrdinaryObject(obj, desc, unshared);
            } else {
                if (extendedDebugInfo) {
                    throw new NotSerializableException(
                        cl.getName() + "
    " + debugInfoStack.toString());
                } else {
                    throw new NotSerializableException(cl.getName());
                }
            }
        } finally {
            depth--;
            bout.setBlockDataMode(oldMode);
        }
    }
    
    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()) {  //如果实现了Externallizable接口则调用writeExternalData()方法
                writeExternalData((Externalizable) obj);
            } else {
                writeSerialData(obj, desc);         //否则调用writeSerialData()方法
            }
        } finally {
            if (extendedDebugInfo) {
                debugInfoStack.pop();
            }
        }
    }
    
    private void writeSerialData(Object obj, ObjectStreamClass desc)  //次方法中系统默认写入非transient部分
        throws IOException
    {
        ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
        for (int i = 0; i < slots.length; i++) {
            ObjectStreamClass slotDesc = slots[i].desc;
            if (slotDesc.hasWriteObjectMethod()) {
                PutFieldImpl oldPut = curPut;
                curPut = null;
                SerialCallbackContext oldContext = curContext;
    
                if (extendedDebugInfo) {
                    debugInfoStack.push(
                        "custom writeObject data (class "" +
                        slotDesc.getName() + "")");
                }
                try {
                    curContext = new SerialCallbackContext(obj, slotDesc);
                    bout.setBlockDataMode(true);
                    slotDesc.invokeWriteObject(obj, this);
                    bout.setBlockDataMode(false);
                    bout.writeByte(TC_ENDBLOCKDATA);
                } finally {
                    curContext.setUsed();
                    curContext = oldContext;
                    if (extendedDebugInfo) {
                        debugInfoStack.pop();
                    }
                }
    
                curPut = oldPut;
            } else {
                defaultWriteFields(obj, slotDesc);   //主要执行方法
            }
        }
    }
    
    private void defaultWriteFields(Object obj, ObjectStreamClass desc)
        throws IOException
    {
        Class<?> cl = desc.forClass();
        if (cl != null && obj != null && !cl.isInstance(obj)) {
            throw new ClassCastException();
        }
    
        desc.checkDefaultSerialize();
    
        int primDataSize = desc.getPrimDataSize();
        if (primDataSize > 0) {
            if (primVals == null || primVals.length < primDataSize) {
                primVals = new byte[primDataSize];
            }
            desc.getPrimFieldValues(obj, primVals);
            bout.write(primVals, 0, primDataSize, false);
        }
    
        int numObjFields = desc.getNumObjFields();
        if (numObjFields > 0) {
            ObjectStreamField[] fields = desc.getFields(false);
            Object[] objVals = new Object[numObjFields];
            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(objVals[i],
                                 fields[numPrimFields + i].isUnshared());
                } finally {
                    if (extendedDebugInfo) {
                        debugInfoStack.pop();
                    }
                }
            }
        }
    }



    private ObjectStreamClass(final Class<?> cl) {   //ObjectStreamClass类的构造方法
            this.cl = cl;
            name = cl.getName();
            isProxy = Proxy.isProxyClass(cl);
            isEnum = Enum.class.isAssignableFrom(cl);
            serializable = Serializable.class.isAssignableFrom(cl);
            externalizable = Externalizable.class.isAssignableFrom(cl);
    
            Class<?> superCl = cl.getSuperclass();
            superDesc = (superCl != null) ? lookup(superCl, false) : null;
            localDesc = this;
    
            if (serializable) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        if (isEnum) {
                            suid = Long.valueOf(0);
                            fields = NO_FIELDS;
                            return null;
                        }
                        if (cl.isArray()) {
                            fields = NO_FIELDS;
                            return null;
                        }
    
                        suid = getDeclaredSUID(cl);
                        try {
                            fields = getSerialFields(cl);
                            computeFieldOffsets();
                        } catch (InvalidClassException e) {
                            serializeEx = deserializeEx =
                                new ExceptionInfo(e.classname, e.getMessage());
                            fields = NO_FIELDS;
                        }
    
                        if (externalizable) {
                            cons = getExternalizableConstructor(cl);
                        } else {
                            cons = getSerializableConstructor(cl);
                            writeObjectMethod = getPrivateMethod(cl, "writeObject",          //在这里通过反射获取了writeObject方法
                                new Class<?>[] { ObjectOutputStream.class },
                                Void.TYPE);
                            readObjectMethod = getPrivateMethod(cl, "readObject",        //在这里反射获取了readObject方法
                                new Class<?>[] { ObjectInputStream.class },
                                Void.TYPE);
                            readObjectNoDataMethod = getPrivateMethod(
                                cl, "readObjectNoData", null, Void.TYPE);
                            hasWriteObjectData = (writeObjectMethod != null);
                        }
                        domains = getProtectionDomains(cons, cl);
                        writeReplaceMethod = getInheritableMethod(
                            cl, "writeReplace", null, Object.class);
                        readResolveMethod = getInheritableMethod(
                            cl, "readResolve", null, Object.class);
                        return null;
                    }
                });
            } else {
                suid = Long.valueOf(0);
                fields = NO_FIELDS;
            }
    
            try {
                fieldRefl = getReflector(fields, this);
            } catch (InvalidClassException ex) {
                // field mismatches impossible when matching local fields vs. self
                throw new InternalError(ex);
            }
    
            if (deserializeEx == null) {
                if (isEnum) {
                    deserializeEx = new ExceptionInfo(name, "enum type");
                } else if (cons == null) {
                    deserializeEx = new ExceptionInfo(name, "no valid constructor");
                }
            }
            for (int i = 0; i < fields.length; i++) {
                if (fields[i].getField() == null) {
                    defaultSerializeEx = new ExceptionInfo(
                        name, "unmatched serializable field(s) declared");
                }
            }
            initialized = true;
        }
    
    
    
     

    3. 为什么实现Serializable接口是需要自定义两个方法,并且格式固定?

      根据上面的调用过程我们知道,实际上在序列化过程中对象中的这俩个方法是通过放射来调用的,由于调用方法的地方是固定的,所以只能在对象中使用固定的格式来完成。

  • 相关阅读:
    决战72hours
    学习中的十七条建议
    数学建模终结篇
    数学建模(7)建模开始
    ASP升级程序
    为blog挑选logo
    Mysql源代码分析系列(4): 主要调用流程(续)转载
    AS学习步骤
    什么是敏捷软件测试[转]
    Mysql源代码分析(6): Plugin架构介绍(续)转载
  • 原文地址:https://www.cnblogs.com/liwangcai/p/11885266.html
Copyright © 2020-2023  润新知