IO流(03)--序列化流、列印流
阿新 • • 發佈:2020-12-18
###序列化流
Java提供了一種**物件序列化**的機制,用一個位元組序列可以表示一個物件,該位元組序列包含該物件的資料、物件的型別和物件中儲存的屬性等資訊。位元組序列寫入到檔案中後,就相當於在檔案中儲存了一個物件資訊。
反之,該位元組序列還可以從檔案讀取出來,重構物件,對它進行反序列化。物件的資料、物件的型別和物件中儲存的資料資訊,都可以用來在記憶體中建立物件。
![](https://img2020.cnblogs.com/blog/2195823/202012/2195823-20201217222137366-1749900797.png)
#### ObjectOutputStream類
`java.io.ObjectOutputStream`類,將Java物件的原始資料型別寫入到檔案中,實現物件的持久化儲存。
##### 構造方法
- public ObjectOutputStream(OutputStream out):建立一個指定的OutputStream的ObjectOutputStream類物件
##### 特有的獨有方法:
- void writeObject(Object obj):將指定的物件寫入到ObjectOutputStream類物件中。
##### 序列化操作
1. 一個物件想要能夠序列化和反序列化,必須滿足兩個條件:
- 該類必須實現`java.io.Serializable`介面,Serializable介面,是一個標記型介面,如果該類沒有實現Serializable介面,將會丟擲NotSerializableException。
- 該類的所有屬性必須是可以實現序列化或者反序列化。如果有一個屬性不想讓它參與序列化,則該屬性必須標明是瞬態的,瞬時的,這個關鍵字是`transient`。
```java
public class Student implements Serializable {
private String name;
private transient Integer age;// 不讓age屬性參與序列化
}
```
#### ObjectInputStream類
`java.io.ObjectInputStream`類是反序列化流,將之前使用ObjectOutputStream序列化流的原始資料恢復為物件。
##### 構造方法
- public ObjectInputStream(InputStream in):建立一個指定的InputStream的物件反序列化流物件。
##### 特有的方法:
- public final Object readObject():從反序列化流中讀取一個物件。
對於JVM來說,能夠進行反序列的物件 ,前提條件是必須能夠找到class檔案的類,如果找不到該類的class檔案,則會丟擲一個ClassNotFoundException異常。
另外,當JVM序列化物件時,能夠找到class檔案,但是class檔案在序列化物件時,發生了修改,那麼反序列化操做會丟擲一個InvalidClassException異常。原因如下:
- 該類的序列化版本號與從流中讀取出來描述該類的版本號不一致。
- 該類包含了未知資料型別。
- 該類沒有可訪問的無參構造方法。
Serializable介面給需要序列化的類,提供了一個序列化版本號,serialVersionUID 該版本號的目的就是在於驗證序列化的物件和對應的類是否是版本一致的。
程式碼演示:
```java
// 序列化操作類
public class Demo01ObjectOutputStream {
public static void main(String[] args) throws IOException {
//1.建立ObjectOutputStream流物件,構造方法中傳遞指定的位元組輸出流。
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day30_IO\\student.txt"));
//2.使用ObjectOutputStream物件中的方法writeObject,把物件寫入到檔案中。
//2.1 先建立一個物件
Student s = new Student("小孫", 30);
s.score = 60;
//2.2寫物件到檔案中
oos.writeObject(s);
//3.釋放資源。
oos.close();
}
}
// 反序列化類操作
public class Demo02ObjectInputStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 1. 建立一個ObjectInputStream流物件,構造方法中傳遞一個位元組輸入流物件
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day30_IO\\student.txt"));
// 2. 使用ObjectInputStream流物件中的方法readObject,讀取儲存在檔案中的物件資料
Object obj = ois.readObject();
// 3.釋放資源。
ois.close();
// 4. 檢視物件的資料
System.out.println(obj);// Student{name='小孫', age=30}
if ( obj instanceof Student) {
Student student = (Student)obj;
System.out.println(student.getAge() + "--" + student.getName());
} else {
System.out.println("轉換失敗");
}
}
}
// 需要被序列化的類
import java.io.Serializable;
public class Student implements Serializable {
// 可以選擇手動自定義一個序列化版本號
private static final long serialVersionUID = 1L;
//private static String name;
private String name;
private Integer age;
private transient String address = "鄭州市";
transient int score;// 0
}
```
原理分析:
![](https://img2020.cnblogs.com/blog/2195823/202012/2195823-20201217222606255-159542040.png)
###### 練習:儲存一堆物件,實現序列化和反序列化動作。
```java
import java.io.Serializable;
public class Student implements Serializable {
// 可以選擇手動自定義一個序列化版本號
private static final long serialVersionUID = 1L;
//private static String name;
private String name;
private Integer age;
private transient String address = "鄭州市";
transient int score;// 0
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
address = "鄭州市";
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
", score=" + score +
'}';
}
}
@SuppressWarnings("unchecked")
public class DemoTestSerialize {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//1.定義多個物件,儲存在集合中
A