小伙子,你真的搞懂 transient 關鍵字了嗎?

来源:https://www.cnblogs.com/javastack/archive/2019/03/06/10481133.html
-Advertisement-
Play Games

先解釋下什麼是序列化 我們的對象並不只是存在記憶體中,還需要傳輸網路,或者保存起來下次再載入出來用,所以需要Java序列化技術。 Java序列化技術正是將對象轉變成一串由二進位位元組組成的數組,可以通過將二進位數據保存到磁碟或者傳輸網路,磁碟或者網路接收者可以在對象的屬類的模板上來反序列化類的對象,達到 ...


先解釋下什麼是序列化

我們的對象並不只是存在記憶體中,還需要傳輸網路,或者保存起來下次再載入出來用,所以需要Java序列化技術。

Java序列化技術正是將對象轉變成一串由二進位位元組組成的數組,可以通過將二進位數據保存到磁碟或者傳輸網路,磁碟或者網路接收者可以在對象的屬類的模板上來反序列化類的對象,達到對象持久化的目的。

更多序列化請參考:《關於Java序列化你應該知道的一切》這篇文章。

什麼是 transient?

簡單來說就是,被 transient 修飾的變數不能被序列化。

具體來看下麵的示例1

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * @author 微信公眾號:Java技術棧
 */
public class TransientTest {

    public static void main(String[] args) throws Exception {

        User user = new User();
        user.setUsername("Java技術棧");
        user.setId("javastack");

        System.out.println("\n序列化之前");
        System.out.println("username: " + user.getUsername());
        System.out.println("id: " + user.getId());

        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d:/user.txt"));
        os.writeObject(user);
        os.flush();
        os.close();

        ObjectInputStream is = new ObjectInputStream(new FileInputStream("d:/user.txt"));
        user = (User) is.readObject();
        is.close();

        System.out.println("\n序列化之後");
        System.out.println("username: " + user.getUsername());
        System.out.println("id: " + user.getId());

    }
}

/**
 * @author 微信公眾號:Java技術棧
 */
class User implements Serializable {

    private static final long serialVersionUID = 1L;

    private String username;
    private transient String id;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getId() {
        return id;
    }

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

}

輸出結果:

序列化之前
username: Java技術棧
id: javastack

序列化之後
username: Java技術棧
id: null

示例1在 id 欄位上加了 transient 關鍵字修飾,反序列化出來之後值為 null,說明瞭被 transient 修飾的變數不能被序列化。

靜態變數能被序列化嗎?

這個話題也是最近棧長的Java技術棧vip群裡面討論的,大家對這個知識點比較模糊,我就寫了這篇文章測試總結一下。

如果你也想加入我們的Java技術棧vip群和各位大牛一起討論技術,那點擊這個鏈接瞭解加入吧。

那麼,到底靜態變數能被序列化嗎?廢話少說,先動手測試下吧!

示例2:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * @author 微信公眾號:Java技術棧
 */
public class TransientStaticTest {

    public static void main(String[] args) throws Exception {

        User2 user = new User2();
        User2.username = "Java技術棧1";
        user.setId("javastack");

        System.out.println("\n序列化之前");
        System.out.println("username: " + user.getUsername());
        System.out.println("id: " + user.getId());

        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d:/user.txt"));
        os.writeObject(user);
        os.flush();
        os.close();
        
        // 在反序列化出來之前,改變靜態變數的值
        User2.username = "Java技術棧2";

        ObjectInputStream is = new ObjectInputStream(new FileInputStream("d:/user.txt"));
        user = (User2) is.readObject();
        is.close();

        System.out.println("\n序列化之後");
        System.out.println("username: " + user.getUsername());
        System.out.println("id: " + user.getId());

    }
}

/**
 * @author 微信公眾號:Java技術棧
 */
class User2 implements Serializable {

    private static final long serialVersionUID = 1L;

    public static String username;
    private transient String id;

    public String getUsername() {
        return username;
    }

    public String getId() {
        return id;
    }

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

}

輸出結果:

序列化之前
username: Java技術棧1
id: javastack

序列化之後
username: Java技術棧2
id: null

示例2把 username 改為了 public static, 併在反序列化出來之前改變了靜態變數的值,結果可以看出序列化之後的值並非序列化進去時的值。

由以上結果分析可知,靜態變數不能被序列化,示例2讀取出來的是 username 在 JVM 記憶體中存儲的值。

transient 真不能被序列化嗎?

繼續來看示例3:

import java.io.Externalizable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

/**
 * @author 微信公眾號:Java技術棧
 */
public class ExternalizableTest {

