Java序列化

来源:https://www.cnblogs.com/lovesong/archive/2018/04/20/8893928.html
-Advertisement-
Play Games

什麼是序列化? 我們創建的對象只有在Java虛擬機保持運行時,才會存在於記憶體中。如果想要超出Java虛擬機的生命周期,就可以將對象序列化,將對象狀態轉換為位元組序列,寫入文件(或socket傳輸),後面使用時再讀入文件,讀入原始位元組並創建一個完全相同的對象。 PS:只有對象的狀態會被序列化,類本身或方 ...


什麼是序列化?

我們創建的對象只有在Java虛擬機保持運行時,才會存在於記憶體中。如果想要超出Java虛擬機的生命周期,就可以將對象序列化,將對象狀態轉換為位元組序列,寫入文件(或socket傳輸),後面使用時再讀入文件,讀入原始位元組並創建一個完全相同的對象。

PS:只有對象的狀態會被序列化,類本身或方法都不會被序列化。

三種序列化方式

1、預設機制

需要序列化的對象,實現java.io.Serializable介面即可。

例子:

import java.io.Serializable;
import java.util.Date;
import java.util.Calendar;

public class PersistentTime implements Serializable {
    private Date time;

    public PersistentTime() {
        time = Calendar.getInstance().getTime();
    }

    public Date getTime() {
        return time;
    }
}


import java.io.ObjectOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FlattenTime {
    public static void main(String[] args) {
        String filename = "time.ser";
        if (args.length > 0) {
            filename = args[0];
        }
        PersistentTime time = new PersistentTime();
        FileOutputStream fos = null;
        ObjectOutputStream out = null;
        try {
            fos = new FileOutputStream(filename);
            out = new ObjectOutputStream(fos);
            out.writeObject(time);
            out.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}


import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Calendar;

public class InflateTime {
    public static void main(String[] args) {
        String filename = "time.ser";
        if (args.length > 0) {
            filename = args[0];
        }
        PersistentTime time = null;
        FileInputStream fis = null;
        ObjectInputStream in = null;
        try {
            fis = new FileInputStream(filename);
            in = new ObjectInputStream(fis);
            time = (PersistentTime) in.readObject();
            in.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
        // print out restored time
        System.out.println("Flattened time: " + time.getTime());
        System.out.println();
        // print out the current time
        System.out.println("Current time: " + Calendar.getInstance().getTime());
    }
}
View Code

註意:

1、持久化的對象必現實現Serializable介面或繼承的父類實現了。

2、不能(例如系統級別的類Thread、OutPutStream)或不想被序列化的欄位必需加transient聲明。

transient是欄位的修飾符,當一個欄位聲明為transient時,它就不能被序列化。

transient不能聲明方法、類、介面,它們不需要被序列化。

2、自定義預設協議

由於類的構造函數只要在對象創建時候才調用,而反序列化的對象是用readObject創建的,不會再去調構造函數。如果構造函數里有執行某些行為,那麼反序列化回來的對象就會丟失這些行為。

解決方法:增加兩個方法,在保證序列化的預設行為後,增加自己要的行為。

private void writeObject(ObjectOutputStream out) throws IOException;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;

例子:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class PersistentAnimation implements Serializable, Runnable {
    
    private static final long serialVersionUID = 2850527457134768151L;
    
    transient private Thread animator;
    private int animationSpeed;

    public PersistentAnimation(int animationSpeed) {
        this.animationSpeed = animationSpeed;
        startAnimation();
    }

    public void run() {
        while (true) {
            // do animation here
        }
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        // our "pseudo-constructor"
        in.defaultReadObject();
        // now we are a "live" object again, so let's run rebuild and start
        startAnimation();
    }

    private void startAnimation() {
        animator = new Thread(this);
        animator.start();
    }
}
View Code

同理,如果父類已經實現Serializable介面,子類又不想被序列化,就可以添加這兩個內容為空的方法。

3、自定義協議

實現Externalizable介面,覆寫writeExternal、readExternal兩個方法,自己定義序列化協議(例如pdf的存取)。

public void writeExternal(ObjectOutput out) throws IOException;
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;

序列化的陷阱

1、緩存流中的對象,再修改對象狀態再寫入是無效的。

ObjectOutputStream out = new ObjectOutputStream(...);
MyObject obj = new MyObject(); // must be Serializable
obj.setState(100);
out.writeObject(obj); // saves object with state = 100
obj.setState(200);
out.writeObject(obj); // does not save new object state 

2、版本控制

當你序列化一個對象存儲到文件後,修改類的定義(例如增加個欄位),當你反序列化時,會報一個java.io.InvalidClassException的異常。這是因為所有可以持續化的類都會有一個唯一的標識符,如果類的標識符跟反序列化對象的標識符不一樣時,就會報這個異常。

解決方法:增加一個serialVersionUID欄位作為類的標識符,只要標識符不變,就可反序列化。

添加方法:在eclipse中,滑鼠懸浮到類名上,就可以看到“添加已生成的串列版本標識”,點擊即可添加serialVersionUID。

3、性能問題

序列化對象寫入文件的性能會比自己手動寫入文件低。

參考文獻

http://www.oracle.com/technetwork/articles/java/javaserial-1536170.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、安裝 # cd /usr/local/src/# wget http://mirrors.shu.edu.cn/apache//activemq/5.15.3/apache-activemq-5.15.3-bin.tar.gz# tar -xzvf apache-activemq-5.15.3- ...
  • 練習6.1: 為bit數組實現下麵這些方法 ...
  • 分頁查詢關鍵代碼: 通過servlet轉發回來的各種信息進行分頁的設計(轉發回的信息有 分頁查詢的List集合 查詢的頁碼 查詢的條數 查詢的資料庫總條數 查詢的總頁碼) 從開始時迴圈10次出現十個數字開始逐步細化 註意:jstl(java標磚標簽庫) 的判斷條件 test="" 引號中的變數運算寫 ...
  • 寫在前面 1.概念 IO流用來處理設備之間的數據傳輸 Java對數據的操作是通過流的方式 Java用於操作流的類都在IO包中 流按流向分為兩種:輸入流,輸出流 流按操作類型分為兩種: 位元組流 : 位元組流可以操作任何數據,因為在電腦中任何數據都是以位元組的形式存儲的 字元流 : 字元流只能操作純字元數 ...
  • 上一節我們結束了有關python的方法相關內容 這一節我們先來學習python的列表推導式 之前跟大家說過range方法的使用,在這裡我就不做過多的解釋了,如忘記了,請翻閱之前的介紹 列表推導式,是Python內置的一種極其強大的生成list的表達式 如果要生成一個list [1 , 2 , 3 , ...
  • 微服務架構模式的核心在於如何識別服務的邊界,設計出合理的微服務。但如果要將微服務架構運用到生產項目上,並且能夠發揮該架構模式的重要作用,則需要微服務框架的支持。 在Java生態圈,目前使用較多的微服務框架就是集成了包括Netfilix OSS以及Spring的Spring Cloud。它包括: Sp ...
  • 中文翻譯:Python之禪 by Tim Peters 優美勝於醜陋(Python 以編寫優美的代碼為目標)明瞭勝於晦澀(優美的代碼應當是明瞭的,命名規範,風格相似)簡潔勝於複雜(優美的代碼應當是簡潔的,不要有複雜的內部實現)複雜勝於凌亂(如果複雜不可避免,那代碼間也不能有難懂的關係,要保持介面簡潔 ...
  • 具體報錯信息: lto1: fatal error: bytecode stream generated with LTO version 6.0 instead of the expected 4.1 compilation terminated. lto-wrapper: fatal error ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...