top of page

Java Ders Notlarım – 6

Merhabalar kıymetli okurlarım, geleceğin programcıları. Bu haftaki ders notumda sizlerle beraber upcasting,downcasting,shallow copy ve deep copy konularını; insanceof anahtar kelimesini; clone methodunu ve abstract classlar konusunu öğreneceğiz. İyi kodlamalar.

Upcasting ve Downcasting

Upcasting

Şimdi size bu iki kavramı daha iyi anlatabilmek için iki tane sınıf oluşturacağım. Bu sınıflardan biri object sınıfından türetilmiş bir sınıf olsun; diğeri de bu sınıftan türetilmiş bir child sınıf olsun. Eğer bu kavramları bilmiyorsanız kalıtım konusunu anlattığım makaleme buraya tıklayarak göz atabilirsiniz. Konumuza geri dönelim. Hemen aşağıya iki sınıfı tanımlamasını yapalım.

// parent classımız
public class Tasit
{
     String TasitAdi;
}

//parent classtan kalıtım alarak oluşturduğumuz child classımız
public class Araba extends Tasit
{

}
 

main fonksiyonu içerisinde bu sınıfları kullanarak size upcastingi açıklayayım. Upcasting dediğiniz mevzu, parent class türünde oluşturduğumuz bir değişkene, child classtan oluşturduğumuz bir nesneyi atama durumudur. Kod ile örnekleyerek açıklığa kavuşturalım.

public static void main(String[] args)
{
    //parent classımızdan bir nesne oluşturduk
    Tasit tasitNesnesi = new Tasit();

    //bir de child classımızdan bir nesne oluşturalım
    Araba arabaNesnesi = new Araba();

    //upcasting mevzusu ise şu
    tasitNesnesi = arabaNesnesi;
}
 

Downcasting

Up castingi anladığımıza göre bir de downcasting i açıklığa kavuşturalım. Downcasting dediğimiz mevzu ise upcasting’in tersi olarak geçiyor ve kullanılması çok zorunlu olmadığı durumlarda tavsiye edilmiyor. Zaman zaman (örneğin equals methodunda) downcasting kullanılması gerekebiliyor.Bu yüzden hemen downcasting mevzusunu koda dökelim.

public static void main(String[] args)
{
	//parent classımızdan bir nesne oluşturduk
	Tasit tasitNesnesi = new Tasit();
	
	//bir de child classımızdan bir nesne oluşturalım
	Araba arabaNesnesi = new Araba();
	
	//downcasting mevzusu ise şu
	arabaNesnesi = (Araba)tasitNesnesi; //bu şekilde yapınca compiler dediğimiz derleme-zamanında hata alabilirsiniz.
	
	//downcasting diğer bir şekilde ise şu
	arabaNesnesi = tasitNesnesi; //bu şekilde yapınca run-time dediğimiz çalışma-zamanında hata alabilirsiniz.
	
	//fakat yukarıdaki yöntemler doğru olmayan kullanımlara giriyor. 
	//yukarıdaki yöntemler yerine zorunlu durumlarda şu şekilde manuel dönüştürme yaparak downcasting yapmak daha doğrudur.Yani;
	tasitNesnesi = (Tasit)arabaNesnesi;
}
 

instanceof anahtar kelimesi

Hazır downcasting mevzusu açılmışken bir classı downcasting yapılabilirliğini kontrol etmek yani bir objenin o classtan mı instance edildiğini öğrenmek için instanceof anahtar kelimesini kullanabiliriz. Kullanım kalımı şu şekildedir.

object instanceof ClassName

Hemen bir örnek ile pekiştirelim

public static void main(String[] args)
{
	//parent classımızdan bir nesne oluşturduk
	Tasit tasitNesnesi = new Tasit();
	
	//bir de child classımızdan bir nesne oluşturalım
	Araba arabaNesnesi = new Araba();
	
	if(arabaNesnesi instanceof Tasit)
	{
		// true durumunda çalışacak kodlar...
	}
	else
	{
		// false durumunda çalışacak kodlar...
	}
}
 

Shallow copy ve Deep Copy

Shallow copy

Object sınıfını temel alarak oluşturduğumuz veya object sınıfını temel alarak oluşturulan bir sınıftan oluşturduğumuz her classa varsayılan olarak gelen bir methoddur kendisi. Bize faydası ne derseniz, bu methodu kullanarak biz nesnenin tıpkısının aynısını deep copy mantığına göre bir kopyasını elde etmiş oluruz. Kod ile örnekleyerek açıklayalım.

Önce bir sınıf tanımlayayım.

public class Tasit 
{
	public String Ad;
}
 

Şimdi ise main fonksiyonu içinde shallow copy’i açıklayalım.

public static void main(String[] args)
{
	//birinci nesnemiz
	Tasit tasitOne = new Tasit();
	
	//bu da ikinci nesnemiz olsun
	Tasit tasitTwo;
	
	//shallow copy olayı şu
	tasitTwo = tasitOne;
}
 

shallow copy dediğimiz şey aslında yüzeysel bir kopya gibi düşünebilirsiniz. yani aslında o nesnedeki bilgilerin aynısına her nekadar sahip olsak ta o nesnenin bağımlı olduğu bellek adresi aynı kalıyor.

Düz bir mantıkla şöyle izah edeyim: shallow copy ile kopyalama veya atama yapınca bellek adresleri eşitlersiniz.

Bu yüzden de ilk nesnenin herhangi bir değeri değiştirilince ikince nesnede de o değer değişmiş olur. Kod ile daha da açık izah edeyim:

public static void main(String[] args)
{
    //birinci nesnemiz
    Tasit tasitOne = new Tasit();
    tasitOne.Ad = "Tasit 1";

    //bu da ikinci nesnemiz olsun
    Tasit tasitTwo;

    //shallow copy olayı şu
    tasitTwo = tasitOne;


    System.out.println("-- Önce --");
    System.out.println("tasitOne.ad : " + tasitOne.Ad);
    System.out.println("tasitTwo.ad : " + tasitTwo.Ad);

    tasitOne.Ad = "Tasit Bir";

    System.out.println("-- Sonra --");
    System.out.println("tasitOne.ad : " + tasitOne.Ad);
    System.out.println("tasitTwo.ad : " + tasitTwo.Ad);

}
 

Bu kodun çıktısı ise şu şekilde olacaktır:

-- Önce --
tasitOne.ad : Tasit 1
tasitTwo.ad : Tasit 1
-- Sonra --
tasitOne.ad : Tasit Bir
tasitTwo.ad : Tasit Bir 

Peki bu durumun çözümü nedir derseniz : Deep Copy

Deep Copy

Deep copy, dediğimiz mevzu ise shallow copy de yapmak istediğimiz şeydir. Yani bir nesneyi kopyalarken bellek adresinin aynı kalmaması ve gerçektende kopyalama yapmaktır ve yeni bir bellek adresinde aynı içerikten bir tane daha oluşturma işlemidir diyebiliriz. Kod ile ne anlatmak istediğimi açıklayayım:

public static void main(String[] args)
{
    //birinci nesnemiz
    Tasit tasitOne = new Tasit();
    tasitOne.Ad = "Tasit 1";

    //bu da ikinci nesnemiz olsun
    Tasit tasitTwo;

    //shallow copy olayı şuydu
    tasitTwo = tasitOne;

    //deep copy olayınıda şöyle özetleyeyim.
    tasitTwo = new Tasit();
    tasitTwo.Ad = tasitOne.Ad;

    System.out.println("-- Önce --");
    System.out.println("tasitOne.ad : " + tasitOne.Ad);
    System.out.println("tasitTwo.ad : " + tasitTwo.Ad);

    tasitOne.Ad = "Tasit Bir";

    System.out.println("-- Sonra --");
    System.out.println("tasitOne.ad : " + tasitOne.Ad);
    System.out.println("tasitTwo.ad : " + tasitTwo.Ad);

}
 

Bu kodun çıktısı da şu şekilde olacaktır :

-- Önce --
tasitOne.ad : Tasit 1
tasitTwo.ad : Tasit 1
-- Sonra --
tasitOne.ad : Tasit Bir
tasitTwo.ad : Tasit 1 

gelelim şimdi clone methoduna.

clone Methodu

clone methodu Cloneable interface’nde bulunan bir method. bu methodu kullanma amacımız yeni oluşturduğumuz classları ihtiyacımız olduğunda deep copy mantığına göre kopyasını oluşturmak. Kod ile nasıl kullanabileceğimize bakalım:

//Cloneable interface'ini implemente ederek yeni clasımızı oluşturuyoruz
public class Tasit implements Cloneable
{
    public String Ad;

    public Tasit()
    {
        Ad = null;
    }

    public Tasit(String ad)
    {
        Ad = ad;
    }

    //Cloneable interface'i için gerekli methodu oluşturdum ve geri dönüş türünü Object yerine Tasit olarak değiştirdim
    public Tasit clone()
    {
        return new Tasit(this.Ad);
    }

}
 

Classımızı test edelim:

public static void main(String[] args)
{
    //birinci nesnemiz
    Tasit tasitOne = new Tasit("Tasit 1");

    //bu da ikinci nesnemiz olsun
    Tasit tasitTwo;

    //clone methodunun basit bir kullanım şekli
    tasitTwo = tasitOne.clone();    

    //bu method gerçektende deep copy yapıyor mu bakalım

    System.out.println("-- Önce --");
    System.out.println("tasitOne.ad : " + tasitOne.Ad);
    System.out.println("tasitTwo.ad : " + tasitTwo.Ad);

    tasitOne.Ad = "Tasit Bir";

    System.out.println("-- Sonra --");
    System.out.println("tasitOne.ad : " + tasitOne.Ad);
    System.out.println("tasitTwo.ad : " + tasitTwo.Ad);

}
 

Test kodlarımızın çıktısı şu şekilde olacaktır:

-- Önce --
tasitOne.ad : Tasit 1
tasitTwo.ad : Tasit 1
-- Sonra --
tasitOne.ad : Tasit Bir
tasitTwo.ad : Tasit 1 

Abstract Class

abstract class dediğimiz class tipi, türkçe mealiyle soyut/öz classtır. Yani iskelet bir class gibi düşünebilirsiniz. Kullanıma amacı ise bu classtan oluşturulacak classlara, iskelet oluşturmak için kullanılır.

Yani şöyle örnek vereyim. Ne yacağınızı üstü kapalı biliyorsunuz örneğim, okuma ve yazma. peki okuma ve yazma yaparken neyi okuyup nasıl okuyup nasıl yazacağına kadar uzayan işlemleri tam kestiremiyorsunuz. İşte tamda bu sırada okuma ve yazma adında iki tane abstract method tanımlayıp sonraki süreçte bu methodların içini doldurarak kolaylıkla ilerleyebilirsiniz.

Ayrıca abstract method tanımladığınız bir classında abstract bir class olması gerekiyor. o sınıfta istereniz abstract olmayan methodlarda tanımlayabilirsiniz ama bir tane dahi olsa abstract metdod olursa o sınıfın artık abstract olma zorunluluğu oluşacaktır.

Kodlarla abstract bir sınıf tanımlayalım:

public abstract class Islem
{
    public abstract void Yazma();
    public abstract void Okuma();
}
 

Şimdide bu abstract classı kullanarak bir sınıf oluşturalım:

public class DosyaIslem extends Islem
{

    @Override
    public void Yazma()
    {
        // buraya dosya yazma işlemi için uygulanan kodlar yazılır.

    }

    @Override
    public void Okuma()
    {
        // buraya dosya yazma işlemi için uygulanan kodlar yazılır.
    }
}
 

Daha iyi anlamak için örnek bir sınıf daha oluşturayım:

public class VeriIslem extends Islem
{

    @Override
    public void Yazma()
    {
        // buraya veri yazma işlemi için uygulanan kodlar yazılır.
    }

    @Override
    public void Okuma()
    {
        // buraya veri okuma işlemi için uygulanan kodlar yazılır.
    }

}
 

abstract classsın zıttı ise yine normal sınıflardır. concrete class diye de geçer.

abstract class tam bir class değildir bu sebeple abstract bir sınıfı new methodu ile yeni bir instance oluşturmak istediğinizde hata alırsınız.

Abstract class her ne kadar tam bir class olmasada abstract class ta bir tip tanımlamasıdır. İstenildiği takdirde methodlar argüman olarak kullanılabilir.

Comments


bottom of page