~BöLÜM-4~

 

 

Erişim

Erişim konusu kütüphaneler için çok büyük bir önem taşımaktadır.Erişim konusunda iki taraf vardır , bir tanesi kütüphaneyi kullanan kişiler (client) , diğeri ise bu kütüphaneyi yazan kişilerdir. Olaylara kütüphaneleri kullanan kişilerin bakış açısından bakarsak , istenen  durum , bir kütüphanenin ilk versiyonunu kullanan bir uygulamanın , bu kütüphanenin ikinci , üçüncü ,dördüncü.... n. inci  versiyonlarında  bile uygulamada herhangi bir uyumsuzluk sorununun yaşanmamasıdır. Kütüphanenin her yeni versiyonununu , -ki yeni versiyon demek daha az hatalı , daha gelişmiş bir kütüphane anlamına gelir , sistemimize entegre ettiğimizde , bu kütüphaneyi kullanan her uygulamayı değiştirmeye kalkışsak hayat çekilmez olurdu herhalde .

Olaylara birde kütüphaneleri yazan kişilerin bakış açısı ile bakalım . Bir kütüphane yazdınız , ve bunu kullanılması için internete koydunuz , bu kütüphane çok tutuldu , herkes tarafından tebrik mesajları geliyor herşey çok güzel .Fakat daha sonradan bu kütüphane içersinde bir hata olduğunu fark ettiniz veya bu kütüphane içersindeki bazı kısımları , daha hızlı çalışması için optimize etmek istiyorsunuz . Kütüphaneye yazan kişinin bu arzuları , bu kütüphane üzerinde nasıl bir etki oluşturur . Kütüphaneyi kullanan kişiler bundan zarar görebilir mi ? veya zarar görmemesi için ne yapılması gerekir.

Bu tür problemlerin çözümü için devreye erişim kavramı girir , Java toplam dört adet erişim belirliyicisi sunar . En erişilebilirden en erişilmeze doğru sıralarsak , public , protected , friendly , private  dır. Bu erişim belirliyicileri sayesinde hem kütüphanleri yazan kişiler özgürlüklerini kavuşur , hemde kütüphaneyi kullanan kişiler kullandıkları kütüphanenin yeni bir versiyonunu rahatlıkla sistemlerini entegre edebilirler.

Kütüphaneleri tasarlayan kişiler , ileride değişebilecek olan sınıfları , veya sınıflara ait metodları , kullanıcı tarafından erişilmez yaparak , hem kütüphanenin rahatça gelişmesini sağlamış olurlar hemde  kütüphaneyi kullanan kişiler endişelerini  gidermiş olurlar."Herşey tamam ama paket ne anlama gelmektedir" , diyenler için gerekli açıklamaları yapalım.

Paket (package)  

Paketler kütüphaneyi  oluşturan elemanlardır . Paket mantığının var olmasında ana sebeblerden biri , isim karmaşasını çözmektir. Örneğin elimizde iki sınıf bulunsun X sınıfı ve Y sınıfı. Bu sınıflar içersinde aynı isimde iki metod olması , örneğin f() metodu , herhangi bir karmaşıklığa sebebiyet vermiyecektir.Sebebi ise bu aynı isimdeki metodların ayrı sınıflarda bulunmasıdır.Peki ya sınıf isimleri  ? Sistemimizde bulunan aynı isimdeki sınıflar karmaşıklığa sebeb vermez eğer ki bu aynı isimdeki sınıflar değişik paketlerin içersinde bulunursa . 

gösterim-1 

import java.io.BufferedReader;

Yukarıdaki gösterimimizde BufferedReader  sınıf isminin java.io paketinde tek olduğunu anlıyoruz (java.io paketi Java ile gelen standart bir pakettir.).Fakat başka paketlerin içersinde BufferedReader sınıf ismi rahatlıkla kullanılabilir. Paketin içersindeki tek bir sınıfı kullanmak yerine , paketin içersindeki tüm sınıfları tek seferde kullanmak için : 

gösterim-2

import java.io.* ;

java.io paketinin içersinde sınıfları  kendi uygulamalarımızda kullanmak için, sadece import java.io.* dememiz yeterli olacaktır.

ör-paket-kullanim

import java.io.*;

public class PaketKullanim {

    public static void main(String args[]) throws IOException{
	BufferedReader  sf = new BufferedReader(new InputStreamReader(System.in));
	System.out.print("Bilgi Giriniz : ");
	String bilgi = sf.readLine();
	System.out.println("bilgi --> " + bilgi);
    }
}

Yukarıda örneğimizde görmediğimiz  yeni kavram mevcuttur , "throws Exception" . İstisnalar(Exception) konusunu ilerleyen bölümlerde detaylı bir şekilde inceliyecegiz. 

Varsayılan Paket (Default Package)

Öncelikle şunu tekrardan belirtelim , .java uzantılı fiziksel dosyayı derlediğimiz zaman , .java uzantılı fiziksel dosyanın tam ismine karşılık gelen .class fiziksel dosyası elde ederiz (tabii *.java dosyasında hata olmadığını farzederek) .Eğer .java fiziksel dosyasında  birden fazla sınıf tanımlanmış ise , tanımlanan bu her sınıf için ayrı ayrı .class fiziksel dosyaları Java tarafından üretilir.

ör-varsayılan-paket-1 - Test1.java

public class Test1 {
    
    public void kos() {
    }
}

class Test2 {
    
    public void kos() {
    }
}

 

Yukardaki örneğimizi , Test1.java adıyla  herhangi dizine  kaydettim (fiziksel java uzantılı dosya ile public sınıfın ismi birebir aynı olmalıdır) , bu dosyayı javac komutu ile derlediğimde iki adet  fiziksel .class dosyası elde ederim ; Test1.class ve Test2.class . Test1.java dosyanın en başına herhangi bir paket ibaresi yerleştirmediğimden dolayı , Java bu sınıfları varsayılan paket  (default package) olarak algılıcaktır.

ör-varsayılan-paket-2 - Test3.java

public class Test3 {
    
    public void kos() {
    }
}

Aynı şekilde bu örneğimizide aynı dizine Test3.java adıyla kaydettip derlenikten sonra genel bakış aşağıdaki gibidir.

 

Şekil-1

Paket Oluşturma

Kendi paketlerimizi oluşturmanın temel amaçlarında biri , aynı amaca yönelik işleri yapan sınıfları bir çatı altında toplamaktadır.Bu sayede yazılan sınıflar daha derli toplu olur , artı aranılan sınıflar daha kolay bulunabilir. Peki eğer kendimiz paket oluşturmak istersek  bunu nasıl başaracağız ? 

ör-paket-2

package tr.edu.kou.util ;

public class Test1 {

    public Test1() {
	System.out.println("tr.edu.kou.util.Test1 objesi olusturuluyor");
    }

    public static void main(String args[]) {
	  Test1 pb = new Test1();
    }
}

ör-paket-2 örneğimizde , Test1.java fiziksel dosyasını işletim sistemimizin herhangi bir dizine yerleştiremeyiz çünkü o artık tr.edu.kou.util paketine ait bir sınıfdır , bu sebepten dolayı içinde bulunması gereken dizinde bu paket ismiyle pararlel olmalıdır.

 

Şekil-2

Paket isimlerine bulunan çözüm , şu andaki internet alan isim sistemiyle(Internet Domain Name System) aynıdır.Örneğin Kocaeli Üniversitesinde matematik paketi yazan bir kişi , bu paketin içersindeki sınıfların,dünyanın herhangi bir yerindeki başka kütüphanenin paketleri içersindeki sınıfların  ismiyle çakışmaması için  internet alan isim sistemini kullanmalıdır. Internet alan isim sistemi , www.kou.edu.tr adresinin  dünya üzerinde tek olduğunu garantiler. Aynı mantığı paket isimlerine uygulayarak , paketlerin içersindeki sınıf ismi  problemine çözüm bulmuş oluruz . Dikkat edilecek olursa , paket isimleri , Internet alan isimlerinin tersden yazılmış halleridir , işletim sistemlerinin farkı göz önüne alınarak , math paketine ait sınıfların içinde bulunması gereken dizin , Unix veya Linux için   tr/edu/kou/math , Window için  tr\edu\kou\math şekilde olmalıdır.

 

Şekil-3

CLASSPATH ayarları 

Java yorumlayıcısı (interpreter) ; işletim sisteminin çevre değişkenlerinden CLASSPATH değişkenini bakarak import ifadesindeki paket'i  bulmaya calisir.

gösterim-3

import  tr.edu.kou.math.*;

Diyelim ki math paketi aşağıdaki dizinde bulunsun :

gösterim-4

C:\kodlar\bolum4\tr\edu\kou\math\

Java yorumlayıcısının , import ifadesindeki paket'i bulması için aşağıdaki tanımı CLASSATH'e eklememiz gerekmektedir.

gösterim-5

CLASSPATH="C:\kodlar\bolum4\;."

CLASSPATH'e eklenen bu tanım sayesinde , Java yorumlayıcısı , C:\kodlar\bolum4\  dizinine  kadar gidip , tr\edu\kou\math dizinini arıyacaktır , eğer -ki böyle bir dizin bulunursa , bu dizinin altındaki tüm sınıflar uygulama tarafından kullanılabilecek hale gelecektir.

 Şekil-4

 

DortIslem.java , dosyasını  C:\kodlar\bolum4\tr\edu\kou\math  dizinine yerleştirelim :

ör-dört-işlem

package tr.edu.kou.math ;

public class DortIslem {

    public DortIslem() {
	System.out.println("tr.edu.kou.util.DortIslem objesi olusturuluyor");
    }

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

    public double cikart(double a , double b) {
	return (a - b) ;
    }

    public double carp(double a , double b) {
    	return (a * b) ; 
    }

    public double bol(double a , double b) {
	if  ( (a != 0) && (b != 0) )  {
	    return (a / b) ;
	} else {
	    return 0 ;
	}
    }  
}

 

Gerekli CLASSPATH , tanımlarını yaptıktan sonra , bu paketi kullanacak olan uygulamamızı , işletim sistemimizin herhangi bir dizinine yerleştirebiliriz.

ör-dört-işlem-kullanım

import tr.edu.kou.math.*;

public class Hesaplama {

    public static void main(String args[]) {
	DortIslem di = new DortIslem();
	double sonuc = di.topla(9.6 , 8.7);
	System.out.println("9.6 + 8.7 = " + sonuc   );
	sonuc = di.cikart(9.6 , 8.7);
	System.out.println("9.6 - 8.7 = " + sonuc   );
	sonuc = di.carp(5.6 , 8.7);
	System.out.println("9.6 * 8.7 = " + sonuc   );
	sonuc = di.bol(5.6 , 8.7);
	System.out.println("9.6 / 8.7 = " + sonuc   );
    }
}

Uygulamanın çıktısı aşağıdaki gibidir:

tr.edu.kou.util.DortIslem objesi olusturuluyor
9.6 + 8.7 = 18.299999999999997
9.6 - 8.7 = 0.9000000000000004
9.6 * 8.7 = 48.71999999999999
9.6 / 8.7 = 0.6436781609195402
Önemli nokta

Dikkat ettiyseniz , CLASSPATH değişkenini tanımlarken , tanımın en sonuna "." nokta koyduk. 

Şekil-5

Bu önemli bir ayrıntıdır. Bu noktanın konmasındaki neden , varsayalın paketlerin(default package) içindeki sınıfların birbirlerini görebilmesini sağlamaktır.Bu nokta unutulursa , anlamsız hata mesajları ile karşılaşılabilir.

Java 2 'yi sisteminize ilk kurduğunuz zaman basit örnekleri  CLASSPATH değişkenine herhangi bir tanım eklemeden bile çalıştırabildiğinizi görürsünüz. Bunun sebebi Java 2 'nin temel kütüphanleri , kendi kurulum dizinine göre tahmin edebilmesinden  ileri gelir.

Çakışma

Ayrı paketin içersindeki , aynı isimdeki sınıfları uygulamızda kullanırsak ne olur ? Tahminen , isimleri aynı olsa bile  değişik paketlerde bulundukları için bir sorun yaşanmaması gerekir. 

Öncelikle tr.edu.kou.util paketinin  içersine kendi ArrayList sınıfımızı yazalım .

ör-io-arraylist

package tr.edu.kou.util;

public class ArrayList {

    public ArrayList() {
	System.out.println("tr.edu.kou.util.ArrayList objesi olusturuluyor");
    }
}

Aşağıdaki örneği işletim sisteminizin herhangi bir dizinine kayıt edebilirsiniz.

ör-çakışma-1

import java.util.*;
import tr.edu.kou.util.*;

public class Cakisma  {

    public static void main(String args[]) {
	System.out.println("Baslagic..");
	ArrayList al = new ArrayList();
	System.out.println("Bitis..");
    }  
}

 

Cakisma.java dosyasını javac komutu ile derlediğimiz zaman , aşağıdaki hata mesajı ile karşılaşırız.

Cakisma.java:8: reference to ArrayList is ambiguous, both class tr.edu.kou.util.
ArrayList in tr.edu.kou.util and class java.util.ArrayList in java.util match
ArrayList al = new ArrayList();
^
Cakisma.java:8: reference to ArrayList is ambiguous, both class tr.edu.kou.util.
ArrayList in tr.edu.kou.util and class java.util.ArrayList in java.util match
ArrayList al = new ArrayList();
^
2 errors

Bu hata mesajının anlamı , ArrayList sınıfının hem java.util paketinde hemde tr.edu.kou.util paketinde bulunmasından kaynaklanan bir ikilemi ifade eder. Uygulamda ArrayList sınıfı kullanılmıştır ama hangi paketin içindeki ArrayList sınıfı ?

Bu sorundan kurtulmak için aşağıdaki örneğimizi inceliyelim 

ör-çakışma-2

import java.util.*;
import tr.edu.kou.util.*;

public class Cakisma2  {

    public static void main(String args[]) {
	System.out.println("Baslagic..");
	tr.edu.kou.util.ArrayList al = new tr.edu.kou.util.ArrayList();
	System.out.println("Bitis..");
    }  
}

Eğer ortada bir ikilem varsa , hangi sınıfını kullanmak istiyorsanız ,o  sınıfın içinde bulunduğu paket isimini de yazarak , oluşan ikilemi ortadan kaldırabilirsiniz. 

Paket içersindeki uygulamaları çalıştırmak

Paketlerin içersindeki tek başına çalışabilen uygulamalarımızı (standalone), herhangi bir yerden önüne sadece paket açıklamasını yazarak çalıştırmamız mümkündür. ör-dört-işlem-kullanım uygulamasının yeni versiyonu C:\kodlar\bolum4\tr\edu\kou\math  dizinine kaydedelim.

ör-paket-uygulama

package tr.edu.kou.math	;

public class Hesaplama {

    public static void main(String args[]) {
	DortIslem di = new DortIslem();
	double sonuc = di.topla(9.6 , 8.7);
	System.out.println("9.6 + 8.7 = " + sonuc   );
	sonuc = di.cikart(9.6 , 8.7);
	System.out.println("9.6 - 8.7 = " + sonuc   );
	sonuc = di.carp(5.6 , 8.7);
	System.out.println("9.6 * 8.7 = " + sonuc   );
	sonuc = di.bol(5.6 , 8.7);
	System.out.println("9.6 / 8.7 = " + sonuc   );
    }
}

Artık Hesaplama sınıfımız tr.edu.kou.math paketinin yeni üyesidir. Paket içersindeki tüm java uzantılı dosyaları C:\kodlar\bolum4\tr\edu\kou\math javac *.java diyerek derlenikten sonra  Hesaplama.class dosyasını java komutu kullanara çalıştırmayı deneyelim .

gösterim-6

java Hesaplama

Bir aksilik var gibi , ekranda beliren hata mesajı aşağıdaki gibidir .

Exception in thread "main" java.lang.NoClassDefFoundError: Hesaplama (wrong name
: tr/edu/kou/math/Hesaplama)
        at java.lang.ClassLoader.defineClass0(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:509)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:12
3)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:246)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:54)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:193)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:186)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:265)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:262)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:322)

Hesaplama sınıfı bulanamıyor diye bir hata mesajı ? nasıl olur ama orda ?? evet orada ama o artık Hesaplama sınıfı değildir , tr.edu.kou.math.Hesaplama sınıfıdır yani artık bir paketin üyesi olmuştur. Aşağıdaki ifade sayesinde işletim sisteminizin herhangi bir dizininden (- tabii CLASSPATH değişkeninin değeri doğru tanımlanmış ise ) tr.edu.kou.math.Hesaplama sınıfına ulaşıp onu java komutu ile çalıştırabiliriz.

gösterim-7

java tr.edu.kou.math.Hesaplama

Uygulamanın çıktısı aşağıdaki gibidir .

9.6 + 8.7 = 18.299999999999997
9.6 - 8.7 = 0.9000000000000004
9.6 * 8.7 = 48.71999999999999
9.6 / 8.7 = 0.6436781609195402

JAR Dosyaları (The JavaTM Archive File)

JAR dosya formatı , birçok dosyayı arşivlemenize ve sıkıştırmamıza  olanak tanır.Normalde JAR dosylarının içersinde sınıf dosyaları bulunur.Bazı durumlarda özellikle appletler de yardımcı dosyalarda(gif , jpeg ...) JAR dosyasının içersinde konulabilir.

JAR dosyasının sağladığı faydalar aşağıdaki gibidir.

  • Güvenlik : Digital olarak JAR dosyasının içeliğini imzalıyabilirsiniz.Böylece sizin imzanızı tanıyan kişiler JAR dosyasının içeliğini rahatlıkla kullanabilirler.
  • Sıkıştırma : Bir çok dosyayı güvenli bir şekilde arşivleyip sıkıştırılabilir.
  • Download zamanını azaltması : Arşivlenmiş ve sıkıştırılmış dosyalar internet üzerinde daha çabuk indirilebilir.
  • Paket mühürleme(versiyon 1.2) : Versiyon uyumluluğunu sağlamak amacı ile JAR dosyasının içersindeki paketler mühürlenebilir. JAR dosyasının içersinde paket mühürlemekten kasıt edilen paket içersinde bulunan sınıfların aynı JAR dsyasında bulunmasıdır.
  • Paket versiyonlama (versiyon1.2) : JAR dosyaları , içindeki dosyalar hakkında bilgiler saklayabililer , örneğin üretici firmaya ait bilgiler ,versiyon bilgileri gibi gibi .
  • Taşınabilirlik : Java Platformunun standart bir üyesi olan JAR dosyaları , kolaylıkla taşınabilir. 

Oluşturduğumuz paketlerimizi JAR dosyasının içersine yerleştirerek daha derli toplu bir görüntü elde etmiş oluruz.  tr.edu.kou.math ve tr.edu.kou.util paketlerini tek bir JAR dosyasında birleştirmek için aşağıdaki komutu kullanmamız yeterli olur ama JAR dosyasını oluşturmak için yazılan komutun hangi dizinde çağrıldığı önemlidir.

JAR-dosyası işlemleri için gerekli olan bazı komutlar :

Açıklama
Komut
JAR dosyası oluşturmak için
jar -cf  jar-dosya-ismi içeriye-atılacak-dosya(lar)
JAR dosyasının içeliğini bakmak için
jar -tf  jar-dosya-ismi
JAR dosyasının içeliğini toptan dışarı çıkartmak için
jar -xf  jar-dosya-ismi
Belli bir dosyayı JAR dosyasından dışarı çıkartmak için
jar -xf  jar-dosya-ismi arşivlenmiş dosya(lar)
JAR olarak paketlenmiş uygulayı çalıştırmak için
jre -cp  jar-dosya-ismi MainClass

tablo-1

gösterim-8

jar -cf kou.jar tr/

 

Gösterim-8'deki ifadeyi C:\kodlar\bolum4  dizinin içersinde iken çalıştırmalıyız ki , JAR dosyasının içersine doğru yapıdaki dizinleri yerleştirelim.

Şekil-6 

 

Oluşmuş olan bu JAR dosyasını CLASSPATH ekleyerek , Javanın bu paketleri bulmasını sağlıyabilirsiniz.Aşağıdaki ifade yerine :

gösterim-9

CLASSPATH="C:\kodlar\bolum4\;."

bu ifadeyi kullanabilirsiniz .

gösterim-10

CLASSPATH="C:\muzik\kou.jar;."

Java CLASSPATH değerindekiden yola çıkarak JAR dosyasını bulup açar , tr\edu\kou\util ve tr\edu\kou\math dizinlerine erişebileceğinden bir sorun yaşanmıyacaktır.Yani JAR dosyasının hangi dizinde olduğu önemli değildir , önemli olan CLASSPATH'de olmasıdır.Tabii paketlerin içersindeki sınıflar geliştikçe güncelliği korumak adına JAR dosyasını tekrardan üretmek gerekecektir.

 

Erişim Belirliyiciler

Java programlama dilinde , 4 tür erişim belirliyicisi vardır ; friendly  public , protected  ve  private . Bu erişim belirliyicileri global olan değişkenlerde(statik veya değil) ve metodlarda (statik veya değil) kullabilirsiniz .Ayrıca sınıflarımıza erişimlerde de sadece public ve friendly erişim belirliyicilerini kullanırız. 

Friendly (Arkadaşca)

Friendly erişim belirliyicisi , global değişkenlere (statik veya değil) , metodlara (statik veya değil) ve sınıflara atanabilir.Friendly türünde erişim belirliyicisine sahip olan  global değişkenler (static veya değil) , içinde bulundukları paketin diğer sınıfları arafından erişilebilirler.Fakat diğer paketlerin içersindeki sınıflar tarafından erişilemezler.  Yani diğer paketlerin içerisindeki sınıflara karşı private erişim belirliyici etkisi oluşturmuş olurlar.Friendly metodlarda (statik veya değil) yanlız aynı paketin içersindeki sınıflar tarafından erişilebilirler , başka paketlerin içersindeki sınıflar tarafından erişilemezler.

Aynı şekilde sınıflarada friendly erişim belirliyicisi atayabiliriz, böylece aynı paketeki diğer sınıflar tarafından erişilebilir ama diğer paketlerin içersindeki sınıflar tarafından erişilemezler

Şimdi tr\edu\kou\ dizinin altina yeni bir dizin oluşturalim , ve ismini  gerekli  verelim, yani tr\edu\kou\gerekli paketini oluşturmuş oldum. Bu paketin içersine iki adet frindly sınıf yazalım , Robot ve Profesor sınıfları

 

ör-friendly-Robot

package tr.edu.kou.gerekli;
class Robot {

    int calisma_sure  = 0;
    String renk  = "beyaz";
    int motor_gucu  = 120;
    
    Robot() {
	System.out.println("Robot olusturuluyor");
    }
}

 

ör-friendly-Profesor

package tr.edu.kou.gerekli;
class Profesor {   
    public void kullan() {
	Robot  upuaut = new Robot(); // sorunsuz
    }
}

 

Yukarıdaki örneklerimizden anlaşılacağı üzere bir global değişkeni (statik veya değil) veya bir sınıfı friendly yapmak istiyorsak önüne hiç bir erişim belirliyicisi koymayız. Şimdi bu iki sınıf aynı paketin içinde olduklarına göre Profesor sınıfı rahatlıkla Robot sınıfına erişebilecektir.Peki başka bir paketdeki sınıf Robot sınıfına erişebilir mi ? 

ör-friendly-Asistan

package tr.edu.kou.util;

import tr.edu.kou.gerekli.*;
public class Asistan {

    public void arastir() {
	System.out.println("Asistan arastiriyor");
    }

    public void kullan() {
	//Robot  upuaut = new Robot(); ! Hata ! erisemez
    }
}

Daha evvelden belirtildiği gibi , friendly olan global değişkenlere (statik veya değil) veya sınıflara sadece içersinde bulunduğu paketin diğer sınıfları tarafından erişilir ,diğer paketlerin içersindeki sınıflar tarafından  erişilemezler. Şekil üzerinde göstermeye çalışırsak :

Şekil-7

 

Varsayılan Paketlerde (Default Package ) Erişim

Aşağıdaki iki java dosyasını işletim sistemimin herhangi bir dizinine kaydetttim.

ör-alt-komşu

class AltKomsu {
    public static void main(String[] args) {
	UstKomsu uk = new UstKomsu();
	uk.merhaba();
    }
}

ör-üst-komşu

class UstKomsu {
    void merhaba() {
	System.out.println("Merhaba");
    }
}

Bu iki sınıf friendly erişim belirliyisine sahiptir yani aynı paketin içersindeki sınıflar tarafından erişilebilirler ama ortada herhangi bir paket ibaresi bulunmamaktadır. Aynı dizinde olan fakat bir paket olarak tanımlanmamış  sınıfların , Java tarafından varsayılan paket çatısı altında toplandığını biliyoruz. Bu iki sınıfın birbirini görebilmesi için CLASSPATH değişkenin değerinde  "." (nokta) ibaresinin olması şarttır (bkz).

Public (Herkese açık)

Public erişim belirliyicisi kullanıdığınız global değişkenler (statik veya değil) veya metodlar (statik veya değil), herkes tarafından erişilebilir hale gelir.Bu erişim belirliyicisini yerleştirmeden evvel iki kere düşünmenizi tavsiye ederim. Bu erişim belirliyicisine sahip olan global değişkenler (statik veya değil) veya metodlar (statik veya değil ) herhangi bir yerden direk olarak çağrılabildiklerinden dolayı , dış dünya ile paketiniz arasındaki arabirim rolünü üstlenirler.

ör-public-makine

package tr.edu.kou.util;

public class Makine {
     
    int devir_sayisi;
    public String model = "2002 model" ;
    
    public int degerAl() {
	return devir_sayisi;
    }

    public void degerAta(int deger) {
	this.devir_sayisi = deger;
	calis();
    }

    void calis() {
	  for (int i = 0 ; i < devir_sayisi ; i++) {
	    System.out.println("Calisiyor , devir_sayisi = " + i);
	  }
    }
}

 

tr.edu.kou.util paketinin içersinde Makine sınıfının iki adet global obje değişkeni bulunmaktadır , bunlardan int ilkel tipindeki devir_sayisi değişkeni friendly erişim belirliyicisine sahiptir , yani sadece tr.edu.kou.util paketinin içersindeki diğer sınıflar tarafından direk erişilebilir. Diğer String tipindeki  model değişkenimiz ise her yerden erişilebilir.  degerAl() metodu public erişim belirliyicisine sahiptir yani heryerden erişilebilir.Aynı şekilde degerAta(int deger) metoduda her yerden erişilebilir ama calis() metodu friendly erişim belirliyicisine sahip olduğundan sadece aynı paketin içersindeki sınıflar tarafından erişilebilir.

ör-makine-kullanım

import tr.edu.kou.util.*;

public class UstaBasi {

    public UstaBasi() {
	Makine m = new Makine();  
	// int devir_sayisi = m.devir_sayisi ; ! Hata ! erisemez
	m.degerAta(6);
	int devir_sayisi = m.degerAl();
	String model = m.model;
	// m.calis() ; ! Hata ! erisemez
    }
}

 

Private (Özel)

Private  olan global değişkenlerimiz (statik veya değil) veya methodlarımıza (sınıflar private olamazlar), aynı paket içinden olsun , veya farklı paketlerden olsun erişilemezler .Ancak  ait olduğu sınıfın içinden  erişilebilirler . Bu sayede eğer bir kütüphane yazarsanız , o kütüphaneyi kullanan kullanıcıların kodlarına zarar vermeden , yeni üst versiyonlar hazırlayabilirsiniz . Private erişim belirliyici sizin için özgürlük anlamina gelebilir.

ör-private-1

package tr.edu.kou.gerekli;

class Kahve {     
	private int siparis_sayisi;
	private Kahve() {
	}
	
	private void  kahveHazirla() {
	    System.out.println(siparis_sayisi + " adet kahve hazirlandi");
    	}

	public static Kahve  siparisGarson(int sayi) {
	    Kahve kahve = new Kahve();
	    kahve.siparis_sayisi = sayi ;    
	    kahve.kahveHazirla();
	    return kahve;
	}
}

ör-private-2

package tr.edu.kou.gerekli;
public class Musteri {
	
	public  static void main(String args[]) {    
		// Kahve kh = new Kahve() ; // ! Hata !		
		// kh.kahveHazirla()  ; //! Hata !
		// kh.siparis_sayisi = 5 ; //	! Hata !
	        Kahve kh  = Kahve.siparisGarson(5);
	}
}

Kahve sınıfının yapılandırıcısı (constructor) private olarak tanımlanmıştır . Bu sebebten herhangi bir başka sınıf , Kahve sınıfının yapılandırıcısı direk olarak çağıramaz ,aynı paketin içersinde olsa dahi . Ama bu private yapılandırıcı aynı sınıfın içersindeki metodlar tarafından rahatlıkla çağırılabilir. Aynı şekilde private olarak tanımlanmış global değişkenelere (statik veya değil) veya metodlara , aynı paket içersinde olsun veya olmasın , kesinlikle erişilemez. Şekil üzerinde gösterirsek : 

Şekil-8

Bu örnekte Kahve Objesini direk olarak oluşturamıyoruz yani  kendimiz direk olarak kafe'nin mutfağından kahve alamiyoruz , kahve içmek için kesinlikle garson a siparis vermeliyiz . Bizde siparisGarson() metodu ile siparişlerimizi garson'a iletmiş oluyoruz. 

Protected (Şartlı erişim)

Sadece global değişkenler (statik veya değil)  ve metodlar(statik veya değil) protected erişim belirliyicise sahip olabilirler .Sınıfların protected erişim belirliyicisine sahip olma imkanı yoktur , sınıflar friendly veya public erişim belirliyicisine sahip olabilirler. Protected erişim belirliyicisi kalıtım(inheritance) konusu ile sıkı sıkıya bağlıdır.Kalıtım konusunu bir sonraki bölümde ele alınıcaktır. Kalıtım konusundan kısaca bahsedersek , ana bir sınıfdan diğer sınıfların türemesi diyebiliriz.

gösterim-11

class Kedi extends Hayvan

Gösterim-7 deki ifade şunu der : Her Kedi bir Hayvandır.Yani Hayvan sınıfından Kedi ürettik,bizim oluşturacağımız her Kedi objesi bir Hayvan olacaktır ama kendine has kedisel özelliklerde taşıcaktır. 

Protected erişim belirliyicisini evdeki buzdolabımızın kapısına vurulmuş bir kilit olarakta düşünebiliriz.Örneğin evimizde bir buzdolabı var ve içinde her türlü yiyecek ve içecek mevcut ,biz aile büyüğü olarak bu buzdolabına herkesin erişmesini istemiyoruz (public yaparsak) aksi takdirde yiyecek ve içecek kısa sürede bitip ailenin aç kalma tehlikesi oluşacaktır , aynı şekilde bu buzdolabına erişimi tamamen kesersek de aile bireyleri aç kalacaktır (private yaparsak). Tek çare özel bir erişim belirliyicisi kullanmaktır yani sadece aileden olanlara ve komşulara(aynı paketin içersindeki sınıflara)  bu buzdolabının erişmesine izin veren bir erişim belirliyicisi yani protected erişim belirliyicisi.

ör-hayvan-1

package tr.edu.kou.util;
public class Hayvan {
	protected String a = "Hayvan.a";
	String b = "Hayvan.b"; //friendly
	private String c = "Hayvan.c";
	public String  d = "Hayvan.d"; ;
}

 

Hayvan sınıfından türetilen Kedi sınıfını tr.edu.kou.gerekli paketinin içersinde yazarsak

ör-hayvan-2

package tr.edu.kou.gerekli;
import tr.edu.kou.util.*;    
public class Kedi  extends Hayvan {
    
    public Kedi() {
	System.out.println("Kedi olusturuluyor");
	System.out.println(a);
	// System.out.println(b); // ! Hata ! erisemez
	// System.out.println(c); // ! Hata ! erisemez
	System.out.println(d);
    }  

    public static void main(String args[]) {
	Kedi k = new Kedi();
    }
}

Kedi.java dosyasını önce derleyip(compile)

gösterim-12

javac Kedi.java

Sonrada çalıştıralım.

gösterim-13

java tr.edu.kou.gerekli.Kedi

Uygulamanın çıktısı aşağıdaki gibi olur: 

Kedi olusturuluyor
Hayvan.a
Hayvan.d

 

Şekil-9

Encapsulation (Kapsüllenme)

Nesneye yönelik programlamanın (Object oriented programming) en özelliklerinden biri kapsüllenmedir. Kapsüllenme , dışarıdaki başka bir uygulamanın , bizim objemize olan erişimlerini kontrol altında tutma mantığıdır. Bu kavrama göre objemizin içersinde dışaradan başka bir uygulamanın erişibilmesi için arabirimler olması gerekir , ama objemizin hesaplamaları veya problemlere yönelik algoritmaların çalıştırdığı içsel , ileride değişebilecek gizli bir bölümün olması gerektiğidiği belirtir.Böylece ileride değişme riski olan algoritma veya hesaplamalar kullanıcıya yansıtılmaz.

Kapsüllenme , dışarıdaki başka uygulamanın , bizim objemiz ile sadece arabirimler (public) sayesinde iletişim kurması gerektiği , ama arka planda işi yapan esas kısmın gizlenmesini söyler (friendly , protected veya friendly).Olaylara bu açıdan bakarsak objemizi iki kısma bölmeliyiz , arabirimler , objenin dünya ile iletişim kurabilmesi için ve gemiyi yürüten kısım , yani hesaplamaların veya problemlere özgü algoritmaların yer aldığı gizli bölüm. 

ör-kapsüllenme-1 

package tr.edu.kou.util;

public class Makine2 {     
	private int alinan  = 0;
	private int geridondurulen  = 0 ;
	
	public int  get() {
		return geridondurulen ;
	}
	
	public void set(int i ) {
		alinan = i ;
		calis();
	}
	
	private void calis() {
		for (int j = 0 ; j < alinan ; j++ ) {
			System.out.println("Sonuc =  "+j);
		}
		geridondurulen = alinan * 2 ; 	
	}
}

Yukarıdaki örneğimizde , bu Makine2 objemize sadece get() ve set() metodları ile ulaşabiliriz , geriye kalan global obje değişkenlerimize veya calis() metoduna aynı paketden veya başka herhangi bir paket içersinden ulaşım söz konusu değildir.Kapsüllenme kavramının dediği gibi , objemiz iki kısımdan oluşturduk , ara birimler ( get() , set() ) ve gemiyi yürüten kısım ( calis() ) .  

Başka paketin içersinde olan başka bir uygulamanın , tr.edu.kou.util.Makine2 objesinin sadece iki metoduna erişebilir, get() ve set().

ör-kapsüllenme-2

package tr.edu.kou.gerekli;

import tr.edu.kou.util.*;
public class GetSet {
	public static void main(String args[]) {
		Makine2 m2 = new Makine2() ;      
		m2.set(5);
		int deger = m2.get();
		// m2.calis() ; // ! Hata !
		// m2.alinan ;  // ! Hata !
		// m2.geridondurulen ;  // ! Hata !
		System.out.println("Deger =" + deger);		
	}	
}

 

Genel bir bakış

Sınıflar için erişim matrisleri aşağıdaki gibidir : 

 

Aynı Paket

Ayrı Paket

Ayrı paket-türetilmiş

public erişebilir erişebilir erişebilir
protected - - -
friendly erişebilir erişemez erişemez
private - - -

Sınıflar protected veya private olamazlar , bu bağlamda matrisimizi şöyle okuyabiliriz ; örneğin elimizde A sınıfı bulunsun 

  • public A sınıfına aynı paketin içersindeki başka bir sınıf tarafından erişebilir.

  • public A sınıfına ayrı paketin içersindeki başka bir sınıf tarafından erişebilir.

  • public A sınıfına ayrı paket içersinden erişibildiğinden , bu sınıfdan yeni sınıflar türetilebilir.

  • friendly A sınıfına aynı paketin içersindeki başka bir sınıf tarafından erişebilir.

  • friendly A sınıfına ayrı paketin içersindeki başka bir sınıf tarafından erişemez.

  • friendly A sınıfına ayrı paket içersinden erişilemediğinden , bu sınıfdan yeni sınıflar türetilemez.

 

Statik veya statik olmayan metodlar için , erişim matrisi aşağıdaki gibidir.

 

Aynı Paket

Ayrı Paket

Ayrı paket-türetilmiş

public erişebilir erişebilir public
protected erişebilir erişemez erişebilir
friendly erişebilir erişemez erişemez
private erişemez erişemez erişemez

Metodlar (statik veya değil)  public , protected , friendly ,private olabilirler.Örneğin public X sınıfının içersinde f() metodumuz olsun .

  • public f() metodu ,  aynı paket içersinden erişilebilir.

  • protected  f() metodu , hem aynı paket içersinden , hemde X sınıfıdan türetilmiş ayrı paketdeki bir sınıf tarafından erişilebilir.

  • friendly f() metodu , sadece aynı paket içersinden erişelebilir.

  • private f() metoduna , sadece kendi sınıfı içersinden erişilebilir.Başka bir sınıfın bu metoda erişmesi mümkün değildir.

 

Statik veya statik olmayan global değişkenler için , erişim matrisi aşağıdaki gibidir.

 

Aynı Paket

Ayrı Paket

Ayrı paket-türetilmiş

public erişebilir erişebilir erişebilir
protected erişebilir erişemez erişebilir
friendly erişebilir erişemez erişemez
private erişemez erişemez erişemez

 

Global değişkenler (statik veya değil)  public , protected , friendly ,private olabilirler.Örneğin public X sınıfının içersinde "String uzunluk"   adında değişkenimiz olsun .

  • public uzunluk değişkeni ,  aynı paket içersinden erişilebilir.

  • protected uzunluk değişkeni metodu , hem aynı paket içersinden , hemde X sınıfıdan türetilmiş ayrı paketdeki bir sınıf tarafından erişilebilir.

  • friendly uzunluk  değişkeni , sadece aynı paket içersinden erişelebilir.

  • private uzunluk değişkeni , sadece kendi sınıfı içersinden erişilebilir.Başka bir sınıfın bu değişkene erişmesi mümkün değildir.

 

Sorular

  1.   (aklınıza gelen bu konular ile ilgili güzel sorular varsa lütfen bildiriniz)

 

Mail Grubu

Java Kitap Projesinin mail grubuna üye olmak için = java_kitap_projesi-subscribe@yahoogroups.com 

Üyelikten çıkmak için =  java_kitap_projesi-unsubscribe@yahoogroups.com

 

Sorulanız ve Yorumlarınız için : upux@yahoo.com

 

Bu dökümanın her hakkı saklıdır.

1