java反序列化浅析
和PHP的序列化一样,都是为了想把对象转成一个字节序列,这样方便持久化存储,必免程序运行结束后对象就从内存里消息,并且将对象序列化后也便于网络传输。
既然是java反序列化,那么我们就要了解在java中是怎么实现序列化的
序列化
java.io.ObjectOutputStream
java.io.ObjectOutputStream 类 写对象 writeObject()
使用该方法对参数指定的obj对象进行序列化,把字节序列写到一个目标输出流中,按照Java的标准约定是给文件一个.ser扩展名
反序列化
java.io.ObjectInputStream
java.io.ObjectInputStream 类 读对象 readObject()
该方法从一个源输入流中读取字节序列,再把他们反序列化为一个对象,并将其返回
特征参考
一段数据以rO0AB开头,你基本可以确定这串就是Java序列化base64加密的数据
或者如果以aced开头,那么它就是这一段java序列化的16进制数据
那我们使用java代码实习一下序列化和反序列化
Person类
1 | package SerialTest; |
Serializable接口
可以发现在这我使用了Serializable接口,这个接口跟进一下,发现里面其实是空的,没有任何方法,这是因为Serializable接口仅仅只是做了一个标记,真正的序列化动作不是靠它完成的。
Java原生实现了一套序列化的机制,它让我们不需要额外编写代码,只需要实现java.io.Serializable接口,并调用ObjectOutputStream类的writeObject方法即可
1 | public static void main(String[ ] args) throws IOException( |
跟进writeObject函数
我们通过阅读它的注释可以得知,在序列化的过程当中,是针对对象本身,而非针对类的,因此静态属性是不参与序列化和反序列化的过程的。另外,如果属性本身声明了transient关键字,也会被忽略。但是如果某对象继承了A类,那么A类当中对象的对象属性也是会被序列化和反序列化的(前提是A类也实现了java.io.Serializable接口)
对Person对象序列化和反序列化
1 | package SerialTest; |
序列化结果为:
sr SerialTest.Person捠??漷 I ageI stuldL namet Ljava/lang/String;L sexq ~ xp d 閠 xicct 鐢?
这样简单的序列化和反序列化很容易实现,但是假如我在序列化之后,再去Person对象里新增一个字段,然后再反序列化,看看是啥效果
可以发现这里发生了异常,显示serialVersionUID不一样
serialVersionUID是什么?
serialVersionUID可以把它想象成一个UID号码,这个号码是对象序列化前后的唯一标识符,如果没有显示为它定义,那么编译器就会自动为它声明一个。