爲了更好的讀源碼,你必須搞定這些java基礎知識!(位運算,進制轉換和原碼,反碼和補碼)

不知道上一篇文章看的怎麼樣了:害怕面試被問HashMap?這一篇就搞定了!
在這篇文章中,我比較詳細的分析了爲什麼HashMap的初始化容量是16以及爲什麼容量的大小要是2的整數次冪!

不知道你看懂了沒,如果你看的懵懵懂懂的話,我猜你對以下基礎知識一定不那麼熟悉:

  1. java中的位運算
  2. 進制之間的轉換
  3. 原碼,反碼和補碼

怎麼樣,對這些基礎知識掌握的如何,這些可以說都是大學時候學的計算機基礎了,不過,我知道你當時肯定沒學會,即使學會了也忘得差不多了。

其實吧,這些基礎知識真的超級重要,你看,現在閱讀源碼的時候因爲這些基礎知識不過關而遇到坎了吧。

別擔心,今天咱們一起越過這道坎!

先從進制轉換開始

對於進制轉換這個啊,說來慚愧,我之前學過不止一次,曾經有一次還花了很長時間,做筆記,畫圖,弄了滿滿的一張A4紙,當時覺得對進制轉換這塊完全OK了,以後再也不怕進制轉換了。

可是嘞後來讀源碼的時候遇到進制轉換的時候還是覺得不知所措,發現之前學的都忘得差不多了,唉。

所以啊,對於學習,我們可不能一味的向前學習新知識,對於之前的知識也要經常回顧,溫故而知新,可以爲師矣嘛

好啦,咱們這次再來一起學習下進制轉換吧!

對於進制轉換啊,其實我們的重點主要放在與十進制之間的各種轉換即可,因爲這纔是我們平常使用頻率比較高的,所以要優先熟練的掌握這些。

啥是二進制

十進制我們再熟悉不過了,那啥是二進制嘞,簡單來說,二進制就是用0和1來表示的數值,在十進制中逢十進一,借一當十,而二進制呢?那就是逢二進一,借一當二,這個好懂,但是這裏我要說些概念。

什麼嘞?後面我們要說到原碼,反碼和補碼,這裏先說下,它們都是二進制數,也就是都是由0和1表示的,單是可能具體的數值不一樣。

我們要知道,對於計算機而言,它只認識0和1,所以對於數據在計算機中的存儲都是以二進制的形式來存儲的,好了,先有這個概念。

十進制與二進制之間的一個規律

先來看一個圖:

在這裏插入圖片描述
不知道你看出來什麼沒,主要看標紅的,前面說過了,二進制就是逢二進一,那麼上圖中標紅的二進制是不是都是產生進位的數值,啥意思嘞,比如二進制11,並沒有產生進位,如果要產生進位,那就要再加一,然後就會產生進位得100,你看是不是?

再看進位產生的二進制對應的十進制是不是這些數值:

2,4,8,16……

那麼你看這些產生進位的二進制數值有什麼特點,是不是最高位(最左邊)是不是都是1,其他都是0,所以這裏就有個規律:

十進制下的2的整數次冪的數的二進制的高位都是1,其他全是0,然後看是2的幾次冪,是幾就有幾個零

好吧,我相信這裏沒什麼難理解的!

ps:看到這裏你是不是更容易理解爲什麼HashMap的容量要是2的整數次冪了呢?

二進制轉十進制

那麼二進制的數據怎麼轉換成十進制呢?我們看十進制的11從右往左是不是依次代表1個1,1個10,加起來也就是11.

那麼來看二進制1011怎麼表示,看下面的:

二進制的數從右向左各個位表示十進制的含義:

第一個1表示:1的個數(有1個1)
第二個1表示:2的個數(有1個2)
第三個0表示:4的個數(有0個4)
第四個1表示:8的個數(有1個8)

