Javaの評価のしくみ
解決済
回答 1
投稿
- 評価
- クリップ 0
- VIEW 743
int i = 2;
System.out.println(i * i + ++i);
実行結果
7
上記の実行結果になる理由を教えてください。
「i * i」が評価されて「4」に置き換わり、そのあと「++i」が評価されて「3」に置き換わったから(この時点で「4 + 3」)でしょうか?
「i * i」のふたつの「i」が評価されて「2」に置き換わり、そのあと「++i」が評価されて「3」に置き換わったから(この時点で「2 * 2 + 3」)でしょうか?
あるいは、ほかの理由があるのでしょうか?
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+8
仕様は
「i * i」が評価されて「4」に置き換わり、そのあと「++i」が評価されて「3」に置き換わったから(この時点で「4 + 3」)
ということになります。
厳密な仕様は言語仕様の15.7(java10)に書いてあります。
https://docs.oracle.com/javase/specs/jls/se10/html/jls-15.html#jls-15.7
大雑把に言えば
- 概ね左から右
- 演算子の計算順序は優先順位によって決まる
- 演算子の左側のオペランドが先に評価される
よってa*b+c
の場合、cよりも「a、bおよびa*bが先に計算される」と決まっています。
・・・が、言語仕様に「計算順序に依存しないようなコードの方がよくて、特に副作用は多くても一つの式で一か所だけの方がよい」とあるように、あまりこの仕様に左右されないような書き方を心がけるのが一番よいと思います。
追記:用語を用いてしゃべるとどうしても意志が伝わっているかどうかわからなくなります。自分が日本語下手なせいなのだと思います。そこで自分が頭の中にイメージしていることを図で表現してみました。
a + b + c * d
最初に優先度により次のようにグルーピングされる(グルーピングしなくてもいいけど、とりあえずしてみます)
a + b + (c * d)
次に演算子+が左結合なのと、左オペランドが先に評価されることを整理すると
a
b
+
(c * d)
+
こういうイメージになる。上の方が先に評価すべきもの。
で、グルーピングした乗算式も左オペランド優先の規則に従って書けば括弧を記述する必要がなくなり
a
. b
+
. c
. . d
. *
. .
+
a + b + ++ cも同様にすると
a + b + (++c)
==>
a
. b
+
. c
. ++ .
. .
+
こんなふうに捉えています。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.09%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2018/04/13 05:30
2018/04/13 08:20
2018/04/13 11:33
x * y + ++z => (x * y) + (++z)
こう結合されます。計算の順番は
(1)+の左から計算=>(x * y)が(++z)より先
(2)*の左から計算=>xがyより先
(3)(++z)を計算
(4)最後に(x * y)と(++z)の結果を加算
そういうふうに考えます。このコメントも大雑把ですが...
2018/04/13 14:40
int i = 2;
System.out.println(i + i + i * i);
このソースコード中の「i + i + i * i」という式においても、「i + i」の部分から評価される(4に置き換わる)ということでしょうか?
2018/04/13 14:42
2018/04/13 14:51
int i=1;
int j=i/0/f();
(f()は何かprintして1を返すようにしておく)
を動かしてみると、f()が呼び出される前に例外がおきるのが観察できますよ?
2018/04/13 14:55
2018/04/13 15:00
2018/04/13 15:23
あぁ‥なるほど。
2018/04/14 03:22
たとえば、僕がひとつまえのコメントで取り上げた「i + i + i * i」という式では、「+」演算子が二回登場しています。これらは同じ演算子です。つまり同じ優先順位グループに属します。なので評価順序が結合規則に定められるのは納得できました。
しかし、「+」演算子と「*」演算子は優先順位が違います。「*」演算子のほうが高いです。なので評価順序が結合規則に定められるのが納得できませんでした。
int i=1;
int j=i/0/f();
上記のコードを実行すると、f()が呼び出される前に例外がおきました。今では僕の認識は間違っていたと思います。
では結合規則とはなんでしょうか?僕なりに本やネットで調べましたがはっきりしません。正しく理解したいので、説明して欲しいです。どうかお願いします。
2018/04/14 04:10 編集
2018/04/14 11:40
The additive operators have the same precedence and are syntactically left-associative (they group left-to-right).
ということで、+や-などのadditive operatorsは同じ優先順位であり左から右へ結合される(要するに演算順序は左の演算子から順に計算される)これが結合規則と呼ばれるものと思います。言語仕様書ではassociative lawについて特に説明してないので数学の結合規則(質問者さんが捉えておられる通り)の意味と思います。
15.7.3. Evaluation Respects Parentheses and Precedence
The Java programming language respects the order of evaluation indicated explicitly by parentheses and implicitly by operator precedence.
演算子の左オペランドから先に計算されるとあります。以上からa + b + c * dを考えると
*は+より優先順位が上なので2番目の+より*が先に演算されるのは確かなんですがそれはa+bより先には演算されません。15.7.3の規則により2番目の+の左オペランド(a+b)が必ず右側のオペランド(c*d)より先に演算されると決まっているからです。
2018/04/14 11:44
2018/04/15 05:14
1、(i + i) + i * i
結合規則により、2つ目の「i」が左の「+」演算子と結合する。
2、(i + i)+(i * i)
優先順位により、3つ目の「i」が右の「*」演算子と結合する。
3、左から順に評価する(カッコ内が先に計算されるので、2つ目の演算子の計算が最後になる)。
4、全体の評価が完了する
「i * i + ++i」の評価過程
1、(i * i) + ++i
優先順位により、2つ目の「i」が左の「*」演算子と結合する。
2、(i * i) + (++i)
優先順位により、3つ目の「i」が左のの「++」演算子と結合する。
3、左から順に評価する(カッコ内が先に計算されるので、2つ目の演算子の計算が最後になる)。
4、全体の評価が完了する
合っていますか?
2018/04/19 18:37
2018/04/19 18:56
2018/04/19 19:00
2018/04/20 23:03
概ねこの通りだと思いますがいかがでしょうか?
ルール
1,結合規則と優先順位によってグループ分けをする。
2,左右のオペランドを評価してから演算子による計算処理を行う。
3,右よりも左のオペランドを先に評価する。
「i + i + i * i」の評価過程
ルール1により「(i + i) + (i * i)」とグループ分けをする。「(i + i)」が結合規則によるもので、「(i * i)」が優先順位によるもの。それぞれひとまとまりとして考える(以降(i + i)をa、(i * i)をbと呼ぶ)。
次に、ルール2とルール3により「a」、「b」の順に評価した後、最後の「+」演算子の計算処理を行う。
そして全体の評価が完了する。
2018/04/20 23:33
本回答では「私自身がどう把握しているか」をご紹介しましたが、問題はそれを見たあなたが腑に落ちたかどうかです。自分は完全な知識があるわけでもありませんし、それを他者に分かり易く伝える能力があると過信もしてません。相手に伝わったようならよし、伝わらなかったら自分の説明が下手だったのだろうと思います。コミュニケーションによる知識・知見の伝達というのは得てしてそういうものですよね?
「人によいといってもらって安心する」のは教育の方法論としては価値があると思いますが、この場は教育の場ではないと自分は考えます。そうではなく「他のプログラマーがどういう知見・知識を持っているかに触れることができる場」だと思っています。それを自分がどうゲットするかどうかは自分自身の問題です。逆に問いかけたいのですがあなたは「納得」したのでしょうか?まだ不安な点があるのでしょうか?不安な点は何でしょうか?
納得できない点があるならそれを具体的に明記すれば知見をお持ちの方がまた価値あるコメントを付けてくださるかも知れませんよ?
わたくしが何を申し上げたいかお判りいただけるでしょうか?
2018/04/21 01:14
今思えばあまり意味のない質問だったかもしれません。
とにかく「自分(KSwordさん)の回答に書いたことにほぼ沿った内容」であれば良かったです。
疑問点や不安に思うことはもう特にありません。
ありがとうございました。