转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6574920.html
一:序列化与反序列化
序列化:把Java对象(动态的状态,如变量、函数)转化为字节序列的过程;
反序列化:从字节序列重构出Java对象的过程。
二:序列化的作用
1)对象持久化:我们知道,对象随着程序的运行而被创建,然后在不可达时被回收,生命周期是短暂的。但是如果我们想长久地把对象的内容保存起来怎么办呢?把它转化为字节序列保存在存储介质上即可。那就需要序列化。
2)网络传输对象:我们知道,两个进程之间通信时,传递的音频、视频等信息是以二进制序列形式来传输的。那么,对象也可以吗?可以,通过序列化把主机A进程上的对象序列化为二进制序列,传输到主机B上的进程从序列中重构出该对象。这在RMI中应用广泛,RMI的结果可以是一个对象。
三:Java序列化对象的方式
1:Java序列化的默认API
通过 java.io.ObjectOutputStream(对象输出流)的writeObject(Object obj)方法可以对参数的obj对象进行序列化,把得到的字节序列写到一个该输出流中。
通过 java.io.ObjectInputStream(对象输入流)的 readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象并将其返回,返回时通过强制类型转换赋值给具体的类对象引用。(根据这个类的信息来解读二进制序列从而重构对象)。
2:让对象可以被序列化的三种方式
1)默认序列化:定义类时实现Serializable接口即可,这个Serializable接口是一个空接口,没有需要实现的方法。作用是标记该类的对象可以被序列化,启用其序列化功能。通过调用 ObjectOutputStream和ObjectInputStream的方法来对该对象进行序列化和反序列化。
2)类自定义序列化:定义类时,实现Serializable接口,并在类中定义
private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; 这两个方法,在方法中通过对象输入流参数、对象输出流参数进行自定义的内容输出。这样通过对象输出流和对象输入流的输入输出方法序列化和反序列化对象时会自动调用类中定义的writeObject、
和readObject方法而不是默认的序列化和反序列化方法。
3)类自定义序列化方式二:实现Externalnalizable接口,并且在类中实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,在方法中定义类对象自定义
的序列化和反序列化操作。这样通过对象输出流和对象输入流的输入输出方法序列化和反序列化对象时会自动调用类中定义的readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法。
四:序列化和反序列化的使用步骤
1:创建类,实现Serializable接口或者Externalizable接口,实现相应的序列化和反序列化方法(也可采取默认方法);
2:在程序代码中创建对象后,创建对象输出流ObjectOutputStream对象并在构造参数中指定流的输出目标(比如一个文件),通过objectOutputStream.writeObject(obj)把对象序列化并输出到流目标处;
3:在需要提取对象处:创建对象输入流ObjectInputStream对象并在构造参数中指定流的来源,然后通过readObject()方法获取对象,并通过强制类型转换赋值给类对象引用
五:Java序列化的特殊情况
1:静态变量和transient关键字修饰的变量不能被序列化;
2:反序列化时要按照序列化的顺序重构对象:如先序列化A后序列化B,则反序列化时也要先获取A后获取B,否则报错。
3:序列化ID的作用:虚拟机是否允许对象反序列化,不仅取决于该对象所属类路径和功能代码是否与虚拟机加载的类一致,而是主要取决于对象所属类与虚拟机加载的该类的序列化 ID 是否一致。
4:自定义序列化方法的应用场景:对某些敏感数据进行加密操作后再序列化;反序列化对加密数据进行解密操作。
5:重复序列化:同一个对象重复序列化时,不会把对象内容再次序列化,而是新增一个引用指向第一次序列化时的对象而已。
六:其他序列化手段
1:把对象包装成JSON格式进行序列化
2:用XML格式序列化
3:采用第三方插件(如:ProtoBuf)进行序列化