//TODO 只是简单使用,没有深入分析,有时间再写一篇深入分析文章
什么是序列化?
Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,就是说当JVM关闭时,我们创建的这些对象就随之丢失了。但在现实应用中,就可能要求在JVM停止运行之后能够持久化保存指定的对象,并在将来重新读取被保存的对象,比如说保存在硬盘或数据库中。Java对象序列化就能够帮助我们实现该功能。必须注意地是,对象序列化保存的是对象的”状态”,即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。
使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。
为什么需要序列化?
- 持久化保存对象状态,比如保存到硬盘或者数据库
- 网络传输
序列化的方法?
本文总结了三种方法
- Java自带Serializable
- JSON
- Protobuf
一、Java自带Serializable
将需要序列化的类实现Serializable接口就可以了,Serializable接口中没有任何方法,可以理解为一个标记,即表明这个类可以序列化.
如果我们想要序列化一个对象,首先要创建某些OutputStream(如FileOutputStream、ByteArrayOutputStream等),然后将这些OutputStream封装在一个ObjectOutputStream中。这时候,只需要调用writeObject()方法就可以将对象序列化,并将其发送给OutputStream(记住:对象的序列化是基于字节的,不能使用Reader和Writer等基于字符的层次结构)。而反序列的过程(即将一个序列还原成为一个对象),需要将一个InputStream(如FileInputstream、ByteArrayInputStream等)封装在ObjectInputStream内,然后调用readObject()即可。
首先新建一个User的实体类,并实现Serializable接口
public class User implements Serializable { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "name=" + name + ",age=" + age; } }
序列化
@Test public void SerializeTest() { // 初始化 User user = new User(); user.setName("crankz"); user.setAge(23); System.out.println("初始化:" + user); try { FileOutputStream fileOut = new FileOutputStream("user.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(user); out.close(); fileOut.close(); System.out.println("序列化成功,文件保存在user.ser中"); } catch (IOException e) { e.printStackTrace(); } }
序列化成功后,会在项目目录下生成一个文件
记事本打开看一下,都是乱码,说明是被Java序列化之后的二进制文件
反序列化
@Test public void deSerializeTest() { try { FileInputStream fileIn = new FileInputStream("user.ser"); ObjectInputStream in = new ObjectInputStream(fileIn); User user = (User) in.readObject(); in.close(); fileIn.close(); System.out.println("反序列化成功:" + user); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
反序列化成功后的结果
二、JSON序列化
JSON常见序列化工具
- Jackson
- Fastjson
- Gson
还是序列化上面的User类为例,介绍三种JSON工具的常见用法。
都需要Maven添加依赖,具体去这里搜索:https://mvnrepository.com/
/** * Jackson的用法 * @throws IOException */ @Test public void jacksonTest() throws IOException { User user1 = new User(); user1.setName("crankz"); user1.setAge(23); ObjectMapper mapper = new ObjectMapper(); //Java类转JSON String json = mapper.writeValueAsString(user1); System.out.println(json); //JSON转Java类 User user2 = mapper.readValue(json, User.class); System.out.println(user2); } /** * Fastjson的用法 */ @Test public void jsonTest() { User user1 = new User(); user1.setName("crankz"); user1.setAge(23); //Java类转JSON String json = JSON.toJSONString(user1); System.out.println("User类转JSON:" + json); //JSON转Java类 User user2 = JSON.parseObject(json, User.class); System.out.println(user2); } /** * Gson的用法 */ @Test public void gsonTest() { User user1 = new User(); user1.setName("crankz"); user1.setAge(23); Gson gson = new Gson(); //Java类转JSON String json = gson.toJson(user1); System.out.println(json); //JSON转Java类 User user2 = gson.fromJson(json, User.class); System.out.println(user2); }
三、Protobuf序列化
使用步骤
- 定义Protobuf结构
- 使用protoc生成相应java类,并导入到实际项目中
- java代码使用
1.定义Protobuf结构
Protobuf要根据他的规则定义结构,这里只做简单演示,具体请看官网:https://github.com/google/protobuf
2.使用protoc生成相应java类,并导入到实际项目中
官网下载相应的工具:https://github.com/google/protobuf/releases
下载相应平台版本,我这里下载window版本。
然后执行命令
protoc.exe --java_out=输出目录 目标文件
执行成功后会在输出目录多一个java格式的文件
把UserPt.java导入到Java项目中
3.Java代码使用Protobuf
请自行添加Maven依赖,去这里:https://mvnrepository.com/
这里只做简单演示,详细请看:https://github.com/google/protobuf
/** * Protobuf的使用 * @throws IOException */ @Test public void protoTest() throws IOException { //按照定义的数据结构,创建一个User类 UserPt.UserProto.Builder userBuilder = UserPt.UserProto.newBuilder(); userBuilder.setName("crankz"); userBuilder.setAge(23); UserPt.UserProto user1 = userBuilder.build(); //将数据写到输出流 ByteArrayOutputStream output = new ByteArrayOutputStream(); user1.writeTo(output); //上面是发送方,将数据序列化后发送 byte[] byteArray = output.toByteArray(); //下面是接受放,将接受的数据反序列化 //接受到流并读取 ByteArrayInputStream input = new ByteArrayInputStream(byteArray); //反序列化 UserPt.UserProto user2 = UserPt.UserProto.parseFrom(input); System.out.println("user2_name:" + user2.getName()); System.out.println("user2_age:" + user2.getAge()); }
三种方法简单总结:
方式 | 优点 | 缺点 |
---|---|---|
JSON | 跨语言、格式清晰、便于人理解 | 字节数比较大,需要第三方类库 |
Object Serialize | java原生方法不依赖外部类库 | 字节数大,不能跨语言 |
Google protobuf | 跨语言、字节数比较少 | 编写.proto配置用protoc工具生成对应的代码 |
参考:
http://www.hollischuang.com/archives/1150
https://blog.csdn.net/u013256816/article/details/50721421