Primitive Type & Reference (Object) Type

Metin Alnıaçık
4 min readSep 17, 2018

--

Primivite type (ilkel tipler) ve reference type (referans tipler)’i birbirinden ayıran en temel nokta bellekte tutulma biçimleridir.

Primitive type nedir?

Değerleri stack (yığıt) üzerinde tutulan ilkel tiplerdir. Örneğin; long, int ve double gibi.
İlkel tiplere değer girilmediğinde varsayılan değerleri aşağıdaki gibidir;
long için 0, int için 0, double içinse 0.0 dır.

Reference type nedir?

Pointer’ları stackte değerleri heap(yığın) de bulunan veri tipleridir. Örnek olarak; String, int[] verebiliriz. Herhangi bir değer girilmediğinde varsayılan değer null olacaktır.

Primitive type’larda (==) kullanırsak bu değişkenlerin içindeki değerlerin eşit olup olmadığına kontrol eder.

Örneğin
int a = 5;
int b = 5;
System.out.println(a == b);
Sonuç true olarak dönecektir.

Reference type’larda ise (==) nesnelerin adreslerinin eşit olup olmadığını kontrol eder. Eğer değişkenlerin içindeki değerlerin eşit olup olmadığını kontrol etmek istiyorsak, bu durumda equals metodu kullanılır.

Örneğin
Long a = new Long(5);
Long b = new Long(5);
System.out.println(a == b);
Sonuç false dönecektir çünkü adresleri farklıdır.
System.out.println(a.equals(b));
Sonuç true dönecektir çünkü değişkenlerin içindeki değerler aynıdır.

Atama (=) işlemi de diğer işlemler gibi farklılık gösterir. Primivite type’larda (=) kullandığımızda değerden yeni bir kopya oluşturur.

Örneğin
int a = 5;
int b = a; // “b”nin değeri de 5 oldu.
a = 10; // “a”nın değeri 10 olarak değişti. Fakat bu durum “b”yi etkilemedi. Çünkü “b” primitive type’dır ve “b”nin değeri hala 5 tir.

Reference type’lar için durum biraz farklıdır.

Örneğin
int[] a = {1,2,3};
int[] b = a; // şu anda b ve a referans tipleri aynı yeri gösteriyor.
b[2] = 10; // bu kısımda b 2. indexdeki veriyi değiştirmesine rağmen a[2] de değişiyor. Çünkü ikinci satırda aynı adresi gösteriyorlar.
System.out.println(a[0] + “, “ + a[1] + “, “ + a[2]); // 1, 2, 10
System.out.println(b[0] + “, “ + b[1] + “, “ + b[2]); // 1, 2, 10

Bazı referans tiplerinde ise güncelleme işlemi gerçekleştirilemez. Güncelleme işlemi yapmaya çalıştığınızda heap üzerinde yeni bir nesne oluşturulur ve pointer yeni nesneyi gösterir. Bu tip nesnelere immutable object (değişmez nesne) denir. Bu duruma örnek olarak String verilebilir.

İlk kısımda name adında bir değişken tanımlanıyor ve değeri Metin olarak atanıyor. Daha sonra name değişkeninin değeri Yusuf olarak güncelleniyor. Bu durumda heap üzerinde yeni bir nesne oluşturuluyor ve name pointer’ı içinde Yusuf değeri yazan nesneyi gösteriyor.

Bu iki tip arasında performans farkları da vardır.

10000000 tane primitive long ve reference type long değişkenin içine atama işlemi yapıyoruz ve aralarında ne kadar fark olduğunu gözlemleyeceğiz. Primitive olan değişkenler 13088785 nanosecond sürüyor. Reference type ise 177690004 nanosecond sürüyor. Aralarındaki fark yaklaşık; reference type, primitive type’ın 13 kat daha fazla olduğu gözlemlendi.

Metoda Primitive Type Bir Parametre Göndermek

Eğer bir metoda primitive type bir parametre gönderiyorsak bu değer kopyalanarak gider. Metodun içinde değer değiştirilse bile orijinal değerde bir değişiklik olmaz.

Sonuç aşağıdaki gibidir;
##main method## 20
##changeNumber method## 40
##again main method## 20

Metoda Reference Type Bir Parametre Göndermek

Reference type bir veri herhangi bir metoda parametre geçildiğinde nesne reference olarak gönderilir. Metot içerisinde parametre üzerinde herhangi bir değişiklik yapılırsa, bu değişiklik orijinal değerin değişmesine neden olur.

Sonuç aşağıdaki gibidir;
##main method## {1, 3, 5}
##changeNumber## {10, 3, 20}
##again main method## {10, 3, 20}

Eğer metot içerisinde değişiklik yapıldığında orijinal değerin değişmesi istenmiyorsa metot içerisine gelen parametreyi new komutu ile tekrar oluşturulur.

Sonuç aşağıdaki gibidir;
##main method## {1, 3, 5}
##changeNumber## {10, 0, 20}
##again main method## {1, 3, 5}

Birde aşağıdaki örneği inceleyelim;
Öncelikle, örnekte kullanacağımız Personel sınıfını ekleyelim.

  • 10. satırda “b” nin değeri “a” nın değerinin kopyası olur. Yani 10
  • 15. satırda “b” nin değeri 5 olarak değiştirilir. Fakat bu “a” nın değerini etkilemez. Çünkü “b” primitive type’dır.
  • 20. satırda “p1” adında bir Personel nesnesi oluşturulur ve “name” alanı “Metin” değeri ile doldurulur.
  • 21. satırdaki işlem ile “p2” nesnesi “p1” nesnesine atanarak aynı adresleri göstermesi sağlanır.
  • 23. ve 24. satırlarda değerlere bakıldığında “p1” ve “p2” nin “name” değerlerinin “Metin” olduğu görülmektedir.
  • 27. satırda “p2” nin “name” alanını “Yusuf” olarak güncelliyor. “p1” ve “p2” aynı adresleri gösterdiği için her iki değişkenin değeri “Yusuf” olarak değişiyor.
  • 35. satırda ise “p2” new anahtar sözcüğü ile kullanılarak yeniden oluşturulmaktadır. Artık “p1” ve “p2” farklı adresleri göstermektedir. “p1” veya “p2” de yapılacak değişiklikler birbirlerini etkilemeyecektir.

Son Olarak İlginç Bir Örneği İnceleyelim;

Sonuç aşağıdaki gibidir;
##main method## Metin
##changeName## Yusuf
##again main method## Metin

Bu örnekte, ilginç olan durum şudur;
String, bir reference type’tır. Sonucun aşağıdaki gibi olması beklerdik.
##main method## Metin
##changeName## Yusuf
##again main method## Yusuf

Fakat bu şekilde olmadı. Bunun nedeni ise daha sonraki yazılarımdan bir tanesinde detaylı olarak açıklayacağım bir konudur. Araştırmak isteyenler için bir ipucu vereyim: immutable object.

Örneğin tamamına github adresimden ulaşabilirsiniz.

İyi günler,
Bol kodlamalar :)

--

--

Responses (2)