Java的序列化机制

          Java序列化机制允许将实现序列化后的Java对象转换为字节序列, 这些字节序列可以保存在磁盘上, 或通过网络传输, 最后可以通过反序列化转换为原来的Java对象。对象序列化得到的字节序列包括该对象的数据, 有关对象类型的信息和存储在对象中数据的类型。整个过程都是Java虚拟机独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象。类ObjectOutputStream 和 ObjectInputStream是高层次的数据流, 它们包含反序列化和序列化对象的方法。一个类的对象要想序列化成功,必须满足两个条件:

1.该类必须实现java.io.Serializable 接口

2. 该类的所有属性必须是可序列化的。如果有属性不是可序列化的,则该属性必须注明是短暂的。

  1.  序列化的实现。

      首先,调用ObjectOutputStream的 writeObject(Object obj)方法

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

    在方法中,调用writeObject0(obj, false)方法,进行输出。

   /**
     * Underlying writeObject/writeUnshared implementation.
     */
    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();
            //序列化对象对应的Class对象的详细信息
            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;
                }
            }

         
            //序列化对象为字符串,数组,枚举时,调用定制的写入方法
            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) {
                //2. 一般对象的写入,实现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);
        }
    }

     判断对象属于序列化对象,然后调用 writeOrnaryObject(obj, desc, unshared)方法。

    /**
     * Writes representation of a "ordinary" (i.e., not a String, Class,
     * ObjectStreamClass, array, or enum constant) serializable object to the
     * stream.
     */
    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();
            }
        }
    }

下面看下writeSerialData(obj, desc)

    /**
     * Writes instance data for each serializable class of given object, from
     * superclass to subclass.
     */
    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方法,则执行这个代码块
                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);
            }
        }
    }

 defaultWriteFields(obj, slotDesc) 方法对要序列化的对象数据进行处理,包括基本类型的字段和对象类型的字段。其中方法的参数ObjectStreamClass存储了一个Class对象的信息,其实例变量包括:Class对象,Class名称,serialVersionUID,实现了Serializable接口还是  Externalizable接口,非transient修饰的变量,自定义的writeObject和readObject的Method对象。

   /**
     * Fetches and writes values of serializable fields of given object to
     * stream.  The given class descriptor specifies which field values to
     * write, and in which order they should be written.
     */
    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 (primVals == null || primVals.length < primDataSize) {
            primVals = new byte[primDataSize];
        }
        //获取类的基本类型数据,保存到primVals字节数组
        desc.getPrimFieldValues(obj, primVals);
        //primVals的基本类型数据写到底层字节容器
        bout.write(primVals, 0, primDataSize, false);

        //获取对应类的所有字段对象
        ObjectStreamField[] fields = desc.getFields(false);
        Object[] objVals = new Object[desc.getNumObjFields()];
        int numPrimFields = fields.length - objVals.length;
        //获取类的obj类型数据,保存到objVals字节数组
        desc.getObjFieldValues(obj, objVals);
        //对所有Object类型的字段,循环
        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 {
                //每个Object类型字段写入, 递归调用
                writeObject0(objVals[i],
                             fields[numPrimFields + i].isUnshared());
            } finally {
                if (extendedDebugInfo) {
                    debugInfoStack.pop();
                }
            }
        }
    }

 以上就是Java对象序列化的实现流程。在使用过程中,注意static静态变量和transient 修饰的字段是不会被序列化的。如果某个序列化类的成员变量是对象类型, 该对象类型的类必须实现序列化,否则会抛出NotSerializableException异常。如果子类实现了Serializable,父类没有实现Serializable接口的话, 父类不会被序列化, 经过反序列化可以发现,父类的字段会丢失。Java序列化机制会通过判断类的serialVersionUID来验证版本是否一致。在进行反序列化时, JVM会把传来的字节流中的serialVersionUID和本地相应实体类的serialVersionUID对比,如果相同,则反序列化成功,否则抛出InvalidClassException异常。

上一篇:MySQL模糊查询再也不用like+%了


下一篇:mysql union 中使用order by失效