Sınıf Yapıları – II

Bir önceki yazımızda sınıf yapılarına giriş yapmıştık. Sınıfların genel özelliklerinden bahsetmiştik ve sınıfların fieldlar ve methodlardan oluştuğunu söylemiştik. Bununla birlikte constructor (Yapıcı fonksiyonlar) ile nesne yaratmaya değinmiştik.

Bir Sınıfa Ait Bir Nesne Yaratmak

Constructor yani yapıcı fonksiyon ile ilgili bazı eklemeler ile konuya devam edelim. Söz dizimi ile ilgili yazımızda methodların yanında bulunan parantezlerin, methoda yollanmak istenen parametrelerin eklendiği/sıralandığı yer olduğunu söylemiştik. Constructor çağrısını yaptığımız satırı tekrar hatırlayalım.

KaraAraclari otomobil = new KaraAraclari();

Eşittir operatörünün sağ tarafında gördüğünüz ifade, new sözcüğü sebebiyle, özel bir method çağrısıdır. Ancak KaraAraclari sınıfımızda yine ismi/imzası KaraAraclari() olan bir method tanımlamadık. Peki bu olmayan methodu nasıl çağırdık.

Constructor kavramı javada özelleşmiş kavramlardandır. Constructor barındırmayan bir sınıf olmaz. Eğer bir constructor tanımlamıyorsanız java sizin yerinize bir tane tanımlayacaktır. Buna default constructor ismi verilir. Peki java bize bir default constructor veriyorsa neden farklı bir tane tanımlayalım ki?

Bu sorunun birden fazla cevabı bulunmakta. Örneğin size şöyle bir istek geldi diyelim:

  • Yeni bir kara aracı yaratıldığında bununla ilgili bir bildirimi ekrana yazdırmalıyız.

Bu sorunu yeni bir kara aracı yarattığımız her yerde bir ekrana bildirim yazdıran bir satırla yapmak mümkün. Ancak bu durumun 1 milyon defa tekrar ettiğini ve bir gün bu bildirimin artık kapatılması gerektiğini düşünün. Böyle bir senaryoda 1 milyon ayrı kod satırının silinmesi büyük bir iş olacaktır. Peki bu durumu nasıl çözebilirdik?

Her nesne yarattığımız yerde bildirim üreten kodu yazmak yerine, nesnenin yaratılma anında bunu yaparsak daha doğru olacaktır. Yani constructor içerisinde! Böylece, bir gün bu bildirim kapatılacaksa bu durumda 1 milyon satır kod değiştireceğimize, 1 satırı değiştirmemiz yeterli olacaktır. Peki ama default constructor bizim yerimize java tarafından tanımlanıyordu. Bunu nasıl düzenleyebiliriz? Bunun cevabı da basit: Default constructor tanımını kodunuza ekleyerek. Gelin bunu kodda görelim.

public class KaraAraclari {

	public int koltukSayisi;
	
	public KaraAraclari() {
		
	}

	public void hareketEt() {
		System.out.println("Hareket başladı");
	}

	public void dur() {
		System.out.println("Hareket bitirildi");
	}

	public void yonVer() {
		System.out.println("Yön verildi");
	}

}

Burada “public KaraAraclari()” ile verilmiş blok java tarafından tanımlanan default constructor fonksiyonunun kendisidir. Bu fonksiyonu sınıfın içerisine aldığımız için artık üzerinde değişiklikler yapabiliriz. Örneğin ekrana yeni bir araç yaratıldığını yazdıralım.

	public KaraAraclari() {
		System.out.println("Yeni bir araç yaratıldı");
	}

Eğer TestClass sınıfınızdaki main methodunu çalıştırırsanız aşağıdaki gibi bir çıktı elde edersiniz.

Şimdi de farklı bir ihtiyaçtan bahsedelim. Yeni bir kara aracı yaratıldığında, bu aracın koltuk sayısı “4” olarak ayarlansın. Bunun için constructor üzerinde minik bir değişiklik yapmamız gerekecek. Aşağıdaki gibi kodumuzu düzenliyorum.

	public KaraAraclari() {
		//System.out.println("Yeni bir araç yaratıldı");
		this.koltukSayisi = 4;
	}

Burada yeni bir ifade ile karşılaşıyoruz: “this“. Bu yeni ifadenin anlamı “Bu sınıfın içerisindeki” olarak ifade edilebilir. Dolayısıyla this.koltukSayisi, bu sınıftaki koltuk sayısı anlamına gelmektedir. TestClass ile bu durumu test etmek istersek aşağıdaki gibi bir kod parçası ile bunu gerçekleştirebiliriz.

