美文网首页
Serializable对象/数据序列化

Serializable对象/数据序列化

作者: kjy_112233 | 来源:发表于2017-08-12 14:19 被阅读0次

    一、Serializable详解

    • Serializalbe这种简单机制是通过牺牲掉执行性能为代价换来的。通过Serializable将对象持久化存储,也可以通过Bundle传递Serializable的序列化数据。
    • 什么是序列化:把一个Object对象的所有信息表示成一个字节序列,这包括Class信息、继承关系、访问权限、变量类型以及数值信息等。

    (1)Serializable实现类

    public class Person implements Serializable {
        public String name;
        public static int age;
        public transient int sex;
    
        public Person(String name) {
            this.name = name;
        }
    }
    
    • 将Person对象序列化与反序列化
            Person person = new Person();
            //定义一个字节数组输出流
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream outputStream;
            try {
                outputStream = new ObjectOutputStream(byteArrayOutputStream);
                //将指定的对象写入字节数组输出,进行序列化
                outputStream.writeObject(person);
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            byte[] bytes = byteArrayOutputStream.toByteArray();
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
            ObjectInputStream objectInputStream;
            try {
                //执行反序列化,从流中读取对象
                objectInputStream = new ObjectInputStream(byteArrayInputStream);
                Person person1 = (Person) objectInputStream.readObject();
            } catch (ClassNotFoundException | IOException e) {
                e.printStackTrace();
            }
    

    (2)ObjectOutputStream源码

        public ObjectOutputStream(OutputStream out) throws IOException {
            //检查继承权限
            verifySubclass();
            //构造一个BlockDataOutputStream用于向out写入序列化数据
            bout = new BlockDataOutputStream(out);
            //构造一个大小为10,负载因子为3的HandleTable和ReplaceTable
            handles = new HandleTable(10, (float) 3.00);
            subs = new ReplaceTable(10, (float) 3.00);
            //有参构造方法默认为false,
            enableOverride = false;
            writeStreamHeader();
            //将缓存模式打开,写入数据时先写入缓冲区
            bout.setBlockDataMode(true);
            if (extendedDebugInfo) {
                debugInfoStack = new DebugTraceInfoStack();
            } else {
                debugInfoStack = null;
            }
        }
    
        public final void writeObject(Object obj) throws IOException {
            //判断是否需要重写writeObject(),无参构造函数该变量默认为true,有参为false。
            if (enableOverride) {
                writeObjectOverride(obj);
                return;
            }
            try {
                writeObject0(obj, false);
            } catch (IOException ex) {
                if (depth == 0) {
                    try {
                        writeFatalException(ex);
                    } catch (IOException ex2) {
                    }
                }
                throw ex;
            }
        }
    
        private void writeObject0(Object obj, boolean unshared)
            throws IOException
        {
            boolean oldMode = bout.setBlockDataMode(false);
            depth++;
            try {
                //处理以前写入的和不可替换的对象
                int h;
                if ((obj = subs.lookup(obj)) == null) {
                    writeNull();
                    return;
                } else if (!unshared && (h = handles.lookup(obj)) != -1) {
                    writeHandle(h);
                    return;
                }
                Object orig = obj;
                Class<?> cl = obj.getClass();
                ObjectStreamClass desc;
    
                Class repCl;
                //ObjectStreamClass表示序列化对象的class详细信息
                desc = ObjectStreamClass.lookup(cl, true);
                if (desc.hasWriteReplaceMethod() &&
                    (obj = desc.invokeWriteReplace(obj)) != null &&
                    (repCl = obj.getClass()) != cl)
                {
                    cl = repCl;
                    //生成替换对象类型的ObjectStreamClass
                    desc = ObjectStreamClass.lookup(cl, true);
                }
    
                if (enableReplace) {
                    Object rep = replaceObject(obj);
                    if (rep != obj && rep != null) {
                        cl = rep.getClass();
                        desc = ObjectStreamClass.lookup(cl, true);
                    }
                    //重新赋值要序列化的对象
                    obj = rep;
                }
    
                //如果替换了对象,请再次运行原始检查
                if (obj != orig) {
                    subs.assign(orig, obj);
                    if (obj == null) {
                        writeNull();
                        return;
                    } else if (!unshared && (h = handles.lookup(obj)) != -1) {
                        writeHandle(h);
                        return;
                    }
                }
                if (obj instanceof Class) {
                    writeClass((Class) obj, unshared);
                } else if (obj instanceof ObjectStreamClass) {
                    writeClassDesc((ObjectStreamClass) obj, unshared);
                // END Android-changed:  Make Class and ObjectStreamClass replaceable.
                } else 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() + "\n" + debugInfoStack.toString());
                    } else {
                        throw new NotSerializableException(cl.getName());
                    }
                }
            } finally {
                depth--;
                bout.setBlockDataMode(oldMode);
            }
        }
    

    (3)ObjectInputStream源码

        public ObjectInputStream(InputStream in) throws IOException {
            verifySubclass();
            bin = new BlockDataInputStream(in);
            handles = new HandleTable(10);
            vlist = new ValidationList();
            enableOverride = false;
            readStreamHeader();
            bin.setBlockDataMode(true);
        }
    
        public final Object readObject()
            throws IOException, ClassNotFoundException
        {
            if (enableOverride) {
                return readObjectOverride();
            }
    
            // if nested read, passHandle contains handle of enclosing object
            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;
            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);
            }
        }
    
    • Serializable 序列化支持替代默认流程,它会先反射判断是否存在我们自己实现的序列化方法 writeObject 或 反序列化方法 readObject。通过这两个方法,我们可以对某些字段做一些特殊修改,也可以实现序列化的加密功能。

    • 我们可以通过 writeReplace 和 readResolve 方法实现自定义返回的序列化实例。通过它们实现对序列化的版本兼容,例如通过 readResolve 方法可以把老版本的序列化对象转换成新版本的对象类型。

    • Serializable 整个序列化过程使用了大量的反射和临时变量,而且在序列化对象的时候,不仅会序列化当前对象本身,还需要递归序列化引用的其它对象。

    • 不被序列化字段。类的 static 变量以及被声明为 transient 的字段,默认的序列化机制都会忽略该字段,不会进行序列化存储。当然我们也可以使用进阶的 writeObject 和 readObject 方法做自定义的序列化存储。

    • serialVersionUID。在类实现了 Serializable 接口后,我们需要添加一个 Serial Version ID,它相当于类的版本号。这个 ID 我们可以显示声明也可以让编译器自己计算。通常建议显示声明会更加稳妥,因为隐士声明假如类发生了一点点变化,进行反序列化都会由于 serialVersionUID 改变而导致 InvalidClassException 异常。

    • 构造方法。Serializable 的反序列化默认是不会执行构造函数的,它是根据数据流中对 Object 的描述信息创建对象的。如果一些逻辑依赖构造函数,就可能会出现问题,例如一个静态变量只在构造方法中赋值,当然我们也可以通过进阶的自定义反序列化修改。

    相关文章

      网友评论

          本文标题:Serializable对象/数据序列化

          本文链接:https://www.haomeiwen.com/subject/qmqjrxtx.html