Java對象的序列化與反序列化那點事

  前段時間和同事討論序列化和反序列化的時候,對一些概念相互爭論了很久,發現好多東西之前只是草草瞭解一下沒有記錄下來,一些概念性的東西似是而非,一旦時間長了不用就容易忘啊,今天抽出時間寫寫關於這方面的內容記錄下來吧,畢竟好記性不如爛筆頭。

  首先明確一點,字節序列化和二進制序列化以及對象序列化表示的是同一個東西,因爲一個字節代表八個二進制位字節本身也是由二進制組成的,但是以上三種說法代表的是同一個東西別搞混了。

  接下來說下定義和序列化的作用:
  序列化:將Java對象轉化爲字節序列
  反序列化:與上面過程相反,將字節序列轉化爲對象
  作用:一般有兩個作用,第一個是將Java對象序列化字節後存儲在本地硬盤進行持久化保存,另外一個作用是在遠程通信的時候,Java對象是以字節流的的形式在網絡上從傳送的

  
  明白了概念以及作用後接下來就看代碼吧,其實代碼也很簡單,直接粘過來
  

public class Person implements Serializable {
    private String name;
    private char sex;
    private int year;
    private double age;

    public Person(String name, char sex, int year, double age) {
        super();
        this.name = name;
        this.sex = sex;
        this.year = year;
        this.age = age;
    }

    public Person() {
        super();
        // TODO Auto-generated constructor stub
    }

    public String getName() {
        return name;
    }

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

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public double getAge() {
        return age;
    }

    public void setAge(double age) {
        this.age = age;
    }

}
public class Test {
    public static void main(String[] args) {
        Person p = new Person("zhangsan", '男', 1980, 37);
        File f = new File("F:\\person.txt");
        try {
            f.createNewFile();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 將Person對象序列化的過程
        try {
            ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(f));
            oo.writeObject(p);
            oo.flush();
            oo.close();
            // 將字節反序列化對象
            ObjectInputStream oi = new ObjectInputStream(new FileInputStream(f));

            Person p1 = (Person) oi.readObject();
            System.out.println("讀取序列化對象的名字: "+p1.getName());
            System.out.println("讀取序列化對象的性別: "+p1.getSex());
            System.out.println("讀取序列化對象的出生年份: "+p1.getYear());
            System.out.println("讀取序列化對象的年齡: "+p1.getAge());
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

  簡單說一下代碼,一個Java對象要實現序列化首先要對應的Java類實現Serializable接口,這是首要前提,其次,如果類的某個字段不想被序列化,那麼在屬性前面加上transient關鍵字,這樣序列化的時候就會忽略該字段,具體形式類似於下圖。
  這裏寫圖片描述
  
  接下里說下序列化與反序列化過程:在序列化階段就是將Java對象轉化爲字節序列存儲在本地硬盤,一般是存放在一個文本文件中,用到了ObjectOutputStream和FileOutputStream這兩個類,通過向指定的文件打開輸出流,之後調用writeObject方法將指定的Java對象以字節序列的形式寫入指定文本文件。而反序列化就是利用了ObjectInputStream和FileInputStream這兩個類,從指定的本地文件打開輸入流調用readObject方法讀取,讀取的內容是字節序列,之後轉化爲Object對象,在測試是否讀取成功前要進行相應的類型轉化。記得在操作完畢後記得關閉相應的輸出流和輸入流以免佔用系統資源

  存儲在本地的文件內容大致是下面這個形式
   sr com.aaa.test.Person4O塹d 漣 D ageC sexI yearL namet Ljava/lang/String;xp@B€ u7 紅 zhangsan
   執行Test類的main方法,在控制檯輸出下面內容表明反序列化成功
  

讀取序列化對象的名字: zhangsan
讀取序列化對象的性別: 男
讀取序列化對象的出生年份: 1980
讀取序列化對象的年齡: 37.0

  之前用transient關鍵字修飾了性別,那麼其他的會正常輸出,而性別會顯示下面內容,也就是說性別這個字段被華麗的無視了
  

讀取序列化對象的性別: 

  這只是一種實現序列化和反序列化的方式,另外還有兩種,一種是實現Serializable接口的同時,如果字段加上transient關鍵字,可以在對應的Java類添加下面兩個方法來繼續序列化這個字段,同理可以序列化所有字段,不過這種方式比較麻煩,不推薦,另外一種是實現Externalizable接口,這種方式也不常見這裏就不寫了
  

    private void writeObject(ObjectOutputStream out) throws IOException{
        out.defaultWriteObject();
        out.writeChar(sex);
    }
    private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException{
        in.defaultReadObject();
        sex=in.readChar();
    }

  
  至此Java對象的序列化與反序列化也就明白的差不多了,對了,另外補充兩點:1.如果一個類實現了Serializable接口,那麼它的子類不需要顯示聲明也可以被序列化 2.序列化僅可以序列化的是普通成員變量,無法序列化靜態變量。OK結束
  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章