# 對象流ObjectInputStream和ObjectOutputStream ## 引言 - 看一個需求 1. 將int num=100這個 int 數據保存到文件中,註意不是 100 數字,而是 int 100,並且,能夠從文件中直接恢復 int 100; 2. 將Dog dog = new ...
對象流ObjectInputStream和ObjectOutputStream
引言
-
看一個需求
- 將int num=100這個 int 數據保存到文件中,註意不是 100 數字,而是 int 100,並且,能夠從文件中直接恢復 int 100;
- 將Dog dog = new Dog("小黃",3)這個dog對象保存到文件中,並且能夠從文件恢復;
- 上面的要求,就是能夠將 基本數據類型 或者 對象 進行 序列化 和 反序列化 操作;
-
序列化和反序列化
- 序列化就是在保存數據時,保存數據的值和數據類型;
- 反序列化就是在恢複數據時,恢復數據的值和數據類型;
- 需要讓某個對象支持序列化機制,則必須讓其類是可序列化的,為了讓某個類是可序列化的,該類必須實現如下兩個介面之一:
- Serializable:這是一個標記介面,沒有方法
- Externalizable:該介面有方法需要實現,因此我們一般實現上面的Serializable
-
基本介紹
- 功能:提供了對基本類型或對象類型的序列化和反序列化的方法;
- ObjectOutputStream 提供 序列化功能;
- ObjectInputStream 提供 反序列化功能;
ObjectOutputStream
代碼演示:
import java.io.*;
/**
* @author: 86199
* @date: 2023/5/5 21:51
* @description: 演示ObjectOutputStream的使用,完成數據的序列化
*/
public class ObjectOutputStream_ {
public static void main(String[] args) throws IOException {
//序列化後,保存的文件格式,不是純文本,而是按照序列化自己規定的格式來保存
String filePath = "e:\\data.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
//序列化數據到 e:\data.dat
oos.writeInt(100);//int -> Integer(實現了 Serializable)
oos.writeBoolean(true);//boolean -> Boolean(實現了 Serializable)
oos.writeChar('a');//char -> Character(實現了 Serializable)
oos.writeDouble(9.5);//double -> Double(實現了 Serializable)
oos.writeUTF("紅樓夢");//String
//保存一個dog對象
oos.writeObject(new Dog("旺財",10));
//關閉流
oos.close();
System.out.println("數據保存完畢(序列化形式)");
}
}
Dog類代碼:
import java.io.Serializable;
/**
* @author: 86199
* @date: 2023/5/5 23:09
* @description:
*/
//如果需要序列化某個對象,實現 Serializable
public class Dog implements Serializable {
private String name;
private int age;
//序列化對象時,預設將裡面所有的屬性都進行序列化,但除了static或transient修飾的成員
private static String nation;
private transient String color;
//序列化對象化時,要求裡裡面的屬性的類型也必須實現序列化介面
private Master master = new Master();
//serialVersionUID 序列化的版本號,可以提高相容性
//這樣對該類進行修改後,進行序列化或者反序列化時就不會認為該類
//是全新的類,只是進行了版本更新
//對象的序列化反序列化是根據序列化版本id進行的,沒有顯式得寫出來會預設根據類的屬性和方法分配一個。導致對象序列化入庫之後,若類被修改,反序列化將會報錯。所以顯式加上序列化版本id,避免反序列化報錯
private static final long serialVersionUID = 1L;
public Dog(String name, int age, String nation, String color) {
this.name = name;
this.age = age;
this.color = color;
this.nation = nation;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", color = '" + color + '\'' +
", nation = '" + nation + '\'' +
'}' + " " + master;
}
}
ObjectInputStream
代碼演示:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import com.hsp.outputstream_.Dog;
/**
* @author: 86199
* @date: 2023/5/5 22:28
* @description: 演示ObjectInputStream的使用,完成數據的反序列化
*/
public class ObjectInputStream_ {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//指定反序列化的文件
String filePath = "e:\\data.dat";
//反序列化時,要保證和序列化時的信息是一致的,若被序列化的數據的類信息有改動,此時直接反序列化自然會出錯,需要重新序列化數據(如果Dog加了serialVersionUID就不會報錯)
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());
Object dog = ois.readObject();//底層Object -> Dog
System.out.println("運行類型 = " + dog.getClass());
System.out.println("dog信息 = " + dog);
//要想使用 我們這個反序列化來的Dog對象,還得使Dog可以在這被引用,然後向下轉型
//1. 如果我們希望調用Dog的方法,需要向下轉型
//2. 需要我們將Dog類的定義,放在可以引用的位置
Dog dog2 = (Dog)dog;
System.out.println(dog2.getName());
//關閉流
ois.close();
}
}
/*運行結果
100
true
a
9.5
紅樓夢
運行類型 = class com.hsp.outputstream_.Dog
dog信息 = Dog{name='旺財', age=10, color = 'null', nation = 'null'} com.hsp.outputstream_.Master@66a29884
旺財
*/