Monday, February 18, 2013
Wednesday, February 6, 2013
[JAVA] 序列化的處理Serialization
序列化的處理
「序列化(Serialization)」是將物件寫入到串流的程式。而「反序列化(Deserialization)」則是將串流讀出來的程序。我們要透過ObjectInputStream和ObjectOutputStream類別來處理序列化和反序列化的工作,該類別分別衍生自InputStream和OutputStream類別。如果您要將某個類別做序列化的處理,該類別必需實作Serializable介面,但該介面只是一個標記介面,並沒有定義任何的成員。ObjectInputStream類別的建構子為:
建構子
ObjectInputStream()
作 用
建構ObjectInputStream物件
建構子
ObjectInputStream(InputStream in)
作 用
建構ObjectInputStream物件,以便由in物件讀取
而ObjectOutputStream類別的建構子為:
建構子
ObjectOutputStream()
作 用
建構ObjectOutputStream物件
建構子
ObjectOutputStream(OutputStream out)
作 用
建構ObjectOutputStream物件,以便由寫入out物件
以下的範例示範如何設計需要序列化的類別:
程式10-18:Chap 10\ Employee.java
01: import java.io.*;
02:
03: public class Employee implements Serializable {
04: private String name;
05: private String ID;
06: private float salary;
07:
08: Employee(String name , String ID , float salary) {
09: this.name = name;
10: this.ID = ID;
11: this.salary = salary;
12: }
13: public String getName(){
14: return name;
15: }
16: public String getID() {
17: return ID;
18: }
19: public float getSalary() {
20: return salary;
21: }
22: }
Employee類別是需要序列化的類別。注意程式的第3行,該行實作了Serializable介面。除了這一行之外,Employee類別和一般的類別寫作並沒有特別需要注意的地方。程式的4~7行定義了3個私有資料成員。程式的第8~11行宣告了一個建構子,用來初始化私有資料成員。而第13~21行的程式則分別顯示出各私有成員的內容。定義好了需要序列化的類別之後,我們再來看一下如何將Employee物件序列化並寫入檔案之中:
程式10-19:Chap 10\ WriteData.java
01: import java.io.*;
02:
03: public class WriteData {
04: public static void main(String[] args) {
05: Employee[] s = new Employee[2];
06:
07: s[0] = new Employee(“Alex” ,“001” , 32000.f);
08: System.out.println(s[0].getName());
09: System.out.println(s[0].getID());
10: System.out.println(s[0].getSalary());
11:
12: s[1] = new Employee(“Ivy”,“002”, 43000.f);
13: System.out.println(s[1].getName());
14: System.out.println(s[1].getID());
15: System.out.println(s[1].getSalary());
16:
17: try{
18: FileOutputStream fs = new FileOutputStream(“Employee.txt”);
19: ObjectOutputStream out = new ObjectOutputStream(fs);
20: out.writeObject(s);
21: out.close();
22: fs.close();
23: } catch (IOException e){
24: System.out.println(e.toString());
25: }
26: }
27: }
程式的執行結果為:
Alex
001
32000.0
Ivy
002
43000.0
程式執行後,您會在目錄下找到「Employee.txt」文字檔,但您無法直接瀏覽該檔的內容。範例程式的第5行宣告一個Employee陣列,可用來儲存2筆資料。而程式的第7~15行分別建立Employee物件,並且將物件的內容顯示在螢幕上。程式的第18~22行是本範例程式的重點。第18行宣告了一個FileOutputStream物件,用來將內容寫入Employee.txt檔案中。再於第19行程式中將FileOutputStream物件傳遞給ObjectOutputStream,並建立新的ObjectOutputStream物件。第20行程式中,使用ObjectOutputStream物件的WriteObject方法將Employee陣列的內容寫入Employee.txt檔案中。寫入的方式很簡單,但請注意,程式中寫入Employee陣列的資料,因此,您在讀取資料時,也必需將檔案的內容輸入Employee陣列中,否則會因型態不符而產生classCastException的例外。
下列的範例程式示範如何將Employee.txt的內容讀出:
程式10-20:Chap 10\ ReadData.java
01: import java.io.*;
02:
03: public class ReadData {
04: public static void main(String[] args) {
05: try{
06: FileInputStream fs = new FileInputStream(“Employee.txt”);
07: ObjectInputStream in = new ObjectInputStream(fs);
08:
09: Employee[] s = (Employee[] ) in.readObject();
10:
11: for(int i = 0 ; i
12: System.out.println(s[i].getName());
13: System.out.println(s[i].getID());
14: System.out.println(s[i].getSalary());
15: }
16: in.close();
17: fs.close();
18: } catch (Exception e) {
19: System.out.println( e.toString());
20: }
21: }
22: }
程式的執行結果為:
Alex
001
32000.0
Ivy
002
43000.0
範例程式的第6行宣告了一個FileInputStream物件指定需要讀取的檔案。而如果需要讀取已序列化的資料,我們需要使用ObjectInputStream物件。因此,程式的第7行將FileInputStream物件傳遞給ObjectInputStream並建立ObjectInputStream物件。第9行宣告Employee陣列用來讀取Employee.txt的內容。該行程式中使readObject方法來讀取資料,但因為Employee.txt存入的資料是Employee陣列,所以,在使用readObject方法讀取後,需要再將讀取的內容轉為Employee陣列。程式第11~14行則顯示出讀取的內容。
當您在宣告類別時,如果實作了Serializable介面,您也可以選擇性的將資料成員做序列化的處理。您可以在不希望被序列化的資料成員前加入transient修飾字。例如:如果您將Employee.java的資料成員修改為:
private String name;
private String ID;
private transient float salary;
現在,salary資料成員加上了transient修飾字。請依次再執行WriteData和ReadData這兩支程式,
您會發現ReadData的執行結果變成了:
Alex
001
0.0
Ivy
002
0.0
這是因為在序列化的過程式,並沒有將salary成員的資料寫入,因此,在讀出資料時,並沒有salary的資料,而是以預設值來顯示。
「序列化(Serialization)」是將物件寫入到串流的程式。而「反序列化(Deserialization)」則是將串流讀出來的程序。我們要透過ObjectInputStream和ObjectOutputStream類別來處理序列化和反序列化的工作,該類別分別衍生自InputStream和OutputStream類別。如果您要將某個類別做序列化的處理,該類別必需實作Serializable介面,但該介面只是一個標記介面,並沒有定義任何的成員。ObjectInputStream類別的建構子為:
建構子
ObjectInputStream()
作 用
建構ObjectInputStream物件
建構子
ObjectInputStream(InputStream in)
作 用
建構ObjectInputStream物件,以便由in物件讀取
而ObjectOutputStream類別的建構子為:
建構子
ObjectOutputStream()
作 用
建構ObjectOutputStream物件
建構子
ObjectOutputStream(OutputStream out)
作 用
建構ObjectOutputStream物件,以便由寫入out物件
以下的範例示範如何設計需要序列化的類別:
程式10-18:Chap 10\ Employee.java
01: import java.io.*;
02:
03: public class Employee implements Serializable {
04: private String name;
05: private String ID;
06: private float salary;
07:
08: Employee(String name , String ID , float salary) {
09: this.name = name;
10: this.ID = ID;
11: this.salary = salary;
12: }
13: public String getName(){
14: return name;
15: }
16: public String getID() {
17: return ID;
18: }
19: public float getSalary() {
20: return salary;
21: }
22: }
Employee類別是需要序列化的類別。注意程式的第3行,該行實作了Serializable介面。除了這一行之外,Employee類別和一般的類別寫作並沒有特別需要注意的地方。程式的4~7行定義了3個私有資料成員。程式的第8~11行宣告了一個建構子,用來初始化私有資料成員。而第13~21行的程式則分別顯示出各私有成員的內容。定義好了需要序列化的類別之後,我們再來看一下如何將Employee物件序列化並寫入檔案之中:
程式10-19:Chap 10\ WriteData.java
01: import java.io.*;
02:
03: public class WriteData {
04: public static void main(String[] args) {
05: Employee[] s = new Employee[2];
06:
07: s[0] = new Employee(“Alex” ,“001” , 32000.f);
08: System.out.println(s[0].getName());
09: System.out.println(s[0].getID());
10: System.out.println(s[0].getSalary());
11:
12: s[1] = new Employee(“Ivy”,“002”, 43000.f);
13: System.out.println(s[1].getName());
14: System.out.println(s[1].getID());
15: System.out.println(s[1].getSalary());
16:
17: try{
18: FileOutputStream fs = new FileOutputStream(“Employee.txt”);
19: ObjectOutputStream out = new ObjectOutputStream(fs);
20: out.writeObject(s);
21: out.close();
22: fs.close();
23: } catch (IOException e){
24: System.out.println(e.toString());
25: }
26: }
27: }
程式的執行結果為:
Alex
001
32000.0
Ivy
002
43000.0
程式執行後,您會在目錄下找到「Employee.txt」文字檔,但您無法直接瀏覽該檔的內容。範例程式的第5行宣告一個Employee陣列,可用來儲存2筆資料。而程式的第7~15行分別建立Employee物件,並且將物件的內容顯示在螢幕上。程式的第18~22行是本範例程式的重點。第18行宣告了一個FileOutputStream物件,用來將內容寫入Employee.txt檔案中。再於第19行程式中將FileOutputStream物件傳遞給ObjectOutputStream,並建立新的ObjectOutputStream物件。第20行程式中,使用ObjectOutputStream物件的WriteObject方法將Employee陣列的內容寫入Employee.txt檔案中。寫入的方式很簡單,但請注意,程式中寫入Employee陣列的資料,因此,您在讀取資料時,也必需將檔案的內容輸入Employee陣列中,否則會因型態不符而產生classCastException的例外。
下列的範例程式示範如何將Employee.txt的內容讀出:
程式10-20:Chap 10\ ReadData.java
01: import java.io.*;
02:
03: public class ReadData {
04: public static void main(String[] args) {
05: try{
06: FileInputStream fs = new FileInputStream(“Employee.txt”);
07: ObjectInputStream in = new ObjectInputStream(fs);
08:
09: Employee[] s = (Employee[] ) in.readObject();
10:
11: for(int i = 0 ; i
12: System.out.println(s[i].getName());
13: System.out.println(s[i].getID());
14: System.out.println(s[i].getSalary());
15: }
16: in.close();
17: fs.close();
18: } catch (Exception e) {
19: System.out.println( e.toString());
20: }
21: }
22: }
程式的執行結果為:
Alex
001
32000.0
Ivy
002
43000.0
範例程式的第6行宣告了一個FileInputStream物件指定需要讀取的檔案。而如果需要讀取已序列化的資料,我們需要使用ObjectInputStream物件。因此,程式的第7行將FileInputStream物件傳遞給ObjectInputStream並建立ObjectInputStream物件。第9行宣告Employee陣列用來讀取Employee.txt的內容。該行程式中使readObject方法來讀取資料,但因為Employee.txt存入的資料是Employee陣列,所以,在使用readObject方法讀取後,需要再將讀取的內容轉為Employee陣列。程式第11~14行則顯示出讀取的內容。
當您在宣告類別時,如果實作了Serializable介面,您也可以選擇性的將資料成員做序列化的處理。您可以在不希望被序列化的資料成員前加入transient修飾字。例如:如果您將Employee.java的資料成員修改為:
private String name;
private String ID;
private transient float salary;
現在,salary資料成員加上了transient修飾字。請依次再執行WriteData和ReadData這兩支程式,
您會發現ReadData的執行結果變成了:
Alex
001
0.0
Ivy
002
0.0
這是因為在序列化的過程式,並沒有將salary成員的資料寫入,因此,在讀出資料時,並沒有salary的資料,而是以預設值來顯示。
Subscribe to:
Comments (Atom)