自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

為什么Java中序列化的SerialVersionUID總是無意義的?

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

[[360997]]

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

一、serialVersionUID的作用

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

(1)不指定serialVersionUID

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

 

然后序列化

  1. public static void main(String[] args) throws Exception { 
  2.         // 序列化 
  3.         User an = new User(); 
  4.         FileOutputStream fos = new FileOutputStream("user"); 
  5.         ObjectOutputStream oos = new ObjectOutputStream(fos); 
  6.         oos.writeObject(an); 
  7.         oos.close(); 
  8.     } 

反序列化

  1. public static void main(String[] args) throws Exception { 
  2.         // 反序列化 
  3.         FileInputStream fis = new FileInputStream("user"); 
  4.         ObjectInputStream ois = new ObjectInputStream(fis); 
  5.         User u = (User)ois.readObject(); 
  6.         System.out.println(u.name+"  " + u.age); 
  7.         ois.close(); 
  8.         fis.close(); 
  9.     } 

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

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

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

現(xiàn)在驗證一下第二種情況:

 

我們再去反序列化的時候,因為JVM會把傳來的字節(jié)流中的serialVersionUID與本地相應(yīng)實體的serialVersionUID進(jìn)行比較,發(fā)現(xiàn)不一致,因此會出現(xiàn)異常錯誤:

 

(2)指定serialVersionUID

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

OK,這就是java中這個serialVersionUID的作用,其實就是給這個類添加一個身份ID,進(jìn)行在序列化之前和之后進(jìn)行版本的比對。上面這個其實也是一個面試常問的一個問題,再次湊巧給總結(jié)了一下,不過今天的主題不是講這個serialVersionUID的,而是后面的那一串?dāng)?shù)字為什么總是無意義的?

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

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

1、有意義的ID

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

 

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

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

2、無意義的ID

我們的java序列化id、數(shù)據(jù)庫中的自增主鍵、消息隊列、甚至于我們的TCP通信中都會使用到這個。無意義的真正含義其實是和我們要做的事無關(guān),也就是說這個ID數(shù)字不應(yīng)該和我們的業(yè)務(wù)邏輯產(chǎn)生聯(lián)系。

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

java序列化的那個例子,你看到serialVersionUID==xxxL,應(yīng)該想不到這一串?dāng)?shù)字和這個類有什么聯(lián)系吧。而且一旦有聯(lián)系就有可能會出現(xiàn)錯誤。那為什么無意義的ID是有用的呢?我們舉一個例子:在分布式系統(tǒng)中有一個分布式的 ID 生成器,Snowflake 算法會為 64 個比特的整數(shù)賦予不同的信息:

范圍 長度 作用
0-0 1 不使用
1-41 41 毫秒級時間戳
42-46 5 數(shù)據(jù)中心標(biāo)識符
47-51 5 機(jī)器標(biāo)識符
52-63 12 序列號

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

因此使用無意義 ID 的主要目的就是利用它的唯一性保證對象的標(biāo)識符不會發(fā)生沖突,無意義 ID 的唯一作用就是保證唯一性,這能幫助我們避免業(yè)務(wù)字段可能存在潛在沖突的可能,這也提示我們想要使用聯(lián)合字段構(gòu)成主鍵時一定要深思熟慮。

3、總結(jié)

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

對于有意義的ID,在特定場景下ID數(shù)字和業(yè)務(wù)邏輯有關(guān),比如身份證號和每個人的唯一標(biāo)識有關(guān)。

對于無意義的ID:這個ID數(shù)子一旦和業(yè)務(wù)邏輯產(chǎn)生聯(lián)系,就有重復(fù)的可能,而且極其不安全。此時一個無意義的ID就有了唯一性。

 

不管有沒有意義都是為了進(jìn)行唯一標(biāo)識,但是使用的場景不相同。

本文轉(zhuǎn)載自微信公眾號「愚公要移山」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系愚公要移山公眾號。

 

責(zé)任編輯:武曉燕 來源: 愚公要移山
相關(guān)推薦

2020-07-27 15:24:22

戴爾

2023-03-09 08:23:07

序列化?接口方法

2011-06-01 15:18:43

Serializabl

2023-12-26 07:26:07

Java序列化反序列化機(jī)制

2009-03-26 22:54:33

IBM院士Sun

2015-09-14 09:34:37

Docker本地開發(fā)開發(fā)環(huán)境

2013-04-24 10:04:35

Windows 8.1

2018-03-19 10:20:23

Java序列化反序列化

2018-06-25 17:05:09

區(qū)塊鏈數(shù)字貨幣比特幣

2020-12-24 18:46:11

Java序列化編程語言

2024-09-03 08:17:59

2009-06-14 22:01:27

Java對象序列化反序列化

2011-06-01 15:05:02

序列化反序列化

2020-08-12 08:35:34

華為阿里加班

2024-09-10 08:28:22

2011-06-01 14:26:11

序列化

2023-12-13 13:49:52

Python序列化模塊

2023-06-20 07:48:21

2023-09-12 07:24:07

Java序列化接口

2010-03-19 15:54:21

Java Socket
點贊
收藏

51CTO技術(shù)棧公眾號