Java konwertuje int na hex iz powrotem

80

Mam następujący kod ...

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

To się równa ffff8000

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

Tak więc początkowo konwertuje wartość -32768 na ciąg szesnastkowy ffff8000, ale potem nie może przekonwertować ciągu szesnastkowego z powrotem na liczbę całkowitą.

W .Net tym działa tak, jak się spodziewałem, i returns -32768.

Wiem, że mógłbym napisać własną małą metodę konwertowania tego samodzielnie, ale zastanawiam się tylko, czy coś mi brakuje, czy to naprawdę błąd?

Rich S.
źródło
1
możliwy duplikat Java minus int do hex i back nie powiodło się
Andreas Dolk
5
Tylko wskazówka: zgodnie z konwencją nazwy zmiennych zaczynają się od małej litery:int firstAttempt = 5;
Simulant

Odpowiedzi:

48

Przepełnia się, ponieważ liczba jest ujemna.

Spróbuj tego i zadziała:

int n = (int) Long.parseLong("ffff8000", 16);
roni bar yanai
źródło
Dzięki roni, to wydaje się być najlepszym rozwiązaniem. Chociaż nadal wydaje się dziwne, że Int.parseInt nie działa tak, jak bym się spodziewał.
Rich S
ffff8000 nie mieści się w int (większym niż max int), jest to liczba dodatnia (jest to ciąg, więc jest ujemna tylko wtedy, gdy ma minus)
roni bar yanai
1
Dzieje się tak, ponieważ parseInt pobiera int podpisaną, a toHexString daje wynik bez znaku (zobacz moją odpowiedź) ...
brimborium
Dzięki, uratowałeś mi dzień :)
Vineesh TP,
1
@roni, co jeśli hex ma wartość String, na przykład String Hex=Integer.toHexString("xyz");jak odzyskać ciąg znaków z hexa jako „xyz”
subodh
73
int val = -32768;
String hex = Integer.toHexString(val);

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

Tak możesz to zrobić.

Powód, dla którego to nie działa w twój sposób: Integer.parseIntprzyjmuje int ze znakiem, podczas gdy toHexStringdaje wynik bez znaku. Więc jeśli wstawisz coś wyższego niż 0x7FFFFFF, błąd zostanie wyrzucony automatycznie. Jeśli longzamiast tego przeanalizujesz go , nadal będzie podpisany. Ale kiedy rzucisz go z powrotem na int, przepełni się do prawidłowej wartości.

brymbor
źródło
27
  • int do Hex:

    Integer.toHexString(intValue);
    
  • Szesnastkowo do int:

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

Możesz także użyć longzamiast int(jeśli wartość nie mieści się w intgranicach):

  • Szesnastkowo do long:

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

    Long.toHexString(longValue)
    
awesoon
źródło
9

Warto wspomnieć, że Java 8 ma metody Integer.parseUnsignedInti Long.parseUnsignedLongrobi to, czego chciałeś, w szczególności:

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

Nazwa jest nieco myląca, ponieważ analizuje liczbę całkowitą ze znakiem z ciągu szesnastkowego, ale działa.

Yuval Sapir
źródło
7

Spróbuj użyć klasy BigInteger, działa.

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());
grzywa
źródło
4

Ponieważ Integer.toHexString (byte / integer) nie działa, gdy próbujesz przekonwertować podpisane bajty, takie jak zdekodowane znaki UTF-16, musisz użyć:

Integer.toString(byte/integer, 16);

lub

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

Odwróć, którego możesz użyć

Integer.parseInt(hexString, 16);
Spektakulatius
źródło
3

Metoda parseInt Javy jest w praktyce zbiorem kodu zjadającego wartość szesnastkową „false”: jeśli chcesz przetłumaczyć wartość -32768, powinieneś zamienić wartość bezwzględną na szesnastkową, a następnie wstawić ciąg przedrostkiem „-”.

Oto przykład pliku Integer.java:

public static int parseInt(String s, int radix)

Opis jest dość wyraźny:

* 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
źródło
2

Używanie Integer.toHexString(...)to dobra odpowiedź. Ale osobiście wolę używać String.format(...).

Wypróbuj tę próbkę jako test.

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();
Szef kuchni Faraon
źródło
2

Poniższy kod zadziała:

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

Hehe, ciekawy. Myślę, że to „intencjonalny błąd”, że tak powiem.

Podstawowym powodem jest sposób zapisu klasy Integer. Zasadniczo parseInt jest „zoptymalizowany” dla liczb dodatnich. Kiedy analizuje ciąg, buduje skumulowany wynik, ale zanegowany. Następnie odwraca znak wyniku końcowego.

Przykład:

66 = 0x42

przeanalizowane jak:

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

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

return -66 * (-1) = 66

Spójrzmy teraz na Twój przykład 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.

Edycja (dodawanie): aby parseInt () działało „konsekwentnie” dla -Integer.MAX_VALUE <= n <= Integer.MAX_VALUE, musieliby zaimplementować logikę „rotacji” po osiągnięciu -Integer.MAX_VALUE w skumulowany wynik, zaczynając od maksymalnego końca zakresu liczb całkowitych i kontynuując w dół od tego miejsca. Dlaczego tego nie zrobili, należałoby zapytać Josha Blocha lub tego, kto to wdrożył. To może być tylko optymalizacja.

Jednak,

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

działa dobrze, tylko z tego powodu. W źródle Integer można znaleźć ten komentarz.

// Accumulating negatively avoids surprises near MAX_VALUE
papka
źródło
2
// Accumulating negatively avoids surprises near MAX_VALUE-> ale wprowadza niespodzianki niższe 0 ^^
brimborium