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

本文仅仅简单介绍了下几种序列化方式的实现,并未经过大量测试对其进行对比分析,待后续有时间和精力在进行补充

Java序列化的方式。的更多相关文章

  1. JAVA - 序列化的方式

    JAVA - 序列化的方式 序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后,可以通过从存储区中读 ...

  2. Java对象表示方式1:序列化、反序列化和transient关键字的作用

    平时我们在Java内存中的对象,是无法进行IO操作或者网络通信的,因为在进行IO操作或者网络通信的时候,人家根本不知道内存中的对象是个什么东西,因此必须将对象以某种方式表示出来,即存储对象中的状态.一 ...

  3. Java序列化的几种方式以及序列化的作用

    Java序列化的几种方式以及序列化的作用 本文着重讲解一下Java序列化的相关内容. 如果对Java序列化感兴趣的同学可以研究一下. 一.Java序列化的作用    有的时候我们想要把一个Java对象 ...

  4. java 的对象拷贝(有深浅拷贝两种方式,深拷贝实现的两种方式(逐层实现cloneable接口,序列化的方式来实现))

    Java提高篇--对象克隆(复制)(转自:http://www.cnblogs.com/Qian123/p/5710533.html#_label0)   阅读目录 为什么要克隆? 如何实现克隆 浅克 ...

  5. java 序列化 serialVersionUID 的作用 和 两种添加方式

    serialVersionUID适用于Java的序列化机制.简单来说,Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的.在进行反序列化时,JVM会把传来的字节流中的 ...

  6. 什么是Java序列化?为什么序列化?序列化有哪些方式?

    先普及一下,计算机中无法识别一个基本单元[字节]来表示,必须经过“翻译”才能让计算机理解人类的语言,这个翻译过程就是[编码],通常所说的字符转换为字节.  有I/O的地方机就会涉及编码,现在几乎所有的 ...

  7. Java对象表示方式1:序列化、反序列化的作用

    1.序列化是的作用和用途 序列化:把对象转换为字节序列的过程称为对象的序列化. 反序列化:把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存 ...

  8. Java序列化的几种方式

    本文着重解说一下Java序列化的相关内容. 假设对Java序列化感兴趣的同学能够研究一下. 一.Java序列化的作用    有的时候我们想要把一个Java对象变成字节流的形式传出去,有的时候我们想要从 ...

  9. 【转】几种Java序列化方式的实现

    0.前言 本文主要对几种常见Java序列化方式进行实现.包括Java原生以流的方法进行的序列化.Json序列化.FastJson序列化.Protobuff序列化. 1.Java原生序列化 Java原生 ...

随机推荐

  1. react native断点调试--Debug React-Native with VSCode

    .babelrc { "presets": [ "react-native" ], "sourceMaps": true } Many Ja ...

  2. 同步docker中的容器时间和宿主机相同

    同步docker中的容器时间和宿主机相同.cd /etc/ 在容器中修改下/etc/localtime文件的名称,避免冲突. mv localtime localtime_bak cp /usr/sh ...

  3. ABAP_DEMO篇33 SUM和COLLECT的用法

    ABAP程序内表中的数量和金额字段  经常会需要合计, SUM和COLLECT 语法都能实现对数量和金额字段的合计. 1. SUM语法 ABAP中SUM语句比不上EXCEL里的强大:SUM只能在loo ...

  4. Linux中tune2fs命令的-o选项

    debug 启用此文件系统的调试代码. bsdgroups 在创建新文件时模拟BSD行为:它们将使用创建它们的目录.标准系统V的行为是默认情况下,新创建的文件采用当前进程的fsgid,除非目录设置了s ...

  5. CLR Exception---E0434F4D

    什么是CLR Exception---E0434F4D 就是公共语言运行时(CLR)异常,异常代码为0xE0434F4D.因此任何托管异常,如NullReferenceException.invali ...

  6. K8s configMap原理介绍

    给容器内应用程序传递参数的实现方式: 1. 将配置文件直接打包到镜像中,但这种方式不推荐使用,因为修改配置不够灵活. 2. 通过定义Pod清单时,指定自定义命令行参数,即设定 args:[" ...

  7. GoCN每日新闻(2019-11-05)

    GoCN每日新闻(2019-11-05) GoCN每日新闻(2019-11-05) 1. Protobuf 终极教程 https://colobu.com/2019/10/03/protobuf-ul ...

  8. HTML引入外部JS文件

    <!--引入外部文件的方式--> <script type="text/javascript" src="attack.js">< ...

  9. Windows(win2016、win2019、win10)在IIS下添加.NET Framework 3.5 NetFx3 失败 (状态为:0x800f0950)的解决办法

    今天一个客户自己的电脑安装了一个windows server 2016 想装一个IIS,程序一个C+写的ERP,NET是必然,NET4.7可以安装了,但就是3.5,如何也装不上,错误(状态为:0x80 ...

  10. mongo helper

    import datetime import pymongo import click # 数据库基本信息 db_configs = { 'type': 'mongo', 'host': '127.0 ...