2015-08-28 103 views
3

我試圖將十六進制轉換爲大整數。基本上我有32個字符= 16個字節,因此,我希望BigInteger也有16個字節,但對於一些情況,即十六進制99開始..它以0我使用將十六進制轉換爲BigInteger

new BigInteger(hex, 16) 

如何產生額外的字節我可以避開第17個字節嗎?

+2

我發現很難嚴格遵循問題的情況。如果您發佈一個簡短但完整的程序來展示問題,即輸入,實際產出和預期產出,那麼它將會更容易幫助您。 –

+0

由於Java的簽名性,當執行'toByteArray()'時,任何以'80'或更高開頭的值都會導致「額外」字節。 – Kayaman

+0

Kayaman,所以除了這個額外的0之外沒有別的辦法嗎? :( –

回答

0

超過127字節的值不能與Java的byte表示,因爲他們已登錄(當然,他們可以但Java將他們視爲負數)。

BigInteger將該值轉換爲字節數組時,它會在前面添加一個0字節以區分正值與負值。

這導致128將變爲[0][-128],而-128將變成[-128]

如果您打算將結果字節存儲爲一個無符號的128位值,那麼您可以截斷該數組的第一個元素,例如, byte[] sanitizedBytes = Arrays.copyOfRange(myBytes, 1, 16);

2

BigInteger's javadoc

不可變的任意精度的整數。所有的操作都表現得好像BigInteger以2的補碼錶示法(例如Java的 原始整數類型)表示。

description of the constructor you are using和:

將BigInteger的指定 基數成一個BigInteger字符串表示。字符串表示由一個 可選的負號或加號組成,後跟一個或多個指定基數的 數字序列。字符到數字的映射是由Character.digit提供的 。該字符串不得包含任何無關的 字符(例如,空格)。

這意味着,如果你有new BigInteger("99000000000000000000000000000000", 16)調用它,你會得到一個BigInteger,其中認爲值(爲正值),就好像它是在二進制補碼錶示法表示。二進制補碼中的正值不適合16字節,所以最終的結果當然是17字節長。

你保證,如果你與之間的值調用它來獲得一個BigInteger與16個字節的maximun(包括兩端):

- new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16) 
- new BigInteger("-80000000000000000000000000000000", 16) 

比第一次比一次更高或更低的任何值會導致超過16個字節。

1

第一個字節不能以1位開始,因爲那意味着一個負數。他們通過在數組起始處添加額外的零字節來防止這種情況。該功能將檢查和砍掉那個字節:

public static byte[] signedToUnsignedBytes(byte[] myBytes) { 
    return myBytes.length > 1 && myBytes[0] == 0 
     ? Arrays.copyOfRange(myBytes, 1, myBytes.length) 
     : myBytes; 
} 
0

看來你是使用BigInteger的唯一目的,以固定長度的十六進制字符串轉換爲byte[]陣列。使用Long.parseUnsignedLong()在Java的8

static byte[] toByteArray(String s) { 
    ByteBuffer bb = ByteBuffer.allocate(16); 
    bb.asIntBuffer().put((int) Long.parseLong(s.substring(0, 8), 16)) 
        .put((int) Long.parseLong(s.substring(8, 16), 16)) 
        .put((int) Long.parseLong(s.substring(16, 24), 16)) 
        .put((int) Long.parseLong(s.substring(24), 16)); 
    return bb.array(); 
} 

或者簡單一點:這可以用另一種方式來完成,例如,使用ByteBuffer

static byte[] toByteArray8(String s) { 
    ByteBuffer bb = ByteBuffer.allocate(16); 
    bb.asLongBuffer().put(Long.parseUnsignedLong(s.substring(0, 16), 16)) 
        .put(Long.parseUnsignedLong(s.substring(16), 16)); 
    return bb.array(); 
} 

這樣,你不應該在乎的情況(你即使對於"000...000"字符串,也總是會獲得16個字節),並且可能會有較少的堆分配。示例用法:

System.out.println(Arrays.toString(toByteArray("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"))); 
// [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] 
System.out.println(Arrays.toString(toByteArray("80000000000000000000000000000000"))); 
// [-128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
System.out.println(Arrays.toString(toByteArray("123FFFFFFFFFFFFFFFFFFFFFFFFFFFFF"))); 
// [18, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] 
System.out.println(Arrays.toString(toByteArray("007FFFFFFFFFFFFFFFFFFFFFFFFFFFFF"))); 
// [0, 127, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] 
System.out.println(Arrays.toString(toByteArray("00000000000000000000000000000001"))); 
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]