当前位置:编程学习 > JAVA >>

Java Serializable系列化与反系列化

 

【引言】

 

    将Java 对象序列化为二进制文件的Java 序列化技术是Java 系列技术中一个较为重要的技术点,在大部分情况下,开发人员只需要了解被序列化的类需要实现Serializable 接口,使用ObjectInputStream 和ObjectOutputStream 进行对象的读写。然而在有些情况下,光知道这些还远远不够,文章列举了笔者遇到的一些真实情境,它们与Java 序列化相关,通过分析情境出现的原因,使读者轻松牢记Java 序列化中的一些高级认识。

 

【系列化serialVersionUID问题】 www.zzzyk.com

 

    在Java系列化与反系列化中,虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化ID 是否一致(就是private static final long serialVersionUID = 1L),如果serialVersionUID不同,你将得到一个java.io.InvalidClassException,看如下代码:

view plain

package wen.hui.test.serializable; 

 

import java.io.Serializable; 

 

/**

 * serializable测试

 *

 * @author whwang

 * 2011-12-1 下午09:50:07

 */ 

public class A implements Serializable { 

 

    private static final long serialVersionUID = 2L; 

 

    public A() { 

 

    } 

 

    public void print() { 

        System.err.println("test serializable"); 

    } 

 

    public static void main(String[] args) throws Exception { 

 

    } 

view plain

package wen.hui.test.serializable; 

 

import java.io.FileInputStream; 

import java.io.FileOutputStream; 

import java.io.ObjectInputStream; 

import java.io.ObjectOutputStream; 

 

/**

 *

 * @author whwang

 * 2011-12-1 下午09:54:36

 */ 

public class Test1 { 

 

    public static void main(String[] args) throws Exception { 

        // write object 

        String fileName = "obj"; 

        toWrite(fileName); 

 

        // read object 

        toRead(fileName); 

    } 

 

    public static void toWrite(String fileName) throws Exception { 

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream( 

                fileName)); 

        oos.writeObject(new A()); 

        oos.close(); 

    } 

 

    public static void toRead(String fileName) throws Exception { 

        ObjectInputStream ois = new ObjectInputStream( 

                new FileInputStream("obj")); 

        A t = (A) ois.readObject(); 

        t.print(); 

        ois.close(); 

    } 

 

 

1、直接运行Test1的main方法,运行正确;

2、先将Test1的main方法中的toRead(fileName)注释,把类A中的serialVersionUID 值改为1,运行Test1;然后在代开toRead(fileName),将toWrite(fileName)注释,同时将类A中的serialVersionUID 值改为2;运行Test1,发现抛出异常,表明如果serialVersionUID不同,即使两个“完全”相同的类也无法反序列化。

view plain

Exception in thread "main" java.io.InvalidClassException: wen.hui.test.serializable.A; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2 

 

序列化ID 在Eclipse 下提供了两种生成策略,一个是固定的1L,一个是随机生成一个不重复的long 类型数据(实际上是使用JDK 工具生成),在这里有一个建议,如果没有特殊需求,就是用默认的1L 就可以,这样可以确保代码一致时反序列化成功。那么随机生成的序列化ID 有什么作用呢,有些时候,通过改变序列化ID 可以用来限制某些用户的使用。如Facade模式中,Client 端通过Façade Object 才可以与业务逻辑对象进行交互。而客户端的Façade Object 不能直接由Client 生成,而是需要Server 端生成,然后序列化后通过网络将二进制对象数据传给Client,Client 负责反序列化得到Façade 对象。该模式可以使得Client 端程序的使用需要服务器端的许可,同时Client 端和服务器端的Façade Object 类需要保持一致。当服务器端想要进行版本更新时,只要将服务器端的Façade Object 类的序列化ID 再次生成,当Client 端反序列化Façade Object 就会失败,也就是强制Client 端从服务器端获取最新程序。

 

【静态变量序列】

直接看代码:

view plain

package wen.hui.test.serializable; 

 

import java.io.Serializable; 

 

/**

 * serializable测试

 *

 * @author whwang

 * 2011-12-1 下午09:50:07

 */ 

public class A implements Serializable { 

 

    private static final long serialVersionUID = 1L; 

 

    public static int staticVar = 10; 

 

    public A() { 

 

    } 

 

    public void print() { 

        System.err.println("test serializable"); 

    } 

 

    public static void main(String[] args) throws Exception { 

 

    } 

view plain

package wen.hui.test.serializable; 

 

import java.io.FileInputStream; 

import java.io.FileNotFoundException; 

import java.io.FileOutputStream; 

import java.io.IOException; 

import java.io.ObjectInputStream; 

import java.io.ObjectOutputStream; 

 

/**

 * 序列化保存的是对象的状态,静态变量属于类的状态,不会被序列化

 * @author whwang

 * 2011-12-1 下午10:12:06

 */ 

public class Test2 { 

 

    public static void main(String[] args) { 

        try { 

            // 初始时staticVar为10 

            ObjectOutputStream out = new ObjectOutputStream( 

                    new FileOutputStream("obj")); 

            out.writeObject(new A()); 

            out.close()

补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,