    public static void main(String[] args) throws Exception {

        User3 user = new User3();
        user.setUsername("Java技術棧");
        user.setId("javastack");
        ObjectOutput objectOutput = new ObjectOutputStream(new FileOutputStream(new File("javastack")));
        objectOutput.writeObject(user);

        ObjectInput objectInput = new ObjectInputStream(new FileInputStream(new File("javastack")));
        user = (User3) objectInput.readObject();

        System.out.println(user.getUsername());
        System.out.println(user.getId());

        objectOutput.close();
        objectInput.close();
    }

}

/**
 * @author 微信公眾號:Java技術棧
 */
class User3 implements Externalizable {

    private static final long serialVersionUID = 1L;

    public User3() {

    }

    private String username;
    private transient String id;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getId() {
        return id;
    }

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

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

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

}

輸出結果:

null
javastack

示例3的 id 被 transient 修改了,為什麼還能序列化出來?那是因為 User3 實現了介面 Externalizable,而不是 Serializable。

在 Java 中有兩種實現序列化的方式,Serializable 和 Externalizable,可能大部分人只知道 Serializable 而不知道 Externalizable。

這兩種序列化方式的區別是:實現了 Serializable 介面是自動序列化的,實現 Externalizable 則需要手動序列化,通過 writeExternal 和 readExternal 方法手動進行,這也是為什麼上面的 username 為 null 的原因了。

transient 關鍵字總結

1)transient修飾的變數不能被序列化;

2)transient只作用於實現 Serializable 介面;

3)transient只能用來修飾普通成員變數欄位;

4)不管有沒有 transient 修飾,靜態變數都不能被序列化;

好了,棧長花了半天時間,終於整理完了。如果對你有幫助,那就轉發分享一下吧!如果你也想加入我們的Java技術棧vip群和各位大牛一起討論技術,那點擊這個鏈接瞭解加入吧

另外,棧長已經整理了大量 Java 系列核心技術知識點文章,關註Java技術棧微信公眾號,在後臺回覆關鍵字:java,即可獲取最新版。

本文原創首發於微信公眾號:Java技術棧(id:javastack),關註公眾號在後臺回覆 "java" 可獲取更多,轉載請原樣保留本信息。


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

-Advertisement-
Play Games
更多相關文章
  • 參考: "ANTLR4: Making a compiler with the JavaScript runtime" 演示效果雖弱, 還是先上圖吧: 線上演示: "地址" . 源碼庫: "program in chinese/quan4" 下載到本地後在瀏覽器中打開"圈4.html"就可以在本地試 ...
  • 參考資料:理解javaScript中的async/await,感謝原文作者的總結,本文在理解的基礎上做了一點小小的修改,主要為了加深自己的知識點掌握 學完了Promise,我們知道可以用then鏈來解決多層回調問題,但是這還不是最理想的操作,我們需要調用很多個then鏈才能達到要求,那麼有沒有一種更 ...
  • 1. 使用插件 clamp.js 可實現多行文本超出後隱藏的功能 2. git地址 https://github.com/josephschmitt/Clamp.js 下載後項目引入clamp.js 3. //多行 3行 let demo = document.getElementById('dem ...
  • swiper4輪播設置autoplay自動切換後,即預設設置: disableOnInteraction屬性 disableOnInteraction屬性 用戶操作swiper之後,是否禁止autoplay。預設為true:停止。如果設置為false,用戶操作swiper之後自動切換不會停止,每次都 ...
  • 一、什麼是適配器模式 定義:適配器模式屬於結構型模式,把一個類的介面變成客戶端所期待的另一種介面,從而使原本介面不匹配而無法一起工作的兩個類能夠在一起工作。 適配器模式又可以分為4種類型,類適配器模式、對象適配器模式、單介面適配器模式(預設適配器模式)和雙向適配器模式。後2種模式的實現比較複雜並且在 ...
  • 單一職責原則 Single Responsibility Principle,簡稱SRP,就一個類而言,應該僅有一個引起它變化的原因。 同價位的相機和手機哪個拍照好? 我覺得說同價位都太謙虛了,低端的千元卡片機完全可以弔打比自身貴至少三五倍價錢的手機,如果是萬元單反,我覺得市場上已經沒有什麼手機的拍 ...
  • 現在辦公要流程化,營銷也有流程,流程現在已經是各種生活活動不可缺少的一部分了。就像這句耳熟能詳的話:“凡事,我們先走個流程嘛!”,在信息化、流程化的背景下。工作流引擎,這個名詞就出現了!那麼,什麼是 工作流引擎呢?所謂工作流引擎是指workflow作為應用系統的一部分,併為之提供對各應用系統有決定作 ...
  • ThreadPoolExecutor 它是線程池最核心的類, 這裡對核心的方法做簡要的剖析(會持續更新),以加深對線程池運行原理的理解。 1. 核心成員變數及相關方法 1 // ctl非常重要,用整型表示,共32位,其中**高3位代表線程池狀態,低29位代表工作線程數**; 2 // 線程池狀態初始 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...