類對象的持久化與序列化

1、所謂類對象的持久化是指:把內存中的對象存儲在某種介質上(除內存外,包括硬盤或者網絡存儲傳輸等),當然持久化的完整操作並不只是爲了把對象數據以字節碼或字節流的形式存儲在介質上,它還要包括對持久化的對象讀取與驗證。

2、所謂類對象的序列化是指:把一個類對象轉化爲字節流或字節碼(把一個字節流對象轉化爲一個類對象過程稱爲反序列化),同時保存其狀態等一些特性。對象序列化需要繼承Serializable接口,它的作用只是標識該類的對象可以被序列化,並同時會自動生成一個屬性serialVersionUID值,用來版本控制或驗證該類的持久化對象在不同版本中是否兼容(?)。
java的序列化機制是通過在運行時來判斷serialVersionUID值的一致性來驗證版本。在進行反序列化時JVM會把獲得序列化字節流中的serialVersionUID值與本地對應的類中的serialVersionUID值進行比較,如果一致,則進行反序列化操作,否則,則報版本不一致的無效類。

3、但是對象的序列化與持久化之間是什麼關係那?
對象的持久化前提是對象的序列化。
爲什麼持久化之前需要序列化那?
序列化是綜合很多種情況下的解決方案:舉個例子
假設有A和B兩個類,A中有一個屬性字段是B類的引用那麼在對A和B進行持久化的時候,A中包含B的引用,那麼需要把B的數據複製一份給A,但當對A和B反序列的時候,系統內存中會出現兩份對象B或B佔用兩份內存空間,這樣對於數據修改保存都會出現問題。
序列化機制解決了以下問題:
1、一個對象序列化唯一對應一個序列化值(serialVersionUID)。
2、當要持久化一個對象時,先檢查該對象是否已經持久化。
3、如果已經保存,則需要標記與已有對象序列號相同標記。
4、對於網絡傳輸或者讀取其他方式獲得的字節碼流進行反序列化驗證。
4、序列化測試代碼
序列化實體類:

package com.serializable.entity;

import java.io.Serializable;

public class Person implements Serializable{
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    } 
}

持久化代碼:

package com.serializable.serializable;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

import com.serializable.entity.Person;

public class SerializableTest {
    public static void main(String[] args) throws IOException {
        Person pn= new Person("張三",26);
        FileOutputStream fos=new FileOutputStream("person.txt");
        ObjectOutputStream oos=new ObjectOutputStream(fos);
        oos.writeObject(pn);
        oos.close();
        fos.close();
        System.out.println(pn.toString());  
    }
}

反序列化代碼:

package com.serializable.deserializable;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

import com.serializable.entity.Person;

public class DeSerializableTest  {
public static void main(String[] args) throws IOException, ClassNotFoundException {
    FileInputStream fis=new FileInputStream("person.txt");
    ObjectInputStream ois=new ObjectInputStream(fis);
    Person pn=(Person)ois.readObject();
    System.out.println(pn.toString());
    ois.close();
    fis.close();
}
}

在序列化與反序列化過程中,只要序列號一致,就可以進行正常操作。
注意:如果沒有在代碼類中顯式定義serialVersionUID的值,那麼系統會根據類的屬性等一系列特性生成一個serialVersionUID,只要修改參與生成serialVersionUID的部分,就會生成不同的serialVersionUID,從而會反序列化報錯。
但是如果在代碼中顯式定義了serialVersionUID值,那麼在序列化前後增加()屬性字段值,serialVersionUID是沒有改變的,是可以正常序列化的。
以下情況是顯式定義了serialVersionUID值,並且沒有改變。
在網絡傳輸中,如果A端持久化後,另一端B新增字段值,但沒有去改變serialVersionUID值,那麼在反序列化時,對於B新增而A沒有的字段值,如果是String類型,則默認爲null,如果是int 則默認爲0……
對於A端新增字段,B端不變則B端反序列化的時候忽略A端新增的字段值。
(serialVersionUID值一致,反序列時,如果該端本地類比另一端少的字段則忽略,如果比另一端多的字段值則是默認的值 比如 int類型爲0)

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