2016-04-06 10 views
4

byteでビットシフトを使用していたときに、符号なし右シフト(>>>)を使用すると奇妙な結果になっていました。期待どおりに動作しintでは、両方の右シフトは(>>>::>>と符号なしの署名):Javaでバイトを使ったビットシフトの奇妙な動作

int min1 = Integer.MIN_VALUE>>31; //min1 = -1 
    int min2 = Integer.MIN_VALUE>>>31; //min2 = 1 

をしかし、私はbyteと同じことを行う際に、奇妙なことは、符号なし右シフトして起こる:

byte b1 = Byte.MIN_VALUE; //b1 = -128 
    b1 >>= 7; //b1 = -1 

    byte b2 = Byte.MIN_VALUE; //b2 = -128 
    b2 >>>= 7; //b2 = -1; NOT 1! 
    b2 >>>= 8; //b2 = -1; NOT 0! 

コンパイラがbyteを内部でintに変換している可能性がありますが、その動作を説明するには十分ではないようです。

ビットシフトがJavaでバイトと同じように動作するのはなぜですか? byteshortcharため

答えて

4

bytepromotedint前にパフォーマンスビット演算であるので、これはまさに起こります。したがって、7ビットまたは8ビットの右シフトが依然として7番目のビット1を残し、その結果が負の値にbytenarrowedある

11111111 11111111 11111111 10000000 

int -128のように提示されます。

は比較:b & 0xFFことで

System.out.println((byte) (b >>> 7));   // -1 
System.out.println((byte) ((b & 0xFF) >>> 7)); // 1 

、すべての最高のビットが前にシフトをクリアしているので、期待通りの結果が生成されます。

+1

「0xFF」を使用することは正しい解決策です。 +1。なぜ私はそれを提案していないのか分からない。 –

2

シフト演算子は常にintで行われます。

そのため、実際にシフトされた値は、あなたが何を本当にやっていることは、鋳造、その後、右に上記の値に7ヶ所をb2 >>= 7;シフトしているんこの

int b = 0b11111111_11111111_11111111_10000000; 

のように見えますint-128、あります最後の8ビットのみを考慮してbyteに戻します。私たちは、バイトに、この背中を変換すると

右に7桁をシフトした後、我々は

 0b11111111_11111111_11111111_11111111; 

を取得し、我々はbyte型が署名されているので、-1である、ちょうど11111111を取得します。

回答を得たい場合は、記号の拡張子なしで31箇所を移動できます。

byte b2 = Byte.MIN_VALUE; //b2 = -128 
b2 >>>= 31; 
System.out.println(b2); // 1 
0

JLS 15.19 Shift Operatorsを参照してください:(5.6.1)

単項数値昇格は別に、各オペランドに対して行われます。

5.6.1 Unary Numeric Promotionで:

オペランドは、コンパイル時の型バイトの短い、またはchar場合、それは拡大プリミティブ変換

によってint型の値に昇格されます

したがって、byteオペランドはシフトする前にintに昇格されます。値-12811111111111111111111111110000000です。

シフトした後、下位8ビットはすべて1であり、byteに割り当てるときに、縮小プリミティブ変換が発生します。 JLS 5.1.3 Narrowing Primitive Conversionを参照:

Tは、単にすべてが、nは型T.

を表すために使用されるビットの数である N最下位ビットを破棄一体型の符号付き整数の縮小変換