对象有状态和行为两种属性。行为存在于类中,而状态存在于个别的对象中。存储状态的选择有很多种,这可能要看你如何使用存储下来的状态而决定。下面我们讨论两种选项:
        如果只有自己写的Java程序会用到这些数据:用序列化(Serialization)
        如果数据需要被其他程序引用:写一个纯文本文件。用其他程序可以解析的特殊字符写到文件中。譬如:tab
        序列化的文件是很难让一般人阅读的,但它比纯文本文件更容易让程序恢复对象的状态,也比较安全。
        当然还有其他的选择。你可以将数据存进任何格式中。
        对象序列化的步骤:
        1.
创建出FileOutputStream
            FileOutputStream fileStream = new FileOutputStream("MyGame.ser");
        2.创建出ObjectOutputStream
            ObjectOutputStream os = new ObjectOutputStream(fileStream);
        3.写入对象
            os.writeObject(characterOne);
            os.writeObject(characterTwo);
            os.writeObject(characterThree);
        4.关闭ObjectOutputStream
            os.close();
       
        Java的输入/输出API带有连接类型的串流,它代表来源与目的地之间的连接,连接串流将串流与其他串流连接起来。
        一般来说,串流要两两连接才能做出有意义的事情--其中一个表示连接,另一个则是要被调用方法的。为何要两个?因为连接的串流通常都是很低层的。以FileOutputStream为例,它有可以写入字节的方法。但我们通常不会直接写字节,而是以对象层次的观点来写入,所以需要高层的连接串流。那为何不以单一的串流来执行呢?这就要考虑到良好的面向对象设计了。每个类只要做好一件事。FileOutputStream把字节写入文件。ObjectOutputStream把对象转换成可以写入串流的数据。当我们调用ObjectOutputStream的writeObject方法时,对象会被打成串流送到FileOutputStream来写入文件。
        对象序列化的时候发生了什么事?
        
对象实例变量的值及Java虚拟机所需的信息被保存下来。
        对象的状态是什么?有什么需要保存?
        当对象被序列化时,被该对象引用的实例变量也会被序列化。且所有被引用的对象也会被序列化……最棒的是,这些操作都是自动的。
        如果要让类能够被序列化,就实现Serializable接口
        
Serializable接口又被称为marker或tag类的标记用接口,因为此接口并没有任何方法需要实现的[备注:该接口没有任何变量及方法]。它的唯一目的就是声明实现它的类是可以被序列化的。[关于该接口的介绍:http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/io/Serializable.html]
        例子:
                import java.io.*;
                public class Box implements Serializable{
                        
                }
        整个对象版图都必须正确地序列化,不然就得全部失败。如果某个实例变量不能或不应该被序列化,就把它标记为transient(瞬时)的。
        
        
解序列化:还原对象
                
序列化的反向操作。
        步骤如下:
         1.创建FileInputStream
         FileInputStream fileStream = new FileInputStream("MyGame.ser");
         2.创建ObjectInputStream
         ObjectInputStream os = new ObjectInputStream(fileStream);
         3.读取对象
         Object one = os.readObject();
         Object two = os.readObject();
         Object three = os.readObject();
         4.转换对象类型
          GameCharacter elf = (GameCharacter) one;
          GameCharacter troll = (GameCharacter) two;
          GameCharacter magician = (GameCharacter) three;
         5.关闭
          os.close();
         解序列化时发生了什么?
         当对象被解序列化时,Java虚拟机会通过尝试在堆上创建新的对象,让它维持与被序列化时有相同的状态来恢复对象的原态。但这当然不包括transient的变量,它们不是null便是使用primitive主数据类型的默认值。
         具体过程如下:
         1.对象从Stream中读出来
         2.Java虚拟机通过存储的信息判断出对象的class类型
         3.Java虚拟机尝试查找和加载对象的类。如果找不到或者无法加载该类,则会抛出异常。
         4.新的对象会被配置在堆上,但构造函数不会执行。
         5.如果该对象在继承树上有个不可序列化的祖先类,则该不可序列化类以及在它之上的类的构造函数就会执行。
         6.对象的实例变量会被还原成序列化时点的状态值。
         
         静态变量会被序列化么?[no]

         下面列出一个完整例子来展示序列化以及反序列化:
          
         
 1package serial;
 2
 3import java.io.Serializable;
 4
 5/**
 6 *
 7 * @author Administrator
 8 */

 9public class GameCharacter implements Serializable {
10
11    int power;
12    String type;
13    String[] weapons;
14
15    public GameCharacter(int p, String t, String[] w) {
16        this.power = p;
17        this.type = t;
18        this.weapons = w;
19    }

20
21    public int getPower() {
22        return power;
23    }

24
25    public String getType() {
26        return type;
27    }

28
29    public String getWeapons() {
30        String weaponsList = "";
31        for (int i = 0; i < weapons.length; i++{
32            weaponsList += weapons[i] + " ";
33        }

34        return weaponsList;
35    }

36}

37

 1package serial;
 2
 3import java.io.FileInputStream;
 4import java.io.FileOutputStream;
 5import java.io.IOException;
 6import java.io.ObjectInputStream;
 7import java.io.ObjectOutputStream;
 8
 9/**
10 *
11 * @author Administrator
12 */

13public class GameSaverTest {
14
15    public static void main(String[] args) {
16        GameCharacter one = new GameCharacter(50"Elf"new String[]{"bow""sword""dust"});
17        GameCharacter two = new GameCharacter(50"Troll"new String[]{"bare hands""big ax"});
18        GameCharacter three = new GameCharacter(50"Magician"new String[]{"spells""invisibility"});
19
20        try {
21            //将one, two, three序列化到storage.ser
22            FileOutputStream fileStream = new FileOutputStream("storage.ser");
23            ObjectOutputStream os = new ObjectOutputStream(fileStream);
24            os.writeObject(one);
25            os.writeObject(two);
26            os.writeObject(three);
27            os.close();
28        }
 catch (IOException ex) {
29            ex.printStackTrace();
30        }

31        one = null;
32        two = null;
33        three = null;
34        try {
35            //从storage.ser中按照序列化的顺序读取出one, two, three
36            FileInputStream fileInputStream = new FileInputStream("storage.ser");
37            ObjectInputStream is = new ObjectInputStream(fileInputStream);
38            one = (GameCharacter) is.readObject();
39            two = (GameCharacter) is.readObject();
40            three = (GameCharacter) is.readObject();
41            System.out.println(one.type);
42            System.out.println(two.type);
43            System.out.println(three.type);
44            is.close();
45
46        }
 catch (Exception ex) {
47            ex.printStackTrace();
48        }

49    }

50}

51
52
        此处为了简洁起便,抛出最顶层异常。
        运行结果如下:
        run:
        Elf
        Troll
        Magician
        成功生成(总时间:1 秒)


        在工程目录下,能看到“storage.ser”这个文件。用记事本打开,可看到以下内容:
 sr serial.GameCharacter恃83rV I powerL typet Ljava/lang/String;[ weaponst [Ljava/lang/String;xp   2t Elfur [Ljava.lang.String;V玳{G  xp   t bowt swordt dustsq ~     2t Trolluq ~    t
bare handst big axsq ~     2t Magicianuq ~    t spellst invisibility