Java konvertiert int in hex und wieder zurück

80

Ich habe den folgenden Code ...

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

Dies entspricht ffff8000

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

Zunächst wird der Wert -32768 in eine Hex-Zeichenfolge ffff8000 konvertiert, dann kann die Hex-Zeichenfolge jedoch nicht wieder in eine Ganzzahl konvertiert werden.

Darin .Netfunktioniert es wie erwartet und returns -32768.

Ich weiß, dass ich meine eigene kleine Methode schreiben könnte, um dies selbst zu konvertieren, aber ich frage mich nur, ob mir etwas fehlt oder ob dies wirklich ein Fehler ist?

Rich S.
quelle
1
mögliches Duplikat von Java negativ int zu hex und zurück schlägt fehl
Andreas Dolk
5
Nur ein Hinweis: Als Konvention beginnen Variablennamen mit einem Kleinbuchstaben:int firstAttempt = 5;
Simulant

Antworten:

48

Es läuft über, weil die Zahl negativ ist.

Versuchen Sie dies und es wird funktionieren:

int n = (int) Long.parseLong("ffff8000", 16);
Roni Bar Yanai
quelle
Danke Roni, das scheint die beste Lösung zu sein. Obwohl es immer noch seltsam erscheint, dass Int.parseInt nicht wie erwartet funktioniert.
Rich S
ffff8000 passt nicht in ein int (größer als max int), dies ist eine positive Zahl (es ist eine Zeichenfolge, also nur negativ, wenn es ein Minus hat)
Roni Bar Yanai
1
Es ist , weil ParseInt ein signiertes int nimmt und toHexString erzeugt ein unsigned Ergebnis (siehe meine Antwort) ...
Brimborium
Danke, du
hast
1
@roni, was ist, wenn hex einen String-Wert hat, String Hex=Integer.toHexString("xyz");wie man einen String vom Hex als "xyz"
zurückbekommt
73
int val = -32768;
String hex = Integer.toHexString(val);

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

So können Sie es machen.

Der Grund, warum es nicht so funktioniert: Integer.parseIntNimmt ein vorzeichenbehaftetes Int und toHexStringerzeugt ein vorzeichenloses Ergebnis. Wenn Sie also etwas höher als einfügen 0x7FFFFFF, wird automatisch ein Fehler ausgegeben. Wenn Sie es longstattdessen als analysieren , wird es weiterhin signiert. Wenn Sie es jedoch auf int zurücksetzen, wird es auf den richtigen Wert überlaufen.

Brimborium
quelle
26
  • int zu verhexen:

    Integer.toHexString(intValue);
    
  • Hex zu int:

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

Möglicherweise möchten Sie auch longanstelle von verwenden int(wenn der Wert nicht den intGrenzen entspricht):

  • Hex zu long:

    Long.valueOf(hexString, 16).longValue()
    
  • long zu Hex

    Long.toHexString(longValue)
    
Awesoon
quelle
9

Es ist erwähnenswert, dass Java 8 die Methoden hat Integer.parseUnsignedIntund Long.parseUnsignedLongdas tut, was Sie wollten, insbesondere:

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

Der Name ist etwas verwirrend, da er eine vorzeichenbehaftete Ganzzahl aus einer Hex-Zeichenfolge analysiert, aber die Arbeit erledigt.

Yuval Sapir
quelle
7

Versuchen Sie es mit der BigInteger-Klasse, es funktioniert.

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

Da Integer.toHexString (Byte / Ganzzahl) nicht funktioniert, wenn Sie versuchen, signierte Bytes wie UTF-16-dekodierte Zeichen zu konvertieren, müssen Sie Folgendes verwenden:

Integer.toString(byte/integer, 16);

oder

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

umgekehrt können Sie verwenden

Integer.parseInt(hexString, 16);
Spektakulatius
quelle
3

Javas parseInt-Methode ist eigentlich eine Menge Code, der "falsches" Hex frisst: Wenn Sie -32768 übersetzen möchten, sollten Sie den absoluten Wert in hex konvertieren und dann den String mit '-' voranstellen.

Es gibt ein Beispiel für eine Integer.java-Datei:

public static int parseInt(String s, int radix)

Die Beschreibung ist ziemlich explizit:

* 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
Benj
quelle
2

Verwenden Integer.toHexString(...)ist eine gute Antwort. Aber persönlich lieber verwenden String.format(...).

Probieren Sie dieses Beispiel als Test aus.

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

Der folgende Code würde funktionieren:

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

Hehe, neugierig. Ich denke, das ist sozusagen ein "absichtlicher Fehler".

Der zugrunde liegende Grund ist, wie die Integer-Klasse geschrieben wird. Grundsätzlich ist parseInt für positive Zahlen "optimiert". Wenn die Zeichenfolge analysiert wird, wird das Ergebnis kumulativ erstellt, jedoch negiert. Dann dreht es das Vorzeichen des Endergebnisses um.

Beispiel:

66 = 0x42

analysiert wie:

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

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

return -66 * (-1) = 66

Schauen wir uns nun Ihr Beispiel FFFF8000 an

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.

Bearbeiten (Hinzufügen): Damit parseInt () für -Integer.MAX_VALUE <= n <= Integer.MAX_VALUE "konsistent" funktioniert, hätte es eine Logik implementieren müssen, um "zu drehen", wenn -Integer.MAX_VALUE in der kumulatives Ergebnis, beginnend am maximalen Ende des ganzzahligen Bereichs und von dort weiter abwärts. Warum sie das nicht taten, musste man Josh Bloch oder denjenigen fragen, der es überhaupt implementiert hatte. Es könnte nur eine Optimierung sein.

Jedoch,

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

funktioniert gut, nur aus diesem Grund. In der Quelle für Integer finden Sie diesen Kommentar.

// Accumulating negatively avoids surprises near MAX_VALUE
Brei
quelle
2
// Accumulating negatively avoids surprises near MAX_VALUE-> aber es
Brimborium