Java negativo int a hexadecimal y posterior falla

public class Main3 { public static void main(String[] args) { Integer min = Integer.MIN_VALUE; String minHex = Integer.toHexString(Integer.MIN_VALUE); System.out.println(min + " " + minHex); System.out.println(Integer.parseInt(minHex, 16)); } } 

Da

 -2147483648 80000000 Exception in thread "main" java.lang.NumberFormatException: For input string: "80000000" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48) at java.lang.Integer.parseInt(Integer.java:459) at Main3.main(Main3.java:7) 

¿Que pasa?

Está documentado que Integer.toHexString devuelve una representación de cadena del entero como un valor sin signo, mientras que Integer.parseInt toma un int firmado. Si usa Integer.toString(value, 16) obtendrá lo que desea.

Esto es algo que siempre me ha molestado. Si inicializa un int con un literal hexadecimal, puede usar el rango completo de valores positivos hasta 0xFFFFFF ; cualquier cosa mayor que 0x7FFFFF realmente será un valor negativo. Esto es muy útil para el enmascaramiento de bits y otras operaciones donde solo te importan las ubicaciones de los bits, no sus significados.

Pero si usa Integer.parseInt () para convertir una cadena en un entero, cualquier cosa más grande que "0x7FFFFFFF" se trata como un error. Probablemente haya una buena razón por la que lo hicieron de esa manera, pero sigue siendo frustrante.

La solución más simple es usar Long.parseLong () en su lugar, luego lanzar el resultado a int.

 int n = (int)Long.parseLong(s, 16); 

Por supuesto, solo deberías hacerlo si estás seguro de que el número estará en el rango Integer.MIN_VALUE..Integer.MAX_VALUE .

Según la documentación, toHexString devuelve “una representación de cadena del argumento entero como un entero sin signo en la base 16.”

Entonces, la operación inversa correcta probablemente sea Integer.parseUnsignedInt que se introdujo como parte de Java 8:

 public class Main3 { public static void main(String[] args) { Integer min = Integer.MIN_VALUE; String minHex = Integer.toHexString(Integer.MIN_VALUE); System.out.println(min + " " + minHex); System.out.println(Integer.parseUnsignedInt(minHex, 16)); } 

Prueba esto:

 public class Main3 { public static void main(String[] args) { Integer min = Integer.MIN_VALUE; String minHex = Integer.toHexString(Integer.MIN_VALUE); System.out.println(min + " " + minHex); System.out.println(Integer.parseInt( "-" + minHex, 16)); } 

}

para obtener esto:

 -2147483648 80000000 -2147483648 

Debe incluir un signo negativo .

No tengo acceso para probar esto en este momento, pero apostaría si prueba este valor en su lugar:

 Integer min = Integer.MIN_VALUE + 1; 

No sería una bomba, pero le daría un número positivo (no negativo) cuando ejecutó ParseInt(min,16) .

Una cadena de bits realmente no tiene suficiente información para determinar el signo en este contexto, por lo que debe proporcionarla. (Considere el caso donde usa min = "F" . ¿Es eso +/- F? Si lo convirtió a bits y vio 1111, y sabía que era un byte, podría concluir que es negativo, pero eso es una gran cantidad de ifs.

Esto parece funcionar para mí:

 public class Main3 { public static void main(String[] args) { Integer min = Integer.MIN_VALUE; String minHex = Integer.toHexString(Integer.MIN_VALUE); System.out.println(min + " " + minHex); System.out.println((int)Long.parseLong(minHex, 16)); } } 

El entero se analiza como un “largo firmado” que maneja un número positivo tan grande y luego el signo se encuentra de nuevo fundiéndolo en “int”.