Java中的序列化

Java中的序列化不是很复杂,用的面比较广,很基础的内容,而且平时都会涉及到,所以了解这块内容帮助很大。

序列化主要用在RPC通信,数据存储,还有前后台交互(目前客户端向服务器通讯也都用JSON了),等等等等。像平时用到的服务治理框架、MVC架构,都会涉及到,可能有的时候,被包装很好,以至于用的人都没有感觉到。

序列化的种类。这个所谓的种类,是我自己的笔记里面写的,并不是老师教过来的。是为了方便在学的时候理顺条理。

  •     二进制
  •     JSON
  •     XML

首先,二进制序列化。是将要序列化的内容(原始类型相当简单,主要是对象),用一定的位编排格式拼装成二进制流的形式。比如对一个对象(包含A、B、C三个属性)序列化,会使用这种方式生成一个二进制数组:类名|参数A类型:参数A的值|参数B类型:参数B的值|参数C类型:参数C的值。而后反序列化,也会使用这个格式,再把这个二进制数组,反序列化成一个对象。


一,二进制序列化的工具有很多种。主要有Java自带的ObjectOutputStream、Hessian、Thrift、Protostuff、ProtocolBuffer、MessagePack、Avro、Kryo等。看起来很乱,没时间的话主要了解前三个就好。

    1,Java原生二进制序列化。使用方式如  :      

    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(new Person("wang", new Date(), 20));

        生成的结果为:

        �� sr 'name.gary.vo.Person I ageL birthdayt Ljava/util/Date;L namet Ljava/lang/String;xp   sr java.util.DatehjKYt  xpw  a2'xt lisi

        这个方式支持循环引用。的缺点就是对类修改的适应性太差,有点类改动就出问题。平时两个模块通讯接口类就必须特别严谨,还有就是有时候会导致在消息队列消费时反序列化出错。

2,Hessian二进制序列化。使用方式如:

    Hessian2Output hessianOutput = new Hessian2Output(baos);
    hessianOutput.writeObject(new Person("wang", new Date(), 21));

        生成结果为:

    C0'name.gary.vo.Personnameagebirthday`zhangsanJ  a2'

        想对比之下,Hessian比原生的序列化结果,简洁很多。可以看得出,属性的类型已经被省略了。可以通过ExtSerializeFactory类进行扩展。Hessian的循环对象引用,是通过在内部维护一个IdentityHashMap的对象池,当遇到已经操作过的对象时,就会使用一种引用方式。

    3,Protostuff二进制序列化。使用方式如:

    GraphIOUtil.toByteArray(new Person("lisi", new Date(), 20), schema, LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));

        生成结果为:

    lisiy��6a

        这个结果比之前的两个,更加简洁,连类名都没有了。但是Protostuff支持循环引用的话,需要设置为graph模式。而且在一个嵌套自引用的反序列化时,Protostuff反序列化出了两个对象,而不是一个对象的引用。

    4,MessagePack二进制序列化。使用方法如:

msgpack.register(Person.class);
msgpack.write(new Person("wang", new Date(), 20));

        生成结果有:

            ��lisi  a3���

        生成对象时,是需要提前注册的如:msgpack.register(Person.class);而且不支持嵌套引用。

    5,Kroyo二进制序列化。使用方法:

    kryo.writeObject(output, new Person("zhangsan", new Date(), 20));
            或
    kryo.writeClassAndObject(output, new Person("lisi", new Date(), 20));

        生成结果:        

    ( java.util.Dat̂���,zhangsan

        或

    name.gary.vo.Perso(java.util.Datɵ��,lis

    MessagePack本身支持两种方法,差别从方法名可以看出来。默认支持循环对象引用,不会死循环。而且他默认的序列化编码竟然是Base64。

至于Avro、Thrift、PB,由于其设计是跨语言,需要使用工具生成很多内容。就不再演示。


二,JSON序列化。

    这个有点开发经验的人,应该都使用过,业务开发时比较常用。

    主要工具有FastJson、Jackson、gson,还有一个JsonLib的包,由于代码维护已经很不活跃且依赖和使用都比较复杂,就不再考虑。

    1,fastjson,是阿里开源的一个工具。使用方式:

    JSON.toJSONString
        一个简单的序列化结果为:
    {"age":21,"birthday":1517063537248,"me":{"$ref":"@"},"name":"shangsan","wife":{"age":18,"name":"li"}}

    2,Jackson,使用的也比较普遍。向Spring框架默认都会使用此工具。

        使用方式:

    objectmapper.writeValueAsString(person);

        序列化结果为:

    {"name":"zhangsan","birthday":null,"age":30,"wife":null,"me":null}

        jackson在循环引用时抛错,解决的话需要使用注解JsonIgnoreProperties或关键字transient,人为阻断。但这种方式指标不治本,而且不是我要的结果。

    3,Gson,循环运用好像也不行。

        使用方式:

    gson.toJson(new Person("zhangsan", new Date(), 21));

        序列化结果:

    {"age":21,"birthday":1517063537248,"me":{"$ref":"@"},"name":"zhangsan","wife":{"age":18,"name":"li"}}


三,XML序列化。

XML前几面是特别火,火到大多数交流都会提到,大多数面试都会问一下这个内容。但是随着Json的出现和大家对简洁配置的推崇,XML现在很少有人再专门提及了。XML的工具,主要的有DOM操作和对象操作两种。

1,DOM操作工具有javax.xml.parsers和org.w3c.dom包小的一些类。使用时,不会面向对象,而是面向XML文档结构,通过getElementsByTagName、getChildNodes、getAttributes、getNodeName、getNodeValue之类的方法,解析出想要的结果。

2,对象操作,就比较直观了。通过注解配置(如javax.xml.bind包下面的JAXB方式),或代码控制(如org.apache.commons.digester3),使用工具将XML文件与对象透明转换,在代码中可以直接操作对象。当然这个方式比DOM操作简单方便一些。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值