Java对象序列化与文件I/O详解
立即解锁
发布时间: 2025-08-18 01:24:45 阅读量: 1 订阅数: 8 

### Java对象序列化与文件I/O详解
#### 1. 对象状态保存的需求与方法
在编程中,我们常常需要保存对象的状态。比如在游戏开发中,需要有保存和恢复游戏的功能;在图表应用中,需要有保存和打开文件的功能。保存对象状态有两种主要方式:
- **手动方式**:逐个询问对象,然后将每个实例变量的值以自定义的格式写入文件。这种方式比较繁琐,但在某些情况下是必要的,例如当应用保存的文件需要被其他非Java应用读取时。
- **面向对象方式**:使用序列化,将对象“冻干”、“扁平化”、“持久化”或“脱水”,然后在需要时将其“重构”、“膨胀”、“恢复”或“补水”。
#### 2. 保存Java程序状态的选项
根据数据的使用场景,有以下两种保存Java程序状态的选项:
|使用场景|保存方式|说明|
| ---- | ---- | ---- |
|仅由生成数据的Java程序使用|使用序列化|编写一个包含扁平化(序列化)对象的文件,然后让程序从文件中读取序列化对象并将其恢复为活动的对象。|
|由其他程序使用|编写纯文本文件|创建一个文件,使用分隔符,以便其他程序可以解析。例如,制表符分隔的文件可由电子表格或数据库应用程序使用。|
#### 3. 具体示例:保存游戏角色
假设我们有三个游戏角色需要保存,分别是精灵(Elf)、巨魔(Troll)和魔法师(Magician),它们有不同的属性,如力量、类型和武器。
- **选项一:序列化角色对象**
创建一个文件并写入三个序列化的角色对象。序列化文件对于人类来说很难阅读,但程序从序列化中恢复这三个对象比从文本文件中读取对象的变量值要容易(且安全)得多。示例代码如下:
```java
import java.io.*;
class GameCharacter implements Serializable {
int power;
String type;
String[] weapons;
public GameCharacter(int power, String type, String[] weapons) {
this.power = power;
this.type = type;
this.weapons = weapons;
}
}
public class SaveGameCharacters {
public static void main(String[] args) {
GameCharacter characterOne = new GameCharacter(50, "Elf", new String[]{"bow", "sword", "dust"});
GameCharacter characterTwo = new GameCharacter(200, "Troll", new String[]{"bare hands", "big ax"});
GameCharacter characterThree = new GameCharacter(120, "Magician", new String[]{"spells", "invisibility"});
try {
FileOutputStream fileStream = new FileOutputStream("MyGame.ser");
ObjectOutputStream os = new ObjectOutputStream(fileStream);
os.writeObject(characterOne);
os.writeObject(characterTwo);
os.writeObject(characterThree);
os.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
```
上述代码中,保存序列化对象的步骤如下:
1. 创建一个`FileOutputStream`对象,用于连接(并创建)一个文件。
2. 创建一个`ObjectOutputStream`对象,它可以写入对象,但需要一个“助手”(即与另一个流链接)。
3. 调用`writeObject()`方法将对象写入文件。
4. 关闭`ObjectOutputStream`,这将自动关闭`FileOutputStream`和文件。
- **选项二:编写纯文本文件**
创建一个文件并写入三行文本,每行代表一个角色,用逗号分隔状态信息:
```plaintext
50,Elf,bow, sword,dust
200,Troll,bare hands,big ax
120,Magician,spells,invisibility
```
然而,从文本文件中恢复对象时,可能会意外地以错误的顺序读取值,导致数据混乱。
#### 4. Java I/O流的工作原理
Java I/O API有连接流和链流。连接流表示与目的地和源(如文件或网络套接字)的连接,链流只有在与其他流链接时才能工作。通常需要至少两个流连接在一起才能完成有用的操作,一个表示连接,另一个用于调用方法。例如,`FileOutputStream`是一个连接流,它有写入字节的方法,但我们通常想写入对象,所以需要一个更高级的链流`ObjectOutputStream`。
以下是数据从对象到文件的流动过程的mermaid流程图:
```mermaid
graph LR
A[Object] --> B[ObjectOutputStream<br/>(a chain stream)]
B -->|object is flattened (serialized)| C[FileOutputStream<br/>(a connection stream)]
C -->|object is written as bytes| D[File]
```
#### 5. 对象序列化的细节
- **对象状态的保存**:对象在堆上有状态,即对象的实例变量的值。序列化对象时,会保存实例变量的值,以便在堆上恢复一个相同的实例。例如:
```java
class Foo implements Serializable {
private int width;
private int height;
public void setWidth(int w) {
width = w;
}
public void setHeight(int h) {
height = h;
}
}
public class SerializeFoo {
public static void main(String[] args) {
Foo myFoo = new Foo();
myFoo.setWidth(37);
myFoo.setHeight(70);
try {
FileOutputStream fs = new FileOutputStream("foo.ser");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(myFoo);
os.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
```
0
0
复制全文
相关推荐










