這個關鍵字的作用其實我在寫java的序列化機制中曾經寫過,不過那時候只是簡單地認識,只要其簡單的用法,沒有的去分析。這篇文章就是去分析一下transient關鍵字。
先給出這篇文章的大致脈絡
首先,介紹了transient的基本概念和基本用法、然后,介紹分析一下transient關鍵字,並介紹幾個需要掌握的問題最后,來個總結
一、初識transient關鍵字
其實這個關鍵字的作用很好理解,就是簡單的一句話:將不需要序列化的屬性前添加關鍵字transient,序列化對象的時候,這個屬性就不會被序列化。
概念也很好理解,下面使用代碼去驗證一下:

然后我們在Test中去驗證一下:

從上面可以看出,在序列化SerializeUser方法中,首先創建一個序列化user類,然后將其寫入到G://Test/template路徑中。在反序列化DeSerializeUser方法中,首先創建一個File,然后讀取G://Test/template路徑中的數據。
這就是序列化和反序列化的基本實現,而且我們看一下結果,也就是被transient關鍵字修飾的age屬性是否被序列化。

從上面的這張圖可以看出,age屬性變為了0,說明被transient關鍵字修飾之后沒有被序列化。
二、分析transient關鍵字
為了更加的去分析transient關鍵字,我們需要帶着幾個問題去解讀:
(1)transient底層實現的原理是什么?
(2)被transient關鍵字修飾過得變量真的不能被序列化嘛?
(3)靜態變量能被序列化嗎?被transient關鍵字修飾之后呢?
帶着這些問題一個一個來解決:
1、transient底層實現原理是什么?
java的serialization提供了一個非常棒的存儲對象狀態的機制,說白了serialization就是把對象的狀態存儲到硬盤上 去,等需要的時候就可以再把它讀出來使用。有些時候像銀行卡號這些字段是不希望在網絡上傳輸的,transient的作用就是把這個字段的生命周期僅存於調用者的內存中而不會寫到磁盤里持久化,意思是transient修飾的age字段,他的生命周期僅僅在內存中,不會被寫到磁盤中。
2、被transient關鍵字修飾過得變量真的不能被序列化嘛?
想要解決這個問題,首先還要再重提一下對象的序列化方式:
Java序列化提供兩種方式。
一種是實現Serializable接口
另一種是實現Exteranlizable接口。 需要重寫writeExternal和readExternal方法,它的效率比Serializable高一些,並且可以決定哪些屬性需要序列化(即使是transient修飾的),但是對大量對象,或者重復對象,則效率低。
從上面的這兩種序列化方式,我想你已經看到了,使用Exteranlizable接口實現序列化時,我們自己指定那些屬性是需要序列化的,即使是transient修飾的。下面就驗證一下
首先我們定義User1類:這個類是被Externalizable接口修飾的

然后我們就可以測試了

上面,代碼分了兩個方法,一個是序列化,一個是反序列化。里面的代碼和一開始給出的差不多,只不過,User1里面少了age這個屬性。
然后看一下結果:

結果基本上驗證了我們的猜想,也就是說,實現了Externalizable接口,哪一個屬性被序列化使我們手動去指定的,即使是transient關鍵字修飾也不起作用。
3、靜態變量能被序列化嗎?沒被transient關鍵字修飾之后呢?
這個我可以提前先告訴結果,靜態變量是不會被序列化的,即使沒有transient關鍵字修飾。下面去驗證一下,然后再解釋原因。
首先,在User類中對age屬性添加transient關鍵字和static關鍵字修飾。
然后,在Test類中去測試

最后,測試一下,看看結果

結果已經很明顯了。現在解釋一下,為什么會是這樣,其實在前面已經提到過了。因為靜態變量在全局區,本來流里面就沒有寫入靜態變量,我打印靜態變量當然會去全局區查找,而我們的序列化是寫到磁盤上的,所以JVM查找這個靜態變量的值,是從全局區查找的,而不是磁盤上。user.setAge(18);年齡改成18之后,被寫到了全局區,其實就是方法區,只不過被所有的線程共享的一塊空間。因此可以總結一句話:
靜態變量不管是不是transient關鍵字修飾,都不會被序列化
三、transient關鍵字總結
java 的transient關鍵字為我們提供了便利,你只需要實現Serilizable接口,將不需要序列化的屬性前添加關鍵字transient,序列化對象的時候,這個屬性就不會序列化到指定的目的地中。像銀行卡、密碼等等這些數據。這個需要根據業務情況了。