BÖLÜM 2
|
|
Altuğ
B. Altıntaş
|
Java programlama dilinde temel tipleri ve nesneleri yönlendirmek ve
değiştirmek için operatörler kullanılır. Bu operatörler yapısı ve
işlevleri bakımından C ve C++ programlama dillerinden miras alınmıştır; ancak
bu miras üzerine kendisi de birçok şey eklemiştir. (yorum ekle)
Değer atamalar sağ taraftaki değerin (-ki bu bir sabit değer veya başka bir
değişken olabilir)
sol taraftaki değişkene atanması ile gerçekleşir. (yorum
ekle)
Gösterim-2.1:
int a ;a=4 ; // doğru bir atama 4=a ; // yanlış bir atama! |
Atama işlemi, temel (primitive) tipler için
basittir. Temel tipler, değerleri doğrudan
kendileri üzerlerinde tuttukları için, bir temel tipi diğerine atadığımız
zaman değişen sadece içerikler olur. (yorum ekle)
Gösterim-2.2:
int a, b ;a=4 ;b=5 ;a=b ; |
Sonuç olarak a ve
b değişkenleri içerikleri aynı olur...
a=5, b=5
Nesneler için atama
işlemleri, temel tiplere göre biraz daha karmaşıktır. Nesneleri yönetmek için
referanslar kullanılır; eğer, nesneler için bir atama işlemi söz konusu ise, akla
gelmesi gereken ilk şey, bu nesnelere bağlı olan referansın gösterdiği
hedeflerde bir değişiklik olacağıdır. (yorum ekle)
Örnek: NesnelerdeAtama.java (yorum ekle)
class Sayi { int i;}public class NesnelerdeAtama { public static void main(String[] args) { Sayi s1 = new Sayi(); Sayi s2 = new Sayi(); s1.i = 9; s2.i = 47; System.out.println("1: s1.i: " + s1.i +", s2.i: " + s2.i);s1 = s2; // referanslar kopyalaniyor.. nesneler degil System.out.println("2: s1.i: " + s1.i +", s2.i: " + s2.i); s1.i = 27; System.out.println("3: s1.i: " + s1.i +", s2.i: " + s2.i); }} |
Yukarıda verilen uygulama
adım adım açıklanırsa: Önce 2 adet Sayi
nesnesi oluşturulmaktadır; bunlar Sayi
tipindeki referanslara bağlı durumdadırlar; s1 ve s2... Bu referanslar artık 2
ayrı Sayi nesnesini
göstermektedirler. Daha sonra s1 referansının işaret ettiği Sayi nesnesinin i alanına 9 sayısını atandı;
benzer şekilde s2 referansının işaret ettiği Sayi nesnesinin i alanına da 47 sayısını atandı. Yapılan
işlemlerin düzgün olup olmadıklarının görülmesi için ekrana yazdırıldığında
aşağıdaki sonuç ile karşılaşır: (yorum ekle)
1: s1.i: 9, s2.i: 47
Şu ana kadar bir sorun
olmadığını anlaşılıp rahatladıktan sonra önemli hamleyi yapıyoruz. (yorum ekle)
Gösterim-2.3:
s1 = s2 ; // referanslar kopyalanıyor... nesneler değil |
Burada gerçekleşen olay
şudur; s1 artık s2’nin işaret ettiği nesneyi göstermektedir.
Şekil-2.1, verilen bu örneğin daha iyi anlaşılmasına yardımcı
olabilir. Kısım-1 durumun, s2’nin
s1’e atanmadan önceki halini göstermektedir.
Kısım-2 ise s2’nin
s1’e atandıktan sonraki halini
göstermektedir. (yorum ekle)

Şekil-2.1. Nesnelerde atama ve referans değişikliği
Kalınan yerden devam
edilirse, şimdi s1 ve
s2’nin değerlerini ekrana yazdırılırsa, s1.i ve s2.i alanları aynı
içeriği taşıdığı görülür. (yorum ekle)
2: s1.i: 47, s2.i: 47
Bunun nedeni ise bu iki
referansın (s1 ve s2 ) aynı nesneyi
göstermeleridir. Son olarak s1 referansının işaret ettiği
nesnenin i alanı değiştirilip ekrana
yazdırıldığında... (yorum ekle)
3: s1.i: 27, s2.i: 27
Görüldüğü gibi s2.i alanının da değeri değişmiş oldu; nedeni ise yine s1 ve s2 referanslarının
aynı nesneyi göstermeleridir. (yorum ekle)
Peki, s1 referansının daha önceden işaret etmiş olduğu Sayi nesnesine ne olacaktır? Cevap
vermek için henüz erken ama yinede söylenirse, bu nesne kullanılmayacağından dolayı
çöp haline gelecektir ve çöp toplayıcısı (Garbage
Collector)
tarafından temizlenecektir. Görüldüğü gibi tasarımcının nesne temizliği
konusunda endişeye kapılmasına gerek yoktur. Çöp toplayıcısını ilerleyen
bölümlerde daha ayrıntılı ele alınacaktır. (yorum ekle)
Bu örneğimizde s1 referansının s2’nin işaret etmiş olduğu nesneyi göstermesini istemeyip
yalnızca s2.i alanı değerinin s1.i alanı değerine atanmasını istenmiş olsaydı, aşağıdaki
gibi yazılması yeterli olacaktı... (yorum ekle)
Gösterim-2.4:
s1.i = s2.i; |
Bu ifade referansların gösterdikleri
nesnelerde herhangi bir değişiklik yapmayacaktır; değişen sadece s1.i alanının değeri olacaktır. (yorum ekle)
Yordamların parametre
kabul ettiklerini ve bu parametreleri alarak işlemler gerçekleştirdiğini
biliyoruz. Peki yordamlara parametre olarak neler gitmektedir? Nesnelerin
kendisi mi? Yoksa nesnelere ait referanslar mı? (yorum ekle)
Örnek: Pas.java (yorum
ekle)
class Harf { char c;}public class Pas { static void f(Harf h) { /* Harf nesnesine yeni bir referans bağlandı (h), yoksa oluşturulan Harf nesnesinin veya yeni bir Harf nesnesinin bu yordama gönderilmesi gibi birşey söz konusu değildir. */ h.c = 'z'; } public static void main(String[] args) { Harf x = new Harf(); // Harf nesnesini oluşturuluyor. x.c = 'a'; // Harf nesnesinin c alanına değer atandı System.out.println("1: x.c: " + x.c); f(x); // dikkat System.out.println("2: x.c: " + x.c); }} |
Yukarıda verilen örnekte Harf ve Pas olarak adlandırılan 2 adet sınıf bulunmaktadır. Pas sınıfı public olduğu için fiziksel dosyanın ismi Pas.java’dır. Bu kadar ön bilgiden sonra
program açıklamasına geçilebilir: İlk olarak Harf nesnesi oluşturuluyor ve Harf
nesnesin char tipinde olan c alanına ‘a’ karakteri atanıyor. Yapılan işlem ekrana
yazdırıldıktan sonra Harf nesnesine
bağlanmış olan Harf sınıfı tipindeki x referansı
f() yordamına gönderiliyor; sonra, f() yordamı içerisinde daha önceden oluşturulan Harf nesnesinin char tipinde olan c alanına ‘z’ karakteri atanıyor.
Bilgiler yeniden ekrana yazdırıldığında Harf
nesnesinin char tipinde olan c alanındaki değerin değişmiş
olduğu görülür. Burada yapılan işlem, kesinlikle, Harf nesnesinin yer değiştirmesi değildir; nesnenin bellekteki yeri
her zaman sabittir... Yalnızca f() yordamı içerisinde Harf nesnesine kısa süreli olarak başka
bir Harf sınıfı tipindeki bir referansın
işaret etmiş olmasıdır (böylece Harf nesnesine
toplam iki referans bağlı olmaktadır biri x
diğeri ise h ). Yordamın sonuna gelindiğinde
ise h referansı geçerlilik alanı
bitmektedir; ancak, bu kısa süre içerisinde Harf
nesnesinin char tipinde olan c alanını değiştirilmiştir. Uygulamanın sonucu
aşağıdaki gibi olur: (yorum ekle)
1: x.c: a2: x.c: z |
Yordam çağrımları temel
tipler için biraz daha açıktır. (yorum ekle)
Örnek: IlkelPas.java
(yorum ekle)
public class IlkelPas { static void f(double a) { System.out.println(a + " gonderildi"); a = 10 ; System.out.println("gonderilen parametrenin degeri 10'a” + “esitlendi"); } public static void main(String[] args) { double a = 5 ; f(a); System.out.println("a --> " + a ); }} |
Yukarıdaki uygulamada double tipindeki a değişkenine 5 değeri atanmaktadır;
daha sonra bu değişkenimiz double tipinde parametre kabul
eden f() yordamına gönderilmektedir.
f() yordamı içerisinde a=10 ifadesi, gerçekte, main() yordamı içerisindeki double tipindeki a değişkeni ile hiç bir
ilgisi yoktur. Bu iki değişken birbirlerinden tamamen farklıdırlar. Sonuç
olarak, temel tipler değerleri kendi üzerlerinde taşırlar. Yordamlara
gönderilen parametreler yerel değişkenler gibidir. Uygulamanın sonucu aşağıdaki
gibi olur: (yorum ekle)
5.0 gonderildigonderilen parametrenin degeri 10'a esitlendia --> 5.0 |
Operatörler programlama
dillerinin en temel işlem yapma yeteneğine sahip simgesel isimlerdir. Tüm
programlama dillerinde önemli bir yere sahip olup bir işlem operatör ile
gerçekleştirilebiliyorsa “en hızlı ve verimli ancak bu şekilde yapılır”
denilebilir. Yalnızca bir operatör ile gerçekleştirilemeyen işlemler, ya bir
grup operatörün biraraya getirilmesiyle ya da o işlemi gerçekleştirecek bir
yordam (method) yazılmasıyla sağlanır. Java dili oldukça
zengin ve esnek operatör kümesine sahiptir; örneğin matematiksel, mantıksal,
koşulsal, bit düzeyinde vs. gibi birçok operatör kümesi vardır; ve, bunlar
içerisinde çeşitli operatörler bulunmaktadır:
(yorum ekle)
§ Aritmetik Operatör
§ İlişkisel Operatör
§ Mantıksal Operatörler
§ Bit düzeyinde (bitwise) Operatörler
Operatörler, genel olarak,
üzerinde işlem yaptığı değişken/sabit sayısına göre tekli operatör (unary operator) veya ikili operatör (binary
operator)
olarak sınıflanmaktadır; 3 adet değişken/sabite ihtiyaç duyan operatörlere de üçlü
operatör denilir. Yani, tek değişken/sabit üzerinde işlem yapan operatör,
iki değişken/sabit üzerinde işlem yapan operatör gibi... Tekli operatörler hem
ön-ek (prefix) hem de son-ek (postfix) işlemlerini desteklerler. Ön-ek’ten kastedilen anlam operatörün
değişkenden önce gelmesi, son-ke’ta de operatörden sonra gelmesidir... (yorum ekle)
|
à operatör değişken //ön-ek ifadesi |
Son-ek işlemlerine örnek
olarak,
|
à değişken
operatör // son-ek ifadesi |
İkili operatörlerde operatör
simgesi ara-ek (infix) olarak iki değişkenin ortasında bulunur: (yorum ekle)
|
à değişken1 operatör değişken2 //ara-ek |
Üçlü
operatörlerde ara-ek (infix)
işlemlerde kullanılır. Java’da üçlü operatör bir tanedir. (yorum ekle)
|
à değişken1 ? değişken2 :
değişken3 //ara ek |
Java programlama dili kayan-noktalı (floating-point) ve tamsayılar için birçok aritmetik işlemi destekleyen çeşitli operatörlere sahiptir. Bu işlemler top