java_對象序列化、反序列化

1.概念

序列化:將對象轉化爲字節序列的過程html

反序列化:將字節序列轉化爲對象的過程java

用途:網絡

A:將對象轉化爲字節序列保存在硬盤上,如文件中,如文本中的例子就是將person對象序列化成字節序列,存在person.txt文件中app

B:網絡傳輸中通常都是以對象序列化的形式存在,在網絡的發送/接收兩端進行對象的序列化/反序列化ide

輸入/輸出的使用:函數

通常都是針對內存而言,內存--硬盤--》outputStream     從硬盤--內存--》inputStream測試

具體使用要根據場景來肯定ui

2.Serializable-example

2.1 無顯式的指定UID,採用編譯系統自動生成的

Object:this

package com.java.baseinfo.knowledge.code.serializable; import java.io.Serializable;

public class Person implements Serializable { private int age; private String name; private String sex; public int getAge() { return age; } public void setAge(int age) { this.age = age; } 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; } @Override public String toString() { final StringBuffer sb = new StringBuffer("Person{"); sb.append("age=").append(age); sb.append(", name='").append(name).append('\''); sb.append(", sex='").append(sex).append('\''); sb.append('}'); return sb.toString(); } }

 object  uidurl

package com.java.baseinfo.knowledge.code.serializable; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; 
public class TestObjSerializeAndDeserialize { public static void main(String[] args) { // 序列化
 SerializablePerson(); // 反序列化 //Deserialization();
 } private static void SerializablePerson() { Person person = new Person(); person.setAge(10); person.setName("測試"); person.setSex("女"); String path = "src/test/resources/person.txt"; try { FileOutputStream fileOutputStream = new FileOutputStream(new File(path)); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(person); System.out.println("序列化成功"); fileOutputStream.close(); objectOutputStream.close(); } catch (FileNotFoundException e) { System.out.printf("FileNotFoundException====>" + e); } catch (IOException e) { System.out.printf("IOException====>" + e); } } private static Person Deserialization() { try { FileInputStream fileInputStream = new FileInputStream(new File("src/test/resources/person.txt")); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); Person person = (Person) objectInputStream.readObject(); System.out.printf("Deserialization.person===>"+person); } catch (FileNotFoundException e) { System.out.printf("FileNotFoundException====>" + e); } catch (IOException e) { System.out.printf("IOException====>" + e); } catch (ClassNotFoundException e) { System.out.printf("ClassNotFoundException====>" + e); } return null; } }

先序列化,才進行反序列化

Deserialization.person===>Person{age=10, name='測試', sex='女'} 

給person增長字段,再用原來的序列化後的結果,進行反序列化;

package com.java.baseinfo.knowledge.code.serializable;

import java.io.Serializable;
public class Person implements Serializable { private int age; private String name; private String sex; // 增長字段測試序列化 private String addText; public int getAge() { return age; } public void setAge(int age) { this.age = age; } 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 String getAddText() { return addText; } public void setAddText(String addText) { this.addText = addText; } @Override public String toString() { final StringBuffer sb = new StringBuffer("Person{"); sb.append("age=").append(age); sb.append(", name='").append(name).append('\''); sb.append(", sex='").append(sex).append('\''); sb.append(", addText='").append(addText).append('\''); sb.append('}'); return sb.toString(); } }

 運行結果

IOException====>java.io.InvalidClassException: com.java.baseinfo.knowledge.code.serializable.Person; local class incompatible: stream classdesc serialVersionUID = 6964452789008335213, local class serialVersionUID = -3534890433624150186
Process finished with exit code 0  

 緣由是:以前代碼中未顯示的指定UID,當Object中新增字段時,編譯器又新生成一個UID,因而出現序列化版本不一致的問題;

2.2 顯式指定UID

package com.java.baseinfo.knowledge.code.serializable;

import java.io.Serializable;

public class Person implements Serializable {

    private static final long serialVersionUID = -3534890433624150186L;
    private int age;

    private String name;

    private String sex;

    public int getAge() {
        return age;
    }

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

    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;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("Person{");
        sb.append("age=").append(age);
        sb.append(", name='").append(name).append('\'');
        sb.append(", sex='").append(sex).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

運行上述main函數, 先進行序列化,而後再對object增長屬性,再序列化的結果,進行反序列化

package com.java.baseinfo.knowledge.code.serializable;

import java.io.Serializable;

public class Person implements Serializable {

    private static final long serialVersionUID = -3534890433624150186L;
    private int age;

    private String name;

    private String sex;

    // 增長字段測試序列化
    private String addText;

    public int getAge() {
        return age;
    }

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

    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 String getAddText() {
        return addText;
    }

    public void setAddText(String addText) {
        this.addText = addText;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("Person{");
        sb.append("age=").append(age);
        sb.append(", name='").append(name).append('\'');
        sb.append(", sex='").append(sex).append('\'');
        sb.append(", addText='").append(addText).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

反序列化結果,新增的字段爲空值

Deserialization.person===>Person{age=10, name='測試', sex='女', addText='null'}
Process finished with exit code 0 

顯式的指定UID,目前經常使用到的場景是:當object增長的字段時候,不但願反序列化出現異常,即但願類的不一樣版本對序列化兼容;

等用到其餘場景的時候,再更新。。

3. Externalizable-example

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class PersonExternal implements Externalizable {

    private int age;

    private String name;

    private String sex;

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
//未實現 } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
//未實現 } public int getAge() { return age; } public void setAge(int age) { this.age = age; } 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; } @Override public String toString() { final StringBuffer sb = new StringBuffer("PersonExternal{"); sb.append("age=").append(age); sb.append(", name='").append(name).append('\''); sb.append(", sex='").append(sex).append('\''); sb.append('}'); return sb.toString(); }  

先序列化再反序列化

package com.java.baseinfo.knowledge.code.serializable;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class TetsExternalizable {

    public static void main(String[] args) {
        //ExternalizableEnCode();

        ExternalizableDecode();
    }

    private static void ExternalizableEnCode() {
        PersonExternal personExternal = new PersonExternal();
        personExternal.setName("測試");
        personExternal.setAge(18);
        personExternal.setSex("女");
        File file = new File("src/test/resources/personExternal.txt");

        try {
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
            outputStream.writeObject(personExternal);
            System.out.printf("ExternalizableEnCode===>序列化完成");

        } catch (FileNotFoundException e) {
            System.out.printf("ExternalizableEnCode.FileNotFoundException===>" + e);
        } catch (IOException e) {
            System.out.printf("ExternalizableEnCode.IOException===>" + e);
        }

    }

    private static void ExternalizableDecode() {
        try {
            File file = new File("src/test/resources/personExternal.txt");
            FileInputStream fileInputStream = new FileInputStream(file);
            ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);

            PersonExternal personExternal = (PersonExternal) inputStream.readObject();
            System.out.println("ExternalizableDecode.personExternal====>" + personExternal);

        } catch (FileNotFoundException e) {
            System.out.printf("ExternalizableDecode.FileNotFoundException===>" + e);
        } catch (IOException e) {
            System.out.printf("ExternalizableDecode.IOException===>" + e);
        } catch (ClassNotFoundException e) {
            System.out.printf("ExternalizableDecode.ClassNotFoundException===>" + e);
        }
    }
}

運行結果

ExternalizableDecode.personExternal====>PersonExternal{age=0, name='null', sex='null'}  

此時發現,當時序列化的對象值並未持久化,是由於咱們沒有重寫Externalizable的writeExternal和readExternal方法

重寫externalizable方法

package com.java.baseinfo.knowledge.code.serializable;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class PersonExternal implements Externalizable {

    private int age;

    private String name;

    private String sex;

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeInt(age);
        out.writeObject(name);
        out.writeObject(sex);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        age = in.readInt();
        name = (String) in.readObject();
        sex = (String) in.readObject();
    }

    public int getAge() {
        return age;
    }

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

    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;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("PersonExternal{");
        sb.append("age=").append(age);
        sb.append(", name='").append(name).append('\'');
        sb.append(", sex='").append(sex).append('\'');
        sb.append('}');
        return sb.toString();
    }
} 

