Niyə bu sonsuz bir döngədə baş verir?

Aşağıdakı kodu var:

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

Biz bilirik ki, x++ və ya x=x+1 yazmalı, x = x++ isə ilk növbədə xin özünü göstərməlidir və sonra onu artırmalıdır. x nə üçün 0 kimi davam edir?

- yeniləmə

Bayt kodu burada:

 public class Tests extends java.> 

Anlamaq üçün cəhdləri oxuyacağam ...

467
30 сент. Tom Brito tərəfindən 30 Sentyabrda təyin olundu . 2010-09-30 17:07 '10 at 17:07 2010-09-30 17:07
@ 27 cavab

Qeyd Başlanğıcda C # kodunu bu cavabda illüstrasiya üçün yerləşdirdilər, çünki C #, ref parametrinə əsasən int parametrlərini keçməyə imkan verir. Mən C # MutableInt nə ilə MutableInt üçün Google-da tapdığım ilk MutableInt sinifini istifadə edərək, onu real hüquqi Java MutableInt yeniləməyə qərar verdim. Mən kömək edə biləcəyimi və ya ağrdığını deyə bilmərəm. Mən demək istəyirəm ki, mən şəxsən Java-nın çox inkişaf etməmişəm; mən bilirəm hər kəs üçün, bu nöqtəni göstərmək üçün daha çox idiomatik yollar ola bilər.


Yəqin ki x++ ' x++ üçün bir metodu yazsaq, bu daha aydın olur.

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

Sağ olsun? Köçürülən dəyəri artırmaq və orijinal dəyəri qaytarmaq: Bu postincrement operator müəyyən edir.

İndi bu davranışın nümunə kodunuzda necə göründüyünü görək:

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

postIncrement(x) nə edir? Artımlar x , bəli. Və sonra artım x dəyərini qaytarır . Bu dönüş dəyəri x'ye təyin edilir.

Beləliklə x'ye təyin edilmiş dəyərlərin sırası 0, sonra 1, daha sonra 0 olur.

Yuxarıda yenidən yazırıqsa, bu daha aydın ola bilər:

 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. 

Yuxarıdakı tapşırığın sol tərəfindəki y ilə əvəz olunduğuna bağlı fiksasiyanı ilk dəfə x artırdığını görürsən və sonra y dəyərini atarsan, məni heyran edir. Y'ye təyin x deyil, bu x daha əvvəl x Həqiqətən, injection y yuxarıdakı skriptdən fərqli şeylər yaradır;

 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. 

Beləliklə aydındır: x = x++ dəyərini effektiv şəkildə dəyişmir. Bu daima x 0 , daha sonra x 0 + 1, daha sonra isə x 0 olur .


Yeniləmə . Yeri gəlmişkən, x nin artım əməliyyatı və yuxarıda göstərilən tapşırığın 1 "arasında" təyin olunmadığından şübhə etmirsiniz ki, bu ara dəyər həqiqətən "mövcuddur" olduğunu göstərmək üçün sürətli bir demodan tərtib edirəm, baxmayaraq ki, həyata keçirilə bilən streamdə.

Demonstration x = x++; bir döngədə, ayrı bir mövzu daim x konsolun dəyərini yazır.

 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); } } } 

Aşağıda yuxarıdakı proqramın bir çıxışıdır. Hər 1s və 0s-lərin düzensiz görünüşünə diqqət yetirin.

 Arxa fondan başlayaraq ... 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 1
343
30 сент. Cavab Dan Tao 30 sep verilir. 2010-09-30 18:09 '10 at 18:09 PM 2010-09-30 18:09

x = x++ aşağıdakı kimi işləyir:

  • Birincisi, x++ ifadəsini qiymətləndirir. Bu ifadənin qiymətləndirilməsi x ifadəsinin dəyərini yaradır ( x artımdan əvvəl x dəyəridir) və x artırır.
  • Daha sonra, artımın dəyərini yenidən yazaraq x ifadəsinin dəyərini təyin edir.

Belə ki, hadisələrin ardıcıllığı aşağıdakılardır (bu, javap -c tərəfindən yaradılmış əsl dekompil edilmiş byte kodudur, şərhlərimlə):

border=0
  8: iload_1 // X-nin cari dəyərini yadda saxla9: iinc 1, 1 // Artım x (yığını dəyişmir)12: istore_1 // yığından x-ə yazın

Müqayisə üçün x = ++x :

  8: iinc 1, 1 // Artım x11: iload_1 // X-nin yığma dəyərinə yığın12: istore_1 // Pop 
166
30 сент. Cavab 30 sentyabrda verilir 2010-09-30 17:13 '10 at 17:13 2010-09-30 17:13

Çünki x nin dəyəri heç də artır.

 x = x++; 

bərabərdir

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

Şərhlər:

Bu əməliyyat üçün bayt koduna baxın. Nümunə sinifini nəzərdən keçirin:

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

İndi disassembler sinfi istifadə edərək, biz:

 $ javap -c test Compiled from "test.java" class test extends java.> 

İndi Java VM hər bir əməliyyat üçün nəzərdə tutulan bir yığındır, məlumatların yığını üzərinə basdırılacaq və əməliyyatın yerinə yetirilməsi üçün yığındakı məlumatlar çıxarılacaq. Yerli dəyişənlərin saxlanması üçün başqa bir məlumat strukturu da var. Yerli dəyişənlərə yalnız bir sıra göstəriciləri olan identifikatorlar verilir.

main() üsulunda mnemoniklərə nəzər salaq:

  • iconst_0 : sabit dəyər 0 yığın iconst_0 .
  • istore_1 : istore_1 üst elementi boşaldılır və indeks 1 ilə yerli dəyişəndə ​​saxlanılır x .
  • iload_1 : 1-ci iload_1 dəyər, yəni 0 olan x , yığın daxil edilir.
  • iinc 1, 1 : yaddaş yeri 1 başına iinc 1, 1 . Beləliklə x indi 1 olur.
  • istore_1 : istore_1 üst hissəsindəki yaddaş yaddaş yerində saxlanılır 1 . Yəni, əlavə dəyərini 0 ə yenidən yazmaq .

Buna görə də, x dəyəri dəyişməz, bu da sonsuz bir dövrə gətirib çıxarır.

104
30 сент. Cavab 30-cu codaddict tərəfindən verilmişdir 2010-09-30 17:15 '10 da 5:15 pm 2010-09-30 17:15
  • Ön ifa notasiyası ifadə dəyərləndirilmədən əvvəl dəyişənliyi artıracaq.
  • Postfix qeydləri ifadənin qiymətləndirilməsindən sonra artacaq.

Bununla belə, " = " " ++ " daha aşağı bir operatora üstünlük verir.

Beləliklə x=x++; aşağıdakı kimi qiymətləndirilməlidir

  • x təyin etmək üçün hazırlanmış (təxmin edilən)
  • x artdı
  • x təyin olunmuş əvvəlki x dəyəri.
52
30 сент. Jaydee tərəfindən Sep 30 ilə cavab 2010-09-30 17:27 '10 at 17:27 2010-09-30 17:27

Cavabın heç biri, kifayət qədər yer olmadığı üçün belədir:

int x = x++ yazdığınızda, özünüzə yeni bir x++ ifadəsinin return dəyərini təyin edirsiniz. Colin Cockrene tərəfindən göstərildiyi kimi xin başlanğıc dəyəri x .

Əyləncə üçün, aşağıdakı kodu yoxlayın:

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

Nəticə olacaq

 0 1 

İfadənin dönüş dəyəri sıfır olan x başlanğıc dəyəridir. Lakin sonra x dəyərini oxumaqla, yenilənmiş dəyəri, yəni birinə sahibik.

34
30 сент. Robert Munteanu tərəfindən verilmiş cavab 30 sentyabr 2010-09-30 17:37 '10 at 17:37 'da 2010-09-30 17:37

Bu, artıq başqalarına yaxşı izah edildi. Mən sadəcə Java spesifikasiyasının müvafiq bölmələrinə istinadlar daxil edirəm.

x = x + + ifadəsidir. Java qiymətləndirmə əmrini yerinə yetirəcək. Birincisi, x'yi artıracaq x ++ ifadəsini qiymətləndirəcək və x dəyərini x dəyərinə görə təyin edəcək . Sonra ifadənin x dəyişən x təyin. Sonda, x əvvəlki dəyərinə qayıdır.

29
30 сент. cavab plodoc 30 sep verilir . 2010-09-30 18:33 '10 at 18:33 2010-09-30 18:33

Bu bəyanat:

 x = x++; 

aşağıdakı kimi qiymətləndirilmişdir:

  • x yığını itələyin;
  • Artırım x ;
  • Yığındakı Pop x .

Beləliklə, dəyər dəyişdirilmir. Bunu müqayisə edin:

 x = ++x; 

kimi qiymətləndirilir:

  • Artırım x ;
  • x yığını itələyin;
  • Yığındakı Pop x .

Nə istəyirsiniz:

 while (x < 3) { x++; System.out.println(x); } 
18
30 сент. Cavab 30 sentyabrda verilir 2010-09-30 17:10 '10 at 17:10 2010-09-30 17:10

Cavab olduqca sadədir. Bu, şeylərin qiymətləndirilməsidir. x++ dəyərini qaytarır və sonra x artırır.

Buna görə x++ ifadəsinin dəyəri 0 dir. Buna görə, hər dəfə bir döngədə x=0 təyin edərsiniz. Əlbəttə ki, x++ bu dəyəri artırır, lakin tapşırıqdan əvvəl olur.

10
02 окт. Mayın 02- də Mike Jones tərəfindən cavablandırıldı 2010-10-02 01:18 '10 at 1:18 'da 2010-10-02 01:18

Http://download.oracle.com/javase/tutorial/java/nutsandbolts/op1.html ünvanından

Artım / azaldılması operatorları (prefiks) və ya sonra (postfix) işlədilə bilərlər. Nəticə kodu ++; və + + nəticə; həm də nəticədə bir nəfər artır. Yalnız fərq , postfiks versiyası (nəticə ++) orijinal dəyərlə qiymətləndirir , prefiks versiyası (nəticə ++) artan dəyəri qiymətləndirir . Sadəcə sadə bir artım / azalma aparırsanız, əslində seçdiyiniz hansı versiyadan bir sual yoxdur. Lakin bu bəyanatı daha geniş bir ifadənin bir hissəsində istifadə edərsəniz, hansı seçimi əhəmiyyətli bir fərq edə bilər.

Nümunə etmək üçün aşağıdakıları cəhd edin:

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

1 və 0 nəyi çap edəcək.

8
30 сент. Cavab Colin Cochrane 30 sep tərəfindən verilir . 2010-09-30 17:27 '10 at 17:27 2010-09-30 17:27

Aşağıdakı davranışı təsirli bir şəkildə alırsınız.

  • sağ tərəfin "nəticəsi" x (0 olan) dəyərini almaq
  • x dəyərinin artırılması (x indi 1)
  • x (x indi 0) üçün sağ tərəfin (0 kimi qeyd olunmuş)

Fikirdən sonra artım (x ++) operator bu AFTER dəyişənini artırır və onun dəyərini istifadə olunan tənlikdə istifadə üçün geri qaytarır.

Düzenle: Bir şərh səbəbiylə kiçik bir əlavə edir. Bunu aşağıdakı kimi düşünün.

 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. 
7
30 сент. RHSeeger tərəfindən verilmiş cavab 30 sentyabr 2010-09-30 17:16 '10 at 17:16 'da 2010-09-30 17:16

Həqiqətən nə olduğunu başa düşmək üçün maşın koduna ehtiyac yoxdur.

Təriflərə uyğun olaraq:

  • Tapşırıq operatoru sağ tərəf üçün ifadəni qiymətləndirir və onu müvəqqəti dəyişən saxlayır.

    1.1. Xin cari dəyəri bu müvəqqəti dəyişənə kopyalanır.

    1.2. x artıq artır.

  • Sonra müvəqqəti dəyişən təsadüf olan ifadənin sol tərəfinə kopyalanır! Beləliklə, köhnə x dəyəri yenidən özünə kopyalanır.

Çox sadədir.

7
01 окт. Cavab houman001 01 okt verilir . 2010-10-01 07:10 '10 at 7:10 2010-10-01 07:10

Çünki bu vəziyyətdə heç bir zaman artım yoxdur. x++ , əvvəlcə bu halda olduğu kimi, artımdan əvvəl dəyərini istifadə edəcək:

 x = 0; 

Ancaq ++x; edirsinizsə ++x; artacaq.

5
30 сент. Cavab 30 gün əvvəl verilir . 2010-09-30 17:11 '10 'da 17:11' de 2010-09-30 17:11 'də

x++ dəyərinin 0 olduğu üçün dəyər 0-ə bərabər olaraq qalır. Bu halda x dəyərinin artırılması və ya olmasın əhəmiyyəti yoxdur, x=0 tapşırığı yerinə yetirilir. Bu, x ("çox qısa müddətdə" 1) müvəqqəti artan dəyərinin üzərində yazılacaq.

3
30 сент. Müəllif : Progman Sep 30 2010-09-30 17:15 '10 da 5:15 pm 2010-09-30 17:15

Cəza

 x = x++; 

"tərcümə edir"

 x = x; x = x + 1; 

Nədir?

1
12 сент. Cavab Willmore 12 Sep tərəfindən verilir. 2016-09-12 08:17 '16 saat 08:17 'da 2016-09-12 08:17

Bu, digərini gözlədiyiniz üsulla işləyir. Ön və arxiv arasındakı fərq bu.

 int x = 0; while (x < 3) x = (++x); 
1
30 сент. Cavab verilir 0x4f3759df 30 Sentyabr. 2010-09-30 17:39 '10 at 17:39 'da 2010-09-30 17:39

+ + 'Nin dəyəri rhs olduqda, nəticə sayı artdıqdan sonra qaytarılır. + + X-ə dəyişdirin və hər şey yaxşı olardı. Java bu artım deyil, bir əməliyyat (x x təyin) yerinə yetirmək üçün optimize edəcək.

1
01 окт. Steven tərəfindən 01 oktyabrda cavab verildi 2010-10-01 02:15 '10 saat 02:15 'da 2010-10-01 02:15

Bəli, mən görə bilirəm ki, tapşırıq artırma dəyərinə olan artımlı dəyəri əvəz edir, yəni, bir səhv olur. artırmağı geri al.

Xüsusilə, "x ++" ifadəsi artımdan öncə "x" və "++ x" deyil, "x" artımdan sonra var.

Bayt kodunun öyrənilməsində maraqlıysanız, biz üç xətti nəzərdən keçiririk:

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

7: iload_1 # 2-ci lokal değişkenin yığını yığma dəyərinə itələyir
8: iinc 1.1 # 2-dən 2-ci lokal dəyişəndən artacaq, yığın bütövlükdən ayrıldığını qeyd edin!
9: istore_1 # yığının üst hissəsinə vuracaq və bu maddənin dəyərini ikinci yerli dəyişənə saxlayacaq
( Burada hər JVM komandasının təsirlərini oxuya bilərsiniz )

Bu səbəbdən, yuxarıda göstərilən kodu qeyri-müəyyən hala gətirəcək, c ++ x versiyası olmayacaqdır. + + X üçün byte kodu tamamilə fərqli olmalıdır, mən bir il əvvəl yazdığım 1.3 Java dərgisindən xatırladığım kimi, bayt kodu aşağıdakı kimi olmalıdır:

 iinc 1,1 iload_1 istore_1 

Beləliklə, sadəcə, ilk iki xəttin əvəz edilməsi, semantik dəyişikliyi, artımdan sonra (yəni ifadənin "dəyəri") yığımın üstündəki qalan dəyər artımdan sonra dəyərdir.

1
02 окт. cavab verdi micdah 02 oct . 2010-10-02 04:16 '10 at 4:16 pm 2010-10-02 04:16

X ++ x funksiyasını çağırırıq ki, bu artımdan (bu artım artımına səbəb olan) əvvəlcədən nə olduğunu "qaytarır".

Belə ki, əməliyyatlar qaydası:
1: önbellek x dəyəri artım 2: artım x
3: Önbelleğe alınan dəyəri (x artırmadan əvvəl x) qaytarın
4: return dəyəri x təyin edilir

1
30 сент. Jhabbott tərəfindən verilmiş cavab Sep 30 2010-09-30 17:16 '10 at 17:16 'da 2010-09-30 17:16
  x++ =: (x = x + 1) - 1 

Beləliklə:

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

Baxmayaraq

  ++x =: x = x + 1 

Beləliklə:

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

Əlbəttə, son nəticə x++; ilə eynidır x++; və ya ++x; uyğun olaraq.

1
26 нояб. Cavab 26 noyabrda Paulpro tərəfindən verildi 2011-11-26 14:08 '11 at 14:08 2011-11-26 14:08

Bir dəyəri artırmadan əvvəl dəyər dəyişənə təyin edilir.

0
01 окт. cavab 01 oktyabr cümə günü verilir . 2010-10-01 10:59 '10 at 10:59 'da 2010-10-01 10:59

Bunun səbəbi, vəzifəsinin artırılmasıdır. Bu ifadənin ifadəsi qiymətləndirildikdə dəyişən artım deməkdir.

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

x artıq 10, ancaq y 9, x dəyəri artdıqdan sonra.

Sonrakı artımların tərifində daha çox baxın.

0
01 окт. Cavab BrunoBrito 01 oktyabr verilir . 2010-10-01 20:23 '10 at 20:23 2010-10-01 20:23

x++ ifadəsi x++ kimi qiymətləndirilir. ++ hissəsi qiymətləndirildikdən sonra dəyərinə təsir göstərir və təsdiqindən sonra deyil. Buna görə x = x++ effektiv şəkildə çevrilir

 int y = x; // evaluation x = x + 1; // increment part x = y; // assignment 
0
01 окт. cavab tia 01 oktyabr verilir . 2010-10-01 19:38 '10 at 19:38 'da 2010-10-01 19:38
  x = x++; (increment is overriden by = ) 

yuxarıdakı bəyanatdan görə, x heç vaxt 3-ə çatmaz;

0
30 сент. Cavab Praveen Prasad 30 Sentyabr verilir. 2010-09-30 20:30 '10 saat 20:30 'da 2010-09-30 20:30

Hesab edirəm ki, Java ++ 'da = (tapşırıq)' dan daha yüksək prioritet var ... Belə mi? Http://www.cs.uwf.edu/~eelsheik/cop2253/resources/op_precedence.html səhifəsinə baxın ...

X = x + 1 ... + yazarsanız, eyni zamanda = (təyinat)

0
01 окт. Cavab 01 oktyabr ayına verilir . 2010-10-01 10:00 '10 10:00 'da, 2010-10-01 10:00' də

Aşağıdakı kodu yoxlayın,

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

çıxış olacaq

 temp = 0 x = 0 

post increment mənasını artırmaq və artımdan əvvəl dəyəri qaytarmaq deməkdir. Buna görə temp dəyər 0 dir. Beləliklə, əgər temp = i və bir loop (kodun ilk satırından başqa). söz mövzusu kimi!

0
29 мая '15 в 11:31 2015-05-29 11:31 cavab mayın 29-da, '15 'də saat 11:31' də verilir. 2015-05-29 11:31

Java spesifikasiyasında bunun davranışını dəqiq müəyyən edən bir şey varmı? (Aydındır ki, bu məntiqi yoxlamaq üçün çox tənbəl olduğumu bildirir.)

Tom's bytecode bir qeyd, əsas xətləri 7, 8 və 11 var. Line 7 hesablama yığını x x yükler. Xətti 8 x artırır. Xətt 11 yığını x-dən x-ə qədər saxlayır. Normal hallarda, özünüzə dəyər verdiyiniz zaman, yükləməyinizə, saxlaya bilməyəcəyinizə və sonra artırmağa səbəb ola biləcəyini düşünmürəm. Eyni nəticə alacaqsınız.

Məsələn, bir şey yazarkən daha normal bir vəziyyətiniz var deyək: r = (x ++) + (y ++);

Söyləyin (pseudocode skip texnika)

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

və ya

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

əhəmiyyətli deyil. Hər hansı bir tətbiq etibarlı olmalıdır, düşünürəm.

Bu davranışdan asılı olan kodu yazmağa çox diqqətli olacağam. Bu, mənim üçün spesifikasiyalar arasında çatışmazlıqdan çox asılıdır. Məsələn, burada bir şey çıldırdığınız və ya iki akarsu olsaydınız və ifadənin içərisində qiymətləndirmə qaydalarından asılı olsalar, bu, vacib bir zaman idi.

0
30 сент. Jay Sep 30 tərəfindən verilmiş cavab 2010-09-30 22:55 '10 at 10:55 pm 2010-09-30 22:55

Artım operatoru təyin etdiyiniz dəyişənə tətbiq olunur. Bu çətinlik çəkir. Əminəm ki, bu proqramın icrası zamanı x dəyişəninin x dəyərini görə bilərik ... bu, loop nə üçün bitməyəcəkdir.

-1
10 дек. Cavab SIVAKUMAR.J 10 Dekabr. 2010-12-10 14:29 '10 at 2:29 PM 2010-12-10 14:29