後置インクリメントの挙動が不明で困ってます

このQ&Aのポイント
  • Eclipse 4.7 Java 8でプログラミングをやっています。
  • 後置インクリメントの挙動がC言語の時と違っていて戸惑っています。
  • なぜそうなるのか分からないので質問しました。
回答を見る
  • ベストアンサー

後置インクリメントの挙動が不明で困ってます

 Eclipse 4.7 Java 8でプログラミングをやっています。 いまスレッドのプログラミングをやっているのですが、後置インクリメント の挙動がC言語の時と違っていて戸惑っています。 問題は、変数 idx でこの変数の値が加算されていきません。 条件演算子がある箇所で加算しているのですが、後置インクリメントでも 加算されていくはずですよね? しかしそうなりません。値は0のままです。 なぜそうなるのか分からないので質問しました。 答えられたらよろしくお願いします。 import static java.lang.System.out; import java.applet.Applet; import java.awt.Graphics; public class JavaThread4 extends Applet implements Runnable { // TODO 自動生成されたメソッド・スタブ final String HelloWorld = "Hello World"; volatile int idx; Thread helloThread = null; public void init() { idx = 0; out.println("init"); } public void paint(Graphics g) { g.drawString(HelloWorld.substring(0, idx), 30, 30); } public void start() { out.println("start"); if(helloThread == null) { helloThread = new Thread(this); helloThread.start(); } } public void run() { out.println("run"); for(;;) { try { Thread.sleep(400); }catch(InterruptedException e) { } out.println(" idx = " + idx); idx = (idx < HelloWorld.length()) ? idx++ : 0;//この部分が問題の部分です repaint(); } } }

  • Java
  • 回答数6
  • ありがとう数4

質問者が選んだベストアンサー

  • ベストアンサー
回答No.4

idx = (idx < HelloWorld.length()) ? idx++ : 0; は if ( idx < HelloWorld.length() )  idx = idx++; else  idx = 0; と同等かと思いますが 普通は、idx=idx++;なんて書かずに、idx++;と書くので気にすることはないですが たしかにC言語だと、環境かコンパイラによって挙動が違うようです。 idx=0; idx = idx++; printf("idx = %d\n" , idx); でテストしたら gcc4.1(32bitOS)だと、idx = 1 gcc4.8(64bitOS)だと、idx = 0 となりました。 なんとなくですが、 idx = idx++; で 右辺の計算結果の0を左辺のidxに代入したあとでidxインクリメントするのか 右辺の計算後に、idxをインクリメントしてから右辺の計算結果の0を左辺のidxへの代入をしているか の違いのような感じです。 (コンパイラの最適化のせいなのか、アーキテクチャの違いなのかわかりませんが) ともかく、 idx = idx++; のような挙動が不安定なコーディングは避けたほうがよいと思います。

DEADSPACE566
質問者

お礼

インクリメントが内部でどうなっているのか理解する必要がありそうです。 >右辺の計算後に、idxをインクリメントしてから右辺の計算結果の0を左辺のi>dxへの代入をしているか そういった挙動をする可能性もあるんですね。 勉強になりました。

その他の回答 (5)

回答No.6

> No.5 説明がわかりにくかったですかね。 C言語でも、No.3で言われているような 前置インクリメント、後置インクリメントの 仕様は、当然のことながら決定されていて、同様の挙動になります。 しかし、今回のような 同じ変数への 後置インクリメントと代入が同時に行われるようなコーディングをしてしまうと、コンパイラの最適化やアーキテクチャによっては 質問者様が、 > 後置インクリメントの挙動がC言語の時と違っていて戸惑っています。 と言われているような、idxがインクリメントしてしまうこともあれば No1でご回答されているように > その後 idxの評価された値(インクリメント前の値)が設定されるのでidxの値は変わりません。 といこともあるようなので、 「そもそもC言語の時点で、同じ変数にインクリと代入を同時に行って どちらが先に実行されるかわからないような、不安定なコーディングを していたのが問題では」という点を 強調したかったのです。

回答No.5

>回答No.4 superside0 >C言語だと、環境かコンパイラによって挙動が違うようです。 Javaの場合は言語仕様として挙動は決定されています、詳細は「回答No.3 amanojaku1」参照。 それは さておき >idx = (idx < HelloWorld.length()) ? idx++ : 0; ↑これを具体的に どうすれば良いのかと言えば、下記のように修正すれば良いと思われます。 idx = (idx < HelloWorld.length()) ? idx+1 : 0;

DEADSPACE566
質問者

お礼

ありがとうございます。 じつは参考書に書いてあるソースを idx = (idx < HelloWorld.length()) ? idx++ : 0; のようにしたら、この結果になったんです。 参考書には idx = (idx < HelloWorld.length()) ? idx+1 : 0; と書いてありました。 もしかしたらこのことを考慮して、こうしたの かもしれません。 これなら問題なく1加算されています。

回答No.3

処理の説明は[回答No.1 wormhole]さんの方を参照して下さい。 前置と後置で処理が違うようです。 int a = 7; int b; b = a++; ↑この場合、内部的には 下記ような処理になり b = a; a = a + 1; ↑結果は「a=8」、「b=7」になります。 int a = 7; int b; b = ++a; ↑この場合、内部的には 下記ような処理になり a = a + 1; b = a; ↑結果は「a=8」、「b=8」になります。

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.2

#1です。 ちなみにCの次のソースを試してみましたが #include <stdio.h> int main(int argc, char **argv) { int idx = 0; int length = 10; for (;;) { printf("%d\n", idx); idx = (idx < length) ? idx++ : 0; } return 0; } 延々と0が出力されます。 環境はFreeBSD-10.3で試したCコンパイラは FreeBSD clang version 3.4.1 (tags/RELEASE_34/dot1-final 208032) 20140512 gcc6 (FreeBSD Ports Collection) 6.4.0 の2つです。

DEADSPACE566
質問者

お礼

なぜなんでしょう? ちなみにC言語の環境はVS2012Express DeskTopです。 環境によって動作が違うだけなんでしょうか?

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.1

>idx = (idx < HelloWorld.length()) ? idx++ : 0;//この部分が問題の部分です 元々、問題あるコーディングかと。 idx < HelloWorld.length() が真の時には、 idxの値が評価後、idxの値がインクリメントされます。 その後 idxの評価された値(インクリメント前の値)が設定されるのでidxの値は変わりません。

DEADSPACE566
質問者

お礼

つまりインクリメントしているがidxには1が代入されないという理解で いいでしょうか? 1加算されず0が代入され、その後にインクリメントされるというわけでは ないという解釈でいいのでしょうか?

関連するQ&A

  • 後置か、それとも前置インクリメントか

    class Sum{ public static void main(String[] args){ int s = 0 , i = 1; do{ i = ++i; s = s+1; }while(i < 10); System.out.println("1から" + i + "までの和は" + s); } } 上記のプログラムについて質問なんですが、 5行目、i = ++i; の部分を i = i++; と、 後置インクリメントにしたところ、実行時何も表示されませんでした。 前置・後置インクリメントの違いも調べましたが、なぜこうなるのかわかりません。どなたか教えていただけないでしょうか? それとも、こういうのは「なぜ?」と考えるだけムダなのでしょうか?

    • ベストアンサー
    • Java
  • 後置インクリメントについて質問

    java解説書に以下のような説明がありました。この説明は、後置インクリメントについての説明です。 「xは10が代入されているとする。 y=x++ + x++ ; //最初の状態。xは10です y=10+ x++ ;//10をそのまま加算し、xを1加算します。xは11です。 y=10+ 11 ;//11をそのまま加算し、xを1加算します。xは12です。yは21になります。」 質問:上から2番目のコメント文の中で、「10をそのまま加算し」とありますが、これは何に加算するんですか?何も入ってないyに加算するということでしょうか?それとも それともxにxを加算するという意味でしょうか?参考書の書き手の意図がわかりません、、。 質問2:yが21、xが12になるプロセスは、 yにx(10)が加算される      ↓ yにx(10)を代入した(計算した)「直後」であるから、後置インクリメントによりxが1増えて、xが11になる      ↓ x(11)をyに代入 ↓ yは21になる ↓ yに11を代入した(計算した)「直後」であるから、後置インクリメントによりxが1増えて、xが12になる こういうことでしょうか? 質問3:質問2の計算プロセスのように、左辺の変数が、右辺の変数が+で繋がれていた場合、左の項から順に足されていくということでしょうか?

    • ベストアンサー
    • Java
  • 後置インクリメントの計算過程について

    後置インクリメントの計算過程について Javaに関して初めての質問となります。よろしくお願いいたします。数日前に学習し始めたばかりの超・初心者です。 現在、基本的な演算について、インクリメント・デクリメントのそれぞれ前置と後置の違いを学習したところなのですが、どうも後置の理解が完璧でないようで、仮に変数をxとした場合、式内にxが二度出てくる場合の後置の計算が理解できません。 具体的には int x, y; x = 10; y = x++ + x++; 上記でコンパイルした結果、y=21となる過程を教えていただけませんでしょうか。 私の理解では、x++は計算に使用した後にxに1を加算するので、まず y = 10 + 10 で、y = 20 となり、その後にxに1を加算してx=11が私の理解です。 よろしくお願いいたします。

    • ベストアンサー
    • Java
  • Java applet

    Java appletを使用する課題なのですが、 途中まで書いて、それから止まってしまっています。 アドバイスなど頂ければ嬉しいです。 課題は、 (1)右から左へ動く文字列左から右へ動く文字列とを表示 (2)文字列が消えたらまた出てくるようにする (3)マウスのクリックボタンを押すと止まり、離すと動きだすようにする (2)まで考えたプログラム(コンパイル、実行済)を以下に載せます。 import java.applet.Applet; import java.awt.*; import java.awt.event.*; public class SasakiYui extends Applet implements Runnable{ Thread th = null; Graphics g; int x; public void init(){ setBackground(Color.white); } public void start(){ if(th == null){ th = new Thread(this); th.start(); } } public void run(){ while(!Thread.interrupted()){ for(x=600;x>-300;x=x-5){ repaint(); try{ Thread.sleep(50); } catch(InterruptedException e){} } } } public void paint(Graphics g){ g.drawString("Happy Brithday!",x,10); g.drawString("Happy Birthday!",600-x,40); } } (3)ができるようにするには、 addMouseListener(new Mouseadapter(){ public void mousePressed(MouseEvent e){……} を使用するのだろうとは思うのですが、 ・これを組み込むのはpublic void init(){の後で良いか ・……の部分に何を書けばいいのか の2点がわかりません; よろしければ、アドバイスお願い致します!

    • ベストアンサー
    • Java
  • Javaアプレットについてですが

    Javaアプレットでボタンを押したら数字が増えるものを作っているのですがどうもうまく動きません。 ソースは下の通りです。 変更しなければいけないところがあるならお願いします。 import java.applet.Applet; import java.awt.Graphics; import java.awt.Button; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; public class Sample7 extends Applet implements Runnable, ActionListener { Button bt; int num; public void init() { bt = new Button("開始"); add(bt); bt.addActionListener(this); Thread th; th = new Thread(this); th.start(); } public void actionPerformed(ActionEvent ae) { public void run() { try{ for(int i=0; i<11; i++){ num = i; repaint(); Thread.sleep(1000); } } catch(InterruptedException e){} } } public void paint(Graphics g) { String str = num + "です。"; g.drawString(str, 50, 50); } }

    • ベストアンサー
    • Java
  • Javaを説明するには

    4枚の絵をパラパラアニメにするソースなのですが。これをわけ合って説明しなくてはならなくなってしまいました。 薄らぼんやりとはわかるのですが。どう説明したらいいのかさっぱり分かりません、どう説明すれば、分かりやすく正しく伝えられるでしょうか?>< import java.applet.Applet; import java.awt.Graphics; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class DNA extends Applet implements Runnable, ActionListener { Image image[] = new Image[4]; int[] timing = { 400,350,230,350}; Thread t; int index1 = 0; int no = 0; private static final long serialVersionUID = 1L; public void init(){ for(int i = 0; i<4; i++){ image[i] = getImage(getDocumentBase(),"img"+(i)+".gif"); } } public void paint(Graphics g){ g.drawImage(image[index1],0,0,this); } public void update(Graphics g) { paint(g); if(++no==4)no=0; } public void start(){ t = new Thread(this); t.start(); } public void run() { while(true){ index1++; if(index1 == 4){ index1 = 0; } repaint(); try{ Thread.sleep(timing[no]); }catch(InterruptedException e){} }} public void actionPerformed(ActionEvent arg0) { } }

  • 画像表示アプレットプログラムについて

    Javaのプログラムを勉強中です。 javaを理解するために下記のプログラム(zukei.java)を作成しました。 このプログラムを実行(appletviewer zukei.java)すると エラーにはなりませんが、(3)の行により画像("b.jpg")がすぐには表示されません。表示されたWindowにほかのWindowをいったんのせてから動かすと(3)行により画像"b.jpg"が表示されます。 (1)(2)の行は最初からうまく動作して表示されます。 もちろん(3)のappletをthisにするとうまく動作します。 理由がわかりません。 どなたかご教授ください。 プログラム zukei.class *<APPLET CODE="zukei.class" WIDTH=500 HEIGHT=500></APPLET> */ import java.applet.*; import java.awt.Graphics; import java.awt.*; public class zukei extends Applet { Applet applet; Image myimage; int iKai; public zukei(){ applet = this.applet; } public zukei(Applet applet) { this.applet = applet; } public void init(){ iKai = 0; myimage = getImage(getDocumentBase(),"b.jpg"); } public void paint(Graphics g) { kaku(); //(1) g.drawArc(100,150,50,50,0,360); //(2) g.drawImage(myimage,10,300,180,180,applet); //(3) } public void kaku(){ System.out.println("ABC" + iKai++); } }

  • java repaint()に関して

    プログラムで以下のpaintComponents内のデバックができません。 理由は一体何なのでしょうか? お願いします。 import java.awt.Graphics; import javax.swing.JPanel; public class MainPanel extends JPanel implements Runnable { Thread th; public MainPanel() { super(); } public void movestart() { th = new Thread(this); th.start(); } public void paintComponent(Graphics g) { System.out.println("このデバックができない"); super.paintComponent(g); } public void run() { while (true) { System.out.println("ここのデバックはできている"); repaint(); try { th.sleep(100); } catch (Exception e) { } } } }

    • ベストアンサー
    • Java
  • Tomcat6.0 日本語が?に文字化け

    HelloWorld!!はろぅわーるど!! と書いてコンパイルすると、IEの画面で HelloWorld!!????????? と表示されます。 日本語というよりは2バイト文字が文字化けしているのかなと思います。 何が足りないのでしょうか。 どなたかよろしくお願いします。 全文はこんな感じです。 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloWorld extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { PrintWriter out = response.getWriter(); out.println("<html>"); out.println("HelloWorld!!はろぅわーるど!!"); out.println("</html>"); out.close(); } }

  • アプレットでマウスイベントが出ない

    クリックしても反応しません。 また、マウスイベントが発生したときに飛ぶメソッドにSystem.out.printlnを入れるとException in thread "AWT-EventQueue-0" java.lang.NullPointerException: component argument pDataが出ることがあります。 import java.applet.Applet; import java.awt.Graphics; import java.awt.event.MouseListener; import java.awt.event.MouseEvent; public class NewJApplet extends javax.swing.JApplet implements MouseListener{ int x = 10; int y = 10; public void init() { x = 50; y = 50; } public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed( MouseEvent e ){ x = e.getX(); // マウスがクリックされた位置のx座標を取得する y = e.getY(); // マウスがクリックされた位置のy座標を取得する repaint(); // アプレットの再描画を指示する } public void mouseReleased(MouseEvent e) { } public void paint(Graphics g) { g.fillOval(x,y,10,10); } } 使ってるのは jre1.6.0_01 NetBeans 5.5です

    • ベストアンサー
    • Java

専門家に質問してみよう