 運行結果

ExternalizableEnCode===>序列化完成ExternalizableDecode.personExternal====>PersonExternal{age=18, name='測試', sex='女'}  

結論:

Externalizable反序列化的時候,會調用被序列化的無參構造函數去建立一個新的對象,而後再將被保存的對象的字段分別填充到新的對象中;因此使用Externalizable時候,除了重寫write/read方法外,所須要序列化的對象還須要提供一個無參的構造函數;若沒有無參構造函數,則會拋異常:java.io.InvalidClassException

eg:

package com.java.baseinfo.knowledge.code.serializable;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class PersonExternal implements Externalizable {

    private int age;

    private String name;

    private String sex;

    //構造函數
    public PersonExternal(int age, String name, String sex) {
        this.age = age;
        this.name = name;
        this.sex = sex;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeInt(age);
        out.writeObject(name);
        out.writeObject(sex);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        age = in.readInt();
        name = (String) in.readObject();
        sex = (String) in.readObject();
    }

    public int getAge() {
        return age;
    }

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

    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;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("PersonExternal{");
        sb.append("age=").append(age);
        sb.append(", name='").append(name).append('\'');
        sb.append(", sex='").append(sex).append('\'');
        sb.append('}');
        return sb.toString();
    }
}  

test main

package com.java.baseinfo.knowledge.code.serializable;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class TetsExternalizable {

    public static void main(String[] args) {
        ExternalizableEnCode();

        ExternalizableDecode();
    }

    private static void ExternalizableEnCode() {
        PersonExternal personExternal = new PersonExternal(18,"測試","女");
/*        personExternal.setName("測試");
        personExternal.setAge(18);
        personExternal.setSex("女");*/
        File file = new File("src/test/resources/personExternal.txt");

        try {
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
            outputStream.writeObject(personExternal);
            System.out.printf("ExternalizableEnCode===>序列化完成");

        } catch (FileNotFoundException e) {
            System.out.printf("ExternalizableEnCode.FileNotFoundException===>" + e);
        } catch (IOException e) {
            System.out.printf("ExternalizableEnCode.IOException===>" + e);
        }

    }

    private static void ExternalizableDecode() {
        try {
            File file = new File("src/test/resources/personExternal.txt");
            FileInputStream fileInputStream = new FileInputStream(file);
            ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);

            PersonExternal personExternal = (PersonExternal) inputStream.readObject();
            System.out.println("ExternalizableDecode.personExternal====>" + personExternal);

        } catch (FileNotFoundException e) {
            System.out.printf("ExternalizableDecode.FileNotFoundException===>" + e);
        } catch (IOException e) {
            System.out.printf("ExternalizableDecode.IOException===>" + e);
        } catch (ClassNotFoundException e) {
            System.out.printf("ExternalizableDecode.ClassNotFoundException===>" + e);
        }
    }
}  

運行結果

ExternalizableEnCode===>序列化完成ExternalizableDecode.IOException===>java.io.InvalidClassException: com.java.baseinfo.knowledge.code.serializable.PersonExternal; no valid constructor

4.transient 關鍵字

若是對象的屬性被賦予transient屬性,則該對象在序列化的時候,當前字段不會被序列化;那麼再反序列化的時候,該字段會被賦予默認值,如int類型會是0,String爲null

eg

public class Person implements Serializable {

    private static final long serialVersionUID = -3534890433624150186L;
    private transient int age;

    private transient String name;

    private String sex;

    // 增長字段測試序列化
    private String addText;  

運行2中的序列化代碼,則結果爲

序列化成功
反序列化Deserialization.person===>Person{age=0, name='null', sex='女', addText='addText'}
Process finished with exit code 0  

參考:https://www.cnblogs.com/xdp-gacl/p/3777987.html      

http://www.importnew.com/17964.html

相關文章
相關標籤/搜索