Tartalmi kivonat
http://www.doksihu Programozás Java nyelven Készítette: dr. Álló Géza http://www.doksihu Tartalomjegyzék Az OO paradigma . 3 Objektumok. 3 Jellemző tulajdonságok . 3 Osztályok . 3 Kapcsolatok. 4 Társítási kapcsolatok . 4 Leszármazási kapcsolat = öröklés . 4 Bővítési kapcsolat = implementálás . 5 Programfejlesztés . 5 Jellemzők . 5 Programtípusok . 5 Java-programok írása . 6 A Java nyelv születése . 6 Fejlesztői eszközök. 7 JDK (Java Development Kit) . 7 JCreator és JBuilder . 8 Jelölési megállapodások . 8 Futtatható program összeállítása . 9 A Java-program szerkezeti elemei . 11 Szintaktikai elemek . 11 Logikai elemek . 12 Struktúra-elemek . 15 Metódusok . 17 Osztályok . 19 Osztályfej . 19 Osztályblokk. 19 Interfészek . 20 Öröklés . 21 Bővítés . 21 Példányosítás . 21 Java osztályok felhasználása . 23 Konténerek . 25 Tömbök . 25 A Vektor osztály. 27 A Collections osztály . 28 Kivételkezelés . 28 Kivételek
lekezelése . 29 Kivételek továbbadása. 29 Állománykezelés . 30 Könyvtárkezelés . 30 Folyamok . 31 Karakterfolyamok. 31 Bájtfolyamok . 32 Közvetlen elérésű állományok . 33 Az extra csomag használata . 34 Átváltás primitív típusok és –objektumok valamint karakterláncok között . 35 http://www.doksihu Az OO paradigma Objektumok A valós világ jelenségei/dolgai közül csak azokkal foglalkozunk, amelyeket a megoldandó feladat szempontjából lényegesnek és/vagy fontosnak ítélünk; ezeket a továbbiakban objektumoknak nevezzük. Kiemeljük az objektumok (lehetőleg) egyértelmű jellemzőit, tulajdonságait és tevékenységi köreit, ezeket a továbbiakban tulajdonságoknak nevezzük. A továbbiakban csak programjainkban megvalósított objektumokról lesz szó. Ezek az objektumok információkat tárolnak, és kérésre előre meghatározott feladatokat oldnak meg Az objektum aktív elem: • Passzív tulajdonságait adatok írják le; ezeket az
objektum (formális) változói, illetve konstansai tartalmazzák. • Aktív tulajdonságait az általa megoldható feladatok határozzák meg, amelyeket metódusok hajtanak végre. A metódusok az objektum saját adataival, osztályának adataival, illetve az objektummal kapcsolatban álló (lásd alább) más objektumok adataival végezhetnek műveleteket. Jellemző tulajdonságok Állapot Az objektumok állapotát adataik pillanatnyi értéke határozza meg. Két, azonos osztályhoz tartozó objektum akkor és csak akkor egyenlő (= azonos állapotú), ha adataik értéke rendre megegyezik. Ebben az esetben ugyanarra a kérdésre pontosan azonos választ adnak. Két objektum akkor és csak akkor azonos, ha fizikailag ugyanazon a tárterületen helyezkedik el! Az azonos objektumok természetesen egyenlők is. Zártság Az objektum belseje sérthetetlen: adatai és metódusai kívülről közvetlenül nem, csak az interfészén keresztül érhetők el. Felelősség Az objektum
felelős, a feladatainak korrekt végrehajtásáért. A végrehajtás módja ("hogyan") az objektum belügye Működési mód Az objektum feladatait metódusok hajtják végre, s ehhez az objektum által elérhető adatokat használják. Az objektumokat üzenetek küldésével lehet rábírni, hogy végrehajtsanak egy feladatot. Egy üzenet az objektum egy metódusát aktiválja (= hívja meg). Polimorfizmus Különböző osztályú objektumok különféle válaszokat adnak ugyanarra az üzenetre. Osztályok Az osztály a típusfogalom általánosítása. Tulajdonképpen absztrakt objektum ("szabásminta"), önmagában nem működőképes. Formálisan meghatározza az adott típusú (osztályú) objektumok tulajdonságait, más szóval: tartalmazza adataik és metódusaik leírását. Működőképes, vagyis a kitűzött feladatok megoldására alkalmas objektumokat mindig egy osztály példányosításával hozunk létre (vö.: típusdeklaráció – adott típusú
változó deklarálása) Következésképpen minden objektum egy és csakis egy, pontosan meghatározott osztályba tartozik, osztályának egy példánya. (Az egyszerűség kedvéért a továbbiakban objektumon példányobjektumot értünk) http://www.doksihu Létrehozása után aktuális adatokkal töltjük fel az objektum formális adatait; ezt a lépést inicializálásnak, az inicializálást végző metódust konstruktornak nevezzük. Kapcsolatok Az osztályok társítási, illetve leszármazási, az objektumok társítási kapcsolatban lehetnek egymással. Mindkét kapcsolattípus lehet kötelező vagy választható (opcionális) Társítási kapcsolatok Ismeretségi kapcsolat Az osztályok, illetve objektumok egymástól függetlenül léteznek, és legalább egyikük ismeri, illetve használhatja a másik, illetve a többi objektum adatait és metódusait. Tartalmazási kapcsolat Egy osztály, illetve objektum ("egész") fizikailag tartalmaz (birtokol) egy vagy
több másik ("rész") objektumot. Gyenge tartalmazás esetén a részek elhagyhatók. Erős tartalmazás esetén az egész nem létezhetik a részek nélkül. A kompozícióban az egész minden részével erős tartalmazási kapcsolatban van. A rész soha nem létezhetik az egész nélkül. A tartalmazási kapcsolat erősebb az ismeretséginél: az egész mindig ismeri mindegyik részét; fordítva ez nem szükségszerű. Leszármazási kapcsolat= öröklés Az osztályokat bővíthetjük egyes újabb tulajdonságok figyelembe vételével, illetve szűkíthetjük korábban figyelembe vettek elhagyásával. Ilyen lépésekre azért lehet szükség, hogy egy osztályból származó objektumok az eredetileg kitűzöttektől kisebb-nagyobb mértékben eltérő feladatokat is meg tudjanak oldani Az öröklés során az ős osztályokból újabb, utód osztályokat származtatunk le. Az öröklődés tranzitív, és hierarchikus rendszert eredményez. Az utód örökli ősének
nyilvános (public), valamint védett (protected) adatait és metódusait, de nem férhet hozzá az ős saját (private) adataihoz és metódusaihoz. Deklarálhat viszont saját adatokat és metódusokat is, amelyekhez őse nem férhet hozzá Az utód deklarálhat az ősével azonos nevű változókat, illetve felülírhatja ősének azokat a metódusait, amelyek számára elérhetők; ezt takarásnak nevezzük. A letakart változókat, illetve metódusokat csak bizonyos feltételek teljesülése esetén lehet használni Multiplicitás Két osztály kapcsolatának multiplicitása azt fejezi ki, hogy az egyik osztályhoz hány objektum tartozhat a másik osztályból. Három esetet különböztetünk meg: Egy – egy kapcsolat Az egyik osztály egy objektuma (kliens) a másik osztálynak legfeljebb egy objektumával (szerver) van kapcsolatban. A kapcsolatot a kliens kezdeményezi, és a szerver teljesíti a kérést (ha tudja). Az egy-egy kapcsolatot úgy valósítjuk meg, hogy a kliens
osztályban létrehozunk egy hivatkozást (referenciát), amely a szerverre mutat. Egy – sok kapcsolat Ebben az esetben a kliens több szerverrel van kapcsolatban. Az ilyen kapcsolatot a Javaban konténerrel valósítjuk meg (lásd alább). Sok – sok kapcsolat Mindkét osztály bármelyik objektuma a másik osztály több példányával állhat kapcsolatban. Ilyen kapcsolatok megvalósításával egyelőre nem foglalkozunk http://www.doksihu Bővítési kapcsolat =implementálás A Javban az Interfész absztrakt osztály: üres metódus-definíciókat (metódusfejeket) tartalmaz. Ebből következik, hogy nem példányosítható; viszont örökíthető, ezt nevezzük implementálásnak. Az interfész metódusait az implementáló osztályban kell megvalósítani Interfész típusú változóval lehet objektumot azonosítani. Interfészek használata helyettesíti a többszörös öröklést. Értékadási kompatibilitás tekintetében az implementáció egyenértékű az
örökítéssel. Programfejlesztés A programfejlesztés felelős alkotómunka, amelyet nem lehet improvizációval megoldani. A programozó felelős programja helyes működéséért, javíthatóságáért és használhatóságáért. Több programból álló rendszer fejlesztési lépései: • követelmény-feltárás (a feladat meghatározása), • elemzés (megoldhatóság és erőforrás-igény felmérése), • tervezés (algaritmusok kidolgozása, programterv), • kódolás (programok megírása), • tesztelés, • dokumentálás (fejlesztői és felhasználói dokumentum megírása). Jellemzők Minőségi programnak a következő követelményeket kell kielégítenie: • helyes (megfelel a kitűzött feladatnak), • hibatűrő (elviseli a hardver és szoftver hibákat), • elronthatatlan (felhasználói beavatkozással nem lehet kiakasztani), • módosítható ("állandó csak a változás"), • hatékony (jó erőforrás kihasználás, nagy sebesség), •
ellenőrizhető (tesztelhető), • felhasználóbarát, • hordozható. Programtípusok Az objektumorientált program egymással kapcsolatban álló, információcserére képes objektumok összessége, ahol minden objektumnak jól meghatározott, a többi objektumétól különböző feladata van. Kötegelt program Az indításkor megadott paramétereket és futási feltételeket a futás során nem lehet megváltoztatni. Interaktív program Algoritmusvezérelt: a beavatkozásokat a program irányítja: az aktor (= felhasználó) a program kérdéseire válaszolhat. Eseményvezérelt: az aktor bármikor beavatkozhat a program futásába: a program fogadja és feldolgozza a beavatkozásokat, végrehajtja az utasításokat. http://www.doksihu Java-programok írása A Java nyelv születése A Java nyelvet a Sun MicroSystems cég JavaSoft nevű munkacsoportja fejlesztette ki. Eredetileg (1991) távközlési eszközök vezérlésre szánták, ám később (1992) átalakították úgy,
hogy a Javaprogramok gépfüggetlenek, vagyis (elvben) bármely számítógépen futtathatók legyenek. Miközben az alkotók megfelelő néven töprengtek, éppen kávéjukat ("a cup of Java") fogyasztották, amely történetesen a Java nevet viselte Világhódító útjára akkor indult, amikor (1994) egy Internet-böngészőbe belecsempészték a Java futtatórendszert, majd az új terméket 1995. május 23-án nyilvánosan is bemutatták Ma már nincs böngésző, amely nem Java-képes. Jellemzők A fejlesztők által kiadott hivatalos ismertetés 11 tulajdonsággal jellemzi a Java nyelvet. Mindegyiküket ugyan eddig nem sikerült maradéktalanul megvalósítani, a nyelv továbbfejlesztése viszont rendületlenül folyik. • Egyszerű (simple): A C++ nyelv egyszerűsített változata; nem hivatásos programozók is könnyen tudják használni. (Rosszmájúak szerint C++--) • Objektumorientált (object-oriented): A Java nyelven írt forrásprogramokban – a
továbbiakban Java-programokban – a feladatokat osztályok kialakításával, illetve leszármaztatásával, és a belőlük létrehozott objektumok működtetésével kell megoldani ("tiszta objektumorientált nyelv"). Egy feladat megoldására szolgáló Java-programok összessége az alkalmazás (application). • Elosztott (distributed): Bármely URL címről fogadhat állományokat. A böngészők a Java nyelv szűkített változatát (subset) ismerik, amelyben – többek között – nem lehetséges más gépek állományait kezelni. A cél a HTML nyelv nehézkességeinek kiküszöbölése volt. Az így készült Java-program az alkalmazáska (applet) Hálózati szerver-gépek programozására fejlesztették ki a Java JSP változatát; ezen a nyelven írt Java-program a servlet. • Robusztus (robust), másképpen hibatűrő (fault-tolerant): egyfelől a rendszerhibák nem teszik tönkre a programokat, és leállás előtt a programozó kellő tájékoztatást a kap
a hiba okáról. Másfelől a programhibák nem akasztják meg a rendszer futását, és semmilyen esetben sem tesznek kárt a számítógép rendszer- és egyéb alkalmazási programjaiban. • Biztonságos (secure): Kódja védett idegen beavatkozások ellen. Sajnos, a Javaadatállományokról ezt nem lehet elmondani • Gépfüggetlen (architecture neutral): A gépfüggetlenséget úgy érik el, hogy a Javaprogramot a Java fordító egy virtuális (elképzelt) gép, a JVM (=Java Virtual Machine) – szabványosított – utasításaiból álló úgynevezett bájtkódra fordítja le. • Értelmező-alapú (interpreted): A bájtkódból egy speciális értelmező (interpreter) program állítja elő a konkrét számítógép bináris (natív) utasításaiból álló, végrehajtható programot; a továbbiakban – nem egészen pontosan – ezt a programot nevezzük JVM-nek. 1 A módszer hátránya, hogy az JVM utasításonként fordítja át a bájtkódot, emiatt a program futása
meglehetősen lassú. A JVM-et folyamatosan fejlesztik, Újabban fordítóprogramok is készülnek: a JIT (Just In Time) fordítóprogram például több mint 10-szer gyorsabb az értelmezőknél. 1 A virtuális gép ötletét Niclas Wirth dolgozta ki. Nyilvánvaló, hogy egy Java nyelven megírt program csak akkor futtatható egy adott számítógépen, ha azon telepítve van a JVM bájtkódját ismerő interpreter, amelyet előzőleg természetesen meg kellett írni. http://www.doksihu • • • • Hordozható (portable): A Java forrásprogram minden gépen futtatható, amelyiken telepítve van a JVM. Hatékony (high performance): A JVM a lehető legjobban gazdálkodik a számítógép erőforrásaival, és a lehető leggyorsabb kódot állítja elő. Mivel a két követelmény ellentmondó, a gyakorlatban csak egyik valósítható meg maradéktalanul Többszálú (multithread): A lefordított program több, párhuzamosan futtatható programrészből ("szálból")
áll, amelyek (látszólag) egyidejűleg futnak. 2 Dinamikus (dynamic): A Java-program interaktív, és legtöbbször eseményvezérelt. A forrásprogram könnyen bővíthető és könnyen futtatható Fejlesztői eszközök JDK (Java Development Kit) A Java különböző verzióit JDK néven adják ki. A fejlesztés folyamatos, jelenleg a JDK142 változat van forgalomban. A JDK tartalmazza a programfejlesztéshez és -futtatáshoz szükséges rendszerprogramokat, valamint a Java osztálykönyvtárát (API = Application Programming Interface), mind forráskód (src.jar 3), mind bájtkód (rtjar) formában Telepítsük a JDK programcsomagot külön könyvtárba; ennek fontosabb alkönyvtárai: bin primitív fejlesztői környezet; fontosabb programjai: javac.exe fordítóprogram (compiler): a Java forrásprogramot szintaktikusan elemzi és jelzi az esetleges hibákat; a szintaktikusan helyes programot bájtkódra fordítja java.exe a JVM megvalósítása (interpreter): értelmezi és
futtatja a bájtkódot appletviewer.exe a böngészőkbe beépített (szűkített) JVM, segítségével lehet tesztelni, hogy appletkjeinket milyennek látjuk majd a böngészőben A fejlesztői programok futtatásához be kell állítani a DOS két környezeti változóját: • a PATH változóhoz hozzá kell fűzni az aktuális JDK-könyvtár útvonalát; • a CLASSPATH változóban pedig – az aktuális könyvtáron kívül – meg kell adni az egyéb programcsomagok – esetünkben az extra csomag – elérési útvonalát is. jre (Java Runtime Environment) a Java futtatási környezete, nélküle nem futtathatók a Java programok; két alkönyvtára: bin a JVM másolata; lib a Java osztálykönyvtár egyes osztályai bájtkód formában. Az API osztálykönyvtár felépítése A Java talán legnagyobb előnye, hogy rengeteg (több mint 2000) "előregyártott" osztályt kínál felhasználásra. Két főcsomagból (java, javax) áll, amelyekben a logikailag
összetartozó osztályokból és interfészekből csomagokat, egyes csomagokban további alcsomagokat képeztek; a legfontosabbak: A valóságban az egyprocesszoros gép egy időpillanatban természetesen csak egy utasítást tud végrehajtani, azonban a futási időt "igazságosan" elosztja a programrészek között; például amíg az egyik programrész adatátvitelre vár, egy másik programrész fut. 3 A .jar (Java ARchive) kiterjesztésű programok önállóan futtathatók (jre nélkül) de futtatásukhoz székség van a jawawexe rendszerprogramra 2 http://www.doksihu java applet: appletek írásához szükséges osztályok awt: (Abstract Window Tools) grafikus felhasználói felület létrehozását segítő osztályok; alcsomagjai például font: betűkészletek, event: eseményfigyelők stb. io: állománykezelő osztályok lang: (language) a Java alaposztályai (Integer, Math, Object, String, StringBuffer, System stb.); ezt a csomagot a fordító automatikusan
hozzáfűzi minden Java-programhoz, nem kell importálni! util: kisegítő osztályok (naptár, nemzetközi beállítások stb.), konténerek (Vector, Collections stb.), javax swing: az awt korszerűsített ("könnyed"), gépfüggetlen változata sound: hangeffektusok JCreator és JBuilder A J-Creator, illetve a JBuilder nevű szerkesztőprogram segítségével könnyen írhatunk Java forrásprogramokat; azonban ezek futtatásához is szükség van a JDK fejlesztői programjaira. Csak a JBuilderrel foglalkozunk, mert kezelni tudja az ékezetes betűket is. Projekt JBuilder-ben csak projektekben lehet alkalmazást fejleszteni. Egy konkrét alkalmazást alkotó forrásállományok és környezeti beállítások összessége Projektállomány Minden projektet egy projektállomány azonosít; kiterjesztése: jpx. A projektállomány tartalmazza a projekt leírását; többek között: - a projektet alkotó állományok listáját, - a JDK profilt, - a projektben használt
útvonalakat, - nyomkövetési és fordítási beállításokat stb. A projektútvonalak a projektállományhoz képest relatívak, így a teljes projekt-könyvtár bárhova áthelyezhető. Alkalmazás-böngésző A JBuilder párbeszédablaka, egy alkalmazás kifejlesztéséhez. Fő területei: - projektpanel: a projekthez tartozó fordítási egységek listája; - struktúrapanel: az aktuális fordítási egység objektumainak felsorolása; - tartalompanel: az aktuális fordítási egység forráskódja; itt írhatjuk, szerkeszthetjük és javíthatjuk a Java-programokat; - üzenetpanel: fordítási és futási hibák, valamint felhasználói (program) üzenetek kiírása, bemenő adatok megadása. Jelölési megállapodások Java-programok tervezésére az UP (Unified Process = egységes eljárás) módszertanát, a programok különböző nézeteinek modellezésére és dokumentálásra az UML (Unified Modeling Language = egységes modellező nyelv) grafikus jelölésrendszerét
szokás használni. Az alábbiakban csak a legfontosabb szabályokat foglaljuk össze: • A diagramokon az osztályokat téglalappal ábrázoljuk, amelyet két vonallal 3 részre tagolunk (akkor is, ha a középső és az alsó sávot üresen hagyjuk): http://www.doksihu A felső sávba írjuk az osztály nevét, nagy kezdőbetűvel és kiemelt (nyomtatásban félkövér) betűtípussal: <OsztályAzn>. A középső sávba kerülnek az osztály saját adatai. Az adatok hozzáférési módja (láthatósága) négyféle, lásd 13 oldal Az alsó sávban az osztály metódusait soroljuk fel, ezek láthatóságának jelölése megegyezik az adatokéval. Az osztálytagokat (= osztályváltozókat és osztálymetódusokat) a programban static módosítóval, a rajzban aláhúzással különböztetjük meg a példánytagoktól (= példányváltozóktól és példánymetódusoktól). • A diagramokon az interfészeket is téglalappal jelöljük, de ezt csak két részre
osztjuk: Az objektumoktól megkülönböztetendő, a felső sávban a nevük előtt <<interfész>> jelölést alkalmazzuk. Az alsó sávban az esetleges konstansokat és az interfész absztrakt metódusait soroljuk fel. Interfésznek nem lehetnek változói! Absztrakt objektumokat nyomtatásban dőlt betűvel, rajzban szaggatott aláhúzással jelölünk. • A diagramokon az objektumokat is téglalappal ábrázoljuk; ezt szükség esetén egy vonallal két részre osztjuk: A felső sávban szerepel az objektum azonosítója <objAzn>:<OsztNév> formában, aláhúzva. Az alsó sávban a példánytagokat, vagyis az objektum saját adatait és metódusait tüntetjük fel, ha ilyenek vannak. • A kapcsolatokat folytonos, nyílvégű vonallal ábrázoljuk, a nyíl a klienstől a szerver felé mutat. A tartalmazási kapcsolatot az egész oldalon üres (gyenge), illetve tele (erős) rombusz jelöli • A multiplicitást a kapcsolatot
jelképező vonalra, közvetlenül az osztály rajzjele mellé írjuk. Lehetséges esetek: *: akárhány (0 is); 1.* : legalább egy; m.n : m és n közé eső szám, a határokat is beleértve; például 01 : nulla vagy egy; k: pontosan k darab; ha nem írunk semmit, pontosan 1 darabot jelent; 1,4,7.* : 1 vagy 4, vagy legalább 7; • Az öröklést folytonos vonallal jelöljük, amelynek végén az ős-osztály felé mutató, üres háromszög fejű nyíl van. Ugyanígy jelöljük az interfészek közötti öröklést is. • Az implementálást szaggatott vonallal jelöljük, amelynek végén az interfész felé mutató, üres háromszög fejű nyíl van. • A (példány)objektumot szaggatott vonallal köthetjük osztályához; ekkor a nyíl az osztály felé irányul. Futtatható program összeállítása Fordítási egység = forrásállomány A fordítási egység osztályokból áll, amelyek közül legfeljebb egy lehet nyilvános (public). A
forrásállomány kötelezően .java kiterjesztésű Az osztályok deklarálási szabályait lásd a 19. oldalon Ha az állományban van olyan nyilvános főosztály, amelyik a main metódust tartalmazza, akkor a főosztály nevének meg kell egyeznie az állomány nevével (betűhíven, kis- és nagybetűk különbözők!) http://www.doksihu Egy Java-program több fordítási egységből is állhat; a többi forrásállomány neve célszerűen, de nem kötelezően azonos az első (nyilvános) osztály nevével. Main metódus A főosztálynak tartalmaznia kell egy main nevű, visszatérési érték nélküli, nyilvános osztálymetódust, amelynek paramétere az indítási (program)argumentum-tömb. A metódusfej szintaxisa: public static void main (String args[ ]) Minden Java alkalmazásban egy és csakis egy main metódusnak kell lennie. A metódusok írási szabályait lásd a 17. oldalon Csomagolás A logikailag és/vagy fizikailag összetartozó osztályokból és
interfészekből csomagot képezhetünk, a package <csomagnév>; csomagdeklaráló utasítással, amely kötelezően a fordítási egység első utasítása. Következmény: egy forrásállomány minden osztálya és interfésze kötelezően ugyanabban a csomagban van. Egy csomagba több fordítási egység is tartozhat, ezeknek kötelezően ugyanabban a könyvtárban kell lenniük. A csomagnév egy szó, és csupa kisbetűvel írjuk. Importálás Ha más csomagokat, illetve ilyenekben levő osztályokat is használni akarunk, ezeket importálni kell, a következő szintaxis szerint: teljes csomag: import <csomagnév>.*; csomagon belüli csomag: import <csomagnév>.<belső csomagnév>*; csomag egy osztálya: import <csomagnév>.<OsztNév>; Az importáló utasítás kötelezően a fordítási egység – csomagdeklaráció utáni – első utasítása. A fordító minden programhoz automatikusan hozzáfordítja a java.lang könyvtárból a szükséges
osztályokat, ezeket nem kell importálni. Fordítás Ha a JDK fejlesztői környezetével dolgozunk, akkor a forrásállományokat javac <áll név>.java utasítással kell lefordítanunk. Hibátlan fordítás után a fordító minden fordítási egység minden osztályából <OsztNév>.class kiterjesztésű bájtkódot generál A névvel bíró belső osztályok azonosítója <külső OsztNév>$<belső OsztNév> alakú; a névtelen belső osztály neve helyett sorszám áll. Ha az alkalmazás több fordítási egységből áll, mindegyiket külön le kell fordítani. Futtatás A futtatást a főosztályt tartalmazó állomány a nevével kell indítani, java <áll név> utasítással ( a .class kiterjesztést tilos megadni) Az alkalmazás belépési pontja a main metódus, és a program addig fut, amíg ennek végéhez nem ér. A lefordított program használja az API osztálykönyvtárat, ezért a futtatáshoz léteznie kell a JDK könyvtárban a
jre alkönyvtárnak! http://www.doksihu A Java-program szerkezeti elemei Szintaktikai elemek Minden Java forrásprogram unikód karakterekből áll, a kis és a nagybetűk különbözőnek számítanak. Speciális karakterek fehér szóköz: szóköz: u0020); tabulátor: = u0009; kocsi vissza : = u000D; soremelés: = u000A; lapemelés: f = 00C; escape-szekvencia: visszatörlés (backspace): = u0008; aposztróf: = u0027; idézőjel: " = u0022; visszatörtvonal: \ = u005C; Azonosító A logikai programelemeket (változó, metódus, objektum, osztály) nevük azonosítja. A változók nevének egy osztályon belül egyedinek kell lennie. Egy név tetszőleges hosszúságú unikód karaktersorozat, az angol abc betűiből 4, számjegyekből és aláhúzásból; első karaktere nem lehet számjegy; nem lehet kulcsszó, sem nyelvi konstans (true, false, null); További megállapodások: az osztályok nevét nagybetűvel, a változók és a metódusok nevét
kisbetűvel, szóösszetételekben a belső szavakat nagybetűvel kezdjük; a csomagnevet csupa kisbetűvel, a konstansok nevét csupa nagybetűvel írjuk. Kulcsszó Fontosabb kulcsszavak: típusjelölők: boolean, byte, char, short, int, long, float, double; final, void; vezérlők: if – else if – else, switch – case – default, for, while, do - while, break, continue, return; módosítók: public, protected, private, static, abstract, final; példányosító: new; hivatkozások: this, super; Literál A programba beépített állandó (konstans). Fajtái: egész: pozitív vagy negatív egészszám, illetve nulla; megadható decimálisan (alapértelmezés), hexadecimálisan: 0x, illetve oktálisan: 0; típusa alapértelmezésben int, utána írt L/l 5 minősítővel long; valós: decimális pozitív vagy negatív egész-, tört- vagy vegyesszám; megadható tizedesponttal vagy exponenciális formában; típusa alapértelmezésben double, utána írt F/f
minősítővel float; karakter: aposztrófok között egyetlen karakter; megadható látható karakterrel, unikóddal vagy escape-szekvenciával; típusa char; szöveg: idézőjelek közé írt, tetszőleges hosszúságú karaktersorozat; tartalmazhat látható karaktereket, unikód-karaktereket és escape-szekvenciákat. A szövegeket String típusú mutatójuk azonosítja (lásd 23. oldal) 4 5 A JBuilder megengedi ékezetes betűk használatát is. l minősítőt ne használjunk, mert összetéveszthető az 1 számjeggyel! http://www.doksihu Kerüljük a literálok használatát, mert megnehezítik a hibakeresést! Elválasztójel (szeparátor) blokk-képző kapcsos zárójelpár : { } metódusképző kerek zárójelpár: ( ) tömbképző szögletes zárójelpár: [ ] listaelem-elválasztó vessző: , minősítő pont: . utasítás-záró pontosvessző: ; Operátor (műveleti jel) Matematikai, logikai, minősítő és egyéb műveletek
elvégzését előíró jel. Az operátorok hierarchikus rendszert alkotnak; rangjukat a precedencia-rend írja elő. A Java operátorait, csökkenő precedencia-rendben a következő táblázat tartalmazza; az egy sorban levők azonos rangúak, kiértékelésük irányát a nyíl mutatja. Operátor Elnevezés Kiértékelés [ ] ( ) . ++ - ++ - - + - ~ ! new (<típus>) <kifejezés> * / % + << >> >>> < <= > >= instanceof == != & ^ | && || ?: = += -= *= /= %= &= ^= |= <<= >>= >>>= unáris postfix operátorok unáris prefix operátorok példányosítás, típuskényszerítés multiplikatív operátorok additív operátorok bitenként léptető operátorok hasonlító operátorok egyenlőségvizsgáló operátorok logikai, illetve bitenkénti ÉS logikai, illetve bitenkénti XOR logikai, illetve bitenkénti VAGY logikai rövid ÉS logikai rövid VAGY feltételes kiértékelés értékadó operátorok
--> <---> --> --> --> --> --> --> --> --> --> --> --> <-- Megjegyzés Egysoros megjegyzést // karakterek után a sor végéig, tetszőleges hosszúságú, akár többsoros megjegyzést /* / megjegyzés-zárójel között írhatunk. A megjegyzéseket a fordítóprogram figyelmen kívül hagyja. Logikai elemek Az objektumokat alkotó logikai elemek a változók és a kifejezések. A Java szigorúan típusos nyelv: minden logikai elemnek valamilyen típussal kell rendelkeznie. Változók A változók – ide értve a konstansokat is – tartalmazzák a feladatok megoldásához szükséges adatokat. A változókat deklarálni kell A deklarálás a változó módosítójának, típusának és nevének (azonosítójának), illetve esetleg kezdőértékének megadását jelenti, a következő szintaxis szerint: [<módosítók>] <típus> <azn1> [= kifejezés1] [, azn2 [= kifejezés2]] http://www.doksihu Módosítók
Láthatósági módosítók Meghatározzák, hogy a változó, illetve egy objektum mely (más) objektumokból érhető el: public (nyilvános): az alkalmazás bármely objektumából elérhető (UML: +); protected (védett): csak az utód-osztályokban, illetve az ezekből képzett objektumokban érhető el (UML: #); private (magán): csak a deklarációt tartalmazó objektumban érhető el (UML: -). Alapértelmezésben nem adunk meg láthatósági módosítót, ekkor a változó, illetve az objektum saját csomagjában nyilvános. Minden változó elérhető abban az objektumban, amelyben deklaráltuk. Kifejtettség-módosítók static: osztályváltozó, ha nem adjuk meg példányváltozó jön létre; final (végleges): a módosítóval konstanst képezhetünk; szintaxisa: final <típus> <azonosító> = <kifejezés>; A konstans nem változtatható értékű változó, ezért konstans ≠ literál! Konstansra a programban névvel hivatkozhatunk, a
literálra nem! Típusok A Javaban két alaptípus létezik (lásd a táblázatot a következő oldalon): • Primitív típus 8 féle van, ezek közül 7 numerikus, 1 logikai típus. A numerikus típusok sorszámozottak vagy valósak lehetnek; az előbbiek között megkülönböztetjük az egész és a karakter típust. A karakterlánc nem típus, hanem a String osztály egy példánya! • A hivatkozási (referencia) típus tulajdonképpen mutató, amely egy objektum tárcímét (= hivatkozását) tartalmazza. Az objektum összetett elem, tárolásához különböző méretű tárterület szükséges, attól függően, hogy hány és milyen (primitív, illetve hivatkozási) típusú változót tartalmaz Kétféle hivatkozási típust különböztetünk meg aszerint, hogy a mutató (valódi vagy interfész) osztály objektumára vagy tömbre hivatkozik-e. Típusa megadásával a változó három jellemzőjét határozzuk meg: a tárolásához szükséges tárterület méretét
(bájtban), ezzel összefüggésben értékkészletét (lásd táblázat), valamint a változóval végezhető műveleteket. A változók azonosítójának tartalma mindig egy tárterület címe (4 B), ami primitív típusú változók esetén az adat címe (közvetlen cím), hivatkozási típusú változók esetében pedig az adat címének címe (indirekt cím, vagyis annak a tárterületnek címe, ahol az adat található). A táblázatban a primitív típusok mérete az adat méretét jelenti, nem az azonosítóét! http://www.doksihu Java típusok Karak- Hivatkozási Osz tály Logikai Valódi Interfész Tömb Egész Sorszámozott Név Valós Numerikus Primitív Csoport char byte short int long float double boolean <OsztályNév> <InterfészNév> <típusNév>[] Méret 2B 1B 2B 4B 8B 4B 8B 1B 4B 4B 4B Értékkészlet u0000 uffff (65535) -128 127 -32 768 32 767 -2 147 483 648 2 147 483 647 - 263 ≈ -1019 263-1 ≈ 1019 (19 ≈
1.4e-45 ≈ 34e38 (6-7 ≈ 4.94e-324≈ 18e308 (14-15 false true Kifejezések Operátorokkal, tényezőkkel, valamint kerek zárójelpárokkal kifejezéseket képezhetünk a <tényező> <operátor> <tényező> szintaxis szerint. A <tényező> (vagy <operandusz>) változó, literál, függvényérték vagy másik kifejezés lehet. Tényezőik száma szerint kétféle operátort különböztetünk meg: Az unáris operátorokhoz csak egy tényező tartozik, ilyenkor a prefix operátor a tényező előtt, a postfix operátor a tényező után áll. A bináris operátorok két tényezővel végzett műveleteket írnak elő, és a tényezők között állnak. Kiértékelési szabályok Először a zárójelben levő kifejezések értékelődnek ki, egymásba ágyazott zárójelpárok esetén belülről kifelé haladva. A műveletek végrehajtási sorrendje megegyezik az operátorok precedenciarendjével (rangjával). Azonos rangú
operátorokkal jelölt műveletek a kiértékelési iránytól függően balról jobbra, illetve jobbról balra haladva hajtódnak végre. Típusváltás (konverzió) Bővítő konverzió: byte --> short --> int --> long --> float --> double; char --> int. Long --> float konverzió esetén a pontosság csonkulhat! Implicit konverzió Műveleteket azonos vagy kompatibilis típusú tényezőkkel lehet végezni. Ha a tényezők nem azonos típusúak, a fordító automatikusan konvertál: a tényezőket a kiértékelés előtt, majd az eredményt: • unáris művelet esetén az int-nél szűkebb típust int-re, • bináris műveletben mindkét tényezőt a bővebb típusra, de legalább intre konvertálja; • értékadáskor, ha a jobboldal típusa szűkebb a baloldalénál: implicit bővítő, http://www.doksihu int, de belefér a baloldali char, byte vagy short típusba: implicit szűkítő konverzió történik. Minden más esetben fordítási
hiba keletkezik. Explicit konverzió Az eredmény típusát "kényszerítéssel" is előírhatjuk a (<típus>) <kifejezés> szintaxis szerint. Ilyenkor a fordító semmilyen ellenőrzést nem végez Struktúra-elemek A Java-program háromféle struktúra-elemből épülhet fel. Utasításblokk Logikailag összetartozó utasítások (utasítás)blokkot alkotnak. Hatásuk szerint megkülönböztethetünk aritmetikai, logikai és szöveges értékadó, vezérlő (elágaztató, ciklusképző, ugró, rutinhívó), be-/kimeneti (adatbekérő és üzenet kiíró, állománykezelő), valamint objektum-kezelő (létrehozó, átalakító, tulajdonság-módosító) utasításokat. A blokkokat (kapcsos) blokkzárójelek: { } határolják A blokkokban lokális változókat lehet deklarálni, amelyek csak a blokkon belül élnek, a blokk elhagyásakor megszűnnek létezni. Ha egy lokális változó neve azonos egy magasabb szintű változóéval, akkor ezt
"letakarja", vagyis a magasabb szinten deklarált változó abban a blokkban csak bizonyos feltételekkel érhető el (lásd az öröklésnél, 21. oldal) Az egy szekvenciát alkotó utasításokat azonos bekezdési szinten írjuk. Egy utasítás tetszőleges számú sorba írható, és mindenkor pontosvesszővel kell lezárni Blokkok, elágazások és ciklusok tetszőleges sorrendben és mélységben egymásba ágyazhatók. Ilyenkor a bekezdési szintek száma a beágyazás mélységével arányosan növekszik Elágazások Feltételvezérelt elágazás if (<feltétel1>) { <blokk1>; } [else if (<feltétel2>) { <blokk2>; } else { <blokkn>; }] Szintaktikai szabályok: A feltétel tetszőleges logikai kifejezés lehet, és mindenkor kerek zárójelek között kell megadni. Feltétel után ne tegyünk pontosvesszőt! Egyágú elágazásnak nincs, kétágúnak egyetlen else ága van; többágú elágazásban tetszőleges számú else if
ág szerepelhet. Ha van ilyen, az utolsó else kulcsszó utáni blokk akkor hajtódik végre, ha egyetlen előző feltétel sem teljesült http://www.doksihu Elágazások egymásba ágyazása esetén az else ág a közvetlen előző if ághoz csatlakozik! Ha ezt nem kívánjuk, ki kell tennünk a blokkzárójelet. Kifejezés-vezérelt elágazás switch (<kifejezés>) { case <érték1>: <blokk1>; break; [case <érték2>: <blokk2>; break; default: <blokkn>; ] } Szintaktikai szabályok: A switch kulcsszó után tetszőleges aritmetikai kifejezés állhat, de típusa csak char, byte, short vagy int lehet. Mindegyik érték csak konstans kifejezés lehet, vagyis csak literálokat és konstansokat (final típusú változókat) tartalmazhat. Két azonos értéket tilos megadni Tartományt több egymás utáni "üres" eset (break nélküli) felsorolásával lehet megadni. Az egyes eseteket break utasítással kell elválasztani,
különben a blokkok folyamatosan végrehajtódnak. Bármelyik blokk helyén "üres" utasítás is állhat Az elágazásban egyetlen blokk hajtódik végre, amelynek vezérlő értéke egyenlő a <kifejezés> értékével. Ha ilyen vezérlő érték nincs, a vezérlés a default kulcsszó utáni blokkra kerül (ha van ilyen). Ciklusok Léptető ciklus for (cv1=<ért1> [,cv2=<ért2>]; <feltétel> ; <lépt1> [,<lépt2> ]) { <cilusmag>; } Szintaktikai szabályok: A ciklusfej három választható (opcionális) részből áll, amelyeket két, kötelezően megadandó pontosvessző választ el. Az inicializáló részben tetszőleges számú (ciklus)változónak adhatunk értéket. Az értékadásokat vesszővel kell elválasztani. A <feltétel> tetszőleges logikai kifejezés lehet, amelyet a Java a ciklusmag minden végrehajtása előtt kiértékel ("előltesztelő ciklus"). A ciklusmag mindannyiszor
végrehajtódik, ahányszor a kifejezés igaz (true) értékű. A léptető részben tetszőleges számú, vesszővel elválasztott léptető utasítás állhat, amelyeket a Java a ciklusmag minden egyes lefutása után végrehajt. Aki nem ragaszkodik a végtelen ciklushoz, célszerűen ebben a részben lépteti a ciklusváltozó(ka)t, illetve módosítja a feltételt. Feltételvezérelt ciklus Előltesztelő: Hátultesztelő: while (<feltétel>) do { { <ciklusmag>; <ciklusmag>; http://www.doksihu } } while (<feltétel>); Szintaktikai szabályok: A <feltétel> tetszőleges logikai kifejezés lehet, amelyet a Java a ciklusmag minden egyes lefutása előtt (előltesztelő változat), illetve után (hátultesztelő változat) kiértékel. A ciklus addig fut, amíg a kiértékelés igaz (true) értékű; a hátultesztelő ciklus legalább egyszer lefut. Végtelen ciklust legkönnyebben úgy lehet írni, hogy a ciklusmagban nem
változtatjuk meg a feltételt. Megszakítás és kihagyás Bármelyik ciklusban bárhol elhelyezhetünk break utasítást. Hatására az aktuális ciklus megszakad és a vezérlés a ciklusmag utáni utasításra, egymásba ágyazott ciklusok esetén az eggyel magasabb szintű ciklus következő utasítására kerül. Bármelyik ciklusban bárhol elhelyezhetünk continue utasítást. Hatására a ciklusmagban még hátralevő utasítások kimaradnak, és a vezérlés az aktuális ciklusfeltétel kiértékelésére kerül. A ciklus a kiértékelés eredménye szerint, ugyanúgy folytatódik, mint normál esetben. Metódusok A metódus egy (utasítás)blokkból álló programrutin, ami egy objektum egy konkrét feladatának algoritmusát valósítja meg. A metódus eljárás, ha nincs visszatérési értéke, illetve függvény, ha van. A függvényeket eljárásként is meg lehet hívni, ilyenkor visszatérési értékük elvész Szintaktikailag a metódus (metódus)fejből és
(metódus)blokkból épül fel. Metódusfej A metódusfej deklarálásának szintaktikája a következő: [<módosítók>] <vt típ> <metNév> ([<form par lista>]) [throws <kivétel>] Módosítók 6 A módosítók a metódust minősítik, sorrendjük tetszőleges. Az egy csoportba tartozók kölcsönösen kizárják egymást. Láthatósági módosítók: lásd 13. oldal Kifejtettség-módosítók: abstract: öröklési célra készült üres metódus: nincs metódusblokk (vagyis kapcsos zójelpár), egy utód osztályban kell majd kifejteni; ilyenkor a metódusfejet ; (pontosvessző) zárja. Absztrakt metódus módosítója nem lehet final. final (végleges): az utód osztályokban a metódus nem módosítható. Osztály-jelölő módosító: static (statikus): osztálymetódus; csak osztálytagokra, vagyis statikus változókra és metódusokra hivatkozhat. Ha ez a kulcsszó hiányzik, példánymetódusról beszélünk; a példánymetódus
példánytagokra (= példányváltozókra és más példánymetódusokra), valamint nyilvános (public) osztálytagokra egyaránt hivatkozhat. 6 Az itt felsoroltakon kívül egyéb módosítók még: transient, volatile (csak változókra), illetve native, synchronized (csak metódusokra); ezekkel nem foglalkozunk. http://www.doksihu Típusjelölő A <vt típus> a metódus visszatérési értékének típusát határozza meg; kötelező megadni. Az eljárások visszatérési típusa void (üres). A függvények visszatérési típusa bármilyen primitív vagy hivatkozási típus lehet. Azonosító Képzési szabályait lásd a 11. oldalon Értelmezési (szemantikai) szabályok: Egy metódust szignatúrája, vagyis neve és formális paraméterlistája együttesen azonosít; a metódus meghívásakor erre figyelemmel kell lenni. Példánymetódust csak példánymetódusból, osztálymetódust példány- és osztálymetódusból is meg lehet hívni, a láthatóság
figyelembe vételével. A Java külön kezeli a változók és a metódusok nevét, ezért egy osztályon belül egy változó és több, különböző szignatúrájú metódus neve is azonos lehet. Túlterhelés Egy metódus túlterhelése azt jelenti, hogy osztályában azonos névvel, de különböző paraméterlistával – eltérő szignatúrával – további metódus(oka)t is deklarálunk. A túlterhelés előnye, hogy a metódus meghívásakor egyes formális paramétereket nem kell megadni Gyakorlatban a kevesebb formális paraméterrel bíró metódus hívja meg a teljes formális paraméterlistával rendelkezőt úgy, hogy osztály- vagy példányváltozókkal pótolja a hiányzó paramétereket. Paraméterátadás A <form par lista> formális paraméterek vesszővel elválasztott felsorolása, amelyben mindegyiknek meg kell adni a típusát is. A formális paraméterek szintaktikailag lokális változóknak minősülnek, ezért nevük nem lehet azonos más,
metódus szintű lokális változóéval. A metódushívásban az aktuális paraméterlistának a formális paraméterlistáéval megegyező számú, és értékadás szerint kompatibilis aktuális paramétert kell tartalmaznia, a megfelelő sorrendben. A Javaban csak érték szerinti paraméterátadás létezik. Emiatt a hivatkozási típusú formális paraméter a metódus meghívásakor ugyanarra a tárterületre fog mutatni, ahová az aktuális paraméter, vagyis a metódusban (elvben) meg lehet változtatni az eredeti (hívó) objektum állapotát. Kivételek továbblökése A metódusfejben throws kulcsszó után kell felsorolni azokat a kivételosztályokat, amelyekhez tartozó kivételeket nem akarjuk lekezelni a metódusban (lásd 29. oldal) Metódusblokk A metódusblokk lokális változó-deklarációkat és utasításokat tartalmazhat. A Java megengedi, hogy a blokkok belsejében is deklaráljunk lokális változókat. A lokális változóknak blokkjukon belül
értéket kell adni, különben futási hiba keletkezik. Murphy törvénye szerint "bármely programban az összes lehetséges hiba előfordul". A belső deklarációk jelentősen meg tudják nehezíteni a hibakeresést, ezért csak kellő körültekintéssel éljünk velük. Visszatérés a hívóhoz Egy metódusból kilépni return [<kifejezés>]; utasítással lehet; <kifejezés> -t csak függvényekben kell megadni, és ekkor típusának értékadás szerint kompatibilisnak kell lennie a függvény típusával. http://www.doksihu Ha egy függvényben van return nélküli elágazási ág, fordítási hiba keletkezik! Osztályok Az osztály absztrakt objektum, amelyből példányosítással valódi objektumokat hozhatunk létre. Szintaktikailag az osztályok (osztály)fejből és (osztály)blokkból épülnek fel. Osztályfej Az osztályfej deklarálásának szintaktikája a következő: [<módosítók>] class <OsztályAzn> ([extends
<OsztályAzn1>]) [implements <InterfészAzn1>[,<InterfészAzn2>] Módosítók public (nyilvános): az osztály az egész alkalmazásban elérhető; ha nem adjuk meg, az osztály saját csomagjában nyilvános (alapértelmezés). abstract: tetszőleges számú (de legalább egy) absztrakt metódust tartalmazó osztály kötelező minősítője. Absztrakt osztály nem példányosítható, és nem lehet final! final (végleges): az osztály metódusai nem módosíthatók és nem írhatók felül. Végleges osztályt nem érdemes örökíteni. Azonosító képzési szabályait lásd a 11. oldalon Az osztály nevének egy alkalmazásban egyedinek kell lennie. Öröklés Utód osztályt extends kulcsszóval lehet létrehozni (lásd 21. oldal) Bővítés Interfészeket implements kulcsszóval kell egy osztályhoz fűzni (lásd 21. oldal) Osztályblokk Az osztályblokkban meg kell különböztetnünk az osztálytagokat a példánytagoktól. A blokk a következő
deklarációkat tartalmazhatja (javasolt a sorrend betartása): Változók Először deklaráljuk az osztályváltozókat static módosítóval, majd a példányváltozókat (módosító nélkül). Az osztályváltozókat a Java, az objektum megszületésekor automatikusan feltölti a típusuknak megfelelő "nullaszerű" kezdőértékkel: boolean: false; char: u0000; numerikus típus: 0; hivatkozási típus: null. Inicializáló blokk Beállíthatjuk a változók kezdőértékét osztály-, illetve példány-inicializáló blokkban is, amely fej nélküli speciális metódus, csak a blokk-képző kapcsos zárójelpár határolja. Az osztály-inicializáló blokkot static kulcsszóval kell megjelölni. Az inicializáló blokk csak egyszer fut le, az osztály, illetve az objektum létrehozásakor. Konstruktorok A konstruktor speciális típus nélküli metódus, mivel nincs (nem lehet) visszatérési értéke. Feladata, hogy beállítsa a létrehozott új objektum kezdeti
állapotát ("inicializálás"). A konstruktor neve (azonosítója) kötelezően és betűhíven azonos az osztály nevével, és csak new kulcsszóval hívható. (Más szóval: "újrainicializálás" nincs!) Szintaxisa: http://www.doksihu [public] <OsztályAzn> ([<formális par lista>]); { <konstruktor blokk>; } A konstruktor túlterhelhető, vagyis azonos névvel, de eltérő formális paraméterlistával több konstruktort is írhatunk. Egy konstruktorból vagy az osztály egy másik konstruktorát, vagy a közvetlen ősosztály konstruktorát lehet meghívni, a this ([<aktuális par lista>]); illetve a super ([<aktuális par lista>]); szintaxis szerint. Ha szerepel ilyen hívás, akkor kötelezően a hívó konstruktor első utasításának kell lennie Minden osztálynak van legalább egy konstruktora. Ha egy osztályban nem deklarálunk (explicit) konstruktort, automatikusan érvényre lép egy paraméter nélküli, üres
(default) konstruktor. (Ha van deklarált konstruktor, akkor nincs alapértelmezett!) A konstruktor nem öröklődik, és nem írható felül Metódusok Először az osztálymetódusokat (static) majd a példánymetódusokat deklaráljuk (lásd 17. oldal). Célszerű utolsónak a main metódust deklarálni, ha van ilyen toString metódus Mindennapos feladat, hogy időnként tájékoztatást kívánunk kapni egy objektum pillanatnyi állapotáról, természetesen olvasható (szöveges) formában. Erre a célra szolgál ez speciális névtelen metódus, amely szöveges formában adja meg az objektum változóinak aktuális értékét. Szintaxisa: public String toString() { return <objektumjellemzőket megadó karakterlánc>; } Ha a programban a végrehajtandó utasítás System.outprintln(objNév); a Java automatikusan megkeresi az adott nevű objektum osztályának ezt a nyilvános példánymetódusát, és lefuttatja. Interfészek Az interfész absztrakt osztály: konstansok
és absztrakt metódusfejek definíciójából áll. Létrehozása: interface <InterfészNév> { [public static final] <típus> <konstansNév> = <kifejezés>; [public abstract] <típus> <metódusNév>; } Az interfészek örökíthetők (lásd alább); a leszármaztatott interfész örökli az ős öszszes konstansát és metódusát. A konstansok, illetve a metódusok módosítói alapértelmezettek: akkor is érvényesek, ha nem adjuk meg. http://www.doksihu A Java API könyvtárának egyes osztályait csak akkor használhatjuk, ha alkalmazásunkban implementáljuk a megfelelő interfészt. Öröklés Örökléssel létező ősosztályból származtatunk le tetszőleges számú (egy vagy több) utódosztályt, továbbfejlesztés vagy kibővítés céljából. Az öröklés szintaxisa: class <UtódosztályNév> extends <ŐsosztályNév> Az utódosztály további utódok őse lehet; a leszármaztatási hierarchia mélysége nem
korlátozott. Az öröklés tranzitív: az utódosztály örökli összes ősének minden adatát és metódusát, amelyik nem private minősítésű. Egyszeres öröklés: A Javaban minden osztálynak legfeljebb egy közvetlen őse lehet. Változók (adatok) takarása Az ősosztály változóit nem lehet felülírni (vagyis újradeklarálni), de a láthatókat letakarhatja az utódosztályban deklarált azonos nevű másik változó, illetve egy metódus azonos nevű paramétere vagy lokális változója is. A letakart változókat minősítők segítségével érhetjük el, az alábbi szabályok szerint: - a hierarchiában legközelebbi letakart osztályváltozót (akár osztály-, akár példánymetódusból ) a megfelelő ősosztály nevével kell minősíteni; - a saját osztályban deklarált példányváltozóra this, a hierarchiában legközelebbi ősosztályban deklarált példányváltozóra super minősítővel lehet hivatkozni. Metódusok felülírása Egy utódosztályban
bármelyik ősosztály bármely metódusa felülírható. A felülíró metódus szignatúrájának és visszatérési értékének meg kell egyeznie a felülírtéval A felülírt osztálymetódust az ősosztály nevével, példánymetódust super minősítővel hivatkozva érhetjük el. Felülíráskor nem szűkíthető a metódus láthatósága! Nem lehet felülírni a private, illetve a final módosítójú metódusokat. Bővítés A bővítés létező interfész implementálását jelenti. Szintaxisa: class <OsztNév> implements <IntefészNév1>[,<InterfészNév2>] Egy osztály tetszőleges számú interfészt implementálhat. Az implementált interfészek – és minden esetleges ősük – minden metódusát ki kell fejteni, a nem használtakat is! Példányosítás Amikor definiálunk egy adott osztályú (= típusú) objektumot, akkor a Java csak egy mutató részére foglal le (4 byte) tárterületet; például az <OsztályAzn> objNév;
deklaráció hatására, ekkor objNév tartalma null. A példányosítás azt jelenti, hogy létrehozzuk az objektumot a new kulcsszóval, akár saját osztályából, akár másikból. Szintaxisa: objNév = new <OsztályAzn> (akt par lista); A két lépést össze is lehet vonni: <OsztályAzn> objNév = new <OsztályAzn>(akt par lista); http://www.doksihu Az objektum-példány részére a fordító kellő nagyságú tárterületet foglal le, ennek címét kapja meg az objektum azonosítója, amely hivatkozási típusú változó. A továbbiakban ezen a mutatón keresztül küldhetünk üzeneteket az objektumnak. Az objektum tárterületén kap helyet saját osztályának és osztálya összes ősének minden nyilvános (public, illetve jelöletlen, azaz csomag szinten nyilvános) példányadata. Az objektum csak osztályának és osztálya őseinek nyilvános metódusait használhatja. Az osztály (static) metódusok csak (static) osztályváltozókkal, a
példánymetódusok mind a nyilvános (public static) osztályváltozókkal, mind a példányváltozókkal végezhetnek műveleteket, mivel ez utóbbiak "látják" az osztály változóit és metódusait is. Konstruktorok láncolása: Egy objektum létrehozásakor automatikusan lefut osztályának megfelelő paraméterezésű konstruktora. Ha az osztálynak van őse, az öröklési lánc minden egyes osztályának legalább egy konstruktorát meg kell hívni (super kulcsszóval) a gyökérig (Object osztály) felmenően. Ha ezt nem tesszük meg, a fordító automatikusan beépít egy paraméter nélküli super() hívást. Ha egy ősosztálynak nincs paraméter nélküli konstruktora, és egy utódjában nem szerepel super hívás, fordítási hiba keletkezik! Példányhivatkozás A példánymetódusok megírásakor még nem ismeretes a majdani példányok tárcíme. A Java ezt a nehézséget úgy hidalja át, hogy minden példánymetódus formális paraméterlistájához
– utolsóként – hozzáfűz egy this nevű, rejtett (implicit) paramétert. Amikor üzenetet küldünk egy konkrét objektumnak, ennek mutatója (tárcíme) lesz a this paraméternek megfelelő aktuális paraméter. A példánymetódus ezen a mutatón keresztül éri el az objektum saját adatait. Objektumhivatkozás (referencia) statikus és dinamikus típusa: Az objektumhivatkozás statikus típusa a deklarálásakor megadott típus. Futás közben – értékadással vagy típuskényszerítéssel – átállíthatjuk a hivatkozást más típusú objektumra; ennek típusa lesz a hivatkozás dinamikus típusa. Értékadási kompatibilitás: A dinamikus típus csak azonos vagy utódosztály típusa lehet. Objektumok összehasonlítása Két, azonos osztályhoz tartozó objektum akkor egyenlő, ha állapotuk megegyezik. Ezt nem lehet összehasonlító operátorral megállapítani, ugyanis az <objAzn1> == <objAzn2> logikai kifejezés az objektumok mutatóját hasonlítja
össze. A kifejezés értéke akkor true, ha a két objektum ugyanazon a tárterületen helyezkedik el, vagyis fizikailag azonos. Ekkor természetesen állapotuk is azonos. Ám egy osztály két, fizikailag különböző (más-más tárterületen elhelyezkedő) objektumának is lehet azonos az állapota! Két objektum egyenlőségének (= állapotuk azonosságának) vizsgálatára speciális metódusok szolgálnak. Ezeknek két fajtájuk van: az equals metódus logikai értéket ad vissza; az objNév1.equals(objNév2) kifejezés akkor true értékű, ha a két objektum (állapota) azonos; a compareTo metódus (lásd alább) egészszámot ad vissza; az objNév1.compareTo(objNév2) kifejezés értéke pozitív, ha az 1. objektum, negatív, ha a 2 objektum nagyobb, és 0, ha a két objektum azonos. http://www.doksihu A könyvtári osztályokban általában van equals metódus, amely az osztály "lelkivilágához" igazodik. Saját osztályaink esetében azonban
rendszerint magunknak kell megírnunk a megfelelő összehasonlító metódust Comparable interfész Ha egy osztályban saját összehasonlító metódust akarunk írni, az osztályfejben implementálunk kell a Comparable interfészt 7, amely a java.lang csomagban van Az interfész mindössze egy metódusfejet definiál: public int compareTo(Object obj) {} A metódus paramétere kötelezően Object típusú. Automatikus szemétgyűjtés Egy objektumot csak addig tudunk elérni, amíg legalább egy mutatója van. A Java megteszi azt a szívességet, hogy automatikusan törli azokat az objektumokat, amelyeknek már nincs élő mutatójuk. Java osztályok felhasználása Már említettük, hogy a Java-programkönyvtárában tárolt osztályok nagy segítséget jelentenek a programozásban. Az alábbiakban áttekintjük a gyakorlatban legfontosabb négy osztály metódusait Ezeket az osztályokat nem kell importálni, mert a javalang csomagban vannak Math osztály Az osztály metódusai
matematikai függvényeket valósítanak meg. Konstansok: final double E (a természetes logaritmus alapszáma = 2,71828) final double PI (a Ludolf-féle szám = 3,14159) Fontosabb nyilvános metódusok: int abs(int szam) 8 szám abszolútértéke; int max(int szam1, int szam2)8 a nagyobbik szám; int min (int szam1, int szam2)8 a kisebbik szám; double ceil(double szam) legközelebbi, nem kisebb egészszám; double floor(double szam) legközelebbi, nem nagyobb egészszám; double rint(double szam) legközelebbi egészszám; long round(double szam) 9 legközelebbi egészszám; double pow(double alap, double kit) alapkit hatvány; double random() 0 <= x < 1 véletlenszám; double sqrt(double alap) az alap négyzetgyöke. 10 String osztály Egy String osztályú objektum (karakterlánc) tetszőleges unikód karaktereket tartalmazhat, de "értéke" létrehozása után már nem módosítható! (Esetleges változtatásokat másik karakterláncban kell tárolni.) Az osztály
gyakrabban használt metódusai a következők: int length() megadja a karakterlánc aktuális hosszát; char charAt(int index) visszaadja az index pozíciójú karaktert; String substring(int kpoz [, int vpoz]) 7 A String osztály például az Object osztályból származik, és implementálja a Comparable interfészt. 8 A függvény long, float és double típussal is meghívható, visszatérési értéke megegyezik a paraméteréével. 9 Ha a paraméter float, akkor a visszatérési érték int típusú. 10 Ne feledjük, hogy a karakterláncok a Javaban a String osztály példány-objektumai! http://www.doksihu visszaadja kpoz-tól a kar.lánc végéig, illetve vpoz-1–ig terjedő részláncot; int indexOf(int kar [, int tol]) int indexOf(String str [, int tol]) megadja a kar karakter, illetve a str részlánc első előfordulásának pozícióját; ha tol paraméter is szerepel, a keresés ettől a pozíciótól kezdődik; int lastIndexOf(int kar) int lastindexOf(String
str) megadja a kar karakter, illetve a str részlánc utolsó előfordulásának pozícióját; a kezdőpozíció itt is megadható; int compareTo(String str) int compareToIgnoreCase(String str) -1, 0, illetve 1 értéket ad vissza, attól függően, hogy a karakterlánc kisebb, egyenlő vagy nagyobb a paraméterbelinél; a második esetben a kis- és a nagybetűk azonosnak számítanak; boolean equals(Object anObject) true értéket ad, ha a két karakterlánc egyenlő; String toLowerCase() String toUpperCase() kisbetűssé, illetve nagybetűssé alakít egy karakterláncot; String concat(String str) a karakterlánchoz hozzáfűzi a paramétert; String replace(char kar1, char kar2) a karakterláncban minden kar1 karaktert kar2-re cserél; String toString() másolat-objektumot készít a karakterláncról. StringBuffer osztály Ebben az osztályban megváltoztatható a karakterlánc; többek között lehet egy karaktert vagy részláncot beszúrni, törölni stb. A gyakrabban használt
metódusok: int length() megadja a karakterlánc aktuális hosszát; char charAt(int index):char String substring(int kpoz, int vpoz) visszaadja az index pozíciójú karaktert, illetve a kpoz- tól vpoz-1-ig terjedő részláncot; void setCharAt(int index, char kar) kicseréli az index pozíciójú karaktert kar-ra; StringBuffer append(<type> value) a karakterlánc végéhez hozzáfűzi a paramétert, karakteres formában; StringBuffer insert(int poz, <type> value) a karakterláncba illeszti a paramétert, karakteres formában, a poz pozíciótól; StringBuffer delete(int kpoz [, int vpoz]) törli a karakterláncból a kpoz-tól végig, illetve vpoz-1-ig terjedő részláncot; StringBuffer repalace(int kpoz, int vpoz, String str) a karakterlánc kpoz-tól vpoz-1-ig terjedő szakaszát str-re cseréli; StringBuffer reverse() a karakterláncban megfordítja a karakterek sorrendjét; String toString() a karakterláncról String típusú másolatot készít.
http://www.doksihu StringTokenizer osztály Az osztály metódusaival részeire bonthatunk egy karakterláncot. A részláncokat elválasztó karakterek (szeparátorok) alapértelmezésben fehér szóközök (lásd 11 oldal), de tetszőlegesen kicserélhetők más karakterekre Az osztály metódusai: StringTokenizer(String str) StringTokenizer(String str, String hatjel) StringTokenizer(String str, String hatjel, boolean returnTokens) mindhárom konstruktor olyan objektumot hoz létre, amelyben a str karakterlánc a határjelekkel határolt szakaszokra van felbontva; a másodikkal megváltoztathatók a határjelek; a harmadik visszaadja a határjel-objektumokat is. String nextToken([String hatjel]) visszaadja a következő szakaszt; ha hatjel is szerepel, meghatározza a továbbiakban érvényes határjele(ke)t; int countTokens() megadja, hogy hány szakasz van még a karakterláncban; boolean hasMoreTokens() true értékű, ha van még szakasz a karakterláncban. Konténerek A
konténer-objektumok az egy-sok kapcsolatot valósítják meg. Általában nemcsak tárolják az elemeket, hanem különböző karbantartási, keresési és bejárási metódusaik is vannak. A Java rendszerben az API konténergyűjtemény (Collection Framework) konténereket, interfészeket és más kiegészítő osztályokat tartalmaz. A konténerek két válfaja a kollekció (egyszerű tárolás), illetve a térkép (kulcs szerinti tárolás). A konténerek mérete elvben nem korlátozott 11, és bármilyen típusú objektumot képesek tárolni. Ezt úgy oldják meg, hogy a betett objektum Object típusú lesz, vagyis elveszíti "osztályöntudatát". Ezért a visszakapott objektumra csak akkor alkalmazhatjuk osztályának metódusait, ha előzetesen rákényszerítjük eredeti osztályát az ((EredetiOsztNév)objektumAzn).metódus() szintaxis szerint. A Java konténereinek használatához – kivéve a tömböket – importálni kell a java.util csomagot Tömbök A tömb
speciális konténer: kizárólag azonos – tetszőleges primitív vagy hivatkozási – típusú, előre meghatározott számú objektum tárolására szolgál. Szövegeket tároló tömb elemei a szövegek mutatóját tartalmazzák. A hivatkozási típusú tömbelemek utód-osztálybeli objektumokra is mutathatnak. Tömb eleme tömb is lehet, az egymásba ágyazások száma a tömb dimenziója. A dimenziószám és az egyes dimenziók mérete elvben nem korlátozott11 A többdimenziós tömbökben az azonos szintű dimenzióknak nem kell azonos méretűeknek lenniük! Az egyes dimenziók elemszámban mért hosszát a dimenzió (final) length konstansa adja meg; ez létrehozásakor kap értéket, amit később már nem lehet megváltoztatni. A tömb elemeire indexükkel hivatkozunk; minden elemnek annyi indexe van, ahány dimenziós a tömb. Az index kötelezően egész típusú; alsó határa mindenkor 0, felső határa length-1 Deklarálás és létrehozás A tömböket
tömbképző [ ] elválasztójellel deklaráljuk; például: 11 A méretnövelésnek a tárterület, illetve az int típus értékkészlete (Integer.MAX VALUE = 2 147 483 647) szab határt http://www.doksihu <típus> <tömbAzn> [ ]; egydimenziós tömb vagy vektor; <típus> <tömbAzn> [ ] [ ]; kétdimenziós tömb vagy mátrix; <típus> <tömbAzn> [ ] [ ] [ ]; háromdimenziós tömb, vagy kartoték; stb. A <tömbAzn> egydimenziós tömb esetében a tömb kezdetére, kétdimenziós tömb esetében a második dimenzió mutatóiból képzett tömbre sít. mutat A tömböket futás során hozzuk létre new operátorral a <típus> <tömbAzn> [ ] = new <típus> [<méret>]; szintaxis szerint. A deklarálás és a létrehozás egy lépésben is történhet Osztályszintű tömb mutatójának alapértelmezett értéke null, lokális tömbé nem meghatározott. A többdimenziós tömb belülről kifelé építkezik. Például
egy szöveges típusú, 3 soros, rendre 2, 4, illetve 3 elemű sorból álló, kétdimenziós tömb sorainak deklarálása és létrehozása: String szövegek[ ] [ ] = new String[3]; szövegek[0] = new String[2]; szövegek[1] = new String[4]; szövegek[2] = new String[3]; A létrehozott tömb elemei típusuknak megfelelő kezdőértéket vesznek fel (lásd 19. oldal) Értékadás és másolás A tömbelemeknek egyenként kell értéket adni. Értékadás ciklusban Létező tömb elemeit a "külvilágból" ciklusban tölthetjük fel. Például az előbbi tömb második sorát a for (int i=0; i<szovegek[1].length; i++) szovegek[1][i] = Console.readLine("1 sor " + (i+1) + " eleme: "); ciklussal. Másolás arraycopyval Tömböket másolni a System csomag arraycopy metódusával lehet, ennek szintaxisa: static void arraycopy(Object src, int spoz, Object dst, int dpoz, int len); ahol src a forrás-, dst a cél-tömb azonosítója; spoz, illetve dpoz
kezdőindex a forrás-, illetve a cél-tömbben; len pedig a másolandó elemek száma. Az előbbi példabeli szövegek tömb 2. sorának 2- 4 elemét feltölthetjük a 3 sorból a System.arraycopy(szövegek[2],0,szövegek[1],1,szövegek[2]length) ; utasítással. Értékadás másik tömbbel Megtehetjük azt is, hogy egy tömböt adunk értékül egy másik tömbnek; ekkor a mutatóknak értékadás szerint kompatibilisnak kell lenniük. Mivel ilyenkor csak átállítjuk az egyik tömb mutatóját a másik tömbre, a két tömbnek nem kell azonos méretűnek lennie. Például a szövegek[1] = szövegek[2] értékadás hatására a tömb 2. és 3 sora azonos lesz, egyszersmind azonban az eredeti 2 sor elvész! Létrehozás és értékadás inicializálással Új tömböt létrehozhatunk úgy is, hogy kezdeti értékadó – inicializáló – blokkal, deklaráláskor adunk kezdőértéket az elemeknek. Például a szövegek tömb 1 sorát a szövegek[0] = {"Benedek",
"Cili"}; utasítással is létrehozhatjuk; ebben az esetben tilos alkalmazni a new operátort! A tömb mérete ekkor megegyezik a felsorolt elemek számával. http://www.doksihu Tömb átadása paraméterként Ha egy metódus formális paramétere tömb, az aktuális paraméternek ezzel értékadás szerint kompatibilis, létező, tetszőleges hosszúságú tömbnek kell lennie. A program indításakor a parancssorban adott paramétereket például a main metódusban vehetjük át. A Vektor osztály A Vektor osztály a Java egyik konténere; implementálja a List interfészt, amely viszont a Collection interfész utódja. A "vektor" tehát egy lista, amelynek kezelésére mindkét interfész metódusait használhatjuk. Tulajdonképpen változtatható méretű tömb: ha betelt, újabb elem hozzáadásakor mérete automatikusan nő, elem törléskor pedig csökken A vektor elemei rendezetlenek, de indexelhetők; az indexnek 0 és a tényleges méret (size-1) közé
kell esnie. Kereséskor az elemek összehasonlítása equals metódussal történik; alapértelmezésben az Object osztály metódusa működik (true értéket akkor kapunk, ha a két objektum azonos, lásd 11. oldal) A konkrét feladatokhoz illeszkedő összehasonlító metódust meg kell írnunk! Ennek feje kötött: public boolean equals(Object obj) {.} A Vector osztály védett adatai és fontosabb nyilvános metódusai: Védett adatok: private int elementCount; private int capacityIncrement; Nyilvános metódusok: Vector([int elementCount [,int capacityIncrement]]) A konstruktor létrehoz egy vektort. Ha nem adjuk meg, alapértelmezésben: elementCount = 10 elem; capacityIncrement = 2*elementCount. 12 Vector(Collection cont) Vektor-konténer létrehozása, és létező cont konténer teljes tartalmának áttöltése (a vektor eredeti tartalma elveszik). int size() visszaadja a vektor aktuális méretét; int capacity() visszaadja a vektor maximális méretét (kapacitását);
Object get(int index) visszaadja az index-edik elemet; boolean contains(Object elem) true értéket ad, ha az elem benne van a vektorban; boolean equals(Object obj) alapértelmezés: két vektort hasonlít össze, és true értéket ad vissza, ha egyenlő méretűek, valamint elemeik páronként egyenlők; elemek összehasonlítása érdekében a metódust felül kell írni! boolean add([int index,] Object elem) 12 A túl gyakori méretnövelés rontja a hatékonyságot, mert ilyenkor a Java új tárterületet foglal, és ide átmásolja a vektor elemeit. Túl nagy méret előírása viszont csökkenti a szabad tárterületet, és egyéb futási problémákat okozhat. http://www.doksihu beteszi az elemet a vektorba a végére, illetve ha megadjuk, az index-edik pozícióba; az utóbbi esetben a mögötte levő elemek indexét és a vektor méretét 1gyel megnöveli; a visszaadott érték true, ha a hozzáadás sikerült; boolean remove(Object elem) Object remove(int index) törli
a megadottal azonos első, illetve az index-edik elemet a vektorból, a mögötte levő elemek indexét és a vektor méretét 1-gyel csökkenti; a visszaadott érték az első esetben true, ha a törlés sikerült, a másodikban a törölt elem mutatója; int indexOf(Object elem [, int index]) int lastIndexOf(Object elem [, int index]) visszaadja a megadott elem indexét; az első esetben elölről, a másodikban visszafelé keres; ha megadjuk, a keresés az index-edik elemtől indul; void clear() törli a vektor összes elemét, a size mutatót 0-ra állítja. A Collections osztály Absztrakt osztály, nem példányosítható. Osztálymetódusai olyan konténerekkel végeznek műveleteket, amelyek implementálták mind a Collection, mind a List interfészt Esetünkben ilyen a Vector osztály, így az alábbi metódusok bármelyikének paramétere vektor is lehet. A Comparable interfészt implementálniuk kell a konténerben tárolt objektumoknak, mert ezek compareTo metódusát
használják összehasonlításhoz a Collections osztály metódusai. Az osztály fontosabb nyilvános metódusai: void sort(List lista) növekvőleg rendezi a lista (vektor) elemeit; void reverse(List lista) megfordítja a lista (vektor) elemeinek sorrendjét; a növekvő rendezettségből csökkenő rendezettség lesz; void shuffle(List lista) összekeveri a lista (vektor) elemeinek sorrendjét; Object min(Collection coll) Object max(Collection coll) visszaadja a lista (vektor) legkisebb, illetve legnagyobb elemét; több azonos elem közül az utolsót kapjuk vissza; int binarySearch(List lista, Object kulcs) rendezett listában (vektorban) megkeresi a kulcs objektumot, és visszaadja az indexét; több azonos elem közül véletlenszerűen választ. Kivételkezelés Javítható futási hiba előfordulása esetén a Java úgynevezett kivétel-objektumot (exception) generál; más szóval kivételt vált ki. A kivételeket a Java kivételkezelő mechanizmusa viszszafelé (felfelé)
görgeti a hívási láncon, amíg a main metódushoz nem érnek; ekkor a program hibaüzenettel leáll A fordító vagy a Java rendszer esetleges hibás működése nem javítható programhibát (error) okoz. Ilyenkor a program mindenképpen leáll http://www.doksihu Kivételosztályok A hibák és a kivételek a Throwable ősosztályból származnak, amelynek két utódja az Error és az Exception osztály; ez utóbbi minden kivétel őse. A kivételek logikailag két csoportba sorolhatók. Nem ellenőrzött kivételek A RuntimeException osztályból leszármazott kivételeket a Java rendszer nem ellenőrzi. Fontosabb fajtáik: ArrayIndexOutOfBoundsException: indexhatár túllépése; NegativeArraySizeException: negatív tömbméret megadása; ArithmeticException: tiltott matematikai művelet (például osztás nullával); ClassCastException: nem saját vagy ősosztály rákényszerítése egy objektumra; IllegalArgumentException: hibás függvényparaméter;
NumberFormatException: hibás számformátum (pl. egészszámban tizedespont); NoSuchElementException: nemlétező elem kikérése konténerből; NullPointerException: hivatkozás nem létező objektumra; stb. Elenőrzött kivételek Ezek közül számunkra legfontosabbak az IOException osztály leszármazottjai: FileNotFoundException: hivatkozás nem létező állományra vagy könyvtárra; EOFException: olvasási kísérlet az állomány végének elérése után; IOException: bármilyen adatátviteli hiba; stb. A fordító ellenőrzi, hogy programunkban keletkezhetnek-e ellenőrzött kivételek, s ha igen, és ezeket nem kezeltük le, fordítási hiba keletkezik! Inicializáló blokkok nem válthatnak ki ellenőrzött kivételt! Kivételek lekezelése A kivétel-objektumot a hívási lánc bármelyik metódusában "el lehet kapni", és (elvben) meg lehet szüntetni a kiváltó okát. Ha ez sikeres, a program tovább futtatható (A rendszerhibákat is el lehet
kapni, de a program leállását nem lehet megakadályozni.) A kivételek lekezelésére a try – catch – finally szerkezet szolgál: - a try blokkban vannak a normális (hibátlan) futás során végrehajtandó utasítások; - ezt a blokkot akárhány, de legalább egy catch blokknak kell követnie; mindegyikben meghatározott osztályú kivételeket kaphatunk el; legfeljebb egy catch blokk hajtódik végre, ezért ezeket olyan sorrendben kell elhelyezni, hogy mindig általánosabb osztályú kivételeket kapjanak el; - ha van finally blokk, ennek utasításai mindenképpen végrehajtódnak. Az elkapott és lekezelt kivétel "elpusztul", a program az utolsó catch blokk utáni utasítással folytatódik. Kivételek továbbadása A nem ellenőrzött kivételeket lehet, az ellenőrzötteket kötelező lekezelni, de ezt a hívási lánc bármelyik metódusában megtehetjük. Ha egy metódusban nem kívánunk lekezelni egy adott osztályú kivételt, ezt továbbadhatjuk a
hívójának úgy, hogy a metódusfej végén megadjuk a kihagyandó kivételosztályokat, vagy egy ősüket: throws <KivételOsztály1>, <Kivételosztály2>, Továbbadáskor a kivételosztályok nem szűkíthetők! Saját kivételek kiváltása Bármelyik Java kivételosztályból saját kivételosztályt származtathatunk le, s ebben tetszőleges hibaüzenetet adhatunk. Saját kivételobjektumunkat a http://www.doksihu throw new <SajátKivételosztályNév> (<saját hibaüzenet>) utasítással kell létrehozni. Az esetleg keletkezett kivételt megfelelő catch blokkban kell elkapni. Állománykezelés Könyvtárkezelés Állományok azonosítása Könyvtári bejegyzések azonosítására File típusú objektumok szolgálnak. Tartalmuk könyvtár- vagy állománynév, de ezt karakterlánc formájában is meg lehet adni. A könyvtárnév elemei könyvtárakat azonosítanak; az állománynév utolsó elemének kötelezően van kiterjesztése. Deklarálás és
létrehozás: File <állNév> = new File("<fizikai név">); Deklaráláskor még nem jön létre kapcsolat a fizikai állománnyal! Útvonalak Abszolút útvonal: az aktuális gyökérkönyvtártól indul. Relatív útvonal: az aktuális könyvtártól indul. Szülő- és gyerek-útvonal: az útvonal (tetszőleges) két részben is megadható, ezeket a Java összefűzi. A szülő-útvonal csak könyvtárnév lehet; a gyerek útvonal utolsó eleme kötelezően állománynév. Absztrakt útvonal: Javaban tárolt útvonalkép; a valódi és az absztrakt útvonalak között az átváltás automatikus. Állományműveletek File típusú objektumokkal állománykezelési műveleteket végezhetünk. Példák: File f = new File(<szülő útvonal>, <gyerek útvonal>); f.getAbsolutePath() megadja az állomány abszolút útvonalát; f.getName() visszaadja az állomány nevét, karakterláncként; f.createNewFile() létrehoz adott nevű üres állományt, ha
még nem létezik; f.isDirectory() true, ha f könyvtárat azonosít; String str[] = f.list() ha f könyvtár, visszaadja bejegyzéseinek nevét, a str tömbben, karakterlánc formában; File fl[] = f.listFiles() ha f könyvtár, visszaadja bejegyzéseinek nevét, a fl tömbben, File típusú objektum formájában. Állományszűrés: (Állomány)szűrésen egy könyvtár adott kiterjesztésű állományainak leválogatását értjük. Erre két módszer áll rendelkezésünkre: • A szűrőosztályban implementáljuk a FilenameFilter interfészt, és kifejtjük ennek accept metódusát. A metódus true értékkel tér vissza, ha a paraméterében megadott állománynév kiterjesztése megfelel a szűrési feltételnek Ha a szűrőt a list vagy a listFiles metódus paramétereként adjuk meg, leválogathatjuk egy könyvtárból az összes megfelelő állományt is. Használjuk a JFileChooser párbeszédablakot. Ehhez importálni kell a javax.swingfilechooserFileFilter osztályt,
amelyet a szűrőosztályban örökítenünk kell, és ki kell fejtenünk ennek accept és getDescription metódusát. (Az utóbbiban kell megadni a figyelembe vett kiterjesztéseket.) A szűrőablakban csak a könyvtárneveket, illetve a(z egyik) feltételnek megfelelő kiterjesztésű állományok nevét látjuk, a beállított kiválasztási mód http://www.doksihu (fileSelectionMode) szerint, és – elfogadása esetén (APPROVE OPTION) – a kijelölt nevet kapjuk vissza. Sajnos! Állománynév-kiválasztási (FILES ONLY) módban is visszakaphatunk könyvtárnevet! Folyamok A célhelyre folyamatosan (tagolatlanul) kiírt, illetve a forráshelyről folyamatosan beolvasott bájt- vagy karaktersorozat. A metódusok használatához importálni kell a java.io csomagot Minden folyamot close() metódussal lehet (kell) lezárni. A műveletek ellenőrzött kivételeket váltanak ki, ezért csak try blokkban programozhatók. Az esetleg keletkezett kivételeket megfelelő catch
blokkokban kell elkapni. A folyamok használata során FileNotFoundException (nem létező állomány) és IOException (feltehetően hardver hiba) kivétel keletkezhet, ezt a továbbiakban nem jelezzük. Karakterfolyamok Egyszerű karakterfolyam A szöveges állományok soros szervezésűek (sorvég: EOLN, állomány vége EOF); ezeket karakterfolyamként célszerű feldolgozni. A kiírás és a visszaolvasás unikód (2 bájtos) karakterformában történik, de ezt egészként (int) is kezelhetjük Beolvasás FileReader fr = new FileReader(<állNév>); A read metódus egyszerre egy karaktert vagy egy karaktertömböt (cpuf) olvashat, folyamatosan. Ha a tömb mérete megegyezik az állomány méretével, egyetlen utasítással beolvashatjuk az egész állományt (Lehetséges legnagyobb tömbméret IntegerMAX VALUE) Ha eredetileg karakterláncot (String) írtunk ki, ezt a String.valueOf(cpuf) metódussal lehet helyreállítani. A ready metódussal lekérdezhető, hogy van-e még
beolvasható karakter az állományban; a skip metódussal pedig kihagyhatunk megadott számú karaktert. Az állomány végét -1 jelzi. Kiírás FileWriter fw = new FileWriter(<állNév>, app); A write metódus egyszerre egy karaktert, egy karaktertömböt vagy egy (rész) karakterláncot írhat ki, folyamatosan. A létező állományt alapértelmezésben felülírja, de ha a logikai típusú app paraméter true értékű, a végéhez hozzáfűzi az új adatokat (alapértelmezés: false). Nyomtatófolyam A nyomtatófolyamban definiált nyomtató metódusok felhasználásával olvasható/nyomtatható formában írhatjuk ki az adatokat a karakterfolyamra. Ha a nyomtatófolyamot FileWriter karakterfolyamhoz kapcsoljuk, akkor kinyomtatható (kiírható) szöveges állomány jön létre Létrehozása: PrintWriter prw = new PrintWriter(new FileWriter(<állNév>); Pufferelt karakterfolyam Az adatokat egy pufferben gyűjti: oda olvassa be, illetve onnan írja ki. A puffer mérete
alapértelmezésben 2048 karakter, de célszerű az állomány méretével megegyezőre válasz- http://www.doksihu tani, mert ekkor a teljes állományt egyetlen utasítással lehet kiírni, illetve visszaolvasni. Ezeknek a pufferező folyamoknak csak karakterfolyam lehet a paraméterük. Beolvasás BufferedReader br = new BufferedReader(new FileReader(<állNév>)); A read metódus egyszerre egy puffernyi adatot olvas be (ha van annyi az állományban). Szöveges objektumok beolvasásakor ügyeljünk rá, hogy a puffer karaktertömb, ezért felhasználás előtt karakterlánccá kell alakítani (String.valueOf(puffer)) Kiírás BufferedWriter bw = new BufferedWriter(new FileWriter(<állNév>)); A write metódus egyszerre egy karaktert, egy karaktertömböt vagy egy (rész) karakterláncot írhat ki. A flush metódus egyszerre kiírja a puffer maradék tartalmát Karakterfolyam pufferelése nem jár gyakorlati előnnyel, mert a FileReader, ill. a FileWriter
metódusaival is kezelhetünk tetszőleges méretű állományokat. Bájtfolyamok Egyszerű bájtfolyam Az adatokat tagolatlan bájsorozatként tárolja. Beolvasás: FileInputStream fins = new FileInputStream(<állNév>); A read metódus egyszerre egy bájtot, vagy egy bájttömböt olvashat be, folyamatosan. Az állomány végét -1 jelzi, kivétel nem keletkezik Kiírás FileOutputStream fous = new FileOutputStream(<állNév>); A write metódus egyszerre egy bájtot vagy egy bájttömböt írhat ki, folyamatosan. Pufferező folyam Az adatokat egy pufferben gyűjti, onnan ír ki, illetve oda olvas be. A pufferező folyamokat szűrőfolyamnak is nevezik, mivel paraméterük csak bájtfolyam lehet. Beolvasás BufferedInputStream bins = new BufferedInputStream(new FileInputStream(<állNév>)); Kiírás BufferedOutputSream bous = new BufferedOutputStream(new FileOutputStream(<állNév>)); Adatfolyam Az adatfolyam szűrőfolyam, mivel bájtfolyamot olvas be, és
primitív típusú változókká, vagy unikód karaktersorozattá konvertálja; illetve kiírás előtt a primitív típusú adatokat vagy a karakterláncokat bájtsorozattá alakítja és bájfolyamot ír ki az állományba. Az adatfolyamot legtöbbször (de nem kötelezően) pufferező folyammal együtt használjuk. Beolvasás DataInputStream dins = new DataInputStream( new BufferedInputStream(new FileInputStream(<állNév>))); A beolvasó metódusok egy-egy primitív adatot (readBoolean, readChar, readByte, readShort, readInt, readLong, readFloat, readDouble), illetve egy unikód karaktersorozatot (readLine) adnak vissza. Beolvasáskor az állomány végén EOFException kivétel keletkezik. A beolvasás sorrendjének természetesen meg kell egyeznie a kiíráséval! Sajnos! Mivel a readLine metódus unikód karaktersorozatot olvas be, az eredeti karakterláncot programozással kell visszaállítani. Használata nem ajánlott! http://www.doksihu Kiírás
DataOutputStream dous = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(<állNév>))); A kiíró metódusok a paraméterül kapott primitív értéket bájtsorozattá (writeBoolean, writeChar, writeByte, writeShort, writeInt, writeFloat, writeDouble), illetve a karakterláncot unikód karaktersorozattá (writeBytes, writeChars) alakítják át. Objektumfolyam Az objektumfolyam szűrőfolyam, mivel az objektumokat bájtsorozattá alakítja át, s ezt írja ki, illetve bájtsorozatokat olvas be, s ezekből képez objektumokat. Csak a sorosítható objektumok átalakítása automatikus, ehhez az objektumnak vagy valamelyik ősének implementálnia kellett a Serializable interfészt. Beolvasás ObjectInputStream oois = new ObjectInputStream( new BufferedInputStream(new FileInputStream(<állNév>))); A readObject metódus által beolvasott bájtfolyamból képzett objektum "elfelejtette" eredeti típusát, ezt típuskényszerítéssel kell
visszaállítani. Ha a kényszerített típus nem kompatibilis az eredetivel, ClassCastException, ha nem létező osztálynevet adunk meg, ClassNotFoundException kivétel keletkezik. Kiírás ObjectOutputStream oous = new ObjectOutputStream( new BufferedOutputStream(new FileOutputStream(<állNév>, folyt))); A writeObject metódus bájtfolyammá alakítja a sorosítható objektumot, és ezt írja ki az állományba. Ha az opcionális folyt paraméter false értékű, a létező állományt felülírja, ha true, akkor bővíti. Sajnos! A bővített állományból nem lehet visszaolvasni a hozzáírt részt! Közvetlen elérésű állományok A közvetlen (véletlen) elérésű (random access) állomány az adatfolyam általánosítása: tetszőleges felépítésű és méretű adathalmazokból – rekordokból – épül fel. A rekordokat bájtsorszámuk azonosítja: bármely rekord közvetlenül kiírható vagy beolvasható, ha az állománymutatót a rekord első bájtjára
pozícionáljuk. (Feltéve, hogy a rekordméret állandó!) Adatátvitel során az állománymutató automatikusan továbblép, az átvitt bájtok számával Beolvasás során, az állomány végének elérésekor EOFException kivétel keletkezik. A lezárt állományt nem lehet ismét megnyitni, újból létre kell hozni! Létrehozása RandomAccessFile raf = new RandomAccessFile(<állNév>, mód); A mód paraméter értéke "r" (csak olvasható) vagy "rw" (olvasható és írható) lehet. Az adatátviteli metódusok azonosak az adatfolyamokéival. További fontosabb metódusok: getFilePointer: visszaadja az állománymutató aktuális értékét; seek: az állománymutatót a paraméterben megadott sorszámú bájtra állítja; length: visszaadja az állomány hosszát (bájtban); setLength: beállítja az állomány hosszát: szükség szerint levágja, illetve bővíti (a kibővítés tartalma határozatlan); skipBytes: az
állománymutató a megadott számú bájttal előrébb, illetve az állomány végére áll; visszatérési érték a lépésszám. http://www.doksihu Az extra csomag használata A System.in osztály képernyőkezelő (beolvasó) metódusai meglehetősen nehézkesek Ezekre a feladatokra használjuk az extra csomag ilyen célú metódusait: Console osztály: beolvasó metódusok char readChar([String str]) A metódusok billentyűzetről olvasnak int readInt([String str]) be egy karaktert, egy egész-, vagy egy double readDouble([String str]) vegyesszámot, illetve egy karakterlácot; String readLine([String str]) ha van, előzőleg kiírják a str üzenetet. Format osztály: formázó metódusok String left(String str, int len) String left(int num, int len) String left(double num, int len, int frac) String right(String str, int len) String right(int num, int len) String right(double num, int len, int frac) A metódusok a szövegeket, illetve az egész- vagy vegyesszámokat len
hosszúságúra egészítik ki, ezen belül a vegyesszámokat frac számú a tizedesjegyre kerekítik úgy, hogy az adatokat a left metódusok balra, a right metódusok pedig jobbra igazítják. http://www.doksihu Átváltás primitív típusok és –objektumok valamint karakterláncok között Az alábbiakban felhasznált deklarácók: String str; StringBuffer sb; boolean bol; Boolean boObj; char ch; Character chObj; byte bjt; Byte btObj; int egész; Integer egObj; double dbl; Double dbObj; Csomagoló osztályok: Character, Boolean, Byte, Short, Integer, Long, Float, Double Numerikus objektumok létrehozása csomagoló osztály példányosításával (new kulcsszóval): chObj = new Character(ch); chObj = new Character(A); boObj = new Boolean(bol); boObj = new Boolean("true"); egObj = new Integer(egész); egObj = new Integer(12345); dbObj = new Double(dbl); dbObj = new Double(3.1415); dbObj = new Double(egész); dbObj = new Double(12345); karakterlánc átváltásával
13: egObj = new Integer(str.trim());egObj = new Integer("12345"); dbObj = new Double(str.trim());dbObj = new Double("27183"); egObj = Integer.valueOf(str); egObj = IntegervalueOf("4"); dbObj = Double.valueOf(str); dbObj=dbObjvalueOf("314"); Karakterlánc-(objektum)ok létrehozása karakterláncokból: str = new String("szöv"); sb = new StringBuffer("szöv"); str = new String(sb); sb = new StringBuffer(str); str = "szöv"; str = String.valueOf("szöv"); primitív típusú adatokból: str = bol? "true" : "false"; str = String.valueOf(A); str = StringvalueOf(chObj); str = String.valueOf(egesz); str = StringvalueOf(egObj); str = String.valueOf(31415); str = StringvalueOf(dbObj); objektumokból str = Integer.toString(egesz); str = egObjtoString(); str = Double.toString(27183); str = dbObjtoString(); Primitív típusú értékek visszaállítása objektumokból numerikus típusból bármelyik
másikba: értékvesztés lehet! ch = chObj.charValue(); bjt = egObjbyteValue(); egész = egObj.intValue(); egész = dbObj.intValue(); dbl = egObj.doubleValue(); dbl = dbObj.doubleValue(); karakterláncból numerikusba (NumberFormatException lehet!) bjt = Byte.parseByte(str); egész = Integer.parseInt(str); dbl = Double.parseDouble(str); Ha a numerikussá alakítandó karakterláncban a típusnak nem megfelelő karakter (például betű, egész számban tizedespont) van, NumberFormatException kivétel keltkezik! 13