`

(转)Java 序列化

    博客分类:
  • java
阅读更多
当我们需要序列化一个JAVA对象时需要实现Serializable接口。这个接口仅仅是一个tag接口,并不需要你真正实现一些方法,因为这个接口没有方法。他作用仅仅是告诉默认JAVA序列化工具,这个对象是可以序列化的。

1.serialVersionUID的作用
    当我们的类实现了Serializable接口后,会有一个警告,告诉你需要生成一个serialVersionUID属性。这个serialVersionUID是做什么用的呢?其实这是JAVA序列化的版本控制功能。当序列化对象时会把这个属性写入,当反序列化时则会把这个属性取出,然后与JAVA类中的serialVersionUID属性值对比,如果一致,则认为是同一个版本,正常反序列化,如果不一致则认为版本不同,抛出InvalidClassException异常。

    很多时候我们忽略这个警告,并不写这个serialVersionUID属性,但仍然可以正常序列化。那是因为如果没有这个属性,JVM将会根据这个类的属性和方法,计算出一个值作为serialVersionUID的值。这种做法会带来潜在的风险。不同的JVM产生serialVersionUID的算法可能会不一致,如果在不同的环境下产生的serialVersionUID不一致,将导致反序列化失败!

    当一个类的结构发生变化,需要改变serialVersionUID,以通知序列化机制此类发生了变化,不兼容原来的版本了!其实并不是只要类结构变化,就必须更改serialVersionUID,JAVA的序列化机制提供了部分变化的兼容机制,有如下几种:
• 添加新的属性 反序列时发现没有此属性,则会赋予该属性默认的类型值
• 添加 writeObject/readObject 方法 因为此方法是用于自定义序列化,不影响序列化
• 删除 writeObject/readObject 方法 同上原因
• 改变属性的访问权限(private protected package public)
• 将一个属性从static变为nonstatic 或者 transient 或者 nontransient

如果你的类改动属于以上范围,默认的JAVA序列化机制可以保证兼容性,也就是说你不需要改动serialVersionUID值。
更多情况参见http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf 5.6.2 Compatible Changes


最近在团队内部发现了一些容易被人们忽视的问题,就是对象的序列化问题。
1.Non Serializable Object
你们有谁去考虑过为什么我们的模型都需要去实现Serializable 接口,大家都应该知道Memcached缓存对象时要求类对需实现 Serializable 这个接口,但最近在项目当中我发现了常常报这么一个异常Non Serializable Object ,大致分析了一下原因是有人把非序列化对象扔到Memcached中导致了这到一个异常。难道这不是一个错误吗?
2.Non-transient non-serializable instance field in Serializable class
这是一个坏味道,意思是在序列化的类中有非序列化的对象,并且没有对非序列化对象标注Transient ,这样做的后果是这个类的实列不能被序列化。
3. 不重视序列号
我常在代码中发现是这样写的,也就是序列化的能力从BaseDomain中继承,但没有加入序列号,实际上序列号是非常有用的,大家想想我们的产品都有版本号,为什么模型却没有?在一个异构的系统当中如果各个系统之间传递消息是用序列化,那么版本号是必不可少的,而且每一次模型变更都要做序列号升级,这样其他系统拿到数据发现序列号不一样,那么其他系统就要考虑升级了,实际上序列化的应用场景还有很多。


其实大部分情况下我们不需要深究哪些改动会影响兼容性。如果我们的序列化仅仅是用作缓存的话,我们可以简单处理,只要改动了类结构,即修改serialVersionUID值,抛弃原先的序列化结果,重新生成!

JAVA序列化过程
    JAVA默认的序列化类是ObjectOutputStream,反序列化类是ObjectInputStream。
Java代码
1. public static void main(String[] args) throws Exception { 
2.  
3.     Object o=new Object(); 
4.      
5.         try { 
6.             //序列化 
7.             FileOutputStream ostream = new FileOutputStream("t.txt"); 
8.             ObjectOutputStream p = new ObjectOutputStream(ostream); 
9.             p.writeObject(o); // 序列化对象,在内部通过调用defaultWriteFields(Object obj, ObjectStreamClass desc)来序列化对象的所有属性。 
10.             p.flush(); 
11.             ostream.close(); 
12.             //反序列化 
13.             FileInputStream fis=new FileInputStream("t.txt"); 
14.             ObjectInputStream istream=new ObjectInputStream(fis); 
15.             Object s=(ObjectSerializable) istream.readObject();//反序列化对象,内部调用defaultReadFields(Object obj, ObjectStreamClass desc)来反序列化所有属性 
16.             System.out.println(s); 
17.             istream.close(); 
18.             fis.close(); 
19.         } catch (IOException ioe) { 
20.             ioe.printStackTrace(); 
21.         } 
22. } 


JAVA自定义序列化
自定义序列化根据定制程度的不同,有多种定制方案。
1.Externalizable定制
Externalizable接口继承了Serializable,其中有2个方法:
Java代码
1. void writeExternal(ObjectOutput out) throws IOException; 
2. void readExternal(ObjectInput in) throws IOException, ClassNotFoundException; 

通过实现Externalizable这个接口,我们可以定制需要序列化的属性。
Java代码
1. /*
2. *ObjectOutputStream在调用writeObject()方法时,会判断需要序列化的类是否继承了
3. *Externalizable接口,如果是,则会调用writeExternal(ObjectOutput out)执行我们
4. *自己写的序列化代码
5. */ 
6. p.writeObject(o);  

Java代码
1. /*
2. *同理,ObjectInputStream在调用readObject()方法时,会判断需要反序列化的类是否继承
3. *了Externalizable接口,如果是,则会调用readExternal(ObjectInput in)执行我们自己
4. *写的反序列化代码
5. */ 
6. Object s=(ObjectSerializable) istream.readObject() 

2.重写ObjectOutputStream/ObjectInputStream
实现Externalizable的方式自定义序列化非常方便,只需要在序列化类内部添加2个方法即可,不需要外部的任何要求。
但是如果我们需要更加深度的定制这还是不够的。Externalizable无法定制序列化对象本身的描述,只能定制对象内部属性的描述。
此时我们需要新建一个自己的序列化类来实现。
Java代码
1. /**
2. * 自定义序列化类
3. */ 
4. public class CustomObjectOutputStream extends ObjectOutputStream { 
5.  
6.     private OutputStream cusOut; 
7.      
8.     public CustomObjectOutputStream(OutputStream out) throws IOException{ 
9.         /*
10.          * 通过调用super()可以将父类的enableOverride设置为true
11.          * 当调用父类的writeObject(obj)时,因为enableOverride=true,会调用writeObjectOverride(Object obj)方法
12.          * 因此我们需要覆写writeObjectOverride(Object obj)如下所示
13.          */ 
14.         super(); 
15.         cusOut=out; 
16.     } 
17.      
18.     @Override 
19.     protected void writeObjectOverride(Object obj) throws IOException { 
20.         //自定义序列化方案 
21.         //cusOut.write(b)... 
22.     } 
23.  
24. } 

Java代码
1. /**
2. * 自定义反序列化类
3. */ 
4. public class CustomObjectInputStream extends ObjectInputStream{ 
5.      
6.     private InputStream cusIn; 
7.  
8.     public CustomObjectInputStream(InputStream in)throws IOException { 
9.         /*
10.          * 通过调用super()可以将父类的enableOverride设置为true
11.          * 当调用父类的readObject()时,因为enableOverride=true,会调用readObjectOverride()方法
12.          * 因此我们需要覆写readObjectOverride()如下所示
13.          */ 
14.         super(); 
15.         cusIn=in; 
16.     } 
17.      
18.     @Override 
19.     protected Object readObjectOverride() throws IOException, 
20.             ClassNotFoundException { 
21.         //自定义反序列化方案 
22.         //cusIn.read() ... 
23.         return null; 
24.     } 
25.  
26. } 

以上2段代码继承了ObjectOutputStream和ObjectInputStream,完全自定义了序列化方法。
既然是完全自定义序列化方法,其实完全没有必要去继承ObjectOutputStream和ObjectInputStream。
上面的代码仅仅适用于做序列化的适配器。其他序列化机制比如hessian,protobuf等,需要适配JAVA默认的序列化机制,则可采用以上的方法适配

分享到:
评论

相关推荐

    java序列化和反序列化的方法

    java 序列化和反序列化的方法 Java 序列化和反序列化是 Java 语言中的一种机制,用于将对象转换为字节流,以便在网络上传输或存储。序列化是将对象转换为字节流的过程,而反序列化是将字节流转换回对象的过程。 在...

    Java序列化_Java序列化结构_

    Java序列化是Java平台中的一种持久化机制,它允许对象的状态被转换成字节流,以便存储、网络传输或在不同时间点恢复。这个过程被称为序列化,而反向操作称为反序列化。序列化在许多场景下都非常有用,比如在分布式...

    Java序列化

    Java序列化是Java平台中的一种标准机制,允许将对象的状态转换为字节流,以便存储在磁盘上、通过网络进行传输或者在某些时候恢复原来的对象状态。这一过程包括两个主要步骤:对象的序列化(将对象转换为字节流)和反...

    Protocol Buffer序列化对比Java序列化.

    【Protocol Buffer序列化对比Java序列化】 Protocol Buffer(简称PB)是Google开发的一种高效的数据序列化协议,而Java序列化是Java平台内置的一种序列化机制。两者的主要目标都是将对象转化为字节数组,便于在网络...

    java反序列化工具

    Java反序列化是一种将已序列化的对象状态转换回对象的过程,它是Java平台中持久化数据的一种常见方式。在Java应用程序中,序列化用于保存对象的状态以便稍后恢复,或者在网络间传输对象。然而,这个过程也可能引入...

    java序列化(Serializable)的作用和反序列化.doc

    ### Java序列化(Serializable)的作用与反序列化详解 #### 一、序列化的概念 序列化是指将程序中的对象转换为一系列字节流的过程,主要用于保存对象的状态或在网络之间传输对象。序列化的主要目的是为了能够持久化...

    java 序列化时排除指定属性

    Java序列化是Java平台提供的一种持久化机制,它允许我们将一个Java对象转换为字节流,以便存储到磁盘上,或者通过网络进行传输。这使得我们可以保存和恢复对象的状态。实现序列化的类需要实现`Serializable`接口,...

    java序列化全解

    Java序列化是Java平台中的一种核心机制,它允许对象的状态被转换成字节流,以便存储到磁盘、数据库,或者在网络中进行传输。这对于实现持久化、远程方法调用(RMI)以及Enterprise JavaBeans(EJB)等高级功能至关...

    java 序列化代码示例

    Java序列化是Java平台中的一种标准机制,它允许将对象的状态转换为字节流,以便存储、传输或恢复。在Java中,一个类如果要实现序列化,需要实现`Serializable`接口,这是一个标记接口,不包含任何方法。下面我们将...

    java序列化(Serializable)的作用和反序列化

    ### Java序列化(Serializable)的作用与反序列化详解 #### 一、序列化是什么? 序列化是指将程序中的对象转换为字节流的过程,从而方便存储或传输这些对象。通常,序列化用于将对象的状态(即其实例变量的值,而非...

    Java序列化Jar包

    Java序列化是Java平台中的一项重要技术,它允许对象的状态被转换为字节流,以便存储或通过网络进行传输。这种技术在分布式系统、持久化存储以及数据交换等场景中非常常见。本资源包含了三个流行的Java序列化框架:...

    java序列化原理与算法

    ### Java序列化原理与算法详解 #### 序言 在现代软件开发中,尤其是在网络通信和数据持久化领域,对象的序列化与反序列化扮演着至关重要的角色。Java作为一种广泛应用的编程语言,提供了强大的内置支持来实现序列化...

    java序列化实现演示

    Java序列化是Java平台中的一种标准机制,允许对象的状态被保存到磁盘或者在网络中进行传输,以便在后续的时间或地点恢复这些对象。这个过程包括两个主要操作:序列化(将对象转换为字节流)和反序列化(将字节流恢复...

    Java序列化的机制和原理

    Java序列化是Java平台提供的一种将对象转换为字节流,以便存储、在网络上传输或者在后续时间重新创建相同对象的机制。这是Java编程中一个非常重要的概念,尤其是在分布式环境和持久化存储中。让我们深入探讨一下Java...

    C#和Java的序列化反序列化

    而在Java中,我们可以通过实现`Serializable`接口来使类支持序列化,或者使用`java.io.ObjectOutputStream`和`java.io.ObjectInputStream`进行对象的序列化和反序列化。 接下来,我们讨论反序列化。反序列化是序列...

    java 对象的序列化与反序列化

    Java对象的序列化和反序列化是Java编程中一项重要的技术,主要用于将对象的状态转换为字节流,以便存储或在网络上传输。这一过程对于理解Java的IO操作、持久化数据以及实现分布式通信等场景非常关键。 首先,我们来...

    Java对象序列化标准最新版

    ### Java对象序列化标准知识点详解 #### 一、系统架构概览 **1.1 概览** Java 对象序列化是一种将Java对象的...以上内容涵盖了Java序列化标准的关键知识点,深入了解这些概念有助于更好地理解和应用Java序列化技术。

    java serializable 序列化与反序列化

    **一、Java序列化** 1. **什么是序列化**:序列化是将对象的状态(属性和成员变量)转换为可以存储或传输的数据格式的过程。在Java中,通常是将对象转换为字节数组,以便写入磁盘或通过网络发送。 2. **为什么需要...

    Java对象序列化和反序列化工具Xson.zip

    Xson是一个Java对象序列化和反序列化程序。支持Java对象到字节数组的序列化,和从字节数组到Java对象的反序列化。 Maven:  <groupId>com.github.xsonorg</groupId>  <artifactId>xson-core  <version>1.0.1 ...

    java序列化之protobuf

    Java序列化是将Java对象转换为字节流的过程,以便可以在网络上传输或存储在磁盘上。这使得数据能够跨不同的系统平台进行传输和持久化。Protocol Buffers(protobuf)是Google推出的一种高效、跨平台的数据序列化协议...

Global site tag (gtag.js) - Google Analytics