java序列化
1.1 什么是java序列化
序列化:把java对象转化为字节序列的过程。
反序列化:把字节序列恢复为java对象的过程。
1.2 为什么需要序列化
java对象是运行在堆内存中的,如果jvm停止,它的生命也就戛然而止。
如果jvm停止后,要把对象保存到磁盘或者另一台机器上,就需要把对象转化为字节数组。序列化可以使对象脱离程序运行而独立存在,它主要有两个好处:
1:减轻内存压力的同时,持久化
序列化可以让对象保存到硬盘上,减轻内存压力的同时,也起到了持久化的作用
2:序列化可以让对象在网络上进行传输
1.3 java序列化常用的API
Serializable 接口
Serializable 接口是一个标记接口,没有方法或字段。一旦实现了此接口,就标志该类的对象就是可序列化的。
Externalizable 接口
Externalizable 集成了Serializable接口,其中包括writeExternal() 和 readExternal()两个抽象方法。如果使用Externalizable 实现序列化需要重写writeExternal()和readExternal()方法。
java.io.objectOutputStream类
表示对象输出流,他的writeObject(Object obj) 方法可以对指定的obj对象参数进行序列化,再把得到的字节序列写到一个目标输出流中。
java.io.objectInputStream类
表示对象输入流,它的readObject()方法,从输入流中读取到字节序列,反序列化为一个对象。
1.4序列化的使用
1:实现Serializab接口。
2:使用objectOutputStream的writeObject()实现序列化。
3:使用ObjectInputStream的readObject()方法 实现反序列化。
1.5序列化底层
ObjectOutputStream 在序列化的时候会判断序列化的object属于String或者arrary或者enum还是Serializable如果都不是抛出notSerializableException异常,所以serializable是一个标识,只是一个序列化标识。
1.6 日常开发的一些注意点
1:static静态变量和transient修饰的字段不会被序列化
因为静态成员变量是类级别的,而序列化是针对对象的,所以不能序列化。
transient关键字可以阻止修饰的字段被序列化到文件中
2:serialVersionUID 问题
serialVersionUID是序列化版本号ID,每一个实现serializable接口的类都有一个表示序列化标识符的静态变量,或者默认等于1L或者等于对象的哈希码。
3:serialVersionUID 有什么用?
java的序列化机制通过serialVersionUID 来检验版本是否一致,在进行反序列化时JVM会把传来的字节流中serialVersionUID 和本地相应实体类的serialVersionUID 进行比较:如果相同,反序列化成功;如果不相同,就抛出 InvalidClassException 异常。
4:如果某个序列化类的成员变量时对象类型,那么该对象必须实现序列化。
5:子类实现了 Serializable,父类没有实现 Serializable 接口的话,父类不会被序列化。
子类实现Serializable接口,父类没有实现,子类可以序列化,这种情况父类一定要提供空的构造方法,不要忘了子类的toString方法
6:类中存在引用对象,这个类对象在什么情况下可以实现序列化?
一个类里面所有的属性是可序列化的,这个类才能顺利的序列化。
7:同一个对象多次序列化之间有属性更新,前后的序列化有什么区别?
当第一次序列化之后,不管如何修改这个对象的属性,都不会对后续的序列化产生影响,反序列化的结果和第一次相同。
其实是序列化算法的原因,所有要序列化的对象都有一个序列化的编码号,当试图序列化一个对象,会检查这个对象是否已经序列化过,若从未序列化过,才会序列化为字节序列去输出,若已经序列化过,则会输出一个编码符号(q~),不会重复序列化一个对象。