Java 序列化與反序列化

一、什麼是序列化?爲何要序列化?java

    Java 序列化就是指將對象轉換爲字節序列的過程,而反序列化則是隻將字節序列轉換成目標對象的過程。面試

    咱們都知道,在進行瀏覽器訪問的時候,咱們看到的文本、圖片、音頻、視頻等都是經過二進制序列進行傳輸的,那麼若是咱們須要將Java對象進行傳輸的時候,是否是也應該先將對象進行序列化?答案是確定的,咱們須要先將Java對象進行序列化,而後經過網絡,IO進行傳輸,當到達目的地以後,再進行反序列化獲取到咱們想要的對象,最後完成通訊。瀏覽器

 

二、如何實現序列化網絡

  2.一、使用到JDK中關鍵類 ObjectOutputStream 和ObjectInputStreamide

    ObjectOutputStream 類中:經過使用writeObject(Object object) 方法,將對象以二進制格式進行寫入。工具

    ObjectInputStream 類中:經過使用readObject()方法,從輸入流中讀取二進制流,轉換成對象。this

 

  2.二、目標對象須要先實現 Seriable接口
spa

  

咱們建立一個Student類:code

public class Student implements Serializable {
    private static final long serialVersionUID = 3404072173323892464L;
    private String name;
    private transient String id;
    private String age;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id='" + id + '\'' +
                ", age='" + age + '\'' +
                '}';
    }

    public String getAge() {
        return age;
    }

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

    public Student(String name, String id) {
        System.out.println("args Constructor");
        this.name = name;
        this.id = id;
    }

    public Student() {
        System.out.println("none-arg Constructor");
    }

    public String getName() {
        return name;
    }

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

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

}

 

        

      代碼中Student類實現了Serializable 接口,而且生成了一個版本號:視頻

private static final long serialVersionUID = 3404072173323892464L;

      首先:

      一、Serializable 接口的做用只是用來標識咱們這個類是須要進行序列化,而且Serializable 接口中並無提供任何方法。

      二、serialVersionUid 序列化版本號的做用是用來區分咱們所編寫的類的版本,用於判斷反序列化時類的版本是否一直,若是不一致會出現版本不一致異常。

      三、transient 關鍵字,主要用來忽略咱們不但願進行序列化的變量

 

    2.三、將對象進行序列或和反序列化

      2.3.1 第一種寫入方式:

public static  void main(String[] args){
        File file = new File("D:/test.txt");
        Student student = new Student("孫悟空","12");
        try {
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(file));
            outputStream.writeObject(student);
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
            Student s = (Student) objectInputStream.readObject();
            System.out.println(s.toString());
            System.out.println(s.equals(student));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

      建立對象Student ,而後經過ObjectOutputStream類中的writeObject()方法,將對象輸出到文件中。

      而後經過ObjectinputStream 類中的readObject()方法反序列化,獲取對象。

 

       2.3.2 第二種寫入方式:

在Student 類中實現writeObject()和readObject()方法:

  private void writeObject(ObjectOutputStream objectOutputStream) throws IOException {
        objectOutputStream.defaultWriteObject();
        objectOutputStream.writeUTF(id);

    }

    private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
        objectInputStream.defaultReadObject();
        id = objectInputStream.readUTF();
    }

      經過這中方式進行序列話,咱們能夠自定義想要進行序列化的變量,將輸入流和輸出流傳入對線實例中,而後進行序列化以及反序列化。

  

      2.3.3 第三種寫入方式:

Student 實現 Externalnalizable接口 而不實現Serializable 接口

 Externaliable 接口是 Serializable 的子類,有着和Serializable接口一樣的功能:

public class Student implements Externalizable {
    private static final long serialVersionUID = 3404072173323892464L;
    private String name;
    private transient String id;
    private String age;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id='" + id + '\'' +
                ", age='" + age + '\'' +
                '}';
    }

    public String getAge() {
        return age;
    }

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

    public Student(String name, String id) {
        System.out.println("args Constructor");
        this.name = name;
        this.id = id;
    }

    public Student() {
        System.out.println("none-arg Constructor");
    }

    public String getName() {
        return name;
    }

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

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }


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

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

}

 

   經過和前面的第二種寫入方法對比,咱們能夠發現他們的實現原理都是十分的相似,不過實現Externalnalizable接口 並不支持第一種序列化方法,它只可以經過實現接口中的writeExternal()和readExternal()方法實現對象的序列化。

 

 

三、面試中關於序列化的問題:

    一、什麼是序列化,如何實現序列化

        java中對象的序列化就是將對象轉換成二進制序列,反序列化則是將二進制序列轉換成對象

        Java 實現序列化有多種方式

          一、首先須要使用到工具類ObjectInputStream 和ObjectOutputStream 兩個IO類

          二、實現Serializable 接口:

              有兩種具體序列化方法:

                  2.1 直接經過ObjectOutputStream 和 ObjectInputStream 類中的 writeObject()和readObject()方法

                  2.2 經過在序列化對象中實現writeObject()和readObject()方法,傳入ObjectOutputStream和ObjectInputStream對象,完成序列化

          三、實現Externalizable 接口:

                  只可以經過實現接口中的writeExternal()和readExternal()方法實現對象的序列化


     二、transient 關鍵字?如何將transient修飾符修飾的變量序列化?
        
transient 的做用是用來屏蔽咱們不但願進行序列化的變量,是對象在進行序列化和反序列話的過程當中忽略該變量。
        咱們能夠經過上述序列化方法中的 實現writeObject 和readObject 方法,在方法中調用輸出流或輸入流的writeUTF()和readUTF()方法。
        或者經過實現Externalizable 接口,實現writeExternal()和readExternal()方法,而後再自定義序列話對象。

     
      三、如何保證序列化和反序列化後的對象一致?(若有異議望指正)
       
 對於這個問題我在查閱了一些資料以後,發現並不能保證序列化和反序列化以後的對象是一致的,由於咱們在反序列化的過程當中,是先建立一個對象,        而後再經過對對象進行賦值來完成對象的反序列化,這樣問題就來了,在建立了一個新的對象以後,對象引用和本來的對象並非指向同一個目標。        所以咱們只能保證他們的數據和版本一致,並不能保證對象一致。
相關文章
相關標籤/搜索