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?



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

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.


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)
    

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.


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

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

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

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

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

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

2
// Accumulating negatively avoids surprises near MAX_VALUE-> ale wprowadza niespodzianki niższe 0 ^^
brimborium
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.