简单的说,是对对象进行序列化的处理,以流的形式进行传输。其目的是为了保存在内存中的各种对象的状态,并且可以把保存的对象状态再读出来。
Java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据。可以将整个对象层次写入字节流中,可以保存在文件中或在网络连接上传递。利用对象序列化可以进行对象的“深复制”,即复制对象本身及引用的对象本身。序列化一个对象可能得到整个对象序列。
实现对象的序列化非常简单,只需对象实现了Serializable接口即可(该接口仅是一个标记,没有方法)。在Java 1.1中,许多标准库类都发生了改变,以便能够序列化——其中包括用于基本数据类型的全部封装器、所有集合类以及其他许多东西。甚至Class对象也可以序列化。
序列化一个对象的步骤:
1.首先要创建某些OutputStream对象
2.然后将其封装到ObjectOutputStream对象内。
3.用ObjectOutputStream的对象调用writeObject()用于实现存储一个对象,完成了对对象的序列化
4.创建InputStream对象
5.将其封装到ObjectInputStream对象内
6.用ObjectInputStream的对象调用readObject()用于实现读取一个对象
说了这么多,来看一个例子。一道题目:
定义一个信息类(Information),将由10个信息对象组成的链表(可直接使用java集合类)写入d:\\1.ser中,然后再从文件中读回这10个对象,并在屏幕上输出来,要求用对象序列化实现。
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package information;
import java.io.*;
import java.util.*;
/**
*
* @author Soledad
*/
public class Information {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
List<Inf> list =new LinkedList<Inf>();
list.add(new Inf("abc"));
list.add(new Inf("def"));
list.add(new Inf("ghi"));
list.add(new Inf("jkl"));
list.add(new Inf("mno"));
list.add(new Inf("pqr"));
list.add(new Inf("stu"));
list.add(new Inf("vwx"));
list.add(new Inf("yza"));
list.add(new Inf("bcd"));
try {
OutputStream os = new FileOutputStream("d:\\1.ser");//创建OutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(os);//封装到ObjectOutputStream内
oos.writeObject(list);//调用writeObject()函数
oos.flush();
InputStream is = new FileInputStream("d:\\1.ser");//创建InputStream对象
ObjectInputStream ois = new ObjectInputStream(is);//封装到ObjectInputStream内
List<Inf> l=(LinkedList<Inf>)ois.readObject();//调用readObject()函数
for(int i=0;i<10;i++)
{
Inf inf = l.get(i);
System.out.println(inf.getString());
}
// TODO code application logic here
}
catch(Exception e){
e.printStackTrace();
}
}
}
//Inf对象实现Serializable接口
class Inf implements Serializable{
private String str;
public String getString(){
return str;
}
public Inf(String s)
{str=s;
}
}
代码里30~37行即为实现序列化操作的步骤。
在代码的最后对Inf对象实现了Serializable接口。
这样子,对象的序列化就大功告成了。
需要注意的几点事项:
(1)如果某个类能够被串行化,其子类也可以被串行化。如果该类有父类,则分两种情况来考虑,如果该父类已经实现了可串行化接口。则其父类的相应字段及属性的处理和该类相同;如果该类的父类没有实现可串行化接口,则该类的父类所有的字段属性将不会串行化。
(2)声明为static和transient类型的成员数据不能被串行化。因为static代表类的状态, transient代表对象的临时数据;
(3)对于父类的处理,如果父类没有实现串行化接口,则其必须有默认的构造函数(即没有参数的构造函数)。否则编译的时候就会报错。在反串行化的时候,默认构造函数会被调用。但是若把父类标记为可以串行化,则在反串行化的时候,其默认构造函数不会被调用。这是为什么呢?这是因为Java 对串行化的对象进行反串行化的时候,直接从流里获取其对象数据来生成一个对象实例,而不是通过其构造函数来完成。
另外,writeObject和readObject本身就是线程安全的,传输过程中是不允许被并发访问的。所以先不用担心线程冲突的问题。