web-dev-qa-db-fra.com

Char en octet? (Java)

Comment cela se fait-il?

char a = '\uffff'; //Highest value that char can take - 65535
byte b = (byte)a; //Casting a 16-bit value into 8-bit data type...! Isn't data lost here?
char c = (char)b; //Let's get the value back
int d = (int)c;
System.out.println(d); //65535... how?

Fondamentalement, j'ai vu qu'une char est 16 bits. Par conséquent, si vous le transformez en byte, comment se fait-il qu'aucune donnée ne soit perdue? (La valeur est la même après la conversion dans un int)

Merci d'avance de répondre à cette petite question ignorante. : P

EDIT: Woah, a découvert que ma sortie originale avait réellement fonctionné comme prévu, mais je viens de mettre à jour le code ci-dessus. Fondamentalement, un caractère est converti dans un octet, puis reconverti dans un caractère, et sa valeur d'origine à 2 octets est conservée. Comment cela peut-il arriver?

15
wakachamo

Comme l'affirme trojanfoe, votre confusion sur les résultats de votre code est due en partie à une extension de signe. Je vais essayer d'ajouter une explication plus détaillée qui pourrait vous aider avec votre confusion.

char a = '\uffff';
byte b = (byte)a;  // b = 0xFF

Comme vous l'avez noté, cela entraîne la perte d'informations. Ceci est considéré comme une conversion rétrécissante . La conversion d'un caractère en octet "supprime simplement tous les bits de l'ordre le plus bas sauf les n".
Le résultat est: 0xFFFF -> 0xFF

char c = (char)b;  // c = 0xFFFF

La conversion d'un octet en caractère est considérée comme une conversion spéciale . Il effectue réellement deux conversions. Tout d'abord, l'octet est étendu par SIGN (les nouveaux bits de poids fort sont copiés de l'ancien bit de signe) vers un int (conversion d'élargissement normale). Deuxièmement, l'int est converti en un caractère avec une conversion de rétrécissement.
Le résultat est: 0xFF -> 0xFFFFFFFF -> 0xFFFF

int d = (int)c;  // d = 0x0000FFFF

La conversion d'un caractère en un entier est considérée comme une conversion widening . Lorsqu'un type de caractère est élargi à un type intégral, il est étendu à ZERO (les nouveaux bits de poids fort sont mis à 0).
Le résultat est: 0xFFFF -> 0x0000FFFF. Une fois imprimé, cela vous donnera 65535.

Les trois liens que j'ai fournis sont les détails officiels de la spécification du langage Java sur les conversions de type primitif. Je vous recommande vivement de jeter un coup d'oeil. Ils ne sont pas très verbeux (et relativement simples dans ce cas). Il détaille exactement ce que Java fera en coulisse avec les conversions de types. C'est un domaine commun d'incompréhension pour beaucoup de développeurs. Postez un commentaire si vous êtes toujours confus avec une étape.

23
robert_x44

C'est signe l'extension . Essayez \u1234 au lieu de \uffff et voyez ce qui se passe.

8
trojanfoe

Java byte est signé. c'est contre-intuitif. dans presque toutes les situations où un octet est utilisé, les programmeurs souhaiteraient plutôt un octet non signé. c'est très probablement un bug si un octet est directement converti en int. 

Cela fait la conversion voulue correctement dans presque tous les programmes:

int c = 0xff & b ;

Empiriquement, le choix de l'octet signé est une erreur.

5
irreputable

Des choses plutôt étranges se passent sur votre machine. Jetez un coup d’œil à Spécification du langage Java, chapitre 4.2.1 :

Les valeurs des types intégraux sont entiers dans les plages suivantes:

Pour octet, de -128 à 127 inclus

... coupez les autres ...

Si votre machine virtuelle Java est conforme aux normes, votre sortie doit être -1

0
darioo