ÖNEMLİ : Kendim için aldığım notlar. Umarım size de bir faydası olur. Kullanılan her bir makale referans olarak eklenmiştir.

Java’da Kalıtım(inheritance) ve Java’da Polimorfizm Serisi


  1. Java’da Polimorfizm 1 - Amaç?
  2. Java’da Polimorfizm 2 - İzlenecek Kurallar Nelerdir?
  3. Java’da Polimorfizm 3 - Casting
  4. Java’da Polimorfizm 4.1 - Statik ve Dinamik Bağlanma 1
  5. Java’da Polimorfizm 4.2 - Statik ve Dinamik Bağlanma 2
  6. Java’da Polimorfizm 4.3 - Dinamik Bağlanma Örnek
  7. Java’da Polimorfizm 5 - Soyut(Abstract) Sınıflar ve Arayüzler(Interfaces)

Casting Nedir?

Bazı durumlarda derleme ve çalışma zamanı kararlarını değiştirmek için derleyiciye yardım etmek gerekebilir. Bu gibi durumlarda casting dediğimiz işlemi uygularız. Ne demek istediğimi bir önceki bölümde yarım bıraktığımız kod üzerinden göstermek istiyorum.


Java Polymorphism(java polimorfizm)

Compile time error


1
2
Person s = new Student("Hasan", 1111);
s.getSID();

Şu şekilde bir hata alırız:

1
Compile time error: Cannot resolve method 'getSID' in 'Person'

Hatırlayacağınız üzere derleme zamanında, derleyici SADECE referans tipini bildiğinden ve metot çağrıları için sadece referans tipinin sınıfına bakacağından, Person sınıfında getSID metodunu bulamayacaktır. Ama biz bu metodun Student sınıfında olduğunu biliyoruz. Student sınıfına da ancak çalışma zamanında erişebileceğimiz için, ya derleme zamanı hatasını almaya razı olacağız ya da derleyiciye bir taahhüt vererek bu metodun aslında Student sınıfında bulunduğunu söyleyeceğiz. Şayet 2. yöntemi seçersek, casting denen işlemi uygulamamız gerekmektedir.

Öncelikli olarak casting çeşitleri hakkında bilgi vermek istiyorum. Sonrasında yukarıdaki sorunun çözümünü ele alırız.

  1. Widening(genişletme) Casting (otomatik olarak gerçekleşir) - daha küçük bir türü daha büyük bir türe dönüştürme işlemine denir.

    • byte -> short -> char -> int -> long -> float -> double
    • Subclass -> Superclass
    • Superclass ref = new Subclass();

    gibi veyahut

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
     public class TestClass {
       public static void main(String[] args) {
         int sampleInt = 2;
    
         // otomatik casting, int'den double'a
         double sampleDouble = sampleInt;
    
         System.out.println(sampleInt);      // Çıktı 2
         System.out.println(sampleDouble);   // Çıktı 2.0
       }
     }
    

    Dikkat ederseniz ekstra bir şey yazmadan java otomatik olarak int türünü double türüne dönüştürdü.

  2. Narrowing(daraltma) Casting (elle belirtmeniz gerekmektedir) - daha büyük bir türü daha küçük boyutlu bir türe dönüştürme işlemidir.

    • double -> float -> long -> int -> char -> short -> byte
    • Superclass -> Subclass
    • Subclass ref = (Subclass) superRef;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
     public class TestClass {
       public static void main(String[] args) {
         double sampleDouble = 2.66;
    
         // Manuel casting, double'dan int'e
         int sampleInt = (int) sampleDouble;
    
         System.out.println(sampleDouble);   // Çıktı 2.66
         System.out.println(sampleInt);      // Çıktı 2
       }
     }
    

    Burada da sampleDouble değişkeni bir double olduğu için, bu türü int türünü daraltırken daraltacağınız türü bu şekilde (int) cast ettiğinizi belirtmeniz gerekmektedir. Yani bu casting türünde elle uygulayacağınız türü belirtmeniz gerekmektedir.

    Bu casting türünde(bu, bölümün ta en başta verdiğimiz örnek oluyor) çok dikkatli olmamız gerekmektedir. Çünkü bunu yaparak bir nevi derleyiciye size güvenmesini söylüyorsunuz. “Derleyici bana güvenmen gerekiyor, çünkü bunun çalışma zamanında bir Alt Sınıf referansı olacağını biliyorum,” diyorsunuz.

Şimdi en baştaki soruya geri dönelim. Şayet ilgili metot çağırma işlemini şu şekilde yaparsam derleme zamanındaki sorunu çözmüş olurum.

1
((Student)s ).getSID();

Runtime Error


Peki kodu şu şekilde değiştirsek sizce ne olurdu?

1
2
Person s = new Person("Hasan");
((Student)s ).getSID();

O zaman da çalışma zamanında aşağıdaki gibi bir hata alırdık.

1
Exception in thread "main" java.lang.ClassCastException: Person cannot be cast to Student

Daha ilk başta yaptığımız hata; çalışma zamanında Person nesnesinin olduğunu bildiğimiz halde, Person sınıfını Student sınıfına gönüştürmeye çalışmamızdır. Bir bakıma derleyicinin güvenini sarstık. Özetle derleyiciye, “bunun çalışma zamanında bir Student sınıfı olacağını ve bu sınıfın da içinde bir getSID metodu barındıracağını taahhüt ettik.” Daha çalışma zamanındaki sınıfı bile tutturamadık.

1
2
Person s = new Student("Bilal", 1234);
((Student) s).getSID();

Kodu bu şekilde güncellersek sorunu çözmüş oluruz. Yalnız bu durumu test edebilseydik gerçekten güzel olabilirdi. Yani cast yapmadan önce bunun bir Student sınıfı olup olmadığını test etme şansımız olsaydı demek istiyorum. Bunu yapabilmemizin yolu instanceof operatörünü kullanmaktır. Bu operatör bize is-a ilişkisini çalışma zamanında test etme imkanı verir.

1
2
3
if(s instanceof Student){
  ((Student) s).getSID();
}

s instanceof Student anlamı s Student sınıfının bir örneği midir? şeklinde bir soru soruyorsunuz.. Diğer bir şekilde ifade edecek olursak, s çalışma zamanında Student ile bir ilişki içinde mi? Yalnız bu operatörün çalışma zamanında test ettiğini unutmayın.

Aslında polimorfizm uyguladığımızda casting yapmamıza da gerek kalmaz. Çünkü java çalışma zamanında hangi yöntemi uygulayacağını bilir. Bu yüzden bu bir tercih meselesidir.

Referanslar