Java négatif int à hex et retour échoue
Question
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));
}
}
Donne
-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)
Quoi de neuf?
La solution
Il est documenté que Integer.toHexString
retourne une représentation sous forme de chaîne de l'entier sous forme de valeur non signée - tandis que Integer.parseInt
prend un entier signé. Si vous utilisez Integer.toString(value, 16)
à la place, vous obtiendrez ce que vous voulez.
Autres conseils
C'est quelque chose qui m'a toujours agacé. Si vous initialisez un int avec un littéral hexadécimal, vous pouvez utiliser toute la plage de valeurs positives allant jusqu'à 0xFFFFFF
; tout ce qui est plus grand que 0x7FFFFF
sera vraiment une valeur négative. C’est très pratique pour le masquage de bits et d’autres opérations dans lesquelles vous ne vous souciez que des emplacements des bits, pas de leur signification.
Mais si vous utilisez Integer.parseInt () pour convertir une chaîne en entier, toute valeur supérieure à "0x7FFFFFFF"
est considérée comme une erreur. Il y a probablement une bonne raison pour laquelle ils l'ont fait de cette façon, mais c'est toujours frustrant.
La solution la plus simple consiste à utiliser Long.parseLong () à la place, puis de convertir le résultat en int.
int n = (int)Long.parseLong(s, 16);
Bien sûr, vous ne devriez le faire que si vous êtes sûr que le nombre va se situer dans la plage Integer.MIN_VALUE..Integer.MAX_VALUE
.
Selon la documentation, toHexString
renvoie & "; une représentation sous forme de chaîne de l'argument entier sous la forme d'un entier unsigned en base 16. &";
Donc, l'opération inverse correcte est probablement Integer.parseUnsignedInt
introduit dans 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));
}
Essayez ceci:
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));
}
}
pour obtenir ceci:
-2147483648 80000000
-2147483648
Vous devez inclure un signe négatif .
Je n'ai pas accès à ce test pour le moment, mais je parierais que si vous essayiez cette valeur à la place:
Integer min = Integer.MIN_VALUE + 1;
Cela ne bombarderait pas, mais vous donnerait un nombre positif (non négatif) lorsque vous courriez ParseInt(min,16)
.
Une chaîne de bits n'a pas vraiment assez d'informations pour déterminer le signe dans ce contexte, vous devez donc le fournir. (Pensez au cas où vous utilisez min = "F"
. Est-ce +/- F? Si vous le convertissez en bits et que vous avez vu 1111, et vous saviez que c'était un octet, vous pourriez en déduire que c'est négatif, mais ça fait beaucoup de si.
Cela semble fonctionner pour moi:
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));
}
}
L'entier est analysé comme un & "long signé &"; que le nombre positif est élevé et que le signe est retrouvé en le lançant en & "int &";