常用的序列化和反序列化
序列化,将对象持久化存储,转换为可存储在文件或者在网络传输的的字节序列
反序列化:将字节序列恢复为对象
常用的几种序列化
原生的jdk
public class JdkSerializableDemo implements Serializable {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Student student = new Student();
student.setNo(1);
student.setName("NormalSerializable");
//序列化
String home = System.getProperty("user.dir");
//字节流文件存储地址
String fileName = home + "\\file\\student.dat";
FileOutputStream fos = new FileOutputStream(fileName);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(student);
oos.flush();
oos.close();
//反序列化
FileInputStream fis = new FileInputStream(fileName);
ObjectInputStream ois = new ObjectInputStream(fis);
Student deStudent = (Student) ois.readObject();
ois.close();
System.out.println(deStudent);
}
}
jdk原生序列化需要对象继承接口Serializable,这个接口点开你会发现其实什么都没有,Serializable其实是一个标记接口,具体序列化是又JVM内部去实现的。
JSON
json也是我们常用的一种序列化的方式,优点是可读性强,但是缺点也有:json进行序列化需要额外的空间,json没有对象,对于java这种强类型语言来说,就需要靠反射去解决。不推荐传输数据量大的时候使用json。
java常用的json工具也很多,这里就使用阿里的fastjson
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.46</version>
</dependency>
public class JsonDemo {
public static void main(String[] args) {
Student student = new Student();
student.setName("JSON序列化");
student.setNo(100);
//序列化
String studentStr = JSON.toJSONString(student);
System.out.println(studentStr);
//反序列化
Student student1 = JSON.parseObject(studentStr, Student.class);
System.out.println(student1);
}
}
Hessian
Hessian是跨语言的序列化框架,性能上要比json和jdk高,生成的字节数也更小,兼用型和稳定性也更强。但也存在一些问题。对于一些java常见的类型不支持。例如LinkedHashMap,LinkedHashSet等Linked系列。Locale类。Byte/Short序列化后变成Integer。
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
public class HessianDemo {
public static void main(String[] args) throws IOException {
Student student = new Student();
student.setNo(101);
student.setName("HESSIAN");
//把student对象转化为byte数组
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Hessian2Output output = new Hessian2Output(bos);
output.writeObject(student);
output.flushBuffer();
byte[] data = bos.toByteArray();
bos.close();
//把刚才序列化出来的byte数组转化为student对象
ByteArrayInputStream bis = new ByteArrayInputStream(data);
Hessian2Input input = new Hessian2Input(bis);
Student deStudent = (Student) input.readObject();
input.close();
System.out.println(deStudent);
}
}
Protobuf
ProtoBuf是谷歌公司开发的一套开源的序列化框架。支持 Java、Python、C++、Go 等语言。使用时需要定义IDL,使用不用语言的编译器生成序列化的工具类。它生成序列化后的体积比Hessian还小,序列化和反序列化的速度也很快。兼容性也很强。
如果要使用protobuf,这里推荐一篇安装的教程:https://www.jianshu.com/p/bb3ac7e5834e
java使用protobuf可以考虑使用protostuff,Protostuff 不需要依赖 IDL 文件,可以直接对 Java 领域对象进行反 / 序列化操作,在效率上跟 Protobuf 差不多,生成的二进制格式和 Protobuf 是完全相同的,可以说是一个 Java 版本的 Protobuf 序列化框架。
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.8.0</version>
</dependency>
public class ProToBufDemo {
public static void main(String[] args) {
//创建builder
Student.student.Builder studentBuilder = Student.student.newBuilder();
studentBuilder.setName("Protoc");
studentBuilder.setNo(1);
//创建student
Student.student student = studentBuilder.build();
System.out.println(student.toString());
try {
//将二进制转为
Student.student st = Student.student.parseFrom(student.toByteArray());
System.out.print(st.toString());
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
}
}
记录一个使用protobuf遇到的问题,protoc生成序列化工具类后,工具类中出现UnusedPrivateParameter报错,升级了protobuf依赖就解决了。