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

Java還在糾結(jié)原碼、補(bǔ)碼和反碼?其實(shí)So Easy

開發(fā) 后端
平??磈dk源碼的時(shí)候有很大的感觸,就是基礎(chǔ)真的很重要,那什么是基礎(chǔ)呢?除了java的基本語法之外,最基礎(chǔ)的莫過于原碼,反碼和補(bǔ)碼了以及基本的運(yùn)算了!

 平常看jdk源碼的時(shí)候有很大的感觸,就是基礎(chǔ)真的很重要,那什么是基礎(chǔ)呢?除了java的基本語法之外,最基礎(chǔ)的莫過于原碼,反碼和補(bǔ)碼了以及基本的運(yùn)算了!

[[270844]]

1.原碼、反碼和補(bǔ)碼

大家應(yīng)該都知道,數(shù)據(jù)在計(jì)算機(jī)中是以二進(jìn)制的形式存在的,比如 byte a = 6; byte b = -6

分為兩種情況來說,一種是正數(shù),一種是負(fù)數(shù);對(duì)于正數(shù)6來說,原碼就是0000 0110,反碼和補(bǔ)碼也是這個(gè);而對(duì)于-6來說,原碼就是1000 0110,這是為什么呢?因?yàn)?**位(最左邊的)是表示符號(hào),0表示正數(shù),1表示負(fù)數(shù);

不管是byte,short,int還是其他的數(shù)字,***位都是用來表示符號(hào)的,所以-6的原碼就是1000 0110,負(fù)數(shù)的反碼就是符號(hào)不變,其他的取反,就是1111 1001;負(fù)數(shù)的補(bǔ)碼就是在反碼的基礎(chǔ)上加1就行了,由于是二進(jìn)制的,是逢2進(jìn)1,所以補(bǔ)碼就是:1111 1010,;

注意:計(jì)算機(jī)中的加減運(yùn)算(計(jì)算機(jī)中只有加法,可以通過加法表示減法,就是用過補(bǔ)碼的形式,看下面栗子)指的是補(bǔ)碼之間的運(yùn)算!而且負(fù)數(shù)在計(jì)算機(jī)中是以補(bǔ)碼的形式存在并參與運(yùn)算的,如果要變?yōu)槭M(jìn)制,就首先需要變?yōu)樵a然后才能變?yōu)槭M(jìn)制或其他進(jìn)制的數(shù);

那么0怎么表示呢?我們可以簡(jiǎn)單看看:0 = 6-6 = 6+(-6)= [0000 0110]補(bǔ)+[1111 1010]補(bǔ)=[0000 0000]補(bǔ)=[0000 0000]原,那么有人要問了,補(bǔ)碼1000 0000那又表示多少呢?再看一個(gè)簡(jiǎn)單的-1-127=(-1)

+(-127)= [1000 0001]原+[1111 1111]原 = [1111 1111]補(bǔ)+[1000 0001]補(bǔ) = [1000 0000]補(bǔ)=[0000 0000]原,兩個(gè)對(duì)比一下,如果都使用原碼的話同一個(gè)原碼[0000 0000]原可以表示兩個(gè)數(shù)0和-128,而用補(bǔ)碼的話卻可以一個(gè)補(bǔ)碼對(duì)應(yīng)單獨(dú)的一個(gè)數(shù),很明顯,一個(gè)補(bǔ)碼對(duì)應(yīng)一個(gè)數(shù)更符合我們的需求!!!

補(bǔ)充一下,對(duì)于負(fù)數(shù)來說,原碼和反碼之間相互轉(zhuǎn)化,試著理解著記憶:

原碼------>反碼:符號(hào)位不變,其他位取反 ;比如 [1000 0001]原 = [1111 1110]反

原碼------>補(bǔ)碼:符號(hào)位不變,其他位取反,然后+1;比如 [1000 0001]原 = [1111 1111]補(bǔ)

反碼------->原碼:符號(hào)位不變,其他位取反;比如 [1111 1110]反 = [1000 0001]原

反碼------->補(bǔ)碼:+1 ;比如 [1111 1110]反 = [1111 1111]補(bǔ)

補(bǔ)碼------->原碼:符號(hào)位不變,其他位取反,然后+1;比如 [1111 1111]補(bǔ) = [1000 0001]原

補(bǔ)碼--------->反碼:先變?yōu)樵a,然后變反碼;比如 [1111 1111]補(bǔ) =[1111 1110]反

