隨筆-128  評論-55  文章-5  trackbacks-0
          1. 什么是Serialization?

          串行化(Serialization)是計算機科學中的一個概念,它是指將對象存儲到介質(如文件、內在緩沖區等)中或是以二進制方式通過網絡傳輸。之后可以通過反串行化從這些連續的位數據重新構建一個與原始對象狀態相同的對象,因此在特定情況下也可以說是得到一個副本,但并不是所有情況都這樣。

          Java有Serialization API為開發者提供了一種標準的機制來串行化類。

          2. 為什么要Serilzation?

          特別地,串行化主要有三種用途:
          1)作為一種持久化機制
              如果使用的是FileOutputStream流的方式,則數據將被自動地寫入文件中,
          2)作為一種復制機制
              如果使用的是ByteArrayOutputStream流的方式,數據將寫入內存中的字節數組中。該字節數組可以用來創建初始對象的副本,
          3)作為一種通信機制
              如果是使用套接字(Socket)流的方式,則數據自動地通過網絡連接傳輸一另一個端點,并由這個端點上的程序來決定做什么。

          3. Serialization的基本用法默認機制

          將要串行化的類必須實現java.io.Serializable接口,或者是繼承實現了該接口的類。然后通過java.io.ObjectOutputStream類來實現持久化,如果用保存到文件上還需要用到java.io.FileOutputStream類。因為ObjectOutputStream被認為是java.io包中的高級類所以可用它來包裝低級的類FileOutputStream。在持久化過程中調用的一個方法是ObjectOutputStream對象的writeObject(obj)方法。

          當要從文件中恢復對象時,則是使用java.io.OjbectInputStream與FileInputStream類,調用一方法是ObjectInputStream對象的readObject()方法。

          示例1:

          import java.io.*;

          public class Cat implements Serializable {
              private String name;
              public Cat () {
                  this.name = "new cat";
              }

              public String getName() {
                  return this.name;
              }

              public void setName(String name) {
                  this.name = name;
              }
          }


          import java.io.*;

          public class CatDemo {
              public static void main(String[] args) {
                  Cat cat = new Cat();
                  try { //串行化
                      FileOutputStream fos = new FileOutputStream("catDemo.out");
                      ObjectOutputStream oos = new ObjectOutputStream(fos);
                      System.out.println(" 1> " + cat.getName());
                      cat.setName("My Cat");   
                  oos.writeObject(cat);
                      oos.close();         
                  } catch (IOException ex) {
                      ex.printStackTrace();
                  }

                  try { //反串行化
                      FileInputStream fis = new FileInputStream("catDemo.out");
                      ObjectInputStream ois = new ObjectInputStream(fis);

                      cat = (Cat) ois.readObject();
                     
                      System.out.println(" 2> " + cat.getName());
                      ois.close();
                  } catch (IOException ex) {
                      ex.printStackTrace();
                  }catch(ClassNotFoundException ex) {    
                  ex.printStackTrace();
              }

              }
          }



          4. Serialization常見問題

          正如前面提到的,所有可串行化的類必須直接或是通過繼承方式間接地實現java.io.Serializable接口,由于Object類關沒有實現這個接口,所以并不是所有類的對象都是可串行化的。像AWT與Swing的GUI組件、字符串、數組等都是可串行化的,而像一些系統級的類(Thread,OutputStream 等)和Socket類是不可串行化的。

          問題一:如果在一個可串行化的類中Has-As不可串行化的類該怎么處理?
          在這種情況下在運行時會拋出NotSerializableException

          為了解決類似問題,Java中提供了transient關鍵字來跳過對不可串行化類的對象的處理。但這依然可能會引起一些問題,在反串行化時,被標識為transient變量不會恢復到其原始狀態,而是提供默認值,如示例2中的pig引用將賦值為null,age變量賦值為0;

          附:基本類型和引用類型的默認值
          對象引用:null
          byte, short, int, long :0
          float, double:0.0
          boolean:false
          char:'\u0000'(這是Unicode字符集的空格)


          示例2:
          import java.io.*;
          public class NewPig2 implements Serializable {
              private String newName;
              private transient Pig pig = new Pig();
              private transient int age = 2;  
              public NewPig2() {
                  newName = "new Pig 2";
                  //pig = new Pig();
              }
              public Pig getPig() {
                  return this.pig;
              }
              public void setName(String name) {
                  this.newName = name;
              }
              public String getName() {
                  return this.newName;
              }
              public int getAge() {
                  return this.age;
              }
          }

          問題二:如果父類不可串行化,子類實現了Serializable會怎樣?
          如果有一個Animal類是不可串行化的,而有一個Dog類繼承自Animal類并且實現了Serializabl接口,則沒有串行化時沒有任何問題,但是在反串行化時將會重新調用Animal的構造函數,如示例3所示。

          示例3的運行結果如下:

          1> No Color - new Dog
          2> Green - My Dog
          4> No Color - My Dog
          因為Animal不可串行化,所以必須運行構造函數,但不會在實現Serializable的反串行化類上運行構造函數。

          示例3:

          public class Animal {
              private String color;
              public Animal () {
                  this.color = "No Color";
              }

              public void setColor(String color) {
                  this.color = color;
              }
              public String getColor () {
                  return this.color;
              }
          }


          import java.io.*;
          public class Dog extends Animal implements Serializable {
              private String name;
              public Dog () {
                  this.name = "new Dog";
              }
              public String getName() {
                  return this.name;
              }
              public void setName(String name) {
                  this.name = name;
              }
          }

          import java.io.*;
          public class DogTest {
              public static void main(String[] args) {
                  Dog dog = new Dog();  
                  System.out.println(" 1> " + dog.getColor() + " - " + dog.getName());
                  dog.setColor("Green");
                  dog.setName("My Dog");
                  System.out.println(" 2> " + dog.getColor() + " - " + dog.getName());
                  try {//串行化
                      FileOutputStream fos = new FileOutputStream("myDog.out");
                      ObjectOutputStream oos = new ObjectOutputStream(fos);
                      oos.writeObject(dog);
                      oos.close();
                  } catch (Exception ex) {
                      ex.printStackTrace();
                  }
                  try {//反串行化
                      FileInputStream fis = new FileInputStream("myDog.out");
                      ObjectInputStream ois = new ObjectInputStream(fis);
                      dog = (Dog) ois.readObject();       
                      System.out.println(" 4> " + dog.getColor() + " - " + dog.getName());
                      ois.close();
                  } catch (Exception ex) {
                      ex.printStackTrace();
                  }
              }
          }

          5.
          自定義默認方法:使用writeOject和readObject

          假如在一個可以串行化的類中有一個不可串行化的對象,但又想保存該對象的狀態信息該如何是好?在這樣情況下可以在這個可串行化的類中實現writeObject()和readObject()。

          示例4:
          import java.io.*;
          import java.util.Scanner;

          public class NewPig3 implements Serializable {
              private String newName;
              private transient Pig pig = new Pig();
              private transient int age = 2;
             
              public NewPig3() {
                  newName = "new Pig 3";
                  //pig = new Pig();
              }

              private void writeObject(ObjectOutputStream oos) throws IOException {
                  oos.defaultWriteObject();
                  oos.writeChars(pig.getName());
              //oos.writeInt(this.age);
              }

              private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
                  ois.defaultReadObject();
                  pig = new Pig();
                  Scanner in = new Scanner(ois);
                  if (in.hasNextLine()) {   
                      pig.setName(in.nextLine());
                  }
              }

              public Pig getPig() {
                  return this.pig;
              }

              public void setName(String name) {
                  this.newName = name;
              }

              public String getName() {
                  return this.newName;
              }

              public int getAge() {
                  return this.age;
              }
          }


          Author: orangelizq
          email: orangelizq@163.com

          歡迎大家訪問我的個人網站 萌萌的IT人
          posted on 2008-09-05 11:26 桔子汁 閱讀(765) 評論(0)  編輯  收藏 所屬分類: J2SE
          <2008年9月>
          31123456
          78910111213
          14151617181920
          21222324252627
          2829301234
          567891011

          常用鏈接

          留言簿(9)

          隨筆分類(124)

          隨筆檔案(127)

          文章分類(5)

          文章檔案(5)

          Good Blog

          技術網站

          搜索

          •  

          積分與排名

          • 積分 - 267505
          • 排名 - 213

          最新評論

          閱讀排行榜

          主站蜘蛛池模板: 闽清县| 乐亭县| 电白县| 绍兴市| 沙洋县| 进贤县| 富蕴县| 象山县| 弥勒县| 离岛区| 宁武县| 邵东县| 渑池县| 新密市| 宁都县| 满洲里市| 深圳市| 洪江市| 尼玛县| 义马市| 张家港市| 武义县| 葫芦岛市| 石林| 荃湾区| 临清市| 衢州市| 若尔盖县| 邹平县| 文化| 卢氏县| 武川县| 潜江市| 八宿县| 周口市| 桂阳县| 施秉县| 武威市| 东乌珠穆沁旗| 乌鲁木齐县| 安达市|