Java中byte轉int類型為什么要&0xFF?
今天查看代碼,翻到MD5加密代碼,如下:
public String getMD5(String source) throws Exception {
StringBuilder sb = new StringBuilder();
byte[] output = MessageDigest.getInstance("MD5").digest(source.getBytes("utf-8"));
for (int i = 0; i < output.length; i++) {
int c = output[i] & 0xFF;
if (c < 16) {
sb.append("0");
}
sb.append(Integer.toHexString(c));
}
return sb.toString();
}
int c = output[i] & 0xFF;
if (c < 16) {
sb.append("0");
}
sb.append(Integer.toHexString(c));
}
return sb.toString();
}
為什么要&0xFF ?
各種查資料,了解到,計算機中存儲都是利用二進制的補碼存儲的,存儲數據機制:正數存儲的二進制原碼,負數存儲的是二進制的補碼。 補碼是負數的絕對值反碼加1。
計算機為什么用補碼存儲數據,當我們明白這個問題后,就可以去理解另一個衍生問題——數據溢出。
首先我們看一段數據溢出的Java代碼:
/*char是無符號數,16位存儲,表示范圍是0~2^16-1(即0~65535)*/
char ch = Character.MAX_VALUE; // ch為65535
ch += (char) 1; // 加1后,引起數據溢出,則ch為0
/*int是有符號數,32位存儲,表示范圍是-2^31~2^31-1(即-2147483648~2147483647)*/
int i = Integer.MAX_VALUE; // i為2147483647
i += 1; // 加1后,引起數據溢出,則i為-2147483648
為什么要使用原碼,反碼,補碼 ?
【加法器】計算機只有加法器沒有減法器(計算機只能識別0和1,也就是高點平和低電平,最底層的運算就是0和1的各種數學運算,也就是二進制運算,又因為組成最基本的輸入輸出的邏輯門實現二進制加法最簡單,所以所有的數學運算都是建立在加法基礎上再通添加各種邏輯門來改進的),兩個數的減法運算會被計算機轉換為加法運算。目的:為了簡化計算機基本運算電路,使加減法都只需要用過加法電路實現,也就是讓減去一個整數或加上一個負數這樣的運算可以用加上一個整數來代替。于是改變負數存儲的形式,存儲成一種可以直接當成正數來相加的形式,這種形式就是補碼。
【模數】模數從物理意義上講是某種計量器的容量。經常舉的一個例子就是鐘表,其模數是12,即每到12就重新從0開始,數學上叫取模或者求余(mod)。java中用%表示求余,例如 14 % 12 = 2。如果此時的正確時間為6點,而你的手表指向的是8點,要把表對準,有兩種方法:一是把表逆時針撥兩小時;二是把表順時針撥10小時。
即8-2=6,(8+10)%12 =6
也就是說在此模數系統里面有8-2=8+10
這是因為2跟10對模數12互為補數。因此有以下結論:在模數系統,A-B或A+(-B)等價于A+[B補],
即8-2或8+(-2)=8+10
我們把10叫做-2在模12下的補碼。我們把補碼表示法(two's complement representation)所表示的四位存儲單
元,按照從0000到1111遞增,均勻分布在時鐘的表盤上。如下圖所示:
順時針方向為加法,逆時針方向為減法
模為2^n:在1111處順時針撥一格,就到了0000。用數學的方式,即1111+1=10000,進位舍棄則結果為0000。那么四位存儲的模就是10000(2^4),這樣用補碼來表示負數就可以將加減法統一成加法來運算,簡化了運算的復雜的程度。
減法轉換為加法:3-1=3+(-1)=0011+1111=0010,到這里有人就有疑問了,0011+1111明明等于10010,怎么會是0010呢?還記得之前提過的最高位進位舍棄嘛,因此對于4位存儲來說,進位舍棄就是0010=2。
數據溢出:當0111(7)加1時,按照我們人的思維來說,應該結果為8,但是對于機器來說則不是,因為0111(7)是四位存儲所能表示的最大符號數,所以它是無法表示01000(8)的,這個時候我們就說數據溢出了。機器的思考方式顯然和我們人腦不一樣,機器按照上面環形圖的方式,由于0111(7)加1時順時針造成的數據溢出,那么我們可以把機器的操作想象成在0111(7)處順時針撥了一格,我們再去對照下環形圖發現這個時候指向了1000(-8)。這個過程想象成撥時針就OK了,對于1000(-8)減1也是同樣的道理。
至此,我們完全可以總結一下:
1、計算機只有加法器沒有減法器,兩個數的減法運算會被計算機轉換為加法運算,而補碼正好能夠解決減法轉換為加法的問題。
2、防止機器發生零重碼,同時解決了原碼和反碼不能表示-8的問題,這樣極大的簡化了計算機的硬件設計。
3、以循環的方式解決數據溢出的問題
現在我們回歸到正題:
1byte = 1字節 = 8bit ,1int = 4字節 = 32bit
比如-12,[0000 1100]原 ,[1111 0011]反 ,[1111 0100]補碼
byte-->int,就是8位變成32位
系統檢測到byte轉int進行運算時,按符號位補位,高位全部補1: 1111 1111 1111 1111 1111 1111 1111 0100
0xFF的二進制表示:1111 1111 ,高位全部補0: 0000 0000 0000 0000 0000 0000 1111 1111
-12的補碼與0xFF進行與(&)操作最后就是: 0000 0000 0000 0000 0000 0000 1111 0100(十進制是244)
當從數字類型擴展到較寬的類型時,補零擴展還是補符號位擴展。由于Java只有有符號數,當byte擴展到short, int時,即正數都一樣,因為符號位是0,所以無論如何都是補零擴展,但負數補零擴展和按符號位擴展結果完全不同。
byte[] a = new byte[10];
a[0]= -127;
int c = a[0]&0xff;
補符號數,原數值不變。
原碼:1111 1111 補碼:1000 0001 轉成int類型,高位補1: 1111 1111 1111 1111 1111 1111 1000 0001 這個32位二進制補碼表示的也是-127,顯然這個兩個補碼表示的十進制數字依然是相同。
補零時,相當于把有符號數看成無符號數。比如-127 = 0x81,看成無符號數就是129
原碼:1111 1111 補碼:1000 0001 轉成int類型,高位補0 : 0000 0000 0000 0000 0000 0000 1000 0001 這個32位二進制補碼表示的是129
也就是說,byte轉int類型時,自動轉型是按符號位擴展的,這樣能保證十進制的數值不會變,而&0xFF是補0擴展,這樣能保證二進制存儲的一致性,但是十進制數值已經發生變化了。而正數可以說是既按符號位擴展,又是補0擴展,所以在二進制存儲和十進制數值上都能保證一致。
參考:
https://www.jianshu.com/p/63cc96758d20
http://www.cnblogs.com/think-in-java/p/5527389.html
https://blog.csdn.net/xmc281141947/article/details/74740061
智能推薦
在WordPress中安裝AMP
您將要創造的 什么是AMP? 去年10月, Google宣布AMP作為一項開源計劃,旨在提供更快的移動網絡瀏覽。 如TechCrunch所述 ,許多人將AMP視為Google試圖與Facebook的Instant Articles和移動應用程序更好地競爭的原因,后者越來越提供更快,更簡化的瀏覽。 我傾向于同意。 使用AMP優化的頁面將顯示在Google搜索結果頂部的移動瀏覽輪播中,從而將傳統HTM...
Java 注解入門實例 && 注解傳參
概念:java提供了一種原程序中的元素關聯任何信息和任何元數據的途徑和方法 JDK內置系統注解: @Override 用于修飾此方法覆蓋了父類的方法; @Deprecated 用于修飾已經過時的方法; @Suppvisewarnings 用于通知java編譯器禁止特定的編譯警告。 注解按照運行機制劃分 源碼注解:...
【C++】C++中的&amp;amp;(引用)的簡單理解
本文通過三方面來理解指針 我們知道在C語言中函數的傳參有兩種方式: 1.傳值 2.傳址 雖然這兩種方式都可以實現函數傳參但是卻各自有著自己的優缺點: 傳值:無法改變形參的值 傳址:不是很形象而且不安全 所以在升級版C++中為了解決這種問題就使用了引用& 一.什么是變量的引用??? 1.概念:引用...
HttpServletRequest&amp;&amp;HttpServletResponse參數的接收和響應
一、請求頭信息: 二、獲取前臺傳值: 1、表單的action請求(id用于js,class用于css,name用于后臺): (1、)req.getParameter(arg)方法,參數為name值。例: (2、)req.getParameterNames()獲取所有的name值,然后再利用上面(1、)中的方法獲取value值。例: (3、)req.getParameterValues(arg);用...
猜你喜歡
Google Amp學習筆記
學習源網址:https://amp.dev/zh_cn/documentation/courses/ 原文是英文版,且比較長。 筆記中簡化了一些,記錄我們常用的組件以及一些要點。 關于 AMP 加速的原因 1、Inline 的 CSS 所有的CSS都只能Inline;在本頁內的css不能>75k 2、禁用了大部分的JS 在AMP模式下是不能運行JavaScript,也是禁止運行JavaScd...
單片機上內存管理(重定義malloc &amp;amp;amp; free)de實現
在單片機上經常會需要用到像標準c庫中的內存分配,可是單片機并沒有內存管理機制,如果直接調用庫函數(malloc,free...),會導致內存碎片越用越多,很容易使系統崩潰掉,這里分享一個自己寫的適用于單片機的內存分配方法,具備輕量級的內存管理能力,有效減少內存碎片,提高單片機系統工作穩定性。 如下圖,heap_start開始的地方,是我們存放用戶...
Google AMP 知識分享
AMP 是什么 AMP,全稱是 Accelerated Mobile Pages, 是 Google 推出的開源前端框架。AMP 最明顯的特征就是 性能,被稱為目前 WEB 屆最快的框架毫不夸張。 Google 對 AMP 的性能進行了極致的優化,比如 JS 和網頁數據放在緩存( 具體可看這篇文章:AMP 如何提升性能)。 是否有必要做 AMP 當然有必要做了。理由有 2 個:首先,是快...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...