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?
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.
C'est signe l'extension . Essayez \u1234
au lieu de \uffff
et voyez ce qui se passe.
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.
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
.