//TODO 只是简单使用,没有深入分析,有时间再写一篇深入分析文章
什么是序列化?
Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,就是说当JVM关闭时,我们创建的这些对象就随之丢失了。但在现实应用中,就可能要求在JVM停止运行之后能够持久化保存指定的对象,并在将来重新读取被保存的对象,比如说保存在硬盘或数据库中。Java对象序列化就能够帮助我们实现该功能。必须注意地是,对象序列化保存的是对象的”状态”,即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。
使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。
除了在持久化对象时会用到对象序列化之外,当使用RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化。
为什么需要序列化?
- 持久化保存对象状态,比如保存到硬盘或者数据库
- 网络传输
序列化的方法?
本文总结了三种方法
- 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工具生成对应的代码 |
参考: