JAVA – Inheritance(Kalıtım) nedir?

JAVA – Inheritance(Kalıtım) nedir?

28 Kasım 2010 0 Yazar: Cem Kefeli

Daha önce nesneye yönelik bir dilin olmazsa olmazlarından birisi olan kalıtım(Inheritance) konusundan Polymorphism nedir? başlıklı yazım içerisinde bahsetmiştim. Çünkü çok biçimlilik(Polymorphism) kalıtım ile oldukça iç içe geçmiş ve kalıtımın yok açtığı doğal sonuçların bir uygulaması olarak göze çarpmaktadır. Dolayısı ile kalıtımın olmadığı bir ortamda çok biçimlilikten söz etmek olanaksızdır.

OOP(Object Oriented Programming) diyorsak nesnelerden bahsediyoruz demektir. Herşey nesne olarak düşünülebilir. Nesneler ise birbirlerinden türeyebilmektedir. Örneğin bir ana sınıf düşünün aklınızda, bir de bu ana sınıfın yavrucuklarını düşünün. Yavrucukları diyorum ama, bunu yavru sınıflar daha küçüktür, daha az öğe içerir gibi düşünmeyin sakın. Tam tersine bu yavrucuklar daha gelişkin olabilirler. Annelerinin tüm özelliklerine sahip olurlar da, hatta bir de annelerinden farklı başka özellikler de içerebilirler. Bu yavrucukların da yavrucukları olabilir. Bu böyle devam eder gider. Hemen aşağıda kalıtımın olduğu bir ortamdan ve bunun uygulamalarından bahsetmeye çalışacağım.

Sağ tarftaki UML diagramında bir kalıtım yapısı bulunmakta. TASIT ana sınıfı(Base class) BenNeyim isminde bir fonksiyon ve integer türünde Deger1Deger2Deger3 isimli üç farklı değişken bulundurmaktadır. TASIT sınıfına ait BenNeyim isimli fonksiyon kendisinin bir taşıt olduğunu belirten log yazdırmaktadır. MOTORLUTASIT ve MOTORSUZTASIT sınıfları ise TASIT ana sınıfından türemekte ve Deger4 isimli integer türünden bir değişken bulundurmaktadır. Java dilinde türetme işlemleri extends anahtar sözcüğü ile yapılmaktadır. Deger4 ise ana sınıfta bulunmayan ve türeyen sınıflar(Derived class) ile birlikte gelen bir değişkendir. Peki ya ana sınıftaki Deger1Deger2Deger3 isimli değişkenlere ne oldu? Acaba yeni türeyen MOTORLUTASIT ve MOTORSUZTASIT sınıfları içerisinden bu değişkenlere erişip kontrol edebilir miyim ki? Bu sorularımıza ve merakımıza biraz daha gem vuruyor ve şimdilik aklımızın bir köşesine yazarak az sonra öğrenmek için bir kenera bırakıyoruz. Dikkat edilirse yeni türettiğimiz sınıflar ile birlikte güzel bir ayrıntı gözümüze çarpar oldu. Artık ” Türeyen her sınıf, ana sınıfı içerir” diyebiliriz kolay bir şekilde. Yani bir bakıma her MOTORLUTASIT ve MOTORSUZTASIT aslında birer TASIT‘tır demek oluyor bu. İşte aralarında bu şekilde ilişki kurulabilen her ortamda kalıtımdan söz etmek mümkündür. Bu bahsettiğimiz ‘IS A’ ilişkisi olarak bilinmektedir. (“MOTORLUTASIT IS A TASIT” == MOTORLUTASIT bir TASIT‘tır.) Yine bu türemiş sınıflara ait BenNeyim fonksiyonu da sınıfın ne olduğunu yazdırmaktadır. TAKSI ve OTOBUSMOTORLUTASIT sınıfından türeyen sınıflardır. Fakat bu sınıfların kendisine özgü başka değişkenleri oluşturulmamıştır. Oluşturulma zorunluluğu da yoktur zaten. Ana sınıf içerisinde soyut(Abstract) olarak belirtilmedikçe override edilmesine gerek yoktur. Fakat ana sınıf içerisinde soyut olarak tanımlanmış bir öğenin alt sınıf içerisinde mutlaka override edilme zorunluluğu bulunmaktadır. Yazının ilerleyen bölümlerinde bu konuları daha detaylı inceleyeceğiz. Yalnızca MOTORLUTASIT sınıfına da kalıtım yolu ile geçen BenNeyim fonksiyonu iptal edilmiş(Override) ve kendisine özgü bir içerik oluşturulmuştur. Aynı şeyleri OTOBUS sınıfı için de söylemek mümkündür. BISIKLET sınıfı ise MOTORSUZTASIT sınıfından türemektedir ve tıpkı TAKSI ve OTOBUS gibi kendisine özgü yeni değişkenleri bulunmamaktadır. TAKSIOTOBUS ve BISIKLET sınıflarının üçüde kalıtım ile kendilerine geçen BenNeyim fonksiyonu içerisine kendisinin ne olduğunu yazdıran yeni kod blokları eklemişlerdir. Yukarıda sorduğumuz sorunun bi benzeri de burda söz konusudur. MOTORLUTASIT ve MOTORSUZTASIT türemiş sınıfları içerisinde yeni oluşturulan Deger4 isimli değişkeni acaba TAKSIOTOBUS ve BISIKLET sınıfları içerisinde kullanabilir miyim? En alt sınıf olan TASIT sınıfı içerisinde bu değişkenin olamamasına rağmen. İşte şimdi yavaş yavaş bu UML diagramına göre hazırlanmış ve bazı eklentiler yapılmış aşağıdaki kod bloğuna bakma ve sorularımızın cevabını alma vakti geldi.

Örneğin bir uygulama yazmak istiyoruz. Bu uygulama hem sürekli ekrana birşeyler yazacak hem de bir yandan ben klavyeden hangi metni girersem onu alıp aynen ekrana basacak. Yani iki iş parçacığından oluşuyor. Eğer multi-threaded bir yapı kullanmazsanız böyle bir uygulamayı gerçek anlamda oluşturamazsınız. Yapılacak işler birbiri ile çakışır, senkron değil de birbirini beklemek zorunda kalan iş parçacıkları oluşur.

Main.java

package Inheritance1;
 
/**
 *
 * @author Cem KEFELİ
 * http://www.cemkefeli.com
 */
public class Main
{
    static public class TASIT
    {
        Integer Deger1=new Integer(55);
        Integer Deger2=new Integer(11);
        Integer Deger3=new Integer(99);
        public void BenNeyim()
        {
            System.out.println("\nBen herhangi bir tasitim.");
            System.out.println("TASIT icin --> Deger1: "+Deger1.toString()+", Deger2: "+Deger2.toString()+", Deger3: "+Deger3.toString()+"");
        }
    }
    static public class MOTORLUTASIT extends TASIT
    {
        Integer Deger4=new Integer(111);
        @Override
        public void BenNeyim()
        {
            Deger2 = 15;
            System.out.println("\nBen motorlu bir tasitim.");
            System.out.println("MOTORLUTASIT icin --> Deger1: "+Deger1.toString()+", Deger2: "+Deger2.toString()+", Deger3: "+Deger3.toString()+", Deger4: "+Deger4.toString()+"");
        }
    }
    static public class MOTORSUZTASIT  extends TASIT
    {
        Integer Deger4=new Integer(222);
        @Override
        public void BenNeyim()
        {
            Deger2 = 19;
            System.out.println("\nBen motorsuz bir tasitim.");
            System.out.println("MOTORSUZTASIT icin --> Deger1: "+Deger1.toString()+", Deger2: "+Deger2.toString()+", Deger3: "+Deger3.toString()+", Deger4: "+Deger4.toString()+"");
        }
    }
    static public class TAKSI  extends MOTORLUTASIT
    {
        @Override
        public void BenNeyim()
        {
            Deger3 = 91;
            System.out.println("\nBen bir taksiyim.");
            System.out.println("TAKSI icin --> Deger1: "+Deger1.toString()+", Deger2: "+Deger2.toString()+", Deger3: "+Deger3.toString()+", Deger4: "+Deger4.toString()+"");
        }
    }
    static public class OTOBUS  extends MOTORLUTASIT
    {
        @Override
        public void BenNeyim()
        {
            Deger3 = 95;
            System.out.println("\nBen bir otobüsüm.");
            System.out.println("OTOBUS icin --> Deger1: "+Deger1.toString()+", Deger2: "+Deger2.toString()+", Deger3: "+Deger3.toString()+", Deger4: "+Deger4.toString()+"");
        }
    }
    static public class BISIKLET  extends MOTORSUZTASIT
    {
        @Override
        public void BenNeyim()
        {
            Deger3 = 98;
            System.out.println("\nBen bir bisikletim.");
            System.out.println("BISIKLET icin --> Deger1: "+Deger1.toString()+", Deger2: "+Deger2.toString()+", Deger3: "+Deger3.toString()+", Deger4: "+Deger4.toString()+"");
        }
    }
    public static void main(String[] args)
    {
        TASIT TASIT1=new TASIT();
        MOTORLUTASIT TASIT2=new MOTORLUTASIT();
        MOTORSUZTASIT TASIT3=new MOTORSUZTASIT();
        TAKSI TASIT4=new TAKSI();
        OTOBUS TASIT5=new OTOBUS();
        BISIKLET TASIT6=new BISIKLET();
        TASIT1.BenNeyim();
        TASIT2.BenNeyim();
        TASIT3.BenNeyim();
        TASIT4.BenNeyim();
        TASIT5.BenNeyim();
        TASIT6.BenNeyim();
    }
}

TASIT sınıfı içerisinde Deger1=55, Deger2=11Deger3=99 isimli değişkenlerimizi oluşturup başlangıç değerlerimizi atamışız. Sonrasında ise BenNeyim fonksiyonu içerisinde bu değerleri TASIT sınıfı için yazdırdık. Program çıktısında da görebileceğiniz gibi verdiğimiz başlangıç değerleri burada olduğu gibi yazdırılmış. Buralar zaten klasik olrak görünen şeyler ve kafamıza takılan bir nokta yok. Gelelim TASIT ana sınıfından türeyen MOTORLUTASIT ve MOTORSUZTASIT sınıflarına. Bu iki sınıf içerisinde de türedikleri sınıf içerisinde yer almayan Deger4 isimli bir değişken oluşturmuşuz. Değerini ise MOTORLUTASIT sınıfı için 111, MOTORSUZTASIT sınıfı için ise 222 olarak belirlemişiz. Buralarda da bir problem yok. Çünkü türeyen sınıf içerisinde yeni tanımlamalar yapılabileceğini ve bunun daha önce yapılan tanımlamalardan hiçbir farkının olmadığını daha önce söylemiştik. MOTORLUTASIT sınıfının BenNeyim fonksiyonu içerisinde sınıfa ait tüm integer tipindeki değişkenlerimizi yazdırıyoruz. İşte bu aşamada artık kalıtımın ta kendisini bizzat hissetmiş olmamız gerekiyor. Çünkü MOTORLUTASIT sınıfı içerisinde Deger4 için bir tanımlama yapmamıza rağmen Deger1Deger2 ve Deger3 için herhangi bir yeni tanımalama yapmadık. Fakat MOTORLUTASIT fonksiyonunun BenNeyim fonksiyonu içerisinde Deger1, Deger2, ve Deger3, değişkenlerini istediğimiz şekilde kullanabiliyoruz. Hatta Deger2 değişkeninin değerini değiştirerek 15 yapıyoruz. BenNeyim fonksiyonu içerisinde yazdırdığımız değerler ise Deger1=55, Deger2=15Deger3=99Deger4=11 olmuştur. Yazdırılan değerlere bakarsak ana sınıfımız olan TASIT sınıfında tanımaladığımız Deger1 ve Deger3 başlangıç değerlerini olduğu gibi görebiliyoruz. Kalıtım işte burada saklı. Ana sınıf içerisinde tanımladığımız her şey çocuklara miras kalıyor ve yavru sınıflar içerisinde de olduğu gibi kullanılabiliyor. Ana sınıflar içerisinde tanımlanan öğelerin yavru sınıflar içerisinde de kullanılabilmesine biz kalıtım diyoruz. MOTORSUZTASIT sınıfı için olanlar da MOTORLUTASIT sınıfı için olanlardan farklı değil aslında fakat burada ana sınıftan miras kalan Deger2 isimli değişkene 19 degerini vermişiz. BenNeyim fonksiyonu içerisinde de tüm değişkenleri yazdırdığımızda Deger1=55, Deger2=19Deger3=99Deger4=11 olarak yazılmıştır.

Artık torun diyebileceğimiz sınıflara geliyoruz. Bunlar TASIT dede sınıfının torunları. TAKSIOTOBUS ve BISIKLET sınıflarına bakacak olursak her hangi bir yeni tanımlamanın yapılmadığını görürüz. Fakat Deger3 değişkeninin değeri değiştirilmiştir. TAKSI sınıfının ana sınıfı olan MOTORLUTASIT sınıfında yeni tanımlanan ve MOTORLUTASIT sınıfının türediği ana sınıf olan TASIT sınıfında yer almayan Deger4 isimli değişkenimizi TAKSI sınıfı içerisinde de kalıtım yolu ile kolayca alıp istediğimiz gibi kullanabiliyoruz.
TAKSI
 sınıfının BenNeyim fonksiyonunu inceleyecek olursak Deger1 değişkeninin iki üst sınıf olan TASIT sınıfından başarı ile kalıtımlandığını ve başlangıç değeri olan 55 değerinin yazıldığını görürüz. Deger2 değişkeninin değerine bakacak olursak ise TASIT ana sınıfında başlangıç değeri olarak atanan 11 değerinin yazıldığını görürüz. Burada sanki bir tuhaflık görünüyor gibi. Biz TASIT sınıfı içerisinde Deger2 isimli bir değişken oluşturduk, sonra bu değişkenin değerini TASIT sınıfından türettiğimiz MOTORLUTASIT sınıfı içerisinde değiştirdik ve en son olarak da MOTORLUTASIT sınıfından türettiğimiz TAKSI sınıfının BenNeyim fonksiyonu içerisinde Deger2 değişkeninin değerini yazdırdık. Bu aşamada aklımıza hemen şöyle bir soru gelmelidir. Ben MOTORLUTASIT sınıfı içerisinde bu değişkenin değerini değiştirdim ve bu sınıftan yeni bir sınıf türeterek adını TAKSI koydum. Neden MOTORLUTASIT sınıfı içerisinde yaptığım değer değişikliğini burada göremiyorum? Burada dikkat edilmesi gereken şey şudur. Kalıtım ile sınıfların öğelerinin tanımlamaları kalıtsal olarak alt sınıflara iletilmektedir. Yani yapılar iletiliyor fakat değer değişiklikleri iletilmiyor. Eğer değer değişikliklerinin de alt sınıflara iletilmesini istiyorsak bunu yapıcı sınıflar içerisinde değer atamaları yaparak ya da kendimize ait bu iş için oluşturduğumuz bazı özel fonksiyonları yapıcı fonksiyon içerisinden çağırarak yapabiliriz. Bu konudaki bir örneği ilerleyen bölümlerde yapacağız. Gelelim Deger3 değişkenine. Deger3 değişkeninin degeri BenNeyim fonksiyonu içerisinde yazdırılmadan hemen önce değiştirilerek 91 yapılmıştır ve yazdırılan değer de budur. TAKSI sınıfının ana sınıfı MOTORLUTASIT sınıfı içerisinde yeni tanımlanan ve değeri 111 olarak atanan Deger4 isimli değişkenin yine kalıtım yolu ile geldiğini de tecrübe etmiş oluyoruz ve degerinin de kalıtım ile gelen 11 olduğunu görüyoruz.
OTOBUS sınıfı içerik bakımından TAKSI sınıfından çok da farklı değildir. Yine TAKSI sınıfında olduğu gibi bu sınıfta da Deger2 değişkeninin değerinin en temel sınıf olan TASIT sınıfındaki ile aynı olduğunu görebiliyoruz. Deger3 değişkeninin değeri ise burda da BenNeyim fonksiyonu içerisinde yazdırılmadan hemen önce değiştirilmiş ve 95 olarak yazdırılmıştır. BISIKLET sınıfı ise MOTORSUZTASIT sınıfından türetilmiştir ve az önce bahsettiğimiz olayların benzerleri de burada yaşanmıştır.

Şimdi ise az önceki örneği yaparken gözümüze çarpan ana sınıflara ait değişken değerlerinin yawru sınıf içerisinde değiştirildikten sonra kalıtım ile daha da alt sınıflara aktarılamama problemimize bir göz atacağız. Aşağıdaki kod bloğu yine en başta verdiğim UML diagram yapısı ile aynı yapıya ait.

Main.java

package Inheritance2;
/**
 *
 * @author Cem KEFELİ
 * http://www.cemkefeli.com
 */
public class Main
{
    static public class TASIT
    {
        Integer Deger1=new Integer(55);
        Integer Deger2=new Integer(11);
        Integer Deger3=new Integer(99);
        TASIT()
        {
            System.out.println("TASIT sinifi  olusturuluyor...");
        }
        TASIT(int YeniDeger2)
        {
            this.Deger2 = YeniDeger2;
            System.out.println("TASIT sinifi  olusturuluyor...");
        }
        public void BenNeyim()
        {
            System.out.println("Ben herhangi bir tasitim.");
            System.out.println("TASIT icin -->          Deger1: "+Deger1.toString()+", 
Deger2: "+Deger2.toString()+", Deger3: "+Deger3.toString()+"");
        }
    }
    static public class MOTORLUTASIT extends TASIT
    {
        Integer Deger4=new Integer(111);
        MOTORLUTASIT()
        {
            super(15);
            System.out.println("MOTORLUTASIT sinifi olusturuluyor...");
        }
        @Override
        public void BenNeyim()
        {
            System.out.println("Ben motorlu bir tasitim.");
            System.out.println("MOTORLUTASIT icin -->   Deger1: "+Deger1.toString()+", 
Deger2: "+Deger2.toString()+", Deger3: "+Deger3.toString()+", Deger4: "+Deger4.toString()+"");
        }
    }
    static public class MOTORSUZTASIT  extends TASIT
    {
        Integer Deger4=new Integer(222);
        MOTORSUZTASIT()
        {
            super(19);
            System.out.println("MOTORSUZTASIT sinifi olusturuluyor...");
        }
        @Override
        public void BenNeyim()
        {
            System.out.println("Ben motorsuz bir tasitim.");
            System.out.println("MOTORSUZTASIT icin -->  Deger1: "+Deger1.toString()+", 
Deger2: "+Deger2.toString()+", Deger3: "+Deger3.toString()+", Deger4: "+Deger4.toString()+"");
        }
    }
    static public class TAKSI  extends MOTORLUTASIT
    {
        TAKSI()
        {
            super();
            System.out.println("TAKSI sinifi olusturuluyor...");
        }
        @Override
        public void BenNeyim()
        {
            Deger3 = 91;
            System.out.println("Ben bir taksiyim.");
            System.out.println("TAKSI icin -->          Deger1: "+Deger1.toString()+", 
Deger2: "+Deger2.toString()+", Deger3: "+Deger3.toString()+", Deger4: "+Deger4.toString()+"");
        }
    }
    static public class OTOBUS  extends MOTORLUTASIT
    {
        OTOBUS()
        {
            super();
            System.out.println("OTOBUS sinifi olusturuluyor...");
        }
        @Override
        public void BenNeyim()
        {
            Deger3 = 95;
            System.out.println("Ben bir otobüsüm.");
            System.out.println("OTOBUS icin -->         Deger1: "+Deger1.toString()+", 
Deger2: "+Deger2.toString()+", Deger3: "+Deger3.toString()+", Deger4: "+Deger4.toString()+"");
        }
    }
    static public class BISIKLET  extends MOTORSUZTASIT
    {
        BISIKLET()
        {
            System.out.println("BISIKLET sinifi olusturuluyor...");
        }
        @Override
        public void BenNeyim()
        {
            Deger3 = 98;
            System.out.println("Ben bir bisikletim.");
            System.out.println("BISIKLET icin -->       Deger1: "+Deger1.toString()+", 
Deger2: "+Deger2.toString()+", Deger3: "+Deger3.toString()+", Deger4: "+Deger4.toString()+"");
        }
    }
    public static void main(String[] args)
    {
        TASIT TASIT1=new TASIT();
        System.out.println("\n");
        MOTORLUTASIT TASIT2=new MOTORLUTASIT();
        System.out.println("\n");
        MOTORSUZTASIT TASIT3=new MOTORSUZTASIT();
        System.out.println("\n");
        TAKSI TASIT4=new TAKSI();
        System.out.println("\n");
        OTOBUS TASIT5=new OTOBUS();
        System.out.println("\n");
        BISIKLET TASIT6=new BISIKLET();
        System.out.println("\n");
        TASIT1.BenNeyim();
        TASIT2.BenNeyim();
        TASIT3.BenNeyim();
        TASIT4.BenNeyim();
        TASIT5.BenNeyim();
        TASIT6.BenNeyim();
    }
}
run:
TASIT sinifi  olusturuluyor...
 
TASIT sinifi  olusturuluyor...
MOTORLUTASIT sinifi olusturuluyor...
 
TASIT sinifi  olusturuluyor...
MOTORSUZTASIT sinifi olusturuluyor...
 
TASIT sinifi  olusturuluyor...
MOTORLUTASIT sinifi olusturuluyor...
TAKSI sinifi olusturuluyor...
 
TASIT sinifi  olusturuluyor...
MOTORLUTASIT sinifi olusturuluyor...
OTOBUS sinifi olusturuluyor...
 
TASIT sinifi  olusturuluyor...
MOTORSUZTASIT sinifi olusturuluyor...
BISIKLET sinifi olusturuluyor...
 
Ben herhangi bir tasitim.
TASIT icin -->          Deger1: 55, Deger2: 11, Deger3: 99
Ben motorlu bir tasitim.
MOTORLUTASIT icin -->   Deger1: 55, Deger2: 15, Deger3: 99, Deger4: 111
Ben motorsuz bir tasitim.
MOTORSUZTASIT icin -->  Deger1: 55, Deger2: 19, Deger3: 99, Deger4: 222
Ben bir taksiyim.
TAKSI icin -->          Deger1: 55, Deger2: 15, Deger3: 91, Deger4: 111
Ben bir otobüsüm.
OTOBUS icin -->         Deger1: 55, Deger2: 15, Deger3: 95, Deger4: 111
Ben bir bisikletim.
BISIKLET icin -->       Deger1: 55, Deger2: 19, Deger3: 98, Deger4: 222
BUILD SUCCESSFUL (total time: 3 seconds)

Yukarıdaki ikinci örneğimizi iyice incelediyseniz artık yavaş yavaş kodumuzu inceleyemeye başlayabiliriz. Sınıf yapıları ve kalıtım şemaları az önce de söylediğim gibi ilk örnek ile aynı. Fakat ilk dikkatimizi çeken sınıflarımıza yapıcı metod(Constructor) adını verdiğimiz fonksiyonların eklenmesi olacaktır. Bu metodlar sınıf ismi ile aynı ismi taşırlar ve dönüş tipleri olamaz. Yani int, void gibi herhangi bir dönüş tipini işaret edemezler. Çünkü işaret ettikleri aslında kendileridir. Bu yapıcı metodun doğal sonucu kendisini oluşturmasıdır. Fakat dönüş tiplerinin olamaması parametre de alamayacağı anlamına gelmez. Herhangi bir fonksiyon gibi bu fonksiyonlar da tüm türlerdeki girişleri kabul edeceklerdir. Fakat aynı sırada ve aynı türde değişkenlerin olduğu bir methot ikinci kez tanımlanamaz. Yani Sınıfım(int giris1, char Karakter) yapıcısı ile Sınıfım(int Sayı, char Harf) aynıdırlar ve biribirinden ayırt edilmelerini sağlayacak bir nitelikleri de yoktur. Dolayısı ile bu yapıcılardan yalnızca bir tanesi sınıf içerisinde yapıcı görevini üstlenebilir.

Dikkatimizi çekmesi gereken bir diğer kavram ise “super” anahtar sözcüğünün varlığıdır. Aslında super’in ortaya çıkış nedeni kalıtımın doğal bir sonucudur. Çünkü türeyen sınıflar içerisinden ana sınıfların yapıcılarının çağırılması çuğu zaman gerekli olmaktadır. Türeyen sınıflardan, ana sınıfının yapıcılarının çağırılmasını sağlayan anahtar kelimeye “super” anahtar kelimesi denmektedir. Ana sınıf içerisinde yer alan tüm yapıcılara bu super ile erişmek mümkündür. Yapıcıların her birisi için ana sınıfın yapıcı fonksiyonlarının kabul ettiği parametre türüne ve sırasına göre çağırım yapmak mümkündür. Fakat dikkat edilmesi gereken nokta super’in kullanıldığğı satırın bulunduğu kod bloğu içerisinde ilk satırda yer almasının zorunlu olduğudur.

Şimdi eğer TASIT sınıfı oluşturulurken neler olduğunu incelersek, yazdırdığımız loglardan bir sınıf oluşturulurken ilk önce yapıcısına uğrandığı sonucunu çıkarabiliriz. Program çıktısında da görülebileceği gibi ilk önce TASIT sınıfı oluşturulurken TASIT sınıfının yapıcısına uğrandığı ve oluşturulduğunu gösteren logumuz vardır(TASIT sinifi olusturuluyor). Peki hangi yapıcı fonksiyon çağırılmıştır? TASIT() ya da TASIT(int YeniDeger2)? Bu sefer TASIT() yapıcısına uğramıştır çünkü sınıf oluşturulurken TASIT TASIT1=new TASIT(); notasyonu kullanılmıştır. Eğer TASIT TASIT1=new TASIT(245); şeklinde olsaydı ozaman da TASIT(int YeniDeger2) yapıcısı kullanılacaktı.

Sırada MOTORLUTASIT sınıfı var. MOTORLUTASIT oluşturulurken de ilk önce yapıcısı çağırılıyor. Fakat burada farklı bir durum da var. Çünkü bu sınıf TASIT sınıfından türetilen bir sınıftır ve yapıcısı çağırılınca da ana sınıfın uygun yapıcısı super anahtar sözcüğü ile çağırılıyor. Yani ilk önce TASIT sınıfı uygun yapıcısı çağırılarak oluşturuluyor ve MOTORLUTASIT sınıfı bu işlemlerden sonra oluşturuluyor. zaten dikkat edilirse “MOTORLUTASIT sinifi olusturuluyor” logu basılmadan önce “TASIT sinifi olusturuluyor.” logu basılmıştır. TASIT sınıfı içerisindeki Deger2 değişkeni ana sınıfın yapıcısı içerisinde değiştiriliyor ve 15 değerine setleniyor. Peki ya TASIT içerisinde bu sefer hangi yapıcı fonksiyon çağırıldı? Tabi ki TASIT(int YeniDeger2) değil mi çünkü bu konuya az önce el atmıştık. super(15) notasyonu kullanıldığına göre, bu notasyona uygun bir yapıya ait yapıcı seçmek lazımdı. Peki ya biz türeyen sınıfın yapıcısı içerisinden ana sınıfın yapıcılarından birisini çağırmasaydık ne olurdu? Yine ana sınıfa ait yapıcı metod çağırılır mıydı acaba? Bu sorunun cevabını ileriye bırakalım şimdilik ve koda devam edelim. Üst sınıfın ve alt sınıfın yapıcılarının ikisi de çağırıldıktan sonra MOTORLUTASIT sınıfı da oluşturulmuş oldu böylece. MOTORSUZTASIT alt sınıfı için de yine aynı durum söz konusu. 

TAKSI ve OTOBUS sınıfları için ise durum yine aynı mantık çerçevesinde değerlendirilebir. Her iki sınıfın oluşturulabilmesi için yapıcı fonksiyonları içerisinden ilk önce alt sınıflarına ait yapıcılar super anahtar sözcüğü ile çağırılıyor. Dolayısı ile MOTORLUTASITLAR sınıfının yapıcı fonksiyonuna geliniyor. MOTORLUTASIT sınıfının yapıcısından ise yine aynı şekilde MOTORLUTASIT sınıfının ana sınıfı olan TASIT sınıfına ait yapıcı çağırılıyor. Eğer loglara bakılırsa TAKSI sınıfı oluşturulurken ilk önce “TASIT sinifi  olusturuluyor” logu, sonrasında “MOTORLUTASIT sinifi olusturuluyor” logu, ve en son olarak da “TAKSI sinifi olusturuluyor” logu basılıyor. OTOBUS sınıfı için de aynı işleyiş geçerlidir.

Fakat BISIKLET sınıfı için durum biraz daha değişiktir. BISIKLET sınıfının yapıcı metodu içerisinde super ile üst sınıfın yapıcısı çağırılmasa bile yazdırdığımız loglardan bu yapıcıların çağırıldığını görmekteyiz. Az önce bahsedip de sonraya bıraktığımız konu burasıydı. Aslında super ile çağırılmasa bile üst sınıfların yapıcılarının çağırılması kalıtımın doğası gereğidir. Çünkü kalıtımın gereği olarak önce türediği sınıfın oluşturulması mecburidir. Dolayısı ile loglara baktığımızda ilk önce “TASIT sinifi  olusturuluyor” logu, sonrasında “MOTORSUZTASIT sinifi olusturuluyor” logu ve en son olarak da en alt sınıf olan BISIKLET‘e ait “BISIKLET sinifi olusturuluyor” logu basılıyor.

Yukarıda karşılaştığımız türetilen nesnelerin türediği sınıfına ait değişkenlerinin değerinin değiştirilmesi fakat türetilen nesneden yeni bir nesne türetildiğinde bu değişikliklerin izlenememesi sorununa burada super anahtar sozcüğü ile çözüm getirmiş bulunuyoruz. Dikkat edilirse MOTORLUTASIT sınıfı içerisinde Deger2 değişkeni 15 degerine set edilmiş, sonrasında MOTORLUTASIT sınıfından yeni bir sınıf olan OTOBUS sınıfı oluşturulmuş ve OTOBUS sınıfına ait BenNeyim fonksiyonu içerisinde Deger2 değişkeninin değeri yazdırıldığında 15 olarak görülmüştür. Oysaki az önceki örneğimizde OTOBUS sınıfı içerisinden bu değerleri değiştirsek bile kalıtım yolu ile alt sınıflarına geçmediğini görmüştük.