码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2016-09-23 13:12:17      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:

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

     序列化:指把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 }
View Code

序列化:

技术分享
 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 }
View Code

运行结果如下:

技术分享

运行报错!

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 }
View Code

序列化和反序列化:

技术分享
 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 }
View Code

运行结果如下:

技术分享

三、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 }
View Code

序列化和反序列化:

技术分享
 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 }
View Code

运行结果:

技术分享

是成功的。

下面我们修改下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 }
View Code

这时执行反序列化操作:

技术分享
 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 }
View Code

运行结果:

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,为它赋予明确的值。

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

标签:

原文地址:http://www.cnblogs.com/gexiaoshan/p/5899399.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!