欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java实现几种序列化方式总结

程序员文章站 2024-03-04 20:44:18
0、前言 本文主要对几种常见java序列化方式进行实现。包括java原生以流的方法进行的序列化、json序列化、fastjson序列化、protobuff序列化。 1、...

0、前言

本文主要对几种常见java序列化方式进行实现。包括java原生以流的方法进行的序列化、json序列化、fastjson序列化、protobuff序列化。

1、java原生序列化

java原生序列化方法即通过java原生流(inputstream和outputstream之间的转化)的方式进行转化。需要注意的是javabean实体类必须实现serializable接口,否则无法序列化。java原生序列化代码示例如下所示:

package serialize;

import java.io.bufferedinputstream;
import java.io.bytearrayoutputstream;
import java.io.ioexception;
import java.io.objectinputstream;
import java.io.objectoutputstream;
import java.util.arraylist;
import java.util.list;
/**
 * 
 * @author liqqc
 *
 */
public class javaserialize {
  public static void main(string[] args) throws classnotfoundexception, ioexception {
    new javaserialize().start();
  }

  public void start() throws ioexception, classnotfoundexception {
    user u = new user();
    list<user> friends = new arraylist<>();
    u.setusername("张三");
    u.setpassword("123456");
    u.setuserinfo("张三是一个很牛逼的人");
    u.setfriends(friends);

    user f1 = new user();
    f1.setusername("李四");
    f1.setpassword("123456");
    f1.setuserinfo("李四是一个很牛逼的人");

    user f2 = new user();
    f2.setusername("王五");
    f2.setpassword("123456");
    f2.setuserinfo("王五是一个很牛逼的人");

    friends.add(f1);
    friends.add(f2);

    long t1 = system.currenttimemillis();
    bytearrayoutputstream out = new bytearrayoutputstream();
    objectoutputstream obj = new objectoutputstream(out);
    for(int i = 0; i<10; i++) {
      obj.writeobject(u);
    }
    system.out.println("java serialize: " +(system.currenttimemillis() - t1) + "ms; 总大小:" + out.tobytearray().length );

    long t2 = system.currenttimemillis();
    objectinputstream ois = new objectinputstream(new bufferedinputstream(new java.io.bytearrayinputstream(out.tobytearray())));
    user user = (user) ois.readobject();
    system.out.println("java deserialize: " + (system.currenttimemillis() - t2) + "ms; user: " + user);
  }

}

运行结果:

java serialize: 8ms; 总大小:420

复制代码 代码如下:

java deserialize: 1ms; user: user [userid=null, username=张三, password=123456, userinfo=张三是一个很牛逼的人, friends=[user [userid=null, username=李四, password=123456, userinfo=李四是一个很牛逼的人, friends=null], user [userid=null, username=王五, password=123456, userinfo=王五是一个很牛逼的人, friends=null]]]

2、json序列化

json序列化一般会使用jackson包,通过objectmapper类来进行一些操作,比如将对象转化为byte数组或者将json串转化为对象。现在的大多数公司都将json作为服务器端返回的数据格式。比如调用一个服务器接口,通常的请求为xxx.json?a=xxx&b=xxx的形式。json序列化示例代码如下所示:

package serialize;

import java.io.ioexception;
import java.util.arraylist;
import java.util.list;

import com.fasterxml.jackson.databind.objectmapper;
/**
 * 
 * @author liqqc
 *
 */
public class jsonserialize {
  public static void main(string[] args) throws ioexception {
    new jsonserialize().start();
  }

  public void start() throws ioexception {
    user u = new user();
    list<user> friends = new arraylist<>();
    u.setusername("张三");
    u.setpassword("123456");
    u.setuserinfo("张三是一个很牛逼的人");
    u.setfriends(friends);

    user f1 = new user();
    f1.setusername("李四");
    f1.setpassword("123456");
    f1.setuserinfo("李四是一个很牛逼的人");

    user f2 = new user();
    f2.setusername("王五");
    f2.setpassword("123456");
    f2.setuserinfo("王五是一个很牛逼的人");

    friends.add(f1);
    friends.add(f2);

    objectmapper mapper = new objectmapper();
    long t1 = system.currenttimemillis();
    byte[] writevalueasbytes = null;
    for (int i = 0; i < 10; i++) {
      writevalueasbytes = mapper.writevalueasbytes(u);
    }
    system.out.println("json serialize: " + (system.currenttimemillis() - t1) + "ms; 总大小:" + writevalueasbytes.length);
    long t2 = system.currenttimemillis();
    user user = mapper.readvalue(writevalueasbytes, user.class);
    system.out.println("json deserialize: " + (system.currenttimemillis() - t2) + "ms; user: " + user);

  }
}

运行结果:

