Les octets en Java sont signés par défaut. Je vois sur d'autres publications qu'une solution de contournement consistant à utiliser des octets non signés est similaire à celle-ci: int num = (int) bite & 0xFF
Quelqu'un pourrait-il m'expliquer s'il vous plaît pourquoi cela fonctionne et convertit un octet signé en un octet non signé, puis son entier respectif? ANDing
un octet avec 11111111 résultats dans le même octet - non?
Une conversion de type a une priorité plus élevée que l'opérateur &
. Par conséquent, vous commencez par transtyper un int, puis un AND pour masquer tous les bits de poids fort qui sont définis, y compris le "bit de signe" de la notation du complément à deux utilisée par Java, vous laissant ainsi la valeur positive de l'octet d'origine. Par exemple.:
let byte x = 11111111 = -1
then (int) x = 11111111 11111111 11111111 11111111
and x & 0xFF = 00000000 00000000 00000000 11111111 = 255
et vous avez effectivement supprimé le signe de l'octet d'origine.
ANDing un octet avec 11111111 donne le même octet - n'est-ce pas?
Sauf que vous utilisez AND avec 00000000000000000000000011111111, car 0xFF est un littéral int
- il n'y a pas de littéraux byte
en Java. Donc, ce qui se passe, c'est que la variable byte
est promue en int
(la transtypage n'est pas nécessaire), son signe est étendu (c'est-à-dire qu'il conserve la valeur éventuellement négative de la variable byte
, mais ensuite l'extension du signe est inversée par AND avec tous ces zéros. Le résultat est un int
dont les bits les moins significatifs sont exactement les anciens byte
et donc la valeur que byte
aurait eu si elle n'était pas signée.
En Java 8, une telle méthode est apparue dans la classe Byte:
/**
* Converts the argument to an {@code int} by an unsigned
* conversion. In an unsigned conversion to an {@code int}, the
* high-order 24 bits of the {@code int} are zero and the
* low-order 8 bits are equal to the bits of the {@code byte} argument.
*
* Consequently, zero and positive {@code byte} values are mapped
* to a numerically equal {@code int} value and negative {@code
* byte} values are mapped to an {@code int} value equal to the
* input plus 2<sup>8</sup>.
*
* @param x the value to convert to an unsigned {@code int}
* @return the argument converted to {@code int} by an unsigned
* conversion
* @since 1.8
*/
public static int toUnsignedInt(byte x) {
return ((int) x) & 0xff;
}
Comme vous le voyez, le résultat est une int
et non un octet.
Comment ça marche, disons que nous avons un byte b = -128;
, représenté par le 1000 0000
, que se passe-t-il lorsque vous exécutez votre ligne? Utilisons un int temp pour cela, disons:int i1 = (int)b;
i1 est maintenant -128 et ceci est en fait représenté en binaire comme ceci:
1111 1111 1111 1111 1111 1111 1000 0000
Alors, à quoi ressemble i1 & 0xFF
en binaire?
1111 1111 1111 1111 1111 1111 1000 0000
&
0000 0000 0000 0000 0000 0000 1111 1111
qui se traduit par
0000 0000 0000 0000 0000 0000 1000 0000
et cela correspond exactement à 128, ce qui signifie que votre valeur signée est convertie en non signée.
Modifier
Convertissez l'octet -128 .. 127
en 0 .. 255
int unsignedByte = 128 + yourByte;
Vous ne pouvez pas représenter les valeurs 128 à 255 en utilisant un octet, vous devez utiliser autre chose, comme un int ou un petit.
Oui, mais de cette façon, vous pouvez être sûr de ne jamais obtenir un nombre> 255 ou <0.
Si le premier bit est 1, le nombre est négatif. Si vous convertissez octet en entier, s'il est négatif, il sera ajouté à 1 octet et, s'il est positif, à 0 octet. L'exécution de la routine et supprimera tous les octets restants du premier 8. Cela ajoute en réalité 256 octets négatifs.