探秘序列化里面的小九九(一)—序列化概念

0、序言

今天第一次更新简书的博客,(心情那个忐忑啊)分享一个最近稍微了解的序列化的知识。

之前做一个Android实时推送的功能,是用传统的Socket然后自定义协议的方式,非常难处理(不要问我为什么用这种坑爹的方式,boss一句话,宝宝心里苦啊)


baobao.png

,常常要处理复杂的数据解析,浪费大量时间在处理数据的打包和解析。然后因为一次面试,突然从面试官口中听到了Protobuf,突然发现世间居然还有这么好用的东西,于是鼓起勇气研究起序列化协议的相关东西。


啰嗦这么多,正文开始

1、基本概念

我们先了解一下基本的使用和概念。
Java中序列化的基本概念如下:

  1. 把对象转换为字节序列的过程称为对象的序列化
  2. 把字节序列恢复为对象的过程称为对象的反序列化。

看这个等于没说,其实我们可以看一个例子:

1.1 如何序列化呢?

老板让收集用户的个人信息,包含它的用户名,密码和年龄并传上来,于是,我们定义一个需要传递的对象如下:

import java.io.Serializable;   
class User implements Serializable {         
    public byte age = 24;          
    public String name;
    public String password;   
} 

如下的方式,调用Java本身的ObjectOutputStream就可以将Object输出到流中,生成一个二进制序列,完成序列化的操作,同样的,反序列化就是调用ObjectInputStream对象的readObject方法。具体我就不再列例子了。

import java.io.FileOutputStream; 
import java.io.ObjectOutputStream; 
class Main {          
    public static void main(String[] args) {          
          FileOutputStream fos = new FileOutputStream("temp.out");                          
          ObjectOutputStream oos = new ObjectOutputStream(fos);                
          User user = new User();                
          oos.writeObject(user);                
          oos.flush();                
          oos.close();       
    }
} 

1.2 还能做什么?

作为一个通信协议,如果序列化只能这样转换,那远远不够的。如何应对产品或是老板无穷无尽的需求更改呢(你懂的!)

  • 安全性!!!
    今天老板跟你说,“我们这些字段中的密码不要传输吧,都能被解析这不是很不好吗?”
    但是转念一想,我不能删除这个字段啊,我要在其他业务中用到这个字段呢,也不能再新建一个没有密码的类,这不是很没必要嘛。
    不要方,我们可以给类定义一个含有transient关键字的字段。这个关键字赋值后的数据,不会再序列化后出现,同时反序列化也不会解析,麻麻再也不用担心你网络传输中会被截取了。
import java.io.Serializable;   
class User implements Serializable {         
    public byte age = 24;          
    public String name;
    public tranisent String password;   
} 
  • 兼容性
    老板的需求当然不会停的咯,今天老板又来说了,“这个年龄啊,还是用年份吧,把原来的删了吧,之前版本的也要兼容”
    这时候你一脸蒙蔽,写出了这样子的版本
import java.io.Serializable;   
class User implements Serializable {         
    public int year = 1992;          
    public String name;
    public tranisent String password;   
} 

然后,你发现这个根本无法兼容旧版本!

这个时候的解决方案就是要用上serialVersionUID,只有使用了自己定义的serialVersionUID,才能使新版本兼容旧版本。

1.3 其他的坑在哪里?

老板给你的需求越来越大,你这个数据类也会越来越复杂,你会开始继承父类,开始定义其他的数据,这个时候需要注意下面几点:

  1. 要想将父类对象也序列化,就需要让父类也实现Serializable 接口。如果父类不实现的话的,就需要有默认的无参的构造函数。
  2. 序列化不保存静态变量,因为静态变量是属于类的状态,在程序开启时会统一加载。
  3. 如果你想自己定义序列化的规则,可以使用Externalizable
class User implements Externalizable{         
    int year = 1992;          
    String name;
    String password;   

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
       out.writeObject(name);
       out.writeInt(age);
    }
     
     @Override
     public void readExternal(ObjectIntput intput) throws IOException{
          this.name = (String) in.readObject();
          this.age = in.readInt();
     }
} 

注意: Externalizable会将tranisent 的关键字的信息屏蔽掉其功能,如果使用了Externalizable就不要使用tranisent关键字。


暂时介绍序列化的概念,下一篇文章介绍一下protobuf的相关知识。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • JAVA序列化机制的深入研究 对象序列化的最主要的用处就是在传递,和保存对象(object)的时候,保证对象的完整...
    时待吾阅读 10,920评论 0 24
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,933评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,765评论 18 399
  • 官方文档理解 要使类的成员变量可以序列化和反序列化,必须实现Serializable接口。任何可序列化类的子类都是...
    狮_子歌歌阅读 2,440评论 1 3
  • 白天我和男朋友去逛街,想到我的眉笔用完了。就准备买一支。挑来挑去就没看到适合我的颜色,男友等得不耐烦了,就说到,这...
    番茄爱上西红柿123阅读 170评论 0 0