Geçen haftaki dersimizde Java SE’ye genel bir giriş yapıp, sınıf kavramı üzerinde durmuştuk. Ardından temel olarak değişkenlere giriş yapmıştık. Bu dersimizde değişkenler konumuzun diziler alt başlığını anlatıp, sınıf kavramını metotlar ile tamamlayacağız ve ilk sınıfımızı yazacağız. Peşin olarak uyarayım 2. dersimiz biraz uzun olacak 🙂

DİZİLER

Dizi, çoğu programlama dilinde kullanılan en temel veri yapılarından birisidir. Aynı tipteki bir çok değişkenin bir araya gelmesiyle oluşturulmuş bir yapıdır. Bellek dediğimiz RAM’de herhangi bir başlangıç adresinden başlayarak, her eleman tanıtıltığı tipin boyutu kadar yer kaplayacak şekilde arka arkaya yerleşir. Örneğin int tipi 4 byte büyüklüğünde bir veri tipidir ve int tipinde 20 elemanlı bir dizi tanıtılmışsa dizinin boyutu 4 * 20 = 80 byte eder. Bu temel bilgileri kısaca verdikten sonra teoriden çıkıp biraz daha pratiğe kayalım.

Dizi Tanıtmak

Dizilerin bir tipi, bir adı ve bir de boyutu vardır. Dolayısıyla dizi tanıtılırken derleyiciye bu üç parametre de verilmek durumundadır. Java’nın syntax’ına gelecek olursak; java, bir diziyi farklı şekillerde tanıtmamıza imkan tanıyan esnek bir yapıya sahiptir. Bu yapıları aşağıda birer örnekle gösterip tek tek açıklayalım.


int[] sayilar;

int sayilar[];

Yukarıdaki iki örnekte de sayilar adında int tipinde birer diziyi “tanıttık”. Ama sadece tanıttık, yani derleyiciye sayilar adında ve int tipinde bir dizi kullanacağımız bilgisini verdik. Henüz JVM bizim için RAM üzerinde bir dizi oluşturmadı. Dikkat ettiyseniz zaten burada dizinin boyut bilgisi girilmemiş durumda.

İlk dersimizde Java’da her şey birer nesnedir demiştik, diziler de birer nesnedir. Java’da bir nesneyi tanıtmak ayrı bir işlemdir, oluşturmak ayrı bir işlemdir. Peki diziyi tanıttık ama nasıl oluşturacağız ? Bir nesnenin oluşturulması için new kelimesi kullanılır. Bu kadar bilgiden sonra gelin artık dizimizi oluşturalım.

int[] sayilar;
sayilar = new int[5];

Yada

int[] sayilar = new int[5];

Şeklinde dizimizi oluşturmuş olduk. Yukarıdaki ilk örnekte, dizinin tanıtılması ve oluşturulması işlemleri iki ayrı satırda gerçekleştirilirken, ikinci örnekte tek satırda bu işlem tamamlanmıştır. Burada [] (köşeli parantez) ile sayilar isimli alanın bir dizi olduğu bilgisini ve new int[5] komutu ile de 5 adet tamsayıdan oluşacağı bilgisini derleyiciye vermiş olduk. Bu komut satırının yürütülmesinden sonra JVM bizim için bellekte 5 elemanlı bir int dizisi oluşturacaktır.

Java’da, dizi oluştururken verilen boyut bilgisi yukarıdaki örnekte olduğu gibi doğrudan bir sayi ile de verilebilirken, boyut bilgisi olarak bir tamsayı değişken de kullanılabilir. Örneğin

int boyut = 5;
int[] sayilar = new int[boyut];

şeklinde bir kullanım da mümkündür. Buna ek olarak, bir dizi tanıtıldığı sırada ilk değerleri verilmek suretiyle de oluşturulabilir.

int[] sayilar = {3,5,7,9,11};

Örneğinde görüldüğü üzere, sayilar adında ve int tipinde bir dizi tanıtıp, {} (süslü parantez) arasına virgüller ile ayırmak koşuluyla elemanları yazarak dizimizi oluşturmuş olduk. Bu durumda new kelimesinin kullanımına gerek kalmaz.

DİZİ İŞLEMLERİ

Dizi tanıtmayı ve ilişkilendirmeyi öğrendiğimize göre, oluşturduğumuz dizi üzerinde çeşitli operasyonlar nasıl yapılır bunu görelim. Dizilerin elemanlarına, indisler yardımıyla erişim sağlanır. Diziyi tanıtırken kullandığımız köşeli parantezleri hatırlayın, örneğin sayilar[0] dediğimiz zaman, sayilar dizisinin ilk elemanına erişmiş oluruz. Burada da gördüğünüz gibi, Java’da dizilerin ilk elemanı 0 numaralı indistedir. Örneğin sayilar dizisinin ilk elemanına 5 değerini atamak istiyorsak

sayilar[0] = 5;

komutu ile bunu yapabiliriz. Ya da bu 5 değeri atanan ilk elemanı konsol ekranına yazdırmak istiyorsak

System.out.println( sayilar[0] );

şeklinde yazdırabiliriz. Burada System.out.println() metodu kendisine parametre olarak verilen değeri konsolda ekrana yazar.

Yada

sayilar[0] = 5;
sayilar[0]++;

şeklinde bir komut ile ilk elemana 5 değerini atayıp sonra bu değeri 1 arttırabiliriz. Yani kısaca dizinin bir elemanına dizi_adı[indis] şeklinde erişiriz.
Burada indis ile ilgili olarak dikkat edilmesi gereken bazı noktalar vardır.
1. Dizi indisi tam sayı olmak zorundadır.

 

2. Dizi indisi negatif sayı olamaz.

Dizilerle İlgili Bazı İşlemler

Dizi Uzunluğunu Almak

int[] sayilar = new int[5];

şeklinde tanıtılmış bir dizimiz olduğunu varsayalım. Bu sayilar dizisinin boyutunu elde etmek için dizinin length alanını kullanırız. Örneğin

System.out.println( "Dizinin uzunluğu : " + sayilar.length );

komutunun ekran çıktısı

Dizinin uzunluğu : 5

şeklinde olacaktır. Bu length özelliğini döngü içerisinde diziyle ilgili operasyonlar yaparken kullanabiliriz.

Kimi dizi operasyonlarının kullanılabilmesi için java.util paketi içerisinden Arrays sınıfı projeye dahil edilmelidir. Bunun için ilgili sınıfın en yukarısında package komutunun altında

import java.util.Arrays;

komutu kullanılmalıdır.

Diziyi Sıralamak
Bir diziyi sıralamak için Arrays.sort( dizi_adı ); şeklinde Arrays sınıfının sort metodu kullanılır. Bu metot, en hızlı sıralama algoritmalarından birisi olan quicksort algoritmasına göre çalışmaktadır.

Arrays.sort( sayilar );

Dizide Arama Yapmak

Dizi içerisinde arama yapmak için yine Arrays sınıfının binarySearch metodu kullanılır. Bu metot, arama yapılacak dizi ile aranacak eleman bilgilerini parametre olarak alıp, eleman bulunduysa bulunduğu indisi, bulunamadıysa olması gereken indisin bir fazlasının negatif değerini döndürür. NOT : BinarySearch() metodunun kullanılması için dizinin sıralı dizi olması gerekir.

Arrays.binarySearch( sayilar );

Diziyi Bir Elemanla Doldurmak

Dizi bütünüyle bir elemanla doldurmak istenirse, yine Arrays sınıfının fill metodu kullanılır. Bu metot, ilgili dizi ile doldurulacak elemanı parametre olarak alır.

Arrays.fill( sayilar, 0 );

Yukarıdaki örnek, sayilar dizisinin tüm elemanlarının değerini 0 yapar.

Çok Boyutlu Diziler

Şimdiye kadar tek boyutlu diziler ile çalıştık. Bunlardan başka bir de çok boyutlu dizi dediğimiz matrisler vardır.

int[][] sayilar = new int[5][5];

Şeklinde kullanılır. Yukarıdaki örnekte 5 satır ve 5 sütundan oluşan toplam 25 elemanı olan tamsayı tipinde bir matris tanıttık.
Matrisimizi tanıtırken ilklendirmek istersek

int[][] matris = { {1,3,5}, {2,4,6}, {0,0,0} };

şeklinde, 3 satırı ve 3 sütunu olan bir matris tanıtmış ve ilk değerlerini vermiş olduk. Burada {}’ler arasındaki her bir satır aynı zamanda bir diziyi temsil eder. 3 ayrı dizi 3 ayrı satır demektir, her dizinin de 3 elemanlı olması ile 3×3 boyutunda bir matris elde etmiş oluruz.

Diziler ve matrisler ile ilgili işlemlere For ve Foreach döngülerinin anlatıldığı konuda tekrar değineceğim.

Dizi konusunu burada tamamlıyoruz arkadaşlar. Sorularınız olursa yorum yazarak belirtebilirsiniz. Şimdi Sınıf kavramına devam edelim.

SCOPE

Scope kavramı nesnelerin tanımlı ve erişilebilir oldukları alan konusunda bize bilgi vermektedir. Bir değişken yada nesne oluşturduğumuzda, bu nesneye proje genelinde her yerden erişim sağlayamayabiliriz. Bütün nesneler, tanımlandıkları blok arasında varlıklarını sürdürürler. Örneğin bir sınıfın içerisinde tanımlanmış bir değişken düşünelim.

public class Insan {
   private String isim;

   public metot1()
   {
      int sayi1 = 5;
      if( sayi1 > 3 )
      {
          sayi1++;
          int sayi2 = 1;
          System.out.println(sayi2);
      }
      System.out.println(sayi2);</pre>
<pre>   }</pre>
<pre>}

Yukarıdaki örnekte, isim değişkeni sınıf içerisinde tanımlandığı için, sınıfın herhangi bir yerinde çağrılıp kullanılabilir.
sayi1 değişkeni, metot1 isimli metot içerisinde tanımlıdır ve metot1 içerisinde her yerden erişilebilir/ kullanılabilir. sayi2 değişkeni ise metot1 içerisindeki if bloğunda tanımlıdır. Sayi1 değişkeninin değeri 5 olduğundan ve 3 den büyük olduğundan if bloğuna girilir ve sayi2 değişkeni tanımlanarak değeri 1 yapılır. Ardından bu değişken 1 değeri ile konsola yazılır. Fakat sayi2 değişkeni if bloğu içerisinde tanımlanmıştır ve if bloğu bittikten sonra sayi2 değişkeninin varlık alanı da sona ermiş olur. Dolayısıyla ikinci System.out.println(sayi2); komutu için derleyici hata verecektir ve sayi2 değişkeninin tanımlı olmadığını söyleyecektir.

Temel anlamda Scope, nesnelerin kapsam alanını ifade eder. Her nesne, tanımlı olduğu blok içerisinde doğrudan erişilebilir durumdadır. Örneğin yukarıdaki metot1 içerisinde

   public metot1()
   {
      int sayi1 = 5;
      if( sayi1 > 3 )
      {
          sayi1++;
          int sayi2 = 1;
          System.out.println(sayi2);
      }
      <strong>int sayi2 = 6;</strong>
      System.out.println(sayi2);
   }

şeklinde bir değişiklik yaparsak (koyu renkli gösterilen kısım eklendi), if içerisinde 1 yazarken if dışarısında 6 yazacaktır. Yani sayi2 isimli iki değişken birbirinden bağımsız iki ayrı değişkendir. Scope kavramı bize bu kolaylığı sağlamaktadır.

GÖRÜNÜRLÜK – VISIBILITY

Bizler yazılımcı olarak nesnelerin, metotların ve sınıfların hangi durumlarda erişime açık yada kapalı olacağını belirlemek hakkına sahibiz. Örneğin bir değişkene başka sınıflardan erişimi kapatıp, bir metodu her yerden erişilebilir kılabiliriz. Bunun için kullandığımız üç ayrı anahtar kelime vardır. Bunlar;
Private : Sadece tanımlı olduğu blok içerisinde görülebilir.
Public : Her yerden görülebilir ve erişilebilir.
Protected : Kalıtım ile bir sınıftan başka sınıflar türetildiğinde, kendi sınıfı ve alt sınıflardan görülüp diğer sınıflar tarafından görünmez. (Kalıtım konusunda anlatılacak)

İlk derste de değindiğim gibi, genel olarak değişkenler private, metotlar ise public olarak tanıtılır. Doğrudan bir değişkene erişmek/ erişilmesine izin vermek doğru bir davranış değildir. Bunun yerine o değişkenin getter/setter metotları ile değişkene erişerek üzerinde operasyonlar gerçekleştirmek daha doğrudur.

Scope ve görünürlük başlıklarında kısa açıklamalar yaptıktan sonra metot kavramı ile metotları anlatmaya devam edelim.

METOT KAVRAMI

İlk dersimizde sınıf için bir şablon niteliğindedir ve nesneler için de o şablondan türetilen birer varlıktır demiştik. Nesnelerin de özellikleri ve eylemleri vardı. Özellikleri değişkenler ile verdik, sıra geldi eylemlere. Örneğin bir araba nesnemiz olsun, arabamızın hız yapmak, fren yapmak, vites değiştirmek, kalan yakıt miktarını görmek, sağa/sola dönmek, korna çalmak gibi eylemleri olsun. Bu eylemlerin her birini ayrı ayrı metotlar olarak düşünebiliriz. Bir anlamda C dilindeki fonksiyonlar gibi de düşünülebilirler.

Metotlar, temel olarak belli bir işi yapmak üzere tanımlanmış kod bloklarıdır. Bu işi yapmak için bazı parametreler alabilirler yada almayabilirler. Örneğin dizi konusundaki sort( dizi_adı ); şeklinde kullandığımız metodu düşünecek olursak, hangi dizinin sıralanması gerektiği bilgisini sıralama metoduna vermemiz gerekir. Bu metot bizim için diziyi kendi içerisinde sıralar. Bununla birlikte metotlar işlerini bitirdikten sonra geriye bir değer de döndürebilirler. Buna örnek olarak da yine dizi konusunda anlattığımız binarySearch( dizi_adı, aranacak_değer); metodunda düşünecek olursak, verdiğimiz dizide istenilen değeri arayan bir metot, değeri bulursa nerede bulduğunu, bulamazsa da bulamadığını ifade edecek bir değeri döndürmesini bekleriz. İşte bu şekilde metotlar birer fonksiyon gibi çalışarak belirli işler yaparlar. Bir metot tanımlamak için

gorunurluk_tipi donus_degeri metot_adı(parametreler)
{
   -- kod bloğu --
}

şeklinde bir format yazabiliriz.
Geri dönüş değeri olarak, bir ilkel tip (int, double, boolean gibi) yada bir sınıf (String, Araba, Insan gibi) yada dönüş değeri yoksa void anahtar kelimesi kullanılır. Örneğin iki sayıyı toplayan bir metot tanıtacak olursak

public int topla(int a, int b)
{
   return a+b;
}

şeklinde bir metot tanıtabiliriz. int tipindeki topla isimli metodumuz, her biri int tipinde a ve b isimli parametreleri alarak return komutu ile a+b işleminin sonucunu döndürür. Yada bir insanın alışveriş sırasında bir ürünü alırken fiyatına göre karar vermesini basitçe modelleyecek olursak

public boolean kararVer( double fiyat, double max )
{
   if( fiyat > max )
      return false;
   else
      return true;
}

şeklinde bir metot düşünebiliriz. Burada double tipinde ürün fiyatını ve kişinin şu fiyattan pahalıysa almam dediği max isimli parametreyi alarak, if içerisinde karşılaştırıp pahalıysa almam ucuzsa alırım şeklinde basitçe bir karar mekanizması kuran bir metot tanımlamış olduk. Henüz if konusunu anlatmadığım için burada da ufakça bir değineyim, if kontrol yaparak, içerisinde verilen şart doğruysa ilk bloğu, yanlışsa else bloğunu çalıştırır.

Metot kavramını temel olarak anladıysak, get ve set metotları ile devam edelim.

GET ve SET METOTLARI

Daha önceden bir kaç defa değindiğimiz gibi değişkenleri public tanıtıp doğrudan erişmek yerine, değişkenlerimizi private tanıtıp get/set metotları üzerinden erişim sağlamalıyız. Burada get metotları ile değişkenimizin/nesnemizin üzerinde okuma yaparken, set metodu ile yazma işlemi gerçekleştireceğiz. Örneğin String tipinde isim alanı olan Insan sınıfını düşünecek olursak, bu kişinin adını öğrenmek için

public class Insan {

   private String isim;

   public Insan(String isim)
   {
      this.isim = isim;
   }

   public String getIsim()
   {
       String cumle = "Benim adım " + isim;
       return cumle;
   }

</pre>
<pre>   public String setIsim(String isim)
   {  this.isim = isim; }</pre>
<pre>}

Yukarıdaki Insan sınıfında

Insan insan = new Insan("Oğuz");

komutunun çalıştırılmasıyla insan adında ve isim değişkeni Oğuz olan bir nesne oluşturmuş olalım.

insan.getIsım();

komutunun çalıştırılmasıyla insan nesnesi, benim adım Oğuz şeklinde bir String ifadesi geri döndürür.
Yada

insan.setIsım("Ahmet");

komutunun çalıştırılmasıyla, insan nesnesinin isim alanına yeni gelen parametre olan Ahmet verisi yazılacaktır. setIsım() metodundaki this komutu, isim alanının sınıfın üye alanı olan isim olduğunu belirtir. Aksi durumda derleyici iki isim değerinin hangisinin neyi ifade ettiğini anlayamaz. Ya parametre için farklı bir isim kullanılmalıdır yada metot gövdesi içerisinde this anahtar kelimesi ile işlem yapılmalıdır.

Constructor (Kurucu Metot)

Constructor’lar özel metotlardır. new anahtar kelimesinin bir nesne oluşturmak için çalıştırdığı metottur. Constructor’ların geri dönüş değeri yoktur. Bazı istisnalar dışında (ENUM gibi) public olarak tanıtılırlar. Parametre olarak nesnenin oluşturulması sırasında ilk değeri verilecek olan değerleri alırlar ve gövde içerisinde sadece ilk değer ataması gibi işlemler yapılır. constructor metodun adı sınıf adıyla aynı olur. Gelin hep beraber bir Araba sınıfı tanıtalım.

public class Araba {
   private String marka;
   private int hiz, vites;
   private double yakit, maxYakit = 100;
   private boolean[] farlar = new boolean[2];

   public Araba(String marka) { this.marka = marka; }

   public String getMarka(){ return marka; }
   public void setMarka(String marka){ this.marka = marka; }
   public String getHiz(){ return hiz; }
   public String setHiz(int hiz){ this.hiz = hiz; }
   public String getVites(){ return vites; }
   public String setVites(int vites)
   {
      if(vites > 0 && vites < 6)
         this.vites = vites;
   }

   public double getYakit() {return yakit;}
   public void setYakit(double yakit)
   {
      if(yakit >= 0 && yakit < maxYakit)
         this.yakit = yakit;
   }
   public boolean getFar(int indis)
   {
       if(indis > -1 && indis < 3)
          return farlar[indis];
   }
   public void setFar(int indis, boolean durum)
   {
       if(indis > -1 && indis < 3)
          this.farlar[indis] = durum;
   }
}

Yukarıdaki araba sınıfımızda, markamızı almamızı ve değiştirmemizi sağlayan getMarka ve setMarka metotları, hız için getHiz ve setHiz metotları, yakit için getYakit ve verilen yakıt bilgisi aracın yakıt kapasitesinden büyük değilse ve negatif değilse yakıtı dolduran setYakit metodu, getVites ve setVites metotları ve sol ve sağ farlar için yakma/kapama işlemi yapan setFar metodu ile far durumunu görmemizi sağlayan getFar metodu bulunmaktadır. Constructor içerisinde sadece aracın marka bilgisi alınarak ilklendirilmektedir.

Evet arkadaşlar, yeterince uzun bir yazı oldu farkındayım 🙂 Eğer konu ile ilgili sorularınız yada eklemek istediğiniz noktalar olursa yorum yazabilirsiniz. Hepinize bol Java’lı günler diliyorum.