11. fejezet

A Jáva osztályok is csak fájlok; Jáva osztályok elhelyezése és fellelése. További káoszteremtõ eszközök: package és import. Jó helyek a fájlrendszeren: a CLASSPATH környezeti változó.

Ha tényleg megcsináltad a feladatokat és nem csak végigfutottál a megoldásokon (ebben az esetben nem fogsz megtanulni Jávául), a játékterül szolgáló könyvtáradban jókora zûrzavar lehet már. Az Elso.java-t már legalább háromszor felülírtad különbözõ változatokkal és ki tudja, mi mûködik ott és mi nem. Ha néhány Jáva gyakorlóprogrammal ekkora zûrzavart lehet csinálni, vajon mire lehet képes egy csapat termelékeny programozó? Világos: végtelen káoszra. A káosz látszólagos rendezettségének növelésére a Jáva bevezeti a csomag (package) fogalmát.

A csomag vészesen analóg a fájloknál megszokott fájlnév-könytárnév szerkezettel. Minden fájlnak van egy neve, de ez még kevés az eléréséhez; általában tudni kell azt is, milyen könyvtárban van. Hasonlóképpen van ez a Jáva osztályokkal; általában nem elég, ha a nevüket tudjuk, tudni kell, milyen csomagban vannak. Íme néhány példa Jáva osztálynevekre csomagnevekkel kibõvítve.

java.awt.color.ColorSpace
java.util.Vector
pelda.Elso

Az elsõ kettõ egy-egy ténylegesen létezõ Jáva könyvtári osztályt jelöl. Vegyük a másodikat: ez a java.util csomagban elhelyezkedõ Vector osztály. A harmadik az én agyam szüleménye, de attól még létezhet. Mindjárt meglátjuk, hogyan!

Ha a Jáva forrásfájlba betesszük a package direktívát, a fájlban mögötte deklarált osztályokat abba a csomagba teszi. pl.

package a.b;

class C {
  ...
}

A fenti varázslat eredménye az, hogy az osztály neve nem egyszerûen C, hanem a.b.C lesz, vagyis az a.b csomagban található.

Mindez nagyon egyszerû, de mi hasznunk ebbõl? Hogyan lehet elérni csodálatos a.b.C osztályunkat? Mi sem egyszerûbb ennél. Ha egy osztályra referenciát akarunk gyártani, az osztály nevét kell használni típusnak. Így ni:

a.b.C ref = new a.b.C();

Egyszerû és elegáns, nemdebár? Egy apró probléma van a dologgal: elõbb-utóbb bele fogunk unni hosszú nevû osztályunk nevének gépelésébe, pláne, ha nem a.b.C az osztály neve, hanem a fent megemlített java.awt.color.ColorSpace és ezzel még egy szelídebb példát választottam. Minthogy a programozók lusta népek, meg lehet ezt úszni kevesebb gépelésbõl is. Ha a programunk elejére odaírjuk az import direktívát, megadhatjuk, milyen osztályoknál vagy csomagoknál nem akarjuk kiírni a teljes nevet. Például mondhatjuk azt, hogy

import a.b.C;

Ezzel kijelentettük, hogy az a.b.C osztályra egyszerûen, mint C-re kívánunk hivatkozni ebben a forrásfájlban. Leírhatjuk, hogy

C ref = new C();

Mindjárt barátságosabb. Ennél többet is tehetünk, azt is mondhatjuk, hogy a csomagban található összes osztályt egyszerûsített formában akarjuk látni.

import a.b.*;

Ez az a.b csomag összes osztályát egyszerûsített formában teszi elérhetõvé.

Nagyon fontos megjegyezni, hogy az import direktíva csupán azt befolyásolja, hogyan oldja fel a fordító az osztályneveket. Akármit is varázsolunk, a lefordított kódba mindenképpen az a.b.C-re való hivatkozás kerül be, import ide vagy oda. Az import ugyancsak nem tölt be semmit se a tárba, mint azt naívan hinnénk. Szerepe csupán a gépelés csökkentésében van, futásidõben semmit se számít.

Még egy fontos megjegyzés: a fordító minden Jáva forrásfájl elejére odaképzel egy import java.lang.*; direktívát, így a java.lang csomagot mindig importálja. A java.lang csomagban régi barátaink vannak, pl. a java.lang.Integer, aminek parseInt metódusához oly sok kedves élményünk fûzõdik, vagy a java.lang.Math, amivel a kapcsolat már tényleg mélyebbé vált egyszerû barátságnál.

De vissza a package-re! Tekintsük a következõ programot! Mi lenne ez más, mint népszerû Elso programunknak egy egyszerûsített változata azzal a csavarral, hogy a programot befoglaló osztályt pelda.Elso-nek neveztük el. Fordítsd le fürgén a javac Elso.java paranccsal, majd futtasd le a java pelda.Elso utasítással. (ne feledd: a java parancsnak a futtatandó osztály nevét kell megadni, ebben az esetben pelda.Elso-t). Ilyen egyszerû egy osztályt csomagba tenni.

Eeeee ... valami nem stimmel? A java pelda.Elso hatására nem az unalomig ismert kiírás jelent meg, hanem az, hogy a pelda/Elso osztály nem található. Mindez arra világít rá, hogy még mindig nem tudunk mindent az osztályok betöltõdésérõl.

Eddig ezzel nem sokat törõdtünk. A lefordított .class fájlokat az aktuális könyvtárban tároltuk és elvártuk, hogy a virtuális gép megtalálja õket. A csomagok bevezetésével a helyzet megváltozik és meg kell ismerkednünk egy osztályt tartalmazó .class fájl fellelésének módjával. Amikor a virtuális gép meglát egy osztálynevet, azonnal elkezdi keresni a CLASSPATH környezeti változó által megadott könyvtárakban. Ha esetleg nem tudnád, mi a környezeti változó, íme egy kis bevezetõ:

2. kitérõ: környezeti változók

A Jáva a CLASSPATH környezeti változót használja a következõ módon. A CLASSPATH értéke könytárak sorából áll (Windows-on pontosvesszõvel, Unix-on kettõsponttal elválasztva). Amikor a rendszer keresni kezdi az a.b.C nevû osztályt, veszi az elsõ könyvtárat a CLASSPATH-en. Ehhez hozzáfûzi a csomag nevét, így lesz egy alkönytárnév és ebben keresi meg az osztálynév.class fájlt. Ha nem találja, továbblép a következõ könyvtárra a CLASSPATH-en és ezt addig csinálja, amíg a könyvtárak a CLASSPATH-en el nem fogynak. Ha nem tudta megtalálni azt osztályt a CLASSPATH-en felsorolt összes könyvtárban, hibajelzést küld.

Lássunk egy egyszerû példát! Tegyük fel, hogy a CLASSPATH értéke a következõ:

c:\Users\javadev;c:\Users\javalib

Tegyük fel továbbá, hogy a rendszer az a.b.C nevû osztályt keresi. Veszi tehát az elsõ könyvtárat a CLASSPATH-en, a c:\Users\javadev-et. Ehhez hozzáilleszti a csomagnevet, vagyis az a.b-t és kapja a c:\Users\javadev\a\b könyvtárat. Itt megpróbálja fellelni a C.class fájlt. Tegyük fel, hogy nem találta meg. Ekkor továbblép a c:\Users\javalib-re és megpróbálja ugyanezt, vagyis felkeresi a c:\Users\javalib\a\b\C.class fájlt. Ha ez megvan, siker. Ha nem, hibaüzenet.

Hosszadalmas magyarázat után vissza a pelda.Elso alkalmazásra! Ha figyelmesen megtanulmányozod a fájlokat a könyvtáradban, rájöhetsz, hol a hiba: a Jáva fordító az aktuális könyvtárba pakolta le a .class fájlt. Ez egy hülye tulajdonsága a javac-nak, amely a Jáva elsõ változata óta kísért. Tedd helyre olymódon, hogy létrehozol egy pelda alkönyvtárat és átmozgatod az Elso.class-t ebbe. Tedd meg! Ha most kiadod a java pelda.Elso parancsot, két dolog történhet: vagy mûködik, vagy nem. Sohase tudtam rájönni, miért, de bizonyos Jáva installációk ilyenkor képtelenek megtalálni a kurrens könyvtárban elhelyezkedõ alcsomagokat, csak ha varázsolunk a CLASSPATH-szel. He netán ez a hiba ütné fel undok fejét, vedd fel az aktuális könyvtárat a CLASSPATH-re.

set CLASSPATH=.

mondd a parancspromptnál Windows-on. Ha most megismétled a parancsot, mûködnie kell.

A javac-nak a tulajdonsága, miszerint mindenképpen az aktuális könytárba pakolja a .class fájlt, még ha az valamilyen csomagba fordítódik igazán kellemetlen és erre a Sun-nál is rájöttek. A Javac-ot meghívhatod a nagyszerû -d kapcsolóval, ekkor létrehozza a csomagok alkönyvtárait és mindent a helyére pakol. Próbáld ki! Töröld le az elõbb létrehozott pelda alkönyvtárat a benne levõ Elso.class-szel együtt, majd mondd azt:

javac -d . Elso.java

ekkor a pelda alkönyvtár rendben létrejön az aktuális könyvtárban és belekerül az Elso.class. Ekkor már probléma nélkül lehet futtatni a java pelda.Elso paranccsal.

A csomagok kezelésének a lehetõsége apróság a Nagy Egészben, de igazán fontos õket ismerni, ha bele akarunk kalandozni a Jáva osztálykönyvtárba.

Ellenõrzõ kérdések

  1. Mi a hasonlóság az alkönyvtárak és a csomagok között?
  2. Hogyan kell egy Jáva osztályt egy adott csomagba tenni?
  3. Mit jelent a package direktíva és mi a paramétere?
  4. Hogyan lehet egy csomagban levõ osztályt elérni?
  5. Mit egyszerûsít az import direktíva?
  6. Hogyan leli fel a virtuális gép a class fájlokat?
  7. Mi a CLASSPATH környezeti változó?
  8. Mi történik, ha a CLASSPATH értéke c:\Users\javalib;c:\Users\enyem és az a.b.C nevû osztályt keressük?
  9. Hova teszi a javac a lefordított osztályokat, ha egyszerûen csak a forrásfájl nevével hívjuk meg?
  10. Hogyan lehet elérni, hogy a javac a csomagokat a megfelelõ alkönyvtárba tegye?

Kovetkezo lecke Tartalomjegyzek