簡體   English   中英

為什么在java中改變符號值

[英]Why left shifting in java changing the sign value

我正在研究java。 我想知道為什么java產生這個輸出。 我在這里分享代碼。

public class vvn {

    public static void main(String[] args)
    {
        byte [] arr = new byte[4];
        arr[0] = (byte)157;
        arr[1] = 1;
        arr[2] = 0;
        arr[3] = 0;
        System.out.format("read 0x%x 0x%x 0x%x 0x%x \n",arr[3],arr[2],arr[1],arr[0]);
        int v = (arr[0] | (arr[1] << 8) | (arr[2] << 16) | (arr[3] << 24));
        System.out.format("read 0x%x\n",v);

    }

}

我得到了輸出

read 0x0 0x0 0x1 0x9d 
read 0xffffff9d

我預計輸出應為0x0000019d

您正在從字節(帶符號的8位)轉換為整數(帶符號的32位)。 最重要的位(最左邊的位)保持符號(參見二進制補碼 )。

你的157是二進制的10011101 由於您將此值分配給有符號字節 (java沒有無符號字節),因此實際上是負數, -99

現在,當您從byte轉換為int時,將保留該值。 如果是負數,這意味着將所有位設置為左側以保留簽名。 在您的情況下, 10011101變為11111111 11111111 11111111 10011101

無論如何,在java中使用無符號字節是一場噩夢。 基本上,你需要用0xff(以切斷'左邊的')來掩蓋所有內容,如下所示:

int v = ((arr[0] & 0xff) |
    ((arr[1] & 0xff) << 8) |
    ((arr[2] & 0xff) << 16) |
    ((arr[3] & 0xff) << 24));

美麗,不是嗎?

更新1:此外,您可能對Guava的UnsignedBytes感興趣...

更新2: Java 8 Byte具有toUnsignedInt()和toUnsignedLong()方法。 因此,您的計算成為:

int v = (Byte.toUnsignedInt(arr[0]) |
    (Byte.toUnsignedInt(arr[1]) << 8) |
    (Byte.toUnsignedInt(arr[2]) << 16) |
    (Byte.toUnsignedInt(arr[3]) << 24));

看。 你的表達(arr [1] << 8)| (arr [2] << 16)| (arr [3] << 24)等於Ox100。 所以,你需要額外的Ox9d,十進制是157.不幸的是,字節diapasone是[-128; 127]。 所以,從字節中獲取157是不可能的。 你的a [0]等於-99

因為最左邊的數字是為符號保留的,所以當你向左移動時,符號會在你提交溢出時發生變化。

在Java中,類型byte是從-128到127的有符號值。這意味着(byte)157導致溢出並且實際上等於-99 當您輸出字節的十六進制值時,因為二進制表示-99 (有符號)和157 (無符號)相等(格式轉換%x將該值解釋為無符號值)。

但是,只要在表達式中使用它, byte值就會提升為int 並且-99作為int的十六進制表示形式是0xffffff9d 您可以通過在程序中添加以下行來查看:

System.out.format("0x%x \n", (int)arr[0]);

我相信問題是java中的按位操作是在int上執行所以當你使用時

arr[0] | ...

arr[0]轉換為int 因此,而不是預期的0x9d ,你得到0xffffff9d所以解決你需要的問題& 0xff掩碼,例如

int v = ((arr[0] & 0xff) | ((arr[1] & 0xff) << 8) | ...;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM