Java基础系列8:Java的序列化与反序列化(修)

简介:

一 简介

对象序列化就是把一个对象变成二进制的数据流的一种方法,通过对象序列化可以方便地实现对象的传输和存储。

把对象转换为字节序列的过程称为对象的序列化

把字节序列恢复为对象的过程称为对象的反序列化

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

对象序列化包括如下步骤:
1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
2) 通过对象输出流的writeObject()方法写对象。

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

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

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


二 Java中的序列化API

如果一个类的对象想被序列化,那么该对象所在的类必须实现java.io.Serializable接口,此接口的定义如下:

public interface Serializable{}

可以发现此接口并没有定义任何的方法,只是一个标识接口,表示一个类可以被序列化,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package  cn.zifangsky.serializable;
 
import  java.io.Serializable;
 
public  class  Person  implements  Serializable {
     private  static  final  long  serialVersionUID = 2651243789670519969L;
 
     private  String name;
     private  int  age;
 
     public  Person(String name,  int  age) {
         this .name = name;
         this .age = age;
     }
 
     public  String toString() {
         return  "Person [name="  + name +  ", age="  + age +  "]" ;
     }
 
}

就像上面这个Person类一样,实现了序列化接口表明此类的对象可以经过二进制的数据流进行传输了。但是如果想要完成对象的输入和输出,还需要借助对象输出流(ObjectOutputStream)和对象输入流(ObjectInputStream)

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

只有实现了Serializable或Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。


三 使用Serializable接口实现的实例

首先定义了一个实现了Serializable接口WebSite的实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package  cn.zifangsky.serializable;
 
import  java.io.Serializable;
 
public  class  WebSite  implements  Serializable {
     private  static  final  long  serialVersionUID = 1835573222135484360L;
 
     private  String siteName;
     private  String siteUrl;
     private  String webMaster;
 
     public  WebSite() {
 
     }
 
     public  WebSite(String siteName, String siteUrl, String webMaster) {
         this .siteName = siteName;
         this .siteUrl = siteUrl;
         this .webMaster = webMaster;
     }
 
     public  String getSiteName() {
         return  siteName;
     }
 
     public  void  setSiteName(String siteName) {
         this .siteName = siteName;
     }
 
     public  String getSiteUrl() {
         return  siteUrl;
     }
 
     public  void  setSiteUrl(String siteUrl) {
         this .siteUrl = siteUrl;
     }
 
     public  String getWebMaster() {
         return  webMaster;
     }
 
     public  void  setWebMaster(String webMaster) {
         this .webMaster = webMaster;
     }
 
     public  String toString() {
         return  "WebSite [siteName="  + siteName +  ", siteUrl="  + siteUrl +  ", webMaster="  + webMaster +  "]" ;
     }
 
}

然后进行序列化和反序列化测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package  cn.zifangsky.serializable;
 
import  java.io.File;
import  java.io.FileInputStream;
import  java.io.FileNotFoundException;
import  java.io.FileOutputStream;
import  java.io.IOException;
import  java.io.ObjectInputStream;
import  java.io.ObjectOutputStream;
 
public  class  TestSerialize {
 
     public  static  void  main(String[] args)  throws  FileNotFoundException, IOException, ClassNotFoundException {
         TestSerialize.serializeWebSite();
         TestSerialize.deserializeWebSite();
     }
     
     /**
      * 使用ObjectOutputStream 序列化WebSite
      * @throws IOException 
      * @throws FileNotFoundException 
     
      * */
     public  static  void  serializeWebSite()  throws  FileNotFoundException, IOException{
         WebSite webSite =  new  WebSite();
         webSite.setSiteName( "zifangsky的个人博客" );
         webSite.setSiteUrl( "http://www.zifangsky.cn" );
         webSite.setWebMaster( "zifangsky" );
         
         //序列化
         ObjectOutputStream objectOutputStream =  new  ObjectOutputStream( new  FileOutputStream( new  File( "C:/Users/Administrator/Desktop/test.txt" )));
         objectOutputStream.writeObject(webSite);
         objectOutputStream.flush();
         objectOutputStream.close();
     }
     
     /**
      * 使用ObjectInputStream 反序列化WebSite
      * @throws IOException 
      * @throws FileNotFoundException 
      * @throws ClassNotFoundException 
     
      * */
     public  static  void  deserializeWebSite()  throws  FileNotFoundException, IOException, ClassNotFoundException{
         ObjectInputStream objectInputStream =  new  ObjectInputStream( new  FileInputStream( new  File( "C:/Users/Administrator/Desktop/test.txt" )));
         //反序列化
         WebSite webSite = (WebSite) objectInputStream.readObject();
         objectInputStream.close();
 
         System.out.println(webSite);
     }
     
}

输出:

1
WebSite [siteName=zifangsky的个人博客, siteUrl=http://www.zifangsky.cn, webMaster=zifangsky]

四 使用Externalizable接口实现的实例

被Serializable接口声明的类的对象的内容都将被序列化,如果现在用户希望自己制定序列化的内容,则可以让一个类实现Externalizable接口,此接口的定义如下:

public interface Externalizable extends java.io.Serializable {
 
    void writeExternal(ObjectOutput out) throws IOException;

    void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

其中,这两个方法的作用是:

i)writeExternal(ObjectOutput out) :在此方法中制定要保存的属性信息,对象序列化时调用

ii)readExternal(ObjectInput in) : 在此方法中读取被保存的信息,对象反序列化时调用


下面将以一个具体的实例来简单说明序列化和反序列化过程:

(1)实现了Externalizable接口的实体类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package  cn.zifangsky.serializable;
 
import  java.io.Externalizable;
import  java.io.IOException;
import  java.io.ObjectInput;
import  java.io.ObjectOutput;
 
public  class  ExternalizableDemo  implements  Externalizable{
     private  String name;
     static  {
         System.out.println( "调用静态代码块" );
     }
 
     public  ExternalizableDemo() {
         System.out.println( "调用无参构造方法" );
     }
 
     public  ExternalizableDemo(String name) {
         this .name = name;
         System.out.println( "调用有参构造方法" );
     }
 
     public  String getName() {
         return  name;
     }
 
     public  void  setName(String name) {
         this .name = name;
     }
 
     public  String toString() {
         return  "ExternalizableDemo [name="  + name +  "]" ;
     }
     
     /**
      * ObjectOutputStream会调用writeExternal(ObjectOutput out))这个方法进行序列化
      * */
     public  void  writeExternal(ObjectOutput out)  throws  IOException {
         out.writeObject(name);
     }
 
     /**
      * ObjectInputStream会调用readExternal(ObjectInput in)这个方法进行反序列化
      * */
     public  void  readExternal(ObjectInput in)  throws  IOException, ClassNotFoundException {
         name = (String) in.readObject();
     }
 
}

(2)然后进行序列化和反序列化测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package  cn.zifangsky.serializable;
 
import  java.io.File;
import  java.io.FileInputStream;
import  java.io.FileNotFoundException;
import  java.io.FileOutputStream;
import  java.io.IOException;
import  java.io.ObjectInputStream;
import  java.io.ObjectOutputStream;
 
public  class  TestExternalizable {
 
     public  static  void  main(String[] args)  throws  FileNotFoundException, IOException, ClassNotFoundException {
         ExternalizableDemo demo =  new  ExternalizableDemo( "hello" );
         // 序列化
         ObjectOutputStream objectOutputStream =  new  ObjectOutputStream(
                 new  FileOutputStream( new  File( "C:/Users/Administrator/Desktop/test2.txt" )));
         objectOutputStream.writeObject(demo);
         objectOutputStream.flush();
         objectOutputStream.close();
         
         //反序列化
         ObjectInputStream objectInputStream =  new  ObjectInputStream( new  FileInputStream( new  File( "C:/Users/Administrator/Desktop/test2.txt" )));
         ExternalizableDemo demo2 = (ExternalizableDemo) objectInputStream.readObject();
         objectInputStream.close();
         System.out.println(demo2);     
     }
 
}

输出:

1
2
3
4
调用静态代码块
调用有参构造方法
调用无参构造方法
ExternalizableDemo [name=hello]

注:

(1)使用Externalizable进行序列化时,当读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中

(2)Externalizable接口与Serializable接口实现序列化的区别:

区别 Serializable Externalizable
实现负责度 实现简单,Java对其有内建支持 实现负责,由开发人员自己完成
执行效率 所有对象由Java统一保存,性能较低 开发人员自己决定保存那些对象,可能造成速度提升
保存信息 保存时占用空间大 部分存储,可能造成空间减小

(3)一个对象被序列化后,到底哪些内容被保存了下来,是属性还是方法?

答:只有属性被序列化。因为每个对象都有相同的方法,但是每个对象的属性却不一定相同,因此对象保存的只有属性信息,那么同样道理在进行序列化操作时也只有属性被序列化


五 transient关键字

当使用Serializable接口实现序列化操作时,如果一个对象中的某个属性不希望被序列化,那么就可以使用transient关键字进行声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package  cn.zifangsky.serializable;
import  java.io.Serializable;
 
public  class  WebSite  implements  Serializable {
     private  static  final  long  serialVersionUID = 1835573222135484360L;
 
     private  String siteName;
     private  String siteUrl;
     private  transient  String webMaster;
 
     public  WebSite(String siteName, String siteUrl, String webMaster) {
         this .siteName = siteName;
         this .siteUrl = siteUrl;
         this .webMaster = webMaster;
     }
 
     public  String toString() {
         return  "WebSite [siteName="  + siteName +  ", siteUrl="  + siteUrl +  ", webMaster="  + webMaster +  "]" ;
     }
 
}

在上面这个类中,不希望webMaster这个属性被序列化,因此把它用transient关键字进行修饰,接下来就是序列化与反序列化测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package  cn.zifangsky.serializable;
 
import  java.io.File;
import  java.io.FileInputStream;
import  java.io.FileNotFoundException;
import  java.io.FileOutputStream;
import  java.io.IOException;
import  java.io.ObjectInputStream;
import  java.io.ObjectOutputStream;
 
public  class  TestSerialize {
 
     public  static  void  main(String[] args)  throws  FileNotFoundException,
             IOException, ClassNotFoundException {
         TestSerialize.serializeWebSite();
         TestSerialize.deserializeWebSite();
     }
 
     /**
      * 使用ObjectOutputStream 序列化WebSite
     
      * @throws IOException
      * @throws FileNotFoundException
     
      * */
     public  static  void  serializeWebSite()  throws  FileNotFoundException,
             IOException {
         WebSite webSite =  new  WebSite( "zifangsky的个人博客" , "http://www.zifangsky.cn" , "zifangsky" );
 
         // 序列化
         ObjectOutputStream objectOutputStream =  new  ObjectOutputStream(
                 new  FileOutputStream( new  File(
                         "C:/Users/Administrator/Desktop/test.txt" )));
         objectOutputStream.writeObject(webSite);
         objectOutputStream.flush();
         objectOutputStream.close();
     }
 
     /**
      * 使用ObjectInputStream 反序列化WebSite
     
      * @throws IOException
      * @throws FileNotFoundException
      * @throws ClassNotFoundException
     
      * */
     public  static  void  deserializeWebSite()  throws  FileNotFoundException,
             IOException, ClassNotFoundException {
         ObjectInputStream objectInputStream =  new  ObjectInputStream(
                 new  FileInputStream( new  File(
                         "C:/Users/Administrator/Desktop/test.txt" )));
         // 反序列化
         WebSite webSite = (WebSite) objectInputStream.readObject();
         objectInputStream.close();
 
         System.out.println(webSite);
     }
 
}

输出:

1
WebSite [siteName=zifangsky的个人博客, siteUrl=http://www.zifangsky.cn, webMaster=null]

从上面的输出可以看出,webMaster这个属性并没有被序列化




本文转自 pangfc 51CTO博客,原文链接:http://blog.51cto.com/983836259/1758247,如需转载请自行联系原作者

相关文章
|
1月前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
1月前
|
存储 安全 Java
🌟Java零基础-反序列化:从入门到精通
【10月更文挑战第21天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
82 5
|
1月前
|
存储 缓存 安全
🌟Java零基础:深入解析Java序列化机制
【10月更文挑战第20天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
30 3
|
1月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
|
2月前
|
存储 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第9天】在Java的世界里,对象序列化是连接数据持久化与网络通信的桥梁。本文将深入探讨Java对象序列化的机制、实践方法及反序列化过程,通过代码示例揭示其背后的原理。从基础概念到高级应用,我们将一步步揭开序列化技术的神秘面纱,让读者能够掌握这一强大工具,以应对数据存储和传输的挑战。
|
1月前
|
存储 缓存 NoSQL
一篇搞懂!Java对象序列化与反序列化的底层逻辑
本文介绍了Java中的序列化与反序列化,包括基本概念、应用场景、实现方式及注意事项。序列化是将对象转换为字节流,便于存储和传输;反序列化则是将字节流还原为对象。文中详细讲解了实现序列化的步骤,以及常见的反序列化失败原因和最佳实践。通过实例和代码示例,帮助读者更好地理解和应用这一重要技术。
48 0
|
1天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
3天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
3天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
3天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
15 3