web-dev-qa-db-fra.com

Octets non signés en Java

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?

14
darksky

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.

25
Ryan Stewart

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.

14
Michael Borgwardt

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;
}
7
user2808577

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.

2
Marius Burz

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.

0
George Bailey