次の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、 に切り捨てられます。0xffbyte
byte d = (byte) (b >>> 4);
bは最初に整数 に符号拡張され、次に にキャストされて-15 = 0xfffffff1右にシフトされ0x0fffffff、 に切り捨てられます。0xffbyte
(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).