新聞中心
這個(gè)題目不主要講serialVersionUID作用,而是講后面的那一串?dāng)?shù)字的意義,當(dāng)然也會(huì)對(duì)java的這個(gè)serialVersionUID的作用進(jìn)行一個(gè)講解。這篇文章是我積壓了很久的一篇文章,寫(xiě)了一半,幾個(gè)月了才發(fā)現(xiàn),于是拿出來(lái)好好整理一下。

創(chuàng)新互聯(lián)公司是專業(yè)的馬關(guān)網(wǎng)站建設(shè)公司,馬關(guān)接單;提供做網(wǎng)站、成都網(wǎng)站設(shè)計(jì),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行馬關(guān)網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
一、serialVersionUID的作用
通過(guò)java進(jìn)行網(wǎng)絡(luò)之間的數(shù)據(jù)傳輸是不能直接把對(duì)象進(jìn)行傳的,需要在發(fā)送端把數(shù)據(jù)切分,在接收端對(duì)切分的數(shù)據(jù)進(jìn)行重裝。這種切分和重裝的方式就叫做序列化。下面我們舉一個(gè)例子:
(1)不指定serialVersionUID
首先我們定義一個(gè)User類,繼承Serializable接口
然后序列化
- public static void main(String[] args) throws Exception {
- // 序列化
- User an = new User();
- FileOutputStream fos = new FileOutputStream("user");
- ObjectOutputStream oos = new ObjectOutputStream(fos);
- oos.writeObject(an);
- oos.close();
- }
反序列化
- public static void main(String[] args) throws Exception {
- // 反序列化
- FileInputStream fis = new FileInputStream("user");
- ObjectInputStream ois = new ObjectInputStream(fis);
- User u = (User)ois.readObject();
- System.out.println(u.name+" " + u.age);
- ois.close();
- fis.close();
- }
現(xiàn)在我們舉了一個(gè)序列化的例子,沒(méi)有指定serialVersionUID,此時(shí)程序在編譯的時(shí)候就會(huì)自動(dòng)為我們生成一個(gè)ID號(hào),整個(gè)過(guò)程是這樣的:
(1)發(fā)送端不指定serialVersionUID,編譯器為我們默認(rèn)生成,并序列化保存在流中發(fā)送到接收端。
(2)接收端把serialVersionUID保存起來(lái),進(jìn)行反序列化時(shí),JVM會(huì)把傳來(lái)的字節(jié)流中的serialVersionUID與本地相應(yīng)實(shí)體的serialVersionUID進(jìn)行比較,如果相同就認(rèn)為是一致的,可以進(jìn)行反序列化。也就是說(shuō)傳過(guò)來(lái)的ID和本地ID不一致時(shí)候就會(huì)出現(xiàn)錯(cuò)誤。
現(xiàn)在驗(yàn)證一下第二種情況:
我們?cè)偃シ葱蛄谢臅r(shí)候,因?yàn)镴VM會(huì)把傳來(lái)的字節(jié)流中的serialVersionUID與本地相應(yīng)實(shí)體的serialVersionUID進(jìn)行比較,發(fā)現(xiàn)不一致,因此會(huì)出現(xiàn)異常錯(cuò)誤:
(2)指定serialVersionUID
這個(gè)情況就不展示了,不斷你之前添加了多少個(gè)字段,或者進(jìn)行更改,因?yàn)閟erialVersionUID唯一,因此反序列化都不會(huì)出現(xiàn)錯(cuò)誤。
OK,這就是java中這個(gè)serialVersionUID的作用,其實(shí)就是給這個(gè)類添加一個(gè)身份ID,進(jìn)行在序列化之前和之后進(jìn)行版本的比對(duì)。上面這個(gè)其實(shí)也是一個(gè)面試常問(wèn)的一個(gè)問(wèn)題,再次湊巧給總結(jié)了一下,不過(guò)今天的主題不是講這個(gè)serialVersionUID的,而是后面的那一串?dāng)?shù)字為什么總是無(wú)意義的?
二、為什么總是無(wú)意義的ID?
java序列化中的serialVersionUID后面我們通常是1L、或者是xxxL。這些數(shù)字有什么意義呢?為什么我們總是需要這些無(wú)意義的ID。帶著這些問(wèn)題我們一步一步來(lái)揭曉答案。
1、有意義的ID
有一些ID是有意義的,最常見(jiàn)的就是我們的身份證號(hào),一共18位。分別代表著省市縣等等。在通常情況下這個(gè)ID在全國(guó)內(nèi)是惟一的。他就像是一個(gè)標(biāo)識(shí)符一樣,唯一地代表了我們。
標(biāo)識(shí)符(identifier)就是一個(gè)可以唯一識(shí)別一個(gè)對(duì)象或者物體的名稱,被識(shí)別的對(duì)象可能是一些想法、物理上可數(shù)的對(duì)象或者物理上的不可數(shù)物質(zhì)。它的前綴 ID 經(jīng)常被用來(lái)表示身份、鑒定過(guò)程或者標(biāo)識(shí)符。
因此唯一性是ID的最大特點(diǎn)。好比是我們的身份證號(hào)碼,整個(gè)中國(guó)你找不出第二個(gè)和你一樣號(hào)碼的人?,F(xiàn)在我們知道了有意義的ID通常情況下是一個(gè)標(biāo)識(shí)符,唯一地代表了這個(gè)物體。現(xiàn)在我們把目光轉(zhuǎn)到無(wú)意義的ID。
2、無(wú)意義的ID
我們的java序列化id、數(shù)據(jù)庫(kù)中的自增主鍵、消息隊(duì)列、甚至于我們的TCP通信中都會(huì)使用到這個(gè)。無(wú)意義的真正含義其實(shí)是和我們要做的事無(wú)關(guān),也就是說(shuō)這個(gè)ID數(shù)字不應(yīng)該和我們的業(yè)務(wù)邏輯產(chǎn)生聯(lián)系。
大多數(shù)業(yè)務(wù)的主鍵都會(huì)使用整數(shù),它的上限一般就是 2^64,如果這些位數(shù)都用來(lái)表示記錄的 ID,那么在有生之年基本上是不可能被使用完的,但是一旦我們將業(yè)務(wù)信息加入 ID,就會(huì)讓原本無(wú)意義的 ID 變得有意義從而影響它的唯一性。
java序列化的那個(gè)例子,你看到serialVersionUID==xxxL,應(yīng)該想不到這一串?dāng)?shù)字和這個(gè)類有什么聯(lián)系吧。而且一旦有聯(lián)系就有可能會(huì)出現(xiàn)錯(cuò)誤。那為什么無(wú)意義的ID是有用的呢?我們舉一個(gè)例子:在分布式系統(tǒng)中有一個(gè)分布式的 ID 生成器,Snowflake 算法會(huì)為 64 個(gè)比特的整數(shù)賦予不同的信息:
| 范圍 | 長(zhǎng)度 | 作用 |
|---|---|---|
| 0-0 | 1 | 不使用 |
| 1-41 | 41 | 毫秒級(jí)時(shí)間戳 |
| 42-46 | 5 | 數(shù)據(jù)中心標(biāo)識(shí)符 |
| 47-51 | 5 | 機(jī)器標(biāo)識(shí)符 |
| 52-63 | 12 | 序列號(hào) |
假設(shè)一臺(tái)機(jī)器上一個(gè)時(shí)間單位最多只能生成 4096 個(gè) ID,一旦超過(guò)了這個(gè)這個(gè)數(shù)量就有可能導(dǎo)致 ID 沖突或者亂序,從而失去其唯一性;這個(gè)算法中涉及的時(shí)間戳、數(shù)據(jù)中心標(biāo)識(shí)符、機(jī)器標(biāo)識(shí)符都沒(méi)有辦法解決唯一性的問(wèn)題,哪怕這三者完全相等,此時(shí)仍然需要使用無(wú)其他意義的序列號(hào)來(lái)保證 ID 的唯一。
因此使用無(wú)意義 ID 的主要目的就是利用它的唯一性保證對(duì)象的標(biāo)識(shí)符不會(huì)發(fā)生沖突,無(wú)意義 ID 的唯一作用就是保證唯一性,這能幫助我們避免業(yè)務(wù)字段可能存在潛在沖突的可能,這也提示我們想要使用聯(lián)合字段構(gòu)成主鍵時(shí)一定要深思熟慮。
3、總結(jié)
上面其實(shí)說(shuō)了這么多,是想讓各位有個(gè)稍微全面的了解。就像很多時(shí)候一句話講完的事,非要BB半天。幾句話總結(jié):
對(duì)于有意義的ID,在特定場(chǎng)景下ID數(shù)字和業(yè)務(wù)邏輯有關(guān),比如身份證號(hào)和每個(gè)人的唯一標(biāo)識(shí)有關(guān)。
對(duì)于無(wú)意義的ID:這個(gè)ID數(shù)子一旦和業(yè)務(wù)邏輯產(chǎn)生聯(lián)系,就有重復(fù)的可能,而且極其不安全。此時(shí)一個(gè)無(wú)意義的ID就有了唯一性。
不管有沒(méi)有意義都是為了進(jìn)行唯一標(biāo)識(shí),但是使用的場(chǎng)景不相同。
本文轉(zhuǎn)載自微信公眾號(hào)「愚公要移山」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系愚公要移山公眾號(hào)。
網(wǎng)站題目:為什么Java中序列化的SerialVersionUID總是無(wú)意義的?
本文URL:http://m.5511xx.com/article/dpepspi.html


咨詢
建站咨詢
