web-dev-qa-db-ja.com

Java intを16進数に変換してから元に戻す

私は次のコードを持っています...

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を16進文字列ffff8000に変換しますが、16進文字列を整数に戻すことはできません。

.Netでは、期待どおりに動作し、returns -32768で動作します。

私は自分でこれを変換する独自の小さなメソッドを書くことができることを知っていますが、私は何かが欠けているのか、これが本当にバグなのか疑問に思っていますか?

66
Rich S

数値が負であるため、オーバーフローします。

これを試してみて、動作します:

int n = (int) Long.parseLong("ffff8000", 16);
44
roni
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にキャストすると、正しい値にオーバーフローします。

63
brimborium
  • intから16進数:

    Integer.toHexString(intValue);
    
  • intへの16進数:

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

longの代わりにintを使用することもできます(値がintの境界に適合しない場合):

  • longへの16進数:

    Long.valueOf(hexString, 16).longValue()
    
  • longから16進数

    Long.toHexString(longValue)
    
20
user1122857

Java 8には、特に必要なことを行うメソッドInteger.parseUnsignedIntおよびLong.parseUnsignedLongがあることに言及する価値があります。

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

この名前は、16進文字列から符号付き整数を解析するため、少しわかりにくいですが、機能します。

8
Yuval Sapir

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());
7
maneesh

使用する必要があるUTF-16デコード文字のような署名付きバイトを変換しようとすると、Integer.toHexString(byte/integer)が機能しないため:

Integer.toString(byte/integer, 16);

または

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

逆に使用できます

Integer.parseInt(hexString, 16);
3
Spektakulatius

JavaのparseIntメソッドは、実際には「偽」の16進数を食べるコードの束です。-32768を変換する場合は、絶対値を16進数に変換し、文字列の先頭に「-」を追加する必要があります。

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
3
Benj

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();
2
Chef Pharaoh

以下のコードが機能します:

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

へへ、好奇心が強い。これは、いわば「意図的なバグ」だと思います。

根本的な理由は、整数クラスの記述方法です。基本的に、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で「一貫して」動作するためには、整数の範囲の最大値から開始し、そこから下方に連続する累積結果。なぜ彼らがこれをしなかったのか、ジョシュ・ブロッホまたはそもそもそれを実装した人に尋ねなければならないでしょう。それは単に最適化かもしれません。

しかしながら、

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

まさにこの理由で、うまく動作します。整数のソースでこのコメントを見つけることができます。

// Accumulating negatively avoids surprises near MAX_VALUE
1
pap