這些都是基本的東西,只要記住在計(jì)算機(jī)中運(yùn)算的話,都是以補(bǔ)碼的形式,而且這里就會(huì)涉及到一個(gè)過程,畫一個(gè)簡(jiǎn)單的圖,計(jì)算機(jī)中運(yùn)算都是用補(bǔ)碼來進(jìn)行的;而中間的轉(zhuǎn)化過程計(jì)算機(jī)可以十分迅速的轉(zhuǎn)化,這個(gè)就不用我們操心;下面我們就看看那個(gè)運(yùn)算到底包括哪些運(yùn)算。。。

JAVA還在糾結(jié)原碼、補(bǔ)碼和反碼?其實(shí)So Easy

2.基本的運(yùn)算

說起現(xiàn)實(shí)中的運(yùn)算,無非就是四則運(yùn)算,加減乘除,而對(duì)應(yīng)于計(jì)算機(jī)中也有加減乘除,加減已經(jīng)在上面說了,可以用補(bǔ)碼的加法來實(shí)現(xiàn)加減,但是乘除呢?在這里我們就說說最簡(jiǎn)單的乘除法啊,乘以2和除以2這種,如果是乘除其他數(shù)還是比較復(fù)雜的,暫時(shí)我也沒有什么興趣研究,有興趣的小伙伴可以查查計(jì)算機(jī)中乘除法的實(shí)現(xiàn),你會(huì)沉迷其中不可自拔!

以byte類型來舉例,byte類型***位是符號(hào)位,所以范圍是在1111 1111到01111 1111之間,變成十進(jìn)制也就是-127到127,加上0000 0000這個(gè)原碼對(duì)應(yīng)兩個(gè)數(shù)0和-128,所以整個(gè)的范圍就是-128到127;

乘除也是分為兩大塊,正數(shù)和負(fù)數(shù);

2.1 正數(shù)乘2運(yùn)算(左移用<<表示)

我們看看一個(gè)簡(jiǎn)單的數(shù)(這里我正數(shù)也寫一下補(bǔ)碼):byte a = 5; 5的原碼為:[0000 0101]原=[0000 0101]補(bǔ) ;乘以2就等于10,原碼為[0000 1010]原=[0000 1010]補(bǔ)

看看這兩個(gè)補(bǔ)碼有什么關(guān)系?就是將5的補(bǔ)碼最右邊添加一個(gè)0,最左邊去掉一個(gè)0!***是將5的補(bǔ)碼看作一個(gè)整體,這個(gè)整體向左移動(dòng)一位,左邊超過的位數(shù)直接去掉,右邊空的位置添0

JAVA還在糾結(jié)原碼、補(bǔ)碼和反碼?其實(shí)So Easy

這個(gè)時(shí)候會(huì)有一個(gè)問題,假如二進(jìn)制補(bǔ)碼是0100 0000,也就是64,向左移動(dòng)一位,你覺得是多少?答案是-128,按理來說應(yīng)該是正數(shù)的128啊,為什么是負(fù)的呢?記住,這個(gè)移位操作是會(huì)覆蓋符號(hào)位的,往左移動(dòng)一位的補(bǔ)碼是1000 0000,注意,這里千萬不要變成原碼,在***節(jié)中說過了補(bǔ)碼為1000 0000的就是-128(這兩個(gè)補(bǔ)碼一定要注意點(diǎn),很特殊,0000 0000代表十進(jìn)制的0,1000 0000代表十進(jìn)制的-128!千萬不要變成原碼比較,因?yàn)樗麄兊脑a都是0000 0000無法區(qū)分)

