导语
程序运行时,在变量、数组和对象中存储的数据是暂时的,程序结束后他们就会丢失。为了保存程序运行的状态和产生的数据,避免每次程序启动都被初始化,我们可以将程序运行的状态和数据保存下来,等到程序再次启动的时候有选择性的恢复,这样我们就不必每次启动都要重新来过了,并且可以在其他的程序中使用。我们有两种方法来保存程序运行的状态和数据,分别是序列化和写入纯文本文件
序列化
我们可以将被序列化的对象写到文件中,然后就可以让你的程序去文件中读取序列化的对象并把他们展开回到活生生的状态
将序列化对象写入文件的过程一共有4步
- 创建出FileOutputStream,并指明序列化输出的文件
FileOutputStream fileStream=new FileOutputStream("MyData.ser");
2、 创建ObjectOutputStream,它能让你写入对象,但无法直接连接文件,需要参数的指引
ObjectOutputStream os=new ObjectOutputStream(fileStream);
3.写入对象
os.writeObject(new Object());
4.关闭ObjectOutputStream串流
os.close();
如果要让类能够被序列化,就要实现Serializable接口
这个接口并没有任何方法需要实现的,它的唯一目的就是声明实现它的类是可以被序列化的。也就是说,此类型的对象可以通过序列化的机制来存储。如果没类是可序列化的,则它的子类也自动地可以序列化
首先我们写一个可以被序列化的类
如果某实例变量不能或者不应该被序列化,就把它标记为transient(瞬间的)
import java.io.Serializable;
public class Game implements Serializable {//实现Serializable接口,声明可被序列化
transient private String name;//声明此对象不可被序列化
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Game(String name, int age) {//创建有参构造方法
this.name = name;
this.age = age;
}
}
接下来我们序列化这个类的对象
public static void main(String[] args) {
Game one=new Game("liqifeng", 19);//实例序列化对象
Game two=new Game("wuyachen",20);//实例序列化对象
try {
//创建FileOutputStream对象,并指明序列化输出的文件“Game.ser”
FileOutputStream out=new FileOutputStream("Game.ser");
//创建ObjectOutputStream对象,它能让你写入对象,但无法直接连接文件,需要参数的指引
ObjectOutputStream os=new ObjectOutputStream(out);
os.writeObject(one);//将对象所引用的对象序列化并写入“Game.ser”文件
os.writeObject(two);//将对象所引用的对象序列化并写入“Game.ser”文件
os.close();//关闭所关联的输出串流
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();//抛出异常
}
以上代码实现的对Game对象的序列化,并将序列化后的信息保存到了Game.ser
文件中。需要说明的是。序列化的文件是很难让一般人阅读的,但是它比纯文本文件更容易让程序恢复状态,也比较安全,因为一般人不知道要如何动手修改数据。
Ok,我们现在已经将文件序列化成功了,也就是说我们已经保存好了对象的状态与数据,现在我们需要解序列化,也就是还原程序运行的状态;
把程序恢复到存储时的状态,也就是解序列化,有点像序列化的反操作
我们需要五个步骤
1.创建出FileInputStream,并指明解序列化输出的文件
FileInputStream input = new FileInputStream("Game.ser");
2、 创建ObjectInputStream,它知道如何读取对象,但是要靠stream提供文件
ObjectInputStream in=new ObjectInputStream(input);
3、读取对象,返回一个Object()对象
Object oneObj=in.readObject();
Object twoObj=in.readObject();
4、转换对象类型
Game oneRestart=(Game)oneObj;
Game twoRestart=(Game)twoObj;
5、关闭流
in.colse();
Ok,介绍完解序列化的步骤,我们来接上一段的代码。上一段代码中我们把程序中序列化,在接下来的代码中我们将进行解序列化,恢复对象的状态
try {
//创建FileInputStream对象,并指名解序列化的文件“Game.ser”
FileInputStream input = new FileInputStream("Game.ser");
//创建ObjectInputStream对象,读取序列化文件“Game.ser”
ObjectInputStream in=new ObjectInputStream(input);
Object oneObj=in.readObject();//读取对象,返回一个Object()对象
Object twoObj=in.readObject();
Game oneRestart=(Game)oneObj;//转换对象类型
Game twoRestart=(Game)twoObj;
System.out.println(oneRestart.getAge());
System.out.println(twoRestart.getName());
in.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();//输出异常
}
上述代码执行后的输出结果是
19
null
为什么会出现null呢,因为我们声明了String name对象为不可序列化的,所以输出null
要点
- 可以通过序列化存储对象的状态
- 使用ObjectOutputStream来序列化对象
- 用FileOutputStream链接ObjectInputStream来将对象序列化到文件上
- 调用ObjectInputStream的writeObject(new Object())来将对象序列化
- 对象被标记为transient时,不可被序列化,否则,还原的时候会被赋予null等初始值
- 读取对象的顺序必须与写入的顺序相同
- readObject()方法返回的对象类型为Object类型,所以需要转换成原来的类型