web-dev-qa-db-fra.com

Java convertissant int en hexadécimal et inversement

J'ai le code suivant...

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

Cela équivaut à ffff8000

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

Ainsi, initialement, il convertit la valeur -32768 en une chaîne hexagonale ffff8000, mais ne peut ensuite pas convertir la chaîne hexadécimale en un entier.

Dans .Net ça marche comme je le pensais, et returns -32768.

Je sais que je pourrais écrire ma propre petite méthode pour convertir cela moi-même, mais je me demande simplement si quelque chose me manque ou s'il s'agit véritablement d'un bug?

66
Rich S

Il déborde, car le nombre est négatif.

Essayez ceci et cela fonctionnera:

int n = (int) Long.parseLong("ffff8000", 16);
44
roni
int val = -32768;
String hex = Integer.toHexString(val);

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

C'est comme ça que tu peux le faire.

La raison pour laquelle cela ne fonctionne pas à votre façon: Integer.parseInt prend un entier signé, tandis que toHexString produit un résultat non signé. Donc, si vous insérez quelque chose de plus grand que 0x7FFFFFF, une erreur sera automatiquement générée. Si vous analysez plutôt long, il sera quand même signé. Mais lorsque vous le reconvertissez en int, il débordera à la valeur correcte.

63
brimborium
  • int to Hex:

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

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

Vous pouvez également utiliser long à la place de int (si la valeur ne correspond pas à la limite int):

  • Hex à long:

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

    Long.toHexString(longValue)
    
20
user1122857

Il est à noter que Java 8 a les méthodes Integer.parseUnsignedInt Et Long.parseUnsignedLong Qui font ce que vous vouliez, plus précisément:

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

Le nom est un peu déroutant, car il analyse un entier signé d'une chaîne hexagonale, mais il fait le travail.

8
Yuval Sapir

Essayez d'utiliser la classe BigInteger, cela fonctionne.

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

Comme Integer.toHexString (octet/entier) ne fonctionne pas lorsque vous essayez de convertir des octets signés tels que les caractères décodés UTF-16, vous devez utiliser:

Integer.toString(byte/integer, 16);

ou

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

inversez vous pouvez utiliser

Integer.parseInt(hexString, 16);
3
Spektakulatius

La méthode parseInt de Java est en réalité un groupe de code mangeant "false" hex: si vous voulez traduire -32768, vous devez convertir la valeur absolue en hex, puis ajouter la chaîne avec "-".

Il existe un exemple de fichier Integer.Java:

public static int parseInt(String s, int radix)

La description est assez explicite:

* 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
3
Benj

Utiliser Integer.toHexString(...) est une bonne réponse. Mais personnellement, préférez utiliser String.format(...).

Essayez cet échantillon comme 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
Chef Pharaoh

Le code ci-dessous fonctionnerait:

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

Héhé, curieux. Je pense que c'est un "bug intentianal", pour ainsi dire.

La raison sous-jacente est la façon dont la classe Integer est écrite. Fondamentalement, parseInt est "optimisé" pour les nombres positifs. Lorsqu'il analyse la chaîne, il génère le résultat de manière cumulative, mais est annulé. Ensuite, il retourne le signe du résultat final.

Exemple:

66 = 0x42

analysé comme:

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

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

return -66 * (-1) = 66

Maintenant, regardons votre exemple 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.

Edit (addition): pour que parseInt () fonctionne de manière "cohérente" pour -Integer.MAX_VALUE <= n <= Integer.MAX_VALUE, il aurait fallu que la logique "réponde" lorsque -Integer.MAX_VALUE soit atteint. résultat cumulatif, en partant de l'extrémité maxi de la plage entière et en descendant vers le bas. Pourquoi ils ne l'ont pas fait, il faudrait d'abord demander à Josh Bloch ou à quiconque de l'avoir mis en œuvre. Cela pourrait simplement être une optimisation.

Cependant,

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

fonctionne très bien, juste pour cette raison. Vous pouvez trouver ce commentaire dans la source d'Integer.

// Accumulating negatively avoids surprises near MAX_VALUE
1
pap