2012-08-17 23 views
48

he el siguiente código ...Java convertir int a hexadecimal y viceversa

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" 

Así, en un principio, se convierte el valor de -32768 a un hexágono string ffff8000, pero luego no puede convertir la cadena hexadecimal nuevamente en un Entero.

En .Net funciona como esperaba, y returns -32768.

Sé que podría escribir mi propio pequeño método para convertir esto, pero me pregunto si me falta algo, o si esto es realmente un error.

+1

posible du plicate de [Java negativo int a hex y la parte posterior falla] (http: // stackoverflow.com/questions/845230/java-negative-int-to-hex-and-back-failed) –

+4

Solo una sugerencia: como nombres de variables de convención comienzan con un carácter minúsculo: 'int firstAttempt = 5;' – Simulant

Respuesta

34

Se desborda porque el número es negativo.

probar esto y va a trabajar:

int n = (int) Long.parseLong("ffff8000", 16); 
+0

Gracias roni, eso parece ser la mejor solución. Aunque todavía parece extraño que Int.parseInt no funcione como esperaba. –

+0

ffff8000 no encaja en un int (más grande que max int), este es un número positivo (es una cadena por lo que es negativo solo si tiene menos) – roni

+1

Es porque parseInt toma un int firmado y toHexString produce un resultado sin signo (ver mi respuesta) ... – brimborium

16
  • int a Hex:

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

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

También puede que quiera usar long en lugar de int (si el valor no se ajusta los int límites):

  • Hex para long:

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

    Long.toHexString(longValue) 
    
48
int val = -32768; 
String hex = Integer.toHexString(val); 

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

Eso es cómo puede hacerlo.

La razón por la que no funciona a su manera: Integer.parseInt toma una int firmada, mientras que toHexString produce un resultado sin signo. Por lo tanto, si inserta algo superior a 0x7FFFFFF, se generará un error automáticamente. Si lo analiza como long, se seguirá firmando. Pero cuando lo vuelves a int, se desbordará al valor correcto.

6

Trate de 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()); 
2

Debe tener en cuenta que el método parseInt de Java es actally un montón de código de comer hexagonal "falsa": si se desea traducir -32768, debe convertir el valor absoluto en hexadecimal, precedidos por la cadena con ' - '.

Hay una muestra de Entero.archivo Java:

public static int parseInt(String s, int radix) 

La descripción es bastante explícito:

* 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 
1

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

El motivo subyacente es cómo se escribe la clase Integer. Básicamente, parseInt está "optimizado" para números positivos. Cuando analiza la cadena, construye el resultado de forma acumulativa, pero negada. Luego, voltea el signo del resultado final.

Ejemplo:

66 = 0x42

analizada como:

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

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

return -66 * (-1) = 66 

Ahora, vamos a ver el 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): con el fin para el parseInt() para trabajar "consistentemente" para -Integer.MAX_VALUE < = n < = Integer.MAX_VALUE, tendrían que implementar lógica para "girar" cuando se llega a -Integer.MAX_VALUE en el resultado acumulado, comenzando de nuevo en el extremo máximo del rango entero y continuando hacia abajo desde allí. Por qué no lo hicieron, uno tendría que preguntarle a Josh Bloch o quién lo implementó en primer lugar. Puede 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, precisamente por esta razón. En el origen de Integer puede encontrar este comentario.

// Accumulating negatively avoids surprises near MAX_VALUE 
+2

'// Acumular negativamente evita sorpresas cerca de MAX_VALUE' -> pero introduce sorpresas más bajas 0 ^^ – brimborium

6

Vale la pena mencionar que Java 8 tiene los métodos Integer.parseUnsignedInt y Long.parseUnsignedLong que hace lo que quería, en concreto:

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

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

1

El uso de Integer.toHexString(...) es una buena respuesta. Pero personalmente prefiero usar String.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(); 
2

Como Integer.toHexString (bytes/entero) no funciona cuando se está tratando de convertir bytes firmados como UTF-16 decodifica caracteres que tiene que utilizar:

Integer.toString(byte/integer, 16); 

o

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

inversa puede utilizar

Integer.parseInt(hexString, 16);