次のJavaコードの抜粋を検討してください
byte b=(byte) 0xf1;
byte c=(byte)(b>>4);
byte d=(byte) (b>>>4);
出力:
c=0xff
d=0xff
期待される出力:
c=0x0f
どうやって?1111 0001
符号なし右シフト後の0000 1111
バイナリ0x0f
のb0xff
として
int
問題は、シフト操作が行われる前に、すべての引数が最初に昇格されることです。
byte b = (byte) 0xf1;
b
署名されているため、値は -15 です。
byte c = (byte) (b >> 4);
b
は最初に整数 に符号拡張され、次に にキャストされて-15 = 0xfffffff1
右にシフトされ0xffffffff
、 に切り捨てられます。0xff
byte
byte d = (byte) (b >>> 4);
b
は最初に整数 に符号拡張され、次に にキャストされて-15 = 0xfffffff1
右にシフトされ0x0fffffff
、 に切り捨てられます。0xff
byte
(b & 0xff) >>> 4
目的の効果を得るために行うことができます。
シフト b
する前に拡張された符号だと思います。int
したがって、これは期待どおりに機能する可能性があります。
(byte)((0x000000FF & b)>>4)
Bitwise and Bit Shift Operatorsによると:
符号なし右シフト演算子 ">>>" はゼロを左端の位置にシフトしますが、">>" の後の左端の位置は符号拡張に依存します。
したがって、b >> 4
変換1111 0001
すると1111 1111
(b は負なので、 が追加されます1
) これは0xff
です。
Java は、代わりに 2 つの異なるシフト演算子を定義することによって、符号なし基本型の明示的なサポートを軽視しようとします。
質問は符号なし右シフトについて述べていますが、例では両方 (符号付きと符号なし) を行い、符号付きシフト (>>) の値を示しています。
あなたの計算は、符号なしシフト (>>>) に適しています。
byte オペランドは、シフトの前に int に昇格されます。
https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.19を参照してください。
単項数値昇格 (§5.6.1) は、各オペランドに対して個別に実行されます。(バイナリ数値昇格 (§5.6.2) はオペランドでは実行されません。)
そしてhttps://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.1
Otherwise, if the operand is of compile-time type byte, short, or char, it is promoted to a value of type int by a widening primitive conversion (§5.1.2).