Java Tuzakları – IV: Java bizimle dalga mı geçiyor?

Birisi size gelip, aşağıdaki kodun “0” bastığını söylese, gözlerinizi ovalayıp koda bir kaç defa daha bakmaktan ve inanmayıp, gidip aynısını yazıp çalıştırmaktan başka ne yapardınız?

...
int i = 0;
i = i++;
System.out.println(i);
...

Aynı kodu aşağıdaki gibi yazarsanız, beklediğiniz olur ve “0” yerine “1” basılır. Siz de derin bir ohh çekersiniz 🙂

...
int i = 0;
int j = i++;
System.out.println(i);
...

Ama kodda “j” yerine “i” koyarsanız, kabus yine başlar.

Aslında problem Java’da değil. Eminim bu kodu aynı şekilde çalıştıran başka diller ya da derleyiciler de vardır. C/C++’ta bu durumun derleyiciye bağlı olduğunu biliyorum örneğin.

Ben bu kodu görünce, hemen “javap”ı kullanarak üretilen bytecodea baktım ve ne olup bittiğini anlamaya çalıştım. “javac”ın ürettiği bytecode şöyle:

Code:
0: iconst_0
1: istore_0
2: iload_0
3: iinc 0, 1
6: istore_0

Malum JVM bir stack makinası. Değerler bu stackte tutuluyor. Yerel değikenler ise bir dizide tutuluyor. Yukarıdaki kod parçası main metottan çağrılan ve başka bir yerel değişkene sahip olmayan bir metotta olduğundan, yerel değişken olarak sadece int “i” var ve onun değeri de, yerel değişken dizisinin “0” nolu odacığında tutuluyor. Ve olan biten şu: 0. satırda stacke “0” yükleniyor. Sonra bu değer 1. satırla “i”ye atanıyor. 2. satırda ise “i”nin değeri stacke kopyalanıyor ve 3. satırla “i”nin değeri 1 arttırılıyor. Buraya kadar iyi. Fakat bakın 6. satırda, az önce stacke kopyaladığımız “i”nin ilk değeri yani “0”, “i”ye tekrar atanıyor. Dolayısıyla, “i”ye yapılan artım kayboluyor. Olup biteni biraz daha anlaşılır yazarsak aslında 2. satırda yapılan şey “i”nin değerinin bir geçici değişkene atanması ve 6. satırda yapılan da bu geçici değişkendeki değerin “i”ye geri atanması. Yani yukarıdaki kodun şundan farkı yok aslında:

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


Dolayısıyla “i”nin değerinin “0”da kalması normal. Yukarıda verdiğim ve arttırılan “i”nin “j”ye atandığı kodun bytecodeuna da bakarsanız farkı görürsünüz.

Ben bu durumla daha yeni karşılaştım. Çünkü hiç bir zaman basit bir şekilde “i++” ya da “i+=1” ile yapacağım şeyi böyle yapmaya kalkışmamıştım. Ama güzel olan, bir şey daha öğrenmiş olmamız.

C#’ta da durum aynı mıdır acaba?

Toplam görüntülenme sayısı: 1173