簡體   English   中英

Java將int轉換為十六進制並再次返回

[英]Java converting int to hex and back again

我有以下代碼...

int Val=-32768;
String Hex=Integer.toHexString(Val);

這相當於ffff8000

int FirstAttempt=Integer.parseInt(Hex,16); // Error "Invalid Int"
int SecondAttempt=Integer.decode("0x"+Hex);  // Error "Invalid Int"

因此,最初,它將值 -32768 轉換為十六進制字符串 ffff8000,但隨后無法將十六進制字符串轉換回整數。

.Net它按我的預期工作,並returns -32768

我知道我可以編寫自己的小方法來自己轉換它,但我只是想知道我是否遺漏了什么,或者這是否真的是一個錯誤?

int val = -32768;
String hex = Integer.toHexString(val);

int parsedResult = (int) Long.parseLong(hex, 16);
System.out.println(parsedResult);

這就是你可以做到的。

它不按您的方式工作的原因: Integer.parseInt采用有符號整數,而toHexString產生無符號結果。 因此,如果您插入高於0x7FFFFFF ,則會自動拋出錯誤。 如果你解析它long ,它仍然會被簽名。 但是當你將它轉換回 int 時,它會溢出到正確的值。

它溢出,因為數字是負數。

試試這個,它會起作用:

int n = (int) Long.parseLong("ffff8000", 16);
  • int到十六進制:

     Integer.toHexString(intValue);
  • 十六進制到int

     Integer.valueOf(hexString, 16).intValue();

您可能還想使用long而不是int (如果該值不適合int邊界):

  • 十六進制到long

     Long.valueOf(hexString, 16).longValue()
  • long到十六進制

    Long.toHexString(longValue)

值得一提的是,Java 8 的Integer.parseUnsignedIntLong.parseUnsignedLong方法Long.parseUnsignedLong您的需求,具體來說:

Integer.parseUnsignedInt("ffff8000",16) == -32768

這個名字有點令人困惑,因為它從一個十六進制字符串解析一個有符號整數,但它確實有效。

嘗試使用 BigInteger 類,它有效。

int Val=-32768;
String Hex=Integer.toHexString(Val);

//int FirstAttempt=Integer.parseInt(Hex,16); // Error "Invalid Int"
//int SecondAttempt=Integer.decode("0x"+Hex);  // Error "Invalid Int"
BigInteger i = new BigInteger(Hex,16);
System.out.println(i.intValue());

由於 Integer.toHexString(byte/integer) 在您嘗試轉換有符號字節(如 UTF-16 解碼字符)時不起作用,因此您必須使用:

Integer.toString(byte/integer, 16);

或者

String.format("%02X", byte/integer);

反向你可以使用

Integer.parseInt(hexString, 16);

Java 的 parseInt 方法實際上是一堆吃“假”十六進制的代碼:如果你想翻譯 -32768,你應該把絕對值轉換成十六進制,然后在字符串前面加上'-'。

有一個 Integer.java 文件示例:

public static int parseInt(String s, int radix)

描述非常明確:

* Parses the string argument as a signed integer in the radix 
* specified by the second argument. The characters in the string 
...
...
* parseInt("0", 10) returns 0
* parseInt("473", 10) returns 473
* parseInt("-0", 10) returns 0
* parseInt("-FF", 16) returns -255

使用Integer.toHexString(...)是一個很好的答案。 但個人更喜歡使用String.format(...)

試試這個樣本作為測試。

byte[] values = new byte[64];
Arrays.fill(values, (byte)8);  //Fills array with 8 just for test
String valuesStr = "";
for(int i = 0; i < values.length; i++)
    valuesStr += String.format("0x%02x", values[i] & 0xff) + " ";
valuesStr.trim();

下面的代碼可以工作:

int a=-32768;
String a1=Integer.toHexString(a);
int parsedResult=(int)Long.parseLong(a1,16);
System.out.println("Parsed Value is " +parsedResult);

嘿嘿,好奇。 我認為這是一個“intentianal bug”,可以這么說。

根本原因是 Integer 類的編寫方式。 基本上, parseInt 是為正數“優化”的。 當它解析字符串時,它會累積構建結果,但會否定。 然后它翻轉最終結果的符號。

例子:

66 = 0x42

解析如下:

4*(-1) = -4
-4 * 16 = -64 (hex 4 parsed)

-64 - 2 = -66 (hex 2 parsed)

return -66 * (-1) = 66

現在,讓我們看看您的示例 FFFF8000

16*(-1) = -16 (first F parsed)
-16*16 = -256 

-256 - 16 = -272 (second F parsed)
-272 * 16 = -4352 

-4352 - 16 = -4368 (third F parsed)
-4352 * 16 = -69888

-69888 - 16 = -69904 (forth F parsed)
-69904 * 16 = -1118464 

-1118464 - 8 = -1118472 (8 parsed)
-1118464 * 16 = -17895552 

-17895552 - 0 = -17895552 (first 0 parsed)
Here it blows up since -17895552 < -Integer.MAX_VALUE / 16 (-134217728). 
Attempting to execute the next logical step in the chain (-17895552 * 16)
would cause an integer overflow error.

編輯(補充):為了使 parseInt() 為 -Integer.MAX_VALUE <= n <= Integer.MAX_VALUE“一致”工作,當到達 -Integer.MAX_VALUE 時,他們必須實現邏輯以“旋轉”累積結果,從整數范圍的最大端開始並從那里繼續向下。 為什么他們不這樣做,人們必須詢問 Josh Bloch 或首先實施它的人。 這可能只是一種優化。

然而,

Hex=Integer.toHexString(Integer.MAX_VALUE);
System.out.println(Hex);
System.out.println(Integer.parseInt(Hex.toUpperCase(), 16));

工作得很好,正是因為這個原因。 在 Integer 的源代碼中,您可以找到此評論。

// Accumulating negatively avoids surprises near MAX_VALUE

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM