一、序列化和反序列化有什么用
很多同学或许知道序列化是对象实现Serializable接口,则可以自动被序列化了,那么到底为什么需要做序列化呢?
计算机底层传输是通过字节流的方式进行传输(也就是byte[]),那么我们的内容(字符串、自定义实体、文件等等)如果需要传输,则需要把这些内容转换成byte[],这一过程其实就是序列化;反过来,如果想把byte[]转换成目标对象,这一过程其实就是反序列化。
序列化和反序列化的常见场景:
①网络传输,比如:Dubbo、Redis通讯传递数据等等
②磁盘IO传输,比如:本地文件->内存;内存->本地文件
③存储,数据的存储底层都是二进制的方式,因此数据的存取就需要进行序列化
讲到这里,我们应该能明白为什么Dubbo传递参数需要实现序列化接口了吧。
其实序列化和反序列化在我们的开发当中无处不在,只是我们很少去关注它的原理,因此感觉会特别的陌生,或者既熟悉又陌生。
二、序列化和反序列化的规则
其实序列化和反序列化准确来说是一种规则,而不是某种具体的技术。通过制定某种规则,按照这种规则去把我们的数据安全的转换成byte[];同时又能按照这种规则把byte[]转换成我们的数据,那么就可以把这种规则落地成技术实现并运用到项目当中。
在Java当中String类型的数据它自动实现序列化接口了,因此它是可以在网络中传输的。如下所示:
public final class String
implements java.io.Serializable,
Comparable<String>,
CharSequence {
public byte[] getBytes() {
return StringCoding.encode(value, 0, value.length);
}
}
我们自定义的实体,具体如下:
public class User{
private String name;
private Integer age;
//get、set方法
}
public static void main(String[] args){
User user=new User();
//发现自定义的实体没有getBytes()方法
//byte[] bytes=user.getBytes();
}
思考:自定义实体没有getBytes()方法,那么怎么转换成byte[]呢?
方案一: 把实体转换成json格式的字符串,那么它最终就可以转换成byte[]了
- 技术:通过Fastjson、Jackjson等框架把实体和json字符串进行互转
- 优点:序列化的结果可以肉眼能识别,并且比较轻量
- 缺点:序列化后的长度相对大
- 说明:相信大家在学习Redis的时候,如果保存的是对象,则使用RedisDeskTopManager远程连接发现是一堆看不懂的乱码,因此常常需要手工指定序列化格式。
方案二: 把实体转换成xml格式的字符串,那么它最终就可以转换成byte[]了
- 技术:通过XStream把实体和xml字符串进行互转
- 优点:序列化的结果可以肉眼能识别,并且对实体的属性描述很清晰
- 缺点:序列化之后的结果占用字节数比较大
方案三: JDK自带的序列化,实体实现Serializable接口
- 说明:实现序列化接口的时候,JDK默认会进行序列化和反序列化操作了,但是我们也可以自己自定义规则,具体如下:
public class User{
private String name;
private Integer age;
//序列化的时候该方法会被执行
private void writeObject(java.io.ObjectOutputStream s){
s.defaultWriteObject();
s.writeObject(name);//name参与序列化,age不参与序列化
}
//反序列化的时候该方法会被执行
private void readObject(java.io.ObjectInputStream s){
s.defaultReadObject();
name=(String)s.readObject();//name参与序列化,age不参与序列化
}
}
方案四: 使用对象流手工操作
public class User{
private String name;
private Integer age;
}
//把实体序列化到本地文件
public static void seri(User user) throws Exception{
FileOutputStream fileOut =new FileOutputStream("/tmp/user.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(user);
out.close();
fileOut.close();
}
//把本地文件反序列化成对象
public static User deser(String path) throws Exception{
FileInputStream fileIn = new FileInputStream(path);
ObjectInputStream in = new ObjectInputStream(fileIn);
User user = (User) in.readObject();
in.close();
fileIn.close();
return user;
}
三、序列化和反序列化有哪些技术
主要主流的序列化和反序列化技术:Java 原生序列化、Hessian 序列化、Kryo 序列化、JSON 序列化等
其实我们核心掌握的是序列化的核心思想即可,技术使用则是非常简单的,大家可以私下去通过案例测试几种技术的性能对比。
- ①序列化的byte[]数组长度的比较
- ②同一个数据序列化的耗时时间比较
- ③反序列化的耗时时间比较
四、如何自定义序列化和反序列化规范
通过上面的讲解,我想大家应该对序列化和反序列化都有一个大体的认识了,最后为了加深大家对序列化和反序列化的理解,大家可以思考如何设计一个序列化框架。其实,上面也提到了它是一种规范的约束,序列化和反序列化都遵守这样一个规则。
public class User{
private String name;
private int age;
}
思考:如何把User实体->byte[]呢?
思路:转换json字符串,{name:"zwy",age:18}
,那么为了缩短最终的byte[]长度,是否还可以进行优化呢?比如说,{"zwy",18}
小结: 本节讲解序列化和反序列化技术,主要是平时我们在做网络通讯的时候,需要经常涉及,在学习Netty的时候序列化技术是必不可少的。
①在学习Netty的时候,自定义协议的时候,需要涉及序列化
②高并发情况下,压缩字节流,提高网络传输效率
慕课网专栏(微服务架构思想+仿百度网盘源码):
https://www.imooc.com/read/73
感谢您的阅读,希望您多多支持,这样我在原创的道路上才能更加的有信心。