json serialize: 55ms; 总大小:341

复制代码 代码如下:

json deserialize: 35ms; user: user [userid=null, username=张三, password=123456, userinfo=张三是一个很牛逼的人, friends=[user [userid=null, username=李四, password=123456, userinfo=李四是一个很牛逼的人, friends=null], user [userid=null, username=王五, password=123456, userinfo=王五是一个很牛逼的人, friends=null]]]

3、fastjson序列化

fastjson 是由阿里巴巴开发的一个性能很好的java 语言实现的 json解析器和生成器。特点:速度快,测试表明fastjson具有极快的性能,超越任其他的java json parser。功能强大,完全支持java bean、集合、map、日期、enum,支持范型和自省。无依赖,能够直接运行在java se 5.0以上版本

支持android。使用时候需引入fastjson第三方jar包。fastjson序列化代码示例如下所示:

package serialize;

import java.util.arraylist;
import java.util.list;

import com.alibaba.fastjson.json;
/**
 * 
 * @author liqqc
 *
 */
public class fastjsonserialize {

  public static void main(string[] args) {
    new fastjsonserialize().start();
  }

  public void start(){
    user u = new user();
    list<user> friends = new arraylist<>();
    u.setusername("张三");
    u.setpassword("123456");
    u.setuserinfo("张三是一个很牛逼的人");
    u.setfriends(friends);

    user f1 = new user();
    f1.setusername("李四");
    f1.setpassword("123456");
    f1.setuserinfo("李四是一个很牛逼的人");

    user f2 = new user();
    f2.setusername("王五");
    f2.setpassword("123456");
    f2.setuserinfo("王五是一个很牛逼的人");

    friends.add(f1);
    friends.add(f2);

    //序列化 
    long t1 = system.currenttimemillis();
    string text = null;
    for(int i = 0; i<10; i++) {
      text = json.tojsonstring(u); 
    }
    system.out.println("fastjson serialize: " +(system.currenttimemillis() - t1) + "ms; 总大小:" + text.getbytes().length);
    //反序列化 
    long t2 = system.currenttimemillis();
    user user = json.parseobject(text, user.class);
    system.out.println("fastjson serialize: " + (system.currenttimemillis() -t2) + "ms; user: " + user);
  }
}

运行结果:

fastjson serialize: 284ms; 总大小:269

复制代码 代码如下:

fastjson serialize: 26ms; user: user [userid=null, username=张三, password=123456, userinfo=张三是一个很牛逼的人, friends=[user [userid=null, username=李四, password=123456, userinfo=李四是一个很牛逼的人, friends=null], user [userid=null, username=王五, password=123456, userinfo=王五是一个很牛逼的人, friends=null]]]

4、protobuff序列化

protocolbuffer是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化。适合做数据存储或 rpc 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

优点:跨语言;序列化后数据占用空间比json小,json有一定的格式,在数据量上还有可以压缩的空间。

缺点:它以二进制的方式存储,无法直接读取编辑,除非你有 .proto 定义,否则无法直接读出 protobuffer的任何内容。

其与thrift的对比:两者语法类似,都支持版本向后兼容和向前兼容,thrift侧重点是构建跨语言的可伸缩的服务,支持的语言多,同时提供了全套rpc解决方案,可以很方便的直接构建服务,不需要做太多其他的工作。 protobuffer主要是一种序列化机制,在数据序列化上进行性能比较,protobuffer相对较好。

protobuff序列化对象可以很大程度上将其压缩,可以大大减少数据传输大小,提高系统性能。对于大量数据的缓存,也可以提高缓存中数据存储量。原始的protobuff需要自己写.proto文件,通过编译器将其转换为java文件,显得比较繁琐。百度研发的jprotobuf框架将google原始的protobuf进行了封装,对其进行简化,仅提供序列化和反序列化方法。其实用上也比较简洁,通过对javabean中的字段进行注解就行,不需要撰写.proto文件和实用编译器将其生成.java文件,百度的jprotobuf都替我们做了这些事情了。

一个带有jprotobuf注解的javabean如下所示,如果你想深入学习可以参照。

package serialize;

import java.io.serializable;
import java.util.list;
import com.baidu.bjf.remoting.protobuf.fieldtype;
import com.baidu.bjf.remoting.protobuf.annotation.protobuf;

public class user implements serializable {
  private static final long serialversionuid = -7890663945232864573l;

  @protobuf(fieldtype = fieldtype.int32, required = false, order = 1)
  private integer userid;

  @protobuf(fieldtype = fieldtype.string, required = false, order = 2)
  private string username;

  @protobuf(fieldtype = fieldtype.string, required = false, order = 3)
  private string password;

  @protobuf(fieldtype = fieldtype.string, required = false, order = 4)
  private string userinfo;

