BÖLÜM 3

 

Altuğ B. Altıntaş
© 2004

 

 

 

NESNELERİN BAŞLANGIÇ DURUMU

VE TEMİZLİK

 

 

 

 

Bir nesnenin başlangıç durumuna getirilme işlemini bir sanatçının sahneye çıkmadan evvelki yaptığı son hazırlıklar gibi düşünebilir... Oluşturulacak olan her nesne kullanıma sunulmadan önce bazı bilgilere ihtiyaç duyabilir veya bazı işlemlerin yapılmasına gereksinim duyabilir. Uygulama programlarının çalışması sırasında oluşan hataların önemli nedenlerden birisi de, nesnelerin yanlış biçimde başlangıç durumlarına getirilmesidir; diğeri ise, temizlik işleminin doğru dürüst yapılmamasıdır. Tasarımcı, bilmediği kütüphanelere ait nesneleri yanlış başlangıç durumuna getirmesinden ötürü çok sıkıntılar yaşayabilir. Diğer bir husus ise temizliktir. Temizlik işleminin doğru yapılmaması durumunda, daha önceden oluşturulmuş ve artık kullanılmayan nesneler sistem kaynaklarında gereksiz yer kaplarlar; ve bunun sonucunda ciddi problemler oluşabilir. Bu bölümde nesnelere başlangıç değerleri verilmesi ve temizleme sürecinin Java programlama dilinde nasıl yapıldığı ele alınmıştır. (yorum ekle)

 

3.1.    Başlangıç Durumuna Getirme İşlemi ve Yapılandırıcılar (Initialization and Constructor)

Başlangıç durumuna getirme işlemlerin gerçekleştiği yer bir çeşit yordam (method) diyebileceğiz yapılandırıcılardır (constructor); ancak, yapılandırıcılar normal yordamlardan çok farklıdırlar. Şimdi biraz düşünelim... Elimizde öyle bir yapılandırıcı olacak ki, biz bunun içerisinde nesnenin kullanılmasından önce gereken işlemleri yapacağız; yani, nesneyi başlangıç durumuna getireceğiz. Ayrıca, Java bu yapılandırıcıyı, ilgili nesneyi oluşturmadan hemen önce otomatik olarak çağırabilecek... (yorum ekle)

Diğer bir problem ise yapılandırıcının ismidir; bu isim öyle olmalıdır ki, diğer yordam (method) isimleriyle çakışmamalıdır. Ayrıca Java’nın bu yapılandırıcıyı otomatik olarak çağıracağı düşünülürse, isminin Java tarafından daha önce biliniyor olması gerekir. (yorum ekle)

Bu problemlere ilk çözüm C++ dilinde bulunmuştur. Çözüm, yapılandırıcıyla sınıf isimlerinin birebir aynı olmasıdır (büyük küçük harf dahil). Böylece Java sınıfın yapılandırıcısını bularak, buna ait bir nesne oluşturmak için ilk adımı atabilecektir. Küçük bir uygulama üzerinde açıklanmaya çalışırsa, bir sonraki sayfadaki örnek verilebilir: (yorum ekle)

 

Örnek-3.1:  YapilandirciBasitOrnek.java (yorum ekle)

 
class KahveFincani { 
 
  public KahveFincani() { 
      System.out.println("KahveFincani...");
  } 
}
 
public class YapilandirciBasitOrnek { 
  public static void main(String[] args) {
       for(int i = 0; i < 5; i++) 
            new KahveFincani(); 
  } 
}
 

 

Yukarıda verilen örnekte art arda 5 adet KahveFincani nesnesi oluşturuluyor; dikkat edilirse, nesneler oluşturulmadan önce (ellerimizi kahve fincanlarının üzerine götürmeden) ekrana kendilerini tanıtan ifadeler yazdılar; yani, nesnelere ilk değerleri verilmiş oldu... (yorum ekle)

Dikkat edilmesi gereken ikinci unsursa, yapılandırıcıya (constructor) verilen isimdir; bu içinde bulunduğu sınıf ismi ile birebir aynıdır. Anımsarsanız, normalde yordam isimleri bir fiil cümlesi içermeliydi (dosyaAc(), openFile(), dosyaOku(), readFile(), dosyaYaz(), arabaSur() vb.); ancak, yapılandırıcılar bu kuralın da dışındadır. Yukarıda verilen uygulamanın sonucu aşağıdaki gibi olur:  (yorum ekle)

 
KahveFincani...
KahveFincani...
KahveFincani...
KahveFincani...
KahveFincani...
 

Yapılandırıcılar, yordamlar (methods) gibi parametre alabilirler:

 

Örnek:  YapilandirciBasitOrnekVersiyon2.java (yorum ekle)

 
class YeniKahveFincani {
  public YeniKahveFincani(int adet) {
       System.out.println(adet + " adet YeniKahveFincani");
  } 
}
 
public class YapilandirciBasitOrnekVersiyon2 { 
  public static void main(String[] args) {
      for(int i = 0; i < 5; i++) 
          new YeniKahveFincani( i );
  }
} 
 

 

Gönderilen parametre sayesinde nesnenin nasıl oluşacağı belirtebilmektedir. Bu örnekte olduğu gibi YeniKahveFincani nesnesi oluşturulurken kaç adet olacağı söylenebiliyor. Uygulamanın sonucu aşağıdaki gibi olur: (yorum ekle)

 

0 adet YeniKahveFincani
1 adet YeniKahveFincani
2 adet YeniKahveFincani
3 adet YeniKahveFincani
4 adet YeniKahveFincani
 

Yapılandırıcılar, yordamlardaki gibi değer döndürme mekanizmasına sahip değildirler; herhangi bir şekilde değer döndüremezler. Bu değer döndürülemez ibaresi yordamlardaki void ifadesine karşılık gelmemektedir. Yapılandırıcılardan çıkılmak isteniyorsa return kullanabilir.  (yorum ekle)

 

3.1.1.    Bir İsmin Birden Çok Yordam İçin Kullanılması

            - Adaş Yordamlar (Overloaded Methods)

İyi bir uygulama yazılması her zaman için iyi bir takım çalışması gerektirir; takım çalışmasının önemli kurallarından birisi de birinin  yazdığı kodu diğer kişilerin de kolaylıkla anlayabilmesinden geçer. Uygulamalardaki yordam isimlerinin, yordam içerisinde yapılan işlerle uyum göstermesi önemlidir. Bu sayede bir başka kişi sadece yordamın ismine bakarak, bu yordam içerisinde oluşan olayları anlayabilme şansına sahip olabilir. Örneğin elimizde bulunan müzik, resim ve metin (text) formatındaki dosyaları açmak için yordamlar yazılmak istenirse, bunların isimlerinin ne olması gerekir? Müzik dosyasını açan yordamın ismi muzikDosyasiAc(), resim dosyası için resimDosya-sıAc(), metin dosyasını açmak için ise textDosyasınıAc() gibi üç ayrı yordam ismi kullanılması ne kadar akıllıca ve pratik olur? Sonuçta işlem sadece dosya açmaktır; dosyanın türü sadece bir ayrıntıdır. Bir ismin birçok yordam için kullanılması (method overloading) bize bu imkanı verebilmektedir. Aynı tür işleve sahip olan yordamların aynı isimlere sahip olabilme özelliği, bizi isim bulma sıkıntısından da kurtarmaktadır.   (yorum ekle)

 

Örnek-3.2:  YordamOverloadingDemo1.java  (yorum ekle)

 
class MuzikDosyasi {
  String m_tur = "Muzik Dosyasi" ;
}
 
class ResimDosyasi {
  String r_tur = "Resim Dosyasi" ;
}
 
class TextDosyasi {
  String t_tur = "Text Dosyasi" ;
}
 
public class YordamOverloadingDemo1 {
  public void dosyaAc(MuzikDosyasi md) {
    System.out.println( "Tur =" + md.m_tur );
  }
 
 
  public void dosyaAc(ResimDosyasi rd) {
    System.out.println( "Tur =" + rd.r_tur );
  }
 
  public void dosyaAc(TextDosyasi td) {
    System.out.println( "Tur =" + td.t_tur );
  }
 
  public static void main(String[] args) { 
      YordamOverloadingDemo1 mod1 = new YordamOverloadingDemo1();
      MuzikDosyasi md = new MuzikDosyasi();       
      ResimDosyasi rd = new ResimDosyasi();       
      TextDosyasi td = new TextDosyasi();
      mod1.dosyaAc(md);
      mod1.dosyaAc(rd);
      mod1.dosyaAc(td);
  }
}
 

 

Uygulamamızın sonucu aşağıdaki gibi olur:

 

Tur =Muzik Dosyasi
Tur =Resim Dosyasi
Tur =Text Dosyasi
 

Yukarıdaki örnekte görüldüğü gibi aynı tür işlemleri yapan yordamların isimleri aynıdır. Peki, Java aynı isimde olan bu üç yordamı birbirinden nasıl ayırt etmektedir? (yorum ekle)

 

Œ Adaş Yordamlar Nasıl Ayırt Edilirler?

Java aynı isme sahip olan yordamları nasıl ayırt edebilmektedir? Cevap olarak parametrelerine göre denilebilir. Konu biraz daha açılırsa, her yordamın kendisine ait özel ve tek  parametresi veya parametre listesi olmak zorundadır.  (yorum ekle)

 

Örnek-3.4:  YordamOverloadingDemo2.java  (yorum ekle)

 
public class YordamOverloadingDemo2 {
  public int toplamaYap(int a , int b){
      int sonuc = a + b ;
      System.out.println("sonuc - 1 = " + sonuc);
      return sonuc ;
  }
 
  public void toplamaYap(int a , double b){
      double sonuc = a + b ;
      System.out.println("sonuc - 2 = " + sonuc);
  }
 
  public double toplamaYap(double a , int b){
      double sonuc = a + b ;
      System.out.println("sonuc - 3= " + sonuc);
      return sonuc ;
  }
 
 
  public static void main(String[] args) { 
      YordamOverloadingDemo2 mod2 = new YordamOverloadingDemo2();
      mod2.toplamaYap(3,4);
      mod2.toplamaYap(3,5.5);
      mod2.toplamaYap(6.8,4);
  }
}
 

 

Bu örnekte üç adet toplamaYap() yordamının parametreleri birbirinden bir şekilde farklıdır: toplamaYap() yordamının ilki, 2 adet temel int tipinde parametre alarak diğer adaş yordamlarından ayrılmaktadır; geriye kalan 2 adet  toplamaYap() yordamı ise aynı tip parametreler almaktadır. Bunlar temel double tipi ve int tipi, bu iki yordamı birbirinden farklı kılan, parametrelerin sırasıdır. Uygulamanın çıktısı aşağıdaki gibidir: (yorum ekle)

 

sonuc – 1 = 7
sonuc - 2 = 8.5
sonuc – 3= 10.8
 
 
Dönüş Değerlerine Göre Adaş Yordamlar Ayırt Edilebilir mi ?

Akıllara şöyle bir soru gelebilir: "Adaş yordamlar dönüş tiplerine göre ayırt edilebilir mi?"  İnceleyelim:

 

Gösterim-3.1:

 
void toplamaYap();
double toplamaYap();
 

 

Elimizde 2 adet aynı isimde ve aynı işlemi yapan, fakat biri değer döndürmeyen (void) diğeri ise double tipinde değer döndüren yordamların olduğunu varsayalım.   (yorum ekle)

 

Gösterim-3.2:

 
double y = toplamayap();
 

 

Gösterim-3.2  için, Java bu yordamlardan hangisini seçeceğini tahmin edebilir; double toplamaYap()... Peki aşağıdaki gibi bir durum için nasıl bir yol izlenmesi gerekir?   (yorum ekle)

 

Gösterim-3.3:

 
toplamayap() ;
 

 

Değer döndüren bir yordamı döndürdüğü tipe karşılık gelen değişkene atama zorunluluğu olmadığı hatırlatalım. Kısacası bu koşulda Java hangi yordamı çağıracağını bilemeyecektir. Bu nedenle, Java dilinde dönüş tiplerine göre yordamların ayırt edilmesi kabul görmez; ayırt edilmesini sağlayan tek şey parametrelerindeki farklılıktır. (yorum ekle)

 

3.1.2.  Varsayılan Yapılandırıcılar (Default Constructors)

Eğer uygulamaya herhangi bir yapılandırıcı koyulmazsa, Java bu işlemi kendiliğinden yapmaktadır. Varsayılan yapılandırıcılar aynı zamanda parametresiz yapılandırıcılar (default constructor veya "no-args" constructor)  olarak ta anılmaktadır; bunları içi boş  yordamlar olarak düşünebilirsiniz.  (yorum ekle)

 

Örnek-3.5:  VarsayilanYapilandirici.java (yorum ekle)

 
class Kedi {
   int i;
}
 
public class VarsayilanYapilandirici {
    public static void main(String[] args) {
         Kedi kd = new Kedi();         //Varsayılan yapılandırıcı çağrıldı
    }
} 
 

 

Java’nın yerleştirmiş olduğu varsayılan yapılandırıcı açık bir şekilde gözükmemektedir. Açık şekilde görmek istenirse;   (yorum ekle)

 

Örnek-3.6:  VarsayilanYapilandirici.java (değişik bir versiyon) (yorum ekle)

 
class Kedi { 
   int i;
 /*  varsayılan yapılandırıcı bu yapılandırıcıyı eğer biz koymasaydık 
Java bizim yerimize zaten koyardı */
   public Kedi() {}
}
 
public class VarsayilanYapilandirici {
   public static void main(String[] args) {
       Kedi kd = new Kedi();         //Varsayılan yapılandırıcı çağrıldı
 }
} 
 
 
Œ  Büyünün Bozulması

Eğer, yapılandırıcı kodu yazan kişi tarafından konulursa, Java varsayılan yapılandırıcı desteğini çekecektir. Bunun nedeni şöyledir: Eğer bir sınıfa ait herhangi bir yapılandırıcı belirtilmezse, Java devreye girip kendiliğinden varsayılan bir yapılandırıcı koyar;  eğer, biz kendimize ait özel yapılandırıcılar tanımlarsak, şöyle demiş oluruz: "Ben ne yaptığımı biliyorum, lütfen karışma". Bu durumda olası tüm yapılandırıcılar bizim tarafımızdan yazılması gerekir. Şöyle ki: (yorum ekle)

 

Örnek-3.7:  VarsayilanYapilandiriciVersiyon2.java (yorum ekle)

class Araba {
  int kapi_sayisi;
  int vites_sayisi ;
 
  public Araba(int adet) {
      kapi_sayisi = adet ;
  }
 
  public Araba(int adet, int sayi) {
      kapi_sayisi = adet ;
      vites_sayisi = sayi ;
  }
}
 
public class VarsayilanYapilandiriciVersiyon2 { 
   public static void main(String[] args) {
        Araba ar = new Araba();   //  ! Hata var!  Bu satır anlamlı değil; yapılandırıcısı yok 
        Araba ar1 = new Araba(2);
        Araba ar2 = new Araba(4,5);
  }
}

&n