前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java序列化和反序列化

Java序列化和反序列化

作者头像
悠扬前奏
发布2019-05-28 20:35:51
8300
发布2019-05-28 20:35:51
举报
1. Java序列化和反序列化(What)

Java序列化(Serialize)是指将一个Java对象写入IO流中; Java反序列化(Deserialize)指的是从IO流中回复IO对象。

2. 序列化的意义(Why)

序列化机制可以将Java对象转换为数据流用来保存在磁盘上或者通过网络传输。这使得对象可以脱离程序独立存在。

3. 如何进行序列化(How)

为了使对象支持序列化机制,需要让它的类变成可序列化的(serializable)。通过实现两个接口之一实现:

  • Serializable
  • Externalnalizable
3.1 序列化的步骤

实现了Serializable接口的类,可以通过两个步骤序列化该对象:

  1. 创建建立在其他节点流上的ObjectOutputStream
代码语言:javascript
复制
//创建ObjectOutputStream输出流
ObjectOutputStream oos = new ObejctOutputStream(new FileOutputStream("object.txt"));
  1. 调用ObjectOutputStream对象的writeObject()方法输出可序列化对象
代码语言:javascript
复制
//将一个Person对象输出到输出流中
oos.writeObject(per);
3.2 序列化的代码
  1. 定义一个Person类,实现了Serializable接口,标识该类的对象是可序列化的。
代码语言:javascript
复制
public class Person implements java.io.Serializable {
    private String name;
    private int age;

    // 这里没有无参构造器
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }

    // name和age的setter和getter方法
    ...
}
  1. 将Person对象写入硬盘
代码语言:javascript
复制
import java.io.*;
public class Test{
    public static void main(String[] args){
        try{
            // 创建ObjectOutputStream输出流
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Object.txt"));
            Person per = new Person("Junzerg", 20);
            // 将per对象写入输出流
            oos.writeObject(per);
        }
        catch (IOException ex){
            ex.printStackTrace();
        }
    }   
}
3.3 序列化结果

AC ED 00 05 73 72 00 06 50 65 72 73 6F 6E 2A 98 15 B9 5C 2E C1 6C 02 00 02 49 00 03 61 67 65 4C 00 04 6E 61 6D 65 74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 78 70 00 00 00

14 74 00 07 4A 75 6E 7A 65 72 67

共75字节。

3.4 序列化的字节数

把Person类的age属性设置为Long,重新序列化,结果为:

AC ED 00 05 73 72 00 06 50 65 72 73 6F 6E BE CF 78 98 E0 A3 0B E9 02 00 02 4A 00 03 61 67 65 4C 00 04 6E 61 6D 65 74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 78 70 00 00 00 00 00 00 00 14 74 00 07 4A 75 6E 7A 65 72 67

共79字节。

4. 反序列化
4.1 反序列化的步骤
  1. 创建一个建立在其他节点流基础上的ObjectInputStream输入流
代码语言:javascript
复制
// 出啊构建一个ObjectInputStream输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Object.txt"));
  1. 调用ObjectInputStream对象的readObject方法读取流中的对象,该方法返回一个Java对象,再强制转换为真实类型。
代码语言:javascript
复制
//从输入流中读取一个Java对象并将其强制类型转换成Person类
Person p = (Person) ois.readObject();
4.2 反序列化的代码

从前文创建的Object.txt中读取Person类

代码语言:javascript
复制
import java.io.*;
public class ReadObject{
    public static void main(String[] args){
        try{
            // 创建一个ObjectInputStream输入流
            ObjectInputStream ois = 
                new ObjectInputStream(new FileInputStream("Object.txt"));
            // 从输入流中读取一个Java对象,转换为Person类
                Person p = (Person)ois.readObject();
                System.out.println("name: " + p.getName()
                    + "\n age: " + p.getAge());
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
    }
}
4.3 反序列化的结果

name: Junzerg age: 20

5 对象引用的序列化和序列化算法
5.1 对象引用的序列化

如果要序列化的类的某个成员变量是一个非String类型的引用类型,那么这个引用类型必须是可序列化的。 例如有一个Teacher类持有Person类的引用

代码语言:javascript
复制
public class Teacher implements Seializable{
    private String name;
    Private Person student;
    public Teacher(String name, Person student){
        this.name = name;
        this.student = student;
    }
    // 省略name和student的stter和getter方法
    ...
}

为了在反序列化Teacher对象时正确恢复,Person类必须也是可序列化的,否则Teacher不可序列化

5.2 多个实例变量引用同一个引用对象的特殊情况

当两个Teacher对象引用同一个Person对象的时候:

代码语言:javascript
复制
Person per = new Person("Junzerg", 20);
Teacher t1 = new Teacher("Miss Li", per);
Teacher t2 = new Teacher("Mr Wu", per);

在程序依次序列化三个对象的过程中,看起来似乎会向输出流中输出三个Person对象。 这时当程序从输入流中反序列化这些对象时,就会得到三个Person对象,这样这样t1和t2引用的就不是同一个Person对象了。

5.3 Java序列化算法

为了避免5.2中出现的错误,Java的序列化算法如下:

  1. 所有保存在磁盘中的对象都有一个序列化编号
  2. 当程序试图序列化一个对象时,程序会先检查该对象是否已经被序列化过,只有改对象从未(在本次虚拟机中)被序列化过,系统才会将给对象转换成字节序列并出输出。
  3. 如果某个对象已经被序列化过,程序将直接出书一个序列化编号,而不是重新序列化该对象。
6. 自定义序列化
6.1 递归序列化

当对某个对象及进行序列化时,系统自动把该对象的所有实例变量依次进行序列化,如果某个实例变量引用另一个对象,则被引用的变量也会被序列化,这种情况被称为递归序列化。

6.2 transient关键字

在递归序列化的过程中,可能遇到不想被序列化或者不能被序列化的变量。这时可以使用transient关键字在序列化时忽略该变量,避免引发java.io.NotSerializableException异常。

6.3 transient关键字的使用
  1. 有带有transient关键字修饰的变量的Person类
代码语言:javascript
复制
public class Person implements java.io.Serializable {
    private String name;
    private transient int age;

    // 这里没有无参构造器
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }

    // name和age的setter和getter方法
    ...
}

注意:transient关键字只能用于修饰实例变量,不可修饰Java程序中的其他部分。

  1. Person对象的序列化和反序列化。
代码语言:javascript
复制
public class TransientTest{
    public static void main(String[] args){
        try{
            // 创建ObjectOutputStream输出流
            ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("transient.txt"));
            //创建ObjectInputStream输入流
            ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("transient.txt"));
            Person per = new Person("Junzerg", 20);
            // 将per对象序列化输出
            oos.writeObject(per);
            Person p = (Person) ois.readObject();
            System.out.println(p.getAge());
        }
        catch (Exception ex){
            ex.printStackTrace();
        }
    }
}
  1. 输出结果 3.1 控制台输出:

0

3.2 transient.txt内容为:

AC ED 00 05 73 72 00 06 50 65 72 73 6F 6E DB F9 DD 8C 83 99 C5 2E 02 00 01 4C 00 04 6E 61 6D 65 74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 78 70 74 00 07 4A 75 6E 7A 65 72 67

大小为65字节。

可以看到per实例中的age变量并没有序列化。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.07.24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Java序列化和反序列化(What)
  • 2. 序列化的意义(Why)
  • 3. 如何进行序列化(How)
    • 3.1 序列化的步骤
      • 3.2 序列化的代码
        • 3.3 序列化结果
          • 3.4 序列化的字节数
          • 4. 反序列化
            • 4.1 反序列化的步骤
              • 4.2 反序列化的代码
                • 4.3 反序列化的结果
                • 5 对象引用的序列化和序列化算法
                  • 5.1 对象引用的序列化
                    • 5.2 多个实例变量引用同一个引用对象的特殊情况
                      • 5.3 Java序列化算法
                      • 6. 自定义序列化
                        • 6.1 递归序列化
                          • 6.2 transient关键字
                            • 6.3 transient关键字的使用
                            相关产品与服务
                            文件存储
                            文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档