我们知道在JAVA类中,很多类都实现了Serializable类的方法,他的意思是将这个类在运行的时候进行序列化,这个接口类的注解是这么写的,

/ * @author  unascribed
 * @see java.io.ObjectOutputStream
 * @see java.io.ObjectInputStream
 * @see java.io.ObjectOutput
 * @see java.io.ObjectInput
 * @see java.io.Externalizable
 * @since   JDK1.1
 */

起源于JDK1.1版本,是属于java.io类里的接口。

1、那什么是序列化?

对象的状态有:

1.      创建阶段(Created)

2.      应用阶段(In Use)

3.      不可见阶段(Invisible)

4.      不可达阶段(Unreachable)

5.      收集阶段(Collected)

6.      终结阶段(Finalized)

7.      对象空间重分配阶段(De-allocated)

那么,如果一个对象在创建之后,如果我想把工程停下来,但是却又想保留住这个对象的信息,以便下次使用,那么怎么办呢?这个时候就是序列化Serializable起到作用的时候了,它把对象的状态和信息转换为字节序列保存到磁盘上,然后在你想使用的时候,通过一些java类方法可以再次读取到这个对象的信息和状态,重新获取该对象。那么如果在保存的时候如果有其他对象的引用,那么序列化过程中把其他对象的信息以递归的方式保存下来,整个保存的格式会是一个复杂的树形,最后读取也是以这个格式来获取对象。


2、如何进行序列化?

如果我们想要序列化一个对象,首先要创建某些OutputStream(如FileOutputStream、ByteArrayOutputStream等,其实就是Serializable类注

解上的呢些类的方法),然后将这些OutputStream封装在一个ObjectOutputStream中。这时候,只需要调用writeObject()方法就可以将对象序列化,

并将其发送给OutputStream(记住:对象的序列化是基于字节的,不能使用Reader和Writer等基于字符的层次结构)。而反序列的过程(即将一个序列还原成

为一个对象),需要将一个InputStream(如FileInputstream、ByteArrayInputStream等)封装在ObjectInputStream内,然后调用readObject()即可。

以下是代码示例:


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
        {
		//输出流保存的文件名为 my.out,ObjectOutputStream能把Object输出成Byte流
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("my.out"));
            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




3:序列化ID

在很多时候,发现model类中有呢么一个字段:


private static final long serialVersionUID = xxxxxxxxxxxxxxl;




可以很明显的看出来,这描述的是一个为long型的序列化ID,那么这个序列化ID是用来干什么的呢?


因为序列化的左右就是用来反序列化的,那么一个已经序列化的文件,在反序列化的时候,我如何知道这段时间中这个对象类是否有变化呢?假如我删了字段,其实如果将这个对象再反序列化回来是错误的,那么如何标记序列化对象和反序列化的时候的对象是否是一致的呢?就是用的这个序列化ID了,其实就相当于对这个对象hash出来了一个long的数值而已,这就是我的理解,如果这两个ID不一致,在反序列化的时候是会报错的。4:序列化的注意事项:

1、静态类是无法被序列化的。序列化的是对象的状态不是类的状态,静态成员属于类级别的,序列化会忽略静态变量,即序列化不保存静态变量的状态。

2、transient是一个瞬时状态,所以也是无法被序列化的。

3、当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口。

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