このループは無期限に続きます。
char a = 100;
for(a=100; a>=0;--a)
System.out.println(a);
a が算術演算の int 値に昇格し、16 ビットの char 値から 32 ビットに拡張され、常に正のままになるために発生しますか?
それは確かに無期限にループします-そしてあなたが述べた理由は近いです。これは、満たさないa
数値を表すことができないために発生します--は署名されていません。算術アンダーフローは Java で明確に定義されており、明示されていません。以下の仕様の関連部分を参照してください。a >= 0
char
整数演算子は、オーバーフローまたはアンダーフローを決して示しません。
これは、単に値を比較する以外にオーバーフロー/アンダーフローの兆候がないことを意味します...たとえば、a
<=--a
の場合、アンダーフローが発生したことを意味します。
減算の前に、値 1 と変数の値に対してバイナリ数値昇格 (§5.6.2) が実行されます。必要に応じて、プリミティブ変換 (§5.1.3) を縮小することによって差異を縮小するか、格納する前に変数の型へのボックス化変換 (§5.1.7) を適用します。前置デクリメント式の値は、新しい値が格納された後の変数の値です。
したがって、ここには 2 つの主要なステップがあることがわかります。2 進数値の昇格と、それに続く原始的な縮小変換です。
拡張プリミティブ変換 (§5.1.2) は、次の規則で指定されているように、オペランドの一方または両方を変換するために適用されます。
- いずれかのオペランドの型が の場合
double
、もう一方は に変換されdouble
ます。- それ以外の場合、いずれかのオペランドが 型の
float
場合、もう一方は に変換されfloat
ます。- それ以外の場合、いずれかのオペランドが 型の
long
場合、もう一方は に変換されlong
ます。- それ以外の場合、両方のオペランドが type に変換されます
int
。
a
デクリメント式が扱いとして扱われint
、拡大変換を実行することがわかります。これにより、値-1を表すことができます。
縮小プリミティブ変換では、数値の全体的な大きさに関する情報が失われる可能性があり、精度と範囲も失われる可能性があります。
...
符号付き整数から整数型 T への縮小変換では、下位 n ビットを除くすべてのビットが単純に破棄されます。ここで、nは型 T を表すために使用されるビット数です。数値の大きさに関する情報が失われる可能性に加えて、 、これにより、結果の値の符号が入力値の符号と異なる場合があります。
下位nビットのみを保持するということは、int
式の下位 16 ビットのみa - 1
が保持されることを意味します。ここでは-1は0b11111111 11111111 11111111 11111111なので、下位の0b11111111 11111111だけが保存されます。char
は符号なしであるため、これらすべてのビットが結果に寄与し、65535が得られます。
ここで何か気づきましたか?基本的に、これは Java 整数演算がモジュラーであることを意味します。この場合、係数は2^16または65536です。これchar
は が 16 ビットのデータ型であるためです。-1 (mod 65536) ≡ 65535であるため、デクリメントはラップアラウンドします。
いいえ。char
値は符号なしです。値が 0 を下回ると、約 65535 に戻ります。
と交換char
しbyte
ます-それでうまくいきます。
他の人が言ったようにchar
、Java の型は署名されていないため、a >= 0
常に true になります。0にa
達してからもう一度デクリメントすると、65535 になります。ひねくれ者になりたい場合は、次のように 101 回の反復後にループを終了するように記述できます。
char a = 100;
for(a=100; a<=100;--a)
System.out.println(a);
コードレビュー担当者は、そのような恐ろしいことを書いたことであなたを引き裂くフィールドデイを過ごすことができます. :)