public void num() { byte a = 64; byte b = (byte) (a<<1); System.out.println(b);//-128 }

2.2 正數(shù)除2運(yùn)算(右移用>>表示)

既然往左移動(dòng)一位是乘以2,那么往右移動(dòng)一位肯定是除以2了!但是記住一個(gè)規(guī)律,往右移動(dòng)的話,右邊超出來的部分去掉,左邊空出來的位置添加和符號(hào)位相同的數(shù)!(記住了規(guī)律這個(gè)負(fù)數(shù)的右移一樣的)

舉個(gè)例子,65的補(bǔ)碼0100 0001,向右移動(dòng)一位,補(bǔ)碼應(yīng)該是0010 0000,記住,此時(shí)最左邊的0是根據(jù)符號(hào)位是0才添加的0,是正數(shù),右移后的原碼和補(bǔ)碼一樣,那么變成十進(jìn)制應(yīng)該是32,這里可以看出一個(gè)大于0的奇數(shù)右移一位的結(jié)果就是除以2然后向下取整,偶數(shù)的話直接就是除以2了

  1. public void num() { 
  2.  byte a = 64; 
  3.  byte b = (byte) (a<<1); 
  4.  System.out.println(b);//-128 
  5.   
  6.  } 

2.3 負(fù)數(shù)乘2運(yùn)算(<<)

正數(shù)其實(shí)比較容易,但是負(fù)數(shù)的話就稍微麻煩一點(diǎn)!例如-127的補(bǔ)碼是1000 0001,左移一位的補(bǔ)碼0000 0010,由于這個(gè)補(bǔ)碼是正的,所以原碼也是這個(gè),變成十進(jìn)制就是2,有沒有覺得特別有意思,哈哈哈!知道為什么嗎?因?yàn)閎yte的范圍是-128到127啊,只要是超過了這個(gè)范圍的就會(huì)變成你想不到的數(shù)!

再舉個(gè)沒有超過范圍的例子,-6的補(bǔ)碼是1111 1010,左移一位的補(bǔ)碼就是1111 0100,由于是負(fù)的,變成原碼為1000 1100,也就是對(duì)應(yīng)十進(jìn)制的-12,這個(gè)結(jié)果和想象的一樣!

2.4 負(fù)數(shù)除2運(yùn)算(>>)

記住在2.2中說的一句話,向右移動(dòng)的話,最右邊超過的部分直接去掉,左邊空出來的位置填上和符號(hào)位相同的數(shù)!說起來很抽象,舉個(gè)栗子:-6的補(bǔ)碼是1111 1010,往右移動(dòng)一個(gè)位置的補(bǔ)碼就是1111 1101,是負(fù)的,變成原碼就知道對(duì)應(yīng)的十進(jìn)制是多少了。。。。

2.5.無符號(hào)右移(>>>)

本來都說了正負(fù)數(shù)的左移和右移應(yīng)該就說完了,但是呢,還有一個(gè)比較特殊的運(yùn)算方式,就是無符號(hào)右移(注意只有無符號(hào)右移,沒有無符號(hào)左移啊!),簡(jiǎn)單的來說就是不管正數(shù)負(fù)數(shù),只要是右移的話,最右邊超過的部分直接丟掉,左邊空出來的位置都添0就ok了!

好像也沒什么可說的,簡(jiǎn)單舉個(gè)栗子吧!-6的補(bǔ)碼是1111 1010,無符號(hào)右移一位的補(bǔ)碼就是0111 1101,正的,原碼和補(bǔ)碼一樣,所以對(duì)應(yīng)的十進(jìn)制是應(yīng)該是125,然而實(shí)際情況有點(diǎn)問題,代碼如下:

  1. @org.junit.Test 
  2.  public void num() { 
  3.  byte a = -6; 
  4.  byte b = (byte) (a>>>1); 
  5.  System.out.println(b);//-3 
  6.   
  7.  } 

打印的結(jié)果為什么是-3呢?,這里就有一個(gè)小小的細(xì)節(jié)操作,在進(jìn)行右移操作的時(shí)候,首先會(huì)將該byte類型的數(shù)變成int類型的,對(duì)int類型的變?cè)a,然后變補(bǔ)碼,移位操作之后,取后8位變?yōu)閎yte類型,然后變?cè)a,***轉(zhuǎn)十進(jìn)制。。。。是不是賊麻煩!還是以上面的-6為栗子,-6要進(jìn)行無符號(hào)右移,所以-6的原碼應(yīng)該是32位的

  1. 10000000 00000000 00000000 00000110 //原碼 
  2. 11111111 11111111 11111111 11111010//補(bǔ)碼 
  3. 011111111 11111111 11111111 1111101//無符號(hào)右移一位 
  4. 11111101//取后八位,就是byte類型的補(bǔ)碼 
  5. 10000011//byte類型原碼,對(duì)應(yīng)十進(jìn)制是-3  

3.簡(jiǎn)單總結(jié)一下

