我们知道在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、当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化。