在Java中socket传输数据时,数据类型往往比较难选择。可能要考虑带宽、跨语言、版本的兼容等问题。比较常见的做法有:

  1. 采用java对象的序列化和反序列化
  2. 把对象包装成JSON字符串传输
  3. 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序列化工具【转】的更多相关文章

  1. Java 序列化工具类

    import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sun.misc.BASE64Decoder; import sun.m ...

  2. Java 序列化对象工具类

    SerializationUtils.java package javax.utils; import java.io.ByteArrayInputStream; import java.io.Byt ...

  3. 浅析JAVA序列化

    1.简述 Serialization(序列化) 是一种将对象以一连串的字节描述的过程:反序列化deserialization是一种将这些字节重建成一个对象的过程. 在分布式环境中,经常需要将Objec ...

  4. Java 序列化与反序列化

    1.什么是序列化?为什么要序列化? Java 序列化就是指将对象转换为字节序列的过程,而反序列化则是只将字节序列转换成目标对象的过程. 我们都知道,在进行浏览器访问的时候,我们看到的文本.图片.音频. ...

  5. Java 序列化Serializable详解

    Java 序列化Serializable详解(附详细例子) Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连 ...

  6. 简述java序列化

      1. 什么是Java对象序列化     Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期 ...

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

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

  8. Java序列化技术与Protobuff

    http://www.cnblogs.com/fangfan/p/4094175.html http://www.cnblogs.com/fangfan/p/4094175.html 前言: Java ...

  9. Google FlatBuffers——开源、跨平台的新一代序列化工具

    前段时间刚试用了一个序列化工具cereal,请看cereal:C++实现的开源序列化库,打算再总结下我对google proto buf序列化库的使用呢, 结果还没动手,大Google又出了一个新的. ...

随机推荐

  1. Java:IO流的综合用法(从键盘录入数据并打印在控制台上)

    import java.io.*; public class IOTestDouble { public static void main(String[] args)throws Exception ...

  2. Qt学习之对话框与主窗口的创建

    Qt中的信号与槽机制 qt中槽和普通的C++成员函数几乎是一样的--可以是虚函数,可以被重载,可以是共有的,保护的或者私有的. 槽可以和信号连接在一起,在这种情况下,每当发射这个信号的信号,就会自动调 ...

  3. C++11中万能的可调用类型声明std::function<...>

    在C++11中,callable object 包括传统C函数,C++成员函数,函数对象(实现了()运算符的类的实例),lambda表达式(特殊函数对象)共4种.程序设计,特别是程序库设计时,经常需要 ...

  4. Oracle数据库信息查询

    查看当前数据库 select name from V$DATABASE; select SYS_CONTEXT('USERENV','INSTANCE_NAME') from dual; 用户 sel ...

  5. 为什么空格拷贝到linux 会变成两个

    为什么空格拷贝到linux 会变成两个 学习了:https://zhidao.baidu.com/question/266438357.html 在vi界面内输入:set paste 然后进行拷贝: ...

  6. 拼接多个 wchar_t *

      /* wcscat example */ #include <wchar.h>   int main () { wchar_t wcs[80]; wcscpy (wcs,L" ...

  7. Javascript游戏,街头霸王

    在线演示 本地下载 街头霸王,有没有记起点什么?我想起了那个有颗大槐树的老院子,还有一台小霸王和一个儿时的伙伴.

  8. iOS日期加减

    - (NSDate *)jsDateFromBeginDate:(NSDate *)beginDate todays:(int)days { NSDate *dateTemp = [[NSDate a ...

  9. JDBC的简单操作

    JDBC是一组能够执行SQL语句的API 由于传统的数据库操作方式需要程序员掌握各个不同的数据库的API,极其不便 因此java定义了JDBC这一标准的接口和类,为程序员操作数据库提供了统一的方式 J ...

  10. getattr和setattr

    >>> class MyData(): def __init__(self,name,phone): self.name=name self.phone=phone def upda ...