由于我們是用一個(gè)byte類型的為例,這也是為了方便舉例子,不然用個(gè)int類型的,隨便一個(gè)數(shù)寫出原碼都是一大串,看著都眼花。。。其實(shí)byte類型的移位運(yùn)算弄清楚了,其他的類型一樣的,看了這么多,不知道大家有沒有總結(jié)出來一點(diǎn)規(guī)律,我就說說我的理解吧!

首先,我們要明確當(dāng)前的數(shù)是一個(gè)什么類型,進(jìn)行移位操作之后會(huì)不會(huì)超出這個(gè)類型的范圍,如果超出了,我們是不能直接得出乘以2或者除以2這種簡(jiǎn)單的結(jié)論的,會(huì)得出一個(gè)意想不到的數(shù)字;

然后,如果移位操作之后沒有超過當(dāng)前類型的范圍,那么就大膽的說左移一位是乘以2,右移一位是除以2向下取整吧!!!

再然后,對(duì)于一個(gè)正數(shù),左移一位就是***位去掉,***位添0;右移一位***位添加和符號(hào)位一樣的數(shù),***位去掉;對(duì)于負(fù)數(shù)而言,也是一樣的,就不多說了

***,就是無符號(hào)右移,這里要注意先要變成int類型的二進(jìn)制原碼,變補(bǔ)碼,然后進(jìn)行移位操作,截取后8位為我們需要的byte類型的補(bǔ)碼,再變?cè)a,***就是變成十進(jìn)制的了。。。

4."或"、"與"、"非"、"異或"

請(qǐng)注意“或”、“與”、“非”和java中的||、&&、!別弄混淆了,java中的這幾個(gè)是用來進(jìn)行邏輯判斷的,而我們這里的“或”“與”“異或”這幾個(gè)是用來計(jì)算二進(jìn)制的,完全沒有什么相關(guān),雖然寫法有點(diǎn)類似,“或”用一根豎線表示|,與用一個(gè)&表示,非用~表示,"異或"用^表示,下面就簡(jiǎn)單說說他們的作用:

或:在二進(jìn)制中,兩個(gè)操作數(shù)進(jìn)行或操作,只要有一個(gè)為1,結(jié)果就為1,否則就為0;舉個(gè)例子,-6|3,首先將各自都變?yōu)檠a(bǔ)碼,也就是變?yōu)?1111 1011)|(0000 0011),根據(jù)下圖,***計(jì)算的補(bǔ)碼為1111 1011,變?yōu)樵a為1000 0101,對(duì)應(yīng)十進(jìn)制的-5,所以-6|3的結(jié)果就是-5!很簡(jiǎn)單吧,現(xiàn)在應(yīng)該知道操作數(shù)是什么了吧!

 

JAVA還在糾結(jié)原碼、補(bǔ)碼和反碼?其實(shí)So Easy

 

  1. public void num() { 
  2.  byte a = -6; 
  3.  System.out.println(~a);//5 
  4.   
  5.  } 

與:兩個(gè)操作數(shù)同時(shí)為1,結(jié)果才是1,否則為0;

異或:看這個(gè)名字就知道了,兩個(gè)操作數(shù)不同結(jié)果就是1,否則為0;

非:就是對(duì)自己取反(符號(hào)位也要取反),用法如下,因?yàn)?6的補(bǔ)碼是1111 1010,取反之后的補(bǔ)碼0000 0101,對(duì)應(yīng)十進(jìn)制的5

  1. public void num() { 
  2.  byte a = -6; 
  3.  System.out.println(~a);//5 
  4.   
  5.  } 

5.簡(jiǎn)單練習(xí)

如果把上面的都看懂了,理解了那么下面這個(gè)就很容易了;

直接說一下這個(gè)方法的用處,就是你隨便輸入一個(gè)int類型的數(shù),它都會(huì)給你返回一個(gè)2的次冪數(shù),比如1,2,4,8,16.32.64等這種數(shù)(1等于2的零次冪,也是2的次冪數(shù))

  1. static final int tableSizeFor(int cap) { 
  2.  int n = cap - 1; 
  3.  n |= n >>> 1; 
  4.  n |= n >>> 2; 
  5.  n |= n >>> 4; 
  6.  n |= n >>> 8; 
  7.  n |= n >>> 16; 
  8.  return (n < 0) ? 1 :n + 1; 
  9.  } 

這個(gè)方法其實(shí)很容易,就是將傳進(jìn)去的int類型的cap首先減一,賦值給n,然后n進(jìn)行5次無符號(hào)右移操作,每次右移之后都和n進(jìn)行"或"操作,***判斷n如果小于零,就返回1,否則就返回n+1

我們就比如傳入5,那么n等于4,無符號(hào)右移一位然后與n進(jìn)行“或”操作,由于位數(shù)太多,我就直接寫結(jié)果了:

  1. 00000000 00000000 00000000 00000100//n的二進(jìn)制補(bǔ)碼 
  2. 00000000 00000000 00000000 00000110//無符號(hào)右移一位然后和n進(jìn)行“或”操作 
  3. 00000000 00000000 00000000 00000111//無符號(hào)右移兩位然后和n進(jìn)行“或”操作 
  4. 00000000 00000000 00000000 00000111//無符號(hào)右移四位然后和n進(jìn)行“或”操作 
  5. 00000000 00000000 00000000 00000111//無符號(hào)右移八位然后和n進(jìn)行“或”操作 
  6. 00000000 00000000 00000000 00000111//無符號(hào)右移十六位然后和n進(jìn)行“或”操作  

***右移16位的n結(jié)果應(yīng)該是7,再到return語句,返回的是n+1,也就是返回8,而8就是2^3,滿足前面說的返回一個(gè)2的次冪數(shù);有興趣的可以試試其他的數(shù),返回的結(jié)果肯定是2的次冪數(shù),有沒有覺得這個(gè)算法特別牛逼!簡(jiǎn)直無敵呀!

如果你看懂了這個(gè)方法的話,你可以打開你的Eclipse或者IDEA,用jdk1.8找到一個(gè)叫做HashMap的類,你就可以看到這個(gè)方法(當(dāng)然我把***的return語句稍微變了一點(diǎn)),這個(gè)就是HashMap進(jìn)行擴(kuò)容的一個(gè)方法,所以我們可以知道HashMap初始化以及擴(kuò)容之后的容量,總是2的冪級(jí)數(shù),是不是很容易啊!

當(dāng)然有的時(shí)候面試,面試官會(huì)問你為什么HashMap的容量要設(shè)置為2的冪級(jí)數(shù)啊?這個(gè)問題就有點(diǎn)東西了,首先你可以把這部分算法給他說一下,瑪?shù)?源碼就是這樣寫的啊!你還問我為什么?然后還要說的話,其實(shí)也很容易,還涉及到了一個(gè)“與”操作,看看這個(gè)(n - 1) & hash,hash就是將一個(gè)鍵值對(duì)的key通過hash算法得到的一個(gè)很大的數(shù),而n就是hashmap長(zhǎng)度,也就是2的次冪數(shù),那么(n - 1) & hash代表什么呢?

有興趣的可以玩一下,其實(shí)就是相當(dāng)于hash%n,就是相當(dāng)于對(duì)n取余,這個(gè)余數(shù)肯定是小于n,這樣首先可以保證得到的數(shù)組中的索引不會(huì)超過數(shù)組,而且用這種方式可以保證數(shù)據(jù)是均勻的分布在hashmap中的那個(gè)數(shù)組中,我這里也就是簡(jiǎn)單提了一下,很容易的!

責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2024-04-18 08:51:10

原碼反碼補(bǔ)碼

2021-05-25 05:26:46

原碼反碼補(bǔ)碼

2020-08-13 08:17:50

MQ緩沖秒殺

2010-04-12 11:02:28

Oracle性能

2012-05-18 14:24:57

fedora 17安裝卸載

2012-09-07 09:41:15

Win 8關(guān)機(jī)

2020-12-10 08:21:27

XML映射Mybatis

2021-10-29 11:30:31

補(bǔ)碼二進(jìn)制反碼

2023-04-03 15:04:00

RPCPHP語言

2018-09-05 21:07:06

數(shù)據(jù)管理

2022-08-18 15:38:11

致態(tài)

2019-03-26 11:36:28

網(wǎng)絡(luò)

2022-07-27 08:49:34

接口加密解密

2019-12-23 10:51:40

Python車票搶票

2024-04-16 10:09:42

2022-11-26 00:00:02

2024-11-27 11:44:08

2012-11-19 10:09:25

2021-04-23 10:38:52

Spring BootSpringMVC源碼

2022-05-06 10:42:09

JavaFlowable引擎
點(diǎn)贊
收藏

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