|
|
|
|
グループ | 演算子 | 概要 | 例 | 結合 | 説明 | |
---|---|---|---|---|---|---|
一次式 | ( ) new . [] |
優先する式 | (1 + 2) |
|||
新規生成 | new 型[] |
左 | →配列生成 →クラスのインスタンス生成 |
|||
メンバー | obj.value |
→フィールドアクセス・メソッド呼び出し | ||||
配列 | array[0] |
→配列 | ||||
後置式 | ++ -- | 後置inc/dec | n++ |
左 | 後置インクリメント・デクリメント | |
単項演算子 | ++ -- + - ~ ! ( ) |
前置inc/dec | ++n |
右 | 前置インクリメント・デクリメント | |
符号 | +n |
正符号・負符号 | ||||
ビット否定 | ~n |
ビット反転 | ||||
論理否定 | !b |
trueをfalseに、falseをtrueにする | ||||
キャスト | (クラス)obj |
|||||
乗除演算子 | * / % | 乗算・除算・剰余 | m * n |
左 | ||
加減演算子 | + - | 加算・減算 | m + n |
左 | ||
文字列連結 | string + n |
左 | →文字列結合 | |||
シフト演算子 | << >> >>> | ビットシフト | n << r |
左 | →シフト演算の注意 | |
関係演算子 | < > <= >= instanceof |
大小比較 | m < n |
左 | ||
型比較 | obj instanceof クラス |
→instanceof | ||||
等価演算子 | == != |
等価 不等価 |
m == n |
左 | →equals()との違い | |
ビット論理演算子 | & | ビットAND | m & n |
左 | ビット単位の論理積 | →booleanの場合 |
^ | ビットXOR | m ^ n |
左 | ビット単位の排他的論理和 | ||
| | ビットOR | m | n |
左 | ビット単位の論理和 | ||
条件AND演算子 | && | 条件AND | b1 && b2 |
左 | ||
条件OR演算子 | || | 条件OR | b1 || b2 |
左 | ||
条件演算子 | ? : | 条件 | b ? m : n |
右 | 三項演算子 | |
代入演算子 | = *= /= %= += -= <<= >>= >>>= &= ^= |= |
代入 | m = n |
右 | →複合代入演算子 |
C言語/C++のカンマ演算子は、Javaには無い。
→文字列内に書かれている演算(式)を解釈・計算するライブラリー
演算子はオペレーター(operator)、演算対象(値・項)をオペランド(operand)と言う。
単項演算子は、オペランドが1つしかない演算子。例えば「-
n」とか「n++
」とか。
二項演算子は、オペランドが2つある演算子。例えば「a +
b」とか「obj instanceof
クラス」とか。
三項演算子は、オペランドが3つある演算子。Javaでは条件演算子「b ?
m :
n」しか無い。
演算子を組み合わせたものを「式」と呼び、その計算を行うことを「評価」と呼ぶことがある。
結合(左結合・右結合)は、式の中に同一優先順位の演算子が並んでいるときに どちらを先に計算するかの順序決め。
左結合の例:「a + b + c」…加算演算子「+」は左結合なので、左側から先に計算される。すなわち「a + b」が行われてからcが加算される。
右結合の例:「a = b = c」…代入演算子「=」は右結合なので、右側から先に評価される。すなわち「b = c」が先に実行され、次に「a =
b」が実行される。
算術演算では、型の変換が行われることがある。[/2008-08-30]
単項演算子(符号の+-や!~、配列のインデックス等)においては、intより短い整数型(byte・char・short)の演算は、intに変換(ワイドニング変換)されて行われる。
二項演算子で、オペランドのどちらかがintより大きい型(double・float・long)のとき、その型に変換されてから計算される。
また、intより小さい型ばかりであれば、intに変換されてから計算される。
例えば「byte b」と「short s」に対し「b + s」は、bがintに拡張され、sがintに拡張されてから加算される。
また、int+doubleならintがdoubleに変換されるし、int+longならintがlongに拡張される。float+longならlongがfloatに変換される。
通常の算術演算では、こうなっている方が便利。
シフト演算(<<・>>・>>>)は二項演算子であって単項演算子ではないが、特殊なので単項数値昇格の対象となっている。
したがって論理右シフト演算「>>>」は注意を要する。
例えば「byte b = -1(0xff)」に対して 右へ1ビットシフトして「0x7f」としたい場合、「b >>> 1」では望んだ結果にならない。
なぜなら、bが単項数値昇格してintに拡張されるので、0xffは0xffffffffになる。(1バイトの0xffと4バイトの0xffffffffは、2の補数表現で見ればどちらも-1を意味する。すわなち同じ値である)
この状態で「>>> 1」を行うので、結果は「0x7fffffff」となる。
ここでbyteにキャストすると一番下の1バイトだけが有効となる(0x7fffffff)ので、結果は「0xff」。0x7fにはならない。
したがって、byteのときは「(b & 0xff) >>> 1」、shortのときは「(s & 0xffff) >>> 1」としなければならない。
(ちなみに「& 0xff」を実施すれば必ず正の数となるので、「>>>」でなく「>>」でも同じ結果になる。ってことは、byteやshortに対する「>>>」なんて不要じゃん…)
Javaでは、評価順序通りに評価が行われることが保証される。(C言語では、実装依存(実装や最適化によって異なる)という事も多かった)
つまり、順序が左→右の演算子では、左の評価が終わってから右の評価を行う。
左の評価が(例外発生とかによって)完全に終了しなかった場合、右の評価は行われない。
int r = func1() + func2(); ↑もしfunc1()で例外が起きたら、func2()は絶対に実行されない。
理論上は、r2=func2()を先に呼び出して、func1()+r2という計算を行っても結果は同じになる。
(意味的には左右を入れ替えてfunc2()+func1()としたのと同じ)
しかしJavaコンパイラーはそういう事はしない。(途中で例外が起きると後のものは実行されないから、順序が重要となる)
メソッドの引数も、左側から順に評価される。
int a = 1; method(a, a = 2, a); ↓ method(1, 2, 2)と同じ
しかしまぁ、こういうのに依存したプログラミングはするべきじゃないけどね(苦笑)
「new クラス名()」によって、クラスのインスタンスを生成する。
→newの普通の使い方(new クラス())
→無名内部クラスの作り方(new クラス(){ })
→内部クラスのインスタンス化(変数.
new
クラス())
→配列のインスタンス化(new クラス[ ])
C++では引数なしコンストラクターの場合は括弧は不要なので「a = new Foo;
」という形で書くことが出来たが、Javaでは「new クラス名」の後ろに必ず括弧が必要。[2003-07-06]
シフト演算子は、整数型に対してのみ使える(浮動小数floatやdoubleでは使えない)。
Javaでは整数の符号の有無を型では管理しない(常に符号有りとして扱われる)。
(C言語やC++では「int」に「signed int」と「unsigned int」がある)
その違いが現れるのはビット右シフト演算なので、右シフト演算子には符号有り用の「>>」と符号無し用の「>>>」が存在する。[2003-07-06]
「>>」ではシフト前の符号が保存されるが、「>>>」では保存されず、最上位ビットに0が入る。
(2の補数表現においては最上位ビットが符号を意味する)
例えば-2(0xfffffffe)に対して「-2 >> 1」は「-1(0xffffffff)」になるが、「-2 >>> 1」は「0x7fffffff」になる。
ただしbyteやshortに対する「>>>」は注意を要する。→数値の昇格
シフト演算子の右オペランドは正の数しか扱えない。というか、負の数を指定して逆方向のシフトになったりはしない。
なぜなら、右オペランドに対し、左オペランドがintの場合は「&
0x1f」、longの場合は「& 0x3f」してから計算されるため。intは32bit、longは64bitなので、その範囲を超えるシフトは無意味、という判断なのだろうか。(64ビット以上シフトすれば、結果は常に0(負数の符号付き右シフトなら-1)だから)
つまり、「int a」に対する「a << -1」は、「a << (-1 & 0x1f)」なので「a << 31」と同じ。
instanceofは、オブジェクトが該当クラス(を継承している)かどうかを判断する演算子。該当クラスであれば真(true)。[2007-06-11]
interface I {} class S {} class A extends S implements I {} class B {}
のとき、「Object obj = new A();
」とすると、「obj instanceof A
」は当然trueだし、「obj instanceof S
」「obj instanceof I
」もtrue。
「Object obj = new B();
」であれば、「obj instanceof A
」「S
」「I
」は全てfalse。
対象オブジェクトがnullであれば、instanceofはfalseになる。
instanceofは、以下のような使われ方をすることが多い。
Object obj = 〜; if (obj instanceof Type) { //「obj instanceof Type」がtrueならば Type t = (Type)obj; //objはTypeのインスタンスなので、Typeへキャストできる 〜 }
※正当な参照型のナローイング変換が可能であることをチェックする目的
→insntaceofの実行速度
→パターンマッチングinstanceof [2021-03-21]
boolean同士に対するビット論理和・論理積(|,&,ついでに^)の結果は、boolean型になる。[2007-11-06]
booleanとintに対するビット論理和・論理積は計算不能(コンパイルエラー)。
「+=」や「*=」等の(単純代入演算子「=」以外の)代入演算子を 複合代入演算子と呼ぶ。
複合代入演算子は、以下のような変換をした式とほぼ等価。
「a += b
」≡「a = (Type)(a + b)
」 (Typeは、aの型。つまりキャスト)
「ほぼ等価」というのは、aに当たる部分が配列などの計算を伴う式だった場合は、その計算は一度しか行われないから。でも勿論その方が都合いいでしょう。
これも論理右シフト代入演算子「>>>=」で注意を要する。
例えば「byte b = -1」に対して「b >>>= 1」は、「b = (byte)(b >>> 1)」に展開されたのと同じ。すなわち、数値昇格の影響を受ける。
「b = (byte)((b & 0xff) >>> 1」が意図した動作となる。(つまりbyteやshortに対する「>>>=」って意味無い…)