疯狂Java学习笔记(56)------------对象序列化

时间:2023-02-26 11:35:12

疯狂Java学习笔记(56)------------对象序列化

所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象!
      
对象序列化是对象持久化的一种实现方法,它是将一个对象的属性和方法转化为一种序列化的格式以用于存储和传输,反序列化就是根据这些保存的信息重建对象的过程。
 
java对象序列化机制一般来讲有两种用途

1.需要将对象的状态保存到文件中(存储),而后能够通过读入对象状态来重新构造对象,恢复程序状态
2.使用套接字在网络上传送对象的程序来说,是很有用的(传输)。

  我们通过让类实现java.io.Serializable 接口可以将类序列化。这个接口是一个制造者(marker)接口。也就是说,对于要实现它的类来说,该接口不需要实现任何方法。它主要用来通知Java虚拟机(JVM),需要将一个对象序列化。

 对于这个,有几点我们需要明确:

1.并非所有类都可以序列化,在cmd下,我们输入serialver java.net.socket,可以得到socket是否可序列化的信息,实际上socket是不可序列化的。
2.java有很多基础类已经实现了serializable接口,比如string,vector等。但是比如hashtable就没有实现serializable接口。

 将对象读出或者写入流的主要类有两个: ObjectOutputStream与ObjectInputStream 。
ObjectOutputStream 提供用来将对象写入输出流的writeObject方法, ObjectInputStream提供从输入流中读出对象的readObject方法。使用这些方法的对象必须已经被序列化的
也就是说,必须已经实现Serializable接口。如果你想writeobject一个hashtable对象,那么,会得到一个异常。
 
在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。
 
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。
 
JDK类库中的序列化API
 

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


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


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

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

对象序列化和反序列范例:

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

[java] view plain copy
<span style="font-size:18px;">import java.io.Serializable;  
  
/** 
 * <p>ClassName: Person<p> 
 * <p>Description:测试对象序列化和反序列化<p> 
 * @author xudp 
 * @version 1.0 V 
 * @createTime 2014-6-9 下午02:33:25 
 */  
public class Person implements 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;  
    }  
}</span>  
序列化和反序列化Person类对象
<span style="font-size:18px;">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;  
import java.text.MessageFormat;  
  
/** 
 * <p>ClassName: TestObjSerializeAndDeserialize<p> 
 * <p>Description: 测试对象的序列化和反序列<p> 
 * @author xudp 
 * @version 1.0 V 
 * @createTime 2014-6-9 下午03:17:25 
 */  
public class TestObjSerializeAndDeserialize {  
  
    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()));  
    }  
      
    /** 
     * MethodName: SerializePerson  
     * Description: 序列化Person对象 
     * @author xudp 
     * @throws FileNotFoundException 
     * @throws IOException 
     */  
    private static void SerializePerson() throws FileNotFoundException,  
            IOException {  
        Person person = new Person();  
        person.setName("gacl");  
        person.setAge(25);  
        person.setSex("男");  
        // ObjectOutputStream 对象输出流,将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();  
    }  
  
    /** 
     * MethodName: DeserializePerson  
     * Description: 反序列Perons对象 
     * @author xudp 
     * @return 
     * @throws Exception 
     * @throws IOException 
     */  
    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;  
    }  
  
}</span>  

serialVersionUID的作用

 

简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)

 

举个实际应用的例子:

为了实现系统交互的目的,我们需要系统之间通过网络传输对象的实体(这些对象一般都是包括了系统中的一些数据)


Java序列化是一种解决方案:
系统A和B之间要进行交互,则A中的对象a首先会序列化,然后通过网络传输到系统B,在B中经反序列化还原,然后对其进行操作,利用对象a所提供的数据。

 

但要实现这种方案对原来的系统有如下的要求:


交互的系统之间要存在完全一致的对象模型,这就需要对原来的系统进行比较大的改变,不符合我们的要求。

因为序列化传输的数据是二进制格式的,除非把这些二进制的数据反序列化为对象,否则我们根本不能对其数据进行处理,也不能看到里面包含的数据是什么。
 要求交互的系统都是基于Java的,因为Java序列化只能应用与Java系统之中。

 

Serializable的作用
    为什么一个类实现了Serializable接口,它就可以被序列化呢?在上节的示例中,使用ObjectOutputStream来持久化对象,在该类中有如下代码:


转载自:https://blog.csdn.net/u011225629/article/details/46240783