Java toByteArray()返回有目的的前导零?

Java toByteArray()返回有目的的前导零?,java,biginteger,Java,Biginteger,我正在将bigint转换为二进制、radix16和radix64编码,并看到神秘的msb零填充。这是一个大整数问题,我可以通过去除零填充或者做其他事情来解决吗 我的测试代码: String s; System.out.printf( "%s length %d\n", s = "123456789A", (new BigInteger( s, 16 )).toByteArray().length ); System.out.printf( "%s length %d\n"

我正在将bigint转换为二进制、radix16和radix64编码,并看到神秘的msb零填充。这是一个大整数问题,我可以通过去除零填充或者做其他事情来解决吗

我的测试代码:

    String s;
    System.out.printf( "%s length %d\n", s = "123456789A", (new BigInteger( s, 16 )).toByteArray().length );
    System.out.printf( "%s length %d\n", s = "F23456789A", (new BigInteger( s, 16 )).toByteArray().length );
产生输出:

    123456789A length 5
    F23456789A length 6
其中较长的数组前面有零填充。检查BigInteger.toByteArray()后,我看到:

现在,我可以找到
私有int位长度,但我找不到定义bitLength()的确切位置,以找出此类执行此操作的确切原因-可能连接到符号扩展?

是的,这是:

字节数组将采用大端字节顺序:最高有效字节位于第0个元素中。数组将包含表示此BigInteger所需的最小字节数,至少包括一个符号位,即
(ceil((this.bitLength()+1)/8))

作为:

返回此
BigInteger
的最小二补表示形式中的位数,不包括符号位


换句话说,两个具有相同大小的值将始终具有相同的位长度,而不考虑符号。将
biginger
视为无符号整数和符号位,而
toByteArray()
返回两部分的所有数据,即“无符号整数所需的位数,符号所需的位数”。

感谢Jon Skeet的回答。下面是我用来转换的一些代码,很可能是可以优化的

import java.math.BigInteger;
import java.util.Arrays;

public class UnsignedBigInteger {

    public static byte[] toUnsignedByteArray(BigInteger value) {
        byte[] signedValue = value.toByteArray();
        if(signedValue[0] != 0x00) {
            throw new IllegalArgumentException("value must be a psoitive BigInteger");
        }
        return Arrays.copyOfRange(signedValue, 1, signedValue.length);
    }

    public static BigInteger fromUnsignedByteArray(byte[] value) {
        byte[] signedValue = new byte[value.length + 1];
        System.arraycopy(value,  0, signedValue, 1, value.length);
        return new BigInteger(signedValue);
    }
}

当我搜索(10)这些数字时,我得到的是78187493530和1040260167834的正值,所以对我来说这更像是一个bug。但不管怎样,我可以忍受一个bug——我只是想知道去掉前导零是否安全。@Orthoteroid:你把它们看作十进制值——试着打印二进制值吧。。。毕竟,您是在尝试计数位,而不是十进制数字。至于去掉前导零是否“安全”,这取决于您以后将如何处理它。为了澄清,我确实不能接受toByteArray返回的非填充前导零,因为我的目的是跨平台基数转换。不过你的评论很有帮助-我可以使用toString(基数),我将得到一个未添加的位字符串。“我必须带着它飞行。”@Orthoteroid:那么你要如何区分负值和非负值呢?如果第一位(或最后一位)始终是符号位(无论是0还是1),则很容易实现。如果您只需要处理非负值,那么您就可以了,但除此之外,您真的需要考虑一下。@Orthoteroid:只需将字节视为8位数据,不管您想如何使用它们。现在认为BigInteger的表示是一个量级和一个符号(如文档所示)。因此,您有9位数据,不能放入1个字节。再次-考虑一下,如果调用toByteArray,您希望表示-1的BigInteger做什么。从我与Jon的讨论中,我认为您可能需要将arg左移到带有零字节的fromUnsignedByte-否则,如果arg设置了高位,您的返回值将为负值。没有?啊!我知道你现在做了什么。只是添加一个注释,说明代码不正确。Java BigInteger只有在其大小中设置了最高位(不包括符号位)的正值时才有额外的零字节前缀。原始帖子中的输入清楚地表明了这一点
F23456789A
在设置的第一个字节中有最高的位,因此它需要额外的字节(包含符号位)<代码>123456789A
没有。同样地,
723456789A
没有。但是
823456789A
。这很容易检查。
import java.math.BigInteger;
import java.util.Arrays;

public class UnsignedBigInteger {

    public static byte[] toUnsignedByteArray(BigInteger value) {
        byte[] signedValue = value.toByteArray();
        if(signedValue[0] != 0x00) {
            throw new IllegalArgumentException("value must be a psoitive BigInteger");
        }
        return Arrays.copyOfRange(signedValue, 1, signedValue.length);
    }

    public static BigInteger fromUnsignedByteArray(byte[] value) {
        byte[] signedValue = new byte[value.length + 1];
        System.arraycopy(value,  0, signedValue, 1, value.length);
        return new BigInteger(signedValue);
    }
}