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

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如下所示,如果你想深入学习可以参照https://github.com/google/protobuf

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原生序列化。对于序列化耗时,上面的测试不准。

还是去看看专业测试分析吧,具体情况可以进去看看https://github.com/eishay/jvm-serializers/wiki

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

(0)

相关推荐

  • 浅谈java中为什么实体类需要实现序列化

    当客户端访问某个能开启会话功能的资源,web服务器就会创建一个HTTPSession对象,每个HTTPSession对象都会占用一定的内存,如果在同一个时间段内访问的用户太多,就会消耗大量的服务器内存,为了解决这个问题我们使用一种技术:session的持久化. 什么是session的持久化? web服务器会把暂时不活动的并且没有失效的HTTPSession对象转移到文件系统或数据库中储存,服务器要用时在把他们转载到内存. 把Session对象转移到文件系统或数据库中储存就需要用到序列化: jav

  • 深入浅析Java Object Serialization与 Hadoop 序列化

    一,Java Object Serialization 1,什么是序列化(Serialization) 序列化是指将结构化对象转化为字节流以便在网络上传输或者写到磁盘永久存储的过程.反序列化指将字节流转回结构化对象的逆过程.简单的理解就是对象转换为字节流用来传输和保存,字节流转换为对象将对象恢复成原来的状态. 2,序列化(Serialization)的作用 (1)一种持久化机制,把的内存中的对象状态保存到一个文件中或者数据库. (2)一种通信机制,用套接字在网络上传送对象. (3)Java远程方

  • Java 对象序列化 NIO NIO2详细介绍及解析

    Java 对象序列化 NIO NIO2详细介绍及解析 概要: 对象序列化 对象序列化机制允许把内存中的Java对象转换成与平台无关的二进制流,从而可以保存到磁盘或者进行网络传输,其它程序获得这个二进制流后可以将其恢复成原来的Java对象. 序列化机制可以使对象可以脱离程序的运行而对立存在 序列化的含义和意义 序列化 序列化机制可以使对象可以脱离程序的运行而对立存在 序列化(Serialize)指将一个java对象写入IO流中,与此对应的是,对象的反序列化(Deserialize)则指从IO流中恢

  • java中fastjson生成和解析json数据(序列化和反序列化数据)

    本文讲解2点: 1. fastjson生成和解析json数据 (举例:4种常用类型:JavaBean,List<JavaBean>,List<String>,List<Map<String,Object>) 2.通过一个android程序测试fastjson的用法. fastjson简介: Fastjson是一个Java语言编写的高性能功能完善的JSON库.fastjson采用独创的算法,将parse的速度提升到极致,超过所有json库,包括曾经号称最快的jack

  • java 中Spark中将对象序列化存储到hdfs

    java 中Spark中将对象序列化存储到hdfs 摘要: Spark应用中经常会遇到这样一个需求: 需要将JAVA对象序列化并存储到HDFS, 尤其是利用MLlib计算出来的一些模型, 存储到hdfs以便模型可以反复利用. 下面的例子演示了Spark环境下从Hbase读取数据, 生成一个word2vec模型, 存储到hdfs. 废话不多说, 直接贴代码了. spark1.4 + hbase0.98 import org.apache.spark.storage.StorageLevel imp

  • java 序列化与反序列化的实例详解

     1.Java序列化与反序列化 Java序列化是指把Java对象转换为字节序列的过程:而Java反序列化是指把字节序列恢复为Java对象的过程.  2.为什么需要序列化与反序列化 我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本.图片.音频.视频等, 而这些数据都会以二进制序列的形式在网络上传送.那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的.如何做到呢?这就需要Java序列化与反序列化了.换句话说,一方面,发送方需要把这个Java对象转换为字

  • java 中序列化与readResolve()方法的实例详解

    java 中序列化与readResolve()方法的实例详解 readResolve方法是作用是什么?这个方法跟对象的序列化相关(这样倒是解释了为什么 readResolve方法是private修饰的). 怎么跟对象的序列化相关了? 下面我们先简要地回顾下对象的序列化.一般来说,一个类实现了 Serializable接口,我们就可以把它往内存地写再从内存里读出而"组装"成一个跟原来一模一样的对象.不过当序列化遇到单例时,里边就有了个问题:从内存读出而组装的对象破坏了单例的规则.单例是要

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

    0.前言 本文主要对几种常见Java序列化方式进行实现.包括Java原生以流的方法进行的序列化.Json序列化.FastJson序列化.Protobuff序列化. 1.Java原生序列化 Java原生序列化方法即通过Java原生流(InputStream和OutputStream之间的转化)的方式进行转化.需要注意的是JavaBean实体类必须实现Serializable接口,否则无法序列化.Java原生序列化代码示例如下所示: package serialize; import java.io

  • 深入理解 Redis Template及4种序列化方式

    概述 使用Spring 提供的 Spring Data Redis 操作redis 必然要使用Spring提供的模板类 RedisTemplate, 今天我们好好的看看这个模板类 . RedisTemplate 看看4个序列化相关的属性 ,主要是 用于 KEY 和 VALUE 的序列化 . 举个例子,比如说我们经常会将POJO 对象存储到 Redis 中,一般情况下会使用 JSON 方式序列化成字符串,存储到 Redis 中 . Spring提供的Redis数据结构的操作类 ValueOpera

  • Java Kryo,Protostuff,Hessian序列化方式对比

    目录 前言 性能对比 前期准备 序列化后字节所占空间大小比较 其他比较 小结 前言 前段时间在写RPC框架的时候用到了Kryo.Hessian.Protostuff三种序列化方式.但是当时因为急于实现功能,就只是简单的的看了一下如何使用这三种序列化方式,并没有去深入研究各自的特性,以及优点和缺点.知道现在就将RPC框架写完了之后,才有时间静下心来对三种方式做一个对比,总结. Kryo.Hessain.Protostuff都是第三方开源的序列化/反序列化框架,要了解其各自的特性,我们首先需要知道序

  • Java的四种引用方式

    目录 1.强引用(StrongReference) 2.软引用(SoftReference) 3.弱引用(WeakReference) 4.虚引用(PhantomReference) 5. 引用队列(ReferenceQueue) 1.强引用(StrongReference) 使用最普遍的引用. 只要引用链没有断开,强引用就不会断开.- 当内存空间不足,抛出OutOfMemoryError终止程序也不会回收具有强引用的对象. 通过将对象设置为null来弱化引用,使其被回收 Object obje

  • Java倒计时三种实现方式代码实例

    写完js倒计时,突然想用java实现倒计时,写了三种实现方式 一:设置时长的倒计时: 二:设置时间戳的倒计时: 三:使用java.util.Timer类实现的时间戳倒计时 代码如下: package timer; import java.util.Calendar; import java.util.Date; import java.util.Timer; import java.util.TimerTask; /** * java演示倒计时 * */ public class TimeTes

  • Java中对象的序列化方式克隆详解

    Java 序列化技术可以使你将一个对象的状态写入一个Byte 流里,并且可以从其它地方把该Byte 流里的数据读出来,重新构造一个相同的对象. 简述: 用字节流的方式,复制Java对象 代码: 流克隆复制函数 public static Object deepClone(Object obj){ if(obj == null){ return null; } try { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); Ob

  • 详解Java的四种引用方式及其区别

    java内存管理分为内存分配和内存回收,都不需要程序员负责,垃圾回收的机制主要是看对象是否有引用指向该对象. java对象的引用包括 强引用,软引用,弱引用,虚引用 Java中提供这四种引用类型主要有两个目的: 第一是可以让程序员通过代码的方式决定某些对象的生命周期: 第二是有利于JVM进行垃圾回收. 下面来阐述一下这四种类型引用的概念: 1.强引用 是指创建一个对象并把这个对象赋给一个引用变量. 比如: Object object =new Object(); String str ="hel

  • java单例模式4种使用方式分享

    1.Java Concurrency In Practice的List 复制代码 代码如下: public class Singleton {      private static class SingletonHolder {          public static Singleton resource = new Singleton();      }      public static Singleton getResource() {          return  Sing

  • java常见的序列化方式

    在远程调用中,需要把参数和返回值通过网络传输,这个使用就要用到序列化将对象转变成字节流,从一端到另一端之后再反序列化回来变成对象. 既然前面有一篇提到了hessian,这里就简单讲讲Java序列化和hessian序列化的区别. 首先,hessian序列化比Java序列化高效很多,而且生成的字节流也要短很多.但相对来说没有Java序列化可靠,而且也不如Java序列化支持的全面.而之所以会出现这样的区别,则要从它们的实现方式来看. 先说Java序列化,具体工作原理就不说了,Java序列化会把要序列化

  • Java定时任务的三种实现方式

    前言 现代的应用程序早已不是以前的那些由简单的增删改查拼凑而成的程序了,高复杂性早已是标配,而任务的定时调度与执行也是对程序的基本要求了. 很多业务需求的实现都离不开定时任务,例如,每月一号,移动将清空你上月未用完流量,重置套餐流量,以及备忘录提醒.闹钟等功能. Java 系统中主要有三种方式来实现定时任务: Timer和TimerTask ScheduledExecutorService 三方框架 Quartz 下面我们一个个来看. Timer和TimerTask 先看一个小 demo,接着我

随机推荐