Buradaki ifadeye dikkat ederseniz, ekrana değeri yazdıran fonksiyonda this.koltukSayisi değil otomobil.koltukSayisi ifadesi kullanılmıştır. Çünkü TestClass sınıfı içerisinde kullanılacak olan this ifadesi yine TestClass sınıfına ait fieldları/methodları refere edecektir. Bir sınıfa ait fielda, o sınıfın dışından erişirken değişken adını kullanırız. Buradaki örnekte değişkenimizin adı otomobil olduğundan ifade de buna göre yazılmıştır.

Alternatif Nesne Yaratma Yöntemi

Bildiğiniz gibi bisiklet de otomobil de kara aracıdır. Ancak bunların birisi tek, diğeri ise dört koltukludur. Bu durumda az önce yaptığımız örnek yanlış bir şekilde çalışmaktadır. Bu durumu düzeltmek için yapıcı fonksiyonumuzu parametrik bir hale getirmeliyiz. Bunun için constructor üzerinde bir değişiklik yapacağız. Aşağıdaki düzenlemeyi gerçekleştiriyoruz:

	public KaraAraclari(int kacKoltuk) {
		this.koltukSayisi = kacKoltuk;
	}

Bu değişikliği yaptığınızda TestClass sınıfınız hata verecektir. Ancak telaşa mahal yok, bunu düzelteceğiz. Öncelikle burada ne yaptığımızı anlatalım. Kavramsal olarak bazı ifadelerin sizde de oluşması için, bu durumları jargona uygun şekilde ifade etmek istiyorum.

  • Method imzasını değiştirdik: Method imzası, bir methodun içeriği olmadan onun erişim düzenleyicisini, geriye döndürdüğü değerin tipini, methodun adını ve methoda gönderilen parametreleri, bu parametrelerin tipini gösteren ifadedir. Methoddaki ana/dış bloğu kaldırdığımızda geriye imzası kalmaktadır. Bu değişiklikle daha evvel parametre almayan bir methoda (constructor) parametre (int kacKoltuk) göndermeye başladık. Dolayısı ile method imzasını değiştirdik ifadesini kullanabiliriz.
  • Methoda parametre geçtik: Bir üst maddede belirttiğim gibi daha evvel parametresiz çalışan bir methoda sayısal bir değeri parametre olarak gönderdik. Parametreler parantez içindeki ifadelerdir. İmzaya parametre eklenirken yani methoda parametre geçilirken, önce parametrenin tipi sonra da method bloğu (scope) boyunca geçerli olacak olan parametre ismi eklenir.

Peki neden TestClass sınıfımız hata verdi? Yeri gelmişken editörümüzün kullanımına da bakalım. TestClass sınıfımıza gidelim. Altı kırmızı ile çizili ifadeye imlecimizi getirdiğimizde aşağıdaki gibi bir görüntüyle karşılaşacaksınız.

Burada editörün bize şunu söylediğini görüyoruz: “Parametre almayan, yani KaraAraclari() imzasına sahip, bir constructor bulunmamaktadır.”

İyi, ancak bu imza default constructora ait ve bunu java bize vermeliydi. Bu durum ancak başka bir constructor tanımı yapılmadıysa geçerlidir. Biz constructorımızın imzasını değiştirip ona parametre eklemiştik. Bu durumda java default constructor için sergilediği davranışını sergilemez ve onu yok eder. Peki bu kötü bir şey değil midir? Cevap ise hayır olacaktır. Bu iyi bir şeydir. Java sizin kurallara bağlı kalmanızı ister. Kural “1 parametre ile nesne yaratabilirsin” ise iki parametre ile ya da hiç parametresiz obje yaratma işlemi gerçekleşmez. Ancak size güzel bir haberim var. Java aynı zamanda yeni bir kural eklemenize izin verir. Gelin şimdi bu durumu yakından inceleyelim.

Kara araçlarını temsil ettiğimiz sınıfımıza yeni bir field daha ekleyerek bu işe başlayalım. Yine etrafımızdaki araçları düşünürsek hepsinin özelliği olarak bir renge sahip olmaları aklımıza gelecektir. O halde sınıfımıza bu özelliği ekleyelim. Tahmin edeceğiniz üzere renk özelliği sayısal bir değerle ifade edilmeyip; metin değer taşıyan bir özelliktir. O halde tipi String olacaktır. Sınıfımızı aşağıdaki gibi güncelliyoruz.

public class KaraAraclari {

	public int koltukSayisi;
	
	public String renk;
	
	public KaraAraclari(int kacKoltuk) {
		this.koltukSayisi = kacKoltuk;
	}

	public void hareketEt() {
		System.out.println("Hareket başladı");
	}

	public void dur() {
		System.out.println("Hareket bitirildi");
	}

	public void yonVer() {
		System.out.println("Yön verildi");
	}

}

Bu durumda ise mevcut constructor ile rengi olan bir araç yaratamıyoruz. Oysa ki constructor fonksiyonumuz iki parametre alsaydı bu duruma düşmeyecektik. Bu şekilde tasarlanmış bir constructor için kod şuna benzerdi:

public KaraAraclari(int koltukSayisi, String renk) {
    this.koltukSayisi = koltukSayisi;
    this.renk = renk;
}

Burada işleri biraz daha karıştırmak istedim. Öncelikle imzaya bakalım. Constructor imzasında, parametre sayısında bir değişiklik olmuş. Parametre kısmı bize şunu söylüyor: “Bu constructor 2 parametre ile çağırılabilir. Bunlardan ilk olan değer sayısaldır ve koltukSayisi ismindedir. İkinci sıradaki parametre ise metin bir değerdir ve ismi renk olacaktır.”

Buraya kadar her şey güzel. Ancak koltukSayisi ve renk isimleri sınıfımızın içerisinde ayrıca bir field idi. Bu ikisini (field ve parametre) birbirinden nasıl ayırt edeceğiz? Buradaki anahtar this sözcüğüdür. Constructor içerisine bakarsanız this.koltukSayisi = koltukSayisi ifadesini görürsünüz. Bunun anlamı “Sınıf içerisindeki koltukSayisi isimli fielda constructora parametre olarak gelen koltukSayisi değerini ata” olacaktır. Aynı durum renk için de geçerlidir.

Bu iki constructordan birini koda eklediğimizde parametresiz, yani default, constructor kaybolacak. Ancak bizim buradaki yaklaşımımız bu üçünden de aynı anda faydalanabilmekti. Güzel haber ise hiçbirinden vazgeçmeden üçüne birden sahip olabileceğimizdir. Hiç çekinmeden bu üç constructor fonksiyonumuzu kodumuza ekliyoruz ve kodumuzu finalize ediyoruz. Ben ayrıca her constructor içerisine bir de ekrana yazı yazan bir kod ekleyeceğim ki örnekler kafanızda daha net otursun.

public class KaraAraclari {

	public int koltukSayisi;
	
	public String renk;
	
	public KaraAraclari() {
		System.out.println("Yeni bir araç yaratıldı (Parametresiz)");
	}
	
	public KaraAraclari(int kacKoltuk) {
		System.out.println("Yeni bir araç yaratıldı (1 parametreli)");
		this.koltukSayisi = kacKoltuk;
	}
	
	public KaraAraclari(int koltukSayisi, String renk) {
		System.out.println("Yeni bir araç yaratıldı (2 parametreli)");
		this.koltukSayisi = koltukSayisi;
		this.renk = renk;
	}

	public void hareketEt() {
		System.out.println("Hareket başladı");
	}

	public void dur() {
		System.out.println("Hareket bitirildi");
	}

	public void yonVer() {
		System.out.println("Yön verildi");
	}

}

Parametresiz constructor da eklendiği için TestClass sınıfımızdaki hata da ortadan kaybolmuş olacak. Şimdi bunlarla bir test yapalım. TestClass sınıfımızı aşağıdaki gibi düzenliyoruz.

public class TestClass {

	public static void main(String[] args) {
		
		KaraAraclari birinciArac = new KaraAraclari();

		KaraAraclari ikinciArac = new KaraAraclari(1);
		
		KaraAraclari ucuncuArac = new KaraAraclari(2, "Kırmızı");
	}
}

Gördüğümüz üzere çıktıya bakarak 3 ayrı constructor fonksiyonunun da çalıştığını gözlemleyebiliyoruz. Ana konudan bağımsız olarak dikkatinizi bir noktaya daha çekmek istiyorum. Gönderdiğimiz parametrelerde sayısal değerleri doğrudan yazarken, metin ifadeleri çift tırnak içerisine aldık. Bu da bir söz dizim kuralı gereğidir. Eğer “Kırmızı” yerine Kırmızı yazsaydık editör bize kızacak ve programımız çalışmayacaktı.

Bu yazımızı da burada sonlandırıyoruz. Bir sonraki yazımız tekrar sınıflar üzerine olacak. Konuları giderek derinleştireceğiz ve javanın temellerinde yatan kavramları tek tek işleyeceğiz. Her zamanki gibi bol tekrar öneriyorum.

Leave a Comment

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir