Bootstrap

十一 Java序列化

序列化简介

Java 提供了一种对象序列化的机制,该机制中一个对象可以被表示为一个包含对象数据、对象类型信息和存储在对象中的数据类型的字节序列。将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。整个过程都是 Java 虚拟机(JVM)独立的,即在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象。
示例:序列化在Java中是怎样工作的,定义Employee类,该类实现了Serializable 接口。
Employee.java 文件代码:

public class Employee implements java.io.Serializable{
   public String name;
   public String address;
   public transient int SSN;
   public int number;
   public void mailCheck(){
      System.out.println("Mailing a check to " + name+ " " + address);
   }
}

序列化对象

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

用途
1)把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,需要用时再把保存在硬盘中的对象还原到内存中。
2)在网络上传送对象的字节序列。
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;

API
java.io.ObjectOutputStream代表对象输出流。
其writeObject(Object obj)方法可对指定obj对象进行序列化,并将字节序列写到目标输出流

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

序列化成功的条件
1.该类必须实现 java.io.Serializable 接口。
2.该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。

序列化的判断
判断一个 Java 标准类是否可序列化需查看该类的文档。
判断一个类的实例是否可序列化只需查看该类有没有实现 java.io.Serializable接口。

反序列化对象

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

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

API
java.io.ObjectInputStream代表对象输入流。
其readObject()方法可从源输入流中读取字节序列,并反序列化为对象作为返回。

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

实例

1.定义一个Person类,实现Serializable接口

/**测试对象序列化和反序列化***/
public class Person implements Serializable {
	// 实现Serializable接口的类都有一个表示序列化版本标识符的静态变量序列化ID,
    private static final long serialVersionUID = -5809782578272943999L;  
    private int age;
    private String name;
    private String sex;


    public int getAge() {
          return age;
    }

    public String getName() {
        return name;
    }
    public String getSex() {
        return sex;
    }

    public void setAge(int age) {
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
}

2.序列化和反序列化Person对象

public static void main(String[] args) throws Exception {
    SerializePerson();              // 序列化Person对象
    Person p = DeserializePerson();   // 反序列Perons对象
    System.out.println(MessageFormat.format("name={0},age={1},sex={2}",p.getName(), p.getAge(), p.getSex()));
}

/***序列化Person对象***/
private static void SerializePerson() throws FileNotFoundException,IOException {
    Person person = new Person();
    person.setName("gacl");
    person.setAge(25);
    person.setSex("男");
    // 将Person对象存储到E盘的Person.txt文件中,完成对Person对象的序列化操作
    ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(new File("E:/Person.txt")));
    oo.writeObject(person);
    System.out.println("Person对象序列化成功!");
    oo.close();
}

/*** Description: 反序列Perons对象***/
private static Person DeserializePerson() throws Exception, IOException {
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E:/Person.txt")));
    Person person = (Person) ois.readObject();
    System.out.println("Person对象反序列化成功!");
    return person;
}

serialVersionUID有两种生成方式:
1.采用这种方式生成的serialVersionUID是1L,例如:
private static final long serialVersionUID = 1L;
2.采用这种方式生成的serialVersionUID是根据类名,接口名,方法和属性等来生成的,例如:
private static final long serialVersionUID = 4603642343377807741L;

;