Java序列化流的奇妙之旅

淵渟嶽發表於2022-03-07

Java序列化流有何奇妙之處呢?通過一個個案例逐一感受序列化流。

!!!好戲在後頭!!!

1.IO流讀寫檔案

先從一個普通檔案讀寫字串開始講起。

例子:輸出字串到檔案,再從檔案中讀取字串

image

在某一天靈感迸發:我可以把Java程式中的物件資訊直接儲存到普通的 txt 檔案中嗎?並且當我想使用它時,還可以拿出來就可以直接用,不需要再做其他處理,就像儲存普通的字串一樣,在檔案中讀出來就可以直接使用的那種。

2.序列化和反序列化流奇妙之處

要想實現物件資訊儲存到普通檔案不被破化,並且讀取出來不需要再做其他處理既可以像使用普通new出來的物件一樣直接使用的效果,必須有一種特殊的IO流來完成,於是誕生了序列化流和反序列化流

2.1.案例一:把普通檔案當作物件儲存庫來使用

詳細的描述:將一個list 集合儲存到普通檔案,再讀出來直接使用,實現list集合資料的增刪改查

Person 類

// 序列化物件資訊:必須實現序列化標記介面Serializable
public class Person implements Serializable {
    // 序列化版本UID
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    private String sex;
    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;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Person{" + "name='" + name + ", age=" + age + ", sex='" + sex + '}';
    }
    public Person() {
    }
    public Person(String name, Integer age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
}

序列化和反序列化

public class Demo2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //資料準備:集合類都實現了序列化介面Serializable
        List<Person> list = new ArrayList<>();
        list.add(new Person("張三",38,"男"));
        list.add(new Person("李四",38,"男"));
        list.add(new Person("如花",18,"女"));

        // 序列化儲存到普通檔案
        File file = new File("D:/demo2.txt");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
        objectOutputStream.writeObject(list);
        objectOutputStream.close();

        // 讀取普通檔案反序列化
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
        List<Person> personList = (List<Person>) objectInputStream.readObject();
        objectInputStream.close();
        for (Person person:personList){
            System.out.println(person);
        }
        
    }
}

執行結果:

image

序列化儲存到普通檔案的資料:

image

雖然沒人會考慮使用這種方式來儲存資料,但這對於理解序列化流有很大的幫助。

2.2.案例二:任意元素型別的List 集合序列化讀寫

**
 * 任意元素型別的List 集合的物件儲存到普通檔案,讀取直接使用
 * @param <T>
 */
public class ObjectList<T extends List> {
    // 序列化儲存到普通檔案
    private File file = new File("D:/demoList.txt");

    public void writerList(T t) throws IOException {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
        objectOutputStream.writeObject(t);
        objectOutputStream.close();
    }

    public T readList() throws IOException, ClassNotFoundException {
        // 讀取普通檔案反序列化
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
        T t = (T) objectInputStream.readObject();
        objectInputStream.close();
        return t;
    }

    public boolean isExists(){
        return file.exists();
    }
    public boolean delete(){
        return file.delete();
    }

    // 測試
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectList<List<Person>> objectList = new ObjectList<>();
        //資料準備:集合類都實現了序列化介面Serializable
        List<Person> list = new ArrayList<>();
        list.add(new Person("張三",38,"男"));
        list.add(new Person("李四",38,"男"));
        list.add(new Person("如花",18,"女"));
        // 持久化物件資料
        objectList.writerList(list);
        // 查詢持久化物件資料
        List<Person> personList = objectList.readList();
        System.out.println("遍歷持久化物件資料>");
        for (Person person:personList){
            System.out.println(person);
            if (person.getAge()==38){// 修改年齡38的都改為18
                person.setAge(18);
            }
        }
        // 修改後持久化物件資料
        objectList.writerList(personList);
        System.out.println("遍歷修改持久化物件資料>");
        List<Person> personList1 = objectList.readList();
        for (Person person:personList1){
            System.out.println(person);
        }
        // 刪除物件儲存的持久化檔案
        if (objectList.isExists()){
            System.out.println("刪除物件儲存的持久化檔案");
            objectList.delete();
        }

    }

}

序列化的目的

  • 序列化流目的:把物件模型資料按序列化規則進行轉化,轉化後的資料可以儲存到磁碟文字或通過網路傳輸;
  • 反序列化流目的:把磁碟檔案或網路傳輸的序列化資料按反序列化規則進行轉化,恢復成物件模型資料,在程式中可直接操作物件模型資料。

前面的案例都是程式和磁碟的IO操作,接下來的是序列化物件通過網路傳輸的案例。

2.3.案例三:自己實現Java RMI(遠端方法呼叫)

Java RMI(Remote Method Invocation)Java 遠端方法呼叫,是Java程式語言裡的一種用於實現遠端方法呼叫的應用程式程式設計介面。RMI的宗旨就是儘可能簡化遠端介面物件的使用。

相類似的遠端過程呼叫RPC(Remote Procedure Call),指的是一個程式呼叫另一個程式(本地或遠端主機的程式)的過程。Java 的 RMI 則在 RPC 的基礎上向前又邁進了一步,既提供了分散式物件間的通訊。但Java RMI僅限於Java語言間相互呼叫,無法實現不同語言間的遠端方法呼叫。

在這感受下怎麼實現遠端方法呼叫,好玩時刻來了。

!!!高能預警!!!

篇幅原因,請移步到:自己寫了個Java RMI(遠端方法呼叫) 的實現案例

image

image

Java往期文章

Java全棧學習路線、學習資源和麵試題一條龍

我心裡優秀架構師是怎樣的?

免費下載經典程式設計書籍

更多優質文章和資源?

image

原創不易:分享,點贊?

相關文章