ObjectOutputStream && ObjectInputStream

ObjectOutputStream&&ObjectInputStream

处理流ObjectOutputStream&&ObjectInputStream

节点流&& 处理流

  1. 节点流:可以从一个特定的数据源(如:文件)读写数据,如:FileReader,FileWriter

  2. 处理流: (也叫包装流),是“连接”在已存在的流(节点流或处理流)之上

    image-20250403111505906

例如:BufferedReader类中有属性Reader,即可以封装一个节点流,该节点流可以是任意的,只要是Reader的子类就行(如上图:可以是文件,数组,管道,字符串…)

FileReader CharArrayReader PipedReader StringReader 都可以传进去 把它称为包装流

区别与联系

  1. 节点流是底层流/低级流,直接根数据源相接
  2. 处理流(包装流)包装节点流,使用了修饰器模式,不会直接与数据源项链
  3. 处理流对节点流进行包装,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出

处理流

拿BufferedReader来说,类里面有一个属性为Reader类的,构造器里传Reader类的 ,因此可以接受Reader子类的对象,就可以对它进行扩展(重写)


ObjectOutputStream

ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。 提供序列化功能

参数:OutputStream out:字节输出流。

  • 构造方法:

    ObjectOutputStream(OutputStream out) 因为它是一个处理流,所以需要一个节点流对象作为参数。

  • 成员方法(无返回值):

  • void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream (即ObjectOutputStream对象(把它叫做流对象吧)调用writeObject方法(流方法))

    eg:

    1
    2
     ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream(filePath));
    oos.writeObject(new Dog("旺财",10));
  • void writeInt (int …) void writeChar(char …) void writeBoolean(boolean …) 同理

ObjectInputStream

(对象的反序列化流)的构造方法:

  • 构造方法:

    ObjectInputStream(InputStream in) 创建从指定 InputStream 读取的 ObjectInputStream。
    参数:InputStream in:字节输入流

  • 成员方法:(读什么类型就返回什么类型的)

    • Object readObject() 从 ObjectInputStream 读取对象。 (这时就把对象看作一个大类)

      即ObjectInputStream对象 使用readInt,readBoolean,readChar,reaIdObject方法读取,返回读取Object类

      eg:

      1
      2
      3
       ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));

      Object dog = ois.readObject();
    • int readInt() boolean readBoolean() char readChar () String readUTF() 同理

序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.zhang.ObjectOutputStream;

import java.io.*;

public class ObjectOutStream {
public static void main(String[] args) throws IOException {

String filePath="D:\\aaa.txt";
ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream(filePath));

//序列化数据到 aaa.txt文件中
oos.writeInt(100);//int--->integer (实现了Serializable)
oos.writeBoolean(true);//boolean--->Boolean(实现了Serializable)
oos.writeChar('a');//char--->Character(实现了Serializable)
oos.writeDouble(3.14);//double--->Double(实现了Serializable)
oos.writeUTF("hello");//String

//保存一个Dog对象
oos.writeObject(new Dog("旺财",10)); //Dog和它在同一个包下所以可以直接用
}

}

Dog 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.zhang.ObjectOutputStream;

import java.io.Serializable;

public class Dog implements Serializable {

public int age;
public String name;
//serialVersionUID序列化的版本号,可以提高兼容性
private static final long serialVersionUID = 1L;
public Dog(String name,int age){
this.age=age;
this.name=name;
}
public String getName(){
return name;
}

@Override
public String toString() {
return "Dog{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}


反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.zhang.InputStream;
import com.zhang.ObjectOutputStream.Dog; //反序列化对象所属的类的路径必须与序列化时调用类的路径一致


import java.io.*;

public class ObjectInStream {


public static void main(String[] args) throws IOException, ClassNotFoundException {
//指定要反序列化的文件
String filePath="D:\\aaa.txt";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));

//读取的顺序(反序列化的顺序)一定要和保存顺序(序列化顺序)一致,否则会报异常
System.out.println(ois.readInt());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readDouble());
System.out.println(ois.readUTF());
//dog 的编译类型是Object,dog 的运行类型是Dog
Object dog = ois.readObject();
System.out.println("运行类型"+dog.getClass());
System.out.println(dog);
//特别重要的细节
//1.注意此时dog是Object类型的哦!Dog类中的方法只有Dog子类中存在,父类Object对象 dog 是不能调用子类中独有的对象的,需要向下强转
// dog.getName();!!不可以!!
//2.!!这里Dog的定义需放到同一个包下或可以引用的地方才能用) 总之序列化和反序列化引用的类的路径必须相同
Dog dog2= (Dog)dog;
System.out.println(dog2.getName());
ois.close();

}

}

小总结:

  • 创建ObjectInputStream (处理流)对象oos
  • 处理流对象oos调用读取对象的方法readObject() 返回Object类型的对象dog
  • 要调用序列化类的方法,需要向下强转为该类(Object—>Dog)再调用

  1. 读写顺序要一致
  2. 要求序列化或反序列化的对象,要实现Serializable
  3. 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
  4. 序列化对象时,默认将里面的所有属性都进行序列化,但是除了static或transient(短暂的)修饰的成员它们不会被序列化
  5. 序列化对象时,要求里面的属性类型也需要实现序列化接口,像int 之类的也是间接实现序列化接口,自定义一种类的时候要注意实现序列化接口
  6. 序列化具备可继承性,如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化

ObjectOutputStream && ObjectInputStream
https://bxhhf.github.io/2025/04/02/ObjectOutputStream&&ObjectInputStream/
作者
bxhhf
发布于
2025年4月2日
许可协议