BÖLÜM 4
|
|
Altuğ
B. Altıntaş
|
Erişim konusu kütüphaneler
için büyük önem taşır. Erişimde iki taraf bulunur; birisi kütüphaneyi kullanan
kişiler (client), diğeri ise bu kütüphaneyi yazanlardır.
Olaylara, hazır kütüphane kullanarak uygulama geliştiren tarafından bakılırsa,
örneğin finans uygulaması yazan bir programcı, işlerin daha da hızlı yürümesi
için daha önceden yazılmış ve denenmiş bir finans kütüphanesini kullanmak
isteyebilir. Finans için özel geliştirilmiş kütüphanenin 1.0 uyarlamasını
kullanan tasarımcı, bunun yeni uyarlamaları
(2.0,
3.0...) çıktığında
da hemen alıp kendi uygulamasına entegre etmek istemesi çok doğaldır. Tahmin
edilebileceği üzere her yeni uyarlama bir öncekine göre daha az hata içerir ve
yeni özellikler sunar. Bu
nedenden dolayı, kütüphane uyarlamaları arasındaki tutarlılık çok
önemlidir. Sonuç olarak, kütüphanenin her yeni uyarlamasında sisteme entegre
edilmesi aşamasında, bu kütüphaneyi kullanan uygulamaları teker teker değiştirmek
yaşamı çekilmez kılabilir! (yorum ekle)
Olaylara, birde kütüphane tasarımcısı açısından bakılırsa... Bir kütüphane yazdınız ve bunun kullanılması için İnternet’e koydunuz. Aradan belirli bir zaman geçti ve sizin yazdığınız kütüphane birçok kişi tarafından kullanılmaya başladı... Fakat, daha sonra, kütüphane içerisinde bazı hatalar olduğunu fark ettiniz; veya, bazı kısımları, daha verimli çalışması için geliştirilmesini istiyorsunuz. Bu arzularınız, ilgili 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?
Böylesi sorunların çözümü
için devreye erişim kavramı girer. Java dili 4 adet erişim belirleyicisi sunar.
Erişim belirleyiciler, en erişilebilirden erişilmeze doğru sıralanırsa, public, protected, friendly ve private’dır. Bunlar sayesinde hem
kütüphane tasarımcıları özgürlüklerine kavuşur hem de kütüphaneyi kullanan
programcılar kullandıkları kütüphanenin yeni bir uyarlamalarını tasarımlarına kolayca
entegre edebilirler. (yorum ekle)
Kütüphane
tasarlayan kişiler, ileride değişebilecek olan sınıfları veya sınıflara ait
yordamları, kullanıcı tarafından erişilmez yaparak hem kütüphanenin rahatça
gelişimini sağlarlar hem de kütüphaneyi kullanan programcıların
endişelerini gidermiş olurlar. (yorum ekle)
Paketler kütüphaneyi
oluşturan elemanlardır. Paket mantığının var olmasında ana nedenlerden birisi
sınıf ismi karmaşasının getirmiş olduğu çözümdür. Örneğin elimizde X ve Y adlı 2 sınıf bulunsun. Bunlar
içerisinde aynı isimli 2 yordam (method) olması, örneğin f() yordamı, herhangi bir
karmaşıklığa neden olmayacaktır. Çünkü aynı isimdeki yordamlar ayrı sınıflarda
bulunurlar. Peki sınıf isimleri? Sistemimizde bulunan aynı isimdeki sınıflar
karmaşıklığa sebep vermez; eğer ki, aynı isimdeki sınıflar değişik
paketlerin içerisinde bulunurlarsa... (yorum ekle)
Gösterim-4.1:
import java.io.BufferedReader; |
Yukarıdaki
gösterimde BufferedReader sınıf
isminin java.io paketinde tek olduğunu
anlıyoruz (java.io Java ile gelen standart bir
pakettir). Fakat, başka paketlerin içerisinde BufferedReader sınıf ismi rahatlıkla kullanılabilir. Yukarıdaki
gösterim java.io paketinin içerisinde
bulunan BufferedReader sınıfını
kullanacağını ifade etmektedir. Paketin içerisindeki tek bir sınıfı kullanmak
yerine ilgili paketin içerisindeki tüm sınıfları tek seferde kullanmak için: (yorum ekle)
Gösterim-4.2:
import java.io.* ; |
java.io paketi içerisindeki sınıfların uygulamalarda kullanılması için import java.io.* denilmesi yeterli olacaktır. Anlatılanlar uygulama içerisinde incelenirse, (yorum ekle)
Örnek-4.1:
PaketKullanim.java (yorum ekle)
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); }} |
PaketKullanim.java uygulamasında görmediğimiz yeni kavram mevcuttur, "throws Exception". Bu kavram istisnalar (Exception- 8. bölüm) konusunda detaylı bir şekilde incelenecektir. (yorum ekle)
Öncelikle belirtmek gerekirse, .java uzantılı fiziksel dosya derlendiği zaman buna tam karşılık .class fiziksel dosyası elde edilir. (*.java dosyasında hata olmadığı varsayılırsa). Fiziksel .java dosyasında birden fazla sınıf tanımlanmış ise, tanımlanan her sınıf için ayrı ayrı fiziksel .class dosyaları üretilir. (yorum ekle)
Örnek-4.2: Test1.java (yorum ekle)
public class Test1 { public void kos() { }}class Test2 { public void kos() { }} |
Yukarıda verilen örnek, Test1.java adıyla herhangi dizine kayıt
edilebilir (fiziksel
java uzantılı dosya ile public sınıfın ismi birebir
aynı olmalıdır).
Bu dosya javac komutu ile derlendiğinde
adları Test1.class ve Test2.class olan 2 adet fiziksel .class dosyası elde edilir. Test1.java dosyanın en üstüne herhangi
bir paket ibaresi yerleştirilmediğinden dolayı Java bu sınıfları varsayılan paket (default package) olarak algılayacaktır. (yorum ekle)
Örnek-4.3: Test3.java
(yorum ekle)
public class Test3 { public void kos() { }} |
Kendi paketlerimizi
oluşturmanın temel amaçlarından birisi, aynı amaca yönelik iş yapan sınıfları
bir çatı altında toplamaktır; böylece yazılan sınıflar daha derli toplu
olurlar. Ayrıca aranılan sınıflar daha kolay bulunabilir. Peki eğer kendimiz
paket oluşturmak istersek, bunu nasıl başaracağız? (yorum ekle)
Örnek-4.4: Test1.java (yorum ekle)
package tr.edu.kou.util ;public class Test1 { public Test1() { System.out.println("tr.edu.kou.util.Test1 nesnesi" + "olusturuluyor"); } public static void main(String args[]) { Test1 pb = new Test1(); }} |
Bu örneğimizde, Test1.java dosyası işletim sisteminin
herhangi bir dizinine yerleştirilemez; çünkü, o artık tr.edu.kou.util paketine ait bir sınıftır. Bundan dolayı Test1.java dosyası işletim sisteminin bu
paket ismiyle paralel olan bir dizin yapısına kayıt edilmesi gerekir. Önemli
diğer bir unsur ise sınıfın ismidir; Test1.java dosyası
içerisinde belirtilen Test1 sınıfının
ismi artık tr.kou.edu.util.Test1’dir.
(yorum ekle)

Şekil-4.2. tr.edu.kou.util.Test1 sınıfı
Paket isimleri için kullanılan yapı İnternet alan isim sistemiyle (Internet DNS) aynıdır. Örneğin, Kocaeli Üniversitesinde matematik paketi geliştiren tasarımcı, bu paketin içerisindeki sınıfların, başka kütüphane paketleri içerisindeki sınıf isimleriyle çakışmaması için İnternet alan adı sistemini kullanmalıdır. İnternet alan adı sistemi, www.kou.edu.tr adresinin dünya üzerinde tek olacağını garantiler. Aynı mantık, paket isimlerine de uygulanarak, paket içerisindeki sınıf isimleri çakışma sorununa çözüm bulunmuş olunuyor. Dikkat edilirse, paket isimleri İnternet alan adlarının tersten yazılmış halleridir. (yorum ekle)
İşletim sistemleri 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, Windows için tr\edu\kou\math şekilde olmalıdır. (yorum ekle)

Şekil-4.3. tr.edu.kou.math.DortIslem sınıfı
Java
yorumlayıcısı (interpreter) işletim sistemi
çevre değişkenlerinden CLASSPATH’e
bakarak import
ifadesindeki paketi bulmaya çalışır... (yorum ekle)
Gösterim-4.3:
import tr.edu.kou.math.*; |
Diyelim ki; math paketi
aşağıdaki dizinde bulunsun:
Gösterim-4.4:
C:\kodlar\bolum4\tr\edu\kou\math\ |
Yorumlayıcının import ifadesindeki paketi bulması için aşağıdaki
tanımın CLASSATH’e eklenmesi gerekir. (yorum ekle)
Gösterim-4.5:
CLASSPATH="C:\kodlar\bolum4\;." |
CLASSPATH’e eklenen bu tanım sayesinde yorumlayıcı C:\kodlar\bolum4\ dizinine kadar
gidip tr\edu\kou\math dizinini
arayacaktır; bulunursa, bu dizinin altındaki tüm sınıflar uygulama tarafından
kullanılabilecek hale gelecektir. (yorum ekle)

Şekil-4.4. CLASSPATH ayarları
DortIslem.java dosyasını C:\kodlar\bolum4\tr\edu\kou\math dizinine yerleştirelim:
Örnek-4.5: DortIslem.java
(yorum ekle)
package tr.edu.kou.math ;public class DortIslem { public static double topla(double a, double b) { return (a + b) ; } public static double cikart(double a, double b) { return (a - b) ; } public static double carp(double a, double b) { return (a * b) ; } public static double bol(double a, double b) { if ( (a != 0) && (b != 0) ) { return (a / b); } else { return 0; } } } |
Gerekli CLASSPATH tanımları yapıldıktan sonra bu paketi
kullanacak olan uygulama herhangi bir dizinine yerleştirebilir. (yorum ekle)
Örnek-4.6: Hesaplama.java (yorum ekle)
import tr.edu.kou.math.*; //dikkat! public class Hesaplama { public static void main(String args[]) { double sonuc = DortIslem.topla(9.6 , 8.7); System.out.println("9.6 + 8.7 = " + sonuc ); Sonuc = DortIslem.cikart(9.6 , 8.7); System.out.println("9.6 - 8.7 = " + sonuc ); Sonuc = DortIslem.carp(5.6 , 8.7); System.out.println("9.6 * 8.7 = " + sonuc ); Sonuc = DortIslem.bol(5.6 , 8.7); System.out.println("9.6 / 8.7 = " + sonuc ); }} |
Uygulamanın sonucu aşağıdaki gibi olur:
9.6 + 8.7 = 18.2999999999999979.6 - 8.7 = 0.90000000000000049.6 * 8.7 = 48.719999999999999.6 / 8.7 = 0.6436781609195402
Dikkat edilirse CLASSPATH değişkenine değer atanırken
en sona "." nokta koyuldu.

Şekil-4.5. Noktanın Önemi
Bu önemli bir ayrıntıdır. Bu noktanın konmasındaki neden varsayılan paketlerin içindeki sınıfların birbirlerini görebilmesini sağlamaktır; unutulursa, anlamsız hata mesajlarıyla karşılaşılabilir. (yorum ekle)
Java’yı sisteme ilk yüklendiği zaman, basit örneklerin, CLASSPATH değişkenine herhangi bir tanım eklemeden bile çalıştırabildiği görülür; nedeni, Java’nın, temel kütüphanelerinin bilinmesindendir. (yorum ekle)
Ayrı paket içerisinde aynı
isimdeki sınıflar uygulamada kullanılırsa ne olur? Adları aynı olsa
bile değişik paketlerde bulundukları için bir sorun yaşanmaması
gerekecektir. Öncelikle tr.edu.kou.util
paketinin içerisine kendi ArrayList
sınıfımızı oluşturalım: (yorum ekle)
Örnek-4.7: ArrayList.java (yorum ekle)
package tr.edu.kou.util;public class ArrayList { public ArrayList() { System.out.println("tr.edu.kou.util.ArrayList nesnesi" + " olusturuluyor"); }} |
Aşağıdaki örneği işletim sisteminin herhangi bir
dizinine kayıt edebiliriz.
Örnek-4.8:
Cakisma.java (yorum ekle)
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ı javac komutu ile derlendiğinde şu hata mesajıyla
karşılaşılır:
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 matchArrayList 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 matchArrayList al = new ArrayList();^2 errors |
Bu hata mesajı, ArrayList’in
hem java.util paketinde hem de tr.edu.kou.util paketinde bulunmasından
kaynaklanan bir ikilemi göstermektedir. Cakisma
sınıfının içerisinde ArrayList sınıfı
kullanılmıştır; ancak, hangi paketin içerisindeki ArrayList sınıfı? Bu sorunu çözmek için aşağıdaki örneği
inceleyelim:
Örnek-4.9: Cakisma2.java (yorum ekle)
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 böyle bir ikilem varsa, gerçekten hangi
sınıfı kullanmak istiyorsanız, o sınıfın içinde bulunduğu paket ismini de
açık bir biçimde yazarak oluşan bu ikilemi ortadan kaldırabilirsiniz. (yorum ekle)
Paket içerisindeki tek başına çalışabilen
uygulamaları (standalone) herhangi bir dizin içerisinden çalışmak için komut satırına,
ilgili “paket ismi+sınıf ismi” girilmesi yeterlidir. Hesaplama.java’nın yeni uyarlamasını C:\kodlar\bolum4\tr\edu\kou\math dizinine kaydedelim. (yorum ekle)
Örnek-4.10: Hesaplama.java (yorum ekle)
package tr.edu.kou.math ; // dikkat! public class Hesaplama { public static void main(String args[]) { double sonuc = DortIslem.topla(9.6 , 8.7); System.out.println("9.6 + 8.7 = " + sonuc ); sonuc = DortIslem.cikart(9.6 , 8.7); System.out.println("9.6 - 8.7 = " + sonuc ); sonuc = DortIslem.carp(5.6 , 8.7); System.out.println("9.6 * 8.7 = " + sonuc ); sonuc = DortIslem.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 bir üyesidir. Hesaplama sınıfımızı java komutu
kullanarak çalıştırmayı deneyelim. C:\kodlar\bolum4
dizininin CLASSPATH değişkeninde tanımlı
olduğunu varsayıyorum. (yorum ekle)
Gösterim-4.6:
java Hesaplama |
Bir aksilik var! Ekrana yazılan 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:123) 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 orada… 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 herhangi bir
dizinden (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. (yorum ekle)
Gösterim-4.7:
java tr.edu.kou.math.Hesaplama |
Uygulamanın çıktısı aşağıdaki gibidir.
9.6 + 8.7 = 18.2999999999999979.6 - 8.7 = 0.90000000000000049.6 * 8.7 = 48.719999999999999.6 / 8.7 = 0.6436781609195402
JAR dosya formatı dosyaların
arşivlenmesine ve sıkıştırılmasına olanak tanır. Olağan durumunda JAR dosyaları
içerisinde sınıf dosyaları (*.class) bulunur; bazen, özellikle Appletler de, yardımcı dosyalar da (gif, jpeg...) JAR dosyası içerisine konulabilir. (yorum ekle)
JAR dosyasının sağladığı
yararlar şöyledir:
· Güvenlik: Dijital olarak JAR dosyasının içeriğini imzalayabilirsiniz. Böylece
sizin imzanızı tanıyan kişiler JAR dosyasının içeriğini rahatlıkla
kullanabilirler. (yorum ekle)
· Sıkıştırma: Bir çok dosyayı güvenli bir şekilde arşivleyip sıkıştırılabilir. (yorum ekle)
· İndirme (download) zamanını
azaltması:
Arşivlenmiş ve sıkıştırılmış dosyalar internet üzerinde daha çabuk
indirilebilir. (yorum ekle)
· Paket mühürleme (versiyon
1.2):
Versiyon uyumluluğunu sağlamak amacı ile JAR dosyasının içerisindeki paketler
mühürlenebilir. JAR dosyasının içerisinde paket mühürlemekten kasıt edilen
paket içerisinde bulunan sınıfların aynı JAR dosyasında bulunmasıdır. (yorum ekle)
· Paket uyarlama (versiyon
1.2): JAR
dosyaları, içindeki dosyalar hakkında bilgiler saklayabilirler, örneğin üretici
firmaya ait bilgiler, versiyon bilgileri gibi. (yorum ekle)
·
Taşınabilirlik: Java Platformunun standart
bir üyesi olan JAR dosyaları kolaylıkla taşınabilir. (yorum ekle)
Oluşturulan paketler JAR
dosyası içerisine yerleştirilerek daha derli toplu bir görüntü elde etmiş
olunur; tr.edu.kou.math ve tr.edu.kou.util paketlerini tek bir JAR
dosyasında birleştirmek için Gösterim-4.8’de verilen komutun kullanılması yeterli
olur; ancak, JAR dosyası oluşturmak için
komutun hangi dizinde yürütüldüğü önemlidir. Tablo-4.1’de JAR dosyası işlemleri
için gerekli olan bazı komutlar verilmiştir: (yorum ekle)
Tablo-4.1. JAR
dosyaları (yorum ekle)
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çeriği bakmak için |
jar -tf jar-dosya-ismi |
JAR dosyasının içeriği 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ş
uygulamayı çalıştırmak için |
java -classpath jar-dosya-ismi MainClass |
Gösterim-4.8:
jar -cf kou.jar tr/ |