2015-04-16 12 views
5

Ho una variabile di byte:Perché lo spostamento di bit senza segno di Java per un byte negativo è così strano?

byte varB = (byte) -1; // binary view: 1111 1111 

Voglio vedere i due più a sinistra bit e fare un senza segno spostamento a destra di 6 cifre:

varB = (byte) (varB >>> 6); 

Ma io sono ottenendo -1 come se fosse di tipo int e ottenendo solo se cambio per 30!

Come posso aggirare questo e ottenere il risultato solo con un cambio a 6 cifre?

+0

Tutte le operazioni aritmetiche su un 'char',' byte' o 'short' promuovono a' int' prima. – Radiodef

risposta

8

Il motivo è l'estensione di segno associata alla promozione numerica a int che si verifica quando si cambia bit. Il valore varB viene promosso a int prima dello spostamento. Il senza segno bit-spostamento a destra si verifica, ma i suoi effetti sono caduto in fase di lancio di nuovo a byte, che mantiene solo gli ultimi 8 bit:

varB (byte)  : 11111111 
promoted to int : 11111111 11111111 11111111 11111111 
shift right 6 : 00000011 11111111 11111111 11111111 
cast to byte : 11111111 

È possibile utilizzare il bit-e gestore & per mascherare il bit indesiderati prima dello spostamento. Bit-anding con 0xFF mantiene solo gli 8 bit meno significativi.

varB = (byte) ((varB & 0xFF) >>> 6); 

Ecco cosa succede ora:

varB (byte)  : 11111111 
promoted to int : 11111111 11111111 11111111 11111111 
bit-and mask : 00000000 00000000 00000000 11111111 
shift right 6 : 00000000 00000000 00000000 00000011 
cast to byte : 00000011 
4

Perché thats come mutevoli per i byte in Java è definito nel linguaggio: https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.19.

L'essenza è che i tipi più piccoli di int sono ampliati in modo silenzioso a int, spostati e quindi ristretti indietro.

Il che rende la singola linea in modo efficace l'equivalente di:

byte b = -1;  // 1111_1111 
int temp = b;  // 1111_1111_1111_1111_1111_1111_1111_1111 
temp >>>= 6;  // 0000_0011_1111_1111_1111_1111_1111_1111 
b = (byte) temp; // 1111_1111 

Per spostare solo il byte è necessario effettuare la conversione allargamento esplicitamente te stesso con la semantica non firmati (e la conversione restringimento deve essere manualmente, troppo) :

byte b = -1;   // 1111_1111 
int temp = b & 0xFF; // 0000_0000_0000_0000_0000_0000_1111_1111 
temp >>>= 6;   // 0000_0000_0000_0000_0000_0000_0000_0011 
b = (byte) temp;  // 0000_0011 
Problemi correlati