浅析若干Java序列化工具【转】
在Java中socket传输数据时,数据类型往往比较难选择。可能要考虑带宽、跨语言、版本的兼容等问题。比较常见的做法有:
- 采用java对象的序列化和反序列化
- 把对象包装成JSON字符串传输
- Google工具protoBuf的开源
本文章所需要的序列化jar包都可以下载:http://download.csdn.net/detail/u013256816/9439971。
为了便于说明各个做法的区别,分别对这三种做法进行阐述。 对UserVo对象进行序列化,class UserVo如下:
1
2
3
4
5
6
7
8
9
10
|
package serialize; import java.util.List; public class UserVo { private String name; private int age; private List<UserVo> friends; //此处省略Getter和Setter方法 } |
初始化一个UserVo实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
UserVo user = new UserVo(); user.setName( "zzh" ); user.setAge( 18 ); UserVo f1 = new UserVo(); f1.setName( "jj" ); f1.setAge( 17 ); UserVo f2 = new UserVo(); f2.setName( "qq" ); f2.setAge( 19 ); List<UserVo> friends = new ArrayList<UserVo>(); friends.add(f1); friends.add(f2); user.setFriends(friends); |
采用java对象的序列化和反序列化
这里简单说明一下java序列化所占用字节大小,具体可以参考http://blog.csdn.net/u013256816/article/details/50474678。
1
2
3
4
5
6
|
ByteArrayOutputStream os = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(user); oos.flush(); oos.close(); System.out.println(os.toByteArray().length); |
序列化大小:205.
优点:java原生支持,不需要提供第三方的类库,使用比较简单。缺点:无法跨语言,字节数占用比较大,某些情况下对于对象属性的变化比较敏感。
把对象包装成JSON字符串传输
JSON工具类有许多种,这里列出三个比较流行的json工具类:Jackson,Gson,FastJson.
1.开源的Jackson
Jackson社区相对比较活跃,更新速度也比较快。Jackson对于复杂类型的json转换bean会出现问题,一些集合Map,List的转换出现问题。Jackson对于复杂类型的bean转换Json,转换的json格式不是标准的Json格式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
package serialize.json; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.codehaus.jackson.JsonEncoding; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.map.ObjectMapper; import org.junit.After; import org.junit.Before; import org.junit.Test; import serialize.UserVo; public class JacksonTest { private UserVo user = null ; private JsonGenerator jsonGenerator = null ; private ObjectMapper objectMapper = null ; @Before public void init() { user = new UserVo(); user.setName( "zzh" ); user.setAge( 18 ); UserVo f1 = new UserVo(); f1.setName( "jj" ); f1.setAge( 17 ); UserVo f2 = new UserVo(); f2.setName( "qq" ); f2.setAge( 19 ); List<UserVo> friends = new ArrayList<UserVo>(); friends.add(f1); friends.add(f2); user.setFriends(friends); objectMapper = new ObjectMapper(); try { jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(System.out,JsonEncoding.UTF8); } catch (IOException e) { e.printStackTrace(); } } @After public void destory() { try { if (jsonGenerator != null ) { jsonGenerator.flush(); } if (!jsonGenerator.isClosed()) { jsonGenerator.close(); } jsonGenerator = null ; objectMapper = null ; user = null ; } catch (IOException e) { e.printStackTrace(); } } @Test public void writeJson() { try { jsonGenerator.writeObject(user); System.out.println(); System.out.println(objectMapper.writeValueAsBytes(user).length); // System.out.println(objectMapper.writeValueAsString(user).length()); } catch (IOException e) { e.printStackTrace(); } } @Test public void readJson() { String serString = "{\"name\":\"zzh\",\"age\":18,\"friends\":[{\"name\":\"jj\",\"age\":17,\"friends\":null},{\"name\":\"qq\",\"age\":19,\"friends\":null}]}" ; UserVo uservo = null ; try { uservo = objectMapper.readValue(serString, UserVo. class ); } catch (IOException e) { e.printStackTrace(); } System.out.println(uservo.getName()); } } |
序列化大小:111.
注意到这里Jackson会输出null,在Jackson的2.x版本中可以通过设置而使其不输出null的字段。
2. Google的Gson
Gson是目前功能最全的Json解析神器,Gson当初是为因应Google公司内部需求而由Google自行研发而来,但自从在2008年五月公开发布第一版后已被许多公司或用户应用。Gson的应用主要为toJson与fromJson两个转换函数,无依赖,不需要例外额外的jar,能够直接跑在JDK上。而在使用这种对象转换之前需先创建好对象的类型以及其成员才能成功的将JSON字符串成功转换成相对应的对象。类里面只要有get和set方法,Gson完全可以将复杂类型的json到bean或bean到json的转换,是JSON解析的神器。Gson在功能上面无可挑剔,但是性能上面比FastJson有所差距。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
package serialize.json; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import serialize.UserVo; public class GsonTest { private UserVo user = null ; @Before public void init() { user = new UserVo(); user.setName( "zzh" ); user.setAge( 18 ); UserVo f1 = new UserVo(); f1.setName( "jj" ); f1.setAge( 17 ); UserVo f2 = new UserVo(); f2.setName( "qq" ); f2.setAge( 19 ); List<UserVo> friends = new ArrayList<UserVo>(); friends.add(f1); friends.add(f2); user.setFriends(friends); } @Test public void writeJson() { try { String str = Gson. class .newInstance().toJson(user); //一行就可以搞定!!! System.out.println(str); System.out.println(str.length()); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } @Test public void readJson() { String serString = "{\"name\":\"zzh\",\"age\":18,\"friends\":[{\"name\":\"jj\",\"age\":17},{\"name\":\"qq\",\"age\":19}]}" ; try { UserVo userVo = Gson. class .newInstance().fromJson(serString, UserVo. class ); System.out.println(userVo.getName()); } catch (JsonSyntaxException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } } |
序列化大小:81.
Gson和Jackson的区别是:如果你的应用经常会处理大的JSON文件,那么Jackson应该是你的菜。GSON在大文件上表现得相当吃力。如果你主要是处理小文件请求,比如某个微服务或者分布式架构的初始化,那么GSON当是首选。Jackson在小文件上的表现则不如人意。
3. 阿里巴巴的FastJson
Fastjson是一个Java语言编写的高性能的JSON处理器,由阿里巴巴公司开发。无依赖,不需要例外额外的jar,能够直接跑在JDK上。
FastJson在复杂类型的Bean转换Json上会出现一些问题,可能会出现引用的类型,导致Json转换出错,需要制定引用。FastJson采用独创的算法,将parse的速度提升到极致,超过所有json库。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
package serialize.json; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import com.alibaba.fastjson.JSON; import serialize.UserVo; public class FastJsonTest { private UserVo user = null ; @Before public void init() { user = new UserVo(); user.setName( "zzh" ); user.setAge( 18 ); UserVo f1 = new UserVo(); f1.setName( "jj" ); f1.setAge( 17 ); UserVo f2 = new UserVo(); f2.setName( "qq" ); f2.setAge( 19 ); List<UserVo> friends = new ArrayList<UserVo>(); friends.add(f1); friends.add(f2); user.setFriends(friends); } @Test public void writeJson() { String str = JSON.toJSONString(user); System.out.println(str); System.out.println(str.length()); } @Test public void readJson() { String serString = "{\"name\":\"zzh\",\"age\":18,\"friends\":[{\"name\":\"jj\",\"age\":17},{\"name\":\"qq\",\"age\":19}]}" ; UserVo userVo = JSON.parseObject(serString,UserVo. class ); System.out.println(userVo.getName()); } } |
注:如果只是功能要求,没有性能要求,可以使用google的Gson,如果有性能上面的要求可以使用Gson将bean转换json确保数据的正确,使用FastJson将Json转换Bean。
Google工具protoBuf
protocol buffers 是google内部得一种传输协议,目前项目已经开源。它定义了一种紧凑得可扩展得二进制协议格式,适合网络传输,并且针对多个语言有不同得版本可供选择。
protoBuf优点:1.性能好,效率高;2.代码生成机制,数据解析类自动生成;3.支持向前兼容和向后兼容;4.支持多种编程语言;5.字节数很小,适合网络传输节省io。缺点:1.应用不够广;2.二进制格式导致可读性差;3.缺乏自描述;
protoBuf是需要编译工具的,这里用的是window的系统。需要下载proto.exe和protobuf-java-2.4.1.jar;
将proto.exe放在当前工程目录下,然后编辑.proto文件,命名为UserVo.proto,如下所示:
1
2
3
4
5
6
7
8
9
10
11
|
package serialize.protobuf; option java_package = "serialize.protobuf" ; option java_outer_classname= "UserVoProtos" ; message UserVo { optional string name = 1 ; optional int32 age = 2 ; repeated serialize.protobuf.UserVo friends = 3 ; } |
在命令行中利用protoc工具生成builder类:
看到生成了UserVoProtos.java,由于这个java文件有1千行左右,篇幅限制不便罗列。
序列化和反序列化测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
package serialize.protobuf; import org.junit.Before; import org.junit.Test; import com.google.protobuf.InvalidProtocolBufferException; public class ProtoBufTest { UserVoProtos.UserVo.Builder user = null ; @Before public void init() { user = UserVoProtos.UserVo.newBuilder(); user.setName( "zzh" ); user.setAge( 18 ); UserVoProtos.UserVo.Builder f1 = UserVoProtos.UserVo.newBuilder(); f1.setName( "jj" ); f1.setAge( 17 ); UserVoProtos.UserVo.Builder f2 = UserVoProtos.UserVo.newBuilder(); f2.setName( "qq" ); f2.setAge( 19 ); user.addFriends(f1); user.addFriends(f2); } @Test public void doSeri() { UserVoProtos.UserVo vo = user.build(); byte [] v = vo.toByteArray(); for ( byte b:v) { System.out.printf( "%02X " ,b); } System.out.println(); System.out.println(v.length); } @Test public void doDeSeri() { byte [] v = new byte []{ 0x0A , 0x03 , 0x7A , 0x7A , 0x68 , 0x10 , 0x12 , 0x1A , 0x06 , 0x0A , 0x02 , 0x6A , 0x6A , 0x10 , 0x11 , 0x1A , 0x06 , 0x0A , 0x02 , 0x71 , 0x71 , 0x10 , 0x13 }; try { UserVoProtos.UserVo uvo = UserVoProtos.UserVo.parseFrom(v); System.out.println(uvo.getName()); } catch (InvalidProtocolBufferException e) { e.printStackTrace(); } } } |
序列化大小:23.
工作机制:proto文件是对数据的一个描述,包括字段名称,类型,字节中的位置。protoc工具读取proto文件生成对应builder代码的类库。protoc xxxxx –java_out=xxxxxx 生成java类库。builder类根据自己的算法把数据序列化成字节流,或者把字节流根据反射的原理反序列化成对象。官方的示例:https://developers.google.com/protocol-buffers/docs/javatutorial。proto文件中的字段类型和java中的对应关系:详见:https://developers.google.com/protocol-buffers/docs/proto.
.proto Type | java Type | c++ Type |
---|---|---|
double | double | double |
float | float | float |
int32 | int | int32 |
int64 | long | int64 |
uint32 | int | uint32 |
unint64 | long | uint64 |
sint32 | int | int32 |
sint64 | long | int64 |
fixed32 | int | uint32 |
fixed64 | long | uint64 |
sfixed32 | int | int32 |
sfixed64 | long | int64 |
bool | boolean | bool |
string | String | string |
bytes | byte | string |
注:protobuf的一个缺点是需要数据结构的预编译过程,首先要编写.proto格式的配置文件,再通过protobuf提供的工具生成各种语言响应的代码。由于java具有反射和动态代码生成的能力,这个预编译过程不是必须的,可以在代码执行时来实现。有个protostuff(http://code.google.com/p/protostuff/)已经实现了这个功能。protostuff基于Google protobuf,但是提供了更多的功能和更简易的用法。其中,protostuff-runtime实现了无需预编译对java bean进行protobuf序列化/反序列化的能力。protostuff-runtime的局限是序列化前需预先传入schema,反序列化不负责对象的创建只负责复制,因而必须提供默认构造函数。此外,protostuff还可以按照protobuf的配置序列化成json/yaml/xml等格式。这里不做详述,有兴趣的朋友可以参考相关资料。
总结:
方式 | 优点 | 缺点 |
---|---|---|
JSON | 跨语言、格式清晰一目了然 | 字节数比较大,需要第三方类库 |
Object Serialize | java原生方法不依赖外部类库 | 字节数大,不能跨语言 |
Google protobuf | 跨语言、字节数比较少 | 编写.proto配置用protoc工具生成对应的代码 |
浅析若干Java序列化工具【转】的更多相关文章
- Java 序列化工具类
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sun.misc.BASE64Decoder; import sun.m ...
- Java 序列化对象工具类
SerializationUtils.java package javax.utils; import java.io.ByteArrayInputStream; import java.io.Byt ...
- 浅析JAVA序列化
1.简述 Serialization(序列化) 是一种将对象以一连串的字节描述的过程:反序列化deserialization是一种将这些字节重建成一个对象的过程. 在分布式环境中,经常需要将Objec ...
- Java 序列化与反序列化
1.什么是序列化?为什么要序列化? Java 序列化就是指将对象转换为字节序列的过程,而反序列化则是只将字节序列转换成目标对象的过程. 我们都知道,在进行浏览器访问的时候,我们看到的文本.图片.音频. ...
- Java 序列化Serializable详解
Java 序列化Serializable详解(附详细例子) Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连 ...
- 简述java序列化
1. 什么是Java对象序列化 Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期 ...
- Java序列化的几种方式以及序列化的作用
Java序列化的几种方式以及序列化的作用 本文着重讲解一下Java序列化的相关内容. 如果对Java序列化感兴趣的同学可以研究一下. 一.Java序列化的作用 有的时候我们想要把一个Java对象 ...
- Java序列化技术与Protobuff
http://www.cnblogs.com/fangfan/p/4094175.html http://www.cnblogs.com/fangfan/p/4094175.html 前言: Java ...
- Google FlatBuffers——开源、跨平台的新一代序列化工具
前段时间刚试用了一个序列化工具cereal,请看cereal:C++实现的开源序列化库,打算再总结下我对google proto buf序列化库的使用呢, 结果还没动手,大Google又出了一个新的. ...
随机推荐
- Python编程学习,高效求解素数程序实例
素数是编程中经常需要用到的. 作为学习Python的示例,下面是一个高效求解一个范围内的素数的程序,不需要使用除法或者求模运算. #coding:utf-8 #设置python文件的编码为utf-8, ...
- Python中filter、map、reduce、lambda 的用法
Python内置了一些非常有趣但非常有用的函数,充分体现了Python的语言魅力! filter(function, sequence):对sequence中的item依次执行function(ite ...
- LRU Cache leetcode java
题目: Design and implement a data structure for Least Recently Used (LRU) cache. It should support the ...
- myeclipse创建maven android项目
一.搭建环境 1.安装android maven插件,我在网上找了半天.没有找到这个插件,于是选择了在线安装.选择myeclipse 的 [help]->[install form catalo ...
- linux /dev 常见特殊设备介绍与应用[loop,null,zero,full,random]
linux是文件型系统,所有硬件如软件都会在对于的目录下面有相应的文件表示.对于dev这个目录,我们知道它下面的文件,表示的是linux的设备.在windows系统中,设备大家很好理解,象硬盘,磁盘指 ...
- (转)Unity3D新手引导开发手记
转自:http://www.cnblogs.com/ybgame/p/3844315.html 最近开始接手新手引导的开发,记录下这块相关的心得 首先客户端是Unity,在接手前,前面的同学已经初步完 ...
- 【Window OS】”对于目标文件系统,文件XXXXX过大“导致无法进行文件操作的解决方法
问题原因:这是目标文件系统不支持这么大的文件的操作问题.例如:目标文件系统的格式是FAT32,FAT32最大支持4G,如果你要进行发送或粘贴4G以上的文件就会出现这个问题. 解决办法:把目标文件系统的 ...
- /etc/rc.d/init.d/functions文件详细分析
/etc/rc.d/init.d/functions文件详细分析 functions这个脚本是给/etc/init.d里边的文件使用的(可理解为全局文件). 提供了一些基础的功能,看看里边究竟有些什么 ...
- java 反射获取属性值 方法
public static void main(String[] args) throws SecurityException, ClassNotFoundException, IllegalArgu ...
- 关于LayoutInflater的错误用法
转自:http://www.doubleencore.com/2013/05/layout-inflation-as-intended/ Layout inflation is the term us ...