有关Java对象的序列化和反序列化也算是Java基础的一部分,下面对Java序列化的机制和原理进行一些介绍。
Java序列化算法透析
Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。Java序列化API提供一种处理对象序列化的标准机制。在这里你能学到如何序列化一个对象,什么时候需要序列化以及Java序列化的算法,我们用一个实例来示范序列化以后的字节是如何描述一个对象的信息的。
序列化的必要性
Java中,一切都是对象,在分布式环境中经常需要将Object从这一端网络或设备传递到另一端。这就需要有一种可以在两端传输数据的协议。Java序列化机制就是为了解决这个问题而产生。
如何序列化一个对象
一个对象能够序列化的前提是实现Serializable接口,Serializable接口没有方法,更像是个标记。有了这个标记的Class就能被序列化机制处理。
package serialization; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; /** * @author yangfei * @since 2014-3-31 */ public class Serialization { static Person getPerson() { Person p = new Person(); p.setName("yangfei"); p.setAge(26); return p; } /** * serialize person Object to file * @throws IOException */ public static void serialization() throws IOException { FileOutputStream fos = new FileOutputStream("temp.out"); ObjectOutputStream oos = new ObjectOutputStream(fos); Person p = getPerson(); oos.writeObject(p); oos.close(); fos.close(); } /** * serialize person Object to file * @throws IOException * @throws ClassNotFoundException */ public static Person deSerialization() throws IOException, ClassNotFoundException { FileInputStream fos = new FileInputStream("temp.out"); ObjectInputStream oos = new ObjectInputStream(fos); Person p = (Person) oos.readObject(); oos.close(); fos.close(); return p; } public static void main(String args[]) throws IOException, ClassNotFoundException{ serialization(); Person p = deSerialization(); System.out.println(p.getName()+"==="+p.getAge()); } }
serialVersionUID的作用
凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:
private static final long serialVersionUID;
以上serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。
简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。
当实现java.io.Serializable接口的实体(类)没有显式地定义一个名为serialVersionUID,类型为long的变量时,Java序列化机制会根据编译的class自动生成一个serialVersionUID作序列化版本比较用,这种情况下,只有同一次编译生成的class才会生成相同的serialVersionUID 。
如果我们不希望通过编译来强制划分软件版本,即实现序列化接口的实体能够兼容先前版本,未作更改的类,就需要显式地定义一个名为serialVersionUID,类型为long的变量,不修改这个变量值的序列化实体都可以相互进行串行化和反串行化。
类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的serialVersionUID,也有可能相同。为了提高哦啊serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。显式地定义serialVersionUID有两种用途:
1) 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;
2)在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。
在测试的时候,序列化完成之后,将Person中的serialVersionUID改为51(原始为1),反序列化的时候报错:
Exception in thread "main" java.io.InvalidClassException: serialization.Person; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 51
参考:
http://developer.51cto.com/art/200908/147650.htm Java序列化的机制和原理
http://www.2cto.com/kf/201312/264301.html java序列化和反序列化以及serialVersionUID的作用