爲什麼是1(默認右邊第一位開始),2,4,8呢?注意上面說的那個規律,所以上面的加起來就是1+2+0+8等於11。

怎麼樣?二進制轉十進制是不是比較簡單,其實後面還有個公式,等下再說,我們繼續往下看

十進制轉二進制

知道嗎?這裏有個通用的方法那就是:除以2,餘數逆序排列,看個例子吧:

在這裏插入圖片描述
也就是說十進制轉換成二進制的話,那就用十進制的數除以2,然後取餘數之後將餘數逆序排列就是對應的二進制數了,怎麼樣是不是更簡單,我們接着往下看

十進制與其他進制之間的轉換

我們之前就說過,對於進制轉換我們重點關注的就是與十進制之間的轉換,我們上面介紹了二進制和十進制之間的互相轉換,那麼還有八進制和十六進制,它們與十進制之間的轉換又是怎樣呢?

這裏首先記住十進制轉換其他進制的通用方法:

“除基數B取餘,逆序排列”方法可以將十進制數轉換爲任意進制數。

那麼這個基數B是啥呢?比如十進制轉換成二進制,那麼這個基數B就是2,知道了吧!

那麼其他進制轉換成十進制怎麼整嘞?記住這個公式:
在這裏插入圖片描述
這個公式可以概括爲:“按權展開”—其他進制轉換爲十進制(B表示各進制的基數,n表示位數)

舉個例子,比如之前1011這個二進制轉換成十進制就可以這樣:
在這裏插入圖片描述
就是這樣的啦,至於其他的什麼八進制和十六進制之間的互相轉換什麼的,不怎麼常用,感興趣的自行了解,對了,我平常都是直接搜索在線進制轉換的😂

進攻位運算

瞭解了進制轉換,尤其是十進制和二進制之間的轉換之後我們就可以開始學習java中的位運算了,因爲位運算實際上都是對二進制進行操作的,接下來我將逐步分析java中常見的位運算。

左移 <<

舉個栗子,5 << 2 將5左移2 結果爲20 爲啥?注意是對二進制進行的操作,來看:

首先會將5轉爲二進制表示形式(java中,整數默認就是int類型,也就是32位):

在這裏插入圖片描述
怎麼去理解,首先在Java中,整數默認就是int類型,也就是佔4個字節32位,你就可以想成這樣

0000 0000 0000 0000 0000 0000 0000 0000

這就是32位,但是每位上都是0,這是一個標準,用於後面的比較,比如5的二進制是

0000 0000 0000 0000 0000 0000 0000 0101

然後把它與標準的進行對比,也就是這樣:

在這裏插入圖片描述
這時候的區別就在後四位,然後將5左移(<<)2,也就是5的二進制以標準爲參考整體左移2位,也就是這樣:

在這裏插入圖片描述
這樣一來,就產生了錯位,看圖:
在這裏插入圖片描述
不過這時候看着總是有點彆扭,應該都是四位四位的在一塊吧,所以從低位開始,四位一組,就成了這樣
0000 0000 0000 0000 0000 0000 0001 0100

換算成十進制就是20了 這就是5 << 2得到結果的由來。

右移 >>

還是先將5轉爲2進製表示形式:
0000 0000 0000 0000 0000 0000 0000 0101 然後右移2位,高位補0:
0000 0000 0000 0000 0000 0000 0000 0001

看圖:

在這裏插入圖片描述
仔細看圖分析分析😃

無符號右移 >>>

先記住這句話:正數右移,高位補0,負數右移,高位補1,負數無符號右移,高位補0 正數無符號右移 ,高位補0 正數換算成二進制後的最高位爲0,負數的二進制最高位爲1

接下來依然是看例子,在此之前我看過好多別人寫的,發現好多都喜歡用5舉例子你知道爲啥嗎😂

5換算成二進制是: 0000 0000 0000 0000 0000 0000 0000 0101

5右移3位後結果爲0,0的二進制爲: 0000 0000 0000 0000 0000 0000 0000 0000 // (這裏高位補0)

