• Java序列化机制原理


     

     

    Java序列化就是将一个对象转化为一个二进制表示的字节数组,通过保存或则转移这些二进制数组达到持久化的目的。要实现序列化,需要实现java.io.Serializable接口。反序列化是和序列化相反的过程,就是把二进制数组转化为对象的过程。在反序列化的时候,必须有原始类的模板才能将对象还原。从这个过程我们可以猜测到,序列化过程并不想class文件那样保存类的完整的结构信息。下面我们以一个简单的例子来看一下,序列化的时候都保存了哪些信息。代码如下:

    package com.ysl;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    
    public class SerializableTest implements Serializable{
    
        private static final long serialVersionUID = -1L;
        public int num = 2018;
    
        public static void main(String[] args){
            try {
                FileOutputStream fos = new FileOutputStream("serializable");
                ObjectOutputStream oos = new ObjectOutputStream(fos);
                SerializableTest test = new SerializableTest();
                oos.writeObject(test);
                oos.flush();
                oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    序列化后的二进制字节数据如下:

    aced 0005 7372 0018 636f 6d2e 7973 6c2e
    5365 7269 616c 697a 6162 6c65 5465 7374
    ffff ffff ffff ffff 0200 0149 0003 6e75
    6d78 7000 0007 e2

    上述的内容分为一下几个部分:

    第一部分是序列化文件头

    • AC ED :STREAM_MAGIC声明使用了序列化协议
    • 00 05 :STREAM_VERSION序列化协议版本
    • 73 :TC_OBJECT声明这是一个新的对象

    第二部分是序列化的类的描述,在这里是SerializableTest

    • 72 :TC_CLASSDESC声明这里开始一个新的class
    • 00 18:class名字的长度是24个字节
    • 636f 6d2e 7973 6c2e 5365 7269 616c 697a 6162 6c65 5465 7374:SerializableTest的完整类名
    • ffff ffff ffff ffff:serialVersionUID,序列化ID,如果没有指定,则会由算法随机生成一个8字节的ID
    • 02 :标记号,声明该类支持序列化
    • 00 01:该类所包含的域的个数为1

    第三部分是对象中各个属性的描述

    • 49:域类型,49代表I,也就是int类型
    • 00 03:域名字的长度为3
    • 6e 75 6d:num属性的名称

    第四部分为对象的父类信息描述

    SerializableTest没有父类,如果有,和第二部分的描述相同

    • 78 :TC_ENDBLOCKDATA,对象块的结束标志
    • 70:TC_NUL:说明没有其他超类的标志

    第五部分为对象属性的实际值

    如果属性是一个对象,那么这里还将序列化这个对象,规则和第二部分一样

    • 00 0007 e2:数值2018

    虽然Java的序列化能够保证对象状态的持久保存,但是遇到一些对象结构复杂的情况还是比较难处理的,下面是对一些复杂情况的总结:

    • 当父类实现了Serializable接口的时候,所有的子类都能序列化
    • 子类实现了Serializable接口,父类没有,父类中的属性不能被序列化(不报错,但是数据会丢失)
    • 如果序列化的属性是对象,对象必须也能序列化,否则会报错
    • 反序列化的时候,如果对象的属性有修改或则删减,修改的部分属性会丢失,但是不会报错
    • 在反序列化的时候serialVersionUID被修改的话,会反序列化失败
    • 在存Java环境下使用Java的序列化机制会支持的很好,但是在多语言环境下需要考虑别的序列化机制,比如xml,json,或则protobuf
  • 相关阅读:
    如何在视频中添加字幕
    需要查询的东西
    VC++6.0选择打开文件命令时停止工作解决方法
    DMA方式的数据传送过程
    MFC如何创建目录
    opencv配置Debug,
    MFC中关闭窗口的几种办法+MFC中MessageBox的用法
    静态RAM和动态RAM的比较
    openCV学习笔记(2)--cvCreateTrackbar
    WWDC 2015动画效果 transform transition animation 练习
  • 原文地址:https://www.cnblogs.com/shoshana-kong/p/10538643.html
Copyright © 2020-2023  润新知