`
zhaojingyu_ok
  • 浏览: 12562 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java 序列化Serializable详解(附详细例子)

    博客分类:
  • JAVA
阅读更多

Java 序列化Serializable详解(附详细例子)

1、什么是序列化和反序列化
Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。

 

2、什么情况下需要序列化 
a)当你想把的内存中的对象保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;

3、如何实现序列化

将需要序列化的类实现Serializable接口就可以了,Serializable接口中没有任何方法,可以理解为一个标记,即表明这个类可以序列化。

 

4、序列化和反序列化例子

如果我们想要序列化一个对象,首先要创建某些OutputStream(如FileOutputStream、ByteArrayOutputStream等),然后将这些OutputStream封装在一个ObjectOutputStream中。这时候,只需要调用writeObject()方法就可以将对象序列化,并将其发送给OutputStream记住:对象的序列化是基于字节的,不能使用Reader和Writer等基于字符的层次结构。而反序列的过程(即将一个序列还原成为一个对象),需要将一个InputStream(如FileInputstream、ByteArrayInputStream等)封装在ObjectInputStream内,然后调用readObject()即可。

 

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
package com.sheepmu;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
 
public class MyTest implements Serializable
{
    private static final long serialVersionUID = 1L;
    private String name="SheepMu";
    private int age=24;
    public static void main(String[] args)
    {//以下代码实现序列化
        try
        {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("my.out"));//输出流保存的文件名为 my.out ;ObjectOutputStream能把Object输出成Byte流
            MyTest myTest=new MyTest();
            oos.writeObject(myTest);
            oos.flush();  //缓冲流
            oos.close(); //关闭流
        } catch (FileNotFoundException e)
        {       
            e.printStackTrace();
        } catch (IOException e)
        {
            e.printStackTrace();
        }
        fan();//调用下面的  反序列化  代码
    }
    public static void fan()//反序列的过程
    {   
         ObjectInputStream oin = null;//局部变量必须要初始化
        try
        {
            oin = new ObjectInputStream(new FileInputStream("my.out"));
        } catch (FileNotFoundException e1)
        {       
            e1.printStackTrace();
        } catch (IOException e1)
        {
            e1.printStackTrace();
        }     
        MyTest mts = null;
        try {
            mts = (MyTest ) oin.readObject();//由Object对象向下转型为MyTest对象
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }    
         System.out.println("name="+mts.name);   
         System.out.println("age="+mts.age);   
    }
}

会在此项目的工作空间生成一个 my.out文件。序列化后的内容稍后补齐,先看反序列化后输出如下:

 

name=SheepMu
age=24

5、序列化ID

序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成),在这里有一个建议,如果没有特殊需求,就是用默认的 1L 就可以,这样可以确保代码一致时反序列化成功。这也可能是造成序列化和反序列化失败的原因,因为不同的序列化id之间不能进行序列化和反序列化。

 

6.序列化前和序列化后的对象的关系

是 "=="还是equal? or 是浅复制还是深复制? 

答案:深复制,反序列化还原后的对象地址与原来的的地址不同

序列化前后对象的地址不同了,但是内容是一样的,而且对象中包含的引用也相同。换句话说,通过序列化操作,我们可以实现对任何可Serializable对象的”深度复制(deep copy)"——这意味着我们复制的是整个对象网,而不仅仅是基本对象及其引用。对于同一流的对象,他们的地址是相同,说明他们是同一个对象,但是与其他流的对象地址却不相同。也就说,只要将对象序列化到单一流中,就可以恢复出与我们写出时一样的对象网,而且只要在同一流中,对象都是同一个。

 

7.静态变量能否序列化

若把上面的代码中的 age变量前加上 static ,输出任然是

name=SheepMu
age=24

但是看下面的例子:

 

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
package com.sheepmu;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class MyTest implements Serializable
{
    private static final long serialVersionUID = 1L;
    private String name="SheepMu";
    private static int age=24;
    public static void main(String[] args)
    {//以下代码实现序列化
        try
        {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("my.out"));//输出流保存的文件名为 my.out ;ObjectOutputStream能把Object输出成Byte流
            MyTest myTest=new MyTest();
            oos.writeObject(myTest);
            oos.flush();  //缓冲流
            oos.close(); //关闭流
        } catch (FileNotFoundException e)
        {       
            e.printStackTrace();
        } catch (IOException e)
        {
            e.printStackTrace();
        }
        fan();//调用下面的  反序列化  代码
    }
    public static void fan()
    {
        new MyTest().name="SheepMu_1";//!!!!!!!!!!!!!!!!重点看这两行 更改部分
          age=1;<span style="font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; ">//!!!!!!!!!!!!!!!!!!!重点看这两行 更改部分</span>
         ObjectInputStream oin = null;//局部变量必须要初始化
        try
        {
            oin = new ObjectInputStream(new FileInputStream("my.out"));
        } catch (FileNotFoundException e1)
        {       
            e1.printStackTrace();
        } catch (IOException e1)
        {
            e1.printStackTrace();
        }     
        MyTest mts = null;
        try {
            mts = (MyTest ) oin.readObject();//由Object对象向下转型为MyTest对象
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }    
         System.out.println("name="+mts.name);   
         System.out.println("age="+mts.age);   
    }
}

输出结果为:

 

name=SheepMu
age=1
为何把最上面代码的age变量添上static 后还是反序列化出了24呢?而新的从新对变量赋值的代码,不是static的得到了序列化本身的值,而static的则得到的是从新附的值。原因: 序列化会忽略静态变量,即序列化不保存静态变量的状态。静态成员属于类级别的,所以不能序列化。即 序列化的是对象的状态不是类的状态。这里的不能序列化的意思,是序列化信息中不包含这个静态成员域。最上面添加了static后之所以还是输出24是因为该值是JVM加载该类时分配的值。注:transient后的变量也不能序列化,但是情况稍复杂,稍后开篇说。

8、总结:

a)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;

b)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

c) static,transient后的变量不能被序列化;

 

分享到:
评论

相关推荐

    java序列化全解

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

    Java 对象序列化详解以及实例实现和源码下载

    Java中的序列化机制有两种实现方式: 一种是实现Serializable接口 另一种是实现Externalizable接口 区别: 实现Serializable接口 1 系统自动储存必要的信息 2 Java内建支持,易于实现,只需实现该接口即可,无须任何...

    java序列化原理与算法

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

    Java对象Serializable接口实现详解

    Java中的Serializable接口是java.io包中定义的,用于实现Java类的序列化操作而提供的一个语义级别的接口。Serializable序列化接口没有任何方法或者字段,只是用于标识可序列化的语义。实现了Serializable接口的类...

    Java序列化的机制和原理

    #### 六、Java序列化算法详解 Java序列化算法主要包括以下几个步骤: 1. **输出类元数据**:首先输出对象所属类的元数据,包括类名、父类名等信息。 2. **递归输出父类描述**:如果类有父类,则递归输出父类的描述...

    Java 序列化详解及简单实现实例

    Java 序列化详解及简单实现实例 Java 序列化是将对象状态转换为可保持或传输的格式的过程。在 Java 中,序列化是通过实现 Serializable 接口或 Externalizable 接口来实现的。序列化的主要目的是使自定义对象持久化...

    什么是Java的序列化和反序列化?如何实现对象的序列化和反序列化?(java面试题附答案).txt

    ### Java中的序列化与反序列化详解 #### 一、概念理解 在Java中,序列化(Serialization)指的是将对象的状态转化为字节流的过程,这一过程通常用于存储对象或者在网络中传输对象。相反地,反序列化...

    java串行化详细的介绍了java串行化的概念

    ### Java序列化详解 在Java开发中,序列化是一个非常重要的概念,它涉及到对象的状态转换为可以存储或传输的形式,并且能够在之后将其恢复为原始形式的过程。本文将深入探讨Java序列化的各个方面,包括其概念、原理...

    序列化之writeReplace方法应用

    在Java序列化过程中,可以通过多种方式来控制哪些字段被序列化,哪些不被序列化: 1. **使用`transient`关键字**:这是一种最简单的控制序列化的方式。只要在一个字段前加上`transient`关键字,该字段就不会被序列...

    详解Java 对象序列化和反序列化

    Java提供了内置的支持来进行对象的序列化和反序列化,主要通过实现`java.io.Serializable`接口来实现。 1. **简洁的代码实现** Java对象序列化的简化代码主要体现在使用`ObjectOutputStream`和`ObjectInputStream`...

    javafaq javafaq javafaq

    序列化是Java提供的一种将对象的状态转换为字节流,以便存储到磁盘或者在网络中传输的技术。通过序列化,我们可以将对象持久化,即使程序结束,对象的状态也能被保存下来,下次启动时可以恢复。 当一个类实现了`...

    java序列化和serialVersionUID的使用方法实例

    在 Java 中,序列化是通过实现 Serializable 接口来实现的,该接口没有任何方法,只是标示该类对象可被序列化。序列化过程中,使用 OutputStream 将对象写出,而反序列化过程中,使用 InputStream 将对象读出。 ...

    java教程之对象序列化使用基础示例详解

    需要注意的是,并非所有Java类都默认支持序列化,例如`java.net.Socket`就不可序列化,而`String`, `Vector`等类则已经实现了`Serializable`接口。`Hashtable`类就是一个没有实现序列化的例子。 Java提供了两个核心...

    java 中序列化与readResolve()方法的实例详解

    在Java编程语言中,序列化是一种将对象的状态转换为字节流的过程,以便...如果你在实际应用中遇到关于Java序列化或`readResolve()`方法的问题,可以查阅更多相关文档或在线社区进行讨论,以获取更深入的理解和支持。

    Java enum的用法详解

    如果不想让枚举实例被序列化,可以在枚举类型上实现`Serializable`接口并添加`transient`关键字: ```java public enum Shape implements Serializable { // ... private transient double constant; // ... } ...

    Java_transient关键字

    在Java编程语言中,`transient`关键字是一个非常重要的概念,主要用于对象序列化过程中对特定变量的控制。当一个类实现了`Serializable`接口时,其对象可以被序列化为一个持久化的存储形式,以便在网络上传输或存储...

    java输入输出流详解.doc

    ### Java 输入输出流详解 #### 一、I/O流概述 在Java中,输入输出流是处理文件读写、网络通信等数据交换的基础。Java提供了丰富的API来支持这些操作,主要包括`java.io`包下的各类流对象。这些流对象按照处理的...

    Java软件开发实战 Java基础与案例开发详解 5-8 javaBean 共5页.pdf

    - **序列化**:JavaBean可以通过实现`Serializable`接口来支持序列化,这样就可以将对象的状态保存到磁盘或在网络间传输。 - **监听器**:对于需要监听属性变化的情况,可以使用Bound属性和相应的监听器模式。 综上...

    java中的SuppressWarnings(xxx).doc

    为了确保序列化的对象能够在不同版本间正确地反序列化,Java 引入了 `serialVersionUID`。 ##### 1.3 编译警告 如果不显式定义 `serialVersionUID`,IDE(如 Eclipse)会在编译时发出警告,提醒开发者应该定义一个...

Global site tag (gtag.js) - Google Analytics