Sadece move method'undan bahsedelim.Tüm hayvanlar hareket ederler ancak hareket etme yöntemleri farklı olabilir. Subclass'larımız Dog ve Bird olsun. Kolaylık olması bakımından her class'daki hareket etme işini aynı isimli method(move) yapacak ve move metodunun return type'ları aynı olacak.
Dog ve Bird class'larına hareket etmelerini şu şekilde söyleyebiliriz:
Dog d = new Dog(); d.move(); Bird b = new Bird(); b.move();
Elimizde birçok hayvan olduğunu ve bunlardan bir kısmının dog bir kısmının bird olduğu farz edelim. Uygun metodu çağırmak için instanceof kullanabiliriz. Fakat daha kolay bir yol vardır.
Ancak bu yolu uygulamak için Animal adlı base class'ımızda da move metodunu mutlaka tanımlamış olmak zorundayız(abstract class olarak da tanımlıyabiliriz.) Bunu yapmışsak eğer polymorphism sayesinde istenilen metodu aşağıdaki gibi çağırabiliriz.
Animal a; a = new Dog(); a.move(); a = new Bird(); a.move();
Default move metodu yazamayız çünkü hayvanlar farklı şekilde hareket ederler. Çözüm ise Animal class'ında abstract move metodu declare etmektir.
Böylece , subclass create etmek istersek subclass'ın move metodunu da define etmek (tanımlamak) zorunlu hale gelir.
Şimdi de başka bir örnek üzerinden polymorphism'i anlatalım:
public class Main { static public class HAYVAN { public void nedir() { System.out.println("Bu bir hayvandir."); } } static public class KUS extends HAYVAN { @Override public void nedir() { System.out.println("Bu bir kustur."); } } static public class PAPAGAN extends KUS { @Override public void nedir() { System.out.println("Bu bir papagandir."); } } static public class KANARYA extends KUS { @Override public void nedir() { System.out.println("Bu bir kanaryadir."); } } static public class BULBUL extends KUS { @Override public void nedir() { System.out.println("Bu bir bulbuldur."); } } static public void Yazdir(HAYVAN hayvanat) //POLYMORPHISM İŞE YARIYOR// { hayvanat.nedir(); } public static void main(String[] args) { HAYVAN Hayvan1 = new HAYVAN(); // Hayvan1 objesi create edildi. KUS Hayvan2 = new KUS(); // Hayvan2 objesi create edildi. PAPAGAN Hayvan3 = new PAPAGAN(); // Hayvan3 objesi create edildi. KANARYA Hayvan4 = new KANARYA(); // Hayvan4 objesi create edildi. BULBUL Hayvan5 = new BULBUL(); // Hayvan5 objesi create edildi. Yazdir(Hayvan1); Yazdir(Hayvan2); Yazdir(Hayvan3); Yazdir(Hayvan4); Yazdir(Hayvan5); } }Yukarıdaki koddan ve şekilden şunu anlıyoruz: En tepedeki base class'ımız HAYVAN. HAYVAN class'ından KUS class'ı türüyor. KUS class'ından da PAPAGAN , KANARYA ve BULBUL class'ları türüyor. En tepedeki base class'ımız olan HAYVAN da dahil olmak üzere tüm classlar'da nedir() metodumuz bulunuyor.
yazdir() adlı metodumuzda polymorphism'in nasıl kullanıldığını , pratikte ne işe yaradığını görüyoruz.
Tüm classlardan birer tane obje create ettik. Sonra ise tüm objeleri Yazdir() metoduna gönderdik.Halbuki yazdır metodunu tanımlarken alabileceği parametre type'ı olarak HAYVAN demiştik. İşte Polymorphism'in güzelliği de buradadır.
Yazdir metodunu aşağıda tekrar gösterelim:
static public void Yazdir(HAYVAN hayvanat) { hayvanat.nedir(); }
Yazdir(Hayvan1); metodu çağırıldığında hayvanat = Hayvan1 assignment'ı yapılır.
Yazdir(Hayvan2); metodu çağırıldığında hayvanat = Hayvan2 assignment'ı yapılır. hayvanat HAYVAN türündeydi. Hayvan2 ise KUS türündeydi. Yani biz aslında ilk anlattığım kısımdaki işlemlerin aynısını yaptık.Bunu şöyle de gösterebiliriz:
HAYVAN hayvanat;KUS Hayvan2 = new KUS();hayvan = Hayvan2; hayvan.nedir(); // Yazdir() metodunun içindeki satırdır. Polymorphism sayesinde Hayvan2 objesine yani KUS class'ına ait nedir() metodu çağırılır.
Yazdir(Hayvan3); metodu çağırıldığında hayvanat = Hayvan3 assignment'ı yapılır. hayvanat HAYVAN türündeydi. Hayvan3 ise PAPAGAN türündeydi. PAPAGAN, HAYVAN class'ının çocuğunun çocuğu olmasına rağmen polymorphism burada da kullanılabilir.
HAYVAN hayvanat;
PAPAGAN Hayvan3 = new PAPAGAN();hayvan = Hayvan3; hayvan.nedir(); // Yazdir metodunun içindeki satırdır. Polymorphism sayesinde Hayvan3 objesine yani PAPAGAN class'ına ait nedir() metodu çağırılır.
Yazdir(Hayvan4) ve Yazdir(Hayvan5) de benzer şekilde çağırılırlar.
Eğer polymorphism olmasaydı biz Yazdir metodunu aşağıdaki gibi yazmak zorunda kalacaktık:
static public void Yazdir(HAYVAN hayvanat) { //hayvanat.nedir(); // POLYMORPHISM kullanırken sadece böyle demiştik if(hayvanat instanceof HAYVAN) { HAYVAN uzunYol =(HAYVAN) hayvanat; uzunYol.yazdir(); } else if(hayvanat instanceof KUS) { KUS uzunYol =(KUS)hayvanat; uzunYol.yazdir();
} else if(hayvanat instanceof PAPAGAN) { PAPAGAN uzunYol =(PAPAGAN)hayvanat; uzunYol.yazdir(); } else if(hayvanat instanceof BULBUL) { BULBUL uzunYol =(BULBUL)hayvanat; uzunYol.yazdir(); } }
A m = new B();
ile
A m = new A();
B n = new B();
m = n;
aynıdır.
Bu da Polymorphism'in bir başka kullanımı diyebiliriz:
public class EMPLOYEE
{ String name = "john"; String surname = "travolta";
int age = 27;
String getDetails()
{
return "Name : " + name + ", Surname: " + surname + ", Age" + age;
}
public void who(EMPLOYEE anybody)
{
System.out.println( anybody.getDetails());
}
} class MANAGER extends EMPLOYEE
{ String department = "Informatics";
@Override String GetDetails()
{
return super.GetDetails()+ ", Department : " + department ;
}
} class ENGINEER extends EMPLOYEE
{ String field = "computer";
@Override String GetDetails()
{
return super.GetDetails() + ", Field : " + field;
}
} Employee emp = new Employee(); Employee mudur = new Manager(); Employee muhendis = new Engineer();
System.out.println(emp.GetDetails()); System.out.println(mudur.GetDetails()); System.out.println(muhendis.GetDetails());
Output:
Name : John , Surname: Travolta , Age : age
Name : John , Surname: Travolta , Age : age , Department : Informatics
Name : John , Surname: Travolta , Age : age , Field : computer
Son olarak akıllarda soru işareti kalmasın diye bir noktayı daha belirtmek istiyorum. Bkz:
public class Employee { private String name; private String address; private int number; public Employee(String name, String address, int number) { System.out.println("Constructing an Employee"); this.name = name; this.address = address; this.number = number; } public void mailCheck() { System.out.println("Mailing a check to " + this.name + " " + this.address); } } public class Salary extends Employee { private double salary; //Annual salary public Salary(String name, String address, int number, double salary) { super(name, address, number); setSalary(salary); } public void mailCheck() { System.out.println("Within mailCheck of Salary class "); System.out.println("Mailing check to " + getName() + " with salary " + salary); } } public class VirtualDemo { public static void main(String [] args) { Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00); Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00); System.out.println("Call mailCheck using Salary reference --"); s.mailCheck(); System.out.println("\n Call mailCheck using Employee reference--"); e.mailCheck(); } }
Output:
Constructing an Employee Constructing an Employee Call mailCheck using Salary reference -- Within mailCheck of Salary class Mailing check to Mohd Mohtashim with salary 3600.0 Call mailCheck using Employee reference-- Within mailCheck of Salary class Mailing check to John Adams with salary 2400.0
Şimdi bu kod hakkında aşağıda yazılanları aynen alıntılıyorum.Lütfen dikkatlice okuyalım:
Here we instantiate two Salary objects . one using a Salary reference s, and the other using an Employee reference e.While invoking s.mailCheck() the compiler sees mailCheck() in the Salary class at compile time, and the JVM invokes mailCheck() in the Salary class at run time.Invoking mailCheck() on e is quite different because e is an Employee reference. When the compiler sees e.mailCheck(), the compiler sees the mailCheck() method in the Employee class.Here, at compile time, the compiler used mailCheck() in Employee to validate this statement. At run time, however, the JVM invokes mailCheck() in the Salary class.This behavior is referred to as virtual method invocation, and the methods are referred to as virtual methods. All methods in Java behave in this manner, whereby an overridden method is invoked at run time, no matter what data type the reference is that was used in the source code at compile time.
Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
e.mailCheck() //Yani compile time'da Employee class'ındaki mailCheck() metodu kullanılır. Ancak run time'da ise Salary class'ındaki mailCheck() metodu kullanılır. Bu metoda virtual method invocation diğer adlarıyla late binding ya da dynamic binding denir.
Aynı şeyin farklı ifadelerini görmeye devam edelim:
Late Binding / Virtual Method Invocation / Runtime Polymorphism / Dynamic Binding (All is the same)
In late binding we create the instance of the super class but call the constructor of the sub class, only to check if an upper class method is overridden in the sub class or not.
class A { int x = 10; A() { System.out.println("Constructor in A"); } void met1() { System.out.println("met1 in A"); } void met2() { System.out.println("met2 in A"); } } class B extends A { int x = 20; B() { System.out.println("Constructor in B"); } void met1() { System.out.println("met1 in B"); } void met3() { System.out.println("met3 in B"); } } class LateBinding { public static void main(String args[]) { A m = new B(); System.out.println(m.x); m.met1(); m.met2(); //m.met3(); This line cause compile time error. Thus we comment this line. } } OUTPUT : Constructor in A Constructor in B 10 met1 in B met2 in A
Bu konuyu araştırırken yararlandığım kaynaklar: http://www.harford.edu/faculty/FBrundick/cis214/programs/polymorph.html http://www.cemkefeli.com/post/2009/09/16/JAVA-Polimorfizm(Cok-bicimlilik)-nedir.aspx http://canavcu.blogspot.com/2011/08/polimorpfizm-nedir.html http://beginlearningjava.blogspot.com/2010/02/late-binding-virtual-method-invocation.html http://www.tutorialspoint.com/java/java_polymorphism.htm