為什麼java中序列化的serialVersionUID總是無意義的?

這個題目不主要講serialVersionUID作用,而是講後面的那一串數字的意義,當然也會對java的這個serialVersionUID的作用進行一個講解。這篇文章是我積壓了很久的一篇文章,寫了一半,幾個月了才發現,於是拿出來好好整理一下。

一、serialVersionUID的作用

通過java進行網絡之間的數據傳輸是不能直接把對象進行傳的,需要在發送端把數據切分,在接收端對切分的數據進行重裝。這種切分和重裝的方式就叫做序列化。下面我們舉一個例子:

(1)不指定serialVersionUID

首先我們定義一個User類,繼承Serializable接口

為什麼java中序列化的serialVersionUID總是無意義的?

然後序列化

為什麼java中序列化的serialVersionUID總是無意義的?

反序列化

為什麼java中序列化的serialVersionUID總是無意義的?

現在我們舉了一個序列化的例子,沒有指定serialVersionUID,此時程序在編譯的時候就會自動為我們生成一個ID號,整個過程是這樣的:

(1)發送端不指定serialVersionUID,編譯器為我們默認生成,並序列化保存在流中發送到接收端。

(2)接收端把serialVersionUID保存起來,進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地相應實體的serialVersionUID進行比較,如果相同就認為是一致的,可以進行反序列化。也就是說傳過來的ID和本地ID不一致時候就會出現錯誤。

現在驗證一下第二種情況:

為什麼java中序列化的serialVersionUID總是無意義的?

我們再去反序列化的時候,因為JVM會把傳來的字節流中的serialVersionUID與本地相應實體的serialVersionUID進行比較,發現不一致,因此會出現異常錯誤:

為什麼java中序列化的serialVersionUID總是無意義的?

(2)指定serialVersionUID

這個情況就不展示了,不斷你之前添加了多少個字段,或者進行更改,因為serialVersionUID唯一,因此反序列化都不會出現錯誤。

OK,這就是java中這個serialVersionUID的作用,其實就是給這個類添加一個身份ID,進行在序列化之前和之後進行版本的比對。 上面這個其實也是一個面試常問的一個問題,再次湊巧給總結了一下,不過今天的主題不是講這個serialVersionUID的,而是後面的那一串數字為什麼總是無意義的?

二、為什麼總是無意義的ID?

java序列化中的serialVersionUID後面我們通常是1L、或者是xxxL。這些數字有什麼意義呢?為什麼我們總是需要這些無意義的ID。帶著這些問題我們一步一步來揭曉答案。

1、有意義的ID

有一些ID是有意義的,最常見的就是我們的身份證號,一共18位。分別代表著省市縣等等。在通常情況下這個ID在全國內是惟一的。他就像是一個標識符一樣,唯一地代表了我們。

為什麼java中序列化的serialVersionUID總是無意義的?

標識符(identifier)就是一個可以唯一識別一個對象或者物體的名稱,被識別的對象可能是一些想法、物理上可數的對象或者物理上的不可數物質。它的前綴 ID 經常被用來表示身份、鑑定過程或者標識符。

因此唯一性是ID的最大特點。好比是我們的身份證號碼,整個中國你找不出第二個和你一樣號碼的人。現在我們知道了有意義的ID通常情況下是一個標識符,唯一地代表了這個物體。現在我們把目光轉到無意義的ID。

2、無意義的ID

我們的java序列化id、數據庫中的自增主鍵、消息隊列、甚至於我們的TCP通信中都會使用到這個。無意義的真正含義其實是和我們要做的事無關,也就是說這個ID數字不應該和我們的業務邏輯產生聯繫。

大多數業務的主鍵都會使用整數,它的上限一般就是 2^64,如果這些位數都用來表示記錄的 ID,那麼在有生之年基本上是不可能被使用完的,但是一旦我們將業務信息加入 ID,就會讓原本無意義的 ID 變得有意義從而影響它的唯一性。

java序列化的那個例子,你看到serialVersionUID==xxxL,應該想不到這一串數字和這個類有什麼聯繫吧。而且一旦有聯繫就有可能會出現錯誤。那為什麼無意義的ID是有用的呢?我們舉一個例子:在分佈式系統中有一個分佈式的 ID 生成器,Snowflake 算法會為 64 個比特的整數賦予不同的信息:

為什麼java中序列化的serialVersionUID總是無意義的?

假設一臺機器上一個時間單位最多隻能生成 4096 個 ID,一旦超過了這個這個數量就有可能導致 ID 衝突或者亂序,從而失去其唯一性;這個算法中涉及的時間戳、數據中心標識符、機器標識符都沒有辦法解決唯一性的問題,哪怕這三者完全相等,此時仍然需要使用無其他意義的序列號來保證 ID 的唯一。

因此使用無意義 ID 的主要目的就是利用它的唯一性保證對象的標識符不會發生衝突,無意義 ID 的唯一作用就是保證唯一性,這能幫助我們避免業務字段可能存在潛在衝突的可能,這也提示我們想要使用聯合字段構成主鍵時一定要深思熟慮。

3、總結

上面其實說了這麼多,是想讓各位有個稍微全面的瞭解。就像很多時候一句話講完的事,非要BB半天。幾句話總結:

對於有意義的ID,在特定場景下ID數字和業務邏輯有關,比如身份證號和每個人的唯一標識有關。

對於無意義的ID:這個ID數子一旦和業務邏輯產生聯繫,就有重複的可能,而且極其不安全。此時一個無意義的ID就有了唯一性。

不管有沒有意義都是為了進行唯一標識,但是使用的場景不相同。

OK,今天的文章先寫到這。


分享到:


相關文章: