Mengapa ini masuk ke loop tak terbatas?

493

Saya memiliki kode berikut:

public class Tests {
    public static void main(String[] args) throws Exception {
        int x = 0;
        while(x<3) {
            x = x++;
            System.out.println(x);
        }
    }
}

Kita tahu dia seharusnya menulis hanya x++atau x=x+1, tetapi pada x = x++itu pertama-tama harus dikaitkan xdengan dirinya sendiri, dan kemudian menambahkannya. Mengapa xterus 0sebagai nilai?

--memperbarui

Inilah bytecode:

public class Tests extends java.lang.Object{
public Tests();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[])   throws java.lang.Exception;
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   iconst_3
   4:   if_icmpge   22
   7:   iload_1
   8:   iinc    1, 1
   11:  istore_1
   12:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   15:  iload_1
   16:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
   19:  goto    2
   22:  return

}

Saya akan membaca tentang petunjuk untuk mencoba memahami ...

Tom Brito
sumber
8
Saya menduga apa yang terjadi adalah: 1. memuat x ke dalam register (= 0); 2. kenaikan x (x = 1); 3. simpan nilai register ke x (x = 0). Dalam C / C ++ ini akan menjadi perilaku yang tidak terdefinisi karena tidak ada titik urutan formal untuk menentukan urutan 2 dan 3. Mudah-mudahan seseorang dapat mengutip Anda sesuatu yang setara dari spec Java.
Rup
19
Kami mencoba ini di C ++ untuk melihat apa yang akan terjadi, dan mencetak 1,2,3 dan keluar. Saya tidak mengharapkan itu. Saya menganggap itu adalah compiler dependen, karena itu adalah perilaku yang tidak terdefinisi. Kami menggunakan gnu g ++.
berduka
13
@saj x++adalah pasca kenaikan; x=adalah penugasan hasil ; yang hasil dari x++adalah asli x(dan ada efek samping dari kenaikan, tapi itu tidak mengubah hasil), Jadi ini dapat diartikan sebagaivar tmp = x; x++; x = tmp;
Marc Gravell
5
Sekarang saya memiliki pertanyaan populer, saya menyesal, jawaban (yang diulang) tidak berhenti datang, bahkan setelah jawaban yang benar dipilih. Layar "Aktivitas Terbaru" saya penuh dengan jawaban yang sama, dan datang lebih banyak lagi ...
Tom Brito
3
@Rob Vermeulen Anda mungkin ingin membaca pertanyaan lengkap sebelum membuat komentar ..;) Ini adalah kode yang dibuat oleh seorang siswa saya, dan saya ingin tahu mengapa perilaku ini.
Tom Brito

Jawaban:

354

Catatan : Awalnya saya memposting kode C # dalam jawaban ini untuk tujuan ilustrasi, karena C # memungkinkan Anda untuk melewati intparameter dengan referensi dengan refkata kunci. Saya telah memutuskan untuk memperbaruinya dengan kode Java legal yang sebenarnya menggunakan MutableIntkelas pertama yang saya temukan di Google untuk semacam perkiraan apa yang refada di C #. Saya benar-benar tidak tahu apakah itu membantu atau menyakiti jawabannya. Saya akan mengatakan bahwa saya secara pribadi belum melakukan semua pengembangan Java; jadi untuk semua yang saya tahu ada banyak cara idiomatis untuk menggambarkan hal ini.


Mungkin jika kita menulis metode untuk melakukan hal yang setara dengan apa x++yang akan membuatnya lebih jelas.

public MutableInt postIncrement(MutableInt x) {
    int valueBeforeIncrement = x.intValue();
    x.add(1);
    return new MutableInt(valueBeforeIncrement);
}

Baik? Tambahkan nilai yang diteruskan dan kembalikan nilai asli: itulah definisi dari operator peningkatan.

Sekarang, mari kita lihat bagaimana perilaku ini diputar dalam kode contoh Anda:

MutableInt x = new MutableInt();
x = postIncrement(x);

postIncrement(x)melakukan apa? Penambahan x, ya. Dan kemudian mengembalikan apa yang x ada sebelum kenaikan . Nilai pengembalian ini kemudian ditugaskan untuk x.

Jadi urutan nilai yang ditetapkan xadalah 0, lalu 1, lalu 0.

Ini mungkin masih lebih jelas jika kita menulis ulang di atas:

MutableInt x = new MutableInt();    // x is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
x = temp;                           // Now x is 0 again.

Fiksasi Anda pada fakta bahwa ketika Anda mengganti xdi sisi kiri dari tugas di atas dengan y, "Anda dapat melihat bahwa itu pertama kali menambah x, dan kemudian mengaitkannya dengan y" menurut saya bingung. Bukan xyang ditugaskan y; ini adalah nilai yang sebelumnya ditugaskanx . Sungguh, menyuntikkan ymembuat segalanya tidak berbeda dari skenario di atas; kami hanya punya:

MutableInt x = new MutableInt();    // x is 0.
MutableInt y = new MutableInt();    // y is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
y = temp;                           // y is still 0.

Jadi sudah jelas: x = x++secara efektif tidak mengubah nilai x. Itu selalu menyebabkan x memiliki nilai x 0 , lalu x 0 +1, dan kemudian x 0 lagi.


Pembaruan : Secara kebetulan, jangan sampai Anda ragu xakan pernah mendapat 1 "antara" operasi kenaikan dan penugasan dalam contoh di atas, saya telah mengumpulkan demo singkat untuk menggambarkan bahwa nilai perantara ini memang "ada," meskipun akan tidak pernah "terlihat" di utas pelaksana.

Demo memanggil x = x++;secara berulang sementara utas terpisah terus mencetak nilai xke konsol.

public class Main {
    public static volatile int x = 0;

    public static void main(String[] args) {
        LoopingThread t = new LoopingThread();
        System.out.println("Starting background thread...");
        t.start();

        while (true) {
            x = x++;
        }
    }
}

class LoopingThread extends Thread {
    public @Override void run() {
        while (true) {
            System.out.println(Main.x);
        }
    }
}

Di bawah ini adalah kutipan dari output program di atas. Perhatikan kejadian 1s dan 0s yang tidak beraturan.

Mulai utas latar ...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1
Dan Tao
sumber
1
Anda tidak perlu membuat kelas untuk lulus dengan referensi di java (meskipun itu pasti akan berhasil). Anda dapat menggunakan Integerkelas, yang merupakan bagian dari pustaka standar, dan bahkan memiliki manfaat menjadi kotak otomatis ke dan dari int hampir secara transparan.
rmeador
3
@rmeador Integer tidak dapat diubah, jadi Anda masih tidak dapat mengubah nilainya. AtomicInteger, bagaimanapun, bisa berubah.
ILMTitan
5
@Dan: Ngomong-ngomong, xdalam contoh terakhir Anda harus dinyatakan volatile, kalau tidak itu adalah perilaku yang tidak terdefinisi dan melihat 1s adalah implementasi spesifik.
axtavt
4
@burkestar: Saya kira tautan itu tidak tepat dalam kasus ini, karena ini adalah pertanyaan Java dan (kecuali saya salah) perilaku ini sebenarnya tidak terdefinisi dalam C ++.
Dan Tao
5
@ Tom Brito - dalam C itu tidak didefinisikan ... ++ bisa dilakukan sebelum atau setelah penugasan. Secara praktis, mungkin ada kompiler yang melakukan hal yang sama dengan Java, tetapi Anda tidak ingin bertaruh.
detly
170

x = x++ bekerja dengan cara berikut:

  • Pertama mengevaluasi ekspresi x++. Evaluasi ekspresi ini menghasilkan nilai ekspresi (yang merupakan nilai xsebelum kenaikan) dan kenaikan x.
  • Kemudian ia menetapkan nilai ekspresi ke x, menimpa nilai tambah.

Jadi, urutan kejadiannya tampak seperti berikut (ini adalah bytecode yang didekompilasi aktual, seperti yang dihasilkan oleh javap -c, dengan komentar saya):

   8: iload_1 // Ingat nilai x saat ini di tumpukan
   9: iinc 1, 1 // Increment x (tidak mengubah tumpukan)
   12: istore_1 // Tulis nilai remeber dari stack ke x

Sebagai perbandingan, x = ++x:

   8: iinc 1, 1 // Peningkatan x
   11: iload_1 // Push nilai x ke stack
   12: istore_1 // Nilai pop dari tumpukan ke x
axtavt
sumber
jika Anda melakukan tes, Anda dapat melihat bahwa itu meningkat pertama, dan kemudian atribut. Jadi seharusnya tidak atribut nol.
Tom Brito
2
@ Tom itu intinya, karena - karena ini semua adalah urutan tunggal itu melakukan hal-hal dalam urutan yang tidak jelas (dan mungkin tidak terdefinisi). Dengan mencoba menguji ini, Anda menambahkan titik urutan dan mendapatkan perilaku yang berbeda.
Rup
Mengenai output bytecode Anda: perhatikan bahwa iincmenambahkan variabel, itu tidak menambah nilai stack, juga tidak meninggalkan nilai pada stack (tidak seperti hampir semua op aritmatika lainnya). Anda mungkin ingin menambahkan kode yang dihasilkan oleh ++xuntuk perbandingan.
Anon
3
@Rep Ini mungkin tidak didefinisikan dalam C atau C ++, tetapi di Jawa, itu didefinisikan dengan baik.
ILMTitan
104

Ini terjadi karena nilai xtidak bertambah sama sekali.

x = x++;

setara dengan

int temp = x;
x++;
x = temp;

Penjelasan:

Mari kita lihat kode byte untuk operasi ini. Pertimbangkan kelas sampel:

class test {
    public static void main(String[] args) {
        int i=0;
        i=i++;
    }
}

Sekarang menjalankan disassembler kelas pada ini kita dapatkan:

$ javap -c test
Compiled from "test.java"
class test extends java.lang.Object{
test();
  Code:
   0:    aload_0
   1:    invokespecial    #1; //Method java/lang/Object."<init>":()V
   4:    return

public static void main(java.lang.String[]);
  Code:
   0:    iconst_0
   1:    istore_1
   2:    iload_1
   3:    iinc    1, 1
   6:    istore_1
   7:    return
}

Sekarang Java VM berbasis stack yang berarti untuk setiap operasi, data akan didorong ke stack dan dari stack, data akan muncul untuk melakukan operasi. Ada juga struktur data lain, biasanya array untuk menyimpan variabel lokal. Variabel lokal diberikan id yang hanya indeks ke array.

Mari kita lihat mnemonik dalam main()metode:

  • iconst_0: Nilai konstan 0 didorong ke stack.
  • istore_1: Elemen teratas stack muncul dan disimpan dalam variabel lokal dengan indeks 1
    yang x.
  • iload_1: Nilai di lokasi 1yang merupakan nilai x tersebut 0, didorong ke dalam tumpukan.
  • iinc 1, 1: Nilai di lokasi memori 1bertambah dengan 1. Jadi xsekarang menjadi 1.
  • istore_1: Nilai di bagian atas tumpukan disimpan ke lokasi memori 1. Itu 0ditugaskan untuk x menimpa nilainya yang bertambah.

Oleh karena itu nilai xtidak berubah yang mengakibatkan infinite loop.

codaddict
sumber
5
Sebenarnya itu bertambah (itulah artinya ++), tetapi variabel akan ditimpa kemudian.
Progman
10
int temp = x; x = x + 1; x = temp;lebih baik tidak menggunakan tautologi dalam contoh Anda.
Scott Chamberlain
52
  1. Notasi awalan akan menambah variabel SEBELUM ekspresi dievaluasi.
  2. Notasi postfix akan bertambah SETELAH evaluasi ekspresi.

Namun " =" memiliki prioritas operator lebih rendah daripada "++ ".

Jadi x=x++;sebaiknya evaluasi sebagai berikut

  1. x siap untuk penugasan (dievaluasi)
  2. x bertambah
  3. Nilai sebelumnya yang xditugaskan ke x.
Jaydee
sumber
Ini jawaban terbaik. Beberapa markup akan membuatnya sedikit lebih menonjol.
Justin Force
1
Ini salah. Ini bukan tentang prioritas. ++memiliki prioritas lebih tinggi daripada =di C dan C ++, tetapi pernyataan tersebut tidak didefinisikan dalam bahasa-bahasa tersebut.
Matthew Flaschen
2
Pertanyaan aslinya adalah tentang Java
Jaydee
34

Tidak ada jawaban yang cukup tepat, jadi begini:

Saat Anda menulis int x = x++, Anda tidak menetapkan xuntuk menjadi dirinya sendiri pada nilai baru, Anda ditugaskan xuntuk menjadi nilai balik x++ekspresi. Yang kebetulan merupakan nilai asli x, seperti yang ditunjukkan dalam jawaban Colin Cochrane .

Untuk bersenang-senang, uji kode berikut:

public class Autoincrement {
        public static void main(String[] args) {
                int x = 0;
                System.out.println(x++);
                System.out.println(x);
        }
}

Hasilnya akan

0
1

Nilai balik dari ekspresi adalah nilai awal x, yaitu nol. Tetapi kemudian, ketika membaca nilai x, kami menerima nilai yang diperbarui, yaitu satu.

Robert Munteanu
sumber
Saya akan mencoba memahami garis bytecode, lihat pembaruan saya, jadi itu akan menjadi jelas .. :)
Tom Brito
Menggunakan println () sangat membantu saya dalam memahami hal ini.
ErikE
29

Sudah dijelaskan dengan baik oleh yang lain. Saya hanya menyertakan tautan ke bagian spesifikasi Java yang relevan.

x = x ++ adalah ekspresi. Java akan mengikuti urutan evaluasi . Pertama akan mengevaluasi ekspresi x ++, yang akan menambah x dan menetapkan nilai hasil ke nilai x sebelumnya . Kemudian akan menetapkan hasil ekspresi ke variabel x. Pada akhirnya, x kembali pada nilai sebelumnya.

plodoc
sumber
1
+1. Sejauh ini, inilah jawaban terbaik untuk pertanyaan aktual, "Mengapa?"
Matthew Flaschen
18

Pernyataan ini:

x = x++;

mengevaluasi seperti ini:

  1. Dorong xke tumpukan;
  2. Penambahan x;
  3. Muncul xdari tumpukan.

Jadi nilainya tidak berubah. Bandingkan dengan:

x = ++x;

yang dievaluasi sebagai:

  1. Penambahan x;
  2. Dorong xke tumpukan;
  3. Muncul xdari tumpukan.

Yang Anda inginkan adalah:

while (x < 3) {
  x++;
  System.out.println(x);
}
cletus
sumber
13
Jelas implementasi yang benar, tetapi pertanyaannya adalah 'mengapa?'
p.campbell
1
Kode asli menggunakan post-increment pada x dan kemudian menugaskannya ke x. x akan terikat ke x sebelum kenaikan, oleh karena itu ia tidak akan pernah mengubah nilai.
wkl
5
@cletus Saya bukan downvoter, tetapi jawaban awal Anda tidak mengandung penjelasan. Itu hanya mengatakan do 'x ++ `.
Petar Minchev
4
@cletus: Saya tidak downvote, tetapi jawaban Anda awalnya hanya x++potongan kode.
p.campbell
10
Penjelasannya juga tidak benar. Jika kode pertama kali diberikan x ke x dan kemudian bertambah x, itu akan berfungsi dengan baik. Ubah saja x++;solusi x=x; x++;Anda dan Anda melakukan apa yang Anda klaim sedang dilakukan oleh kode asli.
Wooble
10

Jawabannya sangat mudah. Ini ada hubungannya dengan urutan hal-hal yang dievaluasi. x++mengembalikan nilai xlalu menambahkan x.

Konsekuensinya, nilai ekspresi x++adalah 0. Jadi, Anda menetapkan x=0setiap kali dalam lingkaran. Tentu saja x++menambah nilai ini, tetapi itu terjadi sebelum penugasan.

Mike Jones
sumber
1
Wow, ada begitu banyak detail di halaman ini ketika jawabannya singkat dan sederhana yaitu yang ini.
Charles Goodwin
8

Dari http://download.oracle.com/javase/tutorial/java/nutsandbolts/op1.html

Operator kenaikan / penurunan dapat diterapkan sebelum (awalan) atau setelah (postfix) operan. Hasil kode ++; dan ++ hasil; keduanya akan berakhir dengan hasil yang bertambah satu. Satu-satunya perbedaan adalah bahwa versi awalan (hasil ++) mengevaluasi ke nilai yang meningkat, sedangkan versi postfix (hasil ++) mengevaluasi ke nilai asli . Jika Anda hanya melakukan kenaikan / penurunan sederhana, tidak masalah versi mana yang Anda pilih. Tetapi jika Anda menggunakan operator ini di bagian dari ekspresi yang lebih besar, yang Anda pilih dapat membuat perbedaan yang signifikan.

Untuk menggambarkan, coba yang berikut ini:

    int x = 0;
    int y = 0;
    y = x++;
    System.out.println(x);
    System.out.println(y);

Yang akan mencetak 1 dan 0.

