JAVA_序列化與反序列化(收納箱)

序列化

對於序列化,平常生活中對於字面意思的理解就是,將一些事物有序的規整起來,比如把一些雜亂物品裝在一個箱子裏,這一個過程實質上就是序列化,竟然我們有把東西裝起來的過程,也就會有把東西從箱子裏再拿出來的過程,這個過程就是反序列化。讓我們看看概念是怎麼定義的。
序列化指堆內存中的java對象數據,通過某種方式把對存儲到磁盤文件中,或者傳遞給其他網絡節點(網絡傳輸)。這個過程稱爲序列化,通常是指將數據結構或對象轉化成二進制的過程。即將對象轉化爲二進制,用於保存,或者網絡傳輸。
反序列化把磁盤文件中的對象數據或者把網絡節點上的對象數據,恢復成Java對象模型的過程。也就是將在序列化過程中所生成的二進制串轉換成數據結構或者對象的過程與序列化相反,將二進制轉化成對象。
對於概念可能真的不是很好理解,其實序列化就是,用一個字節序列表示一個對象,而該字節序列裏保存着該對象的數據,對象的類型,對象的存儲屬性,然後將字節序列寫道文件中,進行保存,傳輸。對於反序列化就是,將文件中的數據讀取回來,重構對象。
其實就是字節與對象之間的轉換,對象(序列化)——> 字節,字節(反序列化)——>對象
接下來對於使用序列化,就要用到一個接口。
Serializable接口,要想被序列化的類,就要實現這個接口。

package java_使用Serializable接口去序列化;
import java.io.*;
public class test implements Serializable {
    public  String name;//對於static修飾的變量 不能被序列化
    public  double age;
    public test(String name,double age){
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "test{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public static void main(String[] args)throws Exception{
        test t = new test("xing",2);
        ObjectOutputStream ob = new ObjectOutputStream(new FileOutputStream("D:/a.txt"));//使用對象流完成序列化
        ob.writeObject(new test("xing",2));//寫入文件中
        ObjectInputStream oj = new ObjectInputStream(new FileInputStream("D:/a.txt"));
        test o = (test)oj.readObject();
        System.out.println(o);//反序列化之後
    }
}
運行結果:
test{name='xing', age=2.0}

從代碼看到,因爲序列化是字節與對象之間的轉換,最後將字節存到文件中,或者從文件中讀取字節,所以我們肯定要使用到IO流,這裏我們要用到對象流

public ObjectInputStream(InputStream in)
//創建從指定 InputStream 讀取的 ObjectInputStream。從流讀取序列化頭部並予以驗證
readObject()
//從 ObjectInputStream 讀取對象
ObjectOutputStream(OutputStream out)
//創建寫入指定 OutputStream 的 ObjectOutputStream。此構造方法將序列化流部分寫入基礎流;
writeObject(Object obj)
//將指定的對象寫入 ObjectOutputStream

通過上面的一小段程序,對於序列化進行了解,但是對於一個類中的一些相關數據,如果我不想都被序列化,傳輸出去,這裏我們會用到一個關鍵字
transient通過該關鍵字修飾的變量不會被序列化,讓我們看一段程序

package java_使用Serializable接口去序列化;
import java.io.*;

public class test1 implements Serializable {
    private  String name;//name沒有被序列化
    private transient String sex;

    public  String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
    public test1(String name,String sex){
        this.name = name;
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "test1{" +
                "sex='" + sex + '\'' + "name=" + name+'\'' +
                '}';
    }
    public static void main(String[] args)throws Exception{
        test1 t = new test1("xing","nan");
        ObjectOutputStream ob = new ObjectOutputStream(new FileOutputStream("D:/a.txt"));
        ob.writeObject(t);
        //t.setName("sun");
        ObjectInputStream obj = new ObjectInputStream(new FileInputStream("D:/a.txt"));
        test1 o = (test1)obj.readObject();
        System.out.println(o.toString());
    }
}
運行結果:
test1{sex='null'name=xing'}

從程序運行結果看到sex的值爲null,然後我們看上面的程序,sex變量被transient所修飾,說明sex並沒有參與序列化,所以在反序列化之後,值爲null。對於是數據類型的,被transient修飾的變量,最後反序列化之後是0
接下來 我們再來看一個關鍵字,static首先直接看程序

package java_使用Serializable接口去序列化;
import java.io.*;
public class test1 implements Serializable {
    private  static String name;//name沒有被序列化
    private transient String sex;

    public  static String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
    public test1(String name,String sex){
        this.name = name;
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "test1{" +
                "sex='" + sex + '\'' + "name=" + name+'\'' +
                '}';
    }
    public static void main(String[] args)throws Exception{
        test1 t = new test1("xing","nan");
        ObjectOutputStream ob = new ObjectOutputStream(new FileOutputStream("D:/a.txt"));
        ob.writeObject(t);
        t.setName("sun");
        ObjectInputStream obj = new ObjectInputStream(new FileInputStream("D:/a.txt"));
        test1 o = (test1)obj.readObject();
        System.out.println(o.toString());
    }
}
運行結果:
test1{sex='null'name=sun'}

從運行結果上看,我們初始化時的name=“xing"而被反序列化之後,變爲"sun”,讓我們看一下程序,原來name這個變量是被static修飾,而我們在修改這個數據是在反序例化之前,如果這個數據參與序列化,則是不會被修改的,這就說明,被static修飾的變量,沒有參與序列化。
其實這還是需要從static說起,被static修飾的變量,不是對象的一部分,所以他更不會去參與序列化,對於序列化前後,static修飾的變量都是在JVM當前中static對應的值。
對於序列化,反序列化這一過程,Java的序列化機制是通過判斷類的serialVersionUID來驗證版本一致性的,JVM會把傳來的字節流中的serialVersionUID與本地相應實體類的serialVersionUID進行比較,如果相同就認爲是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常,InvalidCastException
最後對於序列化小結:
static關鍵字修飾的變量不參與序列化,final變量值參與序列化,transient關鍵字只能修飾變量,而不能修飾方法和類。

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