0、序言
今天第一次更新简书的博客,(心情那个忐忑啊)分享一个最近稍微了解的序列化的知识。
之前做一个Android实时推送的功能,是用传统的Socket然后自定义协议的方式,非常难处理(不要问我为什么用这种坑爹的方式,boss一句话,宝宝心里苦啊)

,常常要处理复杂的数据解析,浪费大量时间在处理数据的打包和解析。然后因为一次面试,突然从面试官口中听到了Protobuf,突然发现世间居然还有这么好用的东西,于是鼓起勇气研究起序列化协议的相关东西。
啰嗦这么多,正文开始
1、基本概念
我们先了解一下基本的使用和概念。
Java中序列化的基本概念如下:
- 把对象转换为字节序列的过程称为对象的序列化
- 把字节序列恢复为对象的过程称为对象的反序列化。
看这个等于没说,其实我们可以看一个例子:
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 其他的坑在哪里?
老板给你的需求越来越大,你这个数据类也会越来越复杂,你会开始继承父类,开始定义其他的数据,这个时候需要注意下面几点:
- 要想将父类对象也序列化,就需要让父类也实现Serializable 接口。如果父类不实现的话的,就需要有默认的无参的构造函数。
- 序列化不保存静态变量,因为静态变量是属于类的状态,在程序开启时会统一加载。
- 如果你想自己定义序列化的规则,可以使用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的相关知识。
网友评论