-5換算成二進制是: 1111 1111 1111 1111 1111 1111 1111 1011

-5右移3位後結果爲-1,-1的二進制爲: 1111 1111 1111 1111 1111 1111 1111 1111 // (高位補1)

-5無符號右移3位後的結果 536870911 換算成二進制: 0001 1111 1111 1111 1111 1111 1111 1111 // (高位補0)

這裏需要注意了:以上說的都是右移的情況,如果是左移,無論是正數還是負數,低位都是用0補

時間關係,就不贅述了。

位與 &

其實核心都是二進制,所以掌握好進制轉換是關鍵,看看位與 &是怎麼計算的:

在這裏插入圖片描述
這裏要看兩個操作數的二進制的各個位的對應情況,總結起來也就是:

有0則0,否則爲1

什麼意思呢?我們舉一個例子來看看

在這裏插入圖片描述
我們猜這個結果是什麼,答案是

在這裏插入圖片描述
注意這裏可不是6除以3,它是這樣計算的,首先6和3都要轉成二進制,6的二進制是110,3的二進制是11也就是011,那麼這樣運算

在這裏插入圖片描述
我相信看圖就能明白的,而二進制的010就是2啦,這就是位與的操作,對於或和亦或其實同樣道理,我們繼續來看:

位或 |

規則就是:有1則1

看例子:

在這裏插入圖片描述

位異或 ^

規則是:相同則0,不同則1

看例子:

在這裏插入圖片描述

有點難懂的位非 ~

這是網站隨便找的一個例子,你看看,求~5,得-6,爲啥?

在這裏插入圖片描述
它這裏的規則是:操作數的第n位爲1,那麼結果的第n位爲0,反之。

不知道你懂嗎?有這麼一個解釋:

6的二進制數爲: 0000 0000 0000 0000 0000 0000 0000 0110 然後6的二進制反碼爲: 1111 1111 1111 1111 1111 1111 1111 1001 將反碼+1得到-6的補碼二進制數:1111 1111 1111 1111 1111 1111 1111 1010

所以這裏就牽涉到原碼,反碼和補碼了,另外還有個重點的點就是:

負數在計算機中是以補碼的形式存在的

好了,我們趕緊來看看什麼是原碼,反碼和補碼吧!

最後攻克原碼,反碼和補碼

這是非常重要的概念,需要熟練掌握,要記得。開始之前,先上一個重要的結論:

數據在計算機中的存儲是二進制的形式,二進制簡單來說就是0和1組合的,無論原碼,反碼還是補碼,都是二進制的形式

其次我們要注意的點就是正數和負數的原碼,反碼和補碼,是有區別的。

原碼

什麼是原碼嘞?

對於正數來說,我們把它的絕對值轉換成的二進制數叫做正數的原碼,對於負數來說我們把它的絕對值轉換成的二進制數,然後最高位補1,稱爲原碼。看看,還是有區別的。

比如 :

00000000 00000000 00000000 00000101 是 5的 原碼。
10000000 00000000 00000000 00000101 是 -5的 原碼。

這裏有個點就是最高位是0代表正數,是1代表負數。

正數和負數在計算機中怎麼表示的

接下來就是在計算機中的表示:

對於正數:原碼,反碼和補碼都是一樣的,所以在計算機中怎麼說都一樣,反正就是本身轉換成二進制的結果,可以說原碼,也可以說補碼,因爲都是一樣的

對於負數:原碼,反碼和補碼是不一樣的,在計算機中***負數是以補碼的形式存在的***

所以說,重點聚焦在負數上,看它的反碼和補碼是怎麼表示的

反碼

那反碼是啥嘞?

負數的反碼爲對該數的原碼除符號位外各位取反[每一位取反(除符號位)]。

這裏有個符號位,啥?還記得剛剛說的嗎?

最高位是0代表正數,是1代表負數。

