質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

1回答

1092閲覧

Javaの評価のしくみ

nom_0124

総合スコア23

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2018/04/12 18:04

Java

1int i = 2; 2System.out.println(i * i + ++i);

実行結果
7

上記の実行結果になる理由を教えてください。
「i * i」が評価されて「4」に置き換わり、そのあと「++i」が評価されて「3」に置き換わったから(この時点で「4 + 3」)でしょうか?
「i * i」のふたつの「i」が評価されて「2」に置き換わり、そのあと「++i」が評価されて「3」に置き換わったから(この時点で「2 * 2 + 3」)でしょうか?
あるいは、ほかの理由があるのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

仕様は

「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 . ++ . . . +

こんなふうに捉えています。

投稿2018/04/12 19:15

編集2018/04/19 10:00
KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nom_0124

2018/04/12 20:30

「*」演算子よりも「++」演算子のほうが優先順位は高いと思いますが、この場合、計算順序に影響しないのでしょうか?
hichon

2018/04/12 23:20

演算子の計算順序は優先順位と結合規則で決まります。「+」演算子は左結合のため、左側の「i * i」が先に評価されます。
KSwordOfHaste

2018/04/13 02:33

計算順序は優先順位によって決まるというのは大雑把すぎる説明でしたね。hichonさんコメントにある結合順位が演算子の優先順位によって決まります。この例では+より++の方が優先順位が高く+より*が優先順位が高いので x * y + ++z => (x * y) + (++z) こう結合されます。計算の順番は (1)+の左から計算=>(x * y)が(++z)より先 (2)*の左から計算=>xがyより先 (3)(++z)を計算 (4)最後に(x * y)と(++z)の結果を加算 そういうふうに考えます。このコメントも大雑把ですが...
nom_0124

2018/04/13 05:40

例えば int i = 2; System.out.println(i + i + i * i); このソースコード中の「i + i + i * i」という式においても、「i + i」の部分から評価される(4に置き換わる)ということでしょうか?
KSwordOfHaste

2018/04/13 05:51

その例だと先頭のi+iが先に評価されるのかi*iがそれより先に評価されるかわかりにくいと思います。javapでbyte codeを見ても確認できますが、例えば int i=1; int j=i/0/f(); (f()は何かprintして1を返すようにしておく) を動かしてみると、f()が呼び出される前に例外がおきるのが観察できますよ?
fuzzball

2018/04/13 05:55

a() + b() + c() * d() でいいですね。
KSwordOfHaste

2018/04/13 06:00

最初そう書こうと思ったんですが、よく見ると質問者さんは+の演算が先かc()、d()、*が先かといったことを質問しておられたので、a(), b(),...でprintしてもそれが観察できないなぁと思い、言語仕様を持ち出して回答してみました。上のコメントは演算子が実行されている順番を知る手軽な方法として0割りが使えるなぁと思ってのことです。
fuzzball

2018/04/13 06:23

>>演算子が実行されている順番 あぁ‥なるほど。
nom_0124

2018/04/13 18:22

僕は結合規則のことを「同じ優先順位グループに属する演算子のあいだに成り立つこと」と思っていました。 たとえば、僕がひとつまえのコメントで取り上げた「i + i + i * i」という式では、「+」演算子が二回登場しています。これらは同じ演算子です。つまり同じ優先順位グループに属します。なので評価順序が結合規則に定められるのは納得できました。 しかし、「+」演算子と「*」演算子は優先順位が違います。「*」演算子のほうが高いです。なので評価順序が結合規則に定められるのが納得できませんでした。 int i=1; int j=i/0/f(); 上記のコードを実行すると、f()が呼び出される前に例外がおきました。今では僕の認識は間違っていたと思います。 では結合規則とはなんでしょうか?僕なりに本やネットで調べましたがはっきりしません。正しく理解したいので、説明して欲しいです。どうかお願いします。
hichon

2018/04/13 19:11 編集

すみません。上で「演算子の計算順序は優先順位と結合規則で決まります。」と書きましたが正確ではありませんでした。演算子の優先順位と結合規則は、演算子をどの項目に適用するか決めるもので、実際の評価順序とは関係ありません。「i + i + i * i」という式は、優先順位と結合規則により「(i + i) + (i * i)」と解釈され、その後の評価は左から右の順に行われます。
KSwordOfHaste

2018/04/14 02:40

15.18. Additive Operators 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)より先に演算されると決まっているからです。
nom_0124

2018/04/14 20:14

「i + i + i * i」の評価過程 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、全体の評価が完了する 合っていますか?
nom_0124

2018/04/19 09:37

どうでしょう?
退会済みユーザー

退会済みユーザー

2018/04/19 09:56

まだ終わってなかったのね
KSwordOfHaste

2018/04/19 10:00

言葉で伝える自信なくなってきたので、絵を書きました。回答をごらんいただければと思います。
nom_0124

2018/04/20 14: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」の順に評価した後、最後の「+」演算子の計算処理を行う。 そして全体の評価が完了する。
KSwordOfHaste

2018/04/20 14:33

少なくとも私には「あなたがどう理解しているか」「どんな場合でも正しく評価順序が把握できるほどこの仕様を把握したか」正確には保証できません。なんとなればあなたがコメントしておられることは自分の回答に書いたことにほぼ沿った内容にすぎないからです。「それでいいと思います」というのは簡単ですが、正直言うとそういうコメントは気休めのようなものでしかないのでは? 本回答では「私自身がどう把握しているか」をご紹介しましたが、問題はそれを見たあなたが腑に落ちたかどうかです。自分は完全な知識があるわけでもありませんし、それを他者に分かり易く伝える能力があると過信もしてません。相手に伝わったようならよし、伝わらなかったら自分の説明が下手だったのだろうと思います。コミュニケーションによる知識・知見の伝達というのは得てしてそういうものですよね? 「人によいといってもらって安心する」のは教育の方法論としては価値があると思いますが、この場は教育の場ではないと自分は考えます。そうではなく「他のプログラマーがどういう知見・知識を持っているかに触れることができる場」だと思っています。それを自分がどうゲットするかどうかは自分自身の問題です。逆に問いかけたいのですがあなたは「納得」したのでしょうか?まだ不安な点があるのでしょうか?不安な点は何でしょうか? 納得できない点があるならそれを具体的に明記すれば知見をお持ちの方がまた価値あるコメントを付けてくださるかも知れませんよ? わたくしが何を申し上げたいかお判りいただけるでしょうか?
nom_0124

2018/04/20 16:14

理解できているか不安だったので(日本語が下手であることが原因ではない)まとめを行いました。 今思えばあまり意味のない質問だったかもしれません。 とにかく「自分(KSwordさん)の回答に書いたことにほぼ沿った内容」であれば良かったです。 疑問点や不安に思うことはもう特にありません。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問