【问题标题】:Java - converting int to byte array without considering signJava - 将 int 转换为字节数组而不考虑符号
【发布时间】:2012-05-28 19:33:42
【问题描述】:

要将 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。我仅限于使用字节数组。有没有办法做到这一点?

更新帖子

感谢您的回复。我还没有找到我正在寻找的确切答案,所以我会尝试提供更多细节。最终,我想在数据输出流上写入不同类型的值。在这篇文章中,我想澄清将整数写入数据输出流时会发生什么。我遇到过两种情况。

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() 方法以与 BigInteger 对象上的 toByteArray() 方法相同的方式将 int 转换为字节数组。但是,情况似乎并非如此,因为 msb 不存在。所以我的问题是,在第二种情况下,如果没有 msb,我们应该如何知道 128 应该是正数而不是负数。

【问题讨论】:

  • Java 的签名 byte 不能代表数字 128。您可以在从数组中读取值时通过一些自定义函数将负数映射为正数。
  • @MarkoTopolnik:哎呀,脑子放个屁。 :p

标签: java bytearray


【解决方案1】:

你可能已经知道了

  • 在一个八位字节中,模式 10000000 可以解释为 128 或 -128,具体取决于,嗯,外部解释
  • Java 的 byte 类型仅将八位字节解释为 -128...127 中的值。

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

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

【讨论】:

    【解决方案2】:

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

    在java中 int 是二进制补码:

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

    所以关于符号位我不明白。不管怎样,你可以做到Math.abs(n)。 byte 的范围从 -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;
    }
    

    【讨论】:

      【解决方案3】:

      要回答您的第一个问题(使用无符号表示法表示非负整数需要多少字节),请考虑以下我在 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+)))
      

      这些突出了问题的数学基础:即,logarithm 告诉您支配给定非负整数需要多少 2 的幂(由位提供),使用floor 调整为阶跃函数,以及作为阶跃函数再次保持该位数所需的字节数,这次使用ceiling 调整。

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

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

      不幸的是,由于 one 的对数总是 zero,无论底数如何,这个版本说整数零可以用零位表示,这不是我们想要的答案。

      对于您的第二个目标,您可以使用我在上面定义的函数来分配所需的字节数,并逐步设置您需要的位,忽略符号。很难判断您是否无法在字节向量中设置正确的位,或者您的问题是否在于解释位以避免将高位视为符号位(即是,二的补码表示)。请详细说明你需要什么样的推动才能让你再次行动。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-08-22
        • 2011-09-04
        • 1970-01-01
        • 2014-12-27
        • 2011-09-16
        • 2020-06-03
        相关资源
        最近更新 更多