java中oxff什么意思_byte&oxff到底為什么【java中的負數】

本文详细解释了如何修复将字节数组转换为十六进制字符串时遇到的负数问题,涉及Java中的补码表示、符号扩展和类型转换规则。通过实例和规则阐述了`2的补码`编码、负数转十六进制的正确方法,并讨论了多个转义案例和转义规则的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

近日需要一個將字節數組轉換為十六進制字符串輸出的函數,於是開始編碼如下://該代碼存在問題

public static String byteToHex(byte[] bt){

StringBuffer sb = new StringBuffer();

for(int i=0;i

String tmpStr = Integer.toHexString(byte[i]);

if(tmpStr.length()<2)

sb.append("0");

sb.append(tmpStr);

}

return sb.toString().toUpperCase();

}

運行測試,一旦遇到負數總出現未可預料的結果,如參數為{-125,125,115,89}時運行結果為FFFFFF837D7359。

開始從網上查資料做修改,對byte數據進行與運算&oxff再進行轉換,很抓狂到底為什么,再一頓搜索,原來問題出在java整數表示方法及位擴張問題上,在java中使用補碼對整數進行表示。修改后代碼如下://正確代碼

public static String byteToHex(byte[] bt){

StringBuffer sb = new StringBuffer();

for(int i=0;i

int tmp = bt[i]&0xff;

String tmpStr = Integer.toHexString(tmp);

if(tmpStr.length()<2)

sb.append("0");

sb.append(tmpStr);

}

return sb.toString().toUpperCase();

}

對於此問題找到了比較全面的解釋如下:public static void main(String[] args) {

System.out.println(0xffffffff);

}

下面兩行代碼的輸出相同嗎?public static void main(String[] args) {

byte b=-1;

System.out.println((int)(char)b);

System.out.println((int)(char)(b & 0xff));

}

請嘗試在Eclipse中運行上面的兩個代碼片段,如果你對輸出結果感到很驚訝,請繼續往下讀…

正如你所看到的:

第1個代碼片段的運行結果是:-1

第2個代碼片段的運行結果是:65535和255

上面的兩個代碼片段來源於《Java解惑》的第6個小問題“多重轉型”,原題目內容如下:public class Multicast{

public static void main (String[] args){

System.out.println((int)(char)(byte)-1);

}

}

上面的代碼中連續進行了3次類型轉換,最后的結果會回到-1嗎?答案當然是不會,它輸出的結果是65535。下面我為大家整理了相關的基礎知識,相信大家讀完后應該就知道其中的原因了。

一、Java中如何編碼負數?Java采用”2的補碼“(Two's Complement)編碼負數,它是一種數值的編碼方法,要分二步完成:第一步,每一個二進制位都取相反值,0變成1,1變成0。比如,+8的二進制編碼是00001000,取反后就是11110111。第二步,將上一步得到的值加1。11110111就變成11111000。所以,00001000的2的補碼就是11111000。也就是說,-8在計算機(8位機)中就是用11111000表示。關於“2的補碼”的詳細信息,請參考阮一峰的博文《關於2的補碼》,博文地址附在本文的參考部分。

二、什么是符號擴展(Sign Extension)?符號擴展(Sign Extension)用於在數值類型轉換時擴展二進制位的長度,以保證轉換后的數值和原數值的符號(正或負)和大小相同,一般用於較窄的類型(如byte)向較寬的類型(如int)轉換。擴展二進制位長度指的是,在原數值的二進制位左邊補齊若干個符號位(0表示正,1表示負)。

舉例來說,如果用6個bit表示十進制數10,二進制碼為"00 1010",如果將它進行符號擴展為16bits長度,結果是"0000 0000 0000 1010",即在左邊補上10個0(因為10是正數,符號為0),符號擴展前后數值的大小和符號都保持不變;如果用10bits表示十進制數-15,使用“2的補碼”編碼后,二進制碼為"11 1111 0001",如果將它進行符號擴展為16bits,結果是"1111 1111 1111 0001",即在左邊補上6個1(因為-15是負數,符號為1),符號擴展前后數值的大小和符號都保持不變。

三、Java類型轉換規則

Java中整型字面量

Java中int型字面量的書寫方式有以下幾種:

十進制方式,直接書寫十進制數字

八進制方式,格式以0打頭,例如012表示十進制10

十六進制方式,格式為0x打頭,例如0xff表示十進制255

需要注意的是,在Java中012和0xff返回的都是int型數據,即長度是32位。

Java的數值類型轉換規則

這個規則是《Java解惑》總結的:如果最初的數值類型是有符號的,那么就執行符號擴展;如果是char類型,那么不管它要被轉換成什么類型,都執行零擴展。還有另外一條規則也需要記住,如果目標類型的長度小於源類型的長度,則直接截取目標類型的長度。例如將int型轉換成byte型,直接截取int型的右邊8位。

四、解析“多重轉型”問題

連續三次類型轉換的表達式如下:(int)(char)(byte)-1

int(32位) -> byte(8位)

-1是int型的字面量,根據“2的補碼”編碼規則,編碼結果為0xffffffff,即32位全部置1.轉換成byte類型時,直接截取最后8位,所以byte結果為0xff,對應的十進制值是-1.

byte(8位) -> char(16位)

由於byte是有符號類型,所以在轉換成char型(16位)時需要進行符號擴展,即在0xff左邊連續補上8個1(1是0xff的符號位),結果是0xffff。由於char是無符號類型,所以0xffff表示的十進制數是65535。

char(16位) -> int(32位)

由於char是無符號類型,轉換成int型時進行零擴展,即在0xffff左邊連續補上16個0,結果是0x0000ffff,對應的十進制數是65535。

五、幾個轉型的例子

在進行類型轉換時,一定要了解表達式的含義,不能光靠感覺。最好的方法是將你的意圖明確表達出來。

在將一個char型數值c轉型為一個寬度更寬的類型時,並且不希望有符號擴展,可以如下編碼:int i=c & 0xffff;

上文曾提到過,0xffff是int型字面量,所以在進行&操作之前,編譯器會自動將c轉型成int型,即在c的二進制編碼前添加16個0,然后再和0xffff進行&操作,所表達的意圖是強制將前16置0,后16位保持不變。雖然這個操作不是必須的,但是明確表達了不進行符號擴展的意圖。

如果需要符號擴展,則可以如下編碼:int i = (short)c; //Cast causes sign extension

首先將c轉換成short類型,它和char是 等寬度的,並且是有符號類型,再將short類型轉換成int類型時,會自動進行符號擴展,即如果short為負數,則在左邊補上16個1,否則補上16個0.

如果在將一個byte數值b轉型為一個char時,並且不希望有符號擴展,那么必須使用一個位掩碼來限制它:char c = (char)(b & 0xff);

(b & 0xff)的結果是32位的int類型,前24被強制置0,后8位保持不變,然后轉換成char型時,直接截取后16位。這樣不管b是正數還是負數,轉換成char時,都相當於是在左邊補上8個0,即進行零擴展而不是符號擴展。

如果需要符號擴展,則編碼如下:char c = (char)b; //Sign extension is performed

此時為了明確表達需要符號擴展的意圖,注釋是必須的。

六、小結實際上在數值類型轉換時,只有當遇到負數時才會出現問題,根本原因就是Java中的負數不是采用直觀的方式進行編碼,而是采用“2的補碼”方式,這樣的好處是加法和減法操作可以同時使用加法電路完成,但是在開發時卻會遇到很多奇怪的問題,例如(byte)128的結果是-128,即一個大的正數,截斷后卻變成了負數。3.2節中引用了一些轉型規則,應用這些規則可以很容地解決常見的轉型問題。

七、參考引用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值