一、定义
Java对象序列化是将实现了Serializable接口的对象转换成一个字节序列,能够通过网络传输、文件存储等方式传输 ,传输过程中却不必担心数据在不同机器、不同环境下发生改变,也不必关心字节的顺序或其他任何细节,并能够在以后将这个字节序列完全恢复为原来的对象(恢复这一过程称之为反序列化)。在序列化期间,对象将其当前状态写入到临时或持久性存储区。之后可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
二、用途
把内存中的对象状态保存到一个文件中或者数据库中
利用套接字在网络上传送对象
通过RMI传输对象
进程间传递对象
所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的java对象都必须是可序列化的。通常建议:程序创建的每个JavaBean类都实现Serializeable接口
不同进程之间的java对象是无法传输,所以我们此处要对对象进行序列化
三、实现
1.类实现 Serializable 接口,这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。
实现Sericalizable接口的时候还要写一个SericalizableUID版本号,JVM会把传进来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。
如果实现接口的时候没有给定UID,就会使用默认的UID。当使用默认的UID的时候,jvm每次编译的时候会生成一个UID,当后面程序改了一些代码,再次编译的时候会生成不同的UID,会导致反序列化失败。
所以在实现Sericalizable接口的时候,我们要给定一个固定的UID值,这样就能保证编译完再反序列化的时候的版本一致性。所以能不能成功反序列化,就是看对象中的UID和实体中UID是否一致。
2.实现Externalnalizable接口,在类中实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,在方法中定义类对 象自定义的序列化和反序列化操作。这样通过对象输出流和对象输入流的输入输出方法序列化和反序列化对象时会自动调用类中定义的readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法。
四、注意事项
某个类可以被序列化,则其子类也可以被序列化
声明为 static 和 transient 的成员变量,不能被序列化。static 成员变量是描述类级别的属性,transient 表示临时数据
反序列化读取序列化对象的顺序要保持一致
序列化使其他代码可以查看或修改,那些不序列化便无法访问的对象实例数据。通常对象实例的所有字段都会被序列化,这意味着数据会被表示为实例的序列化数据。这样,能够解释该格式的代码有可能能够确定这些数据的值,而不依赖于该成员的可访问性。类似地,反序列化从序列化的表示形式中提取数据,并直接设置对象状态,这也与可访问性规则无关。即在序列化进行传输的过程中,这个对象的private等域是不受保护的;
Java有很多基础类已经实现了serializable接口,比如String,Vector等。但是也有一些没有实现serializable接口的。
强烈建议显式 serialVersionUID 声明尽可能使用 private 修饰符,因为此类声明仅适用于立即声明的类——serialVersionUID字段,不会被子类继承
五、后记
目前JAVA常用的序列化有protobuf,json,xml,Serializable,hessian,kryo。
JSON:用途最广泛,序列化方式还衍生了阿里的fastjson,美团的MSON,谷歌的GSON等更加优秀的转码工具。
优点:使用方便。
缺点:数据冗长,转码性能一般。