Java convirtiendo int a hexadecimal y viceversa

80

Tengo el siguiente código...

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

Esto equivale a ffff8000

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

Entonces, inicialmente, convierte el valor -32768 en una cadena hexadecimal ffff8000, pero luego no puede convertir la cadena hexadecimal de nuevo en un entero.

En .Netfunciona como esperaba, y returns -32768.

Sé que podría escribir mi propio método para convertir esto yo mismo, pero me pregunto si me estoy perdiendo algo o si esto es realmente un error.

Rico S
fuente
1
posible duplicado de Java int negativo a hexadecimal y falla hacia atrás
Andreas Dolk
5
Solo una pista: como los nombres de variables de la convención comienzan con un carácter en minúscula:int firstAttempt = 5;
Simulante

Respuestas:

48

Se desborda, porque el número es negativo.

Prueba esto y funcionará:

int n = (int) Long.parseLong("ffff8000", 16);
roni bar yanai
fuente
Gracias roni, esa parece ser la mejor solución. Aunque todavía parece extraño que Int.parseInt no funcione como esperaba.
Rich S
ffff8000 no encaja en un int (int grande entonces max), esto es un número positivo (que es una cadena negativa por lo que sólo si tiene menos)
, Roni Bar yanai
1
Es porque parseInt toma un int firmado y toHexString produce un resultado sin firmar (ver mi respuesta) ...
brimborium
Gracias, me salvaste el día :)
Vineesh TP
1
@roni, ¿qué pasa si hexadecimal tiene un valor de cadena como String Hex=Integer.toHexString("xyz");cómo recuperar la cadena del hexadecimal como "xyz"
subodh
73
int val = -32768;
String hex = Integer.toHexString(val);

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

Así es como puedes hacerlo.

La razón por la que no funciona a su manera: Integer.parseInttoma un int firmado, mientras que toHexStringproduce un resultado sin firmar. Entonces, si inserta algo mayor que 0x7FFFFFF, se lanzará un error automáticamente. Si lo analiza como en su longlugar, seguirá estando firmado. Pero cuando lo devuelva a int, se desbordará al valor correcto.

brimborium
fuente
27
  • int a Hex:

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

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

También puede utilizar en longlugar de int(si el valor no se ajusta a los intlímites):

  • Hex a long:

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

    Long.toHexString(longValue)
    
asombroso
fuente
9

Vale la pena mencionar que Java 8 tiene los métodos Integer.parseUnsignedInty Long.parseUnsignedLongeso hace lo que querías, específicamente:

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

El nombre es un poco confuso, ya que analiza un entero con signo de una cadena hexadecimal, pero hace el trabajo.

Yuval Sapir
fuente
7

Intente usar la clase BigInteger, funciona.

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
fuente
4

Como Integer.toHexString (byte / integer) no funciona cuando intenta convertir bytes firmados como caracteres decodificados UTF-16, debe usar:

Integer.toString(byte/integer, 16);

o

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

reverso que puedes usar

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

El método parseInt de Java es en realidad un montón de código que come hexadecimal "falso": si desea traducir -32768, debe convertir el valor absoluto en hexadecimal y luego anteponer la cadena con '-'.

Hay una muestra del archivo Integer.java:

public static int parseInt(String s, int radix)

La descripción es bastante explícita:

* 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
fuente
2

Usar Integer.toHexString(...)es una buena respuesta. Pero personalmente prefiero usarString.format(...) .

Pruebe esta muestra como prueba.

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 Faraón
fuente
2

El siguiente código funcionaría:

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

Jeje, curioso. Creo que esto es un "error intencional", por así decirlo.

La razón subyacente es cómo se escribe la clase Integer. Básicamente, parseInt está "optimizado" para números positivos. Cuando analiza la cadena, genera el resultado de forma acumulativa, pero se niega. Luego cambia el signo del resultado final.

Ejemplo:

66 = 0x42

analizado como:

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

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

return -66 * (-1) = 66

Ahora, veamos su ejemplo 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.

Editar (adición): para que parseInt () funcione "consistentemente" para -Integer.MAX_VALUE <= n <= Integer.MAX_VALUE, habrían tenido que implementar la lógica para "rotar" al alcanzar -Integer.MAX_VALUE en el resultado acumulativo, comenzando de nuevo en el extremo máximo del rango de enteros y continuando hacia abajo desde allí. Por qué no hicieron esto, habría que preguntarle a Josh Bloch oa quien sea que lo implementó en primer lugar. Podría ser solo una optimización.

Sin embargo,

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

funciona bien, solo por esta razón. En el código fuente de Integer puedes encontrar este comentario.

// Accumulating negatively avoids surprises near MAX_VALUE
papilla
fuente
2
// Accumulating negatively avoids surprises near MAX_VALUE-> pero introduce sorpresas inferiores 0 ^^
brimborium