为了账号安全,请及时绑定邮箱和手机立即绑定

序列化和反序列化到底有什么用呢?

标签:
Java

一、序列化和反序列化有什么用

很多同学或许知道序列化是对象实现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

感谢您的阅读,希望您多多支持,这样我在原创的道路上才能更加的有信心。

点击查看更多内容
3人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消