Java中负字节和短数据类型中的位操作

Posted

技术标签:

【中文标题】Java中负字节和短数据类型中的位操作【英文标题】:Bit manipulation in negative byte and short data types in Java 【发布时间】:2015-08-22 23:28:27 【问题描述】:

我试图在不使用 int 原始类型的情况下实现一个存储 32 位数字的类。为此,我使用了两个short 变量msbslsbs 来存储数字的32 位,每个变量16 位。 变量msbs 将存储数字的前16 位,而lsbs 变量将存储剩下的16 位。

在将给定字节保存到变量时,我应用下一个公式:(字节顺序以 Little-Endian 表示法给出)

输入 -> byte[] n = 0b00110101, -3, 0b1001, 0b0; 到数字 0b00000000 00001001 11111101 00110101 (654645)

msbs = ((n[3] << 8) | n[2]); lsbs = ((n[1] << 8) | n[0]);

如下图

private void saveNumber(byte[] n) 
    msbs = (byte)((n[3] << 8) | n[2]);
    lsbs = (byte)((n[1] << 8) | n[0]);

    System.out.println(Integer.toBinaryString((n[1] << 8) | n[0]));//Prints 11111111111111111111110100110101

    System.out.println("msbs -> " + Integer.toBinaryString(msbs));
    System.out.println("lsbs -> " + Integer.toBinaryString(lsbs));//Prints 110101

线

System.out.println(Integer.toBinaryString((n[1] &lt;&lt; 8) | n[0]));//Prints 11111111111111111111110100110101

打印出我需要的东西,尽管一开始有大量无用的 1 位(我可以通过将其转换为 short 来摆脱它) 但是当我打印 lsbs 时,我存储完全相同的值(显然)它输出 110101 而它应该是 0b1111110100110101

为什么会出现这种情况?我知道这一定是Java在将值11111111111111111111110100110101存储为16位原始类型时执行的“内部”转换(我个人认为这不会发生,因为我将8位转移到留下一个 8 位数字,应该给我一个 16 位数字) 作为旁注,msbs 变量正在做我想要它做的事情,所以问题应该与 Java 表示负数的方式有关

顺便说一句,我知道 Java 并不是最适合玩比特的语言。

【问题讨论】:

为什么应该是1111110100110101?当您执行((n[1] &lt;&lt; 8) | n[0]) 时,会给出1111110100110101。当您将其转换为 byte 时,您会删除除最后 8 位之外的所有位,只留下 00110101 您的意思是投射到short吗? 您没有为此使用ByteBuffer 是否有特殊原因? 我仍然想知道为什么我把它转换成字节。 【参考方案1】:

为什么会出现这种情况?

在 Java 中,所有按位操作都是 32 位或 64 位操作。这与其他一些语言不同,并且可能出乎意料。但事实就是如此。

我知道这一定是 Java 执行的“内部”转换......

Java 不会在您的任何示例中进行隐式缩小转换1。事实上,我认为意外行为的原因是您的代码中的明确缩小范围:

  msbs = (byte)((n[3] << 8) | n[2]);

您已将 32 位值从 ((n[3] &lt;&lt; 8) | n[2]) 显式转换为 byte。根据您所说的预期,您应该转换为 short


旁白:当你写这样的东西时“我个人认为这不会发生......”这意味着你怀疑Java编译器的正确性。事实上,在 99.999% 的情况下2,真正的问题是有人不理解编译器应该 对他们做什么;即他们的语言知识太浅3。在大多数情况下,有一个编程语言规范准确地说明了特定构造的含义。在 Java 案例中,它是 Java 语言规范。


1 - 事实上,我能想到的唯一情况是原始类型发生内部收缩的情况是在赋值运算符中。

2 - 我编了这个数字,但重点是编译器错误很少会导致意外的应用程序行为。

3 - 或者这只是程序员遗漏的一个应用程序错误。疲劳会对大脑造成不良影响...

【讨论】:

嗯,还是不知道为什么我把它转换成字节。无论如何,将显式转换为 short 解决了我的问题。

以上是关于Java中负字节和短数据类型中的位操作的主要内容,如果未能解决你的问题,请参考以下文章

C语言中的位段操作—嵌入式学习(实习篇)

在 JavaCard 中将字节转换为短字节

Java的按位操作符

Java的按位操作符

基本数据类型和引用数据类型的区别

字节数组到短数组并在java中再次返回