John Connor: Wait a minute here. You're telling me that this thing can imitate anything it touches?
The Terminator: Anything it samples by physical contact.
|
Çok şekillik, Nesneye Dayalı Programlamanın en önemli mekanizmasıdır. Aşağıda çok şekilliliğin Java'da nasıl çalıştığını incelememizi sağlayacak bir kod örneği verilmiştir:
package com.example.polymorphism; /** * * @author Binnur KURT (binnur.kurt@gmail.com) * */ public class Question { public static void main(String[] args) { C c = new C(2); A a = c; B b = c; System.out.println(a.x); System.out.println(b.x); System.out.println(c.x); System.out.println(((A) c).x); System.out.println(((B) c).x); System.out.println(((A) b).x); System.out.println(a.getX()); System.out.println(b.getX()); System.out.println(c.getX()); System.out.println(((A) c).getX()); System.out.println(((B) c).getX()); System.out.println(((A) b).getX()); } } class A { public int x; public A(int x) { this.x = x; } public int getX() { return x; } } class B extends A { public int x; public B(int x) { super(3 * x); this.x = x; } @Override public int getX() { return x; } } class C extends B { public int x; public C(int x) { super(2 * x); this.x = x; } @Override public int getX() { return x; } }
Daha sonra B'den gelen x için Heap'de yer ayrılır ve ardından B'nin kurucusu bu x'e ilk değerini atar: 4. |
Son olarak, C'den gelen x için Heap'de yer ayrılır ve ardından C'nin kurucusu bu x'e ilk değerini atar: 12. Böylelikle C sınıfından nesne yaratılması işlemi tamamlanmış oluyor. |
B tipinden bir referans hem B tipinden bir nesneye hem de B sınıfından türetilmiş ne kadar sınıf varsa (sadece C sınıfı) hepsini referans edebilir. Bu örnekte B tipinden referansımız olan b değişkeni de C tipinden bir nesneyi gösteriyor. |
Artık aşağıdaki ifade ile bellekte oluşan yapıyı tanıyoruz:
C c = new C(2); A a = c; B b = c;
Şimdi sırayla aşağıdaki kod parçalarının davranışını çalışabiliriz:
- Referanslar üzerinden özniteliklere erişim
Öncelikli olarak yukarıdaki kod parçasının kötü tasarlanmış olduğunu belirtmeliyim. Nesneye Dayalı Programlamada hiç bir zaman öznitelikleri, referans üzerinden, doğrudan erişime açmamalıyız! Verilerimizi gizlemeliyiz! Ancak bu çalışmadaki amacımız dilin inceliklerini ve arka tarafta çalışmasındaki detayları kavramak olacaktır.
Şimdi aşağıdaki kod parçasının davranışını çalışabiliriz:
System.out.println(a.x); System.out.println(b.x); System.out.println(c.x);
Verilere referanslar üzerinden erişildiğinde önemli olan referansın gösterdiği nesnenin tipi değil, referansın tanımlandığı tipdir. Bu nedenle a.x'de A sınıfında tanımlanan x'in değerine, b.x'de B sınıfında tanımlanan x'e ve en nihayetinde de c.x'de C sınıfındaki x'e erişiyoruz. Bu nedenle yukarıdaki kod parçası çalıştırıldığında ekranda 12, 4 ve 2 değerlerini görürüz.
Şimdi ise referansları farklı tiplere dönüştürürerek yine veriye erişmek istiyoruz:
System.out.println(((A) c).x); System.out.println(((B) c).x); System.out.println(((A) b).x);
Yukarıdaki analiz hala geçerlidir: verilere referanslar üzerinden erişildiğinde önemli olan referansın gösterdiği nesnenin tipi değil, referansın tanımlandığı tipdir. Ancak bu sefer tip dönüşümü yapıldığı için hedef tipin tanımladığı sınıftaki veriye erişeceğiz. Buna göre ekran çıktısı sırasıyla 12, 4 ve 12 olacaktır.
Yukarıdaki örneklerde görüldüğü gibi referanslar üzerinden özniteliklere eişildiğinde çok şekillilik çalışmıyor. Çünkü çok şekillilik sadece fonksiyonlar üzerinde çalışır, veriler üzerinde çalışmaz!
- Referanslar üzerinden özniteliklere erişim
Şimdi a, b ve c referanslarını kullanarak getX() isimli metodu önce doğrudan çağıralım:
System.out.println(a.getX()); System.out.println(b.getX()); System.out.println(c.getX());
Her üç referans değişkeni de (a, b ve c) C tipinden bir nesneyi gösterdiği için her üç durumda da C sınıfındaki getX() metodu çalışacaktır ve ekranda üç satır olmak üzere 2 değerini görürüz.
Aşağıdaki durumda ise a, b ve c değişkenleri üzerinde tip dönüşümü yaparak kullanıyoruz:
System.out.println(((A) c).getX()); System.out.println(((B) c).getX()); System.out.println(((A) b).getX());
Bu kullanımlarda değişen bir durum olmayacak ve çok şekillilik her zaman çalışacaktır. Sonuç olarak istediğiniz kadar referans değişken üzerinde tip dönüşümü yapın, referansın gösterdiği nesne hala C tipinden, dolayısı ile C sınıfındaki getX() fonksiyonu çalışacaktır. Yukarıdaki kod parçası çalıştığında ekranda üç satır olmak üzere 2 değerini görürüz ∎
Very insightful, thank you.
ReplyDelete