  @protobuf(fieldtype = fieldtype.object, required = false, order = 5)
  private list<user> friends;

  public integer getuserid() {
    return userid;
  }

  public void setuserid(integer userid) {
    this.userid = userid;
  }

  public string getusername() {
    return username;
  }

  public void setusername(string username) {
    this.username = username;
  }

  public string getpassword() {
    return password;
  }

  public void setpassword(string password) {
    this.password = password;
  }

  public string getuserinfo() {
    return userinfo;
  }

  public void setuserinfo(string userinfo) {
    this.userinfo = userinfo;
  }

  public list<user> getfriends() {
    return friends;
  }

  public void setfriends(list<user> friends) {
    this.friends = friends;
  }

  @override
  public string tostring() {
    return "user [userid=" + userid + ", username=" + username + ", password=" + password + ", userinfo=" + userinfo
        + ", friends=" + friends + "]";
  }

}

jprotobuf序列化代码示例如下所示:

package serialize;

import java.io.ioexception;
import java.util.arraylist;
import java.util.list;

import com.baidu.bjf.remoting.protobuf.codec;
import com.baidu.bjf.remoting.protobuf.protobufproxy;
/**
 * 
 * @author liqqc
 *
 */
public class protobuffserialize {

  public static void main(string[] args) throws ioexception {
    new protobuffserialize().start();
  }

  public void start() throws ioexception {
    codec<user> studentclasscodec = protobufproxy.create(user.class, false);

    user u2 = new user();
    list<user> friends = new arraylist<>();
    u2.setusername("张三");
    u2.setpassword("123456");
    u2.setuserinfo("张三是一个很牛逼的人");
    u2.setfriends(friends);

    user f1 = new user();
    f1.setusername("李四");
    f1.setpassword("123456");
    f1.setuserinfo("李四是一个很牛逼的人");

    user f2 = new user();
    f2.setusername("王五");
    f2.setpassword("123456");
    f2.setuserinfo("王五是一个很牛逼的人");
    friends.add(f1);
    friends.add(f2);

    long stime_jpb_encode = system.currenttimemillis();
    byte[] bytes = null;
    for(int i = 0; i<10; i++) {
      bytes = studentclasscodec.encode(u2);
    }
    system.out.println("jprotobuf序列化耗时:" + (system.currenttimemillis() - stime_jpb_encode) + "ms; 总大小:" + bytes.length);

    long stime_jpb_decode = system.currenttimemillis();
    user user = studentclasscodec.decode(bytes);
    long etime_jpb_decode = system.currenttimemillis();
    system.out.println("jprotobuf反序列化耗时:"+ (etime_jpb_decode-stime_jpb_decode) + "ms; user: " + user);
  }

}

运行结果:

jprotobuf序列化耗时:9ms; 总大小:148

复制代码 代码如下:

jprotobuf反序列化耗时:0ms; user: user [userid=null, username=张三, password=123456, userinfo=张三是一个很牛逼的人, friends=[user [userid=null, username=李四, password=123456, userinfo=李四是一个很牛逼的人, friends=null], user [userid=null, username=王五, password=123456, userinfo=王五是一个很牛逼的人, friends=null]]]

5、总结

我们通过main方法来进行对比测试,(但是通过测试发现少量数据无法准确显示每种序列化方式的优劣,故这里无法给出比较好的答案,仅供参考)。示例代码如下所示:

package serialize;

import java.io.ioexception;

/**
 * @author liqqc
 */
public class main {

  public static void main(string[] args) throws ioexception, classnotfoundexception {

    protobuffserialize protobuffserialize = new protobuffserialize();
    protobuffserialize.start();

    system.err.println();
    system.err.println();

    javaserialize javaserialize = new javaserialize();
    javaserialize.start();
    system.err.println();

    jsonserialize jsonserialize = new jsonserialize();
    jsonserialize.start();
    system.err.println();

    fastjsonserialize fastjsonserialize = new fastjsonserialize();
    fastjsonserialize.start();
  }
}

运行结果:

jprotobuf序列化耗时:7ms; 总大小:148
jprotobuf反序列化耗时:0ms

java serialize: 6ms; 总大小:420
java deserialize: 1ms

json serialize: 37ms; 总大小:341
json deserialize: 27ms

fastjson serialize: 173ms; 总大小:269
fastjson serialize: 35ms

上面的测试仅供参考,并不能代表通过大量数据进行测试的结果。可以发现:序列化后对象的所占大小上:protobuff序列化所占总大小是最少的;其次是fastjson序列化;最后是json序列化和java原生序列化。对于序列化耗时,上面的测试不准。

还是去看看专业测试分析吧,具体情况可以进去看看

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。