https://www.cnblogs.com/think-in-java/p/5527389.htmlhtml
無心間翻看之間的代碼,發現了一段難以理解的代碼。java
byte[] bs = digest.digest(origin.getBytes(Charset.forName(charsetName))) ; 數組
for (int i = 0; i < bs.length; i++) { app
int c = bs[i] & 0xFF ;jvm
if(c < 16){ ide
sb.append("0"); 加密
} spa
sb.append(Integer.toHexString(c)) ; orm
} htm
return sb.toString() ;
bs是由一段字符串通過MD5加密後,輸出的byte數組。我起初難以理解爲何在接下來的循環中要將bs[i]&oxFF再複製給int類型呢?
bs[i]是8位二進制,0xFF轉化成8位二進制就是11111111,那麼bs[i]&0xFF不是仍是bs[i]自己嗎?有意思嗎?
後來我又寫了一個demo
package jvmProject;
public class Test {
public static void main(String[] args) {
byte[] a = new byte[10];
a[0]= -127;
System.out.println(a[0]);
int c = a[0]&0xff;
System.out.println(c);
}
}
我先打印a[0],在打印a[0]&0xff後的值,原本我想結果應該都是-127.
可是結果然的是出人意料啊!
-127
129
究竟是爲何呢?&0xff反而不對了。
樓主真的是不懂啊,後來往補碼那個方向想了想。
記得在學計算機原理的時候,瞭解到計算機內的存儲都是利用二進制的補碼進行存儲的。
複習一下,原碼反碼補碼這三個概念
對於正數(00000001)原碼來講,首位表示符號位,反碼 補碼都是自己
對於負數(100000001)原碼來講,反碼是對原碼除了符號位以外做取反運算即(111111110),補碼是對反碼做+1運算即(111111111)
概念就這麼簡單。
當將-127賦值給a[0]時候,a[0]做爲一個byte類型,其計算機存儲的補碼是10000001(8位)。
將a[0] 做爲int類型向控制檯輸出的時候,jvm做了一個補位的處理,由於int類型是32位因此補位後的補碼就是1111111111111111111111111 10000001(32位),這個32位二進制補碼錶示的也是-127.
發現沒有,雖然byte->int計算機背後存儲的二進制補碼由10000001(8位)轉化成了1111111111111111111111111 10000001(32位)很顯然這兩個補碼錶示的十進制數字依然是相同的。
可是我作byte->int的轉化 全部時候都只是爲了保持 十進制的一致性嗎?
不必定吧?比如咱們拿到的文件流轉成byte數組,難道咱們關心的是byte數組的十進制的值是多少嗎?咱們關心的是其背後二進制存儲的補碼吧
因此你們應該能猜到爲何byte類型的數字要&0xff再賦值給int類型,其本質緣由就是想保持二進制補碼的一致性。
當byte要轉化爲int的時候,高的24位必然會補1,這樣,其二進制補碼其實已經不一致了,&0xff能夠將高的24位置爲0,低8位保持原樣。這樣作的目的就是爲了保證二進制數據的一致性。
固然拉,保證了二進制數據性的同時,若是二進制被看成byte和int來解讀,其10進制的值必然是不一樣的,由於符號位位置已經發生了變化。
象例2中,int c = a[0]&0xff; a[0]&0xff=1111111111111111111111111 10000001&11111111=000000000000000000000000 10000001 ,這個值算一下就是129,
因此c的輸出的值就是129。有人問爲何上面的式子中a[0]不是8位而是32位,由於當系統檢測到byte可能會轉化成int或者說byte與int類型進行運算的時候,就會將byte的內存空間高位補1(也就是按符號位補位)擴充到32位,再參與運算。上面的0xff實際上是int類型的字面量值,因此能夠說byte與int進行運算。