繁体   English   中英

Java-将int转换为字节数组而不考虑符号

[英]Java - converting int to byte array without considering sign

要将int转换为字节数组,我使用以下代码:

int a = 128;
byte[] b = convertIntValueToByteArray(a);
private static byte[] convertIntValueToByteArray(int intValue){
  BigInteger bigInteger = BigInteger.valueOf(intValue);
  byte[] origByteArray = bigInteger.toByteArray();
  byte[] noSignByteArray = new byte[bigInteger.bitLength()/8];

  if(bigInteger.bitLength()%8!=0){
    noSignByteArray = origByteArray;
  }else{
    System.arraycopy(origByteArray,1,noSignByteArray,0,noSignByteArray.length);
  }

  return noSignByteArray;
}

我正在尝试做两件事。

1)我需要知道原始整数的字节数(四舍五入为关闭字节)。 但是,当我调用toByteArray()方法时,不需要为符号位添加的其他位。 这就是为什么我有辅助方法的原因。 因此,在此示例中,如果没有辅助方法,则当我将128转换为字节数组时,由于符号位的原因,长度为2个八位位组,但我只是期望它是一个八位位组。

2)我需要数字的正表示。 在此示例中,如果尝试打印数组b中的第一个元素,则得到-128。 但是,我将要使用的数字只能是正数,因此我真正想要的是128。我仅限于使用字节数组。 有没有办法做到这一点?

更新的帖子

感谢您的回复。 我没有找到我想要的确切答案,因此我将尝试提供更多详细信息。 最终,我想在数据输出流上写入不同类型的值。 在本文中,我想说明将int写入数据输出流时会发生什么。 我遇到了两种情况。

1)

DataOutputStream os = new DataOutputStream(this.socket.getOutputStream());

byte[] b = BigInteger.valueOf(128).toByteArray();

os.write(b);

2)

DataOutputStream os = new DataOutputStream(this.socket.getOutputStream());
os.write(128);

在第一种情况下,当从数据输入流中读取字节时,似乎字节数组中的第一个元素为0表示msb,而数组中的第二个元素包含数字-128。 但是,由于msb为0,我们将能够确定它打算为正数。 在第二种情况下,没有msb,并且从输入流读取的字节数组中存在的唯一元素是-128。 我期望数据输出流的write()方法以与toByteArray()方法对BigInteger对象相同的方式将int转换为字节数组。 但是,由于不存在msb,因此似乎并非如此。 所以我的问题是,在第二种情况下,我们应该如何知道如果没有msb,则128应该是一个正数,而不是一个负数。

您可能已经知道

  • 在一个八位位组中,根据外部解释,模式10000000可以解释为128或-128
  • Java的byte类型仅将八位byte解释为-128 ... 127中的值。

如果您要构建一个应用程序,其中整个世界仅由非负整数组成,那么您可以在字节值-128表示128和-127表示129和...以及-的前提下简单地完成所有工作。 1表示255。这当然是可行的,但需要花一些工夫。

像这样处理“无符号字节”的概念通常是通过将字节扩展为全都设置为零的shortint的高阶位,然后执行算术或显示值来完成的。 您将需要确定这种方法是否更符合您的喜好,而不只是在数组中将128表示为两个八位位组。

我认为以下代码可能就足够了。

在java中, int是二进制补码二进制数:

-1              = 111...111
ones complement = 000...000; + 1 =
1               = 000...001

所以关于标志位我不明白。 就是这样,您可以执行Math.abs(n) 字节的范围是-128到127,但是解释是屏蔽问题,如下所示。

public static void main(String[] args) {
    int n = 128;

    byte[] bytes = intToFlexBytes(n);
    for (byte b: bytes)
        System.out.println("byte " + (((int)b) & 0xFF));
}

public static byte[] intToFlexBytes(int n) {
    // Convert int to byte[4], via a ByteBuffer:
    byte[] bytes = new byte[4];
    ByteBuffer bb = ByteBuffer.allocateDirect(4);
    bb.asIntBuffer().put(n);
    bb.position(0);
    bb.get(bytes);

    // Leading bytes with 0:
    int i = 0;
    while (i < 4 && bytes[i] == 0)
        ++i;

    // Shorten bytes array if needed:
    if (i != 0) {
        byte[] shortenedBytes = new byte[4 - i];
        for (int j = i; j < 4; ++j) {
            shortenedBytes[j - i] = bytes[j]; // System.arrayCopy not needed.
        }
        bytes = shortenedBytes;
    }
    return bytes;
}

要回答您的第一个问题(使用无符号表示来表示非负整数需要多少字节),请考虑以下我在Common Lisp中编写的函数。

(defconstant +bits-per-byte+ 8)

(defun bit-length (n)
  (check-type n (integer 0) "a nonnegative integer")
  (if (zerop n)
      1
      (1+ (floor (log n 2)))))

(defun bytes-for-bits (n)
  (check-type n (integer 1) "a positive integer")
  (values (ceiling n +bits-per-byte+)))

这些突出显示了问题的数学基础:即,对告诉您,控制给定的非负整数(被调整为带有floor的阶跃函数)需要多少次幂(由位提供),并调整了它的字节数需要再次保持该位数作为步进函数,这次用ceiling调整。

请注意,数字零不能作为对数函数的输入,因此我们明确避免使用它。 您可能会注意到,也可以通过对核心表达式进行一点转换来编写bit-length函数:

(defun bit-length-alt (n)
  (check-type n (integer 0) "a nonnegative integer")
  (values (ceiling (log (1+ n) 2))))

不幸的是,作为一个对数始终为零 ,不管是基础的,这个版本说,整零可以通过零位表示,这不是我们想要的答案。

对于第二个目标,您可以使用上面定义的函数来分配所需的字节数,并递增设置所需的位,而忽略符号。 很难说出在字节向量中设置正确的位是否遇到麻烦,或者您的问题是在解释位时避免将高位视为符号位(即二进制补码表示 )。 请详细说明您需要什么样的推动才能使自己再次前进。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM