序列化,反序列化和transient关键字

一、序列化和反序列化的概念

序列化:指把java对象转换为字节序列的过程。

反序列化:指把字节序列恢复为java对象的过程。

对象的序列化主要有两种用途:
  1) 把对象的字节序列保存到硬盘上,通常存放在一个文件中;
  2) 在网络上传送对象的字节序列。

1.当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

2.在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。

二、JDK类库中的序列化API

java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
  java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

只有实现了Serializable接口的类的对象才能被序列化。
  对象序列化包括如下步骤:
  1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流,字节数组输出流;
  2) 通过对象输出流的writeObject()方法写对象。

  对象反序列化的步骤如下:
  1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流,字节数组输入流;
  2) 通过对象输入流的readObject()方法读取对象。

1、类未实现Serializable接口,进行序列化的范例:

定义一个未实现Serializable的类:User

 1 package com.paic.egis.smts.activity;
 2
 3
 4 public class User{
 5     private String userId;
 6     private String userName;
 7     public String getUserId() {
 8         return userId;
 9     }
10     @Override
11     public String toString() {
12         return "User [userId=" + userId + ", userName=" + userName + "]";
13     }
14     public void setUserId(String userId) {
15         this.userId = userId;
16     }
17     public String getUserName() {
18         return userName;
19     }
20     public void setUserName(String userName) {
21         this.userName = userName;
22     }
23
24 }

序列化:

 1 package com.paic.egis.smts.activity;
 2
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.io.FileOutputStream;
 6 import java.io.IOException;
 7 import java.io.ObjectInputStream;
 8 import java.io.ObjectOutputStream;
 9
10 public class Test {
11
12     public static void main(String[] args) throws Exception{
13         serialize();
14         User o = (User) deSerialize();
15         System.out.println(o.toString());
16
17     }
18
19     public static void serialize() throws IOException{
20         User u = new User();
21         u.setUserId("11");
22         u.setUserName("df");
23         FileOutputStream fo = new FileOutputStream(new File("d://a.txt"));
24         ObjectOutputStream os = new ObjectOutputStream(fo);
25         os.writeObject(u);
26     }
27
28     public static Object deSerialize() throws IOException, ClassNotFoundException {
29         FileInputStream fi = new FileInputStream(new File("d://a.txt"));
30         ObjectInputStream oi = new ObjectInputStream(fi);
31         return oi.readObject();
32     }
33
34 }

运行结果如下:

运行报错!

2、类实现Serializable接口,进行序列化和反序列化的范例:

定义一个实现Serializable的类:UserSerialize

 1 package com.paic.egis.smts.activity;
 2
 3 import java.io.Serializable;
 4
 5 public class UserSerialize implements Serializable{
 6     /**
 7      *
 8      */
 9     private static final long serialVersionUID = 1L;
10     private String userId;
11     private String userName;
12     public String getUserId() {
13         return userId;
14     }
15     @Override
16     public String toString() {
17         return "User [userId=" + userId + ", userName=" + userName + "]";
18     }
19     public void setUserId(String userId) {
20         this.userId = userId;
21     }
22     public String getUserName() {
23         return userName;
24     }
25     public void setUserName(String userName) {
26         this.userName = userName;
27     }
28
29 }

序列化和反序列化:

 1 package com.paic.egis.smts.activity;
 2
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.io.FileOutputStream;
 6 import java.io.IOException;
 7 import java.io.ObjectInputStream;
 8 import java.io.ObjectOutputStream;
 9
10 public class Test {
11
12     public static void main(String[] args) throws Exception{
13         serialize();
14         UserSerialize o = (UserSerialize) deSerialize();
15         System.out.println(o.toString());
16
17     }
18
19     public static void serialize() throws IOException{
20         UserSerialize u = new UserSerialize();
21         u.setUserId("11");
22         u.setUserName("df");
23         FileOutputStream fo = new FileOutputStream(new File("d://a.txt"));
24         ObjectOutputStream os = new ObjectOutputStream(fo);
25         os.writeObject(u);
26     }
27
28     public static Object deSerialize() throws IOException, ClassNotFoundException {
29         FileInputStream fi = new FileInputStream(new File("d://a.txt"));
30         ObjectInputStream oi = new ObjectInputStream(fi);
31         return oi.readObject();
32     }
33
34 }

运行结果如下:

三、serialVersionUID的作用

serialVersionUID作用:序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。

有两种生成方式:

一个是默认的1L,比如:private static final long serialVersionUID = 1L;

一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:private static final long  serialVersionUID = xxxxL;

下面举例说明下:

还是上面说到的类:UserSerialize,把定义的serialVersionUID去掉。

 1 package com.paic.egis.smts.activity;
 2
 3 import java.io.Serializable;
 4
 5 public class UserSerialize implements Serializable{
 6 //    /**
 7 //     *
 8 //     */
 9 //    private static final long serialVersionUID = 1L;
10     private String userId;
11     private String userName;
12     public String getUserId() {
13         return userId;
14     }
15     @Override
16     public String toString() {
17         return "User [userId=" + userId + ", userName=" + userName + "]";
18     }
19     public void setUserId(String userId) {
20         this.userId = userId;
21     }
22     public String getUserName() {
23         return userName;
24     }
25     public void setUserName(String userName) {
26         this.userName = userName;
27     }
28
29 }

序列化和反序列化:

 1 package com.paic.egis.smts.activity;
 2
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.io.FileOutputStream;
 6 import java.io.IOException;
 7 import java.io.ObjectInputStream;
 8 import java.io.ObjectOutputStream;
 9
10 public class Test {
11
12     public static void main(String[] args) throws Exception{
13         serialize();
14         UserSerialize o = (UserSerialize) deSerialize();
15         System.out.println(o.toString());
16
17     }
18
19     public static void serialize() throws IOException{
20         UserSerialize u = new UserSerialize();
21         u.setUserId("11");
22         u.setUserName("df");
23         FileOutputStream fo = new FileOutputStream(new File("d://a.txt"));
24         ObjectOutputStream os = new ObjectOutputStream(fo);
25         os.writeObject(u);
26     }
27
28     public static Object deSerialize() throws IOException, ClassNotFoundException {
29         FileInputStream fi = new FileInputStream(new File("d://a.txt"));
30         ObjectInputStream oi = new ObjectInputStream(fi);
31         return oi.readObject();
32     }
33
34 }

运行结果:

是成功的。

下面我们修改下UserSerialize类:添加一个熟悉sex

 1 package com.paic.egis.smts.activity;
 2
 3 import java.io.Serializable;
 4
 5 public class UserSerialize implements Serializable{
 6 //    /**
 7 //     *
 8 //     */
 9 //    private static final long serialVersionUID = 1L;
10     private String userId;
11     private String userName;
12
13     private String sex;
14
15     public String getSex() {
16         return sex;
17     }
18     public void setSex(String sex) {
19         this.sex = sex;
20     }
21     public String getUserId() {
22         return userId;
23     }
24     @Override
25     public String toString() {
26         return "User [userId=" + userId + ", userName=" + userName + "]";
27     }
28     public void setUserId(String userId) {
29         this.userId = userId;
30     }
31     public String getUserName() {
32         return userName;
33     }
34     public void setUserName(String userName) {
35         this.userName = userName;
36     }
37
38 }

这时执行反序列化操作:

 1 package com.paic.egis.smts.activity;
 2
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.io.FileOutputStream;
 6 import java.io.IOException;
 7 import java.io.ObjectInputStream;
 8 import java.io.ObjectOutputStream;
 9
10 public class Test {
11
12     public static void main(String[] args) throws Exception{
13 //        serialize();
14         UserSerialize o = (UserSerialize) deSerialize();
15         System.out.println(o.toString());
16
17     }
18
19     public static void serialize() throws IOException{
20         UserSerialize u = new UserSerialize();
21         u.setUserId("11");
22         u.setUserName("df");
23         FileOutputStream fo = new FileOutputStream(new File("d://a.txt"));
24         ObjectOutputStream os = new ObjectOutputStream(fo);
25         os.writeObject(u);
26     }
27
28     public static Object deSerialize() throws IOException, ClassNotFoundException {
29         FileInputStream fi = new FileInputStream(new File("d://a.txt"));
30         ObjectInputStream oi = new ObjectInputStream(fi);
31         return oi.readObject();
32     }
33
34 }

运行结果:

Exception in thread "main" java.io.InvalidClassException: com.paic.egis.smts.activity.UserSerialize; local class incompatible: stream classdesc serialVersionUID = -3074015237131537750, local class serialVersionUID = -126714174808369076
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at com.paic.egis.smts.activity.Test.deSerialize(Test.java:31)
at com.paic.egis.smts.activity.Test.main(Test.java:14)

意思就是说,文件流中的class和classpath中的class,也就是修改过后的class,不兼容了,处于安全机制考虑,程序抛出了错误,并且拒绝载入。那么如果我们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是自己去指定serialVersionUID

      因此强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。

时间: 2024-09-29 02:39:11

序列化,反序列化和transient关键字的相关文章

Java对象表示方式1:序列化、反序列化和transient关键字的作用

http://www.cnblogs.com/xrq730/p/4821958.html 平时我们在Java内存中的对象,是无 法进行IO操作或者网络通信的,因为在进行IO操作或者网络通信的时候,人家根本不知道内存中的对象是个什么东西,因此必须将对象以某种方式表示出来,即 存储对象中的状态.一个Java对象的表示有各种各样的方式,Java本身也提供给了用户一种表示对象的方式,那就是序列化.换句话说,序列化只是表示对 象的一种方式而已.OK,有了序列化,那么必然有反序列化,我们先看一下序列化.反序

Java序列化1:序列化、反序列化和transient关键字的作用

网上讲Java序列化的文章很多,感觉很多都讲得不全,这篇文章希望可以全面地剖析Java的序列化机制.为什么要进行序列化和反序列化?我们写了一个Object,但那是Java虚拟机堆内存里面的东西,利用Object进行网络通信.IO操作的时候怎么会认识Java堆内存里面的东西?所以,需要序列化和反序列化机制的保障. 序列化:将一个对象转换成一串二进制表示的字节数组,通过保存或转移这些字节数据来达到持久化的目的. 反序列化:将字节数组重新构造成对象. 默认序列化 序列化只需要实现java.io.Ser

Java IO 序列化 transient关键字

Java IO 序列化 transient关键字 @author 敏敏Alexia 转自:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html 1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化. 然而在实际开发过程

Java序列化——transient关键字和Externalizable接口

提到Java序列化,相信大家都不陌生.我们在序列化的时候,需要将被序列化的类实现Serializable接口,这样的类在序列化时,会默认将所有的字段都序列化.那么当我们在序列化Java对象时,如果不希望对象中某些字段被序列化(如密码字段),怎么实现呢?看一个例子: import java.io.Serializable; import java.util.Date; public class LoginInfo implements Serializable {     private stat

Java transient关键字序列化时使用小记

1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化. 然而在实际开发过程中,我们常常会遇到这样的问题,这个类的有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操

使用transient关键字解决ehcache序列化错误

使用Ehcache时发现个不起眼的小问题 在一个Model中有以下代码: public class MyModel implements Serializable { private static final long serialVersionUID = -990334519496260591L; private IUserService us = ServiceManager.me.getUserService(); //getter and setter } 在将这个Model的一个实例缓

序列化反序列化

对Java对象序列化的目的是持久化对象或者为RMI(远程方法调用)传递参数和返回值. 下面是一个序列化对象写入文件的例子: ---------------------------- 1 package utils; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.io.O

Java transient关键字

哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transient关键字的使用,涨下姿势~~~好了,废话不多说,下面开始: 1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Seriliza

Java transient关键字使用小记

1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化. 然而在实际开发过程中,我们常常会遇到这样的问题,这个类的有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操