Java中byte的符號位

在Java中byte類型是有符號的,而Java中又沒有提供無符號的byte類型,因此在其表示範圍爲-128-127之間。而這樣對於一些I/O處理程序來說需要對考慮符號位問題,通常的做法可能是:
    int unsignedByte = signedByte >=0 ? signedByte : signedByte + 256;

     這裏我們發現,由於byte的符號位的關係,我們不得不採用長度更長的int類型來處理符號位帶來的問題。因此,我們會覺得byte由於要考慮符號位其範圍變小了,所以,我們只好通過int來處理。在這個類型的轉換過程中,任意長度的int類型會截斷其高位的字節來適應byte類型,因爲int類型要比byte類型寬。這也就是爲什麼一個int的127轉換成了byte還是一個127。


    不過,我們考慮另外一種情況,就是當一個int值大過byte表示的數值範圍的時候,這個時候問題就出現了。比如,int的128轉換成一個byte類型會是-128。這是因爲補碼運算的關係造成的。首先,128寫成16進制是0x00000080,當做int到byte的類型轉換的時候,前面的0被截斷形成0x80。在二進制中0x80可以寫成10000000,如果這是一個無符號數哪麼一切正常,但是如果是一個有符號數就會經過補碼運算。對於負數而言,其補碼運算就是反碼(就是1轉換成0並且反正既然)加一。哪麼,10000000的補碼就是01111111加一,即10000000=128(十進制)。因此,byte0x80事實上表示的也

就是-128了。類似的int類型的129就是byte類型的-127,而int類型的130則是byte類型的-126,等等,直到int的255對應爲byte的-1。


     哪麼如果到了256呢?此時,地位的字節被0來填充,簡而言之256就是0x00000100。因此,轉換成byte就是0,這個轉換循環也就是256個。因此,我們根據上述原理,得出如下規律:
byte byteValue=0;   
int temp = intValue % 256;   
if ( intValue < 0) {   
  byteValue =  (byte)(temp < -128 ? 256 + temp : temp);   
}   
else {   
  byteValue =  (byte)(temp > 127 ? temp - 256 : temp);   
}  
上述過程中,我們既可以把有符號的byte轉換成無符號的byte(用int類型存儲),也可以把有符號但可能超出byte範圍的數據轉換成有符號的byte。

在剖析該問題前請看如下代碼
public static String bytes2HexString(byte[] b) {
   String ret = "";
   for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[ i ] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
ret += hex.toUpperCase();
   }
   return ret;
}
上面是將byte[]轉化十六進制的字符串,注意這裏b[ i ] & 0xFF將一個byte和 0xFF進行了與運算,然後使用Integer.toHexString取得了十六進制字符串,可以看出
b[ i ] & 0xFF運算後得出的仍然是個int,那麼爲何要和 0xFF進行與運算呢?直接 Integer.toHexString(b[ i ]);,將byte強轉爲int不行嗎?答案是不行的.

其原因在於:
1.byte的大小爲8bits而int的大小爲32bits
2.java的二進制採用的是補碼形式

問題1:java中沒有實現這種“byte a = 0xB2 --> String b = “B2””轉換的簡單實現需要自己實現。 
答:自己編寫的轉換函數,思路將byte的高低4位分開,分別轉換爲對應的字符然後合成返回的字符串。

java 代碼
  1. public static String byteToString(byte b) {    
  2. byte high, low;    
  3. byte maskHigh = (byte)0xf0;    
  4. byte maskLow = 0x0f;    
  5.   
  6. high = (byte)((b & maskHigh) >> 4);    
  7. low = (byte)(b & maskLow);    
  8.   
  9. StringBuffer buf = new StringBuffer();    
  10. buf.append(findHex(high));    
  11. buf.append(findHex(low));    
  12.   
  13. return buf.toString();    
  14. }    
  15.   
  16. private static char findHex(byte b) {    
  17. int t = new Byte(b).intValue();    
  18. t = t < 0 ? t + 16 : t;    
  19.   
  20. if ((0 <= t) &&(t <= 9)) {    
  21. return (char)(t + '0');    
  22. }    
  23.   
  24. return (char)(t-10+'A');    
  25. }    
  26.   

未解決的疑問在java中不存在類似C中的無符號量,所以如果一個字節超過0x80其對應的整型值即爲負值,但在高位右移4位後還是負值,且與對應的正值相差16,比如0xB2經過右移後的期望值是0x0B(11)但實際值是-5與預期的值相差16(這個16通過多次試驗得出),對此現象爲找到合理的解釋。

問題2:“String a=”B2” --> byte b=0xB2”字符的byte轉換爲byte數據類型 
答:思路通過Integer作爲轉換的中間橋樑

java 代碼
  1. public static int stringToByte(String in, byte[] b) throws Exception {    
  2. if (b.length < in.length() / 2) {    
  3. throw new Exception("byte array too small");    
  4. }    
  5.   
  6. int j=0;    
  7. StringBuffer buf = new StringBuffer(2);    
  8. for (int i=0; i
  9. buf.insert(0, in.charAt(i));    
  10. buf.insert(1, in.charAt(i+1));    
  11. int t = Integer.parseInt(buf.toString(),16);    
  12. System.out.println("byte hex value:" + t);    
  13. b[j] = (byte)t;    
  14. i++;    
  15. buf.delete(0,2);    
  16. }    
  17.   
  18. return j;    
  19. }    
  20.   

問題3:整數(表示範圍限定爲兩個字節unsigned short)通過Integer.byteValue()轉換成byte[2],如果超出一個byte的表示範圍將會截斷高位的值。 
答:思路一個byte能表示的最大整數爲256(超過128爲負值,超過256將被截斷),所以取256的倍數爲byte[0],256的餘數爲byte[1]。

java 代碼
  1. byte[] d = new byte[l+2];        
  2. ….        
  3. buff.put(new Integer(l/256).byteValue());        
  4. buff.put(new Integer(l%256).byteValue());   
發佈了91 篇原創文章 · 獲贊 88 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章