1. 程式人生 > 其它 >Java-IO(序列化流)

Java-IO(序列化流)

序列化與反序列化

  • 序列化:把物件按照流一樣的方式存到文字檔案或者資料庫或者網路中傳輸等等。
    物件 -- 流資料:ObjectOutputStream
  • 反序列化:把文字檔案中的物件或者網路中的流資料給還原成一個物件的過程。
    流資料 -- 物件:ObjectInputStream

未序列化異常

  • NotSerializableException: com.shujia.wyh.day25.Person
    只有支援java.io.Serializable介面的物件才能寫入流中。
    類的序列化由實現java.io.Serializable介面的類啟用。
    不實現此介面的類將不會使任何狀態序列化或反序列化。
    可序列化類的所有子型別都是可序列化的。

觀察API

  • 通過觀察API發現,Serializable介面中沒有任何抽象方法和常量,說明它是一個標記介面。
    (回想一下,我們之前說過的Object類中的克隆)
當寫入物件資料後,在讀取資料之前,將物件屬性發生改變,或者其他改變操作會發生異常
  • java.io.InvalidClassException: com.shujia.wyh.day25.Person;
    local class incompatible:
    stream classdesc serialVersionUID = 8333181233940260538,
    local class serialVersionUID = -2276749375407741261
    即改變前後的 serialVersionUID 值發生改變,

形象理解

在沒有進行修改類之前:

  • Person.class -- id=100
    寫資料的適合:object -- id=100
    讀資料的時候:object -- id=100
  • 在進行修改後(刪除了一個private)
    Person.class -- id=200
    之前寫的時候:object -- id=100
    讀資料的時候:object -- id=100

解決辦法:

  • 在實際開發中,因為業務的問題,不允許重複地往檔案中或者資料庫中重複寫入,那怎麼解決呢?
  • 這個問題本質上是由於id值地不匹配導致地,如果說有一個辦法,無論我怎麼修改class類,這個id值都不會變化就好了。
    Java在序列化中提供了一個ID值,可以讓我們去設定。
    我們不需要手動去設定,自動生成即可。

設定:

  • idea - 設定 - inspecttions - 在搜尋欄中搜索 serializable 修改兩個屬性就好
    使用辦法:游標放在 類名上,按下Alt+ enter.

類中屬性並不想被序列化,解決辦法

  • java提供了一個關鍵字給我們使用,可以讓我們在序列化的時候選擇哪些成員變數不被序列化
    transient

程式碼

自定義類程式碼
public class Person implements Serializable {
    private static final long serialVersionUID = -2276749375407741261L;
    private String name;
    //    private int age;
    transient int age;

    public Person() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
main方法程式碼
public class ObjectOutputStreamDemo1 {
    public static void main(String[] args) {
        //寫資料,序列化,將一個物件存到一個檔案中,這個過程叫做序列持久化。
//        write();

        read();
    }

    public static void read(){
        //建立物件輸入流
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("src\\com\\shujia\\wyh\\day25\\obj.txt"));
            //呼叫方法讀取資料
            Object o = ois.readObject();
//            System.out.println(o);

            //要想使用讀取到的物件型別中的方法,就得向下轉型
            Person p = (Person) o;
            System.out.println(p);
        } catch (Exception e) {
            e.printStackTrace();
        }  finally {
            if(ois!=null){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void write(){
        ObjectOutputStream oos = null;
        //建立一個物件輸出流
        try {
            oos = new ObjectOutputStream(new FileOutputStream("src\\com\\shujia\\wyh\\day25\\obj.txt"));
            //建立一個物件
            Person p = new Person("李毅", 18);

            //呼叫方法,將物件寫入到檔案中進行儲存
            oos.writeObject(p);

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(oos!=null){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}