|
|
演算子 |
H.Kamifuji . |
Javaでは2つまたは3つの値を対象として様々な演算を行うための演算子が用意されています。演算子には加算や減算などの四則演算を行うものや値を比較するものなどがあります。ここでは各演算子の使い方について詳しく確認していきます。 当ページでは、Linux CentOS7 の Gnome で動作テストしています。 現在(2021/08)では、JDK-16.0.2 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2021/11)では、JDK-17.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2023/04)では、JDK-20.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2024/10)では、JDK-23 にアップされています。一部、上位互換について、見直しを行っていきます。 |
|
算術演算子は数値を計算する場合に使用します。次のようなものが用意されています。
上記の算術演算子は演算の対象(これをオペランドとも言います)が2つあり、演算を行うと数値の結果を得ることができます。 例えば次のように使用します。 int num; num = 10 + 4; // num = 14 num = 9 - 2; // num = 7 num = 3 * 8; // num = 24 num = 7 / 3; // num = 2 num = 7 % 3; // num = 1演算を行った結果、演算子を含む式が演算を行った結果となりますので、演算を行った結果を変数に代入して利用することが可能となります。 整数を整数で割った場合には商も剰余も整数となります。例えば7を3で割ると商が2で余りが1です。17を5で割れば商が3で余りが2となります。この時の商が「/」演算子の結果となり、余りが「%」演算子の結果となります。 浮動小数点数に対する演算整数と整数に対する演算を行った場合は得られる結果も整数となりますが、演算子の対象の値がどちらか一つでも浮動小数点数の場合には演算の結果得られる値も浮動小数点数となります。double d; d = 10 / 8 // d = 1.0 d = 10.0 / 8; // d = 1.25 d = 10 / 8.0; // d = 1.25 d = 10.0 / 8.0; // d = 1.25「10 / 8」のように両方とも整数だった場合には結果も整数となります。この場合結果は「1」となりますがdouble型の変数に代入していますので出力すると「1.0」となります。そして「10.0 / 8」などどちらか一つでも浮動小数点数であった場合は得られる結果も浮動小数点数となります。この場合は「1.25」となります。 ※実際には演算が行われる前に演算子の対象となる値のデータ型の変換が行われてから演算が行われます。異なるデータ型の演算を行ったりした場合に、結果がどのようなデータ型になるかについての詳細は「演算の時の型変換ルール」を参照して下さい。 サンプルプログラム下記のサンプルを実行してみよう。class JSample1_1{ public static void main(String args[]){ System.out.println(10 + 4); System.out.println(9 - 2); System.out.println(3 * 8); System.out.println(7 / 3); System.out.println(7 % 3); double d; d = 10 / 8; System.out.println(d); d = 10.0 / 8.0; System.out.println(d); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample1_1 14 7 24 2 1 1.0 1.25 [xxxxxxxx@dddddddddd Ope]$ |
単項演算子は数値の正と負を反転させるために使用します。次のようなものが用意されています。
どちらの演算子も算術演算子でも使われたものですが、単項演算子として使用する場合は演算の対象が一つとなります。単項マイナス演算子は演算子の右側の値の正と負を反転させます。 例えば次のように使用します。 int n1, n2, n3; n1 = 10; n2 = -n1; // n2 = -10 n3 = -8変数「n2」の前に単項マイナス演算子の「-」を付けることで、演算子の右側にある値の正と負を反転させます。結果として「- n1」は「-10」となりますので変数「n2」には「-10」が代入されます。また変数の前ではなく単に数値の前に付けることで負の値であることを表すこともできます。 なお「+」も用意されていますが特に何も行いません。 int n1, n2; n1 = 10; n2 = +n1; // n2 = 10あくまで「-」演算子の反対の意味を持つものとして用意されているだけのようです。 short型、byte型、char型の値に対して単項マイナス演算子を使う場合には注意が必要です。詳しくは「演算の時の型変換ルール」を参照して下さい。 では簡単なサンプルで試してみます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample2_1{ public static void main(String args[]){ int n1, n2; n1 = 10; n2 = - n1; System.out.println(n2); n2 = + n1; System.out.println(n2); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample2_1 -10 10 [xxxxxxxx@dddddddddd Ope]$単項マイナス演算子を付けることで、演算子の右側の符号が反転していることが確認できます。 |
四則演算を行う上で特に注意すべきなのが除算と剰余の演算についてです。ここではそれぞれの注意点を見ていきます。 除算除算の際に注意全き点は0で割ってしまうこと(0除算)です。例えば次のサンプルを試してみて下さい。サンプルプログラム下記のサンプルを実行してみよう。class JSample3_1{ public static void main(String args[]){ int n; n = 3 / 0; System.out.println(n); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample3_1 Exception in thread "main" java.lang.ArithmeticException: / by zero at JSample3_1.main(JSample3_1.java:5) [xxxxxxxx@dddddddddd Ope]$コンパイルエラーにはなりませんが実行時に「java.lang.ArithmeticException: / by zero」と言うエラーとなります。これは整数を0で割った場合のエラーです。 例えばユーザーに入力してもらった数値で除算を行うようなプログラムなど、事前にどんな数値を使って除算が行われるか分からないようなプログラムを作成する場合は、0で割られないようにチェックするようにしなければなりません。 ただしこのエラーが発生するのは整数を0で除算した場合です。浮動小数点数を0で除算した場合や、整数を0.0で除算した場合には違った結果となります。次のサンプルを試してみて下さい。 サンプルプログラム下記のサンプルを実行してみよう。class JSample3_2{ public static void main(String args[]){ double d; d = 3.1 / 0; System.out.println(d); d = 3 / 0.0; System.out.println(d); d = -3.1 / 0; System.out.println(d); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample3_2 Infinity Infinity -Infinity [xxxxxxxx@dddddddddd Ope]$今度はエラーとはなりません。計算した結果を出力すると「Infinity」となりました。「Infinity」はdouble型の無限大の値を文字列として出力させた時に表示されるものです。「-Infinity」は負の無限大です。このように整数の場合と浮動小数点数の場合とで結果が異なりますので注意が必要です。 剰余剰余の場合も除算と同じように整数を0で割った余りを計算すると実行時エラーとなります。サンプルプログラム下記のサンプルを実行してみよう。class JSample3_3{ public static void main(String args[]){ int n; n = 3 % 0; System.out.println(n); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample3_3 Exception in thread "main" java.lang.ArithmeticException: / by zero at JSample3_3.main(JSample3_3.java:5) [xxxxxxxx@dddddddddd Ope]$コンパイルエラーにはなりませんが実行時に「java.lang.ArithmeticException: / by zero」と言うエラーとなります。 では次に浮動小数点数を0で除算した剰余や、整数を0.0で除算した剰余を計算してみます。次のサンプルを試してみて下さい。 サンプルプログラム下記のサンプルを実行してみよう。class JSample3_4{ public static void main(String args[]){ double d; d = 3.1 % 0; System.out.println(d); d = 3 % 0.0; System.out.println(d); d = -3.1 % 0; System.out.println(d); } }上記をコンパイルした後で実行すると次のように表示されます。 ![]() [xxxxxxxx@dddddddddd Ope]$ java JSample3_4 NaN NaN NaN [xxxxxxxx@dddddddddd Ope]$今度はエラーとはなりません。計算した結果を出力すると「NaN」となりました。「NaN」は定義済みの定数で正常な数値ではないという意味になります(NaNはNot a Numberの意味で非数などと言われます)。ある値が「NaN」なのかどうかは単純な比較では調べられず専用のメソッドなどを使うなど扱いには注意が必要です。 除算と剰余についてはここまで記載したように0除算を行わないように注意してプログラムを記述するようにして下さい。 |
既に確認した算術演算子やその他の演算子を使用する時に、1つの式の中に複数の演算子があった場合を考えてみます。次の例を見て下さい。 int num; num = 10 + 5 * 4;このような場合、どのように計算が行われるのかは二つの可能性があります。まずは10と5の加算が先に行われ、次に加算の結果と4の乗算が行われる場合です。 1) 10 + 5 = 15 2) 15 * 4 = 60 3) num = 60この場合は、変数「num」に60が代入されます。もう一つは5と4の乗算が先に行われ、次に乗算の結果と10の加算が行われる場合です。 1) 5 * 4 = 20 2) 10 + 20 = 30 3) num = 30このようにどの演算が先に行われるのかによって式全体の結果が異なってきます。 演算がどの順番で行われるのかは演算子の優先順位と結合規則によって決まります。優先順位はどの演算が先に行われるのかを決定するのに使われ、結合規則は優先順位が同じ演算子だった場合にどの演算が先に行われるのかを決定するのに使います。 演算子の優先順位と結合規則は次の通りです。 優先順位 高い ------------------------------------------------ 左 (引数) [配列添字] . ++ --(後置き) 右 ! ~ + - (単項演算子) ++ --(前置き) 右 new (型) 左 * / % 左 + - (算術演算子) 左 << >> >>> 左 > >= < <= instanceof 左 == != 左 & 左 ^ 左 | 左 && 左 || 右 ?: 右 = ope= ------------------------------------------------ 優先順位 低い※ ope= は「+=」「-=」「*=」「/=」「%=」「<<=」「>>=」「>>>=」「&=」「|=」「^=」のことです。 上に書かれているほど優先順位が高く、下になるほど優先順位は低くなります。同じ行に書かれている演算子は優先順位に違いはありません。 例として「*」と「+」を見てください。「*」の方が「+」よりも上に書かれていますので「*」の方が優先順位が高くなっています。その為、同じ式の中で「*」と「+」の2つの演算子があった場合にはまず先に「*」を使った演算が行われます。 次の例を見てください。 int num; num = 10 + 5 * 4;上記の例では、先に「5 * 4」の演算が行われ、そして次に「10 + 20」の演算が行われます。そして最後に「=」によって変数「num」に30が代入されます。今まで特に意識せずに使ってきましたが「=」も演算子の一つでありそして最も優先順位が低い演算子です。その為「=」演算子による代入は最後に行われます。 次に優先順位が同じ演算子があった場合です。例えば「+」と「-」は同じ優先順位です。優先順位が同じ場合には演算子の結合規則に従います。先ほどの一覧の各行の一番左に書かれているのが結合規則です。左の場合は左結合、右の場合は右結合と呼ばれます。演算子が左結合の場合には左から順に、右結合の場合には右から順に演算が行われます。 次の例を見てください。 int num; num = 10 + 5 - 4;今回の場合、「+」と「-」は優先順位が同じです。そして左結合の演算子のためまず「10 + 5」の演算が先に行われ、そして次に「15 - 4」の演算が行われます。そして最後に「=」によって変数「num」に11が代入されます。 今後出てくる各演算子を記述する上で、演算子の優先順位がどのようになっているのかを常に意識して記述するようにして下さい。 では簡単なサンプルで試してみます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample4_1{ public static void main(String args[]){ int n1, n2; n1 = 10 * 5 + 4; n2 = 4 + 10 * 5; System.out.println(n1); System.out.println(n2); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample4_1 54 54 [xxxxxxxx@dddddddddd Ope]$記述した順番に関わり無く演算子の優先順位によってどの演算が先に行われるのかが決まっていることが確認できます。 |
一つの式の中に複数の演算子が含まれていた場合は演算子の優先順位と結合規則に従って演算されることは前のページでご説明しました。ここでは演算子の優先順位に関わらず特定の演算を優先させたい場合の方法を確認します。 次の例を見てください。 int num; num = 10 + 5 * 4;優先順位に従えば「*」の方が「+」よりも優先順位が高いためまず「5 * 4」の演算が先に行われます。ここで「10 + 5」の方を先に演算させたい場合には括弧()を使って次のように記述します。 int num; num = (10 + 5) * 4;括弧で囲まれた中の演算は、優先順位に関係なく優先的に行われます。よって先に「10 + 5」が演算され、次に「15 * 4」が演算されることになります。 括弧の中に複数の演算子が含まれていた場合には、括弧の中だけで演算子の優先順位や結合規則を使って演算される順番が決まります。 int num; num = (10 + 8 / 2) * 4;上記の場合はまず括弧の中の「10 + 8 / 2」が演算されますが、この中には「+」と「/」の二つの演算子が含まれているため優先順位から先に「8 / 2」が演算されます。 また括弧の中にさらに括弧を記述することもできます。 int num; num = ((10 + 8) / 2) * 4;括弧の中に括弧がある場合でも考え方は同じです。外側の括弧の中にある「(10 + 8) / 2」が演算されますが、この式には括弧が含まれているため括弧の中の「10 + 8」がまず最初に演算されます。 このように式の中の一部分を括弧でくくることで、優先的に演算を行わせることができるようになります。 では簡単なサンプルで試してみます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample5_1{ public static void main(String args[]){ int num; num = 10 + 8 / 2 * 4; System.out.print("10 + 8 / 2 * 4 = "); System.out.println(num); num = (10 + 8 / 2) * 4; System.out.print("(10 + 8 / 2) * 4; = "); System.out.println(num); num = ((10 + 8) / 2) * 4; System.out.print("((10 + 8) / 2) * 4 = "); System.out.println(num); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample5_1 10 + 8 / 2 * 4 = 26 (10 + 8 / 2) * 4; = 56 ((10 + 8) / 2) * 4 = 36 [xxxxxxxx@dddddddddd Ope]$括弧を記述することで優先順位が変更されていることが確認できます。 |
演算の中でも数値を1つだけ増加することと1つだけ減少させる処理は比較的多く使用されます。「+」演算子や「-」演算子を使って記述すると次のようになります。 int num = 7; num = num + 1;変数「num」に代入されている値と1を加算し、その結果を改めて変数「num」に格納しています。1つだけ減らす場合も「-」演算子を使って同じように記述することができます。 このように1だけ増加する、又は1だけ減算するために用意された演算子がインクリメント演算子(++)とデクリメント演算子(--)です。
例えば先ほどの例は次のように書き換えることができます。 int num = 7; num++;同じように変数の値を1つだけ減らす場合には次のように記述することができます。 int num = 7; num--;「++」演算子や「--」演算子は対象となる変数の値を変化させますので、演算結果を変数に代入する必要はありません。 なお「a++」と記述する代わりに「++a」と記述することもできますが、結果が異なる場合があります。詳しくは次のページの「前置と後置」で解説します。 では簡単なサンプルで試してみます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample6_1{ public static void main(String args[]){ int num; num = 10; System.out.println(num); num++; System.out.println(num); num++; System.out.println(num); num--; System.out.println(num); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample6_1 10 11 12 11 [xxxxxxxx@dddddddddd Ope]$ |
インクリメント演算子とデクリメント演算子にはそれぞれ前置と後置の二種類が用意されています。 インクリメント演算子の前置きと後置きは次のようになります。 前置: ++変数 後置: 変数++デクリメント演算子の前置きと後置きは次のようになります。 前置: --変数 後置: 変数--前置であっても後置であってもインクリメント演算子は対象の変数の値を1だけ増加させ、デクリメント演算子の場合は対象の変数の値を1だけ減少させることに違いはありません。次の例を見て下さい。 int a = 7; a++; System.out.println(a); // 8 ++a; System.out.println(a); // 9前置であっても後置であってもこのような使い方の場合には同じ結果となります。 前置と後置で結果が異なる場合では前置と後置で結果が異なる場合について確認します。次の例を見て下さい。int a = 7; int b; b = a++; System.out.println(a); System.out.println(b);後置のインクリメント演算子を使っています。この場合は次のように実行されます。 int a = 7; int b; b = a; a = a + 1; System.out.println(a); // 8 System.out.println(b); // 7後置のインクリメント演算子の場合、まずインクリメント演算子が書かれていないかのように文が実行されます。今回の場合であれば変数「b」に変数「a」を代入していますので数値の7が変数「b」に代入されます。それから変数「a」の値を1だけ増加させます。 では次の例を見て下さい。 int a = 7; int b; b = ++a; System.out.println(a); System.out.println(b);前置のインクリメント演算子を使っています。この場合は次のように実行されます。 int a = 7; int b; a = a + 1; b = a; System.out.println(a); // 8 System.out.println(b); // 8前置のインクリメント演算子の場合、まず対象の変数を1だけ増加させます。よって変数「a」の値が8となります。それからインクリメント演算子を除いた文の実行をします。今回の場合であれば変数「b」に変数「a」を代入していますので数値の8が変数「b」に代入されます。 今回の場合はインクリメント演算子と代入が含まれる場合でしたが、「a++;」や「--b;」などのよう文でない場合には前置と後置で結果が異なる場合がありますので注意して下さい。 では簡単なサンプルで試してみます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample7_1{ public static void main(String args[]){ int num; System.out.println("後置の場合"); num = 10; System.out.println(num++); System.out.println(num); System.out.println("前置の場合"); num = 10; System.out.println(++num); System.out.println(num); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample7_1 後置の場合 10 11 前置の場合 11 11 [xxxxxxxx@dddddddddd Ope]$ |
整数の値に対してビット単位で処理を行うために用意されているのがビット演算子です。次の演算子が用意されています。
数値を2進数の形式で表示し、各ビットに対して演算を行います。例えばint型は32ビットの値を取りますので次のように表示することができます。 0x3F30A5A5 0011 1111 0011 0000 1010 0101 1010 0101 ---- ---- ---- ---- ---- ---- ---- ---- 3 F 3 0 A 5 A 50x3F30A5A5という16進数で表記されたint型の数値は2進数で表すと00111111001100001010010110100101となります。ビット演算子を使用すると2進数で表された各ビットに対して操作を行う事ができます。 では順に確認していきます。(int型だと面倒なので8ビットのbyte型を使って確認していきます)。 ※「<<」「>>」「>>>」の3つの演算子については次のページで説明します。 ビットANDビットANDは演算子の左辺と右辺の同じ位置にあるビットを比較して、両方のビットが共に「1」の場合だけ「1」にします。次の例を見てください。byte b; b = 0x55 & 0x0F;変数「b」には0x55と0x0FのビットANDした結果が代入されます。この時、次のような処理が行われます。 01010101 = 0x55 00001111 = 0x0F -------- 00000101 = 0x050x55と0x0Fをそれぞれ2進数で表します。そして各ビットを比較し両方のビットが「1」の場合だけ「1」となり、それ以外の場合は全て「0」となります。結果として00000101(0x05)という値が変数「b」には代入されることになります。 ビットORビットORは演算子の左辺と右辺の同じ位置にあるビットを比較して、どちらか一つでもビット「1」の場合に「1」にします。次の例を見てください。byte b; b = 0x55 | 0x0F;変数「b」には0x55と0x0FのビットORした結果が代入されます。この時、次のような処理が行われます。 01010101 = 0x55 00001111 = 0x0F -------- 01011111 = 0x5F0x55と0x0Fをそれぞれ2進数で表します。そして各ビットを比較しどちらかのビットが「1」の場合は「1」に、両方のビットが「0」の場合は「0」にします。結果として01011111(0x5F)という値が変数「b」には代入されることになります。 ビットXORビットXORは演算子の左辺と右辺の同じ位置にあるビットを比較して、どちらかのビットが一つだけ「1」の場合に「1」にします。次の例を見てください。byte b; b = 0x55 ^ 0x0F;変数「b」には0x55と0x0FのビットXORした結果が代入されます。この時、次のような処理が行われます。 01010101 = 0x55 00001111 = 0x0F -------- 01011010 = 0x5A0x55と0x0Fをそれぞれ2進数で表します。そして各ビットを比較しどちらかのビット一つだけが「1」の場合には「1」に、両方のビットが「1」であるか両方のビットが「0」の場合は「0」にします。結果として01011010(0x5A)という値が変数「b」には代入されることになります。 ビットNOTビットNOTは演算子の右辺の値の各ビットを反転(0なら1に、1なら0にする)させます。次の例を見てください。byte b; b = ~0x55;変数「b」には0x55をビットNOTした結果が代入されます。この時、次のような処理が行われます。 01010101 = 0x55 -------- 10101010 = 0xAA0x55を2進数で表します。そして各ビットを「0」なら「1」に、「1」なら「0」にします。結果として10101010(0xAA)という値が変数「b」には代入されることになります。 では簡単なサンプルで試してみます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample8_1{ public static void main(String args[]){ byte b; b = 0x55 & 0x0F; System.out.print("0x55 & 0x0F = "); System.out.printf("0x%02x\n", b); b = 0x55 | 0x0F; System.out.print("0x55 | 0x0F = "); System.out.printf("0x%02x\n", b); b = 0x55 ^ 0x0F; System.out.print("0x55 ^ 0x0F = "); System.out.printf("0x%02x\n", b); b = ~0x55; System.out.print("~0x55 = "); System.out.printf("0x%02x\n", b); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample8_1 0x55 & 0x0F = 0x05 0x55 | 0x0F = 0x5f 0x55 ^ 0x0F = 0x5a ~0x55 = 0xaa [xxxxxxxx@dddddddddd Ope]$※プログラムの中で使っている「System.out.printf」は16進数の形式で画面に出力するために使用しています。 |
ビット演算子の中でも下記の3つはシフト演算子と呼ばれることもあります。
これらの3つの演算子は対象の値の各ビットを右または左へシフトします。 10進数で右または左へ数値をシフトした場合、それは数値を1/10にしたり10倍することを意味します。例えば1230を左へシフトして12300とすれば10倍したことになりますし、右へシフトして123とすれば1/10になったこととなります。同じように2進数でシフトした場合は1/2にしたり2倍したりすることを意味します。 では順に確認していきます。(int型だと面倒なので8ビットのbyte型を使って確認していきます)。 左シフト<<演算子は対象の値を指定した数だけ左へシフトします。次の例を見てください。byte b; b = 0x15 << 2;変数「b」には0x15を左へ2つシフトした値が代入されます。この場合は次のような処理が行われます。 00010101 = 0x15 -------- 00101010 = 左へ1つシフト 01010100 = 左へ2つシフト0x15を左へ2つシフトすると01010100(0x54)となります。左へシフトする場合、左側からはみ出たビットは捨てられ、シフトしたことによて空いた右側には0が詰められます。 右シフト(符号有り)>>演算子は対象の値を指定した数だけ右へシフトします。次の例を見てください。byte b; b = 0x2A >> 2;0x2Aを右へ2つシフトすると00001010(0x0A)となります。右へシフトする場合、右側からはみ出たビットは捨てられます。そしてシフトによって空いた左側には元のビットが1だった場合は1が詰められ、元のビットが0だった場合は0が詰められます。この結果、右シフトしても負の整数は符号がそのままで数値が1/2となります。 下記は最上位ビットが1だった場合の例です。 10100011 = 0xA3 -------- 11010001 = 右へ1つシフト 11101000 = 右へ2つシフト右へシフトした時に空いた一番左側のビットには、シフトする前が1だったので1で詰められています。 右シフト(符号無し)>>>演算子は対象の値を指定した数だけ右へシフトします。>>演算子との違いはシフト前の一番左のビットが何であっても右へシフトした時に一番左のビットは常に0で詰められます。次の例を見てください。byte b; b = 0xA3 >>> 2;変数「b」には0xA3を右へ2つシフトした値が代入されます。この場合は次のような処理が行われます。 10100011 = 0xA3 -------- 01010001 = 右へ1つシフト 00101000 = 右へ2つシフト0x2Aを右へ2つシフトすると00101000(0x28)となります。この演算子の場合は、右シフトによって1/2となるということよりも純粋にビットを右へシフトさせたい場合などに使用されます。 では簡単なサンプルで試してみます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample9_1{ public static void main(String args[]){ byte b; b = 8 << 3; System.out.print("8 << 3 = "); System.out.println(b); b = -10 << 2; System.out.print("-10 << 2 = "); System.out.println(b); b = 8 >> 1; System.out.print("8 >> 1 = "); System.out.println(b); b = -20 >> 2; System.out.print("-20 >> 2 = "); System.out.println(b); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample9_1 8 << 3 = 64 -10 << 2 = -40 8 >> 1 = 4 -20 >> 2 = -5 [xxxxxxxx@dddddddddd Ope]$左へ一度シフトすると数値が2倍になり、右へ一度シフトすると1/2になっていることが分かります。 |
変数に値を代入する時に使用する代入演算子(=)はこれまでのサンプルなどでも使用してきました。
「=」の右辺に書かれた値や変数などを左辺に書かれた変数に代入します。 代入演算子は「=」の他に別の演算子と組み合わせた次のものが用意されています。
これらの演算子は変数に代入する値に何らかの演算を行って、その結果を再度同じ変数に代入する場合に便利です。次の例を見てください。 int num; num = 10; num = num + 8;変数「num」に代入されていた10に8を加えて再度変数「num」に代入しています。このような場合は次のように記述することができます。 int num; num = 10; num += 8;このように簡潔に記述することができます。 多重代入「値の代入」でも記述しましたが代入演算子は次のような記述が可能です。変数1 = 変数2 = 変数3 = 値;この時、使用されている「=」演算子は全て同じですから優先順位も同じです。そこで結合規則に従って処理が行われます。「=」演算子の結合規則は右となっているため、右から順に処理が行われます。 変数3 = 値; 変数2 = 変数3; 変数1 = 変数2;結果的に全ての変数に一番右に記述された値が代入されることになります。 単なる「=」だけではなく「+=」や「*=」の場合も同じです。 変数1 += 変数2 *= 変数3 = 値;代入演算子は全て同じ優先順位ですので、右から順に処理が行われます。 変数3 = 値; 変数2 = 変数2 * 変数3; 変数1 = 変数1 + 変数2;ただあまり多重代入を使うと分かりにくくなりますので、全ての変数に同じ値を代入するような場合以外はあまり使わない方がいいかもしれません。 では簡単なサンプルで試してみます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample10_1{ public static void main(String args[]){ int num; num = 10; System.out.println(num); num += 5; System.out.println(num); num *= 2; System.out.println(num); num /= 3; System.out.println(num); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample10_1 10 15 30 10 [xxxxxxxx@dddddddddd Ope]$ |
今後、処理を制御するための様々な方法が出てきます。その中でもある条件を満たしている時だけ実行する条件分岐や、条件が満たされている間は繰り返し同じ処理を行う繰り返し処理などが多く利用する機会が多いと思います。 詳しい解説は別のページで行いますので下記のサンプルだけ簡単に見てください。 int old = 10; if (old >= 20){ System.out.println("20歳以上です"); }else{ System.out.println("20歳未満です"); }変数「old」に代入された値を20と比較します。大きいか等しければ「20歳以上です」と画面に出力し、小さい場合には「20歳未満です」と画面に出力します。 このような条件式で使用されるのが関係演算子です。関係演算子は2つの値を比べます。大きいか小さいかまたは等しいかなどを評価し、結果として式全体がtrue又はfalse となります。 左辺 関係演算子 右辺 ^^^^^^^^^^^^^^^^^^^^ 式が評価され、結果として式がtrueかfalseとなる関係演算子として用意されているのは次の通りです。
関係演算子を含む式が正しければtrueとなり間違っていればfalseとなります。例えば 10 < 20 は正しいので 10 < 20 という式がtrueとなります。なおinstanceofは取り合えず気にしないで下さい。別のページでまた確認します。 ではそれぞれ確認してみます。 大小の比較大きさを比較する関係演算子は「<」「<=」「>」「>=」の4つが用意されています。それぞれ「小さい」「以下」「大きい」「以上」を判定しています。左辺 < 右辺 左辺 <= 右辺 左辺 > 右辺 左辺 >= 右辺次の例を見てください。 int num = 10; boolean b1, b2; b1 = num > 5; b2 = num <= 4;「num > 5」は変数「num」の値が10ですので正しいです。結果として式はtrueとなりますので変数「b1」にはtrueが代入されます。 「num <= 4」は変数「num」の値が10ですので間違いです。結果として式はfalseとなりますので変数「b2」にはfalseが代入されます。 等しいかどうかの比較等しいかどうかを判定する関係演算子は「==」「!=」の2つが用意されています。それぞれ「等しい」「等しくない」を判定しています。左辺 == 右辺 左辺 != 右辺次の例を見てください。 int num = 10; boolean b1, b2; b1 = num == 5; b2 = num != 4;「num == 5」は変数「num」の値が10ですので間違いです。結果として式はfalseとなりますので変数「b1」にはfalseが代入されます。 「num != 4」は変数「num」の値が10ですので正しいです。結果として式はtrueとなりますので変数「b2」にはtrueが代入されます。
注意する点として、等しいかどうかを判定する関係演算子の場合、対象となる値が「基本のデータ型」の場合には値そのものを比較しますが、クラスや配列などの場合には比較するものが異なります。詳しくは配列やクラスのページで解説します。
では簡単なサンプルで試してみます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample11_1{ public static void main(String args[]){ int num = 10; System.out.println("num = " + num); System.out.print("num > 5 --> "); System.out.println(num > 5); System.out.print("num <= 4 --> "); System.out.println(num <= 4); System.out.print("num == 5 --> "); System.out.println(num == 5); System.out.print("num != 4 --> "); System.out.println(num != 4); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample11_1 num = 10 num > 5 --> true num <= 4 --> false num == 5 --> false num != 4 --> true [xxxxxxxx@dddddddddd Ope]$ |
関係演算子を使うことで様々な条件を記述することができますが、さらに論理演算子を使うことで「10より大きく かつ 30より小さい」や「x が 10と等しい 又は y が20と等しい」などのように複数の条件式を組み合わせたより複雑な条件式を記述できます。 論理演算子を使った場合も結果として式がboolean型のtrue(真)かfalse(偽)のいずれかとなります。論理演算子として用意されているのは次の通りです。
論理演算子の場合には対象となる値がboolean型の値です。これはboolean型の値を指定する場合もありますが、通常は関係演算子を使った条件式などを記述します。 ではそれぞれ確認してみます。 論理積「&&」は論理積とも呼ばれ、演算子の左辺及び右辺の値が共にtrueの場合だけ全体もtrueとなります。左辺 && 右辺左辺と右辺の値による全体の値の一覧は次の通りです。
次の例を見てください。 int num = 10; boolean b; b = num > 5 && num <= 20;この場合、まず「num > 5」について判定します。結果はtrueです。次に「num <= 20」を判定します。結果はtrueです。そして&&演算子の両端の値が共にtrueですので式「num > 5 && num <= 20」はtrueとなります。 なお最後に「&&」演算子が判定されるのは「gt;」演算子や「<=」演算子と比べて優先順位が低いためです。 論理和「||」は論理和とも呼ばれ、演算子の左辺または右辺の値の少なくとも一つがtrueの場合に全体がtrueとなります。左辺 || 右辺左辺と右辺の値による全体の値の一覧は次の通りです。
次の例を見てください。 int num1 = 10; int num2 = 20; boolean b; b = num1 > 20 || num2 < 30;この場合、まず「num1 > 20」について判定します。結果はfalseです。次に「num2 < 30」を判定します。結果はtrueです。そして||演算子の両端の値の少なくとも一つがtrueですので式「num1 > 20 || num2 < 30」はtrueとなります。 なお「&&」演算子と「||」演算子の優先順位は同じではなく「&&」の方が優先順位が高くなっています。次の例を見てください。 int num1 = 30; int num2 = 10; boolean b; b = num1 > 20 || num2 < 30 && num2 %gt; 20;この場合、先に「num2 < 30 && num2 > 20」が判定されます。これはfalseとなります。次に「num1 > 20 || false」が判定されますので全体としてはtrueとなります。もし先に「num1 > 20 || num2 < 30」から判定された場合は次に「true && num2 > 20」が判定されるため全体としてはfalseとなり本当の結果とは変わってしまいます。 このように論理演算子が複数含まれるような式の場合には優先順位に注意して下さい。 論理否定「!」は論理否定とも呼ばれ、演算子の右辺の値を反転します。!右辺右辺の値による全体の値の一覧は次の通りです。
次の例を見てください。 int num = 10; boolean b; b = !(num > 20);この場合、まず「num > 20」について判定します。結果はfalseです。そして!演算子によっての式「!(num > 20)」はtrueとなります。 なお!演算子は優先順位がかなり高いので必要に応じて括弧を使って下さい。 判定される順番&&演算子や||演算子では左辺及び右辺の値を使って全体の判定を行いますが、どちらの演算子もまず左辺から判定します。左辺 && 右辺&&演算子の場合で考えてみると、まず左辺を判定します。ここで左辺がfalseだった場合には全体がfalseと確定するため右辺の判定は行いません。 左辺 || 右辺||演算子の場合もまず左辺を判定します。ここで左辺がtrueだった場合には全体がtrueと確定するため右辺の判定は行いません。 ここで順番を何故気にするのかと言えば、まず左辺から先に判定されるため左辺と右辺のどちらに何を記述するのかによって処理効率が変わる場合があります。左辺だけで結果が確定する場合が多いようにしておけば、右辺を判定する必要がなく効率的です。 また左辺で結果が確定した場合に右辺は判定されませんので、右辺にインクリメント演算子を含む式が記述されていた場合など式そのものが処理されない場合もあります。次の例を見てください。 int num1 = 30; int num2 = 25; boolean b; b = num1 > 10 || ++num2 < 40;この場合、||演算子の左辺だけで全体がtrueとなることが確定するため右辺はまったく処理されません。その為変数「num2」の値も1増えることはありません。もしも左辺がfalseだった場合には右辺も判定されるため変数「num2」の値が式を判定後に1だけ増加します。このように論理演算子を使用する場合には注意が必要となります。 では簡単なサンプルで試してみます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample12_1{ public static void main(String args[]){ int num = 30; System.out.println("num = " + num); System.out.print("num > 5 && num < 20 --%gt; "); System.out.println(num > 5 && num < 20); System.out.print("num > 20 || num < 10 --> "); System.out.println(num > 20 || num < 10); System.out.print("!(num < 20) --> "); System.out.println(!(num < 20)); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample12_1 num = 30 num > 5 && num < 20 --> false num > 20 || num < 10 --> true !(num < 20) --> true [xxxxxxxx@dddddddddd Ope]$ |
条件演算子は三項演算子とも呼ばれる演算子で条件によって処理を分けることができます。書式は次の通りです。 条件式 ? 式1 : 式2条件式の値がtrueだった場合に式1を処理し、falseだった場合に式2を処理します。 次の例を見てください。 char c; int num; num = 20; c = num >= 0 ? '正' : '負';条件式に記述された「num >= 0」を評価します。変数「num」の値が20ですので正しく条件式はtrueとなります。よって「'正'」という式が処理されます。今回の場合は単なる値が書かれただけの式ですので何もしませんが、条件演算子では実行された式の値が全体の式の値となります。よって変数「c」には式全体の値である'正'が代入されます。 条件によって処理を分ける場合、通常はif文を使って行いますが、簡単なものであれば条件演算子を使っても記述することができます。 では簡単なサンプルで試してみます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample13_1{ public static void main(String args[]){ char c; int num; num = 20; c = num >= 0 ? '正' : '負'; System.out.print(num + "は"); System.out.println(c); num = -4; c = num >= 0 ? '正' : '負'; System.out.print(num + "は"); System.out.println(c); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample13_1 20は正 -4は負 [xxxxxxxx@dddddddddd Ope]$ |
「+」演算子は算術演算子の加算や単項演算子としても使われていますが文字列に対して使用すると文字列と文字列を連結する演算子となります。 文字列1 + 文字列2次の例を見てください。 System.out.println("目覚まし" + "時計");上記では「目覚まし」と「時計」という2つの文字列を連結しています。文字列を連結するというのは左側の文字列の後ろに右側の文字列をつなげた文字列となります。よって「目覚まし時計」という文字列を画面に出力することになります。 文字列と数値の連結「数値 + 数値」の場合は加算された結果となり、「文字列 + 文字列」の場合は文字列が連結されます。では「文字列 + 数値」や「数値 + 文字列」の場合はどうなるのでしょうか。「+」演算子は左辺または右辺の値が文字列であった場合、もう片方の数値を文字列に変換して文字列を連結します。次の例を見てください。 System.out.println("200" + 9);「+」演算子の左辺が文字列なので右辺の数値は文字列に変換されます。よって次のように記述したかのように処理されます。 System.out.println("200" + "9");結果的に「2009」が画面に出力されることになります。 文字列連結の順序「+」演算子の結合規則は左ですので、式の中に複数の「+」演算子が含まれる場合は左から順に連結が行われます。次の例を見てください。 System.out.println(100 + 80 + "$");この場合、まず100と80の加算が行われます。そして次の「+」演算子の右辺は文字列ですので、先ほどの加算の結果である180と「$」が文字列連結され最終的に「180$」が画面に出力されることになります。 これを次のようにすると処理内容が変わってきます。 System.out.println("$" + 100 + 80);この場合、まず「$」と100の文字列連結が行われます。そして次の「+」演算子の左辺は文字列ですので先ほどの連結の結果である「$100」と80が文字列連結されます。最終的に「$10080」が画面に出力されることになります。 文字列を連結する場合はケアレスミスが発生しやすいので、必要であれば括弧を使うようにして演算の順序を明確にして下さい。先ほどの例は次のように括弧を使うことで先に数値の加算を行うことができます。 System.out.println("$" + (100 + 80));この場合、まず「$」と100と80の加算した結果の文字列連結が行われます。最終的に「$180」が画面に出力されることになります。 では簡単なサンプルで試してみます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample14_1{ public static void main(String args[]){ System.out.println(200 + 9); System.out.println("200" + 9); System.out.println(200 + "9"); System.out.println("200" + "9"); System.out.println(100 + 80 + "$"); System.out.println("$" + 100 + 80); System.out.println("$" + (100 + 80)); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Ope]$ java JSample14_1 209 2009 2009 2009 180$ $10080 $180 [xxxxxxxx@dddddddddd Ope]$ |
|