Colin Cochrane
sumber
1
Bukan hasil evaluasi yang menjadi masalah, namun, itu adalah urutan toko.
Rup
2
Saya tidak setuju. Jika x = 0 maka x ++ akan mengembalikan 0. Oleh karena itu x = x ++ akan menghasilkan x = 0.
Colin Cochrane
Rup benar tentang ini. Ini adalah urutan toko yang menjadi masalah dalam kasus khusus ini. y = x ++ tidak sama dengan x = x ++; Pada yang terakhir, x sedang ditugaskan 2 nilai dalam ekspresi yang sama. Tangan kiri x sedang ditugaskan hasil evaluasi ekspresi x ++, yaitu 0. Sisi kanan x sedang bertambah menjadi 1. Di mana urutan penugasan 2 ini terjadi adalah apa masalahnya. Dari posting sebelumnya jelas bahwa cara kerjanya adalah: eval = x ++ => eval == 0: increment right x => x == 1: kiri x = eval => x == 0
Michael Ekoka
7

Anda secara efektif mendapatkan perilaku berikut.

  1. ambil nilai x (yaitu 0) sebagai "hasil" dari sisi kanan
  2. menambah nilai x (jadi x sekarang 1)
  3. tetapkan hasil dari sisi kanan (yang disimpan sebagai 0) ke x (x sekarang 0)

Gagasannya adalah bahwa operator pasca kenaikan (x ++) menambah variabel yang dipertanyakan SETELAH mengembalikan nilainya untuk digunakan dalam persamaan yang digunakan.

Sunting: Menambahkan sedikit karena komentar. Anggap saja seperti berikut.

x = 1;        // x == 1
x = x++ * 5;
              // First, the right hand side of the equation is evaluated.
  ==>  x = 1 * 5;    
              // x == 2 at this point, as it "gave" the equation its value of 1
              // and then gets incremented by 1 to 2.
  ==>  x = 5;
              // And then that RightHandSide value is assigned to 
              // the LeftHandSide variable, leaving x with the value of 5.
RHSeeger
sumber
OK, tapi apa yang menentukan urutan langkah 2 dan 3?
Rup
@Rup - Bahasa yang mendefinisikannya. Sisi kanan persamaan dievaluasi terlebih dahulu (dalam hal ini, "x ++"), dan hasilnya ditugaskan ke variabel di sisi kiri. Begitulah cara kerjanya bahasa. Sejauh "x ++" "mengembalikan" x untuk persamaan, begitulah cara kerja operator kenaikan postfix (mengembalikan nilai x, lalu menambahkannya). Jika sudah "--x", maka itu akan menjadi (kenaikan x, lalu kembalikan nilainya). Kembali bukanlah kata yang tepat di sana, tetapi Anda mendapatkan idenya.
RHSeeger
7

Anda tidak benar-benar membutuhkan kode mesin untuk memahami apa yang terjadi.

Menurut definisi:

  1. Operator penugasan mengevaluasi ekspresi sisi kanan, dan menyimpannya dalam variabel sementara.

    1.1. Nilai x saat ini disalin ke variabel sementara ini

    1.2. x bertambah sekarang.

  2. Variabel sementara kemudian disalin ke sisi kiri ekspresi, yang kebetulan x! Jadi itu sebabnya nilai lama x lagi disalin ke dalam dirinya sendiri.

Ini sangat sederhana.

houman001
sumber
5

Ini karena tidak pernah bertambah dalam kasus ini. x++akan menggunakan nilai itu terlebih dahulu sebelum bertambah seperti pada kasus ini akan seperti:

x = 0;

Tetapi jika Anda melakukan ++x;ini akan meningkat.

mezzie
sumber
jika Anda melakukan tes, Anda dapat melihat bahwa itu meningkat pertama, dan kemudian atribut. Jadi seharusnya tidak atribut nol.
Tom Brito
1
@ Tom: lihat jawaban saya - Saya menunjukkan dalam tes bahwa x ++ sebenarnya mengembalikan nilai lama x. Di situlah rusak.
Robert Munteanu
"jika Anda membuat tes" - beberapa orang tampaknya berpikir bahwa tes yang ditulis dalam C memberitahu kita apa yang akan dilakukan Java, ketika itu bahkan tidak akan memberi tahu kita apa yang akan dilakukan C.
Jim Balter
3

Nilai tetap pada 0 karena nilainya x++adalah 0. Dalam hal ini tidak masalah jika nilai xmeningkat atau tidak, tugas x=0dijalankan. Ini akan menimpa nilai kenaikan sementara x(yaitu 1 untuk "waktu yang sangat singkat").

Progman
sumber
Tetapi x ++ adalah operasi pasca. Jadi x harus ditambah setelah penugasan selesai.
Sagar V
1
@Agar V: hanya untuk ekspresi x++, bukan untuk seluruh penugasanx=x++;
Progman
Tidak, saya pikir itu hanya perlu ditambahkan setelah nilai x yang akan digunakan dalam penugasan dibaca.
Rup
1

Ini berfungsi seperti yang Anda harapkan. Perbedaan antara awalan dan postfix.

int x = 0; 
while (x < 3)    x = (++x);
patrick
sumber
1

Pikirkan x ++ sebagai pemanggilan fungsi yang "mengembalikan" apa X sebelum kenaikan (itulah mengapa ini disebut kenaikan pasca).

Jadi urutan operasi adalah:
1: cache nilai x sebelum incrementing
2: increment x
3: kembalikan nilai yang di-cache (x sebelum di-incremented)
4: nilai return ditugaskan ke x

jhabbott
sumber
OK, tapi apa yang menentukan urutan langkah 3 dan 4?
Rup
"mengembalikan apa itu X sebelum kenaikan" salah, lihat pembaruan saya
Tom Brito
Pada kenyataannya langkah 3 dan 4 tidak operasi terpisah - itu tidak benar-benar panggilan fungsi yang kembali nilai, itu hanya membantu untuk berpikir seperti itu. Setiap kali Anda memiliki tugas sisi kanan "dievaluasi" maka hasilnya ditugaskan ke sisi kiri, hasil evaluasi dapat dianggap sebagai nilai balik karena membantu Anda memahami urutan operasi, tetapi itu tidak benar-benar .
jhabbott
Ups, benar. Maksud saya langkah 2 dan 4 - mengapa nilai yang dikembalikan disimpan di atas nilai yang bertambah?
Rup
1
Ini adalah bagian dari definisi operasi penugasan, pertama sisi kanan dievaluasi sepenuhnya, kemudian hasilnya ditugaskan ke sisi kiri.
jhabbott
1

Ketika ++ berada di rhs, hasilnya dikembalikan sebelum angkanya bertambah. Ubah ke ++ x dan itu akan baik-baik saja. Java akan mengoptimalkan ini untuk melakukan operasi tunggal (penugasan x ke x) daripada kenaikan.

Steven
sumber
1

Sejauh yang saya bisa lihat, kesalahan itu terjadi, karena penugasan mengesampingkan nilai yang bertambah, dengan nilai sebelum kenaikan, yaitu ia membatalkan kenaikan.

Secara khusus, ekspresi "x ++", memiliki nilai 'x' sebelum kenaikan dibandingkan dengan "++ x" yang memiliki nilai 'x' setelah penambahan.

Jika Anda tertarik untuk menyelidiki bytecode, kami akan melihat tiga baris yang dimaksud:

 7:   iload_1
 8:   iinc    1, 1
11:  istore_1

7: iload_1 # Akan meletakkan nilai variabel lokal ke-2 di stack
8: iinc 1,1 # akan menambah variabel lokal ke-2 dengan 1, perhatikan bahwa ia membiarkan stack tidak tersentuh!
9: istore_1 # Akan memunculkan bagian atas tumpukan dan menyimpan nilai elemen ini ke variabel lokal ke-2
(Anda dapat membaca efek dari setiap instruksi JVM di sini )

Inilah sebabnya mengapa kode di atas akan berulang tanpa batas, sedangkan versi dengan ++ x tidak akan. Bytecode untuk ++ x akan terlihat sangat berbeda, sejauh yang saya ingat dari kompiler Java 1.3 yang saya tulis sedikit lebih dari setahun yang lalu, bytecode harus seperti ini:

iinc 1,1
iload_1
istore_1

Jadi, hanya menukar dua baris pertama, ubah semantik sehingga nilai tertinggal di atas tumpukan, setelah kenaikan (yaitu 'nilai' ekspresi) adalah nilai setelah kenaikan.

mikha
sumber
1
    x++
=: (x = x + 1) - 1

Begitu:

   x = x++;
=> x = ((x = x + 1) - 1)
=> x = ((x + 1) - 1)
=> x = x; // Doesn't modify x!

Sedangkan

   ++x
=: x = x + 1

Begitu:

   x = ++x;
=> x = (x = x + 1)
=> x = x + 1; // Increments x

Tentu saja hasil akhirnya adalah sama dengan hanya x++;atau ++x;pada baris dengan sendirinya.

Paul
sumber
0
 x = x++; (increment is overriden by = )

karena pernyataan di atas x tidak pernah mencapai 3;

Praveen Prasad
sumber
0

Saya bertanya-tanya apakah ada sesuatu di spec Java yang secara tepat mendefinisikan perilaku ini. (Implikasi yang jelas dari pernyataan itu adalah bahwa saya terlalu malas untuk memeriksa.)

Catatan dari bytecode Tom, garis kuncinya adalah 7, 8 dan 11. Baris 7 memuat x ke dalam tumpukan perhitungan. Peningkatan baris 8 x. Baris 11 menyimpan nilai dari tumpukan kembali ke x. Dalam kasus normal di mana Anda tidak menetapkan nilai kembali ke diri mereka sendiri, saya tidak berpikir akan ada alasan mengapa Anda tidak dapat memuat, menyimpan, lalu menambah. Anda akan mendapatkan hasil yang sama.

Seperti, misalkan Anda memiliki kasus yang lebih normal di mana Anda menulis sesuatu seperti: z = (x ++) + (y ++);

Apakah itu dikatakan (pseudocode to skip technicalities)

load x
increment x
add y
increment y
store x+y to z

atau

load x
add y
store x+y to z
increment x
increment y

harus tidak relevan. Entah implementasi harus valid, saya akan berpikir.

Saya akan sangat berhati-hati dalam menulis kode yang tergantung pada perilaku ini. Ini terlihat sangat tergantung pada implementasi, antara-celah-dalam-spesifikasi bagi saya. Satu-satunya waktu yang akan membuat perbedaan adalah jika Anda melakukan sesuatu yang gila, seperti contoh di sini, atau jika Anda memiliki dua utas berjalan dan bergantung pada urutan evaluasi dalam ekspresi.

Jay
sumber
0

Saya pikir karena di Java ++ memiliki prioritas lebih tinggi daripada = (tugas) ... Apakah itu? Lihatlah http://www.cs.uwf.edu/~eelsheik/cop2253/resources/op_precedence.html ...

Cara yang sama jika Anda menulis x = x + 1 ... + memiliki prioritas lebih tinggi daripada = (tugas)

cubob
sumber
Ini bukan masalah prioritas. ++memiliki prioritas lebih tinggi daripada =di C dan C ++ juga, tetapi pernyataan itu tidak terdefinisi.
Matthew Flaschen
0

The x++ekspresi mengevaluasi ke x. Bagian itu ++mempengaruhi nilai setelah evaluasi , bukan setelah pernyataan . jadi x = x++secara efektif diterjemahkan ke dalam

int y = x; // evaluation
x = x + 1; // increment part
x = y; // assignment
tia
sumber
0

Sebelum menambah nilai satu, nilai ditugaskan ke variabel.

kumara
sumber
0

Itu terjadi karena posnya bertambah. Ini berarti bahwa variabel bertambah setelah ekspresi dievaluasi.

int x = 9;
int y = x++;

x sekarang 10, tetapi y adalah 9, nilai x sebelum dinaikkan.

Lihat lebih lanjut di Definisi Peningkatan Pasca .

BrunoBrito
sumber
1
Anda x/ ycontoh berbeda dari kode nyata, dan perbedaan relevan. Tautan Anda bahkan tidak menyebutkan Java. Selama dua bahasa itu tidak menyebutkan, pernyataan dalam pertanyaan tidak terdefinisi.
Matthew Flaschen
0

Periksa kode di bawah ini,

    int x=0;
    int temp=x++;
    System.out.println("temp = "+temp);
    x = temp;
    System.out.println("x = "+x);

output akan menjadi,

temp = 0
x = 0

post incrementberarti kenaikan nilai dan kembalikan nilai sebelum kenaikan . Itulah sebabnya nilai tempadalah 0. Jadi bagaimana jika temp = idan ini dalam satu lingkaran (kecuali untuk baris kode pertama). seperti dalam pertanyaan !!!!

utama
sumber
-1

Operator kenaikan diterapkan ke variabel yang sama seperti yang Anda tetapkan. Itu meminta masalah. Saya yakin Anda dapat melihat nilai variabel x Anda saat menjalankan program ini .... itu harus menjelaskan mengapa loop tidak pernah berakhir.

SIVAKUMAR.J
sumber