也就是最左邊的那一位。

取反操作指:原爲1,得0;原爲0,得1。(1變0; 0變1)

比如:

正數00000000 00000000 00000000 00000101 的反碼還是
00000000 00000000 00000000 00000101

負數10000000 00000000 00000000 00000101 的反碼則是
11111111 11111111 11111111 11111010

另外啊反碼是相互的,因此也可稱:
10000000 00000000 00000000 00000101 和 11111111 11111111 11111111 11111010互爲反碼。

不過這裏有個問題,那就是+0和-0,什麼意思呢?

原碼和反碼在表示數的時候的有點尷尬啊,比如表示零的時候,同樣都是0,但是原碼就有兩種表示法:

 [-0]原=10000000

 [+0]原=00000000

反碼也有兩種表示法:

 [+0]反=00000000

 [- 0]反=11111111

這就有點難受啊,不都是0嗎,於是乎,就出了補碼

補碼

那啥又是補碼嘞?

負數的補碼爲對該數的原碼除符號位外各位取反,然後在最後一位加1

比如:10000000 00000000 00000000 00000101 的反碼是:11111111 11111111 11111111 11111010

那麼,補碼爲:
11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011

這裏有兩點需要注意:
1、從補碼求原碼的方法跟原碼求補碼是一樣的 ,也可以通過完全逆運算來做,先減一,再取反。
2、補碼卻規定0沒有正負之分

第二個啥意思呢,也就是說對於0的表示,補碼只有一種[-0]補=00000000。感覺這樣就正常多了。

總結一下

原碼錶示法規定:用符號位(最左邊)和數值表示帶符號數,正數的符號位用“0”表示,負數的符號位用“1”表示,數值部分用二進制形式表示。

反碼錶示法規定:正數的反碼與原碼相同,負數的反碼爲對該數的原碼除符號位外各位取反。

補碼錶示法規定:正數的補碼與原碼相同,負數的補碼爲對該數的原碼除符號位外各位取反,然後在最後一位加1.

正零和負零的補碼相同,[+0]補=[-0]補=0000 0000B

簡單說說

其實你看,這些基礎知識仔細研究起來,還是有一定難度的,覺得亂巴巴的,怪不得上大學的時候聽不懂呢😂,而且這三個知識點貌似經常一起運用,所以對於這三點基礎,還是有必要花時間琢磨一番的。

好啦,就到這了,歡迎大家一起討論!

感謝閱讀

大學的時候選擇了自學Java,工作了發現吃了計算機基礎不好的虧,學歷不行這是沒辦法的事,只能後天彌補,於是在編碼之外開啓了自己的逆襲之路,不斷的學習Java核心知識,深入的研習計算機基礎知識,所有心得全部書寫成文,整理成有目錄的PDF,持續原創,PDF在公衆號持續更新,如果你也不甘平庸,那就與我一起在編碼之外,不斷成長吧!

其實這裏不僅有技術,更有那些技術之外的東西,比如,如何做一個精緻的程序員,而不是“屌絲”,程序員本身就是高貴的一種存在啊,難道不是嗎?

非常歡迎你的加入,未來的日子,編碼之外,有你有我,一起做一個人不傻,錢很多,活得久的快樂的程序員吧!

回覆關鍵字“PDF”,獲取技術文章合集,已整理好,帶有目錄,歡迎一起交流技術!

另外回覆“慶哥”,看慶哥給你準備的驚喜大禮包,只給首次關注的你哦!

任何問題,可以加慶哥微信:H653836923,另外,我有個交流羣,我會***不定期在羣裏分享學習資源,不定時福利***,感興趣的可以說下我邀請你!

對了,如果你是個Java小白的話,也可以加我微信,我相信你在學習的過程中一定遇到不少問題,或許我可以幫助你,畢竟我也是過來人了!

在這裏插入圖片描述

感謝各位大大的閱讀🥰

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章