Önsöz Kitap Hakkında Bu kitap Java'ya yeni başlayanlar veya az bilenler için yazılmıştır. Java'da şu veya bu şekilde kod yazabilen, fakat dilin temel yapısını henüz tam olarak anlamadığını düşünenler için de faydalı olabilir. Tek tek class'ları veya kütüphaneleri referans kitabı mantığında anlatmak yerine, okuyucunun dilin temel esprisini yakalaması sağlanmaya çalışılmıştır. Elbette gerektiğinde önemli class'lar ve kütüphaneler hakkında da bilgi vermektedir. Zaten bunlar dili tam olarak kavramak için de bilinmesi gereken asgari düzeydeki konulardır. Bir bölümde Nesneye Yönelik Programlama (Object-Oriented Programming) anlatılıyor. Ancak kitabın geneli OOP'u daha iyi anlamanıza katkıda bulunmayı amaçlamaktadır. Nesnelerle çalışmanın gereğini tam olarak kavramamış bir geliştirici Java'yı diğer bazı dillere bezner biçimde kullanarak bir çok zenginlikten mahrum kalabilir. Bu kitaptan Inheritance, Abstraction, Encapsulation, Interface, Polymorphism gibi bir çok kelimenin (daha doğrusu kavramın) ne anlama geldiğini öğrenebilirsiniz. Bu kavramları tümüyle kavramak elbette zamanla ve deneyimle olacaktır. Biz burada sadece doğru yönde ilerlemeniz için bir yardımda bulunmuş oluyoruz. Gerisi okuyucuya kalmıştır. Nesneye Yönelik Programlama bir 'bilgi' olmaktan çok 'beceri'dir. Ancak 'zamanla' kazanılması mükündür. Vaktinden önce ne kadar iyi bilirseniz bilin doğru bir biçimde uygulayamazsınız. Hatta bilinçiz nesneye yönelik tasarım, nesnesiz program yazma tekniğinden daha kötü sonuçlar doğurabilir. Bu kitap bu bakımdan çeşitli tuzaklara düşememeniz için gerekli uyarıları sırası geldikçe yapmaktadır. Kitabın ilerleyen bölümlerinde mutlaka öğrenilmesi gereken bazı kütüphaneler (API'lar)anlatılmaktadır. Bu kütüphaneleredeki bütün class'lar ayrıntılı olarak incelenmemektedir elbette. Zaten bu konuların her biri ayrı bir kitap konusudur. Bu kitapta belli kütüphanelerin temel yapısı anlatılmaktadır. Gerisini okuyucu kendisi ilerletebilir. Ezberciliğin her konuda kötü bir şey olduğunu herkes bilir ya; Java'da ezbercilik imkansızdır. Bu kitabın yazarı dahil hiç kimse bütün class'ların bütün property ve method'larını ezberleyemez. Java çok zengin bir kütüphaneye sahiptir. Bu kitabın yazarı en fazla kullandığı nesneler için bile sürekli documantasyon/referansa (Javadoc'a) bakmaktadır. Bir çok deneyimli programcının da böyle yaptığı zaten biliniyor. Önemli olan kaybolmadan arama yapabilecek kadar bilgi sahibi olmaktır. İşte bu kitap da bunu sağlamaya çalışmaktadır. Java'nın Özellikleri Java Basittir. Java, kendisine yakın güçteki dillerin en basitidir. Örneğin, Java model olarak aldığı C++'tan çok daha kolaydır. C++'ın çok güçlü bir dil olduğu tartışılmaz. Ama C++ ve C# çoğu bir dilde bulunması çok da şart olmayan karmaşık bir çok özellik içermektededir. Bütün bu özelliklerin öğrenilmesi çok zaman alır. Oysa Java gereksiz çok fazla özellik içermez. Ve Java'da bir özelliğin öğrenilmesi ve kullanılması çok kolaydır. Başka dillerde çok zor yazılan işlemler Java'da çok basit ifadelerle gerçekleştirilebilmektedir. Java'nin basitliği yanlış anlaşılmamalıdır. VisualBasic/ASP, Delphi/Pascal, Perl, PHP gibi dillerden ve ortamlardan daha basit değildir. Bu sayılan diller çok kolay öğrenilebilen, kısa zamanda yeterli düzeye ulaşılabilen dillerdir. Ancak bu dillerde yapılabileceklerin belli bir sınırı vardır. Bu dillerde büyük çaplı ve karmaşık işler yapamazsınız veya yapmanız durumda çok zorluk çekersiniz. Oysa Java programlamanın her dalında iddia sahibidir. Her geçen gün Java yeni bir alanda söz sahibi olmaktadır. Bu bağlamda 'basit' demek, 'çok gelişmiş işlemlerin basit bir şekilde yapılabilmesini sağlayan' demektir. Yoksa 'programcı bunu anlamaz' diye düşünülmesinden ötürü hiç bir özellik dışarda bırakılmamıştır. Java Nesneye Yöneliktir. Java tamamen (bazı kişilere göre %99) nesneye yönelik'tir. Diğer bazı diller gibi nesneye yöneliklik sonradan dile eklenmemiştir, başından beri Java'da bulunmaktadır. Bir Java programında olabilecek her şey ya nesnedir ya da bir nesnenin parçasıdır. Java nesneye yönelik programlamayı sadece mümkün değil aynı zamanda kolay kılmıştır. Java'da bir nesnenin yapılması, kullanılması, geliştirilmesi, başka bir yere aktarılaması çok kolaydır. Java Dağıtıktır. Java 'dağıtık' bir dildir. 'Dağıtık' birden fazla bilgisayarda çalışan programların bir biriyle uyumlu çalışabilmesidir. Bir yazılım parçasının bir kısmının bir makinede diğerinin başka makinede aynı anda çalışması mümkündür. Bu yüzden Internet'in dilinin Java olduğu söylenmektedir. Günümüzde tek bir makine üzerinde çalışan, başka hiç bir yerle bağlantısı olmayan uygulama kalmamış gibidir. Bir çok işletme Interenet üzerinden iş yapmaktadır. Bir çok işletmede birden fazla makine birbirine bağlı olarak çalışmaktadır. Bu yüzden Java dağıtık programlama için en uygun çözümlerden biridir. Java Sağlamdır. Java sağlam bir dildir. Programlamadaki hataların çoğu daha yazılma aşamasında anlaşılabilmektedir. Yazılma aşamasında anlaşılmayanlar, programın çalışması esnasında yakalanabilmektedir. Bir 'exception'la, programda hatanın ne olduğu, nerede olduğu ve hangi işlemi yaparken olduğu bile belirtilebilmektedir. Başka dillerin aksine çalışma esnasında bir Java programı "Bir hata oldu!" deyip çökmez. Bir çok durumda hataya rağmen program çökmeden çalışmaya devam eder. Hata olması durumunda da programı çalıştıranlar hatayı ayrıntılarıyla öğrenme olanağına sahip olur. Java Güvenlidir. Java güvenli bir dildir. Java diliyle virüs yapılamaz. Hiç bir virüs bir Java programına bulaşamaz. Bir Java programının yaptığı her hareket takip edilir. Kötü niyetli bir program, bir işlemi eğer izin verilmediyse yapamaz. Bu özellik, Internet gibi herkesin başkasının makinesine erişebildiği bir ortmada çok önemlidir. Java'yı güvenlik gereksinimi yüksek bir çok firma bu yüzden tercih etmektedir. Mimarilere Yansızdır. Sıradan kullanıcıların bildiğinin aksine dünya üzerinde bir çok işletim sistemi vardır. Hatta kullanıcın çoğunun iyi bildiği Windows işletim sistemi bazı bilgisaya alanlarında hiç kullanılmaz. UNIX/Linux, Apple Mac, IBM'in çeşitli işletim sitemleri dünya işletim sistemi pazarında büyük yer tutmaktadır. Bir çok masaüstü kullanıcısının tek bildiği işletim sisteminin, bazı sektörlerde adı dahi geçmemektedir. Java'da yazılan bir program hemen hemen bütün işletim sistemlerinde hiç değiştirmeye gerek duymaksızın çalışır. Diğer dillerde bu özellik yoktur. Hatta Windows'un bir versiyonunda çalışan program diğer bir versiyonda çalışmayabilmekte, bazen makinenin çökmesi gibi büyük sonuçlar bile doğurabilmektedir. Windows'u üreten Microsoft firmasının yazdığı programlar bile kendilerinin işletim sistemlerinin bazılarında çalışmamaktadır. Kendilerinin yazdığı belgelerde hangi işletim sistemlerinin hangi versiyonlarında hangi programlarının çalışmadığını belirtilmektedir. Bu durum bütün işletim sistemi ve bütün programlar için geçerlidir. Ürettiği yazılımların her platformda çalışmasını isteyen firmalar giderek daha çok Java'ya yönelmektedir. Java Taşınabilirdir. Java programları her ortamda aynı veya benzer bir şekilde çalışır. Her ortam/makine için ayrı bir program yazmaya gerek kalmaz. Programcı programın çalışacağı makinenin durumunu göz önüne almak zorunda kalmaz. Bir programın görüntüsü çalıştığı hey yerde hemen hemen aynıdır. C programları da hemen hemen her işletim sisteminde yeniden derlenmek suretiyle çalışabilir. Ama programcı bunun için hazırlık yapmalıdır. Bir işletim siteminde tamsayı -2^15 ile 2^15 arasında değer alırken diğerinde -2^31 ile +2^31 arasında alabilir. Ama Java bu farkları programcıya şeffaf kılar. Programcı her işletim sistemi ve her sürüm için ayrı bir program yazmak zorunda kalmaz. Java Yorumlanır. Java 'yorumlamalı' bir dildir. Yani bir Java programının komutları, çalışırken makinenin anlayacağı formata çevrilir. Java'da bu Java Virtual Machine (JVM) tarafından yapılır. Bunun avantajı bir programın kullanıdığı standart kütüphanelerin programla birlikte taşınması zorunluluğunu ortadan kaldırmasındır. Bir yorumlayıcı herhangi bir ortamda varsa, bir dildeki standart her özellik o ortamda var demektir. Programla birlikte bu kütüphanelerin de taşınması gerekmez. Bu da bir Java programının bir makineden başka makineye indirilmesini çok hızlandırır. Çünkü sadece programcının yazdığı nesneler yolculuk yapar. Applet'lerin çalışma prensibi budur. Ana makinede bulunan applet, tarayıcı tarafından kullanıcının makinesine alınır ve çalıştırılır. Java ortamı, yani JVM tarayıcının içinde mevcutur. Java Yüksek Başarımlıdır. Diğer dillerde olmayan bir çok özelliğe sahip olmasına rağmen, Java'da bunun için fazla bir performans kaybı yoktur. Java'nın ilk versiyonlarında çalışan programlar diğer dillerde yazılan eşdeğerlerine göre elbette yavaştır. Ancak Java'nın gelişmesiyle birlikte Java bu farkı, üstün özelliklerinde vazgeçmek zorunda kalmaksızın kapatmaktadır. En son Java sürümüyle birlikte JIT (Just-In Time-Tam Zamanında Derleme) teknolojisi devreye girmiş bulunlaktadır. Bununla birlikte Java programları, diğer dillerde en iyi yazılmış programların hızını hemen hemen yakalayabilmektedir. Java yapılması 'imkansız' gibi görüneni çok da fazla performans kaybına yol açmadan yapar. Java'nın yavaşlığı en fazla eleştiri alan özelliklerden biridir. Bir programın hızlı çalışması, makinelerin hafıza veya işlemcisini terfi ettirerek çözülebilir. İşlemcinin ve hafızanın çok ucuzladığı günlerde, bu, bir işletme için pek fazla maddi bir yük değildir. Bir programcının sağlam, güvenli ve Java'nı sahip olduğu üstün özelliklere sahip program üretmesi daha fazla masraflıdır. Bir işletmenin, durup dururken bir programın makineyi çökertmesinden dolayı katlanacağı külfet az değildir. Programı yapanların bile hatayı anlamak için saatlerce bazen günlerce uğraşması işletmeye yine maliyet olarak yansıyacaktır. Bu kadar eleştiri almasına rağmen Java'nın giderek daha fazla yaygınlaşmasının elbette nedenleri vardır. Java'nın yavaşlığından sadece Java'yı bilmeyenler ve kullanmayanlar şikayet etmektedir. Ancak Java 'hızla' yayılmaktadır. Java Çok Kanallıdır. Java dili başından 'çok kanallıdır' (multi-threaded'dir). Çok kanallılık, bir programın aynı anda birden fazla işlemi yürütebilmesi demektir. Bir program herhangi bir şeyi beklerken arada başka bir işlemi gerçekleştirebilir. Beklenen olay gerçekleşince ilk işlem kaldığı yerden aynen devam ettirilir. Üstelik bunun için programcının fazla bir şey yapması da gerekmemektedir. Çok kanallılık bir çok dilde hiç yoktur. C++ gibi dillerde de dilin özelliği değil, ona sonradan eklenmiş kütüphanelerle kullanılabilmektedir. Ama Java'nın kendisi doğuştan çok kanallıdır. Bu yüzden çok kanallı program yapmak için en kolay dil Java'dır. Java Dinamiktir. Java'da bir programla kullandığı birimlerin (kütüphaneler,modüller veya sınıfların) birbirine bağlanması çalıştırma anında yapılır. Buna 'sonradan bağlama' (late binding) denir. Kullanılan birimlerin iç yapısı değiştirildiğinde, bu birimleri kullanan programın değişmesi gerekmez. Yeter ki birimlerin dışarıdan çağırma şekilleri değişmesin. Oysa C++ gibi dillerde herhangi bir değişiklikte (bu bir modülün iç yapısında çağıranları ilgilendirmeyen çok ufak bir değişiklik bile olsa) herşeyin yeniden işleme tabi tutulması gerekir. Buna da 'erken bağlama' (early binding) denir. Java'da late-binding bu özellik olmasaydı, Java kütüphanlerindeki her hata düzeltme ve değişiklikte dünyadaki bütün programları yeniden işleme tabi tutmamız gerekirdi ki bu mümkün değildir. Sonuç Java iyi bir programlama dilidir. Giderek yaygınlaşması, diğer dillerin giderek Java'ya benzemeye başlaması ve taklitlerinin çıkması da bunu göstermektedir. Java'yı tercih etmeyenler elbette olmuştur ve olacaktır. Ama buzdolabının bile Java bildiği bu dönemde bu dili hiç bilmemek, tümüyle yok saymak bilgisayar alanında var olmak isteyen insanlar için büyük bir eksiklik olacaktır. Java Platform'u Java Platform'u Java sadece bir programlama dili değildir. Aynı zamanda bir yazılım platformudur. Java Platform'u işletim sistemi üzerinde çalışan, uygulamalara çok çeşitli servisler veren, bunu her işletim sistemi için standart bir biçimde başarabilen bir platformdur. Java Programlama Dili ise bu platform üzerinde yazılım geliştirmek için kullanılan programlama dilidir. O yüzden Java'yı öğrenmek sadece Java dilini öğrenmek demek değildir. Java platformu üzerinde çalışan farklı bir dil de üretilebilir. Ancak Java dilinin iyi bir programlama dili olması nedeniyle böyle bir ihtiyaç doğmamışır. Java platformunun yapısı, daha önce benzer bir platform olmaması nedeniyle, özellikle başka dillerle çalışmış insanlara karmaşık gelebilir. Ancak Java, diğer dillerdeki, özellikle de C/C++ dilindeki "çözümsüz" veya "çözümü zor" konulara pratik çözümler üretmiştir. O yüzden başka dillerle profesyonel programlama yapmış olan insanlar sık karşılaştıkları bir çok sorunun Java'da çok kolay çözülmüş olduğunu görebilmektedirler. Bu bölümde bir Java programının çalışma biçimini, öncellikle diğer dillerde yazılmış programların çalışma biçimlerini gözden geçirerek inceleyeceğiz. Derleme (Compilation) ve Yorumlama (Interpretation) Programalama dili, insanla makine (bilgisayar) arasında iletişim kurmak için kullanılan dildir. Başka bir deyişle programcı bilgisayara, özellikle de işlemciye istediklerini yaptırmak için bir dil kullanır. Bu dil konuşma diline yakın bir dil olmalıdır ki insanlar rahatça kullanabilsin. Bilgisayar işlemcisinin dili ise sadece sayılardan oluşur. Bilgisayarlar sayısal (dijital) aygıtlardır. İşlemciler sadece belli sayılarla ifade edilen makine kodlarından anlar. Bu kodlardan oluşan dile 'makine dili' denir, üretilen koda da 'makine kodu' (machine code) denir. Bilgisayarın ilk dönemlerinde insanlar programlarını sayı kodları kullanarak yazıyorlardı. Bu kodlar her işlemci türü için değişik olduğundan, yazılan programlar sadece belli bir işlemci ile çalışabiliyordu. Hatta bir işlemci sürümü için yazılan kod bir önceki sürümde çalışmayabiliyordu. Bu yüzden 'programlama dili' kavramı ortaya çıkmıştır. Bu yapıda, programcı bilgisayarın yapması gerekenleri ona, konuşma diline yakın bir dille söyler. Bu dilde yazılanlar makine diline çevrilir. Böylece programcılar, hem işlemciminin kendine komut kümesini öğrenmek zorunda kalmazlar; hem de yazdıkları programlar birden fazla işlemciyle çalışabilir. Programalama diliyle düz metin şekinde olan programa 'kaynak kodu' (source code) denir. Makine dilinde olan koda da "ikili kod" (binary code) denir. Programlama dilinden makine diline çevirme işi iki şekilde yapılabilir. Biri 'anında', ikincisi 'önceden'. Anında çevirmek, programa dilindeki ifadeleri bir yandan okuyup bir yandan makine diline çevirmek demektir. Buna 'yorumlama' (interpretation) denir. Önceden çevirme ise, programlama dilindeki ifadelerin çalıştırılmadan önce makine diline çevrilmesi, sonra da çalıştırılması anlamına gelir. Buna da 'derleme' (compilation) denir. Derleme'nin faydası daha hızlı olmasıdır. Çünkü makine diline çevirme sadece ve sadece bir kere yapılmaktadır. Yorumlama da ise her çalıştırmada çevirme işlemi yapıldığından daha yavaştır. Derlemenin zararı da, programdaki her değişiklikte önce derlemeyi sonra çalıştırmayı gerekli kılmasıdır. Sık değişiklik yapılan durumlarda bu, programcı için ciddi bir sorundur. Oysa yorumlama anında olduğu için, değişiklik de anında etkili olmaktadır. Perl, Basic gibi diller yorumlamalı, C ve Pascal gibi diller de derlemeli dildir. JVM - Java Virtual Machine (Java Sanal Makinesi) Java'daki durum biraz daha karışıktır. Java hem 'derlemeli' bir dildir, hem de 'yorumlamalı'. Java programlama diliyle yazılmış kaynak kodu, sanal bir işlemcinin anlayabileceği makine koduna çevrilir. Bu kod gerçek bir makine olmadığından ona makine kodu denmez. Ama programala dili gibi konuşma dilinde de olmadığından kaynak kodu da değildir. Bu ara dille yazılmış koda 'bayt kod' (bytecode) denir. Çünkü makine kodu gibi baytlardan oluşur. Yani kaynak kodu bayt koduna 'derlenir'. Sanal işlemci bu bayt kodlarının makine koduna programın çalışması esnasında çevirir. Her işletim sistemi ve işlemci için ayrı bir sanal makine vardır. Java kaynak kodları Java derleyicisi tarafından bayt koda çevrilir. Üretilen bu kod bütün işlemciler için aynıdır. Her işletim sistemi ve işlemciye göre sanal makine, bu bayt kodu ilgili işlemcinin makine diline anında çevirir yani yorumlar. Bu sanal makineye Java Sanal Makinesi - Java Virtual Machine (JVM) denir. Şimdi teorik olarak anlattığımız sürecin, uygulamadaki bileşenlerini inceleyelim. Java platformunun programlama dili 'Java' dır. Bu dilde yazılmış kaynak kodları '.java' uzantılı dosyalarda saklanır. "javac" adlı bir derleyici ile ikili koda çevrilir. İkili kod'lar '.class' uzantılı dosyalarda saklanır. Bu dosyalar 'java.exe' adlı yorumlayıcı tarafından çalıştırılır. Java kaynak kodu herhangi bir metin düzenleyici ile yazılabilir. Java'nın derleyicisi ücretsiz olarak dağıtılmaktadır. Java'nın yorumlayıcısı (JVM)'de plug-in olarak yüklenebilmektedir. Bu plug-in de ücretsizdir. Ayrıca bilinen bütün tarayıcılar'ın bir JVM'i bulunmaktadır. Bir JVM içerinde çalışan Java application'u C ile yazılmış native kodu çağırabilir. Bu durumda performans'tan kazanılmakla birlikte platform bağımsızlığı kaybedilmiş olur. O yüzden bu, sadece çok hız gerektiren az sayıda işlem için kullanılabilir. Java'nın hızı giderek arttığından buna zamanla daha az ihtiyaç duyulmaktadır. Bir .exe programı da Java programlarının içerisinden çalıştırılabilir. Ancak bu durumda çalışan proses tamamen JVM'in dışında, aşağıdaki işletim sisteminin kontrolünde bulunur. Application'la veri alışverişi bulunmayan programları dışarıdan çağırmak için kullanılabilir. Java'nın Kullanım Alanları Applet'ler Bir web sayfası içerisinde çalışabilen görsel Java bileşenlerine 'applet' denir. Bir web sitesinden client'a .html veya .gif dosyası gibi indirilir ve browser tarafından çalıştırılır. Client'ta çalışması nedeniyle kullanıcıyla çabuk etkileşim kurabilmektedir. Server'da çalışan CGI ve benzeri programlar her işlemde server'a gidilmesini gerekli kılmaktadır. Bu da bandwith'i sınırlı client'lar için ciddi bir sorun olmaktadır. Özellikle game ve chat gibi uygulamaları da applet hemen hemen tek mantıklı seçenek olarak durmaktadır. Servlet'ler Server makinelerinde bir application server içerisinde çalıştırılabilen program modüllerine 'servlet' denir. Bunlar bağımsız application değildirler ve yüklenmeleri, çalıştırılmaları ve gerektiğinde devreden çıkartılmaları bir application server tarafından yapılır. Bir URL olarak çağrıldıklarında, varsa kullanıcıdan gelen parametreleri alıp çalışırlar ve çıktı olarak da HTML üretirler. Bir dosyada 'statik' olarak bulunan HTML'in client'a aktarılması yerine HTML'in 'dinamik' olarak (real time'da) üretilip output'a basılması söz konusudur. Application'lar Java'nın önce Applet'lerle sonra da Servlet'lerle gündeme gelmesi, onun sanki normal bir programlama dili olarak kullanılamayacağı gibi bir izlenim yaratmamalıdır. Java'nın internet'e en uygun dil olması, internet dışındaki uygulamalarda kullanılamayacağı anlamına gelmez. Bir ortamda Java platform'u yüklüyse her tür işlem için Java application'u çalıştırılabilir. Ancak, herhangi bir makinede bir Java programı çalıştırılabilmesi için JRE (Java Runtime Engine - Java Çalışma-Zamanı Motoru) bulunmalıdır. Bir çok işletim sistemi Java'yla birlikte gelmekte veya kurulurken Java'yı tercihe bağlı olarak yüklemektedir. JRE yaklaşık 10 MB yer kapladığından ve çok çabuk kurulduğundan CD ile dağıtılan programlarla birlikte de verilebilmektedir. Micro Edition Java'nın kullanım alanlarında biri de el cihazlar veya çeşitli makinelerdir. Bunlarda Java'nın micro edition'u çalışır. Standart Java'dan farklı olan bu edition, bazı ek class'lar içerdiği gibi bazı standart kütüphaneleri de içermez. Dilde de bazı farklar vardır. Örneğin kesirli sayılar micro edition'da yoktur. Bunların dışında Java'nın temel çalışma biçimi aynıdır. Bir server veya başka bir kaynaktan aplication yükleyip çalıştırmak applet benzeri olan midlet class'larıyla yapılır. Java'yı destekleyen cep telefonları, buzdolapları, arabalar bulunmaktadır. Yakın bir gelecekte Java'nın kullanım alanının daha da yaygınlaşacağını düşünülmektedir. Enterprise Edition Server'larda, işletmelerin network'lerinde e-ticaret, mail, kullanıcı sistemi gibi bir çok işlemi desteklemek üzere çeşitli kütüphanelerle donatılmış bir başka Java versiyonu daha vardır : Enterprise Edition. Bu edition standart Java artı dağıtık işlemler için bazı kütüphaneler içermektedir. Değişik veritabanı ve e-ticaret çözümü üreten firmalar için bir standart teşkil ettiğinden, Java'nın platform bağımsızlığı yanında, yazılım üreticilerinden bağımsız sistem kurulabilmesini de sağlamaktadır. Firmayı tek bir işletim sistemine veya yazılım üreticisine bağımlı olmaktan kurtarmaktadır. Sisteme entegre bir ürün başka bir şirketin yaptığı ürünle rahatlıkla iletişim kurabilmekte, bir sistem yerine diğeri çok kolay yerleştirilebilmektedir. Bir çok büyük veritabanı ve e-ticaret yazılımı üreticisi Java enterprise edition'u desteklemektedir. JRE ve SDK JRE (Java Runtime Engine - Java Çalışma Zamanı Motoru) Bir makinede Java'yla yapılmış bir programın çalışması için orada mutlaka Java interpreter'ı olması gereklidir. Applet'ler browser içindeki Java'yla çalışırlar. Java kodlarını çalıştıran sisteme JRE (Java Runtime Engine- Java Çalışma Zamanı Motoru) denir. Java'da yapılmış bir program herhangi bir makineye kurulurken (eğer yoksa) öncelikle JRE kurulmalıdır. Ancak bu işlem bir makine için sadece bir kere yapıldığından, üzerinde JRE kurulmuş bir makineye herhangi bir program yüklenirken tekrar JRE kurulmasına gerek yoktur. JRE bazı işletim sistemlerinde kendiliğinden kurulu olup, bazılarında da tercihe bağlı olarak kurulabilmektedir. Elbette yazılan program, Java'nın o makinede kurulu sürümünden daha ileri bir sürümü gerekli kılıyorsa JRE'nin upgrade edilmesi gerekir. Java'da yeni bir sürüm yüklenince eski sürümle çalışan programlar çalışmaya devam eder. Bütün Java sürümleri 'geriyle uyumlu' (backward compatible)'dırlar. Yıllar önce yapılmış Java'nın ilk sürümüne göre çalışan uygulamalar, son sürümle de çalışmaktadır. Java Plug-in JRE kurulduğu zaman aynı zamanda browser'lar için bir plug-in olarak çalışır. Herhangi bir HTML sayfasında applet'le karşılaşıldığında artık browser'ın kendi Java'sı değil bu plug-in devreye girer. Bu applet'in Java'nın son sürümlerindeki özellikler içermesi durumunda zaten zorunludur. Internet Explorer'ın en son sürümü bile örneğin Java'nın 1.1 versiyonunu içermektedir. Oysa şu anda Java'nın son sürümü 1.4'dür. Netscape Navigator ve Opera gibi browser'lar da kurulurken Java plug-in'ini tercihe bağlı olarak yüklemektedirler. JRE 10 MB'a yakın olduğu için bir kullanıcının Java plugin'ini (JRE'yi) indirmesi bağlantı hızına göre değişmekle birlikte dakikalar mertebesinde süren bir işlem olabilmektedir. Ancak kurulumu 1 dakikadan daha az sürmektedir. Intranet gibi şirket için network ortamlarında her hangi bir makineye konan JRE, saniyeler mertebesinde çok kısa sürede client makineye kurulabilmektedir. SDK (Software Development Kit - Yazılım Geliştirme Kiti) Java'da yazılmış programların çalışması için JRE gerekmektedir. Ancak JRE program geliştirmek için kullanılamaz. JRE sadece Java programlarını çalıştırmak için gerekli araçları içerdiğinden derleyici içermez. Bir programı çalıştırmak isteyen bir kulanıcının zaten bir program yapıp derlemesi gibi bir gereksinmesi yoktur. O yüzden program yapmak isteyenlerin Java SDK (Software Development Kit - Yazılım Geliştirme Kiti)'ni kurmaları gerekmektedir. SDK JRE'yi de içermektedir. Programcının derlediği programı elbette çalıştırması da gerekir. SDK belli bir klasöre kurulur ve hemen hemen bütün araçlar bu klasörün altındadır. Bu yüzden bir makineden diğerine kopyalandığında bile çalışabilir. Sistemde çok fazla değişiklik yapmadığından sistemin bütününü veya başka programları olumsuz yönde etkileyecek hiç bir işlem yapmaz. O yüzden de kurulumu riskli değildir. Ayrıca sisteme çok fazla bağlı olmadığından, sistemdeki değişikliklerden etkilenmez. Java'yı derlemek ve çalışırmak için standart tek bir editör (IDE, RAD) yoktur. SDK sadece derleme ve çalıştırmak için kullanılır. Java kodu yazmak için sadece bir metin düzenleyici yeterlidir. Ancak daha hızlı kod yazabilmek için çeşitli şirketlerin Java geliştirme ortamları vardır. Bunlarla çalışmak daha kolay olmasına karşın burada herbirinin ayrı ayrı incelenmesi mümkün değildir. SDK'yla çalışmak zor olsa da diğer bütün editörle yapılabilen her tür işlem SDK'yla da yapılabilir. Yani SDK 'eksik' değildir. Sadece kullanım kolaylığı sağlayan araçlar içermez. Buna karşın bedavadır ve diskte çok az yer kaplar. Ayrıca editörler her zaman en yeni Java versiyonunu içermezler. SDK'ile çalışmaya alışanlar Java'nın son versiyou çıktığı anda hatta daha test aşamasındayken bile onunla çalışmaya başlayabilirler. Belli şirketlerin çıkardığı editörlerin en son sürümü yakalamaları bir süre sonra olabilmektedir. Derleme ve Çalıştırma (Windows İçin) Çalışma Ortamının Kurulması Burada JDK kurmak için standart bir yöntem anlatılacaktır. Bu şekilde çalışmanın bir çok yararı bulunmaktadır. Özellikle laboratuar ve ağ yöneticilerinin bu sisteme uymaları kendilerine bir çok fayda sağlayacaktır. Adım 1 : SDK Kurucu'yu İndirin SDK'yı download etmek için http://java.sun.com/j2se/1.4/download.html adresine gidin. 'Windows (all languages)' ve 'SDK' bölgesinde download seçeneğini tıklayın. Çıkan anlaşmaya 'Accept' deyin. Daha sonraki sayfada çıkan asıl download linkini tıklayın ve dosyayı c:\jdownload klasörüne (yoksa yaratıp) kaydedin. Adım 2 : SDK'yı Kurun Kurucu programı ('c:\jdownload\j2sdk-1_4_0-win.exe') çalıştırın ve klasör olarak c:\jsdk (yoksa yaratıp) verin. Adım 3 : Bir Çalışma Dizini Yaratın Diskte c:\jwork adıyla bir dizin yaratın. Adım 4 : Basit Bir Uygulama Yazın Çalışma dizinine 'c:\jwork\MyClass.java' şeklinde bir dosya yaratın ve içine şunları aynen yazın public class MyClass{ public static void main(String[] args){ System.out.println("OK!"); } } Adım 5 : Source Kodu Derleyin c:\jsdk\bin\javac MyClass.java Adım 6 : Programı Çalıştırın c:\jsdk\java -cp c:\jwork MyClass Eğer ekranın son satırında "OK!" görüyorsanız sistemize Java başarıyla kurulmuş demektir. Yazdığınız class'ları aynı şekilde derleyebilirsiniz. Basit Applicationlar Main Method'u Java'da yapılabilecek en basit program ekrana yazı yazan bir application'dur. Greeter.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class Greeter{ 2 public static void main(String[] args){ 3 System.out.println("Merhaba Dunya!"); 4 } 5 } Basit bir işlem gerçekleştirmesine rağmen bu class, bir Java class'ı ve application'u hakkında bir çok bilgi içermektedir. Java'da her birim bir class olmak zorundadır. Bağımsız variable veya function yoktur. Her variable veya function mutlaka bir class'ın içinde yer alır. Her application aslında özel bazı koşullara sahip bir class'dır. Bir class'ın application olabilmesi için gerekli koşul public static void main(String[] args){ } diye bir method'unun olmasıdır. Java bir class'ı uygulama olarak çalıştıracağı zaman, o class'ın main() method'unu bulur ve oradan itibaren çalıştırır. Bu method yukarıdaki şekliyle aynen bulunmalıdır yoksa Java bu class'ın bir program olduğunu anlayamaz. Ekrana yazı yazmak için System.out.println() şeklinde bir ifade kullanılır. Bu, System adlı class'ın out adlı property'sinin println() adlı methodunu çağırmak demektir. System class'ı uygulamanın çalıştığı ortamla ilişkili bazı property'ler ve method'lar barındırır. Ekrana yazmak için out adlı bir property'si bulunmaktadır. println() method'u da ekrana bir yazı yazıp yeni bire satıra geçer, yani bir satırlık yazı yazar. Görüldüğü gibi Java'da basit bir application yazmak için bile (Greeter örneğinde olduğu gibi) bir class yapmak gerekir. Ekrana yazı yazmak için bile bir classın (System'in ) bir property'sinin (out'un) bir method'unun (println()'in) çağırılması gerekmektedir. En basit application için bunları yapmak gerekiyorsa Java'nın çok zor ve öğrenilemez olduğu düşünülebilir. Ancak en karmaşık application'larda da sadece bu ve benzer işlemler yapılır. Sadece class, property ve method isimleri ve işlevleri değişir. Variable Kullanımı Greeter class'ıyla aynı işlevi yapan bir başka class yazalım. GreeterWithVariable.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterWithVariable{ 2 public static void main(String[] args){ 3 String message="Merhaba Dunya!"; 4 System.out.println(message); 5 } 6 } Bu class ekrana yine aynı mesajı yazacaktır. Ancak bu kez ekrana yazılacak yazı önce bir variable'da saklanıyor, sonra ekrana basılmak üzere println()'e veriliyor. Java'da değişken bu şekilde yapılır : Type name=value; Type, bir değişkenin nasıl bir veri sakladığını gösterir. Java'da bir variable'ın mutlaka type'ının belli olması gerekir. String message="Merhaba Dünya"; Şeklinde bir ifade de "message diye bir variable var, bunun type'ı String'dir ve ilk değeri 'Merhaba Dünya!'dır" demektir. String bir class'dır ve içerisinde karakter barındırır. Method Kullanımı Yine aynı şeyi yapan bir class yapalım. Ancak ekrana bir satır basan bir method kullanarak yapalım. GreeterWithMethod.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterWithMethod{ 2 public static void printLine(String line){ 3 System.out.println(line); 4 } 5 public static void main(String[] args){ 6 printLine("Merhaba Dunya!"); 7 } 8 } printLine() methodunun işlevi kendisine verilen String'i ekrana basmaktır. main() methodunda da printLine() methodu çağırılmaktadır. Bir method bir kez yazılıldıktan sonra defalarca kullanılabilir. public static void main(String[] args){ printLine("Merhaba Dünya!"); printLine("Merhaba Güneş!"); printLine("Merhaba Ay!"); } Method tanımlamak şu şekilde olur : ReturnType name(ParameterType1 parameter1,ParameterType2 parameter2) Burada her methodun alacağı parameter'lar ve return edilecek değerin type'ı belirtilir. Eğer dönülecek hiç bir değer yoksa return type olarak void yazılır. Birden Fazla Method Kullanımı Aynı class içince birden fazla method yazılabilir. Bunlar gerektiğinde birbirlerini çağırabilir. GreeterWithDoubleMethod.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterWithDoubleMethod{ 2 public static void printLine(String line){ 3 System.out.println(line); 4 } 5 public static void printGreeting(String greeted){ 6 printLine("Merhaba "+ greeted); 7 } 8 public static void main(String[] args){ 9 printGreeting("Dunya!"); 10 } 11 } Bu application çalıştırıldığında ekranda "Merhaba Dünya" yazar. İki string tipini birleştirmek için '+' operatorü kullanılır. Tamsayılar için toplama anlamına gelen '+', Stringler için birleştirme anlamına gelir. 1+2 işleminin sonucu 3 ederken "1"+"2" işleminin sonucu "12" eder. Dosya Listesi Greeter.java GreeterWithVariable.java GreeterWithMethod.java GreeterWithDoubleMethod.java Basit Class'lar Class Kullanımı Bir class yapalım ama bu class bir application olmasın. Bu sadece başka bir uygulamaya hizmet verecek bir class olsun. GreetingPrinter.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreetingPrinter{ 2 public static void printLine(String line){ 3 System.out.println(line); 4 } 5 public static void printGreeting(String greeted){ 6 printLine("Merhaba "+ greeted); 7 } 8 } Şimdi de GreetingPrinter adlı class'ı kullanan bir application yapalım. GreeterWithClassUse.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterWithClassUse{ 2 public static void main(String[] args){ 3 GreetingPrinter.printLine("Dunya"); 4 } 5 } Burada iki class'ın işbirliği sözkonusu. GreetingPrinter ekrana bir selamlama basabiliyor. GreeterWithClassUse ise bu class'ı kullanarak "Merhaba Dünya" diyebiliyor. Aynı şekilde bir başka application da bu class'ı kullanabilir. AnotherGreeterWithClassUse.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class AnotherGreeterWithClassUse{ 2 public static void main(String[] args){ 3 GreetingPrinter.printLine("Evren"); 4 } 5 6 } Bir class yapmanın avantajı, bir işlemi bir kere yapmak, bir daha da oradan kullanmaktır. GreeterPrinter'da bir değişiklik yapma ihtiyacı duyarsak öbür class'lar otomatik olarak duruma adapte olacaktır. Örneğin, GreeterPrinter.printGreeting()'i public static void printGreeting(String greeted){ printLine("Merhaba "+ greeted+"! "); } şeklinde değiştirelim. İki uygulama da çalışınca selamlamayı ünlemle yapacaktır. Parametere Kullanımı GreetingPrinter görüldüğü gibi sadece "Merhaba diyebilmektedir. Bunu kullanan classlardan birinin "Ne Haber?" deme hakkı yoktur. Bunun için başka bir class yapalım : FlexibleGreetingPrinter.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class FlexibleGreetingPrinter{ 2 public static void printLine(String line){ 3 System.out.println(line); 4 } 5 public static void printGreeting(String greeted,String salutation ){ 6 7 8 } printLine(salutation+ " "+ greeted + "!" ); } Bu printGreetings() methodu bir yerde FlexibleGreeting.printGreetings("Dünya","Merhaba"); şeklinde başka bir yerde FlexibleGreeting.printGreetings("Dünya","Ne Haber"); diye çağrılabilir. Aynı İsimli Birden Fazla Method Yazmak : Overloading İki kullanımda da mutlaka Merhaba veya Ne Haber" diye bir selamlama verilmelidir. Oysa aksi belirtilmediği sürece "Merhaba" demesi sağlanabilir. FlexibleGreetingPrinterWithDefault.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class FlexibleGreetingPrinterWithDefault{ 2 public static void printLine(String line){ 3 System.out.println(line); 4 } 5 public static void printGreeting(String greeted,String salutation ){ 6 7 8 9 10 11 } printLine(salutation+ " "+ greeted + "!" ); } public static void printGreeting(String greeted){ printGreeting(greeted,"Merhaba"); } Bu şekilde benzer işlevi gören aynı adlı iki method iki farklı şekilde kullanılabilir. Bir yerde FlexibleGreetingPrinterWithDefault.printGreeting("Dünya","Nasılsın"); şeklinde çaırılabilir. Bir başka yerde FlexibleGreetingPrinterWithDefault.printGreeting("Dünya"); denebilir. İkinci durumda biz söylemesek de "Merhaba" diyecektir. Buna overloading denir. İkinci bir versiyon yazarak printGreeting()'i overload etmiş olduk. Dosya Listesi GreetingPrinter.java GreeterWithClassUse.java AnotherGreeterWithClassUse.java FlexibleGreetingPrinter.java FlexibleGreetingPrinterWithDefault.java Object Kullanımı Object Yaratmak Diyelim ki aynı method, parameter'lerden biri hep aynı olmak üzere çok defa çağrılıyor. FlexibleGreetingPrinterWithDefault.printGreeting("Dünya","İyi Misin"); FlexibleGreetingPrinterWithDefault.printGreeting("Alem","İyi Misin"); FlexibleGreetingPrinterWithDefault.printGreeting("Evren","İyi Misin"); FlexibleGreetingPrinterWithDefault.printGreeting("Güneş","İyi Misin"); görüldüğü gibi gereksiz yere "İyi Misin" parameter'i sürekli giriliyor. Çünkü bu class'a şöyle diyemiyorsunuz. "'İyi Misin' selemlamasını aklında tut. Sonra da aynı selamlamayı Dünya, Alem gibi isimle kullan." Oysa Java'da bunu yapmak mümkündür. Bunun için class şu şekide olmalıdır. NonStaticGreetingPrinter.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class NonStaticGreetingPrinter{ 2 String salutation; 3 public void printGreeting(String greeted){ 4 System.out.println(salutation+ " "+ greeted + "!" ); 5 } 6 } Kullanımı da şöyle olur. NonStaticGreetingPrinter printer=new NonStaticGreetingPrinter(); printer.salutation="İyi Misin"; printer.printGreeting("Dünya"); printer.printGreeting("Alem"); printer.printGreeting("Evren"); printer.printGreeting("Güneş"); Dikkat ettiyseniz printGreeting() methodunun başında static yazmıyor. static keyword'u methodlar için kullanılıdığında, ilgili method, bu class'tan bir nesne yaratılmaksızın kullanılabilir demektir. Ancak bu durum kullanacağı veriyi dışardan her sefer alan method'lar için geçerlidir. O yüzden FlexibleGreetingPrinterWithDefault.printGreeting("Güneş","İyi Misin") ifadesinde "İyi Misin" selamlamasını sürekli girmek zorundayız. Bunun nedeni bu classından hiç nesne yaratılmamış olması ve veri tutma yeteneğinizin olmamasıdır. NonStaticGreetingPrinter ise yaratılabilir ve salutation değerini saklayabilir. Bir nesne içerisinde değer saklayabilen variable'a property denir. Kullanımı da object.property biçimindedir. Bir nesne yaratmak için ClassName object=new ClassName(); gibi bir ifadeye gerek vardır. NonStaticGreetingPrinter printer=new NonStaticGreetingPrinter(); gibi. Bu class'da salutation bir property'dir. printGreeting() methodunun her çağrılışında salutation property'sinin değeri kullanılır. Bu property bir kez atandı diye bir daha değişmez durumuda değildir. NonStaticGreetingPrinter printer=new NonStaticGreetingPrinter(); printer.salutation="İyi Misin"; printer.printGreeting("Dünya"); printer.printGreeting("Alem"); printer.salutation="Kötü Müsün"; printer.printGreeting("Evren"); printer.printGreeting("Güneş"); biçiminde salutation değeri değiştirilebilir. Değiştikten sonra ekranda görülen selamlama da değişir. Bunun için object'i tekrar yaramaya gerek de yoktur. NonStaticGreeter classında salutation property'si tanımlanırken default bir değer verilebilir. String salutation="Merhaba"; O zaman en başta bir değer atamadan da kullanılabilir. NonStaticGreetingPrinter printer=new NonStaticGreetingPrinter(); printer.printGreeting("Dünya"); printer.printGreeting("Alem"); Dosya Listesi NonStaticGreetingPrinter.java Class'lar (Sınıflar) Class,Property ve Method Kavramları Yazılım geliştirmenin iki temel bileşeni vardır : veri ve işlev. Her tür program belli veriler üzerinde belli işlever gerçekleştirir. Nesne, belli bir anlam bütünlüğü içeren veriler ve gerektiğinde o verilerle çalışan işlemlerden oluşan yapıdır. Dikdörgenler prizması diye bir nesne olduğunu düşünelim. Bununla ilgili en, boy ve yükseklik gibi veriler vardır. Ayrıca alanını ve hacmini hesaplama gibi işlemler bulunmaktadır. Java'da veri ve işlem içeren her birime "class" (sınıf) denir. Class'ların içerdiği veriye "property" (özellik), işlemlere de "method" (yöntem) denir. Dikdörtgenler prizması'nı belirten bir nesne yapalım. Göster Gizle Kopar Satır Gizle Satır Göster 1 public class RectangularPrism{ 2 float width; 3 float height; 4 float depth; 5 float getVolume(){ 6 return width*height*depth; 7 } 8 float getArea(){ 9 return 2*(width*height+width*depth+height*depth); 10 } 11 12 } Burada yaptığımız, dikdörtgenler prizması diye bir nesne olduğunu, bu nesnenin width, height, depth gibi özellikleri olduğunu, bu nesneyle alan ve hacim hesaplaması yapabileceğimizi söylemekten ibarettir. Ayrıca her property'nin veri tipini de belirttik. Dikdörgenler prizmasının kenarların kesirli sayılarla belirtilebilir. Instance Yukarıda bir class'ı tanımladık ('definition' yaptık). Bu class bütün dikdörtgenler prizmalarında olabilecek özellikler ('property'ler) ve yöntemler ('method'lar) içeriyor. Henüz ortada belli bir prizma yok. Belli bir pizmanın "yaratılması" gerekli ki biz hacmini ve alanını bulalım. Class tanımına uygun olarak yaratılan nesnelere instance (örnek) denir. Dikdörtgenler prizmasına bir örnek verilmesi, başka bir deyişle bir dikdörtgenler prizması yaratılması lazım. Buna nesneye yönelik programlamadaki terminolojiyi kullanırsak, RectangularPrism class'ından bir instance yaratılması gerekiyor. Bir prizma yaratalım, boyutlarını 10,20 ve 30 olarak verelim. Alanını ve hacmini hesaplayıp ekrana yazalım. RectangularPrismTest.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class RectangularPrismTest{ 2 public static void main(String[] args){ 3 RectangularPrism prism=new RectangularPrism(); 4 prism.width=10.0f; 5 prism.height=20.0f; 6 prism.depth=30.0f; 7 float volume=prism.getVolume(); 8 System.out.println("Volume : "+volume); 9 float area=prism.getArea(); 10 System.out.println("Area : "+area); 11 } 12 } Burada RectangularPrism class'ından bir instance yarattık. İsmi de 'prism'. Bu isim rastgele seçilmiş bir isimdir, kısaca 'p' de diyebilirdik. Ancak bir kez prism dedikten sonra aşağıda aynı ismi kullanmak zorundayız. Property Intialization Bir nesne yaratılırken 'property'lerinin değerleri default (varsayılan) değerlerine atanır. Property'ler de birer nesneyse (primitive type değilse) 'null' değerini alır. Bir değer olarak 'null' hiç bir değeri yok demektir. Bir nesneyi yaratıp kullanan kişi bir method'u çağırmak için gerekli olan property'lerin değerlerini önceden vermezse hata durumu oluşur. Örneğin, prism değerinin 'height' property'si verilmezse hacim hesaplanmaya çalışılırsa ne olacak? Nasıl bir hacim değeri üretilecek? Böyle sorunlarla karşılaşmamak için property'lerin 'initialize' edilmesi gerekebilir. Property'ler belirlenirken float width=1.0f; float height=1.0f; float depth=1.0f; şeklinde bir initialization yapılabilir. Böylelikle bir değerin verilmesi unutulsa bile belli bir değer default alınacağından sorun çıkmaz. Height değeri verilmezse hacim 1 çıkar. Alan da 2*(1*1+1*1+1*1)=6 çıkar. Constructor Bir nesnenin yaratılma aşamasında bazı işlemlerin yapılması, bazı değerlerin atanması gerekebilir. Bir nesne yaratılırken çağrılan method benzeri yapıya 'constructor' denir. Constructor aslında bir method değildir. Ama class'la aynı ismi taşıyan, dönüş değeri olmayan bir method olarak da düşünülebilir. Prizmanın boyutlarının daha instance yaratılırken verilmesi bu şekilde sağlanabilir. PrismWithConstructor.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class PrismWithConstructor{ 2 float width; 3 float height; 4 float depth; 5 public PrismWithConstructor(float w,float h,float d){ 6 width=w; 7 height=h; 8 depth=d; 9 } 10 float getVolume(){ 11 return width*height*depth; 12 } 13 float getArea(){ 14 return 2*(width*height+width*depth+height*depth); 15 } 16 17 } Bu class'ı kullanan bir application yapalım. PrismWithConstructorTest.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class PrismWithConstructorTest{ 2 public static void main(String[] args){ 3 PrismWithConstructor prism=new PrismWithConstructor(10.0f,20.0f,30.0f); 4 float volume=prism.getVolume(); 5 System.out.println("Volume : "+volume); 6 } 7 } Method Signature Bir method'un ismiyle birlikte sırasıyla aldığı parametre tipleri, o method'un 'signature'unu oluşturur. Siz bir method çağırdığınızda, öncelikle o nesnede o isimde bir method olup olmadığına bakılır. Eğer varsa, çağırdığınız parametreler'in tipleriyle birlikte eşleştirme yapılır ve uygun bir method varsa derleme işlemi başarılı olur. Aksi takdirde kod derlenemez. Bir nesnenin bir methodunu çağırdığınızda compiler kızıyorsa ve siz method ismini doğru yazdığınıza eminseniz, bilinki verdiğiniz paramtereler ya eksiktir, ya fazladır, ya sırası yanlıştır ya da parametre tipleri yanlıştır. Overloading (Çeşitleme) Bir method'la aynı isimde başka bir method yazılabilir. Buna overloading (çeşitleme) denir. Bu işlem, benzer işlemleri farklı parameteler'le yapan iki method için yapılır. Bu şekilde, bir çok method ismini öğrenmekten kurtulmuş oluruz. Ancak, overloading işleminde yeni method'un signature'u mutlaka farklı olmalıdır ki bir method çağırdığınıza hangisini çağırdığınız anlaşılabilsin. Zaten aynı isimde aynı parametreleri aynı sırada alan bir ikinci method yazmanın hiç bir anlamı yoktur. Aynı işi yapıyorlarsa, bir tanesine hiç gerek yok. Farklı işler yapıyorlarsa farklı bir isimde olmalıdır. Bir method'un return type'ı signature'a dahil değildir. Yani aynı isimde aynı parametre tiplerini aynı sırada belirten fakat iki ayrı return type olan iki ayrı method olamaz. Java'da bir method'un döndürdüğü değerin fazla bir önemi yoktur. Sadece o method'u çağıran için gerekliyse bir anlamı vardır. Hatta bir değer döndüren method, döndürdüğü değer kullanılmadan da çağrıabilir. Bazı method'lar belki lazım olur diye belli bir değeri döndürmektedirler. Birden Fazla Constructor Bir class'ın farklı parametreler alan birden fazla constructor'u olabilir. Yani constrcutor'lar da method'lar gibi 'overload' edilebilirler. PrismWithMultipleConstructor.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class PrismWithMultipleConstructor{ 2 float width; 3 float height; 4 float depth; 5 public PrismWithMultipleConstructor(float w,float h){ 6 width=w; 7 height=h; 8 depth=1.0f; 9 } 10 public PrismWithMultipleConstructor(float w,float h,float d){ 11 width=w; 12 height=h; 13 depth=d; 14 } 15 float getVolume(){ 16 return width*height*depth; 17 } 18 19 } Bir constructor başka bir constructor'u çağırabilir. Bunun için 'this' operatörü kullanılmalıdır. public PrismWithMultipleConstructor(float w,float h){ this(w,h,1.0f); } public PrismWithMultipleConstructor(float w,float h,float d){ width=w; height=h; depth=d; } Burada iki constrcutor'dan biri diğerini çağırıyor. Kendisine gelen değerleri aynen öbürüne devrederken bir değeri kendisi belirliyor. Bu yöntemin yararı, bir değişiklik yapıldığında sadece tek bir constructor'un değiştirilmesinin yeterli olmasıdır. Default & Parameter'siz Constructor'lar Aslında, programcı hiç bir tane yazmasa dahi, her class'ın bir constructor'u vardır. Sanki public class MyClass{ public MyClass(){ } } şeklinde bir constructor verilmiş gibi kabul edilir. Programcı hiç bir şey yapmadığında sağlanan default constructor hiç parametre almaz ve hiç bir işlem yapmaz. Hiç parametre almayan ama bazı initilization işlemleri yapan contructor'lar da yazılabilir. O zaman parameterless constructor (parametresiz kurucu) olur. Birim küpü 2, 2, 2 boyutlarında kabul ettiğimizi varsayalım. PrismWithParameterlesConstructor.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class PrismWithParameterlesConstructor{ 2 float width; 3 float height; 4 float depth; 5 public PrismWithParameterlesConstructor(){ 6 width=2.0f; 7 height=2.0f; 8 depth=2.0f; 9 } 10 public PrismWithParameterlesConstructor(float w,float h,float d){ 11 width=w; 12 height=h; 13 depth=d; 14 } 15 float getVolume(){ 16 return width*height*depth; 17 } 18 float getArea(){ 19 return 2*(width*height+width*depth+height*depth); 20 } 21 22 } Görüldüğü gibi class'ın iki constructor'u var. Birisi parametreleri dışardan alıyor, diğeri içerde belirliyor. İki constructor'u da test edelim. Birisi default contructor'la birim küp yaratsın, diğeri boyutları vererek. PrismWithParameterlesConstructorTest.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class PrismWithParameterlesConstructorTest{ 2 public static void main(String[] args){ 3 PrismWithParameterlesConstructor prism1= 4 5 6 7 8 9 10 11 } 12 } new PrismWithParameterlesConstructor(); PrismWithParameterlesConstructor prism2= new PrismWithParameterlesConstructor(10.0f,20.0f,30.0f); float volume1=prism1.getVolume(); float volume2=prism2.getVolume(); System.out.println("Volume 1: "+volume1); System.out.println("Volume 2: "+volume2); , Dosya Listesi RectangularPrism.java RectangularPrismTest.java PrismWithConstructor.java PrismWithConstructorTest.java PrismWithMultipleConstructor.java PrismWithParameterlesConstructor.java Application Argument'ları Komut Satırı Argument'ları Bir Java application'unda dışarıdan argument alınması mümkündür. Bu şekilde application'un duruma göre değişik çalıştırılabilmesi, application'u değiştirmeden mümkün olur. Normal şartlar altında bir application'un çalışması için komut satırından java ClassName girilmesi gerekir. Ancak argument verilmesi durumunda java ClassName Argument0 Argument1 ... biçiminde kullanılır. Bu argument'ler main method'una args[] array'i olarak verilir. main() methodunun public static void main(String[] args) biçiminde tanımlanmasının nedeni budur. Programın içinde argument'lara public static void main(String[] args) { String arg0=args[0]; String arg1=args[1]; } biçiminde erişilebilir. Dışarıdan aldığı isme selam veren bir application yazalım. GreeterByArguments.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterByArguments{ 2 public static void main(String[] args){ 3 String greeted=args[0]; 4 System.out.println("Merhaba "+greeted); 5 } 6 7 } Bu uygulamayı çalıştırırken java GreeterByArguments Dünya girersek ekrana "Merhaba Dünya" yazar. Aynı şekilde java GreeterByArguments Evren de diyebilirdik. Yani bizim application'umuzu kullanan kişi istediği değeri girebilir, istediği selamı ekrana çıkarabilir. Elbette biz bunu programın içinde de yapabilirdik. Ancak bu durumda her değişiklikte yeniden program yazmamız veya her sefer kodu değişitirip derlememiz gerekirdi. Oysa bir uygulama bir kez yazıldıktan sonra başka bir yerde hatta başka bir ülkedeki insanlar tarafından kullanılabilir olmalıdır. Her değişiklikte application'u yeniden yazmak çoğu kez mümkün olmaz. Argument'ların Kontrolü Yukarıdaki uygulama çalıştırılırken argument vermek unutulursa hata uyarısı alınır. Çünkü uygulama mutlaka neyi selamlayacağının girilmesini istemektedir. Bu hatadan kurtulmak için kullanıcının bir değer girip girmediği kontrol edilebilir. GreeterByArgumentsChecked.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterByArgumentsChecked{ 2 public static void main(String[] args){ 3 if(args.length==1){ 4 String greeted=args[0]; 5 System.out.println("Merhaba "+greeted); 6 } 7 } 8 } Uygulamaya argument girilmemesi durumunda sadece hata vermemesi değil, kullanıcıya bir uyarı mesajı vermesi daha uygun olur. GreeterByArgumentsWithWarning.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterByArgumentsWithWarning{ 2 public static void main(String[] args){ 3 if(args.length==1){ 4 String greeted=args[0]; 5 System.out.println("Merhaba "+greeted); 6 }else{ 7 System.out.println("Lutfen kime selam verilecek girin"); 8 } 9 } 10 } Genellikle application'lar bu durumda girilecek argument'ler hakkında bilgi veren bir yazıyı ekrana basarlar ve programdan çıkarlar. Programdan çıkmak, yani application'un çalışmasını kesmek için System.exit() methodu kullanılır. GreeterByArgumentsWithHelp.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterByArgumentsWithHelp{ 2 public static void main(String[] args){ 3 if(args.length==1){ 4 String greeted=args[0]; 5 System.out.println("Merhaba "+greeted); 6 }else{ 7 System.out.println("kullanma:java GreeterByArguments GreeterByArgumentsWithHelp greeted"); 8 System.exit(0); 9 } 10 } 11 12 } Exit methoduna '0' girmenin manası, programın doğal olarak, programcı tarafından durdurulduğunu göstermektir. Bir hata olduğunu belirtmek için 0 dışında bir değer, örneğin '-1' girilebilir. Bir application'un, belli bir argument'in girilmemesi durumunda da varsayılan (default) değerle çalışması sağlanabilir. GreeterByArgumentsWithDefault.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterByArgumentsWithDefault{ 2 public static void main(String[] args){ 3 String greeted; 4 if(args.length==1){ 5 greeted=args[0]; 6 }else{ 7 greeted="Dunya"; 8 } 9 System.out.println("Merhaba "+greeted); 10 } 11 12 } Bu application java GreeterByArgumentsWithDefault Evren diye de çağrılabilir, java GreeterByArgumentsWithDefault şeklinde de. İkinci durumda "Merhaba Dünya" yazacak ve hata vermeyecektir. Dosya Listesi GreeterByArguments.java GreeterByArgumentsChecked.java GreeterByArgumentsWithWarning.java GreeterByArgumentsWithHelp.java GreeterByArgumentsWithDefault.java Değişkenler ve Tipler Type kavramı Java'da her variable'ın belli bir type (tip)'i olması gereklidir. Tip, variable'ın nasıl bir veri taşıdığını ve onun üzerinde ne gibi operasyonlar yapabileceğimizi belirler. Değişkenin type'ı tamsayıysa çıkarma yapabilirsiniz, String ise yapamazsınız. Java yapılan işlemlerde kullanılan değerlerin tiplerine son derece dikkat eder. Herhangi bir tip uyumsuzluğunda derleme hatası gelir. İki sayıyı toplayıp sonucu ekrana basan bir application yapalım. IntegerAdder.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class IntegerAdder { 2 public static void main(String[] args){ 3 int a=200; 4 int b=100; 5 int sum; 6 sum=a+b; 7 System.out.println("Sum is "+sum); 8 } 9 } Bu application'da int a=200; ifadesi bir variable'ın declaration'unu içerir. Tanımlama şu biçimde yapılabilir. Type Variable=IntialValue; Elbette bu declaration değişkenin ilk değerinin belli olması durumunda kullanılır. İlk değerin daha sonra belli olması durumunda declaration Type Variable; biçiminde yapılır. Toplamın sonucu baştan bilinmediği için önce int sum; biçiminde declaration yapılabilmiştir. Değeri daha sonra bir işlem sonucunda belli olacaktır. sum=a+b; Buradaki iki satırı tek satır olarak yazmak da mümkündür int sum=a+b; Bu durumda tanımlama ve işlem aynı ifade içerisinde yer almış olmaktadır. Class Type'lar Java'da temel olarak iki çeşit type vardır : primitive type'lar ve class type'ları. Örneğin int primitive type'tır. String'de bir class type'ıdır. İki String type'ındaki veriyi birleştirmek istersek yine + kullanılır. Ancak işlem bu kez toplama değil birleştirme olur. StringConcatanator.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class StringConcatanator{ 2 public static void main(String[] args){ 3 String a="200"; 4 String b="100"; 5 String concatanation; 6 concatanation=a+b; 7 System.out.println("Birle&#351;tirilmi&#351; String is "+concatanation); 8 } 9 } Bu uygulama değeri "200" olan String type'ındaki a ile değeri "100" olan String type'ındaki b değişkenini birleştirir. Sonu yine bir String'tir ve "200100"dür. Görüldüğü gibi variable'ların type'ı işlemlerin nasıl yapılacağını belirlemektedir. int type'ınındaki bir variable int a=200; şeklinde tanımlanırken String type'ındaki a String a="200"; biçiminde tanımlandı. String değerleri belirtmek için çift tırnak kullanılır. Primitive Type'lar Primitive type'lar tamsayı, gerçel sayı, mantıksal ve karakter type'lar dır. Tamsayı type'ları, alabilecekleri maksimum ve minimum değerlerin sırasına göre byte, short, int, long'dur. Gerçek sayılar float ve ondan daha büyük değerleri alan double'dır. Tip olarak boolean sadece true ve false gibi iki değer alır. char tipi de harf,rakam ve noktalama işaretleri gibi karakterleri tutabilir. PrimitiveTypesPrinter.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class PrimitiveTypesPrinter{ 2 public static void main(String[] args){ 3 int i=50000; 4 short s=500; 5 long l=5L; 6 byte b=3; 7 float f=2.5f; 8 double d=3.5; 9 char c='K'; 10 11 12 13 14 15 16 17 18 19 } 20 } boolean x=true; System.out.println(" System.out.println(" System.out.println(" System.out.println(" System.out.println(" System.out.println(" System.out.println(" System.out.println(" Integer : " + i ); Short: "+ s ); Long: "+ l ); Byte : "+b ); Float : "+ f ); Double : "+ d ); Characater : "+c ); Boolean : "+ x ); Dosya Listesi IntegerAdder.java StringConcatanator.java PrimitiveTypesPrinter.java Basit Data Tipleri Array'ler Birden fazla veri sıralı olarak saklanmak istenirse diziler kullanılır. Dizilerin declaration'u Type[] name=new Type[Length]; biçiminde olur. Örneğin 10 elemanlı bir int dizisi int[] a=new int[10]; şeklinde tanımlanır Dizinin bir elemanına erişim de name[i] biçiminde gerçekleşir. Örneğin yukarıdaki dizinin 3. elemanının değerini 7 yapmak için. a[3]=7; yazmak yeterlidir. Dizinin 5'inci elemanının değerine erişim de int x=a[5]; biçiminde olur. Bir array'in değerlerini daha tanımlarken belirlemek mümkündür int[] a=new int[10]{10,9,8,7,6,5,4,3,2,1 }; Bir array'in elemanlarını toplayan bir uygulama yazalım. ArraySum.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class ArraySum{ 2 public static void main(String[] args){ 3 int[] a=new int[]{10,9,8,7,6,5,4,3,2,1 }; 4 int sum=0; 5 for(int i=0;i<a.length;i++){ 6 sum+=a[i]; 7 } 8 System.out.println("Sum of Array : "+ sum); 9 } 10 11 } Array'ler de aslında bir nesnedir. Loop'ta kullanılan a.length ifadesinde a array'inin, array'in boyunu veren length adlı property'si kullanılmıştır. Primitive Type'ların Wrapper'ları Java'da herşey class'dır. Ancak class olarak kullanılmayan primitive type'lar da bulunur. Her primitive type'ın bir de class karşılığı bulunur ki bu type'la ilgili yapılabilecek işler bu class aracılığıyla yapılabilsin. Bu class'lara wrapper denir. İçlerinde bir primitive type tutma özellikleri vardır. Örneğin int tipine karşılık Integer class'ı vardır. Bu class'ın içinde int tipiyle ilgili çeşitli property ve methodlar bulunur. Bir String'in int'e veya bir int'in String'e dönüştürülmesi için birer method bulunur. Örneğin, kesirli bir sayı gösteren bir String'i kesirli bir sayı haline getirmek için String s="1.5f"; float f=Float.parseFloat(s); şeklinde bir işlem gereklidir. Bir integer'i String'e çevirmek için int i2=2; String s2=Integer.toString(i2); şeklinde bir kod yazılır. Bir primitive tip yerine, wrapper'ı kullanılabilir. Integer w=new Integer(2); Daha sonra ilkel hali int i=w.intValue(); şeklinde alınabilir. Dışardan argument olarak integer bir sayı alan program yapalım IntegerSum.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class IntegerSum{ 2 public static void main(String[] args){ 3 String a=args[0]; 4 int i=Integer.parseInt(a); 5 String b=args[1]; 6 int j=Integer.parseInt(b); 7 int sum=i+j; 8 System.out.println("Sum : "+sum); 9 } 10 } String Class'ı Yazı veya metin denilen verileri saklamak için iki yol vardır. Ya char array'i kullanmak. char[] c=new char[]{'J','a','v','a'}; veya String class'ını kullanmak String s="Java"; String s=new String("Java"); String class'ı da aslında içerisinde bir character array taşır. char[] c=new char[]{'J','a','v','a'}; String s=new String(c); diyerek bir character dizisinde String üretebiliriz. Bir string'in character'lerine char[] a=s.toCharArray(); şeklinde erişilebilir. String class'ı bu tip veri üzerinde ihtiyaç duyulabilecek bir çok method içermektedir. İçerisinde "JAVA 1.2" ifadesini içeren bir cumleyi, "Java 1.3" ile değiştirme uygulaması yapalım. VersionUpgrader.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class VersionUpgrader{ 2 public static void main(String[] args){ 3 String string="We use JAVA 1.2 in application development"; 4 String older="JAVA 1.2"; 5 String newer="Java 1.3"; 6 int start=string.indexOf(older); 7 String before=string.substring(0,start); 8 int finish=start+older.length(); 9 int end=string.length(); 10 String after=string.substring(finish,end); 11 String result=before+newer+after; 12 System.out.println("Result : "+result); 13 } 14 } String.indexOf() methodu' belirtilen verilen String'in asıl String'in içinde hangi sırada basladığını gösteriyor. String.substring() bir String'in bir parçasını almak için, String.length() de character sayısını bulmak için kullanılır. Dosya Listesi ArraySum.java IntegerSum.java VersionUpgrader.java Akış Kontrolü 'For' Loop'u Bir programın akışını kontrol etmek için bazı yapılar bulunur. Belli bir koşulun gerçekleşmesine göre bir iş, gerçekleşmemesine göre başka bir iş yapılabilir. Bir işlemin belli bir koşul sağlanıncaya kadar veya sağlandığı sürece yapılması da istenebilir. Aynı selamı 10 kere ekrana basan bir uygulama yazalım. GreeterByForLoop.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterByForLoop{ 2 public static void main(String[] args){ 3 for(int i=0;i<10;i++){ 4 System.out.println("Merhaba Dunya"); 5 } 6 } 7 8 } Bir işlemin kaç kere yapılacağını belli olduğu tipteki loop'lar 'for' loop'larıdır. Yapısı for( FirstStatement; TerminationCondition; StementForEachIteration ){ BlockToExcecute; } biçimindedir. Burada for loop'unun içine ilk olarak, en başta (sadece bir kere) yapılması istenen işlem, ikinci olarak loop'tan çıkmak için sağlanması beklenen koşul girilir. Son olarak da her sefer yapılması gereken işlem belirtilir. Örnek'te i değişkeni 0'a eşitleniyor, her sefer 10'dan küçük mü diye kontrol ediliyor ve her sefer bir arttırılıyor. i=10 olduğunda i>10 ifadesi artık yanlış olacağından loop o noktada bitmektedir. int i=0; ifadesi hem bir variable declaration'u hem da initial value verme işlemidir. Bu, Java gibi bir değişkenin tipinin ve değerinin baştan belli olmasını zorunlu tutan dillerde gereklidir. i++ ifadesi de bir i değerinin bir arttırılması anlamına gelir i=i+1 yazmanın kısa ve hızlı bir yoludur. While Loop'u Yukarıdaki işlemi başka bir loop çeşidi olan while loop'u ile de gerçekleştirebilirdik. GreeterByWhileLoop.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterByWhileLoop{ 2 public static void main(String[] args){ 3 int i=0; 4 while(i<10){ 5 System.out.println("Merhaba Dunya"); 6 i++; 7 } 8 } 9 10 } Görüldüğü gibi while döngüsünün yapısı while(ContinuationCondition){ BlockToExecute; } biçimindedir. Örnekte for döngüsünün yerine kullanılmıştır ancak while döngüsünün işlevi bir işlemi belli bir koşul gerçekleştiği sürece yapmaktır. Bu koşul bir sayının belli bir değere ulaşması olduğu gibi döngünün içerisinde belirlenebilecek herhangi bir değer de olabilir. Özetle bu koşul gerçekleştiği sürece bu işlemi yap anlamına gelir. 'Do-While' Loop'u Aynı işlemi while döngüsünün bir başka türü olan do-while döngüsü ile de halledebiliriz. GreeterByDoWhileLoop.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterByDoWhileLoop{ 2 public static void main(String[] args){ 3 int i=0; 4 do{ 5 System.out.println("Merhaba Dunya"); 6 i++; 7 }while(i<10); 8 } 9 10 } do-while döngüsünün yapısı while döngüsünün tersidir. do{ BlockToExecute; }while(ContinuationCondition); biçimindedir. Bu tip döngüde önce işlem yapılmakta sonra döngünün bitip bitmediği kontrol edilmektedir. Elbette koşulu önce veya sonra kontrol etmek çoğu kez isteğe bağlıdır. Ancak bir koşulun gerçekleşip gerçekleşmediği ancak döngünün içinin bir kez çalıştırılması sonucunda belli oluyorsa do-while kullanmak zorunludur. 'If' Yapısı Programın akışını kontrol etmekte en çok kullanılan yapı if yapısıdır. Bir koşul gereçkleşiyorsa belli bir işlemi gerçekleşmiyorsa bir başkasını yapmaya yarar. Ancak bu bir kez yapılan bir kontroldür ve programın akışı bir kez buradan dallandı mı bir daha aynı koşula bakılmaz. Adı ve cinsiyeti girilen bir insana erkekse selam veren bir uygulama yazalım. GreeterByIfStatement.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterByIfStatement{ 2 public static void main(String[] args){ 3 String name=args[0]; 4 String genus=args[1]; 5 if( genus.equals("Erkek") ){ 6 System.out.println("Merhaba Bay "+name); 7 } 8 9 10 } } Burada kontrolü yapılan koşul genus.equals("Erkek") şeklindedir. Yani; dışarıdan alınan genus arguman'ı "Erkek" değerine eşitse. 'If-Else' Yapısı Bir koşulun sağlanmaması durumunda da bir işlemi gerçekleştiren bir program yazalım. GreeterByIfElseStatement.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterByIfElseStatement{ 2 public static void main(String[] args){ 3 String name=args[0]; 4 String genuine=args[1]; 5 if(genuine.equals("Erkek") ){ 6 System.out.println("Merhaba Bay "+name); 7 }else{ 8 System.out.println("Merhaba Bayan "+name); 9 } 10 } 11 } 'If-Else-If' Yapısı Yukarıdaki örnek cinsiyetin erkek değilse kadın olduğunu varsaymaktadır. Yanlış bir ifade girilse de kadın kabul edilmesi istenmeyebilir. GreeterByIfElseIfStatement.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterByIfElseIfStatement{ 2 public static void main(String[] args){ 3 String name=args[0]; 4 String genuine=args[1]; 5 if( genuine.equals("Erkek") ){ 6 System.out.println("Merhaba Bay "+name); 7 }else if(genuine.equals("Kadın")){ 8 System.out.println("Merhaba Bayan "+name); 9 }else{ 10 System.out.println("Merhaba Bay/Bayan "+name); 11 } 12 } 13 } Bu şekilde istendiği kadar if ve else arasında istendiği kadar else if yapısı kullanılabilir. Switch-Case Yapısı Çok fazla sayıda if-else kullanmak yerine basit tipte veriler için switch-case diye başka bir kontrol ifadesi bulunmaktadır. Kullanıcıdan girilen sayıya göre bir işlem gerçekleştiren bir uygulama yazalım. Kullanıcı tek rakam girmeye zorlanırsa 10 tane ihtimal vardır ve çok sayıda if-else yapısı kurmak işi karmaşıklaştıracaktır. GreeterBySwitchCaseStatement.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class GreeterBySwitchCaseStatement{ 2 public static void main(String[] args){ 3 String argument=args[0]; 4 int number=Integer.parseInt(argument); 5 switch(number){ 6 case 0: System.out.println("0 Girdiniz.");break; 7 case 1: System.out.println("1 Girdiniz.");break; 8 case 2: System.out.println("2 Girdiniz.");break; 9 case 3: System.out.println("3 Girdiniz.");break; 10 case 4: System.out.println("4 Girdiniz.");break; 11 case 5: System.out.println("5 Girdiniz.");break; 12 case 6: System.out.println("6 Girdiniz.");break; 13 case 7: System.out.println("7 Girdiniz.");break; 14 case 8: System.out.println("8 Girdiniz.");break; 15 case 9: System.out.println("9 Girdiniz.");break; 16 } 17 } 18 19 } Görüldüğü gibi String tipinde olan argument, Integer.parseInt methoduyla int tipine çevrilmiştir. Çünkü switch ifadesi sadece int, char gibi basit tiplerle çalışmakta, içerisine herhangi bir class tipi kabul etmemektedir. Dosya Listesi GreeterByForLoop.java GreeterByWhileLoop.java GreeterByDoWhileLoop.java GreeterByIfStatement.java GreeterByIfElseStatement.java GreeterByIfElseIfStatement.java GreeterBySwitchCaseStatement.java Exception'lar Exception Kavramı Her program doğru olarak yazılması durumunda hatasız olarak çalışacaktır. Ancak bu ideal bir durumdur ve hatasız bir program yazmak hiç bir kimseye nasip olmamıştır. Önemli olan hatasız bir uygulama yapmak değil, hata oluştuğunda bunu programın anlayabilmesini ve önlem alabilmesini sağlamaktır. Hiç bir şey yapılamıyorsa, en azında kullanıcıya hatanın bildirilmesi gerekmektedir. Ancak, bir hata olması durumunda program kesinlikle çökmemelidir. Hatanın önlenmesi için en çok kullanılan yöntem, hata oluşturabilecek sorunların konrol edilmesidir. Örneğin, bir dosyayı okumadan önce programcı okumak istediği bir dosyanın okumaya çalıştığı yerde olup olmadığını kontrol edebilir. Ancak her durumu programcının öngörebilmesi ve önlemini alması her zaman mümkün olmaz. Hatanın ve anormal durumların ele alınmasında en iyi yol 'exception' kullanmaktadır. Exception'ların devreye girmesiyle hata ayıklamak çok daha kolaylaşmıştır. Exception'larla bir program parçası hatayı anlamaya ve değerlendirmeye zorlanabilir. Örneğin okunacak bir dosyanın orada bulunmaması durumunda programcının bunu anlaması ve bir tepki vermesi zorunlu hale getirilebilir. Try-Catch Bloğu Çağrılan bir method'ta hata oluşması durumunda bunun yakalanması için try-catch bloğu kullanılır : try{ // Hata oluşturabilecek herhangi bir işlem. }catch(Exception e){ // Hata durumunda yapılacaklar. } Girilen bir sayının tek mi çift mi olduğunu anlayan basit bir program yapalım. OddEvenDifferantiatorWithoutException.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class OddEvenDifferantiatorWithoutException{ 2 public static void main(String[] args){ 3 String input=args[0]; 4 int number=Integer.parseInt(input); 5 int mod=number % 2; 6 if ( mod == 0){ 7 System.out.println("cift"); 8 }else{ 9 System.out.println("tek"); 10 } 11 12 } 13 } Bu program çalışır durumdadır. Kullanıcının girdiği bir sayının çift mi tek mi olduğunu anlayabilmektedir. Ancak kullanıcı ya sayı yerine "A" girerse? Bu durumda program çalışmayacak o anda her şey çokecektir. Bunu önlemenin yolu elbette önce girilen String'n bir sayı olup olmadığını anlamaktır. Ancak bu çok karmaşık bir işlemdir. Bütün karakterler alınmalı ve her birinin rakam olup olmadığı tek tek kontrol edilmelidir. Bunu yapan isNumber() diye bir method yazılabilir. Ancak Exception kullanarak daha basit bir şekilde sorun çözülebilmektedir. OddEvenDifferantiatorWithException.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class OddEvenDifferantiatorWithException{ 2 public static void main(String[] args){ 3 try{ 4 String input=args[0]; 5 int number=Integer.parseInt(input); 6 int mod=number % 2; 7 if ( mod == 0){ 8 System.out.println("Çift"); 9 }else{ 10 System.out.println("Tek"); 11 } 12 System.out.println("Te&#351;ekkürler"); 13 }catch(NumberFormatException e){ 14 System.out.println("Say&#305; giriniz!"); 15 } 16 17 } 18 } NumberFormatException, Integer class'ının static methodu parseInt() tarafından fırlatılabilmektedir. Burada sadece Exception da yakalanabilirdi. Ancak bu durumda diğer hatalar için de aynı mesaj çıkacaktı. Try-Catch-Finally Bir exception'ın fırlaması durumunda kodun yürütülmesi o noktada durur ve artık catch() bloğunun içerisindekiler yürütülmeye başlar. Bazı durumlarda bir işlemin hata olsa da olmasa da gerçekleştirilmesi istenebilir. Try bloğunun içindeki kod parçaları hata durumunda çalışmayacağı için buraya konması doğru olmaz. Yukarıdaki örnekte hata olması durumunda "Teşekkürler" yazısı ekrana basılmayacaktır. Diyelim ki biz kullanıcıya hata yapsa da yapmasa de teşekkür etmek istiyoruz. Bunun için kod şu hale getirilmeklidir. OddEvenDifferantiatorWithExceptionAndFinally.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class OddEvenDifferantiatorWithExceptionAndFinally{ 2 public static void main(String[] args){ 3 try{ 4 String input=args[0]; 5 int number=Integer.parseInt(input); 6 int mod=number % 2; 7 if ( mod == 0){ 8 System.out.println("cift"); 9 }else{ 10 System.out.println("tek"); 11 } 12 }catch(NumberFormatException e){ 13 System.out.println("enter number"); 14 }finally{ 15 System.out.println("thank"); 16 } 17 18 } 19 } Throw Programcı istediği yerde kendisi de bir Exception fırlatabilir. Bir yerde throw keyword'üyle fırlattığı exception'u başka bir yerde kendi yakalayabilir. Girilen bir rakamaın 1000'ler basamağındaki rakamını bulan bir program yazalım. Ancak bir sayının binler basamağındaki sayısını bulabilmek için girilen sayının binden büyük olması gerekir. ThousandsFinderWithThrow.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class ThousandsFinderWithThrow{ 2 public static int getTousands(int number){ 3 if(number<1000){ 4 throw new IllegalArgumentException("1000'de kuçuk sayi girilmemeli!"); 5 } 6 int division=number/1000; 7 int digit=division % 10; 8 return digit; 9 } 10 public static void main(String[] args){ 11 try{ 12 String input=args[0]; 13 int number=Integer.parseInt(input); 14 int digit=getTousands(number); 15 System.out.println("Binler : "+digit); 16 }catch(IllegalArgumentException e){ 17 String message=e.getMessage(); 18 System.out.println(message); 19 } 20 21 } 22 } Throws Bir method kendisini çağıran kodu Exception'u yakalamaya (try-catch içine almaya) zorlayabilir. Bunun için yapılması gereken method'un tanımında throws keyword'üyle Exception'un adının verilmesidir. public void method() throws AnyException { // Her hangi bir lod parçası. } Bu methodun çağrıldığı yerde mutlaka public void another(){ try{ object.method(); }catch(AnyException e){ System.out.println("Bir hata oluştu!"); } } biçimde yakalanması gerekir. Bir method bir exception'u yakalamak istemezse kendisi de onu throws listesine alabilir. public void another() throws AnyException { object.method(); } Ancak bu sefer de bu methodu hangi method çağırıyorsa o yakalamak zorundadadır. Tabii o da throws listesinde göstermezse. En sonunda mutlaka bir method bu exception'u yakalayacaktır. RuntimeException'lar Bazı exceptionları yakalamak zorunlu değidir. Bunun için o exception'un runtime exception olması gerekir. Yani RuntimeException veya onu extend etmiş herhangi bir exception olması. Bu tip exception'lar genellikle hatanın çalışma esnasında yaklanması gerektiği durumlarda kullanılır. IllegalArgumentException ve NumberFormatException class'ları runtime exception'dur. Exception Türetme Kullanıcı kendi exception'larını da yazabilir. class AnyKindOfException extends Exception{ } ve diğer exceptionlarla aynı şekilde fırlatabilir veya yakalayabilir. Dosya Listesi OddEvenDifferantiatorWithoutException.java OddEvenDifferantiatorWithException.java OddEvenDifferantiatorWithExceptionAndFinally.java ThousandsFinderWithThrow.java StringTokenizer ve StringBuffer Java'da String işlemlerini kolaylaştırmak için çok çeşitli class'lar bulunur. Bunlar arasında bir string'i parçalara ayırmay ayarayan StringTokenizer ve string'leri birleştirmeye yarayan StringBuffer en fazla kullanılanlarındandır. StringTokenizer Bir string'i belli karakterlere göre parçalamak için StringTokenizer class'ı kullanılır. Her bir parçaya 'token' denir. Sınırlayıcı karakterlerin her biri 'delimiter' diye adlandırılır. StringTokenizer, verilen stringi verilen karakterlere göre parçalar ve sırayla verir.Çalışma mantığı token'ları bir dizi olarak verme şeklinde olmaz. Token'lara erişim sırayla gerçekleşirilir. Bir tümce içinde geçen sözcükleri bulmaya yarayan bir kod parçası yazalım. String sentence="Java is a simple, object-oriented, distributed, interpreted," +" robust, secure,architecture-neutral, portable, multithreaded, dynamic," +" buzzword-compliant, general-purpose programming language."; String delims=" ;,.-"; StringTokenizer tokenizer=new StringTokenizer(sentence,delims); while(tokenizer.hasMoreTokens()){ String token=tokenizer.nextToken(); System.out.println(token); } StringTokenizer, parçalayacağı string'i ve sınırlayıcı karakterleri constructor'da ister. Delimiter'ler bir string biçiminde birleştirilerek verilir. Bu sadece çalışma kolaylığı sağlamak içindir, yoksa verilen string'deki her karakter ayrı ayrı düşünülür. Whitespace (boşluk) karakterleri aynen, 'yeni satır' (new line) gibi karakterler '\' ile kaçılarak belirtilir. StringTokenizer Enumeration interface'ini implement eder. Başka bir deyişle StringTokenizer da Enumeration olarak erişilebilir. StringTokenizer tokenizer2=new StringTokenizer(sentence,delims); while(tokenizer2.hasMoreElements()){ String token=(String)tokenizer2.nextElement(); System.out.println(token); } Burada hasMoreTokens() ve nextToken() yerine hasMoreElements() ve nextElement() kullanılmıştır. Ancak Enumeration string değil object tipiyle çalıştığı için token'ın string olarak kullanılabilmesi için cast edilmesi gerekir. Bazı durumlarda delimiter'ler de gerekebilir. StringTokenizer constructor'unda parametre olarak 'returnDelims' değerini alır. Default'u false olan bu değer true girilirse, token'larını yanısıra delimiter'lar da döner sonuçta. boolean returnDelims=true; StringTokenizer tokenizer3=new StringTokenizer(sentence,delims,returnDelims); while(tokenizer3.hasMoreTokens()){ String token=tokenizer3.nextToken(); System.out.println(token); } StringTokenizerTest.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.util.*; 2 public class StringTokenizerTest { 3 public static void main(String[] args){ 4 String sentence="Java is a simple, object-oriented, distributed, interpreted," 5 +" robust, secure,architecture-neutral, portable, multithreaded, dynamic," 6 +" buzzword-compliant, general-purpose programming language."; 7 StringTokenizer tokenizer=new StringTokenizer(sentence); 8 while(tokenizer.hasMoreTokens()){ 9 String token=tokenizer.nextToken(); 10 System.out.println(token); 11 } 12 String delims=" ;,.-\n\r\t"; 13 StringTokenizer tokenizer2=new StringTokenizer(sentence,delims); 14 while(tokenizer2.hasMoreElements()){ 15 String token=(String)tokenizer2.nextElement(); 16 System.out.println(token); 17 } 18 boolean returnDelims=true; 19 StringTokenizer tokenizer3=new StringTokenizer(sentence,delims,returnDelims); 20 while(tokenizer3.hasMoreTokens()){ 21 String token=tokenizer3.nextToken(); 22 System.out.println(token); 23 } 24 } 25 } StringBuffer Java'da metin biçimindeki verileri tutmak için String class'ı kullanılır. Bu class içerisinde bir char[] (karakter dizisi) tutar. Bu değişmez. Dolayısıyle birden fazla string'in birleştirlmesi, bir string'in içersinden bir bölümünün çıkarılması gibi işlemler yeni bir string üretilmesi şeklinde olur. Bu işlemler için aslında programcı bilmese de StringBuffer adlı class kullanılır. Örneğin x = "a" + 4 + "c" şeklindeki kod x = new StringBuffer().append("a").append(4).append("c").toString() şeklindeki kodun kısa yazılışıdır. Ancak işlem tek ifade içerisinde olmadığı durumlarda, bir çok String nesnesi yaratılır. Çünkü string içerisindeki değerler sabittir. Bir karakter bile eklense yeni bir string yaratılmış olur. x+="a"; x+="b"; gibi basit ifadelerde bile çok sayıda string nesnesi yaratılır. Dolayısıyla çok fazla stirng operasyonu içeren kodların Stirng class'ını kullanması performans açısından kayba yol açar. O yüzden bu durumlarda StringBuffer kullanmak faydalı olabilir. Bu nesne de bir char[] (karakter dizisi) tutar ancak bu eklem çıkarma yapıldıkça değişir, gerektiğinde uzar. StringBuffer nesnesi StringBuffer buffer=new StringBuffer(); şeklinde boş olarak, StringBuffer buffer=new StringBuffer("initial"); da olduğu gibi başlangıçta bir değer vererek olabilir. Bir string eklemek için buffer.append("mystring"); şeklinde bir ifade gerekir. Buradaki append() methodu temel tipler ve object için oveload edilmiştir (her biri için ayrı bir method append() yazılmıştır). Karakter veya sayı eklemek için, örneğin buffer.append('A'); buffer.append(2.4); ifadeleri yeterlidir. Bu append() methodu kolaylık olsun diye StringBuffer'ın kendisini geri döndürmektedir. buffer.append("first").append("second"); şeklinde bir ifade yazılabilir. İlk append method'undan buffer döndüğü için ikinci bir append yazılabilmektedir. StringBuffer'ın ortasında bir yere metin eklemek için buffer.insert(5,"xxx"); şeklinde bir ifade gereklidir. Burada "xxx" 5'. karakterden itibaraen araya sokulur. Belli bir kısmı değiştirmek için buffer.replace(3,5,"yyy"); şeklinde bir ifade yeterlidir. Burada replace() method'uyla İndisi 3'ten başlayıp 5'e kadar giden bölge silinir yerine "yyy" konur. StringBuffer'la yapılacak işler bittikten sonra String class'ına çevirmek gerektiğinde String string=buffer.toString(); şeklinde toString() method'u kullanılır. Genellikle üzerinde değişiklikler yapılacak string önce StringBuffer class'ına constructor'da verilir. En son işlemler bittikten sonra tekrar toString methodu'yla string'e döndürülür. StringBufferTest.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class StringBufferTest { 2 public static void main(String[] args){ 3 StringBuffer buffer=new StringBuffer(); 4 buffer.append("One"); 5 buffer.append("Two"); 6 buffer.append("Three"); 7 buffer.append("Four").append("Five"); 8 buffer.append('S').append('i').append('x'); 9 char[] chars= new char[]{'S','e','v','e','n'}; 10 buffer.append(chars); 11 buffer.insert(6,"-"); 12 buffer.replace(12,16,"-4-"); 13 String string=buffer.toString(); 14 System.out.println(string); 15 String sub=buffer.substring(19,22); 16 System.out.println(sub); 17 } 18 } Dosya Listesi StringTokenizerTest.java StringBufferTest.java Vector ve Hashtable Java'da bir den fazla değeri tutmaya yarayan temel veri yapısı array (dizi)dir. Diziler 'sabit miktarda değerleri' tutarlar ve bir 'index' (indis) aracağılığıyla elemanlara erişim sağlarlar. Ancak bazı durumlarda elemanların sayısı baştan belli değildir. Sonradan belli olur veya baştan belirlenen değer sonradana değişir. Bazı durumlarda da erişim için index kullanılamaz. Bir arada tutulması istenen elemanlar için bir index gibi bir sayı tutmak anlamsızdır. Her eleman sayı olmayan bir 'key' (anahtar)'a bağlı olabilir. Veritabanları için ID alanları, web sitelerinde kullanıcı isimleri, kimlik veya vergi numaraları bunlara örnektir. Bu tipte veriler için dizi kullanmak anlamsızdır, çünkü elamanlar sıralı değildir. '3.' veya '5.' elemanı diyebileceğimiz bir eleman yoktur. Elemanları sayısının da sırasının da anlamı yoktur. Örneğin, 3. eleman silinince yani aradan bir eleman çıkınca 5. eleman 4. eleman haline gelir. Bu durumda daha önce 5'ler erişilebilen elemanı 4 numaraya düşebilir. Bu durumlarda dizi kullanılamaz. Java'da birden fazla nesneyi tutmak için Collection'lar kullanılır. Collectionlar Java 2 Standart Edition'a 1.2'de dahil olmuştur. Bu versiyondan önce Collection gibi kullanılabilecek sadece Vector ve Hashtable gibi bir kaç class bulunmaktaydı. Collection'lar Java'ya dahil olunca bu class'lar da Collection'ların arasında katılmıştır. Collection'ların daha yeni ve daha kullanışlı olmalarında rağmen Java'da bir çok yerde Vector ve Hashtable kullanılmaya devam edilmektedir. Bula 'eskimiş' değildirler. Bu iki class'ın öğrenilmesi Collection'ları öğrenmek için iyi bir başlama noktası olabilir. Vector Vector, temelde bir array'le aynı işlevi görür. Elemanlarına 'index'le erişilebilir. Ancak index olmadan erişmek de mümkündür. 'Araya şu elanı sok' veya 'Sonuna şu elemanı ekle' denebilir. Eleman sayısı başta belirlenmek zorunda değilidir. Eleman eklendikçe Vector büyür. Vector tanımlamak, Vector class'ına ait bir nesne tanımlamaktır : Vector v=new Vector(); Eleman eklemek te bu nesnenin bir method'unu çağırmak şeklinde olur : v.addElement("x"); aynı şekilde eklenmiş bir elemanını index'iyle almak için bir method çağrılır String v=(String) v.elementAt(3); Cast Burada 'cast' yapmak zorundayız. Vector ve Hashtable'ın, genel olarak bütün Collection'ların tip bilgisini kaybetmesi gibi bir durum söz konusudur. Collection'lar genel yapılar olduğu için içlerinde barındırdıkları nesnenin tipini (class'ını) bilmezler. Onlar sadece 'Object' tutarlar. Örneğin 'elementAt' methodu public Object elementAt(int index); şeklinde tanımlanmıştır. 'addElement' metodu da public void addElement(Object o); şeklinde tanımlanmış. 'String' class'ı bir obje olduğundan, yani her String aynı zamanda bir Object olduğundan eleman eklerken 'cast' sorunu çıkmaz. Ancak alırken String yerine object aldığımızdan ve her Object bir String olmayabileceğinden cast işlemi yapılmalıdır. Bir vectorden eleman silmek için 'removeElement' methodu bulunmaktadır. Eleman sayısını almak için size() diye bir method vardır. Bütün elemanlara erişim için bir döngü kurulabilir. Bir vektörün bütün elemanlarını ekrana basmak için for(int i=0;i<v.size();i++){ String item=(String) v.elementAt(i); System.out.println(item); } şeklinde bir kod yazılabilir. Enumeration Bir vector'deki bütün elemanlara erişmenin farklı yöntemi daha vardır : Enumeration kullanmak. Örneğin : Enumeration e=v.elements(); while(e.hasMoreElements()){ String item=(String) e.nextElement(); System.out.println(item); } şeklindeki kod, bütün elemanlara erişim yapar. Enumeration bütün elemanlara erişmek için kullanılan bir interface'dir. hasMoreElements() methodu elemanların bütün bitmediğini belirtir. nextElement() method'u da sıradaki elemanı verir. Bu method çağrılınca sıra bir sonraki elemana geçer. Başka bir deyişle, bu methd iki işi birden yapar. Sıradaki elemanı ver Sırayı bir sonraki geçir bu sayede method her çağrıldığıda farklı bir değer, yani sıradaki değeri verir. VectorTest.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.util.*; 2 public class VectorTest { 3 public static void main(String[] args){ 4 Vector v=new Vector(); 5 v.addElement("Bir"); 6 v.addElement("İki"); 7 v.addElement("Üç"); 8 v.addElement("Dört"); 9 v.removeElement("Bir"); 10 for(int i=0;i<v.size();i++){ 11 String item=(String) v.elementAt(i); 12 System.out.println(item); 13 } 14 Enumeration e=v.elements(); 15 while(e.hasMoreElements()){ 16 String item=(String) e.nextElement(); 17 System.out.println(item); 18 } 19 } 20 } Hashtable Bir grup değere 'index'le değil 'key'le erişmek için Hashtable class'ı kullanılır. İndex int tipinde bir sayıysa key herhangi bir object, örneğin bir string olabilir. Bu class her değeri bir key'le birlikte saklar ve o key verildiğinde o key karşılık gelen değeri verir. Hashable yaratmak için Hashtable ht=new Hashtable(); şeklinde bir ifade yeterli. Bir eleman eklemek için ht.put("mykey","myvalue"); yazılabilir. Bir değeri almak için de String val=(String) ht.get("x"); şeklinde bir ifade yeterli. Burada cast yapmak zorunlu, çünkü Hashtable'dan bir nesne Object tipinde alınıyor. Onu herhangi bir class tipinde kullanmak için cast etmek lazım. Hashtable'daki bütün değerleri almak için de Enumeration interface kullanılır. Hastable'lar index'le erişim yapmadıkları için bütün eleman ları almanın başka bir yolu yok. Bir döngü yapmak mümkün değildir. Enumeration'la erişimde elemanlar konulduğu sırada alınmayabilir. HashtableTest.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.util.*; 2 public class HashtableTest { 3 public static void main(String[] args){ 4 Hashtable ht=new Hashtable(); 5 ht.put("x","A"); 6 ht.put("y","B"); 7 ht.put("z","C"); 8 String val=(String) ht.get("x"); 9 System.out.println("val : "+val); 10 Enumeration e=ht.elements(); 11 while(e.hasMoreElements()){ 12 String item=(String) e.nextElement(); 13 System.out.println(item); 14 } 15 } 16 } Dosya Listesi VectorTest.java HashtableTest.java Package'ler ve Derleme Birimleri Package Birbiriyle işlev veya kullanım açısından ilişkili class'lar 'package' adı verilen bir birim altında birleştirilir. Bir class'ın ait olduğu package'i belirtmek için 'package' keyword'ü kullanılır. package mypackage; public class MyClass // .. } Bir class'ın diğer bir class'la aynı package'te olması, ona bazı avantajlar sağlar. Aslında bütün class'lar bir package'e ait olmak zorundadır. Hiç bir isim verilmediğinde o class isimsiz default package'de kabul edilir. Package'i belirtilmemiş bütün classlar aynı package'in class'ları sayılır. Bazı durumlarda sadece örnek olsun diye yapılıp hatalı (derlenemez durumda) bırakılan class, yine package'siz olan başka bir class'ın derlenmesini engelleyebilir. Import Bir class'ın kendisiyle aynı package'de olmayan class'ı kullanabilmesi için, class tanımından önce import etmesi gerekir. Bu sadece kullanılacan class'ların tam olarak hangi pakette olduğunu söylemek anlamına gelir. Bunun için 'import' keyword'ü kullanılır. package myanotherpackage; import mypackage.MyClass; public class MyAnotherClass // .. } Burada sadece kullanılacağı belirtilmektedir. Yoksa, import edilen class'ın import eden class'ın üzerine 'include' edilmesi (eklenmesi) sözkonusu değildir. 'java.lang' package'indeki class'ları kullanmak için import ifadesine gerek yoktur. Bu package olmadan hiç bir Java programı yapılamayacağı için, default olarak import edilmiş sayılır. '*' Operatörüyle Import Bir package'deki bütün class'ları import etmek için '*' operatörü kullanılabilir. package myanotherpackage; import mypackage.*; public class MyAnotherClass // .. } Bu işlem, altalta çok sayıda import ifadesi yazmaktan daha kolaydır. '*' operatörü kullanılıdığında bir çok class'ın gereksiz yere import edildiği gibi bir izlenim doğmakla birlikte, import işlemi aslında bir belirtmeden öteye gerçek bir 'içine alma' işlemi anlamına gelmediği için önemli bir performans kaybına yol açmaz. Sadece bazı programcılar okunurluğu arttırmak için böyle bir yola gitmektedirler. Fully-Qualified Name (Tam Nitelendirilmiş İsim) Aslında her class package ismiyle birlikte adlandırılır. Örneğin, 'mypackage' isimli bir package'de 'MyClass' isimli bir class'ın tam nitelendirilmiş ismi 'mypackge.MyClass' dır. Import ifadesi, sadece programcıyı her class ismini böyle uzun yazmaktan kurtarmaktadır. 'java.awt' package'inde olan Button adlı class'ın bir instance'ını 'import java.awt.*' diyerek kullanırsak Button b=new Button(); şeklinde yaratabiliriz. Hiç 'import' kullanmayarak aynı ifadeyi java.awt.Button b=new java.awt.Button(); şeklinde de yazabiliriz. Bu şekilde paket ismiyle birlikte verilen class isimlerine fully-qualified name denir. Alt Package'ler Bazı durumlarda çok fazla class içermemesi için bir package alt birimlere bölünebilir. Örneğin, görsel bileşenler içeren 'java.awt' package'ın image'larla ilşkili olan 'java.awt.image' şeklinde bir alt package'i bulunmaktadır. Aslında alt package'in teknik anlamda üst package'in 'içinde' olması sözkonusu değildir. Alt package isimlendirmesi iki 'ayrı' package'i sadece anlamca ilişkilendirmektedir. Bir class'ta üst package'i import etmek, otomatikman alt package'lerin de import edileceği anlamına gelmez. Örneğin, 'java.awt.*' ifadesi 'java.awt.event.*' ifadesini içermez. Bu alt package'den herhangi bir class kullanılacaksa ayrıca import edilmesi gerekir. Standart Package'ler Java'nın kendi API'ı (Application Programming Interface - Uygulama Programlama Arayüzü'ü) bir çok class'dan oluştuğu için bir çok package altında gruplandırılmıştır. Bunların çoğu 'java.' ve 'javax.' la başlar. 'javax' öneki daha çok, sonradan extension (ekleme) package'ler için kullanılır. Önceden 'extension' olan package'ler daha sonra standart API'a dahil olabilmektedir. Java'nın standart package'leri benzer ve ilişkili class'lardan oluşur. Her package'de bulunan class'ların ezberlenmesine gerek yoktur. Sadece her package'de ne tür class'ların bulunduğu öğrenilmesi yeterlidir. Örneğin, arayüzle ilgili class'lar 'java.awt'dedir. Görsel bir bileşen olarak Button bu package'tedir. Yine görsel bir bileşen olan text alanı'nın (TextArea'nın) da bu package'de olması gayet doğaldır. Naming Convention (İsimlendirme Geleneği) Package isimlerinin rastgele verilmesi, bir sistemde farklı kurumlara ait package'leri bulunması durumunda 'name collision' (isim çarpışması) adı verilen bir sorun yaratabilmektedir. Aynı package ismini başka bir kurum da kullandıysa ne olacak? Örneğin siz package'in adını 'myapplets' koydunuz. Sistemde aynı isimde başka bir kuruma ait bir package daha var tesadüfen. Java önce hanginizinkini bulursa onu yükler. Sizinki önce bulunuyorsa onların package'i doğru çalışmaz, onlarınki önceyse sizinki. Bu sorunlarla karşılaşmamak için package isimlerinde standart bir yöntem uygulanır. Bir kurum, sahip olduğu İnternet domain ismini tersten yazarak package isimlerinin önüne ekler. Örneğin 'godoro.com'a sahip olan kurum veya kişiler, chat appletlerini 'com.godoro.chat' diye bir package'e koyabilirler. ChatApplet isimli biri class için fully-qualified class name 'com.godoro.chat.ChatApplet' şeklinde olur. Java'yı ortaya çıkaran 'Sun' firması da kendi package'lerini 'com.sun.' şeklinde başlatmaktadır. ÖZel kuruluşlar com., ticari olmaytan kurumlar da org. ile başlarlar. Aynı Package'teki Class'lar Aynı package'deki class'lar birbirlerinin private olmayan property ve methodlarına, onlar public olmasala bile ulaşırlar. Ayrıca, aynı package'deki class'ların birbirlerini 'import' etmeleri gerekmez. Derleme Birimi Class'lar '.java' uzantılı dosyalarda bulunabilirler. Bu dosya aslında bir compilation unit (derleme birimi)dir (). Bir dosyada birden fazla class alt alta tanımlanabilir. Ancak en fazla bir tanesi 'public' olabilir. Ve dosyanın (derleme biriminin) adı bu public class'ın adıyla aynı olmalıdır. Bu class derleme biriminin asıl class'ıdır ve adı değiştirildiğinde dosyanın da adı değiştirilmelidir. Tek dosyada bulunan class'lar derlendiğinde her biri için ayrı .class üretilir. Yani derlendikten sonra class'lar birbirinden ayrılırlar. Bir derleme biriminde sadece bir tane class bulundurmak, zorunlu olmasa da bir gelenek halini almıştır. Encapsulation Encapsulation Kavramı Her class çeşitli üyelerden (property ve method'lardan) oluşur. Hemen hemen bütün class'lar başka bir class tarafından kullanılmak amacıyla üretildiğinden, bazı üyeler sadece dışarıdan kullanılmak üzere hazırlanmıştır. Buna karşı bazı property ve method'lar, diğerlerine yardımcı olmak, sadece onlar tarafından class'ın iç işlerinde kullanılmak için yazılırlar. Belli bir class'ı kullanan class'ın bunları görmesi veya bilmesi gerekmez. Hatta bazı durumlarda property ve method'ların sadece ufak bir kısmı dışarısı tarafından kullanılır. Bir insanın belli bir class'a baktığında üyelerden hangisi kendisinin işine yarar, hangisi sadece başka methodlarda kullanılmak için yapılmıştır ve class'a özel'dir anlaması çok zor olabilir. Bazı durumlarda da güvenlik ve sağlamlık sağlamak amacıyla bir class'ı kullanan class'ın bazı property'leri değiştirmesi ve bazı methodlara erişmesi engellenmek istenebilir. Bazı property ve methodların ait olduğu class'ın dışında erişimini sınırlama özelliğine 'encapsulation' (kapsülleme) denir. Encapsulation sağlamak için private, public ve proteced sözcükleri kullanılır. Bunlara access modifier (erişim değiştirici) denir. Hiç birini kullanmak da bu bağlamda belli bir tercih anlamına gelir. Default Access Hiç bir access modifier kullanılazsa, yani bir property ve methodun başında private, protected ve public keyword'lerinden hiç biri kullanılmazsa bu üye 'package private' olur. Yani ona sadece aynı package'deki diğer class'lar erişebilir, diğer package'lerdekiler erişemez. Public Access Sistemdeki bütün class'ların erişebilmesini sağlamak için 'public' erişim değiştiricisi kullanılır. Herkesin erişmesinde sakınca bulunmayan üyeleri için kullanılır. Genellikle bu değiştirici özellikle başkaları erişsin diye yazılan property ve method'lar için kullanılır. Bir nesnede ne kadar az public değişken varsa dışarıya o kadar sade görünür ve o kadar kolay kullanılır. O nesneyi kullananlar gereksiz bir çok üye arasında dolaşmak zorunda kalmazlar. Private Access Bir property veya method'un sadece tanımlandığı class'dan erişilebilmesini, başka bir deyişle, o class dışındaki bütün class'lardan (aynı package'de olsalar bile) erişiminin yasaklanmasını sağlamak için 'private' keyword'ü kullanılır. Bir değişkenin dışardan görülebilmesini ancak değiştirilemesini veya değiştirme işleminin class'ın kontrolünde yapılmasını sağlamak için standart bir yöntem izlenir. Bir property'yi readonly (salt okunur) yapmak için, o property private yapılır. Ona erişmek için bir tane public method yazılır. Bu şekilde dışarından property'nin value'si dolaylı olarak öğrenilmiş olur. Göster Gizle Kopar Satır Gizle Satır Göster 1 public class MyDiscreetClass{ 2 private int value=3; 3 public int getValue(){ 4 return value; 5 } 6 } Bu class'tan yaratılmış bir nesne'yi kullanan örnek yapalım. MyDiscreteUserClass.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class MyDiscreteUserClass{ 2 public static void main(){ 3 MyDiscreetClass d=new MyDiscreetClass(); 4 int v=d.getValue(); 5 System.out.println("Value : "+v); 6 } 7 } Buradaki value private olduğu için int v=d.value; yazarsak derleyici hata verir. Property orada olduğu halde artık erişilmez hale gelmiştir. Ama değeri öğrenmek için getValue() methodu kullanılabildiği için bir programın işleyişini bozmaz. Biz bu değeri değiştirmek istersek : d.value=5; derleyici yine hata verecektir. Bu şekilde class kendi property'sini korumuş oluyor. Bir değişkenin hem okunması hem de değiştirilmesi istenip sadece bunun kontrollü bir şekilde yapılmasını istersek yine property'yi private tutarız ve hem erişebilmek için hem de değiştirebilmek için iki ayrı method yazarız. Bir değerin eksi olmamasını sağlayan bir class yapalım : MyControlledClass.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class MyControlledClass{ 2 private int value=3; 3 public int getValue(){ 4 return value; 5 } 6 public void setValue(int v){ 7 if(v>0){ 8 value=v; 9 }else{ 10 value=-v; 11 } 12 } 13 } Bu değeri değiştirip sonrsa yeni değeri alan bir program yazalım. MyControlledUserClass.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class MyControlledUserClass{ 2 public static void main(){ 3 MyControlledClass d=new MyControlledClass(); 4 d.setValue(-7); 5 int v=d.getValue(); 6 System.out.println("Value : "+v); 7 } 8 } Bu program, kendisinin değiştirmeye (kullanılan class açısından bakarsak, 'bozmaya') çalıştığı değerin hala sağlam olduğunu ortaya koymaktadır. Protected Access Bazı durumlarda bir property veya method'un dışarıya kapalı olmasını ancak o class'ı extend edenlere açık olması istenebilir. Bu durumda 'protected' erişim değiştiricisi kullanılır. Bir class diğerini extend ederse, onun bütün public property'lerin erişebilir hale gelir. Zaten bunlara her class'ın erişebilmektedir. Hiç bir private property extend eden class'a geçmez. Bunlar diğer bütün class'lara da kapalıdır. Ancak protected property ve methodlar dışarıya kapalı oldukları halde, extend edilen class bunlara erişim hakkına sahiptir. Bu keyword, belli bir property veya method'un sadece onu extend eden class'ları ilgilendirmesi durumunda kullanılır. Erişim değiştirici olarak protected verilmiş property veya method'lara o class'la aynı package içerisindeki bütün class'lar tarafından da erişilebilir. Erişim Düzeyleri Sıralaması Encapsulation düzeyleri için public > protected > 'default' > private şeklinde bir sıralama yapılır. Büyük olan düzey küçük olanların haklarını da kapsar. Bir property'nin public olup private özelliği içermemesi, yani tanımlandığı class'tan erişilemez ama onun dışındaki bütün class'lardan erişilmesi gibi bir durum söz konusu olamaz. Dosya Listesi MyDiscreetClass.java MyDiscreteUserClass.java MyControlledClass.java MyControlledUserClass.java Inheritance (Kalıtım) Inheritance Kavramı Bir class'ın başka bir class'daki property ve method'lara sahip olmasına inheritance denir.. Belli bir class, daha genel bir kavramı ifade eden class'ın üyelerine sahip olarak, onları tekrar tanımlamak zorunda kalmaz. Bir class'ın diğerindeki özellikleri miras olarak alması için kullanılan keyword 'extends' dir. Anlam olarak "Bu class şu class'ı 'genişletir' yani ondaki property ve methodları alır ve yenilerini ekler" demektir. Inheritance, bazı durumlarda başka birinin yazdığı class'a bazı eklemeler yaparak belli bir işlem için kullanılır hale getirmek için kullanılabilir. Böylelikle sadece o class'ta olmayan property ve methodları eklemek suretiyle çok kısa sürede gelişmiş bir class sahibi olabilir. Bazen de ortak bir çok özellik içeren iki nesnede de aynen bulunan property ve methodları tanımlamaktan kurtulmak için kullanılabilir. 'Extends' Kullanımı Diyelim ki bize bir küp ve küre'yle hacim, yüzey alanı, kütle ve ağırlık gibi hesaplamalar yapmamız gerekiyor. Bir çok özellik bu iki nesnede ortaktır. İkisinde de bir özkütle vardır. Hacim hesaplama teknikleri değişebilir ama kütle hesap teknikleri değişmez. Her iki cisim için de kütle, özkütle ile hacmin çarpımıdır. Bu iki cisim için SimpleSphere ve SimpleCube gibi iki class yapacaksak, ortak özellikleri içeren SimpleBody diye bir class yapmak akıllıca olur. Şimdilik sadece SimpleSphere'e ihtiyacımız varsa dahi, sonradan SimpleCube veya başka bir cismin gerekebileceğini düşünerek bir base class yapmak da faydalı olabilir. Göster Gizle Kopar Satır Gizle Satır Göster 1 public class SimpleBody{ 2 private double density=1.0; 3 public SimpleBody(){ 4 } 5 public SimpleBody(double d){ 6 setDensity(d); 7 } 8 public void setDensity(double d){ 9 density=d; 10 } 11 public double getDensity(){ 12 return density; 13 } 14 } Görüldüğü gibi, cismin yoğunluğunu belirten bir property ve bunula ilgili iki method var. Bu class'ı 'extend' eden SimpleSphere adlı bir class yapalım. SimpleSphere.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class SimpleSphere extends Body{ 2 public double radius=1.0; 3 public SimpleSphere(double d,double r){ 4 super(d); 5 radius=r; 6 } 7 public double getVolume(){ 8 return (3.14 * radius * radius * radius )/3; 9 } 10 } Yazdığımız SimpleSphere class'ın radius property'si dışında, density property'si de vardır. Şöyle bir kod parçası geçerlidir : SimpleSphere s=new SimpleSphere(); s.setRadius(3.6); s.setDensity(1.2); Extend eden class'a subclass, extend edilen class'a da super class (veya base class) denir. Super Class'ın Constructor'unun Kullanımı Bir class'ı extend eden class'ın constructor'u extend ettiği class'ın constructor'unu 'super()' şeklinde çağırabilir. Bu şekilde super class'a veri aktarılmış olur. SimpleSphere class'ına bir constructor ekleyelim : public SimpleSphere(double d,double r){ super(d); setRadius(r); } Bu şekildeki constructor'u kullanmak istersek SimpleSphere sphere=new SimpleSphere(3.6,1.2); biçiminde bir kod yazmak yeterli olacaktır. Bir constructor'ın diğerini çağırması durumunda super ifadesi kesinlikle ilk satırda belirtilmelidir. Herhangi bir kod parçası yazıldıktan sonra super class'ın bir constructor'u çağrılamaz. Super class'ın constructor'u açık olarak çağrılmadıkça, parametresiz olan super() constructor'un çağrıldığı varsayılır. Super constructor'un böyle bir constructor'u yoksa mutlaka parametreli bir constructor çağrılmalıdır. Aksi takdirde derleyici hata verir. Super Class'larda Protected Property'ler Base class'da 'private' olan property'lere subclass'tan erişilemez. Erişilmesi için 'public' yapılması durumunda da ilgili üye herkese açık hale gelecektir. Sadece extend eden class'ın erişimini sağlamak için 'protected' erişim değiştiricisi kullanılır. SimpleBody class'ında 'density' property'si protected olmalıdır. Overriding (Ezme) Bir subclass super class'ının bir methodunun davranışını yeniden yazabilir, yani super'dekini ezebilir. Buna overriding denir. Bunun için aynı üst class'ın method'unun signature'uyla aynı olmalıdır. Bu işlem bazen methodun tamamen değiştirme, bazen de sadece bir ekleme yapma şeklinde yapılır. SimpleSphere class'ında, SimpleBody class'ında density property'sini belirleyen setDensity() method'u, negatif değer kontrolü yapacak şekilde değiştirmek için public void setDensity(double d){ if(d>=0){ density=d; }else{ density=0.0; } } biçimde bir kod yeterlidir. SimpleSphere class'ında setDensity() methodu çağrıldığında bu yeni method geçerli olacaktır. Elbette bu değişiklik SimpleBody class'ı ve bu class'ı extend eder diğer class'ları bağlamaz. Onlar hala üsteki methodu çağırırlar. Override eden method, override edilen methodu çağırabilir. Ancak ikisinin de adı da parametreleri de aynı olduğu için super anahtar sözcüğü kullanılır. public void setDensity(double d){ if(d>=0){ super.setDensity(d); }else{ super.setDensity(0.0); } } Super class'da olan bir method'un ismiyle aynı farklı parametreler alan bir method yazlıabilir. Ama bu durumda overriding değil overloading yapılmış olur. Yani var olan bir method'u değiştirmek yerine yeni bir method eklenmiş olur. İlk method çağrıldığında yine eskisi gibi çalışır. Multiple Inheritance (Çoklu Kalıtım) Java'da 'multiple inheritance', yani bir class'ın iki veya daha çok class'ı extend etmesi, onların property ve method'larını miras alması mümkün değildir. C++ gibi diğer nesneye yönelik dillerde bu mümkündür ama Java'da kafa karışıklığına, çalışma zorluğuna, birbirine girmiş yapılar yaratmaya neden olduğu için izin verilmemiştir. Java'daki single inheritance (tekli inheritance)da hangi class'ın hangisini extend ettiği bir ağaç yapısı şeklinde net bir şeklide görülmektedir. Aslında bu yazılım tasarımı açısından da gereklidir. Örneğin bir hayvan hem memeli hem de kuş olmaz. Hem balık hem memeli olmaz. Hatta yarasa uçsa bile, balina yüzse bile onlar birer memelidir. Yarasanın kuşlar gibi uçtuğunu görüp onu hem memeli hem kuş saymak ne kadar yanlışsa, bir class'ı iki ayrı class'ın özelliklerine birden sahip olması gerektiğini düşünmek o derece yanlıştır. Eğer tasarımınız bunu zorunlu kılıyorsa ya yanlış tasarım yapmışsınızdır ya yanlış çözümleme yapmışsınızdır. Çoklu kalıtımın gerekli gibi göründüğü durumlarda başka çözüm yolları devreye girer. Bunları programcı ve sistem tasarımcıları Java'da bilgi ve deneyimlerini arttırdıkça öğrenebilirler. Örneğin iki class'ı extend etmek yerine birini extend etmek, diğerini bir property olarak tanımlamak ve kullanmak mantıklı bir çözüm olabilir.. Dosya Listesi SimpleBody.java SimpleSphere.java Interface'ler ve Abstract Class'lar Interface Kavramı Java'da interface, bir class'ta olması gereken method ve property'leri tanımlayan yapıdır. Kendisi normal bir class değildir, sadece neyin yapılacağını göstermekte, ancak nasıl yapılacağını göstermemektedir. Örnek olarak, bir madde'de ne gibi işlevler ve özellikler olması gerektiğini belirten bir interface yazalım. Göster Gizle Kopar Satır Gizle Satır Göster 1 public interface Matter{ 2 public double getVolume(); 3 public double getMass(); 4 } Bu ifade, 'bir maddenin yoğunluğu, hacmi ve kütlesi olur' demenin Java'daki yoludur. Ancak görüldüğü gibi maddenin yoğunluğu nasıl hesaplanır, kütlesi nasıl verilir, hiç bir şekilde belirtmemektedir. Sadece ne olması gerktiğini söylemektedir. Interface'in Implementation'u Bir class'ın interface'deki bütün method'ları içerdiğini, gerçekleştirdiğini belirtmesine implementation denir ve 'implements' keyword'üyle kullanılır. CubeMatter.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class CubeMatter implements Matter{ 2 public double density=1.0; 3 public double edge=1.0; 4 public double getDensity(){ 5 return density; 6 } 7 public double getVolume(){ 8 return edge*edge*edge; 9 } 10 public double getMass(){ 11 return density*edge*edge*edge; 12 } 13 } Burada "Küp diye bir nesnemiz var ve o bir maddedir, yani bir maddede olabilecek bütün nitelikler onda da bulunur." demiş olduk ve bunların nasıl hesaplandığını gösterdik. Aynı interface'i implement eden başka bir class'da yapılabilir. SphereMatter.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class SphereMatter implements Matter{ 2 public double density=1.0; 3 public double radius=1.0; 4 public double getDensity(){ 5 return density; 6 } 7 public double getVolume(){ 8 return (3.14 * radius * radius * radius )/3; 9 } 10 public double getMass(){ 11 return density*(3.14 * radius * radius * radius )/3; 12 } 13 } Görüldüğü gib bu class'da aynı interface implement ediyor. Ancak hacim ve kütle hesaplaması çok değişik. Absract Class'lar Bazı methodlarını implement etmiş, bazılarının imlementation'unun kendisini extend eden class'a bırakmış olan class'a abstract class denir. Bu tip class'lar en çok, iki class'ın ortak methodlarından bazılarının implementation'u da aynı olması durumunda kullanılır. Örneğin bir küp için de kütle, hacim ve yoğunluğun çarpımına eşittir, bir küre için de. Ancak yaptığımız iki nesnede de bu ortak özelliği kullanamıyor. Her birisi kütle hesaplamasını kendisi yapılıyor. Matter interface'ini implement eden ne kadar class varsa bu işlem o kadar tekrarlanacak demektir. Bu 'ortak' işlemi bir kere yapıp, hep onun kullanılmasını sağlamak mümkündür. Ancak çözülmesi gereken bir sorun var : Her class'ın kütlesi aynı şekilde hesaplanıyor bunu hesaplamak için gerekli hacim değerini bilmiyoruz ve her class kendisine göre değişik bir şeklide hesaplıyor. Bu sorun abstract method kullanarak çözülebilir. Body.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 abstract public class Body{ 2 public double density=1.0; 3 public Body(double d){ 4 density=d; 5 } 6 public double getDensity(){ 7 return density; 8 } 9 public double getMass(){ 10 return density*getVolume(); 11 } 12 abstract public double getVolume(); 13 } Burada abstract bir Body class'ı yarattık. Bu class, hem Cube'ün hem de Sphere'in ortak özelliklerini içermektedir. Zaten density property'si ikisinde de ortaktır. Bu şekilde inherintace yoluyla Cube ve Sphere'a geçebilir. Burada getVolume() method'u abstract bırakılmıştır. Yani implement edilmemiştir. Çünkü volume hesaplamak için her nesne farklı bir method kullanmaktadır. Ancak getMass() implement edilmiştir. Çünkü kütle yoğunlukla hacmin çarpımıdır. Burada object-oriented porgramlama dışındaki bir teknikle asla yapılamayacak bir işlem bulunmaktadır. Bir method (getMass()) henüz yazılmamış bir mehodu (getVolume()'u) kullanarak bir işlem yapabilmektedir. Bu şekilde her cisim için ayrı ayrı hesap yapmaktan kurtulmuş olduk. Şimdi küp ve küre için yeni class'lar yapalım : CubeBody.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class CubeBody extends Body{ 2 public double edge=1.0; 3 public CubeBody(double d,double e){ 4 super(d); 5 edge=e; 6 } 7 public double getVolume(){ 8 return edge*edge*edge; 9 } 10 } Görüldüğü gibi bu class kütle hesabını yapan getMass() diye bir method'u yazmak zorunda kalmadı. Çünkü ona miras yoluyla sahip olmuştur. Aşağıdaki gibi kod yazılabilir : CubeBody cube=new CubeBody(2.5,10.2); double mass=cube.getMass(); System.out.println("Mass : "+mass); Aynı şekilde yeni bir küre class'ı yazalım. SphereBody.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class SphereBody extends Body{ 2 public double radius=1.0; 3 public SphereBody(double d,double r){ 4 super(d); 5 radius=r; 6 } 7 public double getVolume(){ 8 return (3.14 * radius * radius * radius )/3; 9 } 10 } Tıpkı küp gibi küre de artık kütle hesabını, hiç bir ek kodlama yapmadan yapabilmektedir. Hem Extend Hem Implement Etmek Bir class sadece bir class'ı extend edebilir. Ancak aynı anda bir class'ı extend edip bir veya daha fazla interface'i implement edebilir. Çünkü 'extends' keywordünün aksine, 'implements' demek yoluyla bir class'ın aldığı hiç bir şey yoktur. Sadece bazı method'ları implement etmeyi taahüt etmektedir. Bir Cube class'ı hem Body classını extend edebilir hem de Matter inetrface'ni implement edebilir. public class Cube extends Body implements Matter{ // ... } Base class'ın bir interface'i imlement etmesi durumda subclass'da etmiş sayılır. Yani public class Body implements Matter{ // ... } dersek public class Cube extends Body{ // ... } dememiz yeterlidir. Cube class'ı Matter'i implement etmiş sayılır. Yani implementation'u da miras yoluyla almış demektir. Interface'in Kullanım Özellikleri Interface'ler bütün methodları absract olan bir absract class gibi düşünülebilirler. Ancak class'lardan ayrılan başka özellikleri vardır. Ayrıca söylensin veya söylenmesin bütün method ve property'ler public sayılır ve başların proteced veya private gibi anahtar sözcükler alamazlar. Interface'lerde bütün propertyler public, final ve static'tir. O yüzden interface'lerde tanımlanan property'ler bir veya daha fazla class'da kullanılan sabitler için kullanılır. MathConstants.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public interface MathConstants{ 2 double PI=3.14; 3 } Circle.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class Circle implements MathConstants{ 2 private double radius=1.0; 3 public getCircumference(){ 4 return 2*PI*radius; 5 } 6 } görüldüğü Circle classında tanımlanmadığı halde PI değişkeni, sadece MathConstants interface'ini implement ettiği için erişilebilir durumdadır. Bu interface'i implement eden Cylinder adlı bir class'da aynı şekilde PI'a erişebilir. Bu anlamda PI bir sabittir. Ama PI property'si sadece implement edilen class'lar tarafından görülmekte olduğundan global değildir. Zaten Java'da global değişken ve sabit yoktur. Onlara ihtiyaç duyulan yerlerde interface kullanılır. Ancak yine de değişken (dah doğrusu sabit) bir yere (interface) ait olduğundan global olmasından doğacak sakıncalardan kurtulunabilir. Örneğin Math.PI ve GreekLetters.PI yazılabilir, ikisi farklı değerler taşıyabilir. Dosya Listesi Matter.java CubeMatter.java SphereMatter.java Body.java CubeBody.java SphereBody.java MathConstants.java Circle.java Polymorphism (Çok Biçimlilik) Polymorphism (Çok Biçimlilik) Nesneye yönelik programlamada polymorphism , nesnelerin içeride farklı çalışmalarına rağmen dışarıdan aynı biçimde görünmelerine denir. Bu şekilde, bir grup nesneyi kullanan class'lar implementation'la ilgili detayları bilmek zorunda kalmazlar, içerideki değişikliklerden etkilenmeden çalışmaya devam ederler. Aynı class'ı extend eden veya aynı interface implement eden class'lar standart bir şekilde erişilebilme özelliklerine sahip olurlar. Polymorphism Olmadan Kodlama Bir miktar kübün toplam kütlesini hesaplamak istediğimizi düşünelim. Küp class'ının ana hatları şöyle olsun : public class Cube{ // ... public double getMass(){ // ... } } Bu class'tan yaratılmış instance'ların kütlelerini toplayan bir method ve program yazalım. Göster Gizle Kopar Satır Gizle Satır Göster 1 public class CubesMassCalculator{ 2 public static double calculateTotalMass(Cube[] cubes){ 3 double total=0.0; 4 for(int i=0;i<cubes.length;i++){ 5 total+=cubes[i].getMass(); 6 } 7 return total; 8 } 9 public static void main(String[] args){ 10 Cube[] cubes=new Cube[3]; 11 cubes[0]=new Cube(2.2,10.5); 12 cubes[1]=new Cube(3.1,6.1); 13 cubes[2]=new Cube(5.6,1.2); 14 cubes[3]=new Cube(9.3,6.1); 15 cubes[4]=new Cube(4.0,3.7); 16 double total=calculateTotalMass(cubes); 17 System.out.println("Total Mass : "+total); 18 } 19 } Aynı programı küreler içinde yazabiliriz. Sphere class'ımız da aynı biçimde tanımlanmış olsun : public class Sphere{ // ... public double getMass(){ // ... } } Ancak calculateTotalMass() method'unu şu biçimin de tanımlamalıyız : public static double calculateTotalMass(Sphere[] spheres){ // .. } Peki ya bir nesne dizimiz değişik cisimlerden oluşuyorsa? Örneğin üç tane kübümüz iki tane küremiz varsa ne olacak? Onun için şöyle bir method daha yazmalıyız. public static double calculateTotalMass(Cube[] cubes,Sphere[] spheres){ // .. } Ya dikdörgenler prizması ve piramit gibi cisimlerimiz de varsa ne yapacağız? Her biri için ayrı toplamlar alan bir sürü method yazmaktan başka çaremiz kalmayacak. İşte polymorphism burada devreye giriyor. Ploymophism'den Yararlanma Eğer iki class'da ortak bir method varsa, bu ikisinin de temel alacağı Body şeklinde bir class yapmak gereklidir : class Body{ // ... public double getMass(){ // ... } } class Cube extends Body{ // ... } class Sphere extends Body{ // ... } Çeşitli tipte cisimlerden olişan bir dizinin toplam kütlesini hesaplayan bir class yapalım. BodiesMassCalculator.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 public class BodiesMassCalculator{ 2 public static double calculateTotalMass(Body[] bodies){ 3 double total=0.0; 4 for(int i=0;i&amp;bodies.length;i++){ 5 total+=bodies[i].getMass(); 6 } 7 return total;<noframes></noframes> 8 } 9 public static void main(String[] args){ 10 Body[] bodies=new Body[3]; 11 bodies[0]=new Cube(2.2,10.5); 12 bodies[1]=new Sphere(3.1,6.1); 13 bodies[2]=new Cube(5.6,1.2); 14 bodies[3]=new Cube(9.3,6.1); 15 bodies[4]=new Sphere(4.0,3.7); 16 double total=calculateTotalMass(bodies); 17 System.out.println("Total Mass : "+total); 18 } 19 } Görüldüğü gibi tek method çeşitli cisimlerin kütlelerini toplayabiliyor. Her cismin farklı bir hacim ve kütle hesaplama şekli olduğu halde. Bunun için tek gerekli şart Cube ve Sphere class'larının Body class'ını extend etmeleri ve Body class'ında getMass() şeklinde bir method olmasıdır. Pyramid diye Body'yi extend eden bir class yapıp, dizinin dördüncü elamanı olarak verirseniz calculateTotalMass() methodu yine toplam kütleyi doğru olarak hesaplayacaktır. Çünkü o zaten Sphere'ı da Cube'ü de tanımamaktadır. Sadece Body class'ını tanımaktadır ki, bir cismin kütlesi olması, onun kütlesini toplama dahil etmesi için yeterlidir. Interface ve Abstract Class'larla Polymorphism Polymorphism özelliğini kullanmak için, class'ların belli bir concrete base class'a sahip olmaları gerekmez. Base class'ları abstract olabilir. Hatta ortak kullanılan method'un kendisi bizzat abstract olabilir. Bu biçimde interface'lerin de kullanılması mümkündür. Aynı interface'i implement eden her class aynı type'da kabul edilir. Yukarıdaki örnekteki class'lar abstract class Body{ // ... abstract public double getMass(); } class Cube extends Body{ // ... public double getMass(){ // ... } } class Sphere extends Body{ // ... public double getMass(){ // ... } } şeklinde de tanımlanmış olsalar aynı şekilde kullanılabilirdi. Body'nin bir class değil de bir interface olarak tasarlanması durumunda da aynı şey geçerlidir. interface class Body{ public double getMass(); } class Cube implements Body{ // ... public double getMass(){ // ... } } class Sphere implements Body{ // ... public double getMass(){ // ... } } Dosya Listesi CubesMassCalculator.java BodiesMassCalculator.java Stream'ler Input ve Output Stream'leri I/O (Input/Output) bilgisayarın hafızası kadar hızlı olmayan bir birimde belli bir verinin okunması ve yazılması işlemidir. Örnek olarak bir disk üzerindeki dosyalar ele alınabilir. Disk üzerindeki dosyalara erişim hafızadaki bilgilere erişim kadar kolay olmaz. Bir dosyadan okuma veya dosyaya yazma yavaş yavaş (hatta bazen byte byte) yapılır. Ayrıca network bağlantıları da aynı şekilde değerlendirilmelidir. Zira network üzerinden başka bir makineyle okuma/yazma yapmak elbette yavaş yavaş gerçekleştirilir. Bazen okunacak veri hazır olmayabilir veya yazılacak birim henüz yazılan datayı aynı hızda alacak durumda olmayabilir. Böyle durumlarda Stream kavramı gündeme gelir. Okumak için InputStream ve yazmak için de OutputStream kullanılır. Streamlar 'byte' konuşurlar. Bir dosya okumak için, FileInputStream ve bir dosyaya yazmak için FileOutputStream kullanılır. InputStream'den Okuma Bir dosyadan byte byte okuma yapıp ekrana basan bir program yazalım. Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.io.*; 2 public class InputStreamer{ 3 public static void main(String[] args) 4 throws IOException 5 { 6 String filename="c:\\myfolder\\myfile.ext"; 7 FileInputStream in=new FileInputStream(filename); 8 int c; 9 while ((c = in.read()) != -1){ 10 System.out.print(c); 11 } 12 in.close(); 13 } 14 } InputStream'in read() methodu bir int okur ancak bu aslında bir byte'tır. Okuma yapmayı bitirince -1 döndürür. Burdan artık stream'den gelecek veri olmadığını anlarız. OutputStream'e Yazma. Elimizdeki bir karakter dizisini bir dosyaya byte byte yazan bir program yapalım. OutputStreamer.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.io.*; 2 public class OutputStreamer{ 3 public static void main(String[] args) 4 throws IOException 5 { 6 String filename="c:\\myfolder\\myfile.ext"; 7 8 9 10 11 12 13 14 } 15 } FileOutputStream out=new FileOutputStream(filename); char[] cs=new char[]{'J','a','v','a'}; for(int i=0;i<cs.length;i++){ char c=cs[i]; out.write(c); } out.close(); OutputStream'in write() methodu veriyi yazmak için kullanılır. File olmayan Stream'ler Bİr file'dan okumak için niye hem InputStream hem de FileInputStream'a ihtiyaç duyulduğu sorusu akla gelebilir. InputStream genel bir kaynaktan byte byte okumaya yarar. FileInputStream'se file'dan okuma yapmak içindir. Aslında FileInputStream, InputStream'i extend eder, yani onun özel bir halidir. FileInputStream dışında network'ten okumak için veya bir ses cihazından okumak için, veya herhangi bir cihazdan okumak için kullanılan InputStream'ler bulunur. Aslında FileInputStream in=new FileInputStream(filename); yerine InputStream in=new FileInputStream(filename); da yazılabilirdi. Okuma kodu değişmezdi. Aynı şekilde AudioInputStream'la InputStream in=new AudioInputStream(...); gibi bir kod yazarak ses cihazından veya dosyasından okuma yapabiliriz. Kod yine değişmez. Bütün bunlar OutputStream'ler için de söylenebilir. Java'nın I/O kütüphanesindeki karmaşıklığın sebeplerinden biri stream'lerin genel bir çözüm içermesi, sadece dosyalarla sınırlandırılmamış olmasıdır. Rasgele Erişimli Dosyalar Hem okuma hem yazma yapma ihtiyacı olduğunda kullanılabilecek bir RandomAccessFile adında bir class vardır. Ancak normal şartlarda aynı anda hem okuma hem yazma gerekmez. Bu class bunun gerekli olduğu nadir durumlarda kullanılır. Hem input stream'lerde olan read methodları hem de output stream'lerde olan write method'ları vardır. Buffer'lı Stream'ler Input ve output stream'ler byte byte okuma yaptıkları için oldukça yavaş çalışırlar. Örneğin diskten bir dosya okunacaksa, bir byte okumak için bile, manyetik ve mekanik esaslarla çalışan disk cihazının okuma yapan kafası diskin ilgili bülümüne yerleştirilecek ve sonra okuma yapılacaktır. Aynı yerden 1000 byte'lık bir veri okunsa da aynı işlem 1000 kere tekrarlanacaktır. Disklerde bu durumu hafifletecek bazı özellikler mevcuttur ancak yazılımda da yapılması gereken bazı işlemler vardır. Burada 'buffering' (tamponlama) devreye girer. Okuma yaparken bir byte bile okunacaksa belli bir miktar (örneğin 1024 tane) byte hafızaya, yani bir buffer' (tampon)'a okunur. İkinci byte okunurken diskten değil buffer'dan okunur. Buffer'daki sayı tükenene kadar böyle gider. Ne zaman ki artık bufferda hiç bir şey kalmaz, gidilir tekrar diskten okuma yapılır. Tabii yine bir byte değil buffer size'ı kadar. Yazma yaparken de buffer kullanılabilir. Belli bir size'da buffer açılır ve stream'a yazılan değerler diske değil bu buffer'a yazılır. Ne zaman ki buffer size'ı dolar, bütün buffer içeriği diske tek seferde yazılır. Bu durumda disk açısından tek yazma işlemi gerçekleştiğinden sistem hızlı çalışır. Ancak yazma yaparken bir sorun var : Ya buffer dolup diske yazma yapmadan programa bir şey olur da işlem yarım kalırsa? Çünkü buffer'da diske yazılmayı bekleyen byte'lar diskteki dosyada yok. Veri eksik kalmış oluyor. O yüzden, öncelikle buffer size'ı küçük tutlmalıdır. Ayrıca 'flush' diye bir işlem vardır. Bu işlem 'buffer'daki veriyi hemen diske yaz, buffer dolmuş olsun olmasın' demektir. Programcı belli bir anlam bütünlüğü olan veriyi yazdıktan sonra flush() method'unu çağırarak buffer'ı diske yazar. Programcı bu buffer işlemlerini kendi yapmak zorunda değildir. Bu işler çin BufferedInputStream ve BufferedOutputStream vardır. Bunlar bir stream'le disk arasına buffer koyarlar. Buffer'ın size'ı istenirse verilir verilmezse default bir değerde olur. Buffer kullanmak basittir : InputStream is=...; BufferedInputStream bis=new BufferedInputStream(is); Bundan sonraki kodda InputStream yerine BufferedInputStream kullanılır. BufferedInputStream'de aslında bir InputStream'dir ve aynı methodlra sahiptir, o yüzden aynı şekilde kullanılır. Aynı şeyler OutputStream ve BufferedOutputStream için geçerlidir. 'Madem buffer bu kadar faydalı niye her stream buffer'lı yapılmıyor. Böylelikle iki ayrı class'dan da kurtulmuş olurduk' diye düşünülebilir. Ancak bazı stream'ler buffer'sız olmalıdır. Gelen byte'ın anında okunması veya yazılması gerekebilir. Bu durumda buffer veriyi arada beklettiği için zararlı olabilir. Stream'leri Kapama Stream'ler işlem yapmadan önce 'açılır' ve işlem yapıldıktan sonra 'kapanır'. Java'da açma işlemi stram'lerin constructor'larında otomatik olarak yapılır. Ancak kapamak için 'close()' kullanılmalıdır. Programdan çıkılırken stream'ler açık dahi olsa kapatılabilir. O yüzden sadece main'den oluşan programlarda bu sorun anlaşılmaz. Ancak buffer'lı stream'lerde close() şarttır. Çünkü buffer'da kalan verilerle ilgili işlemler, gerekiyorsa flush da close'da yapılır. Dosya Listesi InputStreamer.java OutputStreamer.java Reader ve Writer'lar Text Stream'leri Stream'ler (InputStream ve OutputStream) byte okumak için kullanılılır. Bunları (veya bunları extend eden class'ları) kullanarak text, yani string okunabilir. Ancak bu durumda character encoding'in bu class'lara verilmesi gerekir. Çünkü 'byte' tipindeki verileri 'char' tipine dönüştürmek için encoding gereklidir. Çünkü, örneğin 'Ç' karakterinin byte olarak değeri bir dilin encoding'inde, 123 diğerinde 127 olabilir. Bunun için Reader ve Writer classları yapılmıştır. Reader'lar ve Writer'lar ortamın encoding'ini alıp byte'la char arasındaki dönüşünü otomatik olarak yaparlar. Bunlar da aslında içlerinde birer stream'e sahiptirler ama bu programcıyı ilgilendirmez. Stream'ler için olduğu gibi Reader ve Writer'ların da buffer'lı versiyonları BufferedReader ve BufferedWriter bulunmaktadır. Performansı arttırmak için kullanılmaları faydalı olur. Reader'lar Character ve text tipinde data okumak için InputStream'ler yerine Reader'lar kullanılır. Bir text dosyasını satır satır okuyup ekrana basan bir application yazalım. Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.io.*; 2 public class TextReader{ 3 public static void main(String[] args) 4 throws Exception 5 { 6 String filename="c:\\myfolder\\myfile.ext"; 7 FileReader file=new FileReader(filename); 8 BufferedReader in=new BufferedReader(file); 9 String line=""; 10 String text=""; 11 while ((line = in.readLine()) != null){ 12 text+=line+"\n"; 13 } 14 in.close(); 15 System.out.print(text); 16 } 17 18 } Writer'lar Character tipinde veri yazmak için Writer'lar kullanılır. Bir String'i text dosyasına yazan bir uygulama yazalım. TextWriter.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.io.*; 2 public class TextWriter{ 3 public static void main(String[] args) 4 throws Exception 5 { 6 String filename="c:\\myfolder\\myfile.ext"; 7 FileWriter file=new FileWriter(filename); 8 PrintWriter out=new PrintWriter(file); 9 String text="Java is a powerful programming language and platform.\n"; 10 text+="However it is still evolving and far from being perfect.\n"; 11 text+="On the other hand, no other language as promising as Java.\n"; 12 out.print(text); 13 out.close(); 14 } 15 } Dosya Listesi TextReader.java TextWriter.java File Class'ı File Class'ının İşlevi Bir dosya hakkında bilgi almak için File class'ı kullanılır. Ancak bu class bir dosyanın içerisindeki veriyi temsil etmemektedir. Dosyalar içerisindeki verilerle çalışmak için FileInputStream, FileOutputStream, FileReader ve FileWriter gibi classlar kullanılır. File class'ı aynı zamanda directory (folder)'ları da temsil eder. Zaten aslında her directory diskte kullanıcının değiştiremediği ancak dolaylı olarak üzerinde çalışabildiği bir dosyadır. Bir dosya hakkında bilgileri ekrana basan bir program yazalım. Göster Gizle Kopar Satır Gizle Satır Göster 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.io.*; import java.util.*; public class FileInspector{ public static void main(String[] args){ String filename="c:\\myfolder\\myfile.ext"; File file=new File(filename); System.out.println("Directory?"+file.isDirectory()); System.out.println("Last Modified :"+new Date(file.lastModified())); System.out.println("Exists?:"+file.exists()); System.out.println("Size :"+file.length()); System.out.println("Hidden?:"+file.isHidden()); } } File class'ı bir file hakkında çeşitli bilgileri öğrenmek için kullanılır. Bunlar işletim sisteminin bir dosya hakkında tuttuğu kjayıtlardan gelmektedir. Dosyanın içeriğiyle ilgili bilgiler değildir. Directory İşlemleri Bir directory altındaki dosyaları listeleyen program yazalım. DirectoryLister.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.io.*; 2 public class DirectoryLister{ 3 static public void walk(File directory){ 4 File[] files=directory.listFiles(); 5 for(int i=0;i<files.length;i++){ 6 File file=files[i]; 7 boolean parent=file.isDirectory(); 8 if(parent){ 9 walk(file); 10 }else{ 11 System.out.print(file.getAbsolutePath() ); 12 System.out.println(" : "+file.length()); 13 } 14 } 15 } 16 public static void main(String[] args){ 17 String name="c:\\myfolder"; 18 File directory=new File(name); 19 DirectoryLister.walk(directory); 20 } 21 } Dosya Listesi FileInspector.java DirectoryLister.java Serialization Serialization Kavramı Bir nesne herhangi stream'a (örneğin bir file'a ) yazılabilir ve bir stream'den okunabilir. Programın çalışması esnasında hafızada bulunan nesneler program bitince (kapatılınca) yok olur. Ancak serialization tekniğiyle bir nesne diske veya herhangi bir yere kaydedilebilir. Bir program, kapanmadan önce bir dosyayaya sakladığı bir nesneyi daha sonra tekrar çalıştırıldığında dosyadan okuyabilir. Hatta bir programın yazdığı nesneyi aynı dosyadan başka bir program da okuyabilir. Bu şekilde nesnelerin network'te bir yerden diğerine gönderilmesi, veritabanına normal bir veri gibi kaydedilebilmesi mümkün olabilmektedir. Serializable Bir class'ın serialization'a tabi tutulabilmesi için bazı koşulları sağlaması gerekir. 1. Class public olmalı. 2. Serializable' interface'ini implement etmeli. Bu interface'de implement edilecek herhangi bir method yoktur. Sadece class'ın serialize edilebilemesine class yazarının izin verdiği anlamına gelir. Bazı classlar güvenlik v.s. nedenlerle buna izin vermek istemeyebilir. Nesnenin içerisindeki bütün veri serializable olmalıdır. Bir tane bile serializable olmayan nesne varsa işlem başarısız olur. 3. Default (parametresiz) bir constructor'ı olmalıdır. Hiç bir constructor yazılmaması durumunda da default contructor'un geçerli olduğu için yine sorun olmaz. import java.io.*; public MyClass implements Serializable{ public MyCLass(){ } } File'e Object Yazma Hehangi bir class'tan oluşturulmuş bir nesne bir dosyaya ObjectOutputStream class'ı aracılığıyla yazılabilir. Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.io.*; 2 public class ObjectStorer{ 3 public static void main(String[] args) 4 throws IOException 5 { 6 String filename="c:\\myfolder\\myobject.ser"; 7 FileOutputStream f=new FileOutputStream(filename); 8 ObjectOutputStream out=new ObjectOutputStream (f); 9 Object mine=new Object(); // 10 out.writeObject(mine); 11 out.close(); 12 } 13 } File'dan Object Okuma Daha önce bir dosyaya yazılmış nesne ObjectInputStream kullanılarak okunabilir. ObjectLoader.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.io.*; 2 public class ObjectLoader{ 3 public static void main(String[] args) 4 throws Exception 5 { 6 String filename="c:\\myfolder\\myobject.ser"; 7 FileInputStream f=new FileInputStream(filename); 8 ObjectInputStream in=new ObjectInputStream (f); 9 Object mine=(Object)in.readObject(); 10 in.close(); 11 } 12 } Bir dosyaya birden fazla nesne yazılabilir ve okunabilir. Ancak nesnelere hangi sırada yazılmışsa o sırada okunmalıdır. Bir nesne kaydedilirken içerisindeki bütün veri, alt nesneleri onların içindekiler dahil kaydedilir. Aynı nesneye iki ayrı nesneden referans varsa iki kez kaydedilme durumu oluşabilir. Class'da değişiklik olursa yazıldığı gibi okunamayacağından sorun çıkar. Bu yüzden class'ın içerisinde public static final long =1233421421L; şeklinde bir property konması gerekir. Bu değer JDK ile birlikte gelen "serialver" adlı tool'dan alınabilir. Dosya Listesi ObjectStorer.java ObjectLoader.java AWT'ye Giriş AWT Hakkında AWT (Abstract Windowing Toolkit - Soyut Pencereleme Takımı) Java'nın grafikli kullanıcı arayüz ortamıdır. Başka bir deyişle pencereler, düğmeler, radyo butonlar ve menüler gibi görsel bileşenler içeren kütüphane AWT'dir. Öncelikle AWT'nin başarılması çok güç bir iş başardığını belirtmek gerekir. Çünkü Java, her işletim sisteminde çalışmak gibi bir iddiayla ortaya çıkan bir dil ama görsel bileşenler her işletim sisteminde çok farklı. Farklı görünmeleri önemli değil, bazı bileşenler bir işletim sisteminde bulunurken diğerinde olmayabiliyor. Bu yüzde AWT, en büyük ortak çarpanı buluyor. Yani bütün işletim sitemlerinde olan bileşenleri kullanıyor. Düğme hepsinde var ama tablo veya toolbar yok. Dahası her işletim sistemind eolan bileşenler de birbirlerinden farklı özellikler içeriyor. Java bunlardan sadece ortak olanları alıyor. O yüzden AWT ile yapılan arayüzler çok zengin ve çok güzel değil. AWT'nin gerçekleştirilmesi için izlenen yol çok farklı. Her bileşen class'ı, aslında işletim sistemindeki bir bileşenin peer'i (eş'i ). Programcı bu class'lardan birinin bir method'unu çağırınca Java bunu alt tarafta bulunan gerçek bileşene iletiyor.O bileşende bir olay gerçekleşince de bu üst tarafa iletiliyor. Elbette bu işlem programcıya şeffaf. Yani programcı bunu bilmiyor. AWT ve Swing Java'da daha zengin bir arayüz sağlayan Swing kütüphanesi var. O da her işletim sisteminde aynı şekilde çalışmasına rağmen zengin bileşenler içeriyor. Ancak Swing, bunu işletim sisteminin bileşenlerini kullanmadan, her şeyi baştan kendisi yaparak başarabiliyor. Yani Swing'in düğme bileşeni, işletim sistemindeki düğme bileşeni değil. Ona benzetilen, ama baştan yaratılan bir bileşen. Swing, kendi bileşenlerini kendi yapıyor, sadece her işletim sistemine uygun bir şekilde gürünmelerini sağlıyor. Hatta istenirse bir işletim sisteminde başka bir işletim sisteminin gürünümü sağlanabiliyor. Yada hiç bir işletim sisteminde olmayan bir görünüm ortaya çıkabiliyor. Swing, AWT'den farklı bir arayüz sağlıyor ama yine de kendisi AWT üzerine kurulu. Yani Swing, AWT'nin temel bileşenlerini kullanıyor. Zaten işletim sisteminin arayüzünün üzerine kurulan AWT. Swing, AWT'deki temel özellikleri kullanarak kendi bileşenini kendi yapmış oluyor. O yüzden AWT'de öğrenilen konulanrın %90'ı aynen Swing'de de geçerli. AWT'yi basit arayüzü nedeniyle tercih etmeyenler de Swing kullanabilmek için AWT'yi bilmek zorunda. AWT'nin Çalışma Mantığı AWT'nin çalışma mantığı diğer arayüz sistemlerinden biraz farklı. Nedenlerin bir tanesi AWT'nin başka işletim sistemlerinin üzerinde çalışmak zorunda olan bir kütüphane olması elbette. Ancak başa bir neden de, Java'nın Internet dili olarak, her türlü makinede çalışmak gibi bir ilkesi olması. Örneğin çok büyük ekranlı çok yüksek çözünürlüklü makinelerde de küçük ekran ve düşük çözünürlüklü makinelerde de çalışmalı. Bir browser içerisinde de çalışmalı bağımsız bir application olarak da çalışmalı. Bu gibi nedenlerden dolayı farklı bir arayüz sistemlerinde çalışanlar için biraz garip gelebilecek bir yapıya sahip. Örneğin, 'şu düğmeyi şu X ve şu Y noktasına koy' demiyorsunuz AWT'de. Onun yerine şunu ortaya şunu sola şunu yukarıya koy diyebiliyorsunuz. Belki bir anlamda sınırlayıcı olabilen bu özellik, pencerenin büyümesi veya küçülmesi durumunda da bileşenlerin görünmesini sağladığı için çok avantajlı olabiliyor. Bir başka özelliği de arayüzün sadece kod yazarak kolaylıkla oluşturulabilmesi. Basit bir pencerenin içerisine bir tane düğme ve bir tekst alanı koymak için sadece bir kaç satır kod yeterli. Hiç bir görsel editör kullanmaya gerek yok. Elbette isteyen kullanabilir ama editör kullanmadan da çok iyi arayüzler üretilebilir. Temel Class'lar AWT'de en temel nesneleri Component, Container ve Window olarak verilebilir. Component tek başına işlev gören en küçük bileşendir. Button, TextField, List gibi bileşenler birer component'tir. Container, içerisinde başka componentler bulunduran bir component'tir. Window, içerisinde çeştili componentler veya container'lar bulunan, ekranda dikdörtgen şeklinde görülebilen bir alan anlamına gelir. Frame (title bar'ı minimize/maximize/close düğmeleri bulunan pencere) ve Dialog birer window'dur. Window'lar Window Class'ı AWT'de Window class'ı ekranda dikdörtgen şeklinde görülebilen bir alan anlamına gelir. Bir uygulamadaki görsel bütün component'leri içerisinde barındıran class budur. Frame gibi Dialog class'ı da bu Window class'ını extend eder. Frame Üzerinde başlık çubuğu, simge durumuna getir, ekranı kapla gibi düğmeler bulunan class Frame'dir. Yaratıldığında görünmez olan bu nesne, içerisine bütün component'ler konulduktan sonra setVisible() method'u kullanılmalıdır. myframe.setVisible(true); yazılarak görünür hale getirilir. Bazı uygulamalar pencere, menü, düğme gibi görsel bileşenler içerebilir. En basit görsel bileşenler java.awt package'i içerisinde yeralır. O yüzden Frame gibi class'ları kullanabilmek için import java.awt.*; gibi bir ifade gereklidir. EmptyFrameShower.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.awt.*; 2 public class EmptyFrameShower{ 3 public static void main(String[] args){ 4 Frame f=new Frame(); 5 f.setBounds(100,100,400,300); 6 f.setVisible(true); 7 } 8 9 } Bu program ekrana bomboş bir pencere çıkartıyor. Bir Frame nesnesi yaratıldığında konumu x=0 y=0, boyutları width=0, height=0 biçimindedir. O yüzden pencerenin boyutları setBounds() method'uyla belirlenmelidir. Component Kullanımı Component, tek başına belli bir işlev gören en küçük görsel bileşendir. Bir pencere içerisine Button, TextArea, CheckBox, List gibi bazı component'ler konulabilir. Örnek olarak bir Button ve TextArea koyalım. ComponentFrameShower.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.awt.*; 2 public class ComponentFrameShower{ 3 public static void main(String[] args){ 4 Frame f=new Frame(); 5 f.setLayout(new BorderLayout()); 6 f.setBounds(100,100,400,300); 7 Button b=new Button("Press me!"); 8 f.add(b,BorderLayout.NORTH); 9 TextArea t=new TextArea("Write in me!"); 10 f.add(t,BorderLayout.CENTER); 11 Label l=new Label("Just read me!",Label.CENTER); 12 f.add(l,BorderLayout.SOUTH); 13 f.setVisible(true); 14 } 15 16 } Bu kod çalıştırıldığında ekrana geçecek pencere : Bir button nesnesinin yaratılması onun görülmesi anlamına gelmez. Onun pencereye add() methoduyla eklenmesi gerekir. Menu'ler Bir Frame'e menu eklemek için MenuBar, Menu ve MenuItem class'ları kullanılır. MenuFrameShower.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.awt.*; 2 public class MenuFrameShower{ 3 public static void main(String[] args){ 4 Frame f=new Frame(); 5 f.setBounds(100,100,400,300); 6 MenuBar mb=new MenuBar(); 7 Menu file=new Menu("File"); 8 file.add(new MenuItem("New")); 9 file.add(new MenuItem("Open")); 10 file.add(new MenuItem("Save")); 11 file.add(new MenuItem("Save As")); 12 file.addSeparator(); 13 file.add(new MenuItem("Exit")); 14 mb.add(file); 15 Menu edit=new Menu("Edit"); 16 edit.add(new MenuItem("Undo")); 17 edit.add(new MenuItem("Redo")); 18 edit.addSeparator(); 19 edit.add(new MenuItem("Cut")); 20 edit.add(new MenuItem("Copy")); 21 edit.add(new MenuItem("Paste")); 22 mb.add(edit); 23 f.setMenuBar(mb); 24 f.setVisible(true); 25 } 26 } Bu kod çalıştırıldığında ekrana gelecek pencere : Dosya Listesi EmptyFrameShower.java ComponentFrameShower.java MenuFrameShower.java Layout'lar Layout Manager'ları Java'da Component'lerin nereye nasıl konacağını belirleyen LayoutManager'lar vardır. Her Container'ın bir layout manager'ı bulunur. Bir Component'in, dikdörtgen olması nedeniyle ekranda x,y, width ve height gibi özellikleri bulunur. Layout manager'lar sayesinde her component için bu değerleri girmek gerekmez. Hangi bileşenin nerde görüneceğine layout manager'lar karar verir. Java'da çok sayıda layout manager bulunmaktadır. Aşağırakiler sadece birer örnektir. BorderLayout En fazla kullanılan layout'lardan biri BorderLayout'tur. Component'leri North, South, East, West ve Center gibi konumlara koyabilir. BorderLayoutSample.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.awt.*; 2 public class BorderLayoutSample{ 3 public static void main(String[] args){ 4 Frame f=new Frame(); 5 Button e=new Button("Doğu"); 6 Button w=new Button("West"); 7 Button n=new Button("North"); 8 Button s=new Button("South"); 9 Label c=new Label("Center",Label.CENTER); 10 f.setLayout(new BorderLayout()); 11 f.add(e,BorderLayout.EAST); 12 f.add(w,BorderLayout.WEST); 13 f.add(n,BorderLayout.NORTH); 14 f.add(s,BorderLayout.SOUTH); 15 f.add(c,BorderLayout.CENTER); 16 f.setBounds(100,100,400,300); 17 f.setVisible(true); 18 } 19 20 } Bu programın ekran görüntüsü şöyledir : GridLayout Bir başka layout da component'leri ızgara biçiminde sıralayan GridLayout'tur GridLayoutSample.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.awt.*; import java.awt.*; public class GridLayoutSample{ public static void main(String[] args){ Frame f=new Frame(); f.setLayout(new GridLayout(4,3)); f.add(new Button("1")); f.add(new Button("2")); f.add(new Button("3")); f.add(new Button("4")); f.add(new Button("5")); f.add(new Button("6")); f.add(new Button("7")); f.add(new Button("8")); f.add(new Button("9")); f.add(new Button("*")); f.add(new Button("0")); f.add(new Button("#")); f.setBounds(100,100,400,300); f.setVisible(true); } } Flow Layout FlowLayout, component'leri soldan sağa doğru sırayla koyar. Bir sıra bitince sol altından yeniden dizer. FlowLayoutSample.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 import java.awt.*; 2 public class FlowLayoutSample{ 3 public static void main(String[] args){ 4 Frame f=new Frame(); 5 f.setBackground(SystemColor.control); 6 f.setLayout(new FlowLayout()); 7 f.add(new Button("Button")); 8 f.add(new TextArea("Area")); 9 f.add(new TextField("TextField")); 10 f.add(new Label("Label")); 11 f.add(new Checkbox("Checkbox")); 12 List list=new List(); 13 list.add("List Item 1"); 14 list.add("List Item 2"); 15 list.add("List Item 3"); 16 f.add(list); 17 f.setBounds(100,100,600,300); 18 f.setVisible(true); 19 } 20 21 } Bu kod çalıştırıldığında ekrana geçecek pencere : GridBagLayout Diğer layout'ların basit yapısına karşın, GridBagLayout karmaşık düzenlemler için kullanılır. Bunun için GridBagConstraints class'ı ile, her componentin ayrı ayrı nasıl dizileceği belirlenebilmektedir. Dosya Listesi BorderLayoutSample.java GridLayoutSample.java FlowLayoutSample.java Component'ler Component Kavramı Kullanıcıdan bir bilgi almak için kullanılan görsel nesnelere 'component' denir. Button, TextField, CheckBox gibi component'ler bulunmaktadır. Bütün component'ler AWT içerisinde bulunan Component adlı class'ı extend eder. Bu class bütün bileşenlerde bulunan yazı rengi, boyutlar gibi property'ler ve çeşitli method'lar içerir. Container Class'ı Bir veya daha çok component içeren component'ler Container'lardır. Container'ın içine konan component'ler belli bir layout manager tarafından yerleştirilir. Aslında Frame içerisine konan componentler de Frame'in içerisindeki container'a konur. Container'ler da aslında birer component'tir. Yani Container class'ı Component class'ını extend eder. Panel Class'ı Container class'ı içerisinde bir veya daha çok component bulundurabilen bileşen olmakla birlikte, programcıların bu class'ı extend eden Panel adlı class'ın bu amaçla kullanılması gerekir. Canvas Class'ı Üzerinde çizim veya image işlemleri yapmak için kullanılması uygun olan component Canvas'dır. Çizim yapmak için Component'teki paint() method'u override edilir : public void paint(Graphics g){ g.drawLine(100,100,300,300) } Button (Düğme) En çok kullanılan componentler'den biri olan Button, üzerinde bir etiket (label) bulunan, fareyle tıklandığında basıldığı izlenimi veren ve bir ActionEvent üreten arayüz elemanıdır. AWT paketinde Toolbar (araç çubuğu) yoktur, ancak bir panele bir kaç düğme eklenerek çok kolay aynı işlevsellik elde edilebilir. Telefonunun arayüzünü emüle eden bir pencere yapalım. Bu uygulama düğmelerden birine basılarak yazılan numarayı güya arasın. İşlem, hangi düğmeye basılıdığını anlamak, eğer "Yes" gibi kontrol tuşuysa bir işlem yapmak, "1","2","3" gibi numaraysa diplay'da göstermekten ibarettir. PhoneSimulatorFrame class'ı implements ActionListener diyerek ve actionPerformed() methodunu yazarak düğmeleri dinleyebilme özelliği kazanmıştır. Düğmelere kendisini button.addActionListener(this) şeklinde kaydettirir. Hangi düğmeye basıldığını event'in source'undan öğrenmektedir. PhoneSimulatorFrame.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import java.awt.*; import java.awt.event.*; public class PhoneSimulatorFrame extends Frame implements ActionListener { private TextField display=null; public PhoneSimulatorFrame() { setBounds(100,100,100,200); setLayout(new BorderLayout()); display=new TextField(""); add(display,BorderLayout.NORTH); Panel buttons=createButtonsPanel(); add(buttons,BorderLayout.CENTER); } public void actionPerformed(ActionEvent event){ Button button=(Button)event.getSource(); String label=button.getLabel(); if(label.equals("Yes")){ String text=display.getText(); if(text.length()==7 || text.length()==11){ System.out.println("Calling "+text); }else{ System.out.println("Error!"); } }else if(label.equals("C")){ display.setText(""); }else if(label.equals("No")){ display.setText(""); System.out.println("Cancelled."); }else{ String text=display.getText(); 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 } text=text+label; display.setText(text); } } private Panel createButtonsPanel(){ Panel buttons=new Panel(new GridLayout(5,3)); addButton(buttons,"Yes"); addButton(buttons,"C"); addButton(buttons,"No"); addButton(buttons,"1"); addButton(buttons,"2"); addButton(buttons,"3"); addButton(buttons,"4"); addButton(buttons,"5"); addButton(buttons,"6"); addButton(buttons,"7"); addButton(buttons,"8"); addButton(buttons,"9"); addButton(buttons,"*"); addButton(buttons,"0"); addButton(buttons,"#"); return buttons; } private void addButton(Panel panel,String label){ Button button=new Button(label); button.addActionListener(this); panel.add(button); } public static void main(String[] args){ PhoneSimulatorFrame frame=new PhoneSimulatorFrame(); frame.setVisible(true); } Burada frame sadece button'ları dinlediği için event'in source'u Button'a cast edilmiştir. Eğer başka bileşenleri de dinleseydi source'un Button olup olmadığını kontrol etmemiz gerekirdi. Bunun için bir nesnenin belli bir class'ın veye subclass'ının bir instance'ı olup olmadığını kontrol eden instanceof operatörü kullanılır. Örnekteki actionPerformed() aşağıdakine uygun olarak değiştirilmelidir. Object source=event.getSource(); if(source instanceof Button){ Button button=(Button) source; } TextArea Bir kaç satırdan oluşan metin girişi için kullanılır. İçerisindeki text'in tamamı ve seçilmiş kısmıyla ilgili bir çok method içerir. TextField Tek satırlık bilgi girişi için bu component kullanılır. TextArea'dan bir farkı da Enter'a basıldığında ActionEvent'i üretebilmesidir. Label Kullanıcının değiştiremeyeceği tek satırlık metin için kullanılır. İşlevi ekranda belli bir yazıyı sergilemekten ibarettir. Checkbox Kullanıcının bir konudaki tercihini öğrenmek için kullanılır. Birden fazla Checkbox bir CheckboxGroup'a eklenirse, sadece aynı anda sadece birinin seçili olabildiği radio button olarak çalışır. List Kullanıcının bir liste içerisinden herhangi birini seçmesi için kullanılır. Bir veya daha fazla maddenin seçilmesine olanak tanır. Bir elemanın üzerinde çift tıklama durumunda çok eleman seçilmiş olur. Choice Birden fazla elemanın tıklamayla açılan bir listeden eleman seçilmesine olanak tanıyan bileşendir. Ekranda sadece seçili olan elamanı gösterir. Form Örneği Çok kullanılann bileşenleri içeren bir form örneği yapalım. Tamam düğmesine basılınca kullanıcının girdiği değerleri ekrana bassın. Burada sadece düğmenin ürettiği ActionEvent dinlenmektedir. Aslında Checkbox,Choice ve TextField'ları da dinlemek mümkündür. Ama o durumda kullanıcının bilgi girişi bitmeden bir tepki verilir ki, form türü bilgi girişlerinde bu pek doğru olmaz. Burada her component grubu ayrı bir panel'e konmuş, daha sonra bütün paneller ana pencereye yerleştirilmiştir. Bu şekilde sadece GirdBagLayout, GridLayout ve BorderLayout kullanılarak karmaşık bir form yapılabilmiştir. Insets class'ı her bileşenin etrafında kendisine ayrılan yerden bırakılacak aralığı belirler. Bu şekilde bileşenlerin kendi alanlarını tamamen doldurması, birbirlerine ve en dış sınırlara yapışması engellenmiş olur. Bir başka önemli konu da, düğmelere ActionListener eklenmesinin anonymous inner class'larla gerçekleştirlmiş olmasıdır. Bu şekilde ayrı bir listener class'ı yapmaya gerek duymadan ya da asıl class'ın ActionListener'ı implement etmeye mecbur bırakmadan düğmeleri dinlemiş olduk. Ayrıca birden fazla bileşenin dinlenmesine rağmen actionPerformed() methodunda hangi düğmeye basıldığını anlamak için herhangi bir ayıklma yapmak zorunda kalmadık. "OK" ve "Cancel" düğmeleri ayrı ayrı dinlenmektedir. Dikkat edildiyse örnekte bazı bileşenler class'da property olarak tutulmuştur. Bunun nedeni, tanımlandıkları method dışında da erişilebilmelerini sağlamaktır. Aksi taktirde her değişkenin içinde bulunduğu '{' ve '}' scope'unun dışında tanınmaması yüzünden bu bileşenlere ve içerisindeki verilere erişemeyebilirdik. ComponentFormSample.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 import java.awt.*; import java.awt.event.*; public class ComponentFormSample extends Frame { private TextField name=new TextField(); private CheckboxGroup gender=new CheckboxGroup(); private Checkbox[] hobbies=new Checkbox[3]; private Choice education=new Choice(); private TextArea description=new TextArea(); public ComponentFormSample() { setFont(new Font("Arial",Font.BOLD,12)); setBackground(Color.lightGray); setBounds(100,100,300,500); setLayout(new GridBagLayout()); Label label=new Label("INFORMATION FORM",Label.CENTER); addPart(label,1,1); Panel names=createNamesPanel(); addPart(names,2,1); Panel genders=createGendersPanel(); addPart(genders,3,1); Panel hobbies=createHobbiesPanel(); addPart(hobbies,4,4); Panel education=createHobbiesPanel(); addPart(hobbies,8,1); Panel descriptions=createDescriptionsPanel(); addPart(descriptions,9,1); Panel buttons=createButtonsPanel(); addPart(buttons,10,1); } public Insets insets(){ return new Insets(25,15,15,15); } private void addPart(Component part,int row,int height){ GridBagConstraints constraints=new GridBagConstraints(); constraints.gridx=0; constraints.gridy=row; constraints.gridwidth=1; constraints.gridheight=height; constraints.weightx=1.0; constraints.weighty=1.0; constraints.fill=GridBagConstraints.BOTH; constraints.insets=new Insets(5,0,5,0); add(part,constraints); } private Panel createNamesPanel(){ Panel panel=new Panel(new GridLayout(1,2)); panel.add(new Label("Full Name ")); panel.add(name); return panel; } private Panel createGendersPanel(){ Panel panel=new Panel(new GridLayout(1,3)); Checkbox male=new Checkbox("Male",gender,true); Checkbox female=new Checkbox("Female",gender,false); 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 panel.add(new Label("Gender")); Panel boxes=new Panel(new GridLayout(1,2)); boxes.add(male); boxes.add(female); panel.add(boxes); return panel; } private Panel createHobbiesPanel(){ Panel panel=new Panel(new GridLayout(4,1)); panel.add(new Label("Hobbies")); hobbies[0]=new Checkbox("Computer",true); panel.add(hobbies[0]); hobbies[1]=new Checkbox("Music",false); panel.add(hobbies[1]); hobbies[2]=new Checkbox("Art",false); panel.add(hobbies[2]); return panel; } private Panel createEducationPanel(){ Panel panel=new Panel(new GridLayout(1,2)); education.add("Primary"); education.add("Secondary"); education.add("High School"); panel.add(new Label("University")); panel.add(education); return panel; } private Panel createDescriptionsPanel(){ Panel panel=new Panel(new BorderLayout()); Label label=new Label("Description"); panel.add(label,BorderLayout.NORTH); panel.add(description,BorderLayout.CENTER); return panel; } private Panel createButtonsPanel(){ Panel panel=new Panel(new GridLayout(1,2)); Button ok=new Button("OK"); ok.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e){ printData(); setVisible(false); } } ); panel.add(ok); Button cancel=new Button("Cancel"); cancel.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e){ setVisible(false); } } ); panel.add(cancel); return panel; } 113 private void printData(){ 114 System.out.println("# Name :"+name.getText()); 115 System.out.println("# Gender :"+gender.getSelectedCheckbox().getLabel()); 116 System.out.println("# Hobbies "); 117 for(int i=0;i<hobbies.length;i++){ 118 System.out.println(hobbies[i].getLabel()+" : "+(hobbies[i].getState()?"Yes":"No")); 119 } 120 System.out.println("# Description : "+description.getText()); 121 } 122 public static void main(String[] args){ 123 ComponentFormSample frame=new ComponentFormSample(); 124 frame.setVisible(true); 125 } 126 } Dosya Listesi PhoneSimulatorFrame.java ComponentFormSample.java Dialog'lar Dialog Ekrana bir Diyalog kutusu getiren class Dialog'dur. Genellikle kullanıcıdan kısa zamanda bir bilgi beklendiğinde kullanılır. Frame'den fazla bir farkı olmadığı için aynı şekilde kullanılabilir. Diyaloğun 'modal' olması durumunda kullanıcının asıl pencrede işlem yapması engellenir. Modal yapmak için mydialog.setModal(true); demek veya constructor'da modal parametresini true olarak girmek gerekir. File Dialog FileDialog, kullanıcı bir dosyayı açmak istediğinde veya belli bir yere farklı kaydetmek istediğinde kullanılır. Basit bir text editörü yapalım. Bir file menüsü olsun ve text dosyalarını açma ve saklama özelliğine sahip olmasını sağlayalım. FileDialog class'ı ekrana kullanıcının dosyayı belirleyebileceği bir diyalog kutusu getirir. Bu class LOAD (Open) ve SAVE modunda açılabilir. Kullanıcının seçtiği dosyanın adını ve directory'si (ayrı ayrı) öğrenilebilir. Dosya açarken FileDialog dialog=new FileDialog(this,"Open",FileDialog.LOAD); dialog.setVisible(true); String filepath=dialog.getDirectory()+dialog.getFile(); şeklinde bir kod parçası kullanılır. Dosyayı başka bir adla kaydederken bu kodda sadece FileDialog dialog=new FileDialog(this,"Save",FileDialog.SAVE); şeklinde değişiklik yapmak yeterlidir. TextEditor.javaIndir Göster Gizle Kopar Satır Gizle Satır Göster 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import java.awt.*; import java.awt.event.*; import java.io.*; public class TextEditor extends Frame implements ActionListener { private TextArea area=new TextArea(); private String filepath="Untitled.txt"; public TextEditor() { setBounds(0,0,640,480); putMenuBar(); setLayout(new BorderLayout()); add(area,BorderLayout.CENTER); } private void putMenuBar(){ Menu file=new Menu("File"); putMenuItem(file,"New"); putMenuItem(file,"Open"); putMenuItem(file,"Save"); putMenuItem(file,"Save As"); file.addSeparator(); putMenuItem(file,"Exit"); MenuBar menubar=new MenuBar(); menubar.add(file); setMenuBar(menubar); } private void putMenuItem(Menu menu,String label){ MenuItem item=new MenuItem(label); item.addActionListener(this); menu.add(item); } public void actionPerformed(ActionEvent event){ MenuItem item=(MenuItem) event.getSource(); String label=item.getLabel(); if(label.equals("New")){ handleNew(); }else if (label.equals("Open")){ handleOpen(); }else if (label.equals("Save")){ handleSave(); }else if (label.equals("Save As")){ handleSaveAs(); }else if (label.equals("Exit")){ handleExit(); } } private void setContent(String text,String filepath){ area.setText(text); this.filepath=filepath; setTitle(filepath); } 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 private void handleNew(){ setContent("","Untitled.txt"); } private void handleOpen(){ try{ FileDialog dialog=new FileDialog(this,"Open",FileDialog.LOAD); dialog.setVisible(true); String filepath=dialog.getDirectory()+dialog.getFile(); String text=loadText(filepath); setContent(text,filepath); }catch(Exception e){ e.printStackTrace(); } } private void handleSave(){ try{ String text=area.getText(); storeText(text,filepath); }catch(Exception e){ e.printStackTrace(); } } private void handleSaveAs(){ try{ FileDialog dialog=new FileDialog(this,"Save",FileDialog.SAVE); dialog.setVisible(true); String filepath=dialog.getDirectory()+dialog.getFile(); setTitle(filepath); String text=area.getText(); storeText(text,filepath); }catch(Exception e){ e.printStackTrace(); } } private void handleExit(){ System.exit(0); } private String loadText(String filepath) throws IOException { FileReader fr=new FileReader(filepath); BufferedReader in=new BufferedReader(fr); String text=""; String line=null; while((line=in.readLine())!=null){ text+=line; } in.close(); return text; } private void storeText(String text,String filepath) throws IOException { FileWriter fw=new FileWriter(filepath); PrintWriter out=new PrintWriter(fw); out.print(text); out.close(); 110 } 111 public static void main(String[] args){ 112 TextEditor editor=new TextEditor(); 113 editor.setVisible(true); 114 } 115 } Dosya Listesi TextEditor.java XML'e Kısa Bir Giriş XML Nedir? XML (Extensible Markup Language), veriyi belli bir yapıda tanımlamak için kullanılan bir dildir. Bir verinin belli bir yapıda olması, o veri içerisindeki bilginin gerektiğinde kullanılabilir, değiştirilebilir ve başka biçimlere dönüştürülebilir olmasını sağlar. XML - Düz Metin Karşılaştırması Diyelim ki saklamak istediğimiz veri bir sınavının soruları olsun. Sınavı düz metin (plain text) şekilde yazalım : Matematik Dersi 2. Ara Sınavı Soru 1 : İki kere iki iki kaç eder? a) 22 b) 3 c) 4 d) 5 Soru 2 : Kendimi kendimden çıkarsam kaç kalır? a) 1 b) 2 c) 0 d) FD Bu metin bir insanın çok rahat okuyabileceği ve anlayabileceği bir biçimde yazılmıştır. Ama bir bilgisayar programı bu metnin içindeki bilgileri okuyamaz. '1. sorunun ikinci şıkkı' gibi bir bilgiyi belge içerisinden nasıl bulunabileceğini düşünelim. En basit yol metni satırlara bölmek ve 4. satırı almak, sonra da ilk boşlıktan sonraki kısmı okumaktır. Peki ya sınav adından sonra bir boşluk eklenirse? Program bu kez yanlış satırı getirecektir. Ya 'b' şıkkında 'b' ile ')' arasına bir boşluk konursa? O zaman sayı yerine bir parantez elde edeceğiz! Görüldüğü gibi düz metin bir programın veri saklaması ve erişmesi için uygun bir biçim değildir. XML - Tablo Karşılaştırması Geleneksel olarak veri tablolarda tutulur. Bir okuldaki öğrenciler 123 234 542 423 Barış Manço Cem Karaca Edip Akbayram Ersen Tablo tarzı veriler düz bir dosya'da (flat file'da) saklanabilir. Her kayıt bir satıra konur ve bir kayıtta her alan arasına boşluk, sekme (tab), noktalı virgül (;), virgül(,) gibi ifadeler konur. Olmayan değerler boş geçilir. O zaman bir programın bunları anlaması kolay olur. Düz tabloların gelişmesiye veritabanları doğmuştur. Bir veri tabanında tablolarda hangi alanların olacağı ve bu alanlarda bulunabilecek verinin (metin,tamsayı veya kesirli sayı gibi) tipleri belirenir. Bunlara erişmek için SQL diye bir dil bulunmaktadır. 542 numaralı öğrencinin adını öğrenmek için select Name form Student şeklinde bir 'sorgu' (query) yazılır. Zamanla, tablo yapısının çok kısıtlı olduğu ortaya çıkmıştır. Birbirine eşdeğer maddelerden oluşmayan veriler için tablo yapısı yetmez. Basit bir liste bile tablolarla kolay olarak gösterilemez. Bir şeyin altında başka birşey, onun altında da başka bir şey varsa tablolar gittikçe karmaşıklaşmaya, düzenli veri saklamak yerine giderek düzensizleşmeye başlar. Bir sınavın sorularını saklamayı düşünelim. Diyelim ki her sınavda bölümler, bölümlerde sorular, sorularda da şıklar olsun. Bunun için nasıl bir tablo yapmamız gerekir? Bir tabloda hem soru hem de şıklar saklanamaz. Bu yüzden birden çok sayıda tablo yapmak zorunda kalırız ver aralarında 'ilişki' (relation) kurmak gerekli hale gelir. Tablolar Sınav, Bölüm, Soru ve Şık şeklinde dört adettir. Üstelik aynı sınavın sorusu bir tabloda şıkkı başka tablodayken, bir sınavın sorusu ile başka sınavın sorusu aynı tabloda yer alır. Bir sınavdaki soruları öğrenmek için dört tablodan veri toplanması gerekir. Oysa XML ne kadar karmaşık yapıda olursa olsun veriyi bir arada tutar ve kolayca erişim sağlar. XML-HTML Karşılaştırması HTML'de veri belli bir yapı içerisinde bulunur. Ancak bu yapı bilginin gerektiğinde erişilebilmesini değil, belli bir biçimde ekranda gösterilmesini sağlar. HTML içerisindeki veriye kolay kolay erişemezsiniz. Bir yazının başlığını bir kişi H1 etiketini kullanarak gösterir, başka bir kişi H2. Hatta font'u büyük vererek de başlık verilebilir. Bu durumda HTML belgesi içinde belli bir verinin tam olarak nerde olduğunu bulmak mümkün değildir. HTML, veri (data) ile biçim (style)'ın iç içe olduğu bir yapıdır. Oysa XML'de veri ayrı biçim ayrı tutulabilir. Aynı biçimle bir çok veri gösterilebilirken aynı veri bri çok biçimde gösterilebilir. Basit bir XML örneği Bir sınavı XML olarak belirmek için şöyle bir yapı kurmak yeterlidir. <exam id="math-3"> <title>Matematik Dersi 2. Ara Sınavı </title> <question number="1"> <text>İki kere iki iki kaç eder?</text> <option id="a">22</option> <option id="b">3</option> <option id="c">4</option> <option id="d">5</option> </question> <question number="2"> <text>Kendimi kendimden çıkarsam kaç kalır?</text> <option id="a">1</option> <option id="b">2</option> <option id="c">0</option> <option id="d">FD</option> </question> </exam> Burada veri belki daha çok yer kaplar ama artık herhangi bir veriye ulaşmak çok basittir. Belki bir kişinin kendi yazığı bir programla bu belgeden veri alması daha zordur ama en azından araya bir şey eklenirse veya çıkartılırsa program yanlış bilgiye erişmez. Dahası, bir XML belgesinden herhangi bir bilgiyi almak için çeşitli olanaklar bulunaktadır. Programcı her zaman kendisi bir şey yapmak zorunda kalmaz. Örneğin XPath'le ilk sorunun 2. şıkkına erişim için /exam/question[number="1"]/option[id="1"]] yazmak yeterlidir. Aynı şekilde 2. sorunun metnine /exam/question[number="1"]/text şeklinde erişmek mümkündür. XPath olmadan da bir 'parser' programla XML belgesi programlar tarafından okunması için 'document' nesnesine okunabilir. XML'in bütün espirisi bir veriyi metin olarak saklamak ve gerektiğinde kolayca erişmektir. Bu, göründüğünden çok daha güçlü özelliktir. Temel XML Terimleri Her XML birimine document denir. Bu genellike bir dosyaya karşılık gelir. Document'ler element'lerden oluşur. Element içerisinde belli bir bütünlük içeren veridir. Bir belge içerisinde herşeyi içine alan bir ana element olmalıdır ki buna 'root' veya da 'document element' denir. Her element attribute'lerden, child element'lerden ve text'lerden oluşur. Attribute bir element hakkında bilgi veren özelliklerdir. Text'se bir element'in içinde bulunan düz metindir. XML'de element, attribute ve text gibi birimlere node denir. Burda anlatılan yapı sadece XML için değil HTML ve JavaScript gibi DOM standardını destekleyen bütün yapılar için geçerlidir. Yazım kurallarına uygun olarak yazılmış bir belgeye 'well-formed' denir. Ancak bu içerisindeki verinin mantıksal olarak doğru yapıda olduğu anlamında gelmez. '<' ile başlayan bir etiketi '>' ile kapatmak gibi kurallara uymak anlamına gelir. Bir XML belgesinin mantıklı bir veri içermesi durumunda 'valid' olur. Örneğin sorunun içine şık koymak yerine şıkkın içine soru koyarsanız veri yine well-formed olabilir, ama valid olmaz. Temel XML Teknolojileri XML'le birlikte bir çok dil ortaya çıkmıştır. Bir XML document'inde ne gibi element'ler ve attribute'ler olduğunu göstermek için kullanılan dile DTD denir. DTD ile benzer bir işlev gören ancak element ve attributelerin değerlerinin geçerlilik kriterlerini belirleme gibi fazladan özellikleri bulunan XSchema diye bir dil daha vardır ki bu dil de aslında XML'le yazılmıştır. Bir XML document'inde belli bir düğümün konumunu belirtmek için XPath kullanılır. Bir XML'i başka bir biçime, yani başka bir XML'e, düz metne veya HTML'e dönüştürmek için XSL kullanılır. XSL'de bir XML dilidir. Bir XML belgesinden diğer bir XML belgesine bağlantı kurmak için XLink, aynı XML belgesinde bir düğümden diğerine işaret etmek için XPointer kullanılır. XML'in çok fazla uygulaması bunmaktadır. XHTML, HTML'in XML versiyonu; MathML matematiksel ifadeleri belirlemek için kullanılan bir dil; SVG iki boyutlu grafikleri metin yoluyla oluşturmak için kullanılan bir dil, SMIL multimedya bileşenlerini birlikte kullanmak için kullanılan bir dildir. Ancak XML bunlarla sınrılı değildir. Hatta her programcının kendine bir veya daha fazla dil oluşturabilir. Bir XML Document'i Oluşturmak XML Dosyası Yaratmak Bir metin dosyasına '.xml' uzantısı verilip içerisine well-formed bir XML belgesi yazarsak herhangi bir uygulama tarafından işlenebilecek bir belge oluşturmuş oluruz. Yapılacak işlemleri sırasıyla verirsek : Bir klasörde ('C:\Java\Xm' olsun) bir metin dosyası yaratıp (adı 'test' olsun) uzantısını 'xml' verin Bu dosyayı bir metin düzenleyicide (NotePad veya WordPad'te) açın İçerisine well-formed XML yazıp kaydedin XML'i gösterebilen bir programda (örneğin Internet Expolorer) yarattığınız belgeyi açın. Eğer yarattığınız XML dosyası XML açabilen herhangi bir programda hatasız açılabiliyorsa XML 'well-formed' demektir. Bu şekilde Java veya herhangi bir programlama ortamına ihtiyaç duymadan XML çalışabilirsiniz. XML Dosyasının İçeriği Bir XML belgesinde olması gereken tek şey bir root element'tir. Yani <exam/> şeklindeki ifade yeterlidir. Zorunlu olmamakla birlikte 'prolog' denilen giriş kısmı genellikle konur <?xml version="1.0" encoding="ISO-8859"?> Bir XML document'inde prolog 'version' ve encoding bilgisi içerebilir. Burada version XML'in versiyonudur, aşağıda kullanılan herhangi bir xml dilinin değil. Genellikle 1.0 konur. Zaten bu yazının yazıldığı tarih itibariyler sadece 1.1 versiyonu bulunmaktadır ki sadece az kullanılan dillerin karakter kodlamalarını desteklemek gibi çok önemli olmayan değişiklikler içermektedir. Belgelerdeki 'encoding' önemlidir, türkçe karakterle için türkçe encoding (ISO-8859-9)vemek gerekir. Encoding değeri olarak 'UTF-8' de verilebilir. Aşağıdaki metni bir dosyaya kaydedederseniz geçerli bir XML belgesi yazmış olursunuz. <exam id="math-3"> <title>Matematik Dersi 2. Ara Sınavı </title> <question number="1"> <text>İki kere iki iki kaç eder?</text> <option id="a">22</option> <option id="b">3</option> <option id="c">4</option> <option id="d">5</option> </question> <question number="2"> <text>Kendimi kendimden çıkarsam kaç kalır?</text> <option id="a">1</option> <option id="b">2</option> <option id="c">0</option> <option id="d">FD</option> </question> </exam> Buradaki XML'in konulduğu örnek : ExamTest.xmlİndir Göster Gizle Kopar Satır Gizle Satır Göster 1 <?xml version="1.0" encoding="ISO-8859-9"> 2 <exam id="math-3"> 3 <title>Matematik Dersi 2. Ara Sınavı </title> 4 <question number="1"> 5 <text>İki kere iki iki kaç eder?</text> 6 <option id="a">22</option> 7 <option id="b">3</option> 8 <option id="c">4</option> 9 <option id="d">5</option> 10 </question> 11 <question number="2"> 12 <text>Kendimi kendimden çıkarsam kaç kalır?</text> 13 <option id="a">1</option> 14 <option id="b">2</option> 15 <option id="c">0</option> 16 <option id="d">FD</option> 17 </question> 18 </exam>