Monday, February 18, 2013

Polymorphism nedir ? ( Detaylı ) , Java'da polymorphism , Polymorphism konu anlatımı

   Farklı hayvanların farklı özelliklerini ve davranışlarını gösteren farklı class'lar oluşturmak istiyoruz.Tüm hayvanlara has özellikler Animal class 'ı içinde gösterilecek,türe özgü özellikler ise subclass'larda belirtilecek. 
   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 HAYVANHAYVAN 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