:最近、私はこの質問に出くわした代入演算子のチェーン理解。
この質問に答える一方で、私は、加算代入演算子の行動の私自身の理解疑う開始+=
または任意の他のoperator=
(&=
、*=
、/=
、など)。
私の質問は、変数がある場合には、a
その変更された値が評価時の表現の他の場所に反映され、その結果、所定の位置に更新され、そしてその背後にあるロジックは何ですか?下の式で 2つの式を次のように見てみてください。
式1
a = 1
b = (a += (a += a))
//b = 3 is the result, but if a were updated in place then it should've been 4
式2
a = 1
b = (a += a) + (a += a)
//b = 6 is the result, but if a is not updated in place then it should've been 4
最も内側の式が最初の式では(a += a)
評価され、値を更新しないと思われるa
ので、結果として出てくる、3
代わりに4
。
しかし、第2の式で、の値がa
更新されるので、結果は6です。
ときに我々はいると仮定すべきであるa
の値が式の他の場所に反映され、ときに我々はいけないでしょうか?
それは覚えておいてくださいa += x
本当に意味a = a + x
。理解するためのキーポイントは、そのされたほかは、左から右に評価される -であること、a
ではa + x
前に評価されますx
。
だから何の数字を出すb = (a += (a += a))
ん。まず、ルールの使用a += x
手段をa = a + x
、その後、我々は正しい順序で慎重に式を評価する起動します。
b = (a = a + (a = a + a))
なぜならa += x
手段a = a + x
b = (a = 1 + (a = a + a))
ためには、a
現在あります1
。我々は左辺を評価覚えておいてくださいa
右辺の前に(a = a + a)
b = (a = 1 + (a = 1 + a))
理由はa
まだあります1
b = (a = 1 + (a = 1 + 1))
理由はa
まだあります1
b = (a = 1 + (a = 2))
理由は1 + 1
あります2
b = (a = 1 + 2)
ので、a
今あります2
b = (a = 3)
理由は1 + 2
あります3
b = 3
ので、a
今あります3
この葉たちとa = 3
とb = 3
上記の推論など。
、のは、他の表現でこれを試してみましょうb = (a += a) + (a += a)
:
b = (a = a + a) + (a = a + a)
b = (a = 1 + 1) + (a = a + a)
、覚えている私たちは、右1の前に左の用語を評価しますb = (a = 2) + (a = a + a)
b = 2 + (a = a + a)
そしてa
今、右辺を評価2.スタートですb = 2 + (a = 2 + 2)
b = 2 + (a = 4)
b = 2 + 4
そしてa
今あります4
b = 6
これは、で私たちを残しa = 4
とb = 6
。これは、両方のプリントアウトすることによって検証することができるa
とb
のJava / JavaScriptの(両方ともここで同じ動作を持つ)で。
また、解析木として、これらの式を考えるのに役立つかもしれません。私たちが評価するときa + (b + c)
、LHSはa
RHSの前に評価されます(b + c)
。これは、ツリー構造でエンコードされています。
+
/ \
a +
/ \
b c
操作の順序は、ツリー構造にエンコードされた-私たちは、もはや任意の括弧を持っていないことに注意してください。私たちは、ツリー内のノードを評価するとき、私たちは中にノードの子を処理固定順(すなわち、左から右用+
)。我々は、ルートノードを処理するとき、例えば+
、我々は、左サブツリーを評価a
右サブツリーの前に(b + c)
かかわらず(括弧が解析ツリーにも存在しないため)右サブツリーを括弧で囲まれているかどうかの、。
このため、Javaの/ JavaScriptはないではない、常にあなたは算術のために教えられてきた可能性があるルールとは対照的に、最初の「最もネストされた括弧を」評価します。
参照してください。Java言語仕様を:
15.7。評価順序
Javaプログラミング言語の保証は、演算子のオペランドは、特定の中で評価されるように見えることを評価順、左から右へ、すなわち、。
...15.7.1。左ハンドオペランドファーストを評価
二項演算子の左側のオペランドは完全に右の任意の部分の前に評価されるようにオペランドを評価されて表示されます。
オペレータは、次いで、化合物代入演算子(§15.26.2)、左側の評価であり、オペランドの両方左オペランド意味する変数を記憶し、暗黙のバイナリ操作で使用するためにその変数の値をフェッチし、保存含まれている場合。
:あなたの質問に似てより多くの例は、次のような、JLSのリンク部分で見つけることができます
例15.7.1-1。左側のオペランドである最初に評価
次のプログラムでは、*演算子は、変数と同一の変数への参照を含む右側のオペランドに割り当てが含ま左側のオペランドを有します。参照した値は、割当てが最初に発生したという事実を反映します。
class Test1 { public static void main(String[] args) { int i = 2; int j = (i=3) * i; System.out.println(j); } }
このプログラムは出力を生成します。
9
6の代わりに9生成する*オペレータの評価のために許可されていません。