Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/384.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用|=将字节打包为长字符串会产生意外的结果_Java - Fatal编程技术网

Java 使用|=将字节打包为长字符串会产生意外的结果

Java 使用|=将字节打包为长字符串会产生意外的结果,java,Java,我试图将byte[]数据连接到一个长变量中。但是由于某些原因,代码并没有像我预期的那样工作 我有一个字节数组,它的最大大小是8个字节,是64位,与长变量的大小相同,所以我尝试将这个数组连接到长变量中 public static void main(String[] args) { // TODO Auto-generated method stub byte[] data = new byte[]{ (byte)0xD4,(byte)0x11,(byte

我试图将byte[]数据连接到一个长变量中。但是由于某些原因,代码并没有像我预期的那样工作

我有一个字节数组,它的最大大小是8个字节,是64位,与长变量的大小相同,所以我尝试将这个数组连接到长变量中

public static void main(String[] args) {
    // TODO Auto-generated method stub

    byte[] data = new byte[]{
            (byte)0xD4,(byte)0x11,(byte)0x92,(byte)0x55,(byte)0xBC,(byte)0xF9
            };

    Long l = 0l;

    for (int i =0; i<6; i++){
        l |= data[i];           
        l <<=8;
        String lon = String.format("%064d", new BigInteger(Long.toBinaryString((long)l)));
        System.out.println(lon);
    }




}
publicstaticvoidmain(字符串[]args){
//TODO自动生成的方法存根
字节[]数据=新字节[]{
(字节)0xD4,(字节)0x11,(字节)0x92,(字节)0x55,(字节)0xBC,(字节)0xF9
};
长l=0l;

对于Java中的(int i=0;i
byte
是有符号的,当您执行
long |=byte
时,
byte
的值被提升,符号位被扩展,如果
byte
是负值,则基本上将所有较高的位设置为1

您可以这样做:

 l |= (data[i] & 255)
将其强制为
int
并在升级为
long
之前终止该符号


细节 先决条件:如果“符号位”一词对您没有意义,那么您必须先阅读。我不会在这里解释它

考虑:

byte b = (byte)0xB5;
long n = 0l;

n |= b; // analogous to your l |= data[i]
请注意,
n |=b
完全等同于
n=n | b
(),因此我们将研究它

因此首先必须计算
n | b
,但是,
n
b
是不同的类型

根据:

当运算符&、^或|的两个操作数都是可转换为基元整数类型(§5.1.8)的类型时,首先对操作数(§5.6.2)执行二进制数字提升

这两个操作数都可转换为基元整数类型,因此我们将参考以了解接下来会发生什么。此处的相关规则如下:

  • 加宽基元转换(§5.1.2)用于转换以下规则指定的一个或两个操作数:

    • 否则,如果任一操作数的类型为
      long
      ,则另一个操作数将转换为
      long
  • 好的,
    n
    long
    ,因此根据此
    b
    现在必须使用中指定的规则转换为
    long
    。相关规则有:

    将带符号整数值扩大转换为整数类型T simply sign扩展了整数值的两个补码表示形式,以填充更广泛的格式

    byte
    是一个有符号整数值,它被转换成一个
    long
    ,因此根据这一点,符号位(最高位)被简单地扩展到左侧以填充空间。这就是我们的示例中所发生的情况(想象一下这里的64位我只是在节省空间):

    因此,
    n | b
    的计算结果是
    0xffffffffffb5
    ,而不是
    0x00000000000000B5
    。也就是说,当符号位被扩展并且OR操作被应用时,所有这些
    1
    基本上覆盖了之前输入的字节中的所有位,最终结果是incorrect

    这都是
    byte
    被签名的结果,Java需要在执行计算之前将
    long | byte
    转换为
    long | long

    如果您不清楚此处发生的隐式转换,以下是显式转换:

    n = n | (long)b;
    
    n = n | (long)((int)b & 255);
    

    解决方法的详细信息 现在考虑“解决办法”:

    因此,我们首先评估
    b&255

    因此,我们可以看到,文本
    255
    的类型是
    int

    这就给我们留下了
    byte&int
    。尽管我们调用的案例与上面的略有不同,但规则大致相同:

    否则,两个操作数都将转换为类型
    int

    因此,根据这些规则,必须首先将
    byte
    转换为
    int
    。因此在这种情况下,我们有:

    (byte)0xB5                                10110101
    promote to int    11111111111111111111111110110101  (sign extended)
    255               00000000000000000000000011111111
    &                 00000000000000000000000010110101
    
    结果是一个
    int
    ,它是有符号的,但是正如你所看到的,现在它是一个正数,它的符号位是0

    然后下一步是计算刚才转换的字节
    n
    。因此,根据上述规则,新的
    int
    被加宽为
    long
    ,符号位扩展,但这次:

    b & 255                    00000000000000000000000010110101
    convert to long  000 ... 0000000000000000000000000010110101
    n                000 ... 0000000000000000000000000000000000
    n | (b & 255)    000 ... 0000000000000000000000000010110101
    
    现在我们得到了预期的价值

    解决方法是将
    b
    转换为
    int
    作为中间步骤,并将高24位设置为0,这样我们就可以将其转换为
    long
    ,而不必使用原始符号位。

    如果您不清楚此处发生的隐式转换,以下是显式转换:

    n = n | (long)b;
    
    n = n | (long)((int)b & 255);
    

    其他东西 正如maraca在评论中提到的,交换循环中的前两行,否则最终会将整个循环的8位向左移动太远(这就是为什么低8位为零)


    我还注意到,您预期的最终结果用前导的
    1
    s填充。如果这是您想要的结果,您可以从
    -1L
    开始,而不是
    0L
    (除了其他修复).

    交换for循环中的前两行,没有理由在这里使用Long intead of Long。有趣的回答谢谢,它是有效的。但是我不明白你对值提升和符号位扩展的意思是什么?谢谢!@JasonC很好的解释!
    b & 255                    00000000000000000000000010110101
    convert to long  000 ... 0000000000000000000000000010110101
    n                000 ... 0000000000000000000000000000000000
    n | (b & 255)    000 ... 0000000000000000000000000010110101
    
    n = n | (long)((int)b & 255);