1. 程式人生 > >Java之路:物件序列化

Java之路:物件序列化

一、物件序列化的基本概念

所謂的物件序列化(在某些書籍中也叫序列化),是指在記憶體之中儲存的物件轉化為二進位制資料流的形式的一種操作。通過將物件序列化,可以方便地實現物件的傳輸及儲存。

但是在Java之中並不是所有的類的物件都可以被序列化,如果一個類物件需要被序列化,則此類一定要實現java. io.Serializable介面。但是這個接口裡面也沒有定義任何的方法,所以此介面依然屬於標識介面,表示一種能力。

在Java中提供有ObjectlnputStreamObjectOutputStream這兩個類用於序列化物件的操作。這兩個類是用於儲存和讀取物件的輸入輸出流類

,不難想象,只要把物件中的所有成員變數都儲存起來,就等於儲存了這個物件,之後從儲存的物件之中再將物件讀取進來就可以繼續使用此物件。

ObjectInputStream與ObjectOutputStream類,用於幫助開發者完成儲存和讀取物件成員變數取值的過程,但要求讀寫或儲存的物件必須實現了Serializable介面,但Serializable介面中沒有定義任何方法,僅僅被用做一種標記,以被編譯器做特殊處理。如下範例所示。

【示例1】

package com.xy.io;

import java.io.Serializable;

public class Person implements
Serializable { // Person實現了Serializable介面,所以此類定義的物件可被序列化 private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String toString() { return "姓名:" + this.name + ", 年齡:" + this.age; } }

二、物件輸出流——ObjectOutputStream

雖然類已經實現了Serializable介面,但是如果要想真正地實現具體的序列化操作,則使用者可以使用ObjectOutputStream類完成,這個類繼承結構如下。

java.lang.Object
|- java.io.OutputStream
|- java.io.ObjectOutputStream

由上述類的繼承關係,可以發現ObjectOutputStream是OutputStream子類,因為物件序列化之後為二進位制資料,所以只能夠依靠位元組流操作,同時在ObjectOutputStream類中定義了以下兩個方法:

1)構造方法。public ObjectOutputStream(OutputStream out) throws IOException;
(2)輸出物件:public final void writeObject(Object obj) throws IOException;

ObjectOutputStream 用於將物件序列化,並儲存。其操作如下。

OutputStream outputFile = new FileOutputStream(new File(“SerializedPerson”));
ObjectOutputStream cout = new ObjectOutputStream(outputFile);
cout.writeObject(new Person("張三",25));
cout.close();

ObjectOutputStream 接收一個OutputStream物件用於儲存待序列化的物件。然後cout呼叫writeObject 方法儲存物件。

三、物件輸入流——ObjectInputStream

如果希望將已被序列化的物件再反序列化回來,則就可以通過ObjectInputStream類完成,它用於讀取將序列化的物件。此類繼承關係如下。

java.lang.Object
|- java.io.InputStream
|- java.io.ObjectInputStream

對於ObjectInputStream類之中主要使用的兩個方法如下。

1)構造方法。public ObjectInputStream(InputStream in) throws IOException;
(1)物件輸入:public final Object readObject() throws IOException, ClassNotFoundException;

實現物件的反序列化(讀取物件)操作如下。

InputStream inputFile = new FileInputStream(new File(“SerializedPerson”));
ObjectInputStream cin = new ObjectInputStream(inputFile);
Person p = (Person) cin.readObject();
System.out.println(p);

ObjectInputStream接收一個InputStream物件用於儲存待序列化的物件。然後cin呼叫readObject方法讀取序列化後的物件。

四、反序列化的基本概念

反序列化實際上就是使用ObjectInputStream 類建立物件將序列化後的物件讀取出來,繼續使用此物件。下面的例子結合ObjectInputStream 和OutputStream演示如何序列化物件和反序列化物件。
【示例2】

package com.xy.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;

public class SerializableDemo {
	public static void main(String[] args) throws Exception {
		File f = new File("SerializedPerson");
		serialize(f);
		deserialize(f);
	}
	
	// 序列化物件方法,將物件儲存在檔案之中
	public static void serialize(File f) throws Exception {
		OutputStream outputFile = new FileOutputStream(f);
		ObjectOutputStream cout = new ObjectOutputStream(outputFile);
		cout.writeObject(new Person("張三", 25));
		cout.close();
	}
	
	// 反序列化物件方法,從檔案中讀取已經儲存的物件
	public static void deserialize(File f) throws Exception {
		InputStream inputFile = new FileInputStream(f);
		ObjectInputStream cin = new ObjectInputStream(inputFile);
		Person p = (Person)cin.readObject();
		System.out.println(p);
		cin.close();
	}
}

class Person implements Serializable {
	private String name;
	private int age;
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public String toString() {
		return "姓名:" + this.name + ", 年齡:" + this.age;
	}
}

【結果】
在這裡插入圖片描述

五、transient關鍵字

在預設情況下,當一個類物件序列化時,會將這個類中的全部屬性都儲存下來,如果不希望類中的某個屬性被序列化(或某些屬性不希望被儲存,則可以在宣告屬性之前加上transient關鍵字。下面的程式碼修改自 【示例2】 ,在宣告屬性時,前面多加了一個transient關鍵字。

private transient String name;
private transient int age;

再次執行 【示例2】 程式時,其輸出結果如下圖所示。
在這裡插入圖片描述
從輸出結果可以看到,Person類中的兩個屬性並沒有被儲存下來,輸出時,是直接輸出了這兩個屬性的預設值null和0。