Top Banner
Created by XMLmind XSL-FO Converter. Javát tanítok Bevezetés a programozásba a Turing gépektől a CORBA technológiáig Bátfai, Norbert, Debreceni Egyetem, Informatikai Kar, Alkalmazott Matematika és Valószínűségszámítás Tanszék <[email protected]> Juhász, István, Debreceni Egyetem, Informatikai Kar, Információ Technológia Tanszék <[email protected]>
399

· PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Feb 06, 2018

Download

Documents

dangnhu
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Created by XMLmind XSL-FO Converter.

Javát tanítok

Bevezetés a programozásba a Turing gépektől a CORBA technológiáig

Bátfai, Norbert, Debreceni Egyetem, Informatikai Kar, Alkalmazott Matematika és Valószínűségszámítás Tanszék <[email protected]>

Juhász, István, Debreceni Egyetem, Informatikai Kar, Információ Technológia Tanszék <[email protected]>

Page 2:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Created by XMLmind XSL-FO Converter.

Javát tanítok: Bevezetés a programozásba a Turing gépektől a CORBA technológiáig írta Bátfai, Norbert és Juhász, István

Publication date 2007 Szerzői jog © 2007 Bátfai Norbert, Juhász István

Copyright 2007, Bátfai Norbert, Juhász István. Ez a digitális tartalom Kempelen Farkas Felsőoktatási Digitális Tankönyvtár vagy más által közreadott digitális tartalom a szerzői jogról szóló 1999. évi LXXVI. tv. 33.§ (4) bekezdésében meghatározott oktatási, illetve tudományos

kutatási célra használható fel. A felhasználó a digitális tartalmat képernyőn megjelenítheti, letöltheti, elektronikus adathordozóra vagy papírra másolhatja, adatrögzítő rendszerében tárolhatja. A Kempelen Farkas Felsőoktatási Digitális Tankönyvtár vagy más weblapján

található digitális tartalmak üzletszerű felhasználása tilos, valamint kizárt a digitális tartalom módosítása és átdolgozása, illetve az ilyen

módon keletkezett származékos anyag további felhasználása is.

A jelen digitális tartalom internetes közreadását a Nemzeti Kutatási és Technológiai Hivatal 2006-ban nyújtott támogatása tette lehetővé.

Page 3:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

i Created by XMLmind XSL-FO Converter.

Ajánlás

Keresztmamának.

Page 4:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

ii Created by XMLmind XSL-FO Converter.

Tartalom

Bevezetés .......................................................................................................................................... vii 1. A szerzőkről ........................................................................................................................ vii 2. Előszó ................................................................................................................................. viii

2.1. Bíztatás .................................................................................................................... ix 2.1.1. Előismeretek ................................................................................................ ix

2.2. Javasolt használati esetek ........................................................................................ ix 2.2.1. A még teljesen kezdő és csak a Java programozás iránt érdeklődőkről szóló

használati eset ........................................................................................................ x 2.2.2. Csak a Java programozás oktatása iránt érdeklődőkről szóló használati eset x 2.2.3. Szekvenciális feldolgozással kezdő, de ezt a Programozás papíron részben

feladókról szóló használati eset .............................................................................. x 2.3. Köszönet .................................................................................................................. xi 2.4. Figyelmeztetés ......................................................................................................... xi 2.5. Könyvjelzők ............................................................................................................ xi

2.5.1. Szervezési könyvjelzők ............................................................................... xi 2.5.2. Főbb tartalmi könyvjelzők .......................................................................... xi 2.5.3. Technikai könyvjelzők ............................................................................... xii

3. Előzetes a példaprogramokból ............................................................................................ xii 3.1. Egygépes példák .................................................................................................... xiii

3.1.1. A LabirintusVilág példa ............................................................................ xiii 3.1.2. A LabirintusApplet példa .......................................................................... xiii 3.1.3. A LabirintusJáték példa ............................................................................. xiv

3.2. Mobiltelefonos példák ........................................................................................... xiv 3.2.1. LabirintusMIDlet példa ............................................................................. xiv

3.3. Hálózati példák ....................................................................................................... xv 3.3.1. A LabirintusServlet példa .......................................................................... xv 3.3.2. A HálózatiLabirintus példa ....................................................................... xvi 3.3.3. A TávoliLabirintus példa .......................................................................... xvi 3.3.4. A KorbásLabirintus példa ........................................................................ xvii 3.3.5. A ElosztottLabirintus példa ...................................................................... xvii

3.4. További példák .................................................................................................... xviii 3.4.1. A további önálló példák könyvjelzői ......................................................... xix 3.4.2. A példák jellege ......................................................................................... xx 3.4.3. Összefoglalás ............................................................................................. xx 3.4.4. Platform ..................................................................................................... xxi 3.4.5. A példaprogramok szerkezete, kipróbálása és a kézikönyv jelölései ........ xxi

4. Látványos Ars Poetica ....................................................................................................... xxv I. Programozás papíron ....................................................................................................................... 1

1. A programozásról .................................................................................................................. 2 1. A programozás filozófiája ........................................................................................... 2

1.1. A programozás alapjai ..................................................................................... 3 1.1.1. Algoritmikus kérdések ........................................................................ 3 1.1.2. A programozás evolúciója ................................................................ 49 1.1.3. A programozás egy filogenetikai törzsfája ....................................... 49 1.1.4. Bepillantás napjaink gyakorlatába .................................................... 52 1.1.5. Néhány látomás: a jövő programozása ............................................. 52

1.2. Az OO világ, a programozó szűkebb hazája ................................................. 59 1.2.1. A Java platform ................................................................................ 61 1.2.2. Objektumok mindenütt: a CORBA OO világ ................................... 73

1.3. Az internet, a programozó tágabb hazája ...................................................... 76 1.3.1. TCP/IP .............................................................................................. 76 1.3.2. A kliens-szerver modell .................................................................... 77 1.3.3. Bepillantás az alkalmazási rétegbe: a HTTP protokoll ..................... 77

2. Saját világok teremtése és Java alapok ................................................................................ 81 1. A Java világa ............................................................................................................. 81

1.1. A Java nyelv .................................................................................................. 81

Page 5:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Javát tanítok

iii Created by XMLmind XSL-FO Converter.

1.1.1. .......................................................................................................... 83 1.1.2. Osztályok és objektumok .................................................................. 84 1.1.3. A programozás világnyelve a Java ................................................... 86 1.1.4. Vissza az OO-hoz ........................................................................... 104 1.1.5. Mi történik a metódusokban? ......................................................... 117 1.1.6. Eseménykezelés .............................................................................. 123 1.1.7. Kivételkezelés ................................................................................. 126 1.1.8. Párhuzamos végrehajtás ................................................................. 130 1.1.9. Interfészek ...................................................................................... 132 1.1.10. Csomagok ..................................................................................... 132

1.2. A Java nyelv használata .............................................................................. 132 1.2.1. Bepillantás a GUI programozásba .................................................. 132 1.2.2. Bepillantás a hálózati programozásba ............................................. 135 1.2.3. Esettanulmány: egy chat program ................................................... 136

II. Programozás gépen .................................................................................................................... 149 3. Java esettanulmányok ........................................................................................................ 150

1. Labirintus esettanulmányok Java nyelven ............................................................... 150 1.1. A tiszta OO labirintus - Labirintus Világ .................................................... 150

1.1.1. A labirintus API felélesztése .......................................................... 150 1.1.2. A LabirintusVilág osztály ............................................................... 167 1.1.3. A labirintus API és a LabirintusVilág a NetBeans IDE környezetben 172

1.2. Java a játékokban: egy teljes képernyős példa - Labirintus Játék ............... 175 1.2.1. A LabirintusJáték osztály ............................................................... 175 1.2.2. A teljes képernyős labirintus fordítása, futtatása ............................ 181

1.3. Java a böngészőkben: Applet objektumok - Labirintus Applet ................... 182 1.3.1. A LabirintusApplet osztály ............................................................. 182 1.3.2. A labirintus applet fordítása, futtatása ............................................ 186

1.4. Java a mobiltelefonokban: MIDlet objektumok - Labirintus MIDlet .......... 188 1.4.1. A LabirintusMIDlet osztály ............................................................ 192 1.4.2. A LabirintusVaszon osztály ............................................................ 194

1.5. Java a webszerverekben: Servlet objektumok - Labirintus Servlet ............. 197 1.5.1. A LabirintusServlet osztály ............................................................ 201

1.6. Java a hálózaton .......................................................................................... 204 1.6.1. TCP/IP - Hálózati Labirintus .......................................................... 204 1.6.2. Java RMI - Távoli Labirintus ........................................................ 213 1.6.3. CORBA - Korbás Labirintus .......................................................... 219

1.7. Elosztott objektumok - Elosztott labirintus ................................................. 226 1.7.1. Az elosztott labirintus API felélesztése .......................................... 227 1.7.2. Az Elosztott labirintus fordítása és futtatása ................................... 244

4. Példaprogramok ................................................................................................................ 249 1. A csomagok szervezése ........................................................................................... 249

1.1. A példaprogramok forrásainak letöltése ...................................................... 249 1.2. javattanitok.labirintus csomag ..................................................................... 249 1.3. javattanitok.elosztott csomag ...................................................................... 250 1.4. javattanitok csomag ..................................................................................... 250

1.4.1. A LabirintusAlkalmazás osztály ..................................................... 251 5. A példák kipróbálása ......................................................................................................... 257

1. A Java telepítése gépünkre ...................................................................................... 257 1.1. A Java SE, Java ME fejlesztői csomag letöltése és beállítása ..................... 257

1.1.1. Java SE Linux környezetben .......................................................... 257 1.1.2. Java SE Windows környezetben ..................................................... 258 1.1.3. A Java dokumentáció, azaz az API doksi letöltése ......................... 258 1.1.4. Java ME .......................................................................................... 259 1.1.5. A NetBeans integrált fejlesztői környezet letöltése és használata .. 259 1.1.6. A NetBeans IDE 5.5 ....................................................................... 260

2. A példaprogramok futtatásáról általában ................................................................. 260 A. Java mellékletek ............................................................................................................... 262

1. A Java verziók újdonságai a tigristől a delfinig ....................................................... 262 1.1. A tigris ........................................................................................................ 262 1.2. A Musztáng ................................................................................................. 264

Page 6:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Javát tanítok

iv Created by XMLmind XSL-FO Converter.

1.3. A delfin ....................................................................................................... 268 2. Az első Java tapasztalatok ....................................................................................... 268 3. Egyszerű összehasonlítások ..................................................................................... 270

3.1. Egyszerű összehasonlítások a sebesség kérdésében .................................... 270 3.1.1. A PiBBPBench Java osztály ........................................................... 272 3.1.2. A pi_bbp_bench forrás ................................................................... 274 3.1.3. A PiBBPBench C Sharp osztály ..................................................... 276

3.2. A Java és a C Sharp nyelvi szintű összehasonlítása .................................... 278 3.2.1. Az alapvető nyelvi elemek összehasonlítása .................................. 283

B. Számítási mellékletek ....................................................................................................... 287 1. Biológiai témájú programok .................................................................................... 287

1.1. Genomi, aminosav vagy akár tetszőleges szekvenciák összehasonlítása .... 287 1.1.1. A Pontmátrix osztály ...................................................................... 292 1.1.2. A Swinges felület építésének alapszabálya .................................... 298

1.2. Sejtautomata szimuláció programja ............................................................ 299 1.3. Orch OR demonstrációk .............................................................................. 312

1.3.1. Hexagonális rács ............................................................................. 312 2. Matematikai témájú programok ............................................................................... 320

2.1. Galton deszka kísérlet programja ................................................................ 320 2.2. Mandelbrot halmaz programja .................................................................... 325 2.3. Mandelbrot halmaz nagyító programja ....................................................... 333 2.4. Mandelbrot halmaz pontjait grafikusan iteráló program ............................. 348 2.5. A Mandelbrot halmazzal kapcsolatos osztályaink összefoglalása ............... 351

2.5.1. A MandelbrotHalmaz osztály ......................................................... 352 2.5.2. A MandelbrotHalmazNagyító osztály ............................................ 356 2.5.3. A MandelbrotIterációk osztály ....................................................... 359

2.6. A Pi jegyeinek nyomában ........................................................................... 361 Irodalomjegyzék ............................................................................................................................. 365

Page 7:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

v Created by XMLmind XSL-FO Converter.

A táblázatok listája

1.1. A bonyolultságmérő programok összefoglalása. ....................................................................... 14 1.2. A bonyolultságmérő programok és bemenetük együttes összefoglalása. .................................. 15 1.3. A 01-et ismétlő bináris sorozat kezdőrészeinek vizsgálata. ....................................................... 36 1.4. A félig véletlen bináris sorozat kezdőrészeinek vizsgálata. ....................................................... 39 1.5. Mikrotubulus sejtautomata szimuláció. ..................................................................................... 56 1.6. Java és C egyszerű sebesség összehasonlítása ........................................................................... 65 2.1. A Java primitív típusai ............................................................................................................. 117 A.1. Java, gcj és C egyszerű sebesség összehasonlítása ................................................................. 272 A.2. Java és C# egyszerű sebesség összehasonlítása ...................................................................... 272 B.1. Az R. W. Gosper-féle sikló ágyú élőlény bemutatása ............................................................. 306

Page 8:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

vi Created by XMLmind XSL-FO Converter.

A példák listája

1.1. Első sorozat: 1000 nulla ............................................................................................................. 10 1.2. Első sorozat, máshogy: 1000 nulla ............................................................................................ 11 1.3. Második sorozat: 01010101 ... ................................................................................................... 11 1.4. Harmadik sorozat: 00000000001 ... 10000000000 .................................................................... 12 1.5. Negyedik sorozat: egyre több 1 jegy két nulla között ................................................................ 13 1.6. Ötödik sorozat: pszeudo véletlen ............................................................................................... 13 1.7. Bármely sorozat: egy másoló program ...................................................................................... 14 1.8. A Chaitin-Kolmogorov bonyolultság nem kiszámítható! .......................................................... 17 1.9. A Chaitin-Kolmogorov bonyolultság gyakorlati alkalmazásai .................................................. 18 1.10. Átváltás binárisba .................................................................................................................... 19 1.11. Bitműveletek, kezdjük egy bináris dumppal ............................................................................ 21 1.12. Titkosítás kizáró vaggyal ......................................................................................................... 22 1.13. Kizáró vagyos titkosítás grafikusan ......................................................................................... 24 1.14. Számrendszer átváltások .......................................................................................................... 24 1.15. A TörtÁtváltó osztály kiegészítése .......................................................................................... 25 1.16. Turing gépek kódolása ............................................................................................................. 26 1.17. Kongruencia generátorok ......................................................................................................... 26 1.18. Galton deszka kísérlet .............................................................................................................. 28 1.19. Hisztogram feladat ................................................................................................................... 31 1.20. Fej vagy írás varázslat ............................................................................................................. 34 1.21. Egy szabályos sorozat .............................................................................................................. 35 1.22. Véletlenszám generátorok ....................................................................................................... 37 1.23. Egy másik szabályos sorozat ................................................................................................... 38 1.24. Egy nem véletlen, de bonyolultabb sorozat ............................................................................. 38 1.25. A Chaitin-féle Omega konstans ismeretében meg tudnánk oldani a megállási problémát! ..... 42 1.26. A Pi közelítése ......................................................................................................................... 43 1.27. A Ramanujan és a Chudnovsky közelítő összegek formulái ................................................... 45 1.28. Az Ar klasszikus elsőrendű matematikai logikai nyelv ........................................................... 47 1.29. Saját terület formalizálása ........................................................................................................ 48 1.30. Mikrotubulus sejtautomata szimuláció .................................................................................... 56 1.31. Java disassembler .................................................................................................................... 63 1.32. Port szkennelő példa ................................................................................................................ 79 1.33. Jól ismert portok feladat .......................................................................................................... 80 2.1. Saját labirintusunk elképzelése .................................................................................................. 83 2.2. A RuntimeException típusú hibák kezeléséről 2. .................................................................... 130 A.1. Írjunk az OsztályNév osztályunkhoz egy példánymetódust, ami visszaadja az osztály String tagját!

......................................................................................................................................................... 285 B.1. Pontmátrix osztály kiegészítése .............................................................................................. 296 B.2. További kísérletek a Pontmátrix osztályunkkal ...................................................................... 297 B.3. A Galton deszka kísérlet programjának kiegészítései ............................................................. 324 B.4. A Mandelbrot halmaz nagyító programjának kiegészítései .................................................... 346

Page 9:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

vii Created by XMLmind XSL-FO Converter.

Bevezetés

„Ha a kéket veszed be... a játéknak vége. Felébredsz az ágyadban, azt hiszel, amit hinni akarsz. De ha a pirosat:

maradsz Csodaországban. És én megmutatom, milyen mély a nyúl ürege.” — MÁTRIX

Ebben a bevezető részben

• röviden bemutatjuk a szerzőpárost

• olvashatjuk a szerzők előszavát

• a könyv néhány javasolt használati esetét

• a szereplő esettanulmányok koncepcionális szintű bemutatását

• megtaláljuk itt a legfontosabb könyvjelzőket

• megismerhetjük a könyvben használt jelöléseket

1. A szerzőkről

Bátfai Norbert 1996-ban szerzett programozó matematikusi, majd 1998-ban kitüntetéses programtervező

matematikusi oklevelet a Debreceni Egyetemen, többek között éppen Juhász István tanítványaként. 1998-ban

megnyerte a Java Szövetség Java Programozási Versenyét.

Bátfai Erikával közös mobil-információtechnológiai cége, az Eurosmobil, második helyezést ért el 2004-ben a

Motorola JavaJáték Versenyén, ugyancsak az Eurosmobil 2004-ben a Sun és a Nokia közös Mobil Java

Fejlesztői Versenyén a Ha hívsz, támadok! - (H.A.H) hálózati (Java EE szerver, Java ME kliens) játéksorozattal

első díjat nyert. 2005-ben az Eurosmobil képviseletében Bátfai Erikával A Java mobiljáték-fejlesztés elmélete és

gyakorlata és a kék (JSR 82) játékok címmel előadott a Java 10. születésnapja alkalmával megrendezett 5. Sun

Java Fejlesztői Napon.

Társszerzője a Fantasztikus programozás (Jávácska Vortál, Jávácska Barátai) című ismeretterjesztő

kalandregény sorozatnak.

Jelenleg a Debreceni Egyetem Informatikai Kara Alkalmazott Matematika és Valószínűségszámítás

Tanszékének munkatársa. Oktatási tapasztalata az alábbi tárgyak gyakorlatain alapul: Java esettanulmányok,

J2SE hálózatok, Java appletek, CORBA, Programozás, Hálózatok, Formális nyelvek és automaták,

Algoritmuselmélet, Bevezetés az informatikába, Operációs rendszerek, Alkalmazások fejlesztése WWW-re,

Objektumorientált programozás a középiskolában, Mobil programozás.

Szerzője a Programozó Páternoszter programozás jegyzetnek.

Page 10:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

viii Created by XMLmind XSL-FO Converter.

Juhász István 1975-ben végzett a Kossuth Lajos Tudományegyetem matematika-fizika szakán, jelenleg a

Debreceni Egyetem Informatikai Karának oktatója. 1982-ben egyetemi doktori címet szerzett. Kutatómunkáját a

matematikai statisztika területén végezte.

1974 óta vesz részt az egyetemi oktatásban. Elsősorban programtervező informatikusokat, programozó

matematikusokat, programtervező matematikusokat, informatika tanárokat, informatikus könyvtárosokat,

matematikusokat, és matematika tanárokat tanított illetve tanít. Főbb oktatási területei: programozás,

adatszerkezetek, adatmodellek, adatbázis-kezelő rendszerek, rendszerfejlesztési technológiák

Az egyetemen a kreditrendszerű képzés koncepciójának és a programtervező informatikus BSC szak illetve a

programtervező informatikus MSC információs rendszerek szakirány egyik kidolgozója volt.

Rendszeresen foglalkozik TDK-s hallgatókkal. Az elmúlt években két első díjas és több helyezést elért dolgozat

született a vezetésével. Tagja az OTDK Informatika szekció Szakmai Bizottságának.

Az utóbbi években társszerzőkkel több könyvet írt és fordított, illetve lektorált és szerkesztett, elsősorban az

információ technológia, az adatbázis-kezelés és a web területén. Írt két elektronikus jegyzetet is.

Jelenlegi kutatási területei: objektumorientált és azon túli paradigmák, objektumorientált adatmodellek,

komponens technológia, az informatika oktatásának didaktikai problémái.

2. Előszó

A programozásra gondolva olykor valami misztikus érzés járja át az embert, ami további hajtóerőt és lelkesedést

kölcsönöz. A sikeres oktatás elsődleges célja ennek átadása, ebből fejlődhet majd ki minden más, ami csak kell:

az ipar számára a professzionális programozó, a tudománynak és az emberiségnek a komplex problémákkal

megküzdeni tudó algoritmuselmélész, az egyénnek és a társadalomnak a boldog és tetterős polgár. Reményeink

szerint ennek az érzésnek az átadásához ezzel a digitális szakkönyvvel mi is hozzá tudunk járulni, miközben

általában foglalkozunk a programozással, annak elméletével és filozófiájával, majd részletesen és gyakorlatiasan

az objektumorientált paradigmával, és ezen belül a Java programozással.

Minden OO programhoz kapcsolható egy sajátos világ, egy mikrokozmosz. A kisebb, egyszerűbb programok

esetén ez a mikrokozmosz általában nem külön létező, hanem csupán egy már létező világ parányi, kiragadott

része. A nagyobb, bonyolultabb programok esetén maga a program, azaz a programozó építheti fel ezt a

mikrokozmoszt. Példaként tekintsünk egy labirintus játék programot, amiben a világ maga a labirintus,

kincsestől, szörnyestől, hősöstől, a szokásos történettel: a hős bolyong, a szörnyek próbálják megenni, a kincs

várja, hogy rábukkanjanak. Az OO programozás ereje abban rejlik, hogy a programozó a fejlesztés során rá van

utalva, hogy saját világokat építsen, saját világokat teremtsen! Építőelemei a választott OO platform API

interfészének osztályai, habarcsa pedig maga a választott OO nyelv.

Ebben a kézikönyvben a Java nyelvvel egy labirintus játék világának felépítése során ismerkedünk meg, ami

során ezt az egyszerű, példa labirintus játékot elkészítjük a weboldalon elhelyezhető appletként, mobiltelefonos

és teljes képernyős PC-s, illetve hálózati: TCP/IP, Java Servlet, Java RMI és CORBA változatban is. De ezeken

a labirintus témájú esettanulmányokon túl biológiai, matematikai és informatikai programozási példákkal is

megismerkedhet majd a kedves Olvasó.

A könyvet elsősorban tanári kézikönyvként ajánljuk középiskolai informatikatanároknak, de kiegészítő

irodalomként hasznos olvasmánynak tartjuk informatikus tanárjelöltek, diákok és általában a programozni

tanulni vágyók számára egyaránt.

Page 11:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

ix Created by XMLmind XSL-FO Converter.

Bátfai Norbert

2.1. Bíztatás

A kézikönyvet itt-ott felütve, a gyakorlati és az elméleti érdeklődésű Olvasót is elbizonytalaníthatja egy-egy

dolog azt illetően, hogy lelkesen vesse bele magát az olvasásába.

A gyakorlati érdeklődésűeknek meglepő lehet, hogy a programozás alapjairól szóló részekben elméleti

konstrukciókkal, például Turing gépekkel találkoznak, amik esetleg korábbi tanulmányaik során nem váltak

kedvenceikké, vagy az is könnyen meglehet, hogy egyáltalán nem is ismerik ezeket a gépeket. Nekik mégis azt

tanácsoljuk, ne hagyják ki ezeket a fejezeteket, mert nem öncélúan, hanem valódi élmények nyújtásának céljával

tárgyaljuk - ráadásul korántsem kimért matematikai, hanem gyakorlati és ismeretterjesztő szinten - ezeket a

képzeletbeli gépeket. Olyan mentális élmények lesznek ezek, amiket némi erőfeszítéssel bárki befogadhat, de a

programozók, az informatikusok különösen könnyen, mivel ezek az tézisek az ő gondolkodási paradigmáik

szerint épülnek fel, mert alapfogalmuk a számítógépes program. S mi éppen e gyakorlati megközelítéssel

tárgyaljuk ezeket az emberi gondolkodást - programozói filozofálást - avagy a matematikai vénát messzire

elvezető alapfogalmakat.

A másik, ami az elméleti érdeklődésűeket és a kevésbé gyakorlottakat lepheti meg, hogy a valódi programozási

részekben olyan példákkal találkozhatnak, melyek leginkább a haladó és nem a bevezető kurzusok témái. Ilyen

témák például a mobil, a hálózati vagy az elosztott programozás. De itt is megnyugtathatjuk a kedves Olvasót,

hogy bevezető szinten tárgyaljuk a példákat, ahol nem a finomságokat akarjuk elemezni, hanem a lényeget

megmutatni. Ennek megfelelően persze megadunk további szakirodalmi hivatkozásokat, ahol az itt érintett,

haladóbb témák részleteiben is elmerülhetnek az érdeklődő Olvasók.

2.1.1. Előismeretek

A kézikönyv gyakorlatias szemlélete a Java programozási részekben úgy jelenik meg, hogy inkább a szerzők

adott Java akcentusát tükrözi, semmint a Java nyelvi utasítások, konstrukciók általános kimerítő tárgyalását.

Annak a kedves Olvasónak, aki ezt hiányként éli meg, a kézikönyv feldolgozása mellé bevezető könyvként a

[JAVA START] vagy a [JAVA KÖNYV] első kötetének elejét ajánljuk a figyelmébe.

Természetesen a könyv feltételezi a számítógépes alapismeretek meglétét, némi programozási ismeretet, az

internet és a web használatát, de elsősorban a motivációra, az alkotni vágyásra és sok-sok gyakorlásra épít.

2.2. Javasolt használati esetek

Az alábbi feldolgozási módokat javasoljuk, ha a kedves Olvasó

i. Középiskolai informatikatanár

Ha a kedves Olvasó már rendelkezik némi Java programozási tapasztalattal, akkor a kézikönyv folyamatos

olvasása nem okozhat gondot.

Ha az Olvasó még nem rendelkezik Java programozási tapasztalatokkal, s ez elbizonytalanítja, akkor e

bevezető részek elolvasása után Az első Java tapasztalatok című melléklet gyors feldolgozását javasoljuk. E

a pontnak nem küldetése a Java programozás bevezetése, hiszen ezt a célt maga az egész kézikönyv célozta

meg. Célja viszont néhány egyszerű, de nem pofonegyszerű, példa végigvitelével az Olvasó eme említett

bizonytalanság érzésének eloszlatása. Ha viszont a bizonytalanság érzése ezen az ágon mégsem jelenik meg,

akkor itt is bátran kezdje a folyamatos olvasást és kövesse a menet közben szereplő feldolgozási utasításokat.

ii. Informatikai jellegű szak felsőoktatásbeli hallgatója

Ha a kedves Olvasó már rendelkezik némi Java programozási tapasztalattal, akkor a folyamatos olvasás itt

sem okozhat gondot. Az esetlegesen mégis felmerülő megértésbeli problémákat a hasonló érdeklődésű

csoporttársakkal való átbeszélés bizonyára sikeresen orvosolja. Ezen az ágon az elméleti, a Programozás

papíron című rész átolvasása után rögtön a Programozás gépen című rész esettanulmányainak feldolgozását

javasolhatjuk. Ezen belül azt a tetszőleges témát, amely leginkább felkeltette az Olvasó érdeklődését.

Ha az Olvasó még nem rendelkezik Java programozási tapasztalatokkal, akkor a kézikönyv szekvenciális

feldolgozásával párhuzamosan érdemes lehet egy bevezető Java kurzus felvétele az Olvasó oktatási

Page 12:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

x Created by XMLmind XSL-FO Converter.

tanintézményében. A Programozás papíron című rész elméleti meggondolásait pedig a Matematikai logika,

Formális nyelvek és automaták vagy leginkább az Algoritmuselmélet című, tartalmú kurzusok elvégzésével

mélyítheti el.

iii. Informatikai jellegű tárgy középiskolai tanulója

Ha a kedves Olvasó már rendelkezik némi Java programozási tapasztalattal, de a folyamatos olvasás során

mégis valamilyen megértésbeli gondja támad, akkor barátaival való megbeszélése után érdemes azt felvetnie

informatikatanárának, szakkörvezetőjének, akitől bizonyára megkapja a megfelelő útbaigazítást.

Ha az Olvasó még nem rendelkezik Java programozási tapasztalatokkal, akkor a feldolgozást A Java világa

című, a Java nyelvi programozást részletesen bevezető résszel javasoljuk kezdeni.

2.2.1. A még teljesen kezdő és csak a Java programozás iránt érdeklődőkről szóló használati eset

Ebben az esetben az alább belinkelt feldolgozási sorrendet javasoljuk pontosan követni a kedves Olvasónak.

1. Előzetes a példaprogramokból

2. Az OO világ, a programozó szűkebb hazája

3. A Java platform

4. Az első Java osztály lefordítása

5. Történet és oktatás

6. A Java OO világ

7. Java SE OO világ

8. Saját világok teremtése és Java alapok

9. A Java világa részletes feldolgozása

10. A választott Java esettanulmányok feldolgozása

2.2.2. Csak a Java programozás oktatása iránt érdeklődőkről szóló használati eset

Ebben az esetben feltehetjük, hogy a kedves Olvasó már nem - az előző pontnak megfelelő - teljesen kezdő.

Ekkor az alább belinkelt feldolgozási sorrendet javasoljuk követni.

1. Előzetes a példaprogramokból

2. Saját világok teremtése és Java alapok

3. A Java világa részletes feldolgozása

4. A választott Java esettanulmányok feldolgozása

2.2.3. Szekvenciális feldolgozással kezdő, de ezt a Programozás papíron részben feladókról szóló használati eset

Ebben az esetben feltehetőleg érdemben olvasni szerette volna az éppen szereplő, de csupán megelőlegezett

Java forrásokat is a kedves Olvasó. Ha továbbra is ragaszkodik ehhez a folyamatosan és mélyen megértő

feldolgozási módhoz, akkor ugorjon az alább belinkelt részre és ennek feldolgozása után már könnyen legyőzi a

most feltorlódott akadályokat.

1. Saját világok teremtése és Java alapok

Page 13:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xi Created by XMLmind XSL-FO Converter.

2.3. Köszönet

Ez a kézikönyv a Nemzeti Kutatási és Technológiai Hivatal, DIGITÁLIS SZAKKÖNYV, DIGIT 2005 pályázat

keretében készült el, ezért köszönetünket elsődlegesen ennek a támogatásnak kell címeznünk. Köszönjük

továbbá a Debreceni Egyetem Informatikai Kar Információ Technológia Tanszékének és Alkalmazott

Matematika és Valószínűségszámítás Tanszékének, mint a szerzők munkahelyeinek, hogy otthont adtak a

pályázat teljesítésének és ezzel egyetemben lehetővé tették az egyetemi hálózat és gépek használatát. Továbbá

köszönjük az EUROSMOBIL-nak, hogy több szereplő, de különösen a mobiltelefonos és a Linuxos Sun

W1100Z Workstation munkaállomáson futtatott példák kipróbálásához és a kézikönyv kifejlesztéséhez a

megfelelő infrastruktúrát a rendelkezésünkre bocsátotta. Végül itt is megköszönjük a lektorok: Korotij Ágnes és

Vágner Anikó munkáját.

2.4. Figyelmeztetés

Nincs felelősségvállalás

A szerzők a példák elkészítésekor a legjobb tudásuk szerint jártak el, de előfordulhatnak, sőt bizonyára

vannak is hibák a programokban, a könyvben. A programok és általában a könyv bármely

felhasználásával kapcsolatba hozható esetleges károkért a szerzők semmilyen felelősséget nem

vállalnak.

Még arra hívjuk fel az Olvasó figyelmét, hogy a szereplő példaprogramok oktatási céllal készültek,

ezért tipikusan valami olyan tulajdonságot mutatnak, amit velük kapcsolatban a könyvben kiemelünk,

feldolgozunk. Például a labirintus elosztott változata azt akarja megmutatni, hogy minden szereplő

objektum külön számítógépen van. De ennél nem többet, ennek megfelelően nem foglalkozik például -

az egyébként természetesen felmerülő - hálózati terheléssel, szinkronizációs problémákkal,

hibakezeléssel, magas szereplőszám esetén a működőképességgel kapcsolatos kérdésekkel.

2.5. Könyvjelzők

2.5.1. Szervezési könyvjelzők

I. A példaprogramok rövid bemutatása

II. A példaprogramok szervezése és forrásszövegek

2.5.2. Főbb tartalmi könyvjelzők

A kézikönyv főbb tartalmi elemeit az alábbi felsorolásba linkeltük be. Az esettanulmányok példáitól eltérő

további gyakorlati példákat egy későbbi pont alatt bontjuk ki bővebben.

I. A programozás és a programozó gondolkodásának alapjai

i. Turing gép

ii. Megállási (végtelen ciklus) probléma

iii. Chaitin-Kolmogorov-Solomonoff bonyolultság

iv. Chaitin gépek és az Omega

II. A programozás filogenetikája

III. A jövő programozása

i. A Penrose-Hameroff Orch OR tudatmodell

IV. Bevezetés a Java programozásba

i. OO tervezés és egyben Java alapok

Page 14:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xii Created by XMLmind XSL-FO Converter.

ii. Java programfejlesztés

iii. Java újdonságok a Tigristől a Musztángon át a Delfinig

V. Labirintusos Java esettanulmányok

i. „Tiszta” OO implementálás

ii. Java Applet

iii. Teljes képernyő - Full Screen Exclusive Mode

iv. Java ME - mobil programozás

v. Szerveroldali Java

a. java.net csomag

b. Java Servlet

c. Java RMI

d. Java IDL

vi. CORBA - elosztott programozás heterogén OO környezetben

VI. További programozási példák

i. Biológiai témájú programok

a. Genomok, fehérjék összehasonlítása

ii. Matematikai témájú programok

a. Fraktálok nagyítása

b. Sejtautomaták

c. A Pi hexadecimális jegyei

d. Galton deszkás kísérletek

2.5.3. Technikai könyvjelzők

I. A Java SE, ME telepítése

II. A jegyzet példaprogramjainak fordítása, futtatása

III. A jegyzet példaprogramjai forrásainak letöltése

3. Előzetes a példaprogramokból

„Minden számítógép-pedagógus tudja a világon, hogy játékokkal kell kezdeni.” —Marx György

Ebben a bevezető részben megtudjuk, milyen példákkal ismerkedhetünk meg a kézikönyv forgatása során. Az

anyagban szereplő számos példára, kódrészletre igaz, hogy részei a jegyzethez készített, a következőkben

felsorolt különböző labirintus játékoknak. Az Olvasó alapértelmezésben, azaz a folyamatos, szekvenciális

olvasás során ugyanebben a sorrendben fog találkozni ezekkel a programokkal. Javaslatunk, hogy - a példák

egymásra épülése és a könyv bevezető jellege miatt - ezen sorrendtől ne térjen el a feldolgozás során, hacsak

más iránymutatást nem kapott a korábbi Javasolt használati esetek című pontban.

Page 15:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xiii Created by XMLmind XSL-FO Converter.

Megjegyzés

Ebbe a szekvenciális olvasásba az is beletartozik, hogy az Olvasó tudásszintjétől függően arra kaphat

utasítást, hogy egy részt éppen hagyjon ki és egy másik rész feldolgozása után térjen ide vissza vagy

éppen ugorjon egy másik, valamit mélyebben kibontó részre.

3.1. Egygépes példák

Az egygépes példák, mint nevük is mutatja, a kézikönyvet egyetlen gép mellett ülve feldolgozó Olvasóknak

nyújtják a programozás élményét. De ebbe a csokorba szedtük a labirintus appletes esettanulmányt is. Nem

csupán azért, mert egyszerű alkalmazásként is futtatható, sokkal inkább azért, mert nem használ aktív

hálózatkezelést; abban az értelemben, hogy jelen programozói nézőpontunkból, egy honlapról történő applet

letöltést passzív hálózatkezelésnek tekintünk.

3.1.1. A LabirintusVilág példa

Kezdetben elkészítjük labirintusunk világát: magát a labirintust, kincsestől, szörnyestől, hősöstől, a szokásos

történettel: miszerint a hős bolyong, a szörnyek próbálják megenni, a kincs várja, hogy rábukkanjanak. A

kézikönyv fő feladata megmutatni, hogyan meséljük el, mutassuk be ezt az elképzelt labirintus világot Java

nyelven. Ha ezzel az elbeszéléssel, leírással elkészültünk, akkor ebben a példában, ebben a programban - avagy

Java nyelven majd azt mondjuk: ebben a LabirintusVilág nevű osztályban - keltjük életre ezt az elbeszélést.

Ennek megfelelően ez az osztály nem fogja csillogó grafikus felülettel felruházni elbeszélésünket, hanem

csupán egy karakteres megjelenést ad majd, hogy megmutassa, hogyan kel életre ez a most teremtett tiszta OO

mikrovilágunk: a labirintus.

A példaprogramokban a téma, a labirintus mikrovilágának életre keltése közös, de a megcélzott platformok és a

létrehozott labirintusok funkcionális szintje már markánsan különböző. Ez utóbbira példa, hogy a jelen program

a labirintus világának valóságát önálló idővel ruházza fel, azaz a labirintus világának valóságában az idő a

játékostól, azaz a hős lépéseitől függetlenül telik, szemben például majd a következő példával, ahol a labirintus

világának valóságában mindig csak akkor üt egyet az óra, ha a játékos, azaz a hős lép egyet. A platformok

különbözősége kapcsán arra gondoljunk, hogy a példák között van Java SE, Java ME, Java EE platformra és

CORBA architektúrára készített program is. A Java SE a Java alapkiadása, egyelőre elég annyi róla, hogy abban

az esetben, ha nem tudjuk, hogy az aktuálisan írt Java programunkat mégis éppen milyen platformra kéne

felkészítenünk, akkor valószínűleg az alapkiadásra, azaz a Java SE kiadásra, a Java sztenderd kiadásra van

szükségünk.

3.1.2. A LabirintusApplet példa

Page 16:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xiv Created by XMLmind XSL-FO Converter.

Ez az osztály a labirintus mikrovilágának egy appletbeli életre keltésére ad példát. Az Applet objektumok azok

a Java SE platformbeli objektumok, akik képesek a böngészőkben létezni, s mint ilyenek megjelenni az

internetes weblapokon. Ezzel, mintegy varázsütésre teremtett labirintus mikrovilágunk már nemcsak a mi PC-

nken létezhet, hanem bármely olyan internetes gép böngészőjében, amelyről ezt az appletünket letöltik. További

érdekessége a példának, hogy önálló alkalmazásként való futtatásra is felkészítettük.

Ennek a példának nincs önálló időbeli fejlődése, hanem csupán a játékos lépéseitől függő, azaz mondhatjuk,

hogy a program futását a játékostól érkező események irányítják. Viszont a labirintus megjelenítése már

grafikus.

3.1.3. A LabirintusJáték példa

A PC-s játékok tipikusan a teljes képernyőt uralják, ez az osztály a labirintus mikrovilágának egy olyan életre

keltését tartalmazza, amely ugyancsak képes erre! Ennek megfelelően a labirintus világának megjelenítése

grafikus, időbeli fejlődése pedig önálló. Ha például a hőst nem mozgatja a játékos, akkor is könnyen meglehet,

hogy az okos szörnyek felkutatják és hipp-hopp, néhány időegység után máris felfalták!

3.2. Mobiltelefonos példák

Ezen példák, mint nevük is mutatja, a mobiltelefonra történő Java alkalmazások fejlesztését vezetik be.

3.2.1. LabirintusMIDlet példa

Page 17:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xv Created by XMLmind XSL-FO Converter.

Ahogyan labirintus világunk appletként a böngészőbe töltődött, úgy töltődik MIDletként a mobiltelefonba. A

MIDlet objektumok azok a Java ME platformbeli objektumok, akik képesek létezni a mobiltelefonok Java

virtuális gépeiben.

Ez az osztály tehát arra ad példát, hogyan vihetjük át mobilra a teremtett labirintus mikrovilágunkat. A labirintus

világának megjelenítése itt is grafikus, időbeli fejlődése szintén önálló.

3.3. Hálózati példák

A hálózati példák, mint nevük is mutatja, a kézikönyvet több összekapcsolt gép mellett ülve feldolgozó

Olvasóknak nyújtják legoptimálisabban a programozás élményét. Ilyen lehet otthon két összekapcsolt gép, vagy

annak az oktatási intézménynek a tantermi hálózata, melyhez az Olvasó tanárként, hallgatóként, diákként

kötődik. De természetesen egyetlen, akár Windows, akár Linux operációs rendszerű gépet használva is

tesztelhetők a példák.

3.3.1. A LabirintusServlet példa

Hasonlóan az előző példához: ahogyan labirintus világunk appletként a böngészőbe töltődött, vagy éppen

MIDletként a mobiltelefonba, úgy töltődik Servletként a webszerverbe. A Servlet osztálybeli objektumok azok

a Java EE platformbeli objektumok, akik képesek a webszerverekben létezni. Tehát szemben az előző két

példával, objektumaink most nem a kliens oldalon, azaz nem a böngészőben és nem a mobiltelefon Java

virtuális gépében léteznek, hanem a szerver oldalon: a webszerverben.

A labirintus világának megjelenítése jelen példánál nem grafikus, hanem a böngészőbe történő HTML nyelvű,

azaz szöveges lapok küldésében merül ki, tehát elvben karakteres, de ebbe a szöveges válaszba megfelelő <img

Page 18:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xvi Created by XMLmind XSL-FO Converter.

scr=""> HTML parancsok küldésével nagyon könnyen grafikussá is tehető a labirintusunk böngészőbeli

megjelenítése. Továbbá a példa időfejlődése sem önálló.

3.3.2. A HálózatiLabirintus példa

Az informatikában van királyi út, abban az értelemben, hogy minél több programon keresztül csinál valamit a

programozó, annál egyszerűbb az élete. Gondoljunk csak arra, hogy mekkora erőfeszítés lenne gépi kódban

olyan programokat írni, amelyek különböző processzorú hardvereken működnek. Ennél kisebb erőfeszítés lenne

olyan programot írni, ami ugyanezeken a különböző hardvereken, de mondjuk mindegyik esetén Linux

operációs rendszerek alatt futna, mert már élvezhetnénk az operációs rendszer támogatását, ha egy magasabb

szintű nyelvet választanánk a fejlesztéshez, mondjuk a C nyelvet. De ha még a különböző hardvereken esetleg

különböző operációs rendszerek is futnak, viszont mindannyiukra megvan a Java Virtuális Gép (JVM - Java

Virtual Machine), akkor igazán a királyi úton járhatunk: Java programunk mindenhol futni fog, ahol fut a Java

Virtuális Gép. Ez a jelenség általában is megfigyelhető: az előző példában nem kellett foglalkoznunk a Servlet

objektumunk és a kliensek hálózati kapcsolatteremésének beprogramozásával, hanem csak azzal, hogy egy kész

kapcsolaton keresztül milyen, de már csupán a saját labirintusunkkal kapcsolatos adatokat akarunk küldeni a

kliensnek.

Ebben az értelemben a jelen példa lépés visszafelé, mert itt bizony foglalkozunk a hálózati kapcsolat

kiépítésének beprogramozásával, lévén, hogy a java.net csomag TCP-s hálózati osztályainak felhasználásával

a socket programozás absztrakciós szintjén dolgozunk itt. Ennek megfelelően kliensként a telnet programot

használjuk majd, azaz a megjelenítésünk karakteres lesz. Viszont a szerver oldalon a labirintust önálló

időfejlődéssel látjuk el.

3.3.3. A TávoliLabirintus példa

Abban az értelemben, ami szerint az előző példával visszafelé léptünk, most előre haladunk: itt nem

foglalkozunk kommunikációs kapcsolatok felépítésével, hanem csak a kommunikációnak a saját labirintus

Page 19:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xvii Created by XMLmind XSL-FO Converter.

példánk kapcsán érdekes részével. A kliens oldalon megszerezzük a távoli labirintus objektum referenciáját, ami

után már nincs akadálya, hogy a referencia után egy pontot téve meghívjuk a hivatkozott objektum egy

metódusát, igen távolról: de hoppá, ez az objektum egy másik, a távoli szerver oldal virtuális gépében van!

3.3.4. A KorbásLabirintus példa

Ezzel a példával tovább lépünk előre az absztrakciónak azon útján, amit a TCP/IP-s példa kapcsán kezdtünk el

boncolgatni. Immár az sem számít majd, hogy objektumaink milyen nyelven készültek, hanem csupán az, hogy

milyen üzeneteket lehet küldeni az objektumainknak vagy ha így jobban tetszik: milyen szolgáltatásokat

nyújtanak az objektumaink. Azt azért gyorsan megjegyezzük, hogy ettől persze mi továbbra is Java nyelven

dolgozunk, Java osztályokat készítünk, de példánknál maradva már leginkább csak arra kell figyelnünk, hogy

mit csinálnak a hősök a labirintusban...

Ez királyi út, de persze ára is van: sok programnak kell együtt és helyesen együtt működnie, hogy a programozó

kisebb terheket hordhasson a vállán...

3.3.5. A ElosztottLabirintus példa

Page 20:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xviii Created by XMLmind XSL-FO Converter.

Az eddigi példákat az jellemezte, hogy volt egy labirintus mikrovilágunk, aminek különféle használati eseteit

készítettük el. A jelen példa pedig arról szól, hogy a hős és a labirintus, sőt még a kincs és a szörny objektumok

is valóban különböző gépeken lehetnek! Például az ábra mutatta esetben a labirintus CORBA objektum a

172.21.0.152 IP számú és egy kincs a 172.21.0.17 IP számú gépen.

3.4. További példák

Találkozni fogunk még számos kisebb-nagyobb labirintus variáns feladattal, ezeket külön nem mutatjuk be itt,

mert e feladatok célja csupán valamilyen aktualitásra vagy apróságra, finomságra való rámutatás. Például a

LabirintusAlkalmazás osztály a Java Musztáng verziójától élő néhány GUI-val kapcsolatos újdonságot

(alkalmazásunk ikonjának elhelyezése az értesítési területre, indító képernyő a programunkhoz), vagy mondjuk

a GenerikusLabirintus osztály a - Java Tigris verziójától használható - generikus vagy éppen az iteráló for

ciklus alkalmazását mutatja be.

Illetve találkozni fogunk még számos kisebb-nagyobb olyan feladattal, amelyeket valamely, a kézikönyvben

érintett területtel kapcsolatban külön tárgyalunk. Ilyenek például a biológiai tárgyú szimulációs illetve számítási,

vagy a matematikai számolási (mint például a Mandelbrot halmaz tetszőleges részének kinagyításáról szóló,

vagy a Pi hexadecimális jegyeit kiszámoló) példák. A következő képet például a kézikönyvhöz készített

Mandelbrotos példaprogrammal generáltuk és mentettük el.

Page 21:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xix Created by XMLmind XSL-FO Converter.

3.4.1. A további önálló példák könyvjelzői

Itt a kézikönyvben szereplő önálló, azaz nem a labirintusos esettanulmányok részeiként szereplő példák közül

emelünk ki néhányat.

I. A Turing-féle gépek. (Programozás papíron.)

II. Számrendszerek, bitműveletek

i. Bitműveletek, kezdjük egy bináris dumppal. (Csak azoknak, akik szeretik a bitfaragást.)

ii. Kizáró vagyos titkosítás. (A táblánál és papíron is jól bemutatható bitműveletes példa, a gyakorlatban

használjunk PGP-t!)

iii. A kizáró vagyos titkosítás Swinges felületen. (Grafikus felülettel látjuk el az iménti példát.)

iv. Számrendszer átváltások. (Bármikor szükség lehet rá, például a kézikönyvben a Pi jegyeinél is

felhasználjuk majd.)

III. Véletlenszám generátorok, normális eloszlás

i. Normális, módosított polártranszformációval [29]. (Matematikusok első OO osztálya.)

ii. Hisztogram feladat. (Normalitás vizsgálat.)

Page 22:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xx Created by XMLmind XSL-FO Converter.

iii. Galton deszka kísérlet. (Szimulációs példa.)

IV. Fraktálok: Mandelbrot halmazok

i. Mandelbrot halmaz programja. (A szépség mellett GUI, szálkezelési, egér és billentyűzet

eseménykezelési példa.)

V. Pi közelítése

i. Gregory-Leibniz formula. (Pi/4 = 1 - 1/3 + 1/5 - 1/7 + ... valameddig egy ciklusban.)

ii. A Ramanujan és a Chudnovsky közelítő összegek formulái. (Hatékonyak, de számolni, a számolással

programozási élményt szerezni a 64 bites lebegőpontos aritmetika nem elegendő.)

iii. BBP (Bailey-Borwein-Plouffe) algoritmust: a Pi hexa jegyeinek számolása [361]. (Ezzel az algoritmussal

már saját PC gépünkön is nagy élményeket élhetünk át a Pi jegyeinek kutatásában!)

VI. Sejtautomaták

i. Sejtautomata szimuláció programja. (A híres Conway-féle életjáték és a Gosper-féle sikló ágyú.)

ii. Az Orch OR sejtautomata szimuláció részét demonstráló programja. (Az Orch OR a Penrose-Hameroff-

féle tudatmodell rövidítése.)

VII. Genomok, fehérjék

i. Genomi, aminosav vagy akár tetszőleges szekvenciák összehasonlítása. (Az aktualitáson túl egy Swinges,

legördülő menüs példa.)

És persze kombinálhatjuk is a példákat, mondjuk a genomi szekvenciák összehasonlítására készített

pontmátrixos programunkkal összehasonlíthatjuk a Pi hexadecimális kifejtésének első és második ezer jegyét,

vagy éppen a Pi ezer jegyét a második emberi kromoszóma első kétezer T, C, A, G jegyével. A programozni

tudás erejét éppen az adja, hogy ha a gépek tudnak válaszolni arra, amire éppen kíváncsiak lettünk, akkor egy

program formájában fel tudjuk nekik tenni a kérdésünket.

3.4.2. A példák jellege

A példaprogramok oktatási céllal készültek, azaz tipikusan valami olyan tulajdonságot mutatnak, amit velük

kapcsolatban a könyvben bemutatunk, kifejtünk. Például a labirintus elosztott változata azt akarja megmutatni,

hogy minden szereplő objektum külön számítógépen van. De ennél nem többet, ennek megfelelően nem

foglalkozik például - az egyébként természetesen felmerülő - hálózati terheléssel, szinkronizációs problémákkal,

hibakezeléssel, magas szereplő szám esetén a működőképességgel kapcsolatos kérdésekkel.

Ezért a példáknál magunk adunk meg például továbbfejlesztési feladatokat, tipikusan olyanokat, amiket mi

magunk már elkészítettünk vagy úgy gondoljuk, hogy el tudnánk készíteni a könyvben tárgyalt részek alapján.

De számos esetben megadjuk a megoldásokat, vagy legalább a megoldások lényegi részét.

3.4.3. Összefoglalás

A kézikönyvhöz készített programok tipikusan interaktív jellegűek. A labirintusos esettanulmányok példáira az

interaktivitás triviálisan teljesül, hiszen mindig a játékos mozgatja a labirintus hősét. A további programok

interaktívak vagy demonstratívak. Az előbbire példaként említhetjük a Mandelbrot halmazokat számoló,

nagyító, színező programokat, az utóbbiakra pedig például az Orch OR modelbelli mikrotubulus sejtautomata

üzemének demonstrálását.

Néhány interaktív jellegű példa alkalmas lehet arra, hogy más, nem konkrétan informatikai tárgyak oktatásában

is felhasználja a tanár Olvasó. Ilyen például a matematikai jellegű számítási példák között a Mandelbrot halmaz

zn+1 = zn2 + c iterációs számítási lépéseit grafikusan is megmutató példa. Vagy ilyenek a biológiai jellegű

számítási példák között a genomi szekvenciák összehasonlítására szolgáló példaprogramjaink, amelyeket

nemcsak a középiskolai, hanem a felsőoktatásbeli, nem konkrétan informatikai szaktárgyakhoz is

felhasználhatunk, hiszen ebben az irodalomban - például a [BIOINFORMATIKA] vagy [PROTEOMIKA]

hivatkozásokban - tipikus, hogy internetes programok címét adják meg a saját tapasztalatokra vágyóknak.

Page 23:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xxi Created by XMLmind XSL-FO Converter.

Remélhetőleg, vagy még inkább pontosabban, ha e könyv eléri célját, akkor az Olvasó kénye-kedve szerint tudja

majd kombinálni a példákat: ott, ahol nincs grafikus megjelenítés: készíteni tud majd ilyet, vagy ott, ahol nincs

önálló időfejlődés, fel tudja ruházni ezzel a példát. Ennek során persze felmerülhetnek további nehézségek,

amikre jelen bevezető könyv keretein belül nem térhettünk ki. Hogy csak néhány kombinációt említsünk: a

LabirintusServlet osztályhoz szeretnénk grafikus megjelenítő appletet vagy a LabirintusServlet

osztályba szeretnénk önálló időfejlődést. Nem konkrétan ez utóbbira, de az ilyen esetekre ajánljuk a Nyékyné

Gaizler Judit: Java 2 útikalauz programozóknak [JAVA KÖNYV] című mélyebb szakkönyvet, de

természetesen fordulhatnak bátran a szerzőkhöz is a [email protected] vagy a [email protected] címre írt,

Javát tanítok Olvasó tárgyú elektronikus levélben.

3.4.4. Platform

A szórakoztató háttér ismerete avagy előfeltételek a további

olvasáshoz

Ha a kedves Olvasó még nem látta, akkor a kézikönyv feldolgozásának érzelmi megalapozásaként

javasoljuk a Mátrix [MÁTRIX MOZI] trilógia első részének és a Mi a csudát tudunk a világról? című

[KVANTUM MOZI] film megnézését és átbeszélését az Olvasó környezetével: a barátokkal,

kollégákkal. Illetve javasolunk még némi számítógépes játékot, mondjuk például a DOOM [DOOM

JÁTÉK] FPS játékkal. További szórakoztató - s itt a szórakoztató alatt természetesen most nem az

ismeretterjesztőt értjük - források tekintetében például a [KAPCSOLAT MOZI] filmet vagy még

inkább a [KAPCSOLAT REGÉNY] regényt ajánlhatjuk. Ez utóbbira a könyv több tartalmi elemében is

hivatkozni fogunk.

Figyeltünk arra, hogy mind a Linux, mind a Windows operációs rendszert használó Olvasók a könyv szöveges

magyarázó és példaprogramos részeit egyaránt és teljesen egyformán élvezni tudják. Ez persze nem volt túl

nehéz, mivel főtémánk a Java, aminek egyik erőssége éppen a platformfüggetlenség. Ez azt jelenti, hogy

mindegy milyen operációs rendszer dolgozik alattunk, ha mi Javaban programozunk, programunk változtatás

nélkül futni fog mindkét platformon.

Operációs rendszer

Mindazonáltal azt tanácsoljuk az Olvasónak, hogy Windows rendszere mellé telepítsen fel egy Linuxot

is, mert a lazábban kapcsolódó olvasmányos részekbe igyekeztünk sok olyan finomságot is beleszőni,

amit egy Linux mellett ülve a legizgalmasabb kipróbálni. Mi például a Fedora (Core 5) Linux

operációs rendszert (http://fedora.redhat.com) használjuk, az Olvasónak is ezen rendszer használatát

javasoljuk.

Fedora Linux Core 6

A kézikönyv írásának vége felé közeledve elérhetővé vált a Fedora Core 6, amire természetesen mi is

frissítettünk, így immár Linux választása esetén e GNU/Linux rendszer használatát javasoljuk

(http://fedora.redhat.com).

Megjegyezhetjük, hogy az Fedora ötöshöz hasonlóan a Fedora hatosra is igaz, hogy 32 bites és 64 bites

rendszerekre egyaránt elérhető az imént megadott címen.

3.4.5. A példaprogramok szerkezete, kipróbálása és a kézikönyv jelölései

A könyvben szereplő minden programot a szerzők készítettek és le is futtattak tipikusan két gépen: egy Linuxos

és egy Windowsos PC-n. A szereplő hálózati példák kapcsán fontos kihangsúlyoznunk, hogy ezek mindegyike

kipróbálható egyetlen, hálózatba nem kapcsolt akár Linuxos, akár Windowsos gépen is.

A kézikönyv számos példájának bemutatása vagy az egyik vagy a másik különálló számítógépen történik.

Page 24:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xxii Created by XMLmind XSL-FO Converter.

A kézikönyv hálózati példái némelyikének bemutatása két gyors Ethernet hálózati kártyával felszerelt és

Ethernet kábellel összekötött, a 192.168.1.1 és a 192.168.1.2 fenntartott IP számokkal beállított

számítógépen történik. Esetünkben az egyik gép Linuxos, a másik Windowsos.

Az otthoni két gép összekapcsolása

Ha az Olvasó már rendelkezik két géppel, amiket az imént említett módon szeretne összekapcsolni,

akkor a két hálózati kártya és a kábel költsége ma már csupán néhány ezer forintnyi költségre rúg.

A kézikönyv néhány hálózati példájának bemutatása pedig egy az internethez is kapcsolt lokális hálózatban

történik.

Page 25:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xxiii Created by XMLmind XSL-FO Converter.

A kézikönyvben a futási eredményekkel kapcsolatos betétek szedése tipikusan a

[norbi@niobe ~]$

vagy az egészen rövid, egyetlen dollárjel

$

prompttal történik, ha a Linuxos és

C:\Documents and Settings\norbi>

prompttal, ha a Windowsos gépen történt a futás. Ez utóbbit néha nyomdatechnikai okokból majd a C:\...>

rövidített alakban írjuk, feltéve persze, hogy ez a rövidítés az értelmezést nem zavarja. Az előbbinél pedig

azokban az esetekben, amikor a tárgyalt példában szükséges lehet megkülönböztetnünk, hogy éppen melyik

gépen dolgozunk, a promptban a szokásos módon megkülönböztetjük, feltüntetjük a hoszt neveket (mint például

alább a niobe és az omega neveket) is.

Page 26:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xxiv Created by XMLmind XSL-FO Converter.

[norbi@niobe ~]$ itt a niobe nevű gépen vagyunk

[norbi@omega ~]$ itt pedig az omega nevű gépen dolgozunk éppen

A kézikönyv a példákkal kapcsolatos forráskód részleteket és teljes forrásprogramokat is tartalmaz. A források

mindkét esetben bőséges dokumentációval vannak ellátva, tehát külön elolvasásuk sem haszontalan. A teljes

programokat Linux és Windows rendszerek alatt is lefordítottuk és futtattuk, tehát ezek kipróbálásával,

futtatásával az Olvasónak - ha követi utasításainkat - sem támadhat áthatolhatatlan akadálya, főleg azért, mert a

kipróbálásról: fordításról, futtatásról, használatról mindig külön is szólunk, sőt számos esetben képeket is

bemutatunk. A teljes forrásprogramokat onnan is felismerheti a kedves Olvasó, hogy tipikusan a következő

jellegű Java dokumentációs megjegyzésekkel kezdődnek. Az alábbi sorok például a Galton deszkás kísérletes

szimulációs példánk kapcsán kifejlesztett GaltonDeszka osztályunkat definiáló GaltonDeszka.java

forrásállomány első sorai.

/*

* GaltonDeszka.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* A Galton deszka kísérletet szimuláló osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

Azt is mutatja, hogy a forráskódot kijelölve azt a GaltonDeszka.java forrásállományba kell beillesztenie a

kedves Olvasónak az önálló felhasználásához, kísérletezéshez.

A magyar ékezetes betűk használatáról

A példaprogramokban igyekeztünk magyar ékezetes betűket használni. Igaz ez a példaprogramokat

alkotó osztályok neveire vagy például az osztályokban használt változónevekre. Sajnos e törekvésünk

során néhány alkalommal az ékezetes betűk használatából adódtak problémáink, ezekben az esetekben

majd ékezet nélküli osztálynevekkel találkozik a kedves Olvasó.

A források olvasásáról

A Java programozó API programozó, ennek megfelelően úgy kell használnia az API dokumentációt,

mint például a Linux/UNIX alatti programozónak a programozói kézikönyv - a második szintű manuál

- lapjait, amit például

[norbi@niobe ~]$ man 2 select

parancs kiadásával olvashatunk. Mi az API dokumentáció használatát annyiban tudjuk segíteni, hogy a

forrásokban felhasznált osztályok nevét mindig a teljes csomagnévvel minősítve írtuk, így például a

java.net.ServerSocket az is elárulja, hogy az Olvasó a szerver socketeket absztraháló

Page 27:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xxv Created by XMLmind XSL-FO Converter.

ServerSocket osztályt a java.net csomagban találja meg. Az API dokumentáció telepítéséről A Java

dokumentáció, azaz az API doksi letöltése című pontban olvashatunk.

4. Látványos Ars Poetica

„S mivel a játékok szocializációs funkciója alapvető jelentőségű, meglehet, hogy éppen az

információs ipar játéktermékei adják meg a döntő, visszavonhatatlan lökést a homo

informaticus evolúciójához.” —Mérő László

A következő ábra szerkezetével az emberiség tudásának egy lehetséges és persze erősen vitatható elrendezését

vázoltuk fel.

A nyilvánvaló visszacsatolások indukálta kérdésekkel - hogy mivel például az emberi lényről az

Orvostudomány doboz környékén beszélünk, de a matematika is az emberek fejében van..., vagy talán inkább a

platóni ideák világában? - nem foglalkoztunk.

Napjaink Informatika doboza az ábra Matematika dobázának közelében egy fiatal doboz lenne, de ha a madáchi

„szellem szemekkel” látnánk, akkor el tudjuk képzelni, hogy minden tudásunk egy absztrakt, de természetes

informatika ágba rajzolható, ez a mi ars poeticánk, amit Neumann [GÉP és AGY] utolsó könyvének utolsó

gondolata inspirál:

„Arra is rá kell mutatni, hogy ez az idegrendszeri nyelv nem is csekély valószínűséggel inkább

a korábban leírt értelemben vett rövid program, mint hosszú program. Meglehet, hogy amikor

matematikai fejtegetésekkel foglalkozunk, akkor egy olyan másodlagos nyelvről tárgyalunk,

amely ráépül a központi idegrendszer által ténylegesen használt elsődleges nyelvre.” —Neumann János

Page 28:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Bevezetés

xxvi Created by XMLmind XSL-FO Converter.

Page 29:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Created by XMLmind XSL-FO Converter.

I. rész - Programozás papíron

Ebben a részben nemcsak fejben, hanem papíron is dolgozunk, de ne ijedjünk meg: egyelőre nem azért nem

kapcsolunk be gépet, mert félünk tőle, hanem mert az itt szereplő gépeket nem lehet bekapcsolni, mivel ezek

egy platóni világban, pontosabban csak a mi képzeletünkben léteznek, működnek.

Továbbá a gyakorlati érdeklődésű Olvasónak is bátran ajánljuk ezt a részt, mert a Turing gépes környezetben

való programozás előszobája az algoritmikus információelméletnek. Ami, a mi olvasatunkban,a programozói

konstruktív szemlélet manifesztációja a tudományban.

A rész befejezéséül az objektumorientált (OO) világ, majd a hálózat, az internet programozóknak fontos

alapfogalmait tekintjük át.

Page 30:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

2 Created by XMLmind XSL-FO Converter.

1. fejezet - A programozásról

„Csak akkor értesz valamit, ha be tudod programozni. Te magad és nem valaki más! Ha nem tudod

beprogramozni, akkor csak úgy gondolod, hogy érted.” —Gregory Chaitin META MATH! The Quest for Omega

A tudomány fejlődésében egyre nagyobb szerepet kapnak az informatikai gondolkodásmódra épülő paradigmák.

E jelenség gyökere az informatikai gondolkodásmód erősen konstruktív jellege. Az informatikai ihletésű

paradigmák alapfogalma a számítások, a számítógépek könnyen kezelhető, precíz modellje a Turing gép. Ebben

az elméleti programozási fejezetben ezekkel a gondolatbeli gépekkel és programozásuk szépségeivel,

nehézségeivel ismerkedünk meg. Elméleti erőfeszítéseink zárásaként bemutatjuk a Turing gépek több,

filozofikusan is nagyon izgalmas felhasználását, amik többek között a matematika megalapozásának kérdéséhez

is elvezethetik a kedves Olvasót. Majd a gyakorlat, a Java programozás felé vesszük az irányt, bevezetve a Java

SE, Java ME OO világ és végül az internet programozásának alapfogalmait.

Ebben az elméletiből-gyakorlati tárgyalásba forduló, programozást bevezető részben

• megismerhetjük a számítógépek, számítások elméleti modelljét: a Turing gépet

• a Turing gépekhez kapcsolódó legfontosabb eredményeket

• egy a Turing gépekre épülő bonyolultsági mértéket

• a végtelen ciklusok elkerülésének Omega valószínűséget

• végül az eddigi elméleti erőfeszítéseink koronájaként a Gödel és Chaitin-féle inkompletibilitási tételeket

• majd tovább lépve a gyakorlat felé: megismerhetjük a Java SE világát

• és a Java ME világát

• végül az internet és a hálózati programozás alapfogalmait vezetjük be

1. A programozás filozófiája

„Elképzelte, ahogy a kis adatcsomag keresztüláramlik a hálózati kábelen és létrehozza a

képernyőn látható tengerészgyalogost. - A jobb oldali számítógépre pillantott és figyelte a

most külső szemszögből látható karakterét, ahogy átfut a képernyőn. Fantasztikus világot

teremtett, most pedig életre keltette.” —David Kushner

Az előszóban említettük, hogy a programozásra gondolva olykor valami misztikus, mámoros érzés járja át a

programozót...

Foglalkozzunk most tovább kicsit ezzel az érzéssel! Mert foglalkozni kell vele: hogyan lehet a diákokban

felépíteni azokat a mentális struktúrákat, amelyek majd rezonálni képesek erre az érzésre? Hol élhetjük hát át ezt

az érzést? A Linux különösen sok alkalmat ad rá: például a kernelfordításnál - a kernelfordítás leírását lásd a

[PROGRAMOZÓ PÁTERNOSZTER JEGYZET]-ben - amikor a C források éppen fordulnak és tudjuk, hogy

néhány perc múlva már ezzel az éppen most lefordított kernellel fogjuk újra bebootolni gépünket, hogy az

általunk, éppen most, a rendszerre szabott szoftver vezérelje azt. De sokszor még gép közelébe sem kell

mennünk, hogy átéljük a szóban forgó élményt. Elég beülni a moziba vagy betenni a dvd lemezt és megnézni az

életünkben felvirradt információs-programozói civilizáció csúcstermékét, az immár kultuszfilmet -

programozóknak pedig kötelező szakmai mozit - a Mátrix [MÁTRIX MOZI] trilógiát. Ennek az alkotásnak a

gyökereitől elvitathatatlan, hogy a virtuális valóságon keresztül az informatikába nyúlnak.

Az információs-programozói civilizáció kialakulásával párhuzamosan egyre mélyebbre és mélyebbre nyúlnak

az informatika fájának gyökerei is. Az Alan Turing által képzeletben, Neumann János vezetésével gyakorlatban

létrehozott, a gondolkodás formalizált lépéseit imitáló gépek utódainak mai hekkerei (hackerei) már az emberi

tudatot, a kvantumfizikai valóságot akarják programozni...

Page 31:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

3 Created by XMLmind XSL-FO Converter.

Kezdjük hát - hogy stílszerűek legyünk - kedves Olvasó, „menjünk fel adásszintre”!

1.1. A programozás alapjai

„Valóban a matematika nyelvén írták a világegyetemet, mint azt Galilei gondolta? Én

hajlamosabb vagyok azt hinni, hogy inkább ez az egyetlen nyelv, amin megpróbálhatjuk

elolvasni.” —Stanislas Dehaene

Mi hát az a nyelv, amit a ma programozójának beszélnie kell? A legalapvetőbb és egyben az átlagos

programozó számára garantáltan a legeslegfelhasználhatatlanabb nyelv a Turing gépeké. Mindig

megnevettethetik az érdeklődő Olvasót azok a viccek, amik poéntartalma a: „Hol van a Turing gép kiállítva?”

beugratós kérdés variánsa. Mert ezek a gépek csupán a matematikai képzeletünkben léteznek. De csak azért ne

becsüljük le ezeket a konstrukciókat, mert mint írtuk, az iparban nem felhasználhatók. Neumann ENIAC

(Elektronikus Numerikus Integráló és Számológép) gépéhez - ami a maga idejében ipari és tudományos

területről egyaránt érkező, számos numerikus jellegű feladatot oldott meg - ma már nem találnánk programozót,

mert a gépek és programozásuk időközben annyira megváltozott. Nem így a Turing gépek, azok ma is

ugyanazok és ugyanúgy programozandók, mint ahogyan Turing annak idején megálmodta és programozta

[TURING CIKK] őket.

A „Hol van a Turing gép kiállítva?” kérdés története

A Debreceni Egyetem helyi legendáriuma ezt a kérdést Szabó József professzor úr kedvelt, tréfás

beugratós, államvizsgán elhangzó kérdéseként jegyzi. A Juhász Istvánnal történő közös

vizsgáztatásakor történt meg az az eset, amikor a hallgató azt felelte: „Otthon az iskolámban”. Ugyanis

egy levelezős általános iskolai tanár Juhász István biztatására megépített két fizikai reprezentációt is,

amelyen a gyerekek nagy lelkesedéssel „Turing-programoztak” [TURING GÉP REPREZENTÁCIÓ].

1.1.1. Algoritmikus kérdések

„Bele kell majd nyugodnunk abba a ténybe, hogy értelmünk erőfeszítései nem adhatnak olyan

teljes képet a világról, amilyet elérni - erőfeszítésektől mentesen, könnyű elmélkedéssel - a

görögök álma volt.” —Wigner Jenő

A következő néhány pontban leverünk gondolkodásunk sodrába néhány olyan mentális cölöpöt, melyekbe

kapaszkodva meg tudjuk vetni lábunkat, ha filozofálni támad kedvünk a programozásról magáról. Megismerjük

az univerzális Turing gépeket és a megállási, azaz a végtelen ciklusok elkerülésének problematikáját, továbbá

egy immár tisztán a programozásra épülő, mindenféle bonyolultságokat összehasonlítani képes fogalmat: a

Chaitin-Kolmogorov-Solomonoff bonyolultságot. Végül a programozás orientált információelmélet

inkompletibilitási tételeit mutatjuk be. Aki programozó akar lenni, annak ezeket a fogalmakat nem árt ismerni.

Aki pedig komolyan akar hekkelni a témában, annak ezeket a fogalmakat ismerni kell, hát még annak, aki - e

pont bevezető idézetének értelmében - görög akar lenni! Ez utóbbi tréfás tagmondatot az inspirálja, hogy

véleményünk szerint egy átlagos programozó a véletlen sorozatok témában rövid idő alatt, szemléletében is

mély tudásra tehet szert, még hasonló tudás megszerzése a hegy matematikai statisztikai oldalán mászva nagyon

nagy nehézségekkel járna számára (a metaforikusan említett hegy statisztikai ösvénynek a leírását a [KNUTH 2.

KÖNYV] könyvben olvashatja a matematikai érdeklődésű Olvasó).

1.1.1.1. A Turing-féle gépek

„Az egyik legjellemzőbb emberi vonás a kíváncsiság. A végtelenségig nem dacolhatsz vele.” —Arthur C. Clarke

A Turing gépeket matematikailag egyszerűen, szépen és pontosan le lehet írni, most mégis inkább egy rajzot

készítünk, mert azt feltételezzük, hogy ez az első találkozásunk ezekkel a gépekkel. Íme legyen az első Turing

hardverünk a következő!

Page 32:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

4 Created by XMLmind XSL-FO Converter.

Bemutatott hardverünk leírása: a memória végtelen sok cellából áll, jelen Turing hardverünkben egy

memóriacella három értéket hordozhat. A # jelöli, hogy üres a cella és lehet még benne a 0 vagy az 1 számjegy.

A vezérlőegység képes beolvasni és írni az I/O fej alatti memória cellát és az állapot regiszterét, továbbá jobbra

és balra lépkedni, de akár helyben is maradni.

Jöjjön a szoftver! A Turing gépet programozhatjuk szövegesen vagy grafikusan. Egy példán keresztül lássuk

először a szöveges módot:

1. Ha Lépked állapotban vagyok és 1-et olvasok, akkor 1-et írok, Lépked állapotban maradok és jobbra lépek!

Röviden: (Lépked, 1) -> (Lépked, 1, ->)

2. Ha Lépked állapotban vagyok és 0-t olvasok, akkor 0-t írok, Lépked állapotban maradok és jobbra lépek!

Röviden: (Lépked, 0) -> (Lépked, 0, ->)

3. Ha Lépked állapotban vagyok és #-et olvasok, akkor #-et írok, Lépked állapotban maradok és jobbra lépek!

Röviden: (Lépked, #) -> (Lépked, #, ->)

4. Kezdetben legyek Lépked állapotban, az input szó első betűjén állva!

Az utasítások általános formája a Turing gép utasításciklusának alábbi (végrehajtása előtt) -> (végrehajtása után)

formájában megadva a következő:

(állapotban vagyok, mit olvasok) -> (állapotban leszek, mit írok, merre lépek)

A program megadásának grafikus módja egy gráf, az úgynevezett állapot-átmenet gráf megadása. A gráf csúcsai

a gép lehetséges állapotai, élei a következő alakúak.

A „program gráf” működése: megnézzük,

hogy milyen állapotban vagyunk és éppen mit olvasunk, majd az állapotunknak megfelelő csúcsból az ilyen (mit

olvasunk, , ) alakú címkével jelzett kivezető élt keresünk és azon megyünk tovább. Ha esetleg nincs ilyen él az

állapotunknak megfelelő csúcsból, akkor a gép megáll.

Adjuk meg most az imént szereplő, szövegesen leírt szoftvert grafikus formában!

Page 33:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

5 Created by XMLmind XSL-FO Converter.

Jelen példánkban az ötödik lépés után már mindig a (#, #, ->) élen

utazunk tovább ugyanoda és mindig ugyanazt, a # jelet olvassuk ott újra, tehát ...

Tehát mit csinál ez a program? Kövessük végig gondolatban, azaz futtassuk le! Remélem nem futtattuk órákig,

mert bizonyára tapasztaltuk, hogy a program soha nem áll le, ez bizony végiglépked az input szó betűin, majd

tovább az üres jeleken, s amit olvas azt visszaírja... ez egy végtelen ciklus: egy olyan szituáció amikor a gép

soha nem áll le.

Nézzünk még egy példát, most a hardver legyen egészen hasonló, mint az előző gépbe épített, de immár egy

állapottal bővebb az állapotaink halmaza:

A szoftver is legyen hasonló, mégpedig grafikus alakban megadva a következő.

Mit csinál a gép? Végigmegy az inputon és a végére ír egy nullát. A szalagon példaként álló 101 szóból az 1010

szót készíti el. Az 11 szóból az 110 szót,

az 1100110101101111001111111111 szóból

az 11001101011011110011111111110 szót, azaz minden bemenő bináris szó végéhez hozzáfűz egy nullát, tehát

kettővel szorozza az input szót: például 101 = 5, 1010 = 10. Az új nulla beírásakor átmegy a Vég állapotba, ahol

aztán meg is áll, mert nincs olyan programutasítás, ami most alkalmazható lenne, hiszen ebből az állapotból

semmilyen él nem vezet ki (szövegesen: nincs olyan programsor, ami arra válaszolna, mit kell csinálni a

vezérlésnek, ha Vég állapotban van és # betűt olvas, így tanácstalanságában a gép megáll).

Készítsünk egy harmadik gépet is, további továbbfejlesztésként: ha az üres szó van induláskor a szalagon, azaz,

ha input nélkül futtatjuk a gépet, akkor ne csináljon semmit, illetve ha esetleg vannak a bináris szó előtt vezető

Page 34:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

6 Created by XMLmind XSL-FO Converter.

nullák, akkor azokat törölje le. Egyébként ugyanúgy kettővel szorozzon!

E harmadik gép szoftvere:

Negyedik gyakorló gépünk üzemeljen kicsit más jelleggel, legyen feladata az input szóról eldönteni, hogy

rendelkezik-e valamilyen tulajdonsággal. Döntse el, hogy az inputként binárisan lekódolt szám kettővel

osztható-e. Szokás szerint minden azzal kezdődik, hogy a programozó kitalálja az algoritmust: igen a válasz, ha

a szám bináris kódja a 0 jeggyel végződik, nem, ha az 1 számjeggyel, vagy nincs input szó.

A szoftvert úgy szervezzük, hogy a gép az Elfogadó állapotában álljon meg, ha az input szó osztható kettővel,

illetve ellenkezőleg, az Elutasító állapotában álljon meg, ha nem osztható. A szoftver legyen tehát a következő:

Page 35:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

7 Created by XMLmind XSL-FO Converter.

1.1.1.1.1. Az univerzális Turing gépek

A fenti három példa már jól mutatja, hogy minden feladatra külön Turing-féle számítógépet kell konstruálnunk.

Meg kell adnunk, hogy milyen betűk lehetnek a szalagon, milyen állapotokban lehet a gép, mi a kezdő és

végállapota - ezek voltak a hardver kérdések - és milyen (állapot, olvasott) -> (állapot, írni, lépésirány)

programutasításai vannak - ezek voltak a felmerülő szoftveres kérdések. Egy nagyon fontos, alapvető, de most

bizonyítás nélkül ismertetett tétel azt mondja, hogy létezik olyan Turing gép, ami képes bármely más Turing-

féle gépet szimulálni. (A bizonyítás szó kapcsán rámutathatunk, hogy ezen a bizonyításon a megfelelő Turing

gép megkonstruálását kell érteni!) Visszatérve a szimulációs tételhez, ez azt jelenti, hogy ezt a speciális Turing

gépet egy másik Turing gép és e másik Turing gép inputjából készített inputtal indítva ugyanazt az eredményt

fogja produkálni, ugyanúgy fog működni, mint önmagában futtatva a másik Turing gép az inputjával. Ezeket a

speciális Turing gépeket univerzális Turing gépeknek nevezzük. Ezek a mi mai számítógépeink megfelelő,

elméleti modelljei, mert innentől nem kell minden feladathoz külön Turing gép, hanem veszünk egy univerzális

Turing gépet és annak inputként (tehát adatként) beadhatunk egy megfelelően lekódolt Turing gépet (mint

végrehajtandó programot) és annak inputját (mint adatot).

Az egyszerű Turing gépet rajzban így festettük le:

Ennek megfelelően az Univerzális Turing gépeket pedig így rajzolhatjuk le:

Mindkét géptípus esetén a továbbiak során röviden majd azt is rajzoljuk, hogy

Page 36:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

8 Created by XMLmind XSL-FO Converter.

Ami alatt azt értjük, hogy a T gép szalagján az x szó az input, az U gép szalagján pedig egy T gép és a T gép x

inputjának egyesítésével előálló szó az input.

1.1.1.2. A Turing gép piac

„Senki sem űzhet ki minket a Cantor által teremtett paradicsomból” — David Hilbert [STEWART KÖNYV]

Miért bírnak alapvető fontossággal a Turing-féle gépek? Mert tapasztalataink alapján úgy gondoljuk, hogy

azokat a feladatokat lehet digitális számítógéppel, tehát valamilyen programozási nyelven megírt algoritmussal

megoldani, amit Turing géppel is meg lehet oldani és megfordítva: amely feladatokat nem tudunk Turing géppel

megoldani, azt algoritmussal, azaz valamely digitális számítógépre valamilyen nyelven megírt semmilyen

programmal sem tudunk megoldani. Ezt a tapasztalatunkat nevezzük Church-Turing tézisnek. A tézissel

kapcsolatban további olvasmányként a [DRAGÁLIN KÖNYV] logika vagy az [ALGORITMUSOK KÖNYV],

illetve a [LOVÁSZ KÖNYV] algoritmuselméleti tankönyveket ajánljuk.

Tehát amit meg tudok írni C-ben vagy Javaban, azt elvben Turing géppel is meg tudnám csinálni, ki tudnám

számítani. Meglehet, hogy ennek a megfelelő Turing gépnek az elkészítése hatalmas fáradtság lenne, mint

ahogyan például a megoldást adó x86 assembly nyelvű program változatnak megírása is jóval nagyobb munka

lenne az eredeti C vagy Java változat megírásánál. Futási ideje is hihetetlenül megnőne, lévén a Turing gép a mi

fejünkben működik, magam interpretálom, játszom le sorban a gép működésének lépéseit... de a lényeg, hogy

elvben nincs különbség a Java nyelvű és a Turing program között. Azért a programozói fizetés tekintetében

inkább a Java nyelv gyakorlására hangolnám a tipikus Olvasót, semmint a Turing programozásra.

1.1.1.3. Végtelen ciklus, avagy a megállás problémája

„Ne kérdd

Tovább a titkot, mit jótékonyan

Takart el istenkéz vágyó szemedtől.

Ha látnád, a földön múlékonyan

Pihen csak lelked, s túl örök idő vár:

Erény nem volna itt szenvedni többé.

Ha látnád, a por lelkedet felissza:

Mi sarkantyúzna, nagy eszmék miatt”

—Madách Imre

A végtelen ciklusok felbukkanása két területen különösen gyakori, ezek a területek a szerver oldali programozás

és az algoritmusokról szóló elméleti vizsgálatok. Ebben a pontban még ez utóbbival foglalkozunk: építünk egy

megépíthetetlen Turing komputert!

Tegyük fel, hogy van egy olyan algoritmusunk - azaz a Church-Turing tézis értelmében van egy olyan Turing

gépünk - ami egy másik algoritmusról, azaz Turing gépről meg tudja mondani, hogy megáll-e majd. Tehát, hogy

nem kerül végtelen ciklusba. Nevezzük ezt a feltételezett speciális gépet M gépnek és felépítése legyen ilyen:

Page 37:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

9 Created by XMLmind XSL-FO Converter.

Ez az M gép az inputjaként kódolva megkapott tetszőleges T Turing gépről el tudja dönteni, hogy az meg fog-e

állni vagy végtelen ciklusba fog esni. Ezt tételeztük fel, hogy van ilyen M (Megállást megvizsgálni tudó) gép.

Nézzük meg az M gép működését egy konkrét T gépre:

i. ha a T gép megálló gép, akkor az M a kékkel jelölt úton működik és előbb-utóbb az elfogadó állapotában áll

meg

ii. ha a T gép végtelen ciklusba eső gép, akkor az M a pirossal jelölt úton működik és előbb-utóbb az elutasító

állapotában áll meg.

Ennek a feltételezetten létező M gépnek a felhasználásával építsük meg a még nagyobb E gépet a következő

tervrajz alapján!

Játsszuk végig az E (Ellentmondó gép) működését egy tetszőlegesen választott, konkrét T inputra:

i. ha a T gép megálló gép, akkor az M a kékkel jelölt úton működik és előbb-utóbb az elfogadó állapotába

megy, ahonnan bármit olvas, visszaírja, helyben marad a fej és átmegy a gép a végtelen ciklus állapotba,

ahogyan a neve is utalja: bármit olvas, visszaírja, helyben marad a fej, azaz ez egy végtelen ciklus! Tehát

nem áll meg az E gép.

ii. ha a T gép végtelen ciklusba eső gép, akkor az M a pirossal jelölt úton működik és előbb-utóbb az elutasító

állapotába megy, ahonnan bármit olvas, visszaírja, helyben marad a fej és átmegy a gép a Megáll állapotába,

ahogy mint neve is erre utal megáll. Tehát megáll az E gép.

Jöjjön most a trükk: hogy működik az E gép, ha a saját maga lekódolása az inputja? Tehát ha az E gépet az T=E

inputtal indítjuk el?

i. Ha az E gép megálló gép, akkor az M a kékkel jelölt úton működik és előbb-utóbb az elfogadó állapotába

megy, ahonnan bármit olvas, visszaírja, helyben marad a fej és átmegy a gép a végtelen ciklus állapotba,

ahogyan a neve is utalja: bármit olvas, visszaírja, helyben marad a fej, azaz ez egy végtelen ciklus! Tehát

nem áll meg az E gép, hanem végtelen ciklusba esik.

ii. Ha az E gép végtelen ciklusba eső gép, akkor az M a pirossal jelölt úton működik és előbb-utóbb az elutasító

állapotába megy, ahonnan bármit olvas, visszaírja, helyben marad a fej és átmegy a gép a Megáll állapotába,

ahogy mint neve is erre utal megáll. Tehát megáll az E gép.

Emeljük ki az eredményt:

i. Ha az E gép megálló gép, akkor nem áll meg az E gép, hanem végtelen ciklusba esik.

ii. Ha az E gép végtelen ciklusba eső gép, akkor megáll az E gép.

Page 38:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

10 Created by XMLmind XSL-FO Converter.

Hoppá! Döbbenetes, nem igaz? Jó kis ellentmondás, ez Turing nagy felfedezése, hogy a megállási probléma

nem dönthető el! Mert az ellentmondásnak csak az lehet a feloldása, hogy a feltételezett M gépünk nem

létezhet! Az E gép már csupán egy légvár vagy még inkább csak egy álomkép volt, mert alkatrésze az M

(Megállást megvizsgálni tudó) gép nem létezhet, mert ha létezne, abból az imént demonstrált ellentmondás

következne. Tehát nincs olyan algoritmus, ami meg tudná mondani, hogy az inputjaként kapott tetszőleges

Turing gép megáll-e vagy végtelen ciklusba esik. Ez nem azt jelenti, hogy a

#include <stdio.h>

int

main(void)

{

printf("Hello, Vilag!\n");

return 0;

}

C programról nem tudom kijelenteni, hogy megáll, hiszen hogyne állna meg.

S nem azt jelenti, hogy a

int

main(void)

{

for(;;)

;

}

C programról nem tudom kijelenteni, hogy végtelen ciklus, hiszen hogyne lenne az. Hanem azt jelenti, hogy

nincs olyan algoritmus, ami a fenti két programról és ezekkel együtt tetszőleges programról meg tudná mondani,

hogy meg fog-e állni vagy végtelen ciklusba esik. Tehát nincs olyan program, aminek a bemenetéül megadva a

fenti két program egyikét, vagy egy tetszőleges más programot, a program lefutna és kiírná, hogy meg fog-e

állni az inputként kapott program vagy végtelen ciklusba esik.

1.1.1.4. A Chaitin-Kolmogorov bonyolultság

„Kövesd a fehér nyulat!” —MÁTRIX

Figyelmeztetés a Javaban kezdő Olvasóknak

Ebben a pontban felhasználunk néhány Java nyelvű programot. Ezek igen egyszerűek, de annak, aki

még nem ismeri a Java nyelvet, meglehet, teljesen olvashatatlanok, ismeretlen jelentésűek. Fontos,

hogy ők még véletlenül se tekintsenek úgy ezekre a programokra, mint Java bevezetésre, mint az első

Java programjaikra, mert ezek nem erre a célra készültek. Most csupán annyi a fontos, hogy a program

mit ír ki és hány karakterből áll. Az előbbit mi leírjuk, az utóbbit könnyen megszámolhatja a kezdő

Olvasó is, természetesen a program bármilyen feldolgozása, megértése nélkül.

1.1. példa - Első sorozat: 1000 nulla

Tekintsük a következő 1000 darab nullából álló mondatot!

00000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000

Page 39:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

11 Created by XMLmind XSL-FO Converter.

00000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000

0000000000000000000000000000000000000000

Nézzünk most meg az ElsőSorozat1 nevű programot, ami éppen ezt a sztringet nyomtatja ki:

public class ElsőSorozat1 {

public static void main(String[] args) {

System.out.print("000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000

0000000000");

}

}

Ez a program 1082 karakterből áll (az egyszerűség kedvéért a szóközöket nem számoljuk).

1.2. példa - Első sorozat, máshogy: 1000 nulla

Nézzünk meg az ElsőSorozat2 nevű programot, ami szintén ugyanezt a sztringet nyomtatja ki:

public class ElsőSorozat2 {

public static void main(String[] args) {

for(int i=0; i<1000; ++i)

System.out.print(0);

}

}

Ez a program már csupán 103 karakterből áll. Ebben az egyszerű esetben könnyen látható, hogy néhány

karakterrel rövidebb Java forrásprogramot is lehetne készíteni - de ezt általában nem lehet tudni - nekünk

mindenesetre most ez a legrövidebb olyan programunk, ami kinyomtatja az 1000 darab nullát.

1.3. példa - Második sorozat: 01010101 ...

Tekintsük az újabb 1000 darab karakterből álló mondatot:

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

Page 40:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

12 Created by XMLmind XSL-FO Converter.

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

0101010101010101010101010101010101010101

Ezt a sztringet nyomtatja ki a MásodikSorozat1 nevű program:

public class MásodikSorozat1 {

public static void main(String[] args) {

for(int i=0; i<500; ++i)

System.out.print("01");

}

}

Ez a program 108 karakterből áll.

1.4. példa - Harmadik sorozat: 00000000001 ... 10000000000

Tekintsük a harmadik 1000 darab karakterből álló mondatot:

00000000001111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

1111111111111111111111111111110000000000

Ezt a sztringet nyomtatja ki a HarmadikSorozat1 nevű program:

public class HarmadikSorozat1 {

public static void main(String[] args) {

System.out.print("0000000000");

for(int i = 0; i<980; ++i)

System.out.print("1");

System.out.print("0000000000");

}

}

Page 41:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

13 Created by XMLmind XSL-FO Converter.

Ez a program 170 karakterből áll.

1.5. példa - Negyedik sorozat: egyre több 1 jegy két nulla között

Tekintsük a negyedik 1000 darab karakterből álló mondatot, 0 számjegyek között egyre több 1 számjegy van:

00101101110111101111101111110111111101111111101111111110111111111101111111111101

11111111111011111111111110111111111111110111111111111111011111111111111110111111

11111111111011111111111111111101111111111111111111011111111111111111111011111111

11111111111110111111111111111111111101111111111111111111111101111111111111111111

11111011111111111111111111111110111111111111111111111111110111111111111111111111

11111101111111111111111111111111111011111111111111111111111111111011111111111111

11111111111111110111111111111111111111111111111101111111111111111111111111111111

10111111111111111111111111111111111011111111111111111111111111111111110111111111

11111111111111111111111111011111111111111111111111111111111111101111111111111111

11111111111111111111101111111111111111111111111111111111111101111111111111111111

11111111111111111111011111111111111111111111111111111111111110111111111111111111

11111111111111111111111011111111111111111111111111111111111111111101111111111111

1111111111111111111111111111111111111111

Ezt a sztringet nyomtatja ki a NegyedikSorozat1 nevű program:

public class NegyedikSorozat1 {

public static void main(String[] args) {

for(int i=0; i<44; ++i) {

System.out.print(0);

for(int j=0; j<i; ++j)

System.out.print(1);

}

System.out.print("1111111111");

}

}

Ez a program 177 karakterből áll.

1.6. példa - Ötödik sorozat: pszeudo véletlen

Tekintsük az ötödik 1000 darab karakterből álló, meglehetősen rendszertelennek tűnő mondatot:

01011010000010010000111000111110111100010100100111101001000000010100100011101010

01111111010000001001000011011000101011110010011010100010010000010110011001000101

01100110010001101001110000110101110011111011010001101110001010010000001110011110

00101001001111100100111101101111000110111011010011110000101001010000111110000100

01110110011100101011000000011011111011011101101110110110000101010110011000100111

00111010110001111010011110100000011110101011100001101100001111001001010101000000

01111111101100000100001000001000000011111000101010111111000000010001111101110100

11010001011010011111010100111010100110101101011011110011001101011011011101101111

00110111000100101011111111111111000001010111100110100101001101111011001000100100

10111011000111101110000110010011010100110111101011001011101011011110110100100011

10001111100010100010111111100100010010111010000001110001101010101000001100100100

10011110000110110111001111110101101011110101100011001100001011010100001111111010

Page 42:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

14 Created by XMLmind XSL-FO Converter.

0000100111011101010100101101001110010001

Ezt a sztringet nyomtatja ki az ÖtödikSorozat1 nevű program:

public class ÖtödikSorozat1 {

public static void main(String[] args) {

System.out.print("010110100000100100001110001111101111000101001001111010

010000000101001000111010100111111101000000100100001101100010101111001001

101010001001000001011001100100010101100110010001101001110000110101110011

111011010001101110001010010000001110011110001010010011111001001111011011

110001101110110100111100001010010100001111100001000111011001110010101100

000001101111101101110110111011011000010101011001100010011100111010110001

111010011110100000011110101011100001101100001111001001010101000000011111

111011000001000010000010000000111110001010101111110000000100011111011101

001101000101101001111101010011101010011010110101101111001100110101101101

110110111100110111000100101011111111111111000001010111100110100101001101

111011001000100100101110110001111011100001100100110101001101111010110010

111010110111101101001000111000111110001010001011111110010001001011101000

000111000110101010100000110010010010011110000110110111001111110101101011

110101100011001100001011010100001111111010000010011101110101010010110100

1110010001");

}

}

Ez a program 1084 karakterből áll.

Összegezzük eredményeinket!

1.1. táblázat - A bonyolultságmérő programok összefoglalása.

SOROZAT PROGRAM MÉRET

Első sorozat ElsőSorozat1 1082

ElsőSorozat2 103

Második sorozat MásodikSorozat1 108

Harmadik sorozat HarmadikSorozat1 170

Negyedik sorozat NegyedikSorozat1 177

Ötödik sorozat ÖtödikSorozat1 1084

Chaitin után azt a sorozatot tekintjük kevésbé bonyolultnak, amit rövidebb programmal sikerült generálni. E

definíció alapján az iménti sorozatok egyre bonyolultabbak voltak. Bár az elsőre is adtunk egy 1082 karakteres

programot, de rögtön utána találtunk egy csupán 103 karakteres programot. Intuíciónkkal jó összhangban van ez

a megközelítés, mert az utolsó sorozatra nemigen tudunk az 1084 hosszú programnál rövidebbet írni, mert nincs

benne olyan szabályosság, amit beprogramozva tömörítést érhetnénk el.

1.7. példa - Bármely sorozat: egy másoló program

Vagy mégis? Tekintsük most meg a következő másoló programot!

Page 43:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

15 Created by XMLmind XSL-FO Converter.

public class TetszőlegesSorozat1 {

public static void main(String[] args) throws Exception {

int i = 0;

while((i=System.in.read()) != -1)

System.out.printf("%c", i);

}

}

Működése a szokásos: abban áll, hogy a bemenetét a kimenetére másolja. Így ezzel is ki tudom nyomtatni

bármelyik sorozatot! A program hossza pedig csak 147 betű!

A program inputjaként megkapva az ötödik sorozatot:

C:\...> echo 0101101000001001000011100011111011110001010010011110100100000001010

01000111010100111111101000000100100001101100010101111001001101010001001000001011

00110010001010110011001000110100111000011010111001111101101000110111000101001000

00011100111100010100100111110010011110110111100011011101101001111000010100101000

01111100001000111011001110010101100000001101111101101110110111011011000010101011

00110001001110011101011000111101001111010000001111010101110000110110000111100100

10101010000000111111110110000010000100000100000001111100010101011111100000001000

11111011101001101000101101001111101010011101010011010110101101111001100110101101

10111011011110011011100010010101111111111111100000101011110011010010100110111101

10010001001001011101100011110111000011001001101010011011110101100101110101101111

01101001000111000111110001010001011111110010001001011101000000111000110101010100

00011001001001001111000011011011100111111010110101111010110001100110000101101010

00011111110100000100111011101010100101101001110010001|java TetszőlegesSorozat1

Ha megnyomva az entert lefuttatjuk, akkor kiírja az ötödik sorozatunkat. Ezért a fenti bonyolultság

definíciónkat ki kell bővítenünk, mert emlékezzünk vissza, most egy 147 karakteres programmal és egy kis

trükkel - nevezetesen, hogy inputként adtuk meg a kívánt sorozatot - sikerült generálnunk az ötödik

sorozatunkat.

Egy x sorozat Chaitin-Kolmogorov bonyolultságának annak a program kódjának és inputjának az együttes

hosszát nevezzük, ami program kinyomtatja x-et és az ilyen programok között a legkisebb. Ennek megfelelően

korábbi összefoglaló táblázatunk most az alábbi alakot ölti.

1.2. táblázat - A bonyolultságmérő programok és bemenetük együttes összefoglalása.

SOROZAT PROGRAM KÓD MÉRET INPUT

MÉRET

A bonyolultság felső

becslése

Első sorozat ElsőSorozat1 1082 0 1082

ElsőSorozat2 103 0 103

TetszőlegesSorozat1 147 1000 1147

Második sorozat MásodikSorozat1 108 0 108

TetszőlegesSorozat1 147 1000 1147

Page 44:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

16 Created by XMLmind XSL-FO Converter.

SOROZAT PROGRAM KÓD MÉRET INPUT

MÉRET

A bonyolultság felső

becslése

Harmadik sorozat HarmadikSorozat1 170 0 170

TetszőlegesSorozat1 147 1000 1147

Negyedik sorozat NegyedikSorozat1 177 0 177

TetszőlegesSorozat1 147 1000 1147

Ötödik sorozat ÖtödikSorozat1 1084 0 1084

TetszőlegesSorozat1 147 1000 1147

Helyreállt tehát a világ rendje, miután a program kódjának és inputjának együttes hosszát tekintettük a

bonyolultság definíció alapjának. Azt vegyük észre, hogy nem bonyolultságról, hanem a bonyolultság felső

becsléséről beszélünk: azaz egy olyan számról, aminél a valódi bonyolultság kisebb, esetleg egyenlő lehet. Mert

ugye jöhet egy nálunk nagyobb hekker, aki még rövidebben megírja...

Miért jó nekünk ez a bonyolultság fogalom? Mert rá építve értelmesen tudjuk definiálni, hogy mit jelent véletlen

sorozatnak lenni. De a fenti Java nyelvű, intuitív megalapozás után mindenekelőtt pontosabban definiáljuk a

Chaitin-Kolmogorov bonyolultságot.

Egy x sorozat Chaitin-Kolmogorov bonyolultságának annak a Turing gépnek (T) és inputjának (y) az együttes

hosszát nevezzük, ami kiszámolja x-et az Univerzális Turing gépen és az ilyenek között a legrövidebb.

Itt a legrövidebb nem a futási időre vonatkozik, hanem, ahogy a Java példáknál is láttuk, a programok és az

input együttes hosszára. Egészen konkrétan ez annyit jelent, hogy megszámoljuk az U gép szalagján az

induláskor az input, azaz a T és az y 0 és 1 jegyekkel való megadása, lekódolása mennyi cellát foglal el.

A Chaitin-Kolmogorov bonyolultság egyébként programozóknak nagyon szemléletes: a vizsgált sorozat

bonyolultsága csakis kisebb vagy egyenlő lehet annak az algoritmusnak (Turing gépnek) és az algoritmus

bemenetének együttes hosszánál, amely algoritmus produkálni tudja ezt a sorozatot.

De micsoda fájdalom annak az Olvasónak, aki máris program írását tervezte arra, hogy kiszámolja a Chaitin-

Kolmogorov bonyolultságot, például az alábbi példa mintájára.

Mert fájdalom, de könnyen belátható - amit a következő példában meg is teszünk - hogy nem létezik olyan

Turing gép, ami ezt képes lenne megtenni, ebből már tudjuk, hogy nincs olyan algoritmus, ami képes lenne ezt

megtenni, tehát hasztalan lenne ilyen program írásával próbálkozni! (Nyilván ennek a lehetetlenségnek nincs

köze ahhoz, hogy a példa bemenet a Biblia volt :)

Figyelmeztetés a Javaban kezdő Olvasóknak

Page 45:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

17 Created by XMLmind XSL-FO Converter.

A következő állítás bizonyításaként szereplő Java programot csak fussa át a kezdő Olvasó, hogy szeme

szokja a Java nyelvet. Ha eközben a megértésben bármi zavar támadna - s a teljesen kezdőknek nyilván

támadni fog - akkor most bátran hagyja ki, s az utána szereplő ábrán győződjön meg az állítás

igazságáról.

1.8. példa - A Chaitin-Kolmogorov bonyolultság nem kiszámítható!

Programozóknak ez annyira fájdalmas megállapítás, hogy a kedves Olvasó meggyőzésére magunk is belátjuk

ezt az állítást, bizonyításaként megadjuk a [LOVÁSZ KÖNYV] ugyanezen bizonyítását megadó Pascal program

Java változatát.

Tegyük fel tehát, hogy van olyan algoritmus, ami kiszámolja a Chaitin-Kolmogorov bonyolultságot, ha ezt

beprogramozza az Olvasó, akkor a következő kódhoz hasonlót készít.

public class ChaitinKolmogorov {

/** A bonyolultság() függvényben lévő bekommentezett rész mérete. */

public static final int BONYOLULTSÁG_FGV_HOSSZA = 10000;

public static void main(String[] args) {

int i=0;

String sorozat = null;

while(true) {

sorozat = Integer.toBinaryString(i++);

if(bonyolultság(sorozat) > 10 * BONYOLULTSÁG_FGV_HOSSZA)

break;

}

System.out.println(sorozat);

}

public static long bonyolultság(String sorozat) {

long bonyolultság = 0;

/*

* Itt van lekódolva az az algoritmus, ami

* feltevésünk szerint létezik és kiszámítja

* a paraméterként kapott sorozat bonyolultságát.

* Ennek a résznek a hossza legyen mondjuk

* 10000, tízezer betű.

*/

return bonyolultság;

}

}

Page 46:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

18 Created by XMLmind XSL-FO Converter.

Ha meglenne a program, akkor fordítanánk, futtatnánk... Feltevésünk értelmében megvan, tehát képzeljük el,

hogy futtatjuk: amikor megáll, akkor kiír egy olyan szót, aminek a bonyolultsága > 100000, hiszen a main

függvény végtelen ciklusából akkor ugrunk ki a break utasítással, amikor ez a feltétel teljesül. De hiszen ez a

program input nélkül futott, mérete 10000+360 betű, a bonyolultság() függvényének bekommentezett része

helyetti valódi rész mérete + a maradék többi. Tehát 10360 karakteres programmal kiszámoltuk (kiírtuk) ezt a

sorozatot, ezért bonyolultsága ennél csak kisebb egyenlő lehet. Hoppá! Döbbenetes, nem igaz? Jó kis

ellentmondás, ami lehetetlenné teszi feltevésünk helyességét, tehát annak ellenkezője igaz, vagyis, hogy nem

létezik olyan algoritmus, amivel tetszőleges szóról kiszámolhatnánk a szó bonyolultságát.

1.9. példa - A Chaitin-Kolmogorov bonyolultság gyakorlati alkalmazásai

A Chaitin-Kolmogorov bonyolultság több nagyon érdekes gyakorlati alkalmazásáról olvashatunk például a

[VITÁNYI HASONLÓSÁG CIKK] cikkben. Itt a szerzők a Chaitin-Kolmogorov bonyolultságból egy távolság

fogalmat, a hasonlósági metrikát származtatják, aminek rögtön bemutatják két gyakorlati alkalmazását is. Az

első alkalmazás során 20 faj mitokondriális DNS-e alapján filogenetikai fát építenek, s a kapott eredményt a

hagyományos módszerek tükrében is bemutatják. A másikban 52 emberi nyelvet hasonlítanak össze és

ugyancsak bemutatják az eredményeket összefoglaló, a tárgyalt nyelvekre vonatkozó filogenetikai fát.

Érdekességként megjegyezhetjük, hogy vizsgált nyelvek között találjuk anyanyelvünket is. A cikkben

megvizsgált nyelvek összehasonlítását az ENSZ weblapján a szóban forgó nyelveken megtalálható Az Emberi

Jogok Egyetemes Nyilatkozatának fordításai alapján, ezeket a fordításokat korpuszonak tekintve végezték el.

A [HANGYÁK és KOLMOGOROV CIKK] cikkben a szerzők hangyákkal hajtanak végre egy kísérletet. Az

élelemhez vezető utat egy bináris fa formájában teszik lehetővé a hangyáknak, tehát a kísérleti elrendezésben a

hangyák nyelvén a LLRL azt jelenthetné, hogy először fordulj balra, majd megint balra, aztán jobbra végül balra,

hogy elérd a táplálékot. A gyakorló hangyászok megnyugtatására mondhatjuk, hogy a szerzők az egész kísérleti

berendezést egy vízzel teli kádba helyezték, így megakadályozták, hogy a hangyák levágják a kanyarokat. A

kísérleti eredmények mutatják, hogy a bonyolultabb utakról a felfedező hangyának több időre van szüksége,

hogy a többiekkel a táplálék forrás helyéről szóló, feltételezetten LLRL jellegű szerkezettel bíró információt

megossza.

A mobil játékfejlesztés egy formális modelljének megadására használják fel a bonyolultságot a [MOBIL JÁTÉK

ÉLMÉNY] cikkben. A szerzők által javasolt modellben a (számítógépes) játék egy a játék fejlesztője és a játék

felhasználója közötti kommunikációs csatorna. Grafikusan ezt a Shannon eredeti [SHANNON INFÓELM

CIKK] és Benczúr által némileg módosított [BENCZÚR CIKK] ismert séma alábbi átalakításával

szemléltethetjük:

Page 47:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

19 Created by XMLmind XSL-FO Converter.

A hivatkozott cikkben a szerzők definíciót adnak a jó játékra és megmutatják, hogy a jó játékok nyelve nem

rekurzív, azaz nincs olyan általános mechanisztikus eljárás, amivel el lehetne dönteni tetszőleges játékról, hogy

jó lesz-e.

1.1.1.4.1. 0, 1 feladatok

Figyelmeztetés a Javaban kezdő Olvasóknak

A következő Java nyelvű példák mindenféle egyszerű gyakorlatok a 0 és az 1 jegyekkel, bitekkel. Az

első átvált kettes számrendszerbe, a második egy bitműveleteket használó bináris dump (megmutatja a

bájtok bitjeit), a harmadik egy ugyancsak bitműveletes titkosító példa. A negyedik egy számrendszer

átváltásos példa. Az ötödik pedig egy Turing gépet kódol le egy 0 és 1 jegyekből álló sorozattá.

Ezen példák forrásait csupán fussa át a kezdő Olvasó, hogy szeme szokja a Java nyelvet. Ha eközben a

források megértésében bármi zavar támadna - és a teljesen kezdőknél nyilvánvalóan támadni fog -

akkor most bátran hagyja ki őket, s ha majd első labirintusos Java programjaink kipróbálásához érkezik

az anyag feldolgozásában, az után térjen vissza ide és írja meg (próbálja ki) ezeket a programokat.

Megjegyezhetjük, hogy ebben a Programozás papíron című részben általában is elegendő a szereplő

forrásokra csak egy pillantást vetni és inkább a programok használatát, működését megfigyelni: hogyan

indítjuk, milyen bemenettel fut, mit ír ki a képernyőre stb. Természetesen mindezt nem egy gép előtt

kipróbálva, hanem az általunk a kézikönyvbe illesztett néha Linuxos, néha Windowsos

pillanatfelvételeket megfigyelve.

1.10. példa - Átváltás binárisba

Már többször szóba került a 0, 1 jegyekkel való lekódolás. Lépjünk ebbe az irányba egy picikét! Lássuk azt a

Java programot, ami a bemenetét 0, 1 sorozattá alakítja. Ezt a programot a korábbi TetszőlegesSorozat1

program továbbfejlesztéseként fejlesszük ki! Következik néhány megoldás, a kezdő Olvasó ezeket, ahogy

megbeszéltük, rövid átfutás után most egyszerűen át is ugorhatja! (Mert ez nemhogy nem OO programozás

bevezető példa, de majd még bitfaragásba is fajul...)

public class NullaEgy {

public NullaEgy() {

int i = 0;

try {

while((i=System.in.read()) != -1)

System.out.printf("%s", Integer.toBinaryString(i));

} catch(java.io.IOException e) {

System.out.println("Hiba az olvasáskor, kilépek. " + e);

}

}

public static void main(String[] args) {

new NullaEgy();

}

}

Bájtonként olvassuk a program bemenetét, amit a Java programozó számára a System.in objektum reprezentál.

Ennek az objektumnak a read() módszere egy bájtot olvas be, azaz a beolvasás eredménye egy 00000000(bináris)

(0) és 11111111(bináris) (255) közé eső szám. Ha viszont már nem lehet mit olvasni a System.in bemenet

objektumról, akkor a read() függvénye ezt a -1 érték visszaadásával jelzi. Ezt azért tudja megtenni, mert a

Page 48:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

20 Created by XMLmind XSL-FO Converter.

read() függvény int típusú értéket ad vissza, ami nem csupán a 0-tól 255-ig tartó intervallumba eső számokat

képes hordozni, hanem ennél jóval-jóval nagyobb tartományt, a negatív -231-től (ami szokásosan kiírva -

2147483648) egészen a 231-1-ig (ami kiírva 2147483647).

A program while ciklusa törzsének egyetlen magányos utasítása nem csinál mást, mint egyszerűen kiírja a -1

számtól különböző beolvasott számot kettes számrendszerben az Integer osztály statikus

toBinaryString(egészet vár) bináris sztringet visszaadó (az iménti bizonyítás forrásában már használt)

függvényével.

De a bitfaragókat ez a program nem elégíti ki, több okból sem: a kapott 0,1 bináris sorozatot nem lehet

visszaalakítani - meg tudja mondani a kedves Olvasó, hogy miért nem? Ha nem, akkor próbálja megtenni

mondjuk a 012abc betűket tartalmazó bemenet.txt állománnyal! A bemenetet triviálisan úgy tudjuk megadni,

hogy kiadjuk a java NullaEgy parancsot, ami elindítja Java programunkat, majd begépeljük a 012abc inputot és

entert nyomunk. De ennél jóval elegánsabb, ha a bemenet.txt állomány tartalmát parancssorból küldjük

programunk bemenetére. Két módot mutatunk erre, az elsőben a < jel szemléletesen mutatja az irányítást. Az

Olvasó, ha gép előtt ülne, akkor (a fenti tartalmú NullaEgy.java forrásállomány létrehozása, majd lefordítása

után) ezt láthatná egy parancsablakában:

C:\...> java NullaEgy < bemenet.txt

110000110001110010110000111000101100011

másik lehetőség a | (csővezeték jel) használata, ami a bal oldalán lévő parancs kimenetét a jobb oldalán lévő

bemenetére (cső)vezeti:

C:\...> type bemenet.txt|java NullaEgy

110000110001110010110000111000101100011

Most a lényeghez visszatérve: ha 8 bitenként vissza akarjuk váltani a kapott

110000110001110010110000111000101100011 kimenetet, akkor gondban vagyunk, mert ez csak 39 jegy,

nekünk pedig az átváltáshoz 6x8 jegy kellene. A problémát az okozta, hogy az átváltott bináris számok nem

voltak 8 jeggyel kiírva, hanem mindig csak annyival, amekkora az adott szám volt:

0 48 110000

1 49 110001

2 50 110010

a 97 1100001

b 98 1100010

c 99 1100011

ezért nem tudnánk ezt a kódolást dekódolni, mert honnan tudnánk, hogy az elejétől elindulva éppen 6, 7 vagy

nyolc jegyenként kéne visszaváltani a bitmintákat?

A másik ok, ami miatt a bitfaragókat nem elégíti ki a tárgyalt program, hogy az Integer osztály statikus

metódusának hívásával túl egyszerűen jutnak a bináris számhoz, ezért írnak egy jobbat bitműveletekkel...

Figyelmeztetés a Javaban kezdő Olvasóknak

Ha az előző forrást átugrottuk, akkor a most következő NullaEgyDump forrás kihagyása még

indokoltabb.

Aki viszont már nem kezdő és bele akar gabalyodni, annak is csak annyi iránymutatást adunk, hogy az

egye változóba a 00000000000000000000000010000000 mintát az éppen vizsgált bájttal beéselve

Page 49:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

21 Created by XMLmind XSL-FO Converter.

tesszük, aminek eredménye a 00000000000000000000000000000000, ha a vizsgált bájt balról első

bitje 0 és 00000000000000000000000010000000, ha a vizsgált bájt balról első bitje 1. Aztán az egye

változó bitmintáját jobbra tologatjuk, a vizsgált bájt bitjeit pedig balra...

1.11. példa - Bitműveletek, kezdjük egy bináris dumppal

Tehát ott tartottunk, hogy írunk egy jobbat bitműveletekkel!

public class NullaEgyDump {

public NullaEgyDump() {

try {

byte [] buffer = new byte[1];

while(System.in.read(buffer) != -1) {

for(int i=0; i<8; ++i) {

int egye = buffer[0] & 0x00000080;

if((egye>>>7) == 1)

System.out.print(1);

else

System.out.print(0);

buffer[0] <<= 1;

}

}

} catch(java.io.IOException e) {

System.out.println("Hiba az olvasáskor, kilépek. " + e);

}

}

public static void main(String[] args) {

new NullaEgyDump();

}

}

Ez már egy igazi dump jellegű program lett: a bemenetét bájtonként veszi és kiírja a bájt nyolc bitjét. Próbáljuk

ki így:

C:\...> java NullaEgyDump < NullaEgyDump.class

11001010111111101011101010111110000000000000000000000000001100100000000001000001

00001010000000000001000000000000000111010000100100000000000111100000000000011111

00001010000000000010000000000000001000010000100100000000000111100000000000100010

...

azaz beadva neki inputként a saját class állományát! Ellenőrizzük, hogy jó-e a kimenet! Az első 4x2x4 jegyet,

ami a 11001010111111101011101010111110, tegyük át hexába, ha az eredmény nem ugyanaz, mint a

Bitfaragó feladat című feladat megoldása, akkor „még van kanál” [MÁTRIX MOZI], azaz még dolgozzunk a

megoldáson!

Page 50:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

22 Created by XMLmind XSL-FO Converter.

Az utolsó 0,1 feladatként megírunk majd egy olyan programot, ami egy Turing gépet alakít át egy bináris szóvá,

de előtte időzzünk még kicsit a bitműveleteknél, a következő klasszikus példánál!

1.12. példa - Titkosítás kizáró vaggyal

„...ez a módszer az egyik legrégibb és legismertebb. Hacsak a kulcs nem nagyon hosszú, a

CIA vagy az NSA várhatóan egy napon belül megfejti file-unkat.” —Kernighan-Plauger A programozás magasiskolája

A kizáró vagyos titkosítás során a titkosítandó szöveg bájtjait lefedjük a titkosító kulcs bájtjaival és az egymás

alá eső biteken végrehajtunk egy kizáró vagy műveletet. A kizáró vagy 1 értéket ad, ha a két bit különböző és 0

értéket, ha megegyező.

11001011 - a tiszta szöveg egy bájtja

^10101100 - a kulcs bájtja

---------

01100111 - kódolt szöveg, amit

^10101100 - újra beexorozzuk kulccsal

---------

11001011 - az eredeti tiszta szöveg

a [KERNIGHAN PROG KÖNYV]-ben részletesen ismertetett eljárás érdekessége, hogy a titkosítás újbóli

végrehajtásával visszakapjuk az eredeti szöveget. Mi ezt az algoritmust az ExorTitkosító osztályban

valósítottuk meg. S alább bemutatjuk ennek a programnak egy felhasználását. Ha az Olvasó lefordítaná, majd

elindítaná az alma parancssor-argumentummal, a program kimenetét pedig átirányítaná a titkosított.szöveg

állományba, miközben a program indulása után annak bemenetére gépelné be a titkosítandó

Ez titkosítva lesz!

Titkosítva, bizony!

szöveget, akkor ezt látná:

[norbi@niobe ~]$ javac ExorTitkosító.java

[norbi@niobe ~]$ java ExorTitkosító alma > titkosított.szöveg

Ez titkosítva lesz!

Titkosítva, bizony!

[norbi@niobe ~]$ more titkosított.szöveg

$LLk5

AALk

[norbi@niobe ~]$ java ExorTitkosító alma < titkosított.szöveg

Ez titkosítva lesz!

Titkosítva, bizony!

Page 51:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

23 Created by XMLmind XSL-FO Converter.

A Windows parancssorból dolgozóknak

A Windows parancssorból dolgozó kedves Olvasó teljesen a Linux esetén mutatottak mintájára járhat

el:

C:\...> javac ExorTitkosító.java

C:\...> java ExorTitkosító alma > titkosított.szöveg

Ez titkos lesz!

C:\...> type titkosított.szöveg

...olvashatatlan...Llk

C:\...> java ExorTitkosító alma < titkosított.szöveg

Ez titkos lesz!

C:\...>

A titkosított szöveg láthatóan emberi fogyasztásra alkalmatlan. A dekódoláshoz nem kell mást tennie az

Olvasónak, mint újra futtatni a programot ugyanazzal a kulccsal, de most bemenetként az iménti futtatáskor

elkészített titkosított szöveget beleirányítva (java ExorTitkosító alma < titkosított.szöveg) . Az

eredmény a sztenderd kimeneten jelentkezik, azaz, amint fent látta az Olvasó, a képernyőn látható.

public class ExorTitkosító {

public ExorTitkosító(String kulcsSzöveg,

java.io.InputStream bejövőCsatorna,

java.io.OutputStream kimenőCsatorna)

throws java.io.IOException {

byte [] kulcs = kulcsSzöveg.getBytes();

byte [] buffer = new byte[256];

int kulcsIndex = 0;

int olvasottBájtok = 0;

while((olvasottBájtok =

bejövőCsatorna.read(buffer)) != -1) {

for(int i=0; i<olvasottBájtok; ++i) {

buffer[i] = (byte)(buffer[i] ^ kulcs[kulcsIndex]);

kulcsIndex = (kulcsIndex+1) % kulcs.length;

}

kimenőCsatorna.write(buffer, 0, olvasottBájtok);

}

}

public static void main(String[] args) {

try {

new ExorTitkosító(args[0], System.in, System.out);

} catch(java.io.IOException e) {

e.printStackTrace();

}

}

}

Page 52:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

24 Created by XMLmind XSL-FO Converter.

A külső while ciklus buffer tömbönként addig olvassa a bemenetet, amíg csak tudja. A belső for ciklusban

helyezzük rá a kulcsot a beolvasott bájtokra a kulcsIndex változó segítségével, majd végrehajtjuk a kizáró

vagy műveletet, az eredmény a buffer tömbben keletkezik, amit végül a kimenetre írunk.

while((olvasottBájtok =

bejövőCsatorna.read(buffer)) != -1) {

for(int i=0; i<olvasottBájtok; ++i) {

buffer[i] = (byte)(buffer[i] ^ kulcs[kulcsIndex]);

kulcsIndex = (kulcsIndex+1) % kulcs.length;

}

kimenőCsatorna.write(buffer, 0, olvasottBájtok);

}

1.13. példa - Kizáró vagyos titkosítás grafikusan

Az iménti példát lássuk el grafikus felülettel! Egy ilyen felület kinézetére láthatunk példát a Jávácska portál

Jávácska titkosítójánál. Jelen saját megoldásunkat mi a Bepillantás a GUI programozásba című fejezetünkben

adjuk meg. A példa érdekessége, hogy Swinges grafikus felületet és legördülő menüt használ.

1.14. példa - Számrendszer átváltások

A következő TörtÁtváltó osztály törteket vált át valamilyen számrendszerbe. Például megmondja, hogy a tízes

számrendszerbeli 5*16-1 + 0*16-2 + 15*16-3 = 0,316162109375 hexában 0.50F amint ezt a következő, a

tízesből16osba() függvényben beprogramozott algoritmus - szorzok 16-tal, az eredmény egész része a hexa

számjegy, az eredmény törtrészét megint szorzom és így tovább, amíg a törtrész el nem fogy - adja:

0.316162109375 * 16 = 5.05859375

0.05859375 * 16 = 0.9375

0.9375 * 16 = 15.0

Az egész részek a helyes sorrendben keletkeznek, leolvasva: 50F, tehát 0,316162109375decimális = 0.50Fhexadecimális

public class TörtÁtváltó {

public static String tízesből16osba(double tört) {

StringBuffer sb = new StringBuffer();

int számrendszer = 16;

Character hexaJegyek[] = {'A', 'B', 'C', 'D', 'E', 'F'};

while(tört != 0.0d) {

int jegy = (int) Math.floor(számrendszer*tört);

if(jegy<10)

sb.append(jegy);

else

sb.append(hexaJegyek[jegy-10]);

Page 53:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

25 Created by XMLmind XSL-FO Converter.

tört = (számrendszer*tört) - Math.floor(számrendszer*tört);

}

return sb.toString();

}

public static void main(String[] args) {

double tört =

+ 0 * (1.0/16.0)

+ 15 * (1.0/(16.0*16.0))

+ 2 * (1.0/(16.0*16.0*16.0))

+ 10 * (1.0/(16.0*16.0*16.0*16.0))

+ 5 * (1.0/(16.0*16.0*16.0*16.0*16.0));

System.out.println(tört);

System.out.println(TörtÁtváltó.tízesből16osba(tört));

System.out.println(TörtÁtváltó.tízesbőlKettesbe(tört));

}

}

Ha a kedves Olvasó fordítaná és futtatná a programot, akkor a következőket látná:

C:\...> javac TörtÁtváltó.java

C:\...> java TörtÁtváltó

0.05923938751220703

0F2A5

A tízesből16osba() függvényben használt kódot a A Pi jegyeinek nyomában című pont PiBBP osztályában

használjuk majd fel, ahol a Pi hexadecimális törtkifejtését állítjuk elő.

1.15. példa - A TörtÁtváltó osztály kiegészítése

Az iménti TörtÁtváltó osztályhoz írjunk egy tízesbőlKettesbe() függvényt!

public static String tízesbőlKettesbe(double tört) {

StringBuffer sb = new StringBuffer();

int számrendszer = 2;

while(tört != 0.0d) {

int jegy = (int) Math.floor(számrendszer*tört);

if(jegy<10)

sb.append(jegy);

tört = (számrendszer*tört) - Math.floor(számrendszer*tört);

}

return sb.toString();

}

A bővítést elvégezve újrafordítás és futtatás után ezt látná az Olvasó:

C:\...> javac TörtÁtváltó.java

Page 54:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

26 Created by XMLmind XSL-FO Converter.

C:\...> java TörtÁtváltó

0.05923938751220703

0F2A5

00001111001010100101

ellenőrizve: 4 bitenként binárisból hexába váltva valóban 0000 = 0, 1111 = F, 0010 = 2, 1010 = A, 0101 = 5.

1.16. példa - Turing gépek kódolása

Például az [ALGORITMUSOK KÖNYV] 206. oldalán javasolt kódolás alapján készítsünk egy olyan

programot, ami egy Turing gépet 0 és 1 jegyekből álló sorozattá alakít!

Barangoljunk a véletlen 0 és 1 jegyek birodalmában! A következő pontban véletlen sorozatokkal találkozunk, a

reá következőben pedig leleplezzük, hogy ezek mégsem véletlenek!

1.1.1.4.2. Véletlen 0, 1 sorozatok

A következő program előállít egy véges véletlen sorozatot, egészen pontosan példányosít egy Random

objektumot, majd egy ciklusban elkér tőle 1000 darab 0 vagy 1 számot, amiket egyébként a program a

generálásuk után azonnal ki is ír a sztenderd kimenetére.

public class VéletlenSorozat {

public static void main(String[] args) {

java.util.Random generátor = new java.util.Random(42);

for(int i=0; i<1000; ++i)

System.out.print(generátor.nextInt(2));

}

}

Futtassuk le kétszer egymás után a programot, a kimeneteket irányítsuk át az első.sorozat és a

második.sorozat állományba, majd hasonlítsuk össze, hogy a két állomány különbözik-e:

[norbi@niobe ~]$ javac VéletlenSorozat.java

[norbi@niobe ~]$ java VéletlenSorozat > első.sorozat

[norbi@niobe ~]$ java VéletlenSorozat > második.sorozat

[norbi@niobe ~]$ diff első.sorozat második.sorozat

[norbi@niobe ~]$

láthatóan a diff program nem jelentette (lefutott és üzenet nélkül visszaadta a promptot), hogy különböznek,

tehát megegyeznek. Ez meglepő! Lehet ugyanaz az eredmény a második futásnál, ha a sorozat véletlen? Igen,

mert ezek a sorozatok nem valódi véletlenek, hanem egy algoritmus produkálta számok. Ezeknek az

algoritmusoknak (kongruencia generátoroknak) fontos tulajdonsága, hogy egy idő után elkezdik ismételni a

generált számokat. Minél nagyobb ez az idő, annál jobbnak tartjuk a generáló algoritmust.

A Random objektum készítésekor átadott 42 szám azt mondja meg, hogy a generáló algoritmus milyen állapotból

induljon. Mivel mindkét futásnál a 42 szerepelt, így már nem meglepő, hogy mindkét futásra ugyanazt a

számsorozatot generálta a programunk.

1.17. példa - Kongruencia generátorok

Page 55:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

27 Created by XMLmind XSL-FO Converter.

Az xt+1 = a*xt + b (mod m) sorozatot kongruencia generátornak nevezzük. Az y mod m y maradékos osztását

jelenti az m értékkel, azaz y % m. Látványosan úgy értelmezhetjük, hogy az y értéket le kell tekergetnünk egy m

órabeosztást tartalmazó csak kismutatós órán és az eredmény az, ahol a mutató megállt. Például 49 mod 12 = 1.

Mennyi a periódusa a Az xt+1 = 7*xt + 9 (mod 11) generátornak például a 42 értékkel indítva?

Ha a kedves Olvasó nem akarja papírral, ceruzával számolgatni, akkor a következő kis programot írná meg:

public class KongruenciaGenerátor {

int aktuális;

int a = 7;

int b = 9;

int m = 11;

public KongruenciaGenerátor(int első) {

aktuális = első;

}

public int következő() {

aktuális = (a*aktuális + b) % m;

return aktuális;

}

public static void main(String[] args) {

KongruenciaGenerátor g = new KongruenciaGenerátor(42);

for(int i=0; i<100; ++i) {

System.out.print(g.következő());

System.out.print(" ");

}

}

}

amit ha lefordítana és futtatna, akkor az alábbi eredményeket kapná:

C:\...>javac KongruenciaGenerátor.java

C:\...>java KongruenciaGenerátor

6 7 3 8 10 2 1 5 0 9 6 7 3 8 10 2 1 5 0 9 6 7 3 8 10 2 1 5 0 9 6 7 3 8 10 2 1 5

0 9 6 7 3 8 10 2 1 5 0 9 6 7 3 8 10 2 1 5 0 9 6 7 3 8 10 2 1 5 0 9 6 7 3 8 10 2

1 5 0 9 6 7 3 8 10 2 1 5 0 9 6 7 3 8 10 2 1 5 0 9

ahonnan látható, hogy a periódus az alábbi

6 7 3 8 10 2 1 5 0 9

hossza tehát 10.

Magában a JDK-ban is kongruencia generátort építettek be az egyenletes eloszlású számok generálására. A JDK

sikeres telepítés után a JDK könyvtárában találhatjuk az src.zip nevű állományt, amiben megtaláljuk a Java

SE OO világ összes osztályának forráskódját, így a Random osztályét is. Itt a java/util/Random.java forrást

Page 56:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

28 Created by XMLmind XSL-FO Converter.

kinyitva nézzük meg, hogy milyen értékkel lesz inicializálva a generátor, azaz honnan lesz indítva, ha a Random

osztály paraméter nélküli konstruktorát hívjuk, azaz new java.util.Random() formában példányosítunk.

Tanács a Javaban nem kezdő és türelmetlen Olvasóknak

Ha a kedves Olvasó azonnal meg akarja válaszolni az iménti kérdést és ennek megfelelően azonnal

telepíteni akarja a JDK-t, azaz a Java fejlesztői környezetet a gépére, akkor A Java telepítése gépünkre

című pontban talál segítséget.

1.18. példa - Galton deszka kísérlet

Látványos feladat olyan grafikus szimulációs programot írni, mely demonstrálja a például a [RÉNYI VALSÉG

KÖNYV] könyvben leírt Galton deszkás kísérletet. A függelékben ezt a Galton deszka kísérlet programja című

pontban mi is megtesszük majd, most csupán a kísérletet ismertetjük és egy előzetes pillantást vetünk a

programunkkal szimulált két különböző Galton utáni kísérleti elrendezésre.

A kísérleti elrendezésben deszkasorokat készítünk. Az első sorba egy deszkát, a másodikba kettőt, a harmadikba

hármat, s így tovább teszünk. A deszkákat pontosan úgy helyezzük el, hogy a felülről ráeső golyó 50-50

százalék eséllyel essen tovább a deszka bal vagy jobb oldalán, az alatta lévő következő deszka sorra. A kísérlet

során arra vagyunk kíváncsiak, hogy a berendezésbe beejtett golyók a sorokon átesve hová érkeznek?

Page 57:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

29 Created by XMLmind XSL-FO Converter.

A zöld oszlopokkal kirajzolt hisztogram mutatja, hogy az adott helyre mennyi golyó esett a kísérlet végrehajtása

során. Mi most empirikusan mutattuk meg, a hivatkozott [RÉNYI VALSÉG KÖNYV] könyvben pedig

teoretikusan mutatja meg a szerző, hogy határátmenetben, azaz ha végtelen sok golyót ejtenénk be a kísérleti

elrendezésbe, akkor a kialakuló hisztogram alakja a híres Gauss-féle harang görbe alakját rajzolná ki. A

véletlennel kapcsolatos jelenségeknél a harang görbe megjelenése a normális eloszlás felbukkanására utal.

A normális eloszlásnál jegyezhetjük meg, hogy matematika szakos hallgatóknak/tanároknak remek OO

bevezető példa lehet egy alább itt is bemutatásra kerülő polártranszformációs normális generátor megírása

Javaban. Miért? Mert programjuk megírása után a JDK fent említett src.zip állományában a

java/util/Random.java forrásban megnézhetik, hogy magában a JDK-ban is hasonlóan oldották meg a

feladatot a Sun programozói! Ezért ennek a generátornak a megírását magunk is megtesszük most a következő

pontban.

A [VÉLETLEN KÖNYV] 98. oldala vagy a [KNUTH 2. KÖNYV] 128. oldala alapján készítsük el a módosított

polármódszeres algoritmust Javaban, avagy - Javaban kezdőként - csupán figyeljük meg az elkészítését! Az

algoritmus matematikai háttere most számunkra lényegtelen, fontos viszont az eljárás azon jellemzője, hogy egy

számítási lépés két normális eloszlású számot állít elő, tehát minden páratlanadik meghíváskor nem kell

számolnunk, csupán az előző lépés másik számát visszaadnunk. Hogy páros vagy páratlan lépésben hívtuk-e

meg a megfelelő számítást elvégző következő() függvényt, a nincsTárolt logikai változóval jelöljük. Igaz

értéke azt jelenti, hogy tárolt lebegőpontos változóban el van tárolva a visszaadandó szám. (Jelen

tárgyalásunkban a következő() függvényben implementált matematikai eljárás, a módosított polármódszer

további tulajdonságai teljesen érdektelenek.)

public class PolárGenerátor {

boolean nincsTárolt = true;

double tárolt;

Page 58:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

30 Created by XMLmind XSL-FO Converter.

public PolárGenerátor() {

nincsTárolt = true;

}

public double következő() {

if(nincsTárolt) {

double u1, u2, v1, v2, w;

do {

u1 = Math.random();

u2 = Math.random();

v1 = 2*u1 - 1;

v2 = 2*u2 - 1;

w = v1*v1 + v2*v2;

} while(w > 1);

double r = Math.sqrt((-2*Math.log(w))/w);

tárolt = r*v2;

nincsTárolt = !nincsTárolt;

return r*v1;

} else {

nincsTárolt = !nincsTárolt;

return tárolt;

}

}

public static void main(String[] args) {

PolárGenerátor g = new PolárGenerátor();

for(int i=0; i<10; ++i)

System.out.println(g.következő());

}

}

Most osztályunkat összevethetjük a JDK fent említett src.zip állományában a java/util/Random.java

forrásban implementált megoldással, ahol a nextGaussian() függvény törzsét és a kapcsolódó (felette

definiált) haveNextNextGaussian és nextNextGaussian példánytagokat tanulmányozzuk!

Ha az Olvasó a programot lefordítaná és futtatná, akkor például a következő kimenetet kaphatná:

-0.7302435745349951

0.3398973333782606

-0.1745186408410782

-0.6733291138289893

-0.7141255333702377

0.8105205642319349

-0.2166963741203095

-0.6100935726625737

-0.0061257158500475665

0.09213084665478943

Page 59:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

31 Created by XMLmind XSL-FO Converter.

Figyelmeztetés a Javaban kezdő Olvasóknak

A következő feladat forrásában a Javaban kezdő kedves Olvasóknak elég a /** és */ közötti

dokumentációs és a /* */ közötti, vagy a // mögötti megjegyzéseket átolvasnia.

1.19. példa - Hisztogram feladat

Az, hogy a generált számok normális eloszlásúak, szemléletesen annyit tesz, hogy a számokból épített

hisztogram a haranggörbe alakjához hasonlatos. A hisztogram oszlopok olyan rendszere, ahol egy oszlop

magassága azt mutatja, hogy az oszlop szélességébe a vizsgált számok közül mennyi esett. Például az imént

generált 10 szám a -1, 0 és a 0, 1 intervallumok felett elhelyezkedő egységnyi széles két doboz között úgy oszlik

meg, hogy az elsőbe 7, a másodikba 3 szám esik, az ennek megfelelő hisztogram grafikonja a következő alakú.

A következő ábrán 100000 generált normális szám egy hisztogramját mutatjuk be.

Vessünk egy pillantást a kézikönyvnek arra az osztályára, mellyel a szereplő hisztogram képeket készítettük,

próbáljuk meg végigolvasni a forráskódot! De közben vigyázzunk, hogy most még ne bonyolódjunk a részletek

boncolgatásába! Szorítkozzunk inkább a dokumentációs megjegyzések értelmezésére, semmint az implementált

függvények törzsének részletes vizsgálatára.

public class Hisztogram {

/** A feldolgozandó értékek alsó határa. */

protected double min;

/** A feldolgozandó értékek felső határa. */

protected double max;

/** A hisztogram dobozai. */

protected int [] dobozok;

/**

* Létrehoz egy <code>Hisztogram</code> objektumot.

*

Page 60:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

32 Created by XMLmind XSL-FO Converter.

* @param min a feldolgozandó értékek alsó határa.

* @param max a feldolgozandó értékek felső határa.

* @param méret a hisztogram dobozainak száma.

*/

public Hisztogram(double min, double max, int méret) {

// Példánytagok aktualizálása:

this.min = min;

this.max = max;

// Létrehozzuk a megfelelő méretű hisztogrammot.

dobozok = new int[méret];

// Paranoiás stílus: végigzongorázzuk a tömb elemeit

for(int i=0; i<dobozok.length; ++i)

// és nullázzuk a hisztogram dobozainak tartalmat:

dobozok[i] = 0;

}

/**

* A kapott érték melyik dobozba esik?

*

* <pre>

* 0. 1. dobozok.length-1

* ---------|-----|-----|-----|-----|-----|-----|-----------

* min | max

* érték

* </pre>

*

* @param érték a hisztogram megfelelő dobozába

*/

public void betesz(double érték) {

++dobozok[(int)((érték-min)/((max-min)/dobozok.length))];

}

/**

* Kirajzolja a hisztogrammot.

*

* @return BufferedImage a hisztogram grafikonjának képe.

*/

public java.awt.image.BufferedImage grafikon() {

int képSzélesség = 300;

int dobozSzélesség = 300/dobozok.length;

int maxDobozÉrték = 0;

for(int i=0; i<dobozok.length; ++i)

if(dobozok[i] > maxDobozÉrték)

maxDobozÉrték = dobozok[i];

int képMagasság = 300;

java.awt.image.BufferedImage grafikon =

new java.awt.image.BufferedImage(

képSzélesség,

képMagasság,

java.awt.image.BufferedImage.TYPE_INT_RGB

);

java.awt.Graphics g = grafikon.getGraphics();

// Kép törlése: fehérrel

g.setColor(java.awt.Color.WHITE);

// lemeszelünk egy képernyőnyi méretű téglalapot:

g.fillRect(0, 0, grafikon.getWidth(), grafikon.getHeight());

for(int i=0; i<dobozok.length; ++i) {

// Egy doboz kirajzolása

g.setColor(java.awt.Color.YELLOW);

if(maxDobozÉrték/képMagasság != 0)

g.fillRect(i*dobozSzélesség,

képMagasság-dobozok[i]/(maxDobozÉrték/képMagasság),

képSzélesség/dobozok.length,

dobozok[i]/(maxDobozÉrték/képMagasság));

Page 61:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

33 Created by XMLmind XSL-FO Converter.

else

g.fillRect(i*dobozSzélesség,

képMagasság-dobozok[i]*(képMagasság/maxDobozÉrték),

képSzélesség/dobozok.length,

dobozok[i]*(képMagasság/maxDobozÉrték));

// Esztétikus a doboz bekeretezése

g.setColor(java.awt.Color.LIGHT_GRAY);

if(maxDobozÉrték/képMagasság != 0)

g.drawRect(i*dobozSzélesség,

képMagasság-dobozok[i]/(maxDobozÉrték/képMagasság),

képSzélesség/dobozok.length,

dobozok[i]/(maxDobozÉrték/képMagasság));

else

g.drawRect(i*dobozSzélesség,

képMagasság-dobozok[i]*(képMagasság/maxDobozÉrték),

képSzélesség/dobozok.length,

dobozok[i]*(képMagasság/maxDobozÉrték));

}

g.dispose();

return grafikon;

}

/**

* Példányosít egy hisztogram objektumot, akinek továbbítja a

* bemenetről olvasott számokat, végül kimenti a hisztogramot.

*/

public static void main(String[] args) throws Exception {

// Feltesszük, hogy korábban már megállapítottuk

// a bejövő számok minimumát és maximumát, ezek

// a most csak becsült -4.5, 4.5

Hisztogram h = new Hisztogram(-4.5, 4.5, 40);

java.io.BufferedReader inputCsatorna =

new java.io.BufferedReader(

new java.io.InputStreamReader(System.in));

String sor = null;

// Olvassuk a bemenetet, amíg tudjuk

while((sor = inputCsatorna.readLine()) != null)

// az olvasott számot továbbitjuk a

// hisztogram objektumnak:

h.betesz(Double.parseDouble(sor));

// A számok feldolgozása után egy képállományba írjuk

// ki az elkészített hisztorgramm grafikonját:

javax.imageio.ImageIO.write(h.grafikon(), "png",

new java.io.File("hisztogram.png"));

}

}

Ha az Olvasó módosítaná az előző pont PolárGenerátor osztályának indító main() módszerében a ciklust,

hogy 100000 normálist állítson elő, s az osztály fordítása után kimenetét a 100000.normális állományba

irányítaná, amit pedig inputként irányítana a futtatott Hisztogram objektumba:

C:\...> java PolárGenerátor >100000.normális

C:\...> java Hisztogram < 100000.normális

akkor a példa bevezetésében mutatott ábra haranggörbe hisztogramját kapná a program által generált a

hisztogram.png állományban.

Feladat a Javaban nem kezdő Olvasóknak

Page 62:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

34 Created by XMLmind XSL-FO Converter.

Az iménti Hisztogram osztály betesz(double érték) módszerét módosítsuk úgy, hogy dobjon egy

RosszÉrtékException saját kivétel objektumot, ha az aktuális paraméterként kapott érték kisebb,

mint a hisztogram min vagy nagyobb, mint a max értéke. A kivétel objektumba üzenetként csomagoljuk

be, hogy éppen melyik szituáció következett be.

A Javaban kezdő Olvasó akkor készítse el ezt a feladatot, ha a kapcsolódó kivételkezelési bevezető

részeket már feldolgozta!

1.20. példa - Fej vagy írás varázslat

A [VÉLETLEN VÉLETLEN] könyvben javasolt játék a véletlennel a következő: a tanulók egy részétől azt

kérjük, hogy írjanak papírra egy 200 elemből álló 0, 1 sorozatot úgy, hogy a sorozat minden tagját egy érme

feldobásával állítják elő. A tanulók másik csoportja ugyancsak 200 elemű 0, 1 sorozatot készít, de ők fejből

írják. S csodák csodája a tanár megtekintve a sorozatokat - kis hibával - megmondja, hogy mely sorozatok

alapulnak valódi pénzfeldobáson. Módszere, hogy azokról a sorozatokról mondja ezt, melyekben van egymást

követő legalább 6 darab nulla vagy egy, mert a fejből generáló tanuló ennyi azonos jegyet egymás után már nem

tekint véletlennek.

Íme egy példa a pénzérmével való dobás alapján képzett sorozatra:

11110010010010111101001110010001110011101100111100

00110011001101110111000101001111110001001001001100

10100111011100100111000100000011101101001000010011

11011000011111000101101010001001111010010011000010

S egy másik a fejből véletlennek generált/titulált alapon képzett sorozatra:

01110010110100110101000010110010110100101011110101

10011001010101101001001000110101010100100101101001

11001100011001111011011110100010110010111010100101

10000110101110110100001101010110111010101101010011

Az eddigi és még néhány elkövetkező, algoritmuselméleti ihletésű pontokat a „Nem fontos a pontosság, csak azt

tudjuk, hogyan lehet elérni” - ezt a tanácsot adta számtalanszor egyetemünk logika vagy mesterséges

intelligencia kurzusain hallgatóinak Dragálin Albert professzor úr - gondolat jegyében bontottuk ki. Azoknak,

akik az érintett alapfogalmak teljesen pontos tárgyalását keresik a [ALGORITMUSOK KÖNYV] vagy a

[LOVÁSZ KÖNYV] könyveket ajánljuk.

1.1.1.5. Tényleg véletlen 0, 1 sorozatok

Vizsgálódjunk kicsit tovább az 1000 bit hosszúságú bináris szavak között! Egy bites szóból 2 van, a 0 és az 1.

Két bites szóból 2x2 darab, a 00, 01, 10, 11. Három bites szóból 2x2x2, 28, négy bitesből 2x2x2x2, 24, ...

láthatóan végül 1000 bites szóból 21000 darab van; ez jó sok, jóval több, mint búzaszem a sakktáblán.

Vajon mennyi 1000 bites szó Chaitin-Kolmogorov bonyolultsága kisebb 990-nél és mennyié nagyobb?

A 990-nél kisebb bonyolultságúak, a korábban kimondott definíciónk alapján, azok a szavak lehetnek, melyeket

990-nél rövidebb bemenetből ki tudunk számítani egy univerzális Turing géppel

ahol a T algoritmus és i inputja együttes hossza kisebb 990-

nél. Könnyen, erősen felülről tudjuk becsülni az ilyen 990 bitnél rövidebb univerzális Turing gép bemeneteket.

Mert 990-nél rövidebb bitminta összesen lehet 2 darab 1 bites + 4 darab 2 bites + 8 darab 3 bites + ... + 2989

Page 63:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

35 Created by XMLmind XSL-FO Converter.

darab 989 bites = 2990 -1 darab összesen. A -1 bemenetet még nagylelkűen hozzácsapva, számoljunk 2990

darabbal.

Tehát maximum 2990 darab szó lehet 990-nél egyszerűbb és ennek megfelelően 21000 / 2990 = 1024, azaz körülbelül

maximum 1000-szer több olyan szó van, ami pedig 990-nél bonyolultabb. Összefoglalva az 1000 bit hosszúságú

bináris szavak minimum 99.9 százaléka 990-nél nagyobb bonyolultságú!

Ugyanezzel a gondolatmenettel láthatnánk be, hogy az 1000 bit hosszúságú szavak között a 999-nél egyszerűbb

szavak maximum 21000-1-en vannak, tehát legalább egy szónak lennie kell, ami bonyolultsága >= 1000.

1.1.1.5.1. Végtelen és véletlen 0, 1 sorozatok

Ebben a pontban megmutatjuk, hogy a megismert Chaitin-Kolmogorov bonyolultság fogalmunkkal miként

tudjuk úgy definiálni a végtelen véletlen sorozat fogalmát, hogy intuíciónk közben meg ne hökkenne. Mert meg

lenne hökkenve? Döntse el önmaga a kedves Olvasó, gondoljon arra, hogy betesszük egy urnába az összes 1000

bit hosszúságú 0, 1 sorozatot. Ekkor a korábbi A Chaitin-Kolmogorov bonyolultság című pont második sorozatát

kihúzni ugyanolyan valószínű, mint az ötödiket, mert mindkét esetben arról van szó, hogy a kihúzott sorozat

bitjeinek az egyik esetben pont annak kell lenni, mint a második vagy a másik esetben pont annak, mint az

ötödik sorozatban a biteknek. Ez a nézőpont szemléletünkkel jól megfér. De mindemellett az ötödik sorozatot

természetesen véletlennek tekintjük, míg az másodikról lerí, hogy teljesen triviálisan szabályos, hogy is lehetne

hát véletlen! - mondja a szemléletünk. A két szemléletében ellentétes megközelítés szülheti meg

meghökkenésünket.

1.21. példa - Egy szabályos sorozat

Készítsünk egy olyan programot, ami bemenetén kapott n számig kiírja a A Chaitin-Kolmogorov bonyolultság

című pont második sorozatát!

public class BinárisSorozat {

public static void main(String[] args) {

int db = 0;

try {

db = Integer.parseInt(args[0]);

} catch(NumberFormatException e) {

db = 100;

}

Page 64:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

36 Created by XMLmind XSL-FO Converter.

for(int i=0; i<db; ++i)

System.out.print(i%2);

}

}

A program a bemenő n számot az első parancssor argumentumaként args[0] szöveges tömbelemben várja,

majd ebből az Integer osztály statikus parseInt() módszerével számot csinál, majd e számig felváltva 0 és 1

jegyeket ír ki. Ha a kedves Olvasó lefordítaná és futtatná a programot, akkor a következőt kapná:

[norbi@niobe ~]$ javac BinárisSorozat.java

[norbi@niobe ~]$ java BinárisSorozat 1

0

A program 185 betű, az inputja 1 betű, összesen 186 betű. Ha most a kedves Olvasó az n=10 értékkel futtatná,

akkor a következő kimenethez jutna:

[norbi@niobe ~]$ java BinárisSorozat 10

0101010101

A program 185 betű, az inputja 2 betű, összesen 187 betű. Az n=100 értékkel indítva:

[norbi@niobe ~]$ java BinárisSorozat 100

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101

A program 185 betű, az inputja 3 betű, összesen 188 betű. Ezerrel indítva:

[norbi@niobe ~]$ java BinárisSorozat 1000

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

01010101010101010101010101010101010101010101010101010101010101010101010101010101

0101010101010101010101010101010101010101010101010101010101010101010101010101010

10101010101010101010101010101010101010101

A program 185 betű, az inputja 4 betű, ez összesen 189 betű.

Összegezzük eredményeinket!

1.3. táblázat - A 01-et ismétlő bináris sorozat kezdőrészeinek vizsgálata.

Page 65:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

37 Created by XMLmind XSL-FO Converter.

HOSSZ BONYOLULTSÁG A KETTŐ HÁNYADOSA

1 186 186

10 187 18.7

100 188 1.88

1000 189 0.189

... ... ...

10000000 193 0.00000193

... ... ...

Jól láthatóan minél hosszabb a generált sorozat, annál inkább közel kerül a nullához a hányados, azaz a

hányados nullához tart, ha a sorozat n hossza a végtelenbe. Az iménti empirikus megalapozás után ebben

biztosak lehetünk, hiszen a bonyolultság, a program és inputja együttes hossza általánosan írva 185 + lg(n) + 1,

mert a 185 karakteres programot ebben a formában futtattuk:

[norbi@niobe ~]$ java BinárisSorozat n

ahol a parancssorban átadott n input szám leírásához lg(n) + 1 számjegy szükséges. A (185 + lg(n) + 1)/n pedig

zérushoz tart, az n tart végtelen esetén.

Ez azt jelenti, hogy a vizsgált sorozat hosszának növelésével a sorozat bonyolultsága nem tud lépést tartani.

Egy végtelen sorozatot akkor nevezünk véletlennek, ha a rá vonatkozó fenti hányados nem zérushoz, hanem az

egyhez tart. Tehát, ha a vizsgált sorozat hosszának növelésével egyforma mértékben növekedik a sorozat

bonyolultsága is!

Példánkból általánosíthatunk is: ha van olyan algoritmus, ami az n szám inputtal előállítja a sorozat első n

betűjét, akkor a sorozat nem lehet véletlen. Mert például H-val jelölve ennek az algoritmusnak a hosszát, a (H +

lg(n) +1)/n hányados ugyanúgy, mint fenti példánkban, a nullához fog tartani, ha n tart a végtelenhez.

1.22. példa - Véletlenszám generátorok

Az előző bekezdés általánosításának tükrében gondoljuk át, véletlen-e a következő program által generált

véletlen sorozat?

public class PszeudoVéletlen {

public static void main(String[] args) {

java.util.Random generátor = new java.util.Random();

for(;;)

System.out.print(generátor.nextInt(2));

}

}

Page 66:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

38 Created by XMLmind XSL-FO Converter.

Természetesen nem, mert az egy korábbi példában szereplő VéletlenSorozat osztályt úgy módosítva, hogy

nem 1000, hanem parancssorban kapott n számig nyomtat és feltéve, hogy a java.util.Random generátor

például éppen a 42-vel inicializálódott a jelen paraméter nélküli konstruktor hívás mögött, elő tudjuk állítani

éppen ennek a sorozatnak a kezdő részeit. S a fentiekhez hasonló számítással megkapjuk, hogy a vizsgálandó

hányados a nullához tart.

1.23. példa - Egy másik szabályos sorozat

Vizsgáljuk meg, hogy véletlen sorozat-e a A Chaitin-Kolmogorov bonyolultság című pont negyedik sorozata

mintájára képzett végtelen sorozat.

1.24. példa - Egy nem véletlen, de bonyolultabb sorozat

Próbáljunk meg egy olyan sorozatot „készíteni”, melyre a vizsgált hányados nem nullához tart! Ennek a célnak

megfelelően a következő FéligVéletlen osztályt úgy alakítottuk ki, hogy a sorozat felét, a második karakterét

is inputként kéri be. S a felhasználót arra kérjük, a program kérésére 0 vagy 1 jegyet írjon be, annak

megfelelően, hogy közben feldobott érméje fej vagy írás-e. Továbbá arra is figyelni kell, hogy a mindig

ugyanazt a kezdő részt adjuk be a program kérésére, azaz az Olvasónak a feldobott érme eredményeket meg kell

jegyeznie, s mindig csak az új pozícióra kell újra dobni.

public class FéligVéletlen {

public static void main(String[] args) throws Exception {

int db = Integer.parseInt(args[0]);

int [] sorozat = new int [db];

int fele = db/2;

java.io.BufferedReader inputCsatorna =

new java.io.BufferedReader(

new java.io.InputStreamReader(System.in));

for(int i=0; i<db; ++i)

if(i%2 == 1){

System.out.print("Az "+i+". tag: ");

String sor = inputCsatorna.readLine();

sorozat[i] = Integer.parseInt(sor);

} else

sorozat[i] = 0;

System.out.println();

for(int i=0; i<db; ++i)

System.out.print(sorozat[i]);

}

}

A program 469 betű hosszú.

Ha a kedves Olvasó lefordítaná és futtatva a programot elvégezne néhány próba futtatást, akkor az alábbiakat

kaphatná:

C:\...> javac FéligVéletlen.java

C:\...> java FéligVéletlen 1

0

Page 67:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

39 Created by XMLmind XSL-FO Converter.

C:\...> java FéligVéletlen 2

Az 1. tag: 1

01

C:\...> java FéligVéletlen 3

Az 1. tag: 1

010

C:\...> java FéligVéletlen 4

Az 1. tag: 1

Az 3. tag: 0

0100

C:\...> java FéligVéletlen 10

Az 1. tag: 1

Az 3. tag: 0

Az 5. tag: 1

Az 7. tag: 1

Az 9. tag: 0

0100010100

Mit mondhatunk a vizsgált sorozat véletlenségéről? Összegezzük eredményeinket!

1.4. táblázat - A félig véletlen bináris sorozat kezdőrészeinek vizsgálata.

HOSSZ BONYOLULTSÁG A KETTŐ HÁNYADOSA

1 469 469

10 469+10+2 48.1

100 469+50+3 5.22

1000 469+500+4 0.973

10000 469+5000+5 0.5474

... ... ...

10000000 469+5000000+8 0.5000477

... ... ...

láthatóan 0.5-höz tartunk és valóban a (469 + n/2 + lg(n) + 1)/n kifejezés, az n tart a végtelenhez határátmenet

esetén az 1/2-hez tart.

1.1.1.6. A megállási Omega valószínűség

„ÁDÁM

Úgyis nem ront-e majd el a halál?

A FÖLD SZELLEMÉNEK SZAVA

A vén hazugság e hiú szavát ne mondd,

ne mondd itt a szellemvilágban.

Page 68:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

40 Created by XMLmind XSL-FO Converter.

Egész természet átborzadna tőle.

Szentelt pecsét az, feltartá az Úr

Magának. A tudás almája sem

Törhette azt fel.”

—Madách Imre

Korábban már láttuk (programoztuk), hogy Turing gépeinket megadhatjuk csupán a 0 és az 1 jegyek leírásával.

Tegyük fel, hogy a világon összesen 10 Turing gép van és ezeket a következő biráris sorozatokkal „kódoltuk”.

Ezek a kódok mindamellett, hogy csak szimbolikusak - mivel ilyen kevés bittel természetesen nem menne a

lekódolásuk - nagyon speciálisak, mert figyeljük meg, hogy egyik kódszó sem kezdődik egy másik kódszóval.

Az ilyen kódolást nevezzük prefixnek. Ami a programozóknak egyébként természetes, mert a programok prefix

kódok, hiszen egyik program sem kezdődik egy másikkal:

Ha a kedves Olvasó megpróbálna egy ilyen felépítésű

public class Program {

}

}

programot lefordítani, akkor az alábbi fordítási hibát kapná:

Page 69:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

41 Created by XMLmind XSL-FO Converter.

C:\...> javac Program.java

Program.java:5: class, interface, or enum expected

}

^

Program.java:6: reached end of file while parsing

^

2 errors

Tegyük fel továbbá, hogy a 10 gép közül az alábbi 4 megáll, 6 gép viszont nem áll meg, azaz végtelen ciklusba

esik.

1.1.1.6.1. Chaitin gépek

A Turing gépek prefix kódolása azért fontos számunkra, mert a Kraft-Fánó-McMillan egyenlőtlenségből

[DEMETROVICS KÖNYV] tudjuk, hogy prefix kódokra teljesül. A hivatkozott egyenlőtlenség pontosan azt

fejezi ki, hogy a kódszó1, kódszó2, ... kódszón n kódszóból álló prefix kódra a

2|kódszó1

| + 2|kódszó2

| + ... + 2|kódszón

| <= 1 teljesül.

A mi esetünkben a kód a 01, 000, 001, 101, 100, 1100, 1101, 1110, 11110, 11111, az egyenlőtlenségbeli összeg

értéke pedig

2-2 +4*2-3 +3*2-4 +2*2-5 = 1

Tehát az egyenlőtlenség - mint ahogyan tudtuk is - valóban nem sérül példánkban sem. Mivel az összeg értéke

mindig a 0 és az 1 közé esik, ezért valószínűségnek tekinthetjük.

A Turing gépek megállási valószínűségének nevezzük azt a fenti típusú összeget, amelyben az összegzést a

megálló gépek kódjára végezzük el. Elképzelt, 10 gépes világunkban tehát a megállás valószínűsége

2*2-3 +2-4 +2-5 = 0,34375

Page 70:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

42 Created by XMLmind XSL-FO Converter.

A prefix Turing gépek (Chaitin gépek) világában ezt a megállási valószínűséget Omegának nevezzük.

([CHAITIN OMEGA], [JAVA PROG és OMEGA] és lásd még az irodalomjegyzék számos Omegával

kapcsolatos bejegyzését.)

1.25. példa - A Chaitin-féle Omega konstans ismeretében meg tudnánk oldani a

megállási problémát!

A [PARADOXON KÖNYV] könyvben bemutatott kapcsolódó gondolatmenet alapján ebben a példában

bemutatjuk, hogy Omega ismeretében meg tudnánk oldani a megállási problémát.

Vizsgáljunk egy tetszőlegesen megválasztott H bit hosszúságú programot! Az alábbi táblázat segítségével

megmutatjuk, hogy a Chaitin-féle megállási Omega konstans ismeretében meg tudnánk mondani, hogy

tetszőleges program megáll-e, azaz meg tudnánk oldani a megállási problémát, ami lehetetlen! Tehát nem

ismerhetjük meg a konstanst, az Omegának őriznie kell titkait az ember előtt...

A vízszintes tengelyen a programok szerepelnek hosszuk szerint, a függőlegesen a futási idő. Minden

időpillanatban elkezdjük futtatni az egy bittel hosszabb programokat. A kísérlet közben megálló programok 2 -

hosszuk értékkel növelik meg az Omega értékét, egészen pontosan OMEGAN jelölje az N. időpillanatig megálló

vizsgált, azaz maximum N hosszú gépek hosszával növelt összeget. Nyilván OMEGAN <= OMEGAN+1, ami

alapján menjünk addig előre az idővel, amikor az OMEGAN monoton közelítés már 1/2H értéknél közelebb van

az OMEGA határértékhez. Következzen ez be például a t=M időpillanatban. Tehát ekkor az OMEGA-

OMEGAM < 2-H. És most jön a trükk: ha a vizsgált H hosszú program eddig nem állt meg, akkor (most már, azaz

véges sok lépés után) tudjuk, hogy már nem is fog megállni, mert ha megállna, akkor 2-H értékkel növelné meg

az Omega approximációját, azaz ebben a megállás valamikori időpillanatában OMEGAvalamikori >= OMEGAM + 2-H

> OMEGA - 2-H + 2-H = OMEGA. Hoppá! Döbbenetes, nem igaz? Jó kis ellentmondás, miszerint az alulról

közelítő OMEGAvalamikori átlépte az OMEGA értéket!

Page 71:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

43 Created by XMLmind XSL-FO Converter.

Az Omega számnak számos további érdekes tulajdonsága is van, például ha a tizedes kifejtését egy

számjegyekből álló betűsorozatnak tekintjük, akkor ez a sorozat véletlen. Szemben például a Pi konstanssal, ami

ugyan nem gyöke egyetlen egyenletnek sem, de végtelen sorokkal tömören leírható, a Pi tizedes kifejtésének

bármely jegyei tetszőleges pontossággal meghatározhatók.

1.26. példa - A Pi közelítése

Az alábbi példa kapcsán javasoljuk elolvasni a [KAPCSOLAT REGÉNY] regényt, mely végén a Pi jegyeivel

színezett történet erős érzelmi motivációt adhat. A hivatkozott [KAPCSOLAT MOZI] filmet is bátran ajánljuk

az Olvasónak, de ebből a feldolgozásból sajnos a könyv kapcsán említett Pi konstanssal kapcsolatos részek

teljesen hiányoznak.

A Pi pontos értékével való ismerkedést kezdjük a Gregory-Leibniz formula bemutatásával.

public class Pi {

double közelítőÉrték;

public Pi(long n) {

double p = 0;

// Gregory-Leibniz formula:

// Pi/4 = 1 - 1/3 + 1/5 - 1/7 + ... + (1-(i%2)*2)/(2*i+1) + ...

for(long i=0; i<n; ++i)

p += (double)(1-(i%2)*2)/(2*i+1);

közelítőÉrték = 4*p;

}

public static void main(String[] args) {

long n = 1;

while(true) {

n *= 10;

Pi pi = new Pi(n);

System.out.println("pi ~ Pi(n) = " + pi.közelítőÉrték

+ ", n = " + n

+ ", Math.PI/Pi(n) = "

+ (Math.PI / pi.közelítőÉrték));

}

}

}

Ha az Olvasó fordítaná és futtatná a programot, akkor a következő kimenetét kapná:

[norbi@niobe ~]$ javac Pi.java

[norbi@niobe ~]$ java Pi

pi ~ Pi(n) = 3.0418396189294032, n = 10, Math.PI/Pi(n) = 1.0327936535639899

pi ~ Pi(n) = 3.1315929035585537, n = 100, Math.PI/Pi(n) = 1.0031931832582315

pi ~ Pi(n) = 3.140592653839794, n = 1000, Math.PI/Pi(n) = 1.0003184111600008

pi ~ Pi(n) = 3.1414926535900345, n = 10000, Math.PI/Pi(n) = 1.0000318320017856

pi ~ Pi(n) = 3.1415826535897198, n = 100000, Math.PI/Pi(n) = 1.0000031831090173

pi ~ Pi(n) = 3.1415916535897743, n = 1000000, Math.PI/Pi(n) = 1.0000003183099935

pi ~ Pi(n) = 3.1415925535897915, n = 10000000, Math.PI/Pi(n) = 1.00000003183099

pi ~ Pi(n) = 3.141592643589326, n = 100000000, Math.PI/Pi(n) = 1.0000000031832477

pi ~ Pi(n) = 3.1415926525880504, n = 1000000000, Math.PI/Pi(n) = 1.0000000003188645

pi ~ Pi(n) = 3.141592653488346, n = 10000000000, Math.PI/Pi(n) = 1.0000000000322917

pi ~ Pi(n) = 3.141592653578537, n = 100000000000, Math.PI/Pi(n) = 1.000000000003583

Page 72:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

44 Created by XMLmind XSL-FO Converter.

egészen addig, amíg egy Ctrl+c nyomásával meg nem állítja a végtelen ciklusban számoló programot.

(Ameddig mi a program futását engedtük, a Pi(n) = 3.141592653578537 10 tizedesig pontos eredményig

jutottunk.)

A képzeletbeli futtatás előtt próbálja elképzelni, megbecsülni az egyre növekvő n = n * 10 mellett a Pi(long

n) konstruktor időbonyolultságát, azaz futási idejét, majd vesse össze elképzeléseit a futtatás során szerzett

„izometrikus” tapasztalataival!

A már Javaban nem kezdő Olvasó első javítási ötlete bizonyára az, hogy a közelítéshez nem készítene külön Pi

objektumokat és azok Pi(long n) konstruktorában nem kezdené mindig elölről az összegzést, hanem inkább

az alábbi módon szervezné át az osztály kódját.

public class Pi {

double közelítőÉrték;

long meddigSzámoltuk;

public Pi() {

közelítőÉrték = 0;

meddigSzámoltuk = 0;

}

public double közelítés(long n) {

double p = 0;

// Gregory-Leibniz formula:

// Pi/4 = 1 - 1/3 + 1/5 - 1/7 + ... + (1-(i%2)*2)/(2*i+1) + ...

for(long i=meddigSzámoltuk; i<n; ++i)

p += (double)(1-(i%2)*2)/(2*i+1);

if(n > meddigSzámoltuk) {

közelítőÉrték = 4*(közelítőÉrték/4 + p);

meddigSzámoltuk = n;

}

return közelítőÉrték;

}

public static void main(String[] args) {

long n = 1;

Pi pi = new Pi();

while(true) {

n *= 10;

System.out.println("pi ~ Pi(n) = " + pi.közelítés(n)

+ ", n = " + n

+ ", Math.PI/Pi(n) = "

+ (Math.PI / pi.közelítés(n)));

}

}

}

A Pi jegyeinek nyomában

Ha az Olvasó futtatná a most vázolt programot, akkor tapasztalhatná, hogy az említett [KAPCSOLAT

REGÉNY] olvasásának befejezésekor keletkezett lelkesítő feszültségét ezekkel bizony nem tudta

levezetni-átvezetni a Pi jegyeinek önálló keresésében. Ha a kedves Olvasó valóban így érezne, akkor A

Pi jegyeinek nyomában matematikai témájú programozási mellékletünket és például a [PI KÖNYV]

könyvet ajánljuk figyelmébe. Itt és most csak az iménti Pi osztályunk két kiterjesztését mutatjuk be, a

RamanujanPi osztályban a hivatkozott [PI KÖNYV] alapján a Ramanujantól származó, még a

Page 73:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

45 Created by XMLmind XSL-FO Converter.

ChudnovskyPi osztályban, ugyancsak a hivatkozott [PI KÖNYV] alapján a Chudnovsky-féle

Ramanujan típusú formulát mutatjuk be.

1.27. példa - A Ramanujan és a Chudnovsky közelítő összegek formulái

public class RamanujanPi extends Pi {

double pTár = 0.0;

public double közelítés(long n) {

double p = 0.0;

double sz = (2.0 * Math.sqrt(2.0)) / 9801.0;

for(long k=meddigSzámoltuk; k<n; ++k)

p += (f(4*k)*(1103.0 + 26390.0*k))

/ (Math.pow(f(k), 4.0) * Math.pow(396.0, 4.0*k));

if(n > meddigSzámoltuk) {

pTár += p;

közelítőÉrték = 1.0/(sz*pTár);

meddigSzámoltuk = n;

}

return közelítőÉrték;

}

/** k!, azaz k faktoriális kistámítása */

public double f(long k) {

double f = 1.0;

for(long l=1; l<k; ++l)

f *= l;

return f;

}

public static void main(String[] args) {

RamanujanPi pi = new RamanujanPi();

for(int n=2; n<5; ++n) {

System.out.println("pi ~ Pi(n) = " + pi.közelítés(n)

+ ", n = " + n

+ ", Math.PI/Pi(n) = "

+ (Math.PI / pi.közelítés(n)));

}

}

}

Ha az Olvasó fordítaná és futtatná a programot, akkor a következő kimenetét láthatná:

[norbi@niobe ~]$ javac RamanujanPi.java

[norbi@niobe ~]$ java RamanujanPi

pi ~ Pi(n) = 3.141592710907427, n = 2, Math.PI/Pi(n) = 0.9999999817552309

pi ~ Pi(n) = 3.1415927109074255, n = 3, Math.PI/Pi(n) = 0.9999999817552313

pi ~ Pi(n) = 3.1415927109074255, n = 4, Math.PI/Pi(n) = 0.9999999817552313

Érdekességként megjegyezhetjük, hogy ugyanaz az R. W. Gosper, akinek „sikló ágyú” nevű sejtautomata

élőlényét bemutatjuk a Az R. W. Gosper-féle sikló ágyú élőlény bemutatása [306] című táblázatban, 1985-ben

erre a formulára alapozva, 17.526.200 tizedesjegyig határozta meg a Pi értékét.

Page 74:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

46 Created by XMLmind XSL-FO Converter.

Mivel mi csupán a 64 bites lebegőpontos aritmetikát használjuk, csak a fent idézett számítást tudjuk futtatni,

azaz a Pi(n) = 3.141592710907427 6 tizedesig pontos eredményig jutottunk.

public class ChudnovskyPi extends RamanujanPi {

public double közelítés(long n) {

double p = 0.0;

for(long k=meddigSzámoltuk; k<n; ++k)

p += ((1-(k%2)*2)*f(6*k)*(13591409 + 545140134*k))

/(f(3*k)*Math.pow(f(k), 3.0)*Math.pow(640320, 3*k+3.0/2.0));

if(n > meddigSzámoltuk) {

pTár += p;

közelítőÉrték = 1.0/(12.0*pTár);

meddigSzámoltuk = n;

}

return közelítőÉrték;

}

public static void main(String[] args) {

ChudnovskyPi pi = new ChudnovskyPi();

for(int n=2; n<5; ++n) {

System.out.println("pi ~ Pi(n) = " + pi.közelítés(n)

+ ", n = " + n

+ ", Math.PI/Pi(n) = "

+ (Math.PI / pi.közelítés(n)));

}

}

}

Ha az Olvasó fordítaná és futtatná a programot, akkor a következő kimenetét láthatná:

[norbi@niobe ~]$ javac ChudnovskyPi.java

[norbi@niobe ~]$ java ChudnovskyPi

pi ~ Pi(n) = 3.141592653589764, n = 2, Math.PI/Pi(n) = 1.0000000000000093

pi ~ Pi(n) = 3.141592653589764, n = 3, Math.PI/Pi(n) = 1.0000000000000093

pi ~ Pi(n) = 3.141592653589764, n = 4, Math.PI/Pi(n) = 1.0000000000000093

(Mivel mi csupán a 64 bites lebegőpontos aritmetikát használjuk, csak a fent idézett számítást tudjuk futtatni,

azaz a Pi(n) = 3.141592653589764 13 tizedesig pontos eredményig jutottunk.)

A Pi jegyeinek nyomában matematikai témájú programozási mellékletünk Pi jegyeit boncoló részében már olyan

osztályokat is tárgyalunk, amelyekkel a 64 bites lebegőpontos aritmetikát használva is remek programozási

élményeket gyűjthetünk. Most csupán ízelítőül vágjuk be ide a PiBBP osztályunkkal kiszámolt 1000 darab

számjegyét a Pi hexadecimális kifejtésének, a kifejtés 1000001. jegyétől.

[norbi@niobe ~]$ javac PiBBP.java

[norbi@niobe ~]$ java PiBBP

6C65E52CB459350050E4BB178F4C67A0FCF7BF27206290FBE70F93B828CD939C475C728F2FDB0CB9

23CF52C40D631D4DB2E98340AA25A6F07DB685C0A9C04F3F6E667CFD6E1764C83ECA94E79661FC18

0E6AEF581987E79E13278712CB01255E8CE4D9E048F782D756370548FB0778323CF2074C2716D121

639F1DD5A31EF6C242676B3783AD528852CCA52A9B4F999C526B0750859AEEC9CE6635B30996A210

CD419D5FD47A4E7AAF906E26A4CCF99A2E493BBB5E7D5E0B94F15196DA8CD1A0C57FE03A629B2D58

42317C173D163EA8717B46930EE0FE82FEC4B01016F155FB446AA6958EAD9265EC0C914CB84755DD

1BCE5100C23804D67A787BEC57CD7D8E190B3F55E3D2558927215504F141AC8B0BA836F7781E1966

Page 75:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

47 Created by XMLmind XSL-FO Converter.

4EFA8B22BEB3816A70F7210E4784A1F37762361286448CD051BCE3A4CE156D70CDBA256C1A36C386

48633C8F13A53405795635084A2DEAF3B9066BC3863BB07447DDDBDE5644034A6893E3E1CFDB3696

31BAA4240D93F17F667F7C51ABF076F7C1BB35DECC240153F4817A579CBD1DAC895E8555929D1ADA

3C787A0BF2881BBC44C4BE505E91FE5A28B9BA47D4845B7639239AD71D8B63BF9D23B2CC88C9D39C

033B0482F5F801D778BBB734EA8B1BE878D129514BFA5C4A6D60E80CF4B14A2A5673992B18397230

54BD44F767B03245F2873973EF6D84B2B96EFC9A

1.1.1.7. Eldönthetetlenség a formális axiomatikus elméletekben

„ANGYALOK KARA

Szabadon bűn és erény közt

Választani, mily nagy eszme,”

—Madách Imre

A tudás fájának gyümölcséből fogyasztva megadatott, hogy dönthessünk igazság és hamisság között, de a

döntés nem egyszerű. Az axiomatikus módszer ezt segíti. Néhány elfogadott igazságból, mechanikus levezetési

szabályok segítségével további igazságokat gyártunk. Saját mindennapi döntéseinkben többször, másokéban

meg még jóval többször vélünk észre venni részrehajlást. Ebben az értelemben az axiomatikus módszer egy

instant eljárás: „csak felöntjük vízzel”, azaz levezetünk; miközben a döntés objektív marad, nem függ az

érvelőtől, a levezetést végzőtől, azaz a „bárki ezt hozta volna ki, így én magam is erre az eredményre jutottam

volna” megközelítés megadja az objektivitás élményét. Ehhez a levezetéshez persze az emberi beszéd

túlságosan is árnyalatgazdag - ezt elfogadni elég a választási kampányok sokszor végtelennek tűnő meddő

dialógus-párbeszédeire gondolni, ahol megszokott, hogy az A állítást és annak tagadását is minden különösebb

nehézség nélkül bizonyítják a jelöltek - ezért a levezetéseket egy speciális nyelven, egy matematikai logikai

nyelven kell elvégeznünk.

A matematikai logikai nyelvek nagyon közel állnak a programozók gondolkodásához, akik ezért könnyen tudják

beszélni, pontosabban írni és olvasni is. Tekintsünk meg egy konkrét arról szóló példát, hogyan beszélünk egy

ilyen matematikai logikai nyelven, ami legyen a [DRAGÁLIN KÖNYV] könyvben ismertetett Ar nyelv.

1.28. példa - Az Ar klasszikus elsőrendű matematikai logikai nyelv

A hivatkozott [DRAGÁLIN KÖNYV] Ar nyelv a számok világabeli pontos állítások leírását teszi lehetővé,

segítségével a számokra vonatkozó állításokat lehet formalizálni.

I. Az Ar típusos nyelv, egyetlen típusa a szám típus, a szám típusú változók nevei betűkből álló azonosítók, de

tipikusan az egyetlen betűből álló változóneveket szoktuk használni: a, b, c, ..., x, y, z, ...

II. Az Ar nyelvben egyetlen konstans, a 0 szimbólummal jelölt konstans van.

III. Az Ar nyelvben a szavak felépítésére három függvény szolgál, ezeket a S(), +(,), *(,) szimbólumok

jelölik. A változónevek és a konstans egyszerű szavak, a függvények segítségével ezekből összetett szavak

építhetők az alábbiak szerint

i. az Sszó szó egy összetett szó (S a szó értékének eggyel való növelése)

ii. a szó+másikszó szó egy összetett szó

iii. a szó*másikszó egy összetett szó Például az SS0, S(0+S0), S(0+S0)*SS0 összetett szavak.

IV. Az Ar nyelv állításai vagy mondatai (szó = másikszó) alakúak. A mondatokból összetett mondatok

alkothatók az ÉS, a VAGY, a NEM és a KÖVETKEZIK logikai jelekkel, az egzisztenciális (LÉTEZIK) és az

univerzális (MINDEN) kvantorok segítségével. Például a LÉTEZIKc (a+c=b) ÉS (!(a=b)) Ar nyelvű állítás

felolvasva: van olyan c, amit az a változóhoz adva b-t ad, azaz a < c.

Az Ar nyelven pontosan meg tudjuk fogalmazni a számok világabeli állításainkat. Írjuk fel például egy Ar

nyelvű mondat formájában, az (a < b) := (LÉTEZIKc (a+c=b) ÉS (!(a=b))) , hogy

Page 76:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

48 Created by XMLmind XSL-FO Converter.

• minden számnál van nagyobb: MINDENx (LÉTEZIKy(x < y))

• van olyan szám, aminél nincs nagyobb: LÉTEZIKy (MINDENx (x < y))

• a számok végtelen sokan vannak: MINDENx (LÉTEZIKy(x < y))

• véges sok szám van: LÉTEZIKy (MINDENx (x < y))

1.29. példa - Saját terület formalizálása

Programozóként a formalizálással kapcsolatban az automatikus tételbizonyítás egy izgalmas terület, ahol olyan

programokat tudunk írni, amelyek képesek formulák igazságának vagy hamisságának mechanisztikus

eldöntésére. Ehhez első lépés a vizsgált terület formalizálása, melynek során ki kell alakítanunk egy nyelvet,

amin tárgyalhatjuk a vizsgált területet. Most példaként foglalkozzunk a programokkal! Egyetlen típusunk legyen

a program típus, a program típusú változók nevei betűkből álló azonosítók, de tipikusan használjuk az x, y, z, ...

betűket. Jelölje E(x), hogy az x program esztétikus, J(x), hogy jó.

• Az esztétikus programok jók: MINDENx (E(x) KÖVETKEZIK J(x))

• Csak az esztétikus programok jók: MINDENx (J(x) KÖVETKEZIK E(x))

• Az esztétikus és csak az esztétikus programok jók: MINDENx ((E(x) KÖVETKEZIK J(x)) ÉS (J(x)

KÖVETKEZIK E(x)))

• Minden program, kivéve a nem esztétikusakat, jó: MINDENx (NEM E(x) KÖVETKEZIK J(x))

• Esztétikus program is lehet rossz: LÉTEZIKx (E(x) ÉS NEM J(x))

• Nem minden esztétikus program jó: NEM MINDENx (E(x) KÖVETKEZIK J(x))

Egy adott tudományterület axiomatikus formális elmélete egy logikai nyelvből és az axiómákból áll. A

természetes számok vizsgálatára létrehozott elméletet az Ar nyelv és a Peano-féle axiómarendszer alkotja. Egy

elméletet teljesnek nevezünk, ha a hozzá tartozó nyelv bármely mondatáról eldönthető, hogy ő vagy éppen az

ellenkezője vezethető le az elméletben.

De az axiomatikus módszernek is megvannak a maga korlátai, melyeket Hilbert nagy szomorúságára Gödel

híres inkompletibilitási tételei formájában tárt fel 1931-ben. A sors szeszélye, hogy éppen egy nappal azelőtt

tette közzé eredményeit, mielőtt Hilbert azóta híressé vált mondásában hitet tett a tudásról alkotott alábbi

meggyőződése mellett: „Tudnunk kell, tudni fogjuk.” Ezzel a hittel szemben az első ilyen inkompletibilitási

tétel állítása, hogy a formális axiomatikus elméletek nem teljesek. Példánknál maradva vannak olyan állítások,

melyek igazak a természetes számok körében, de az Ar elméletben sem bizonyítani, sem cáfolni nem lehet őket,

azaz sem a megfelelő Ar nyelvi mondat, sem annak tagadása nem vezethető le az elméletben. A témakör pontos

fogalmait az Olvasó a [DRAGÁLIN KÖNYV] könyvben találja meg.

A Chaitin-Kolmogorov bonyolultsággal kapcsolatban megismert fogalmainkat felhasználva könnyen tehetünk

igaz, de bizonyíthatatlan állításokat. Lássuk a [VITÁNYI KÖNYV] ilyen bevezető példájának egy programozói

megfogalmazását. Ez a hivatkozott [VITÁNYI KÖNYV] példa arról szól, hogy léteznek bonyolultságot

használó igaz, de bizonyíthatatlan - azaz Gödeli - állítások. Nevezetesen az állítás az, hogy az „x sorozat

véletlen” állítás nem bizonyítható. Ennek bizonyításaként tegyük fel, hogy mégis az! Ekkor tudunk egy olyan

programot írni, amely generálja a megfelelő elméletbeli levezetéseket és előbb-utóbb rátalál az indirekt

feltevésünk szerint létező levezetésre, azaz a bizonyításra...

A megfelelő formális axiomatikus elméletet F-el jelölve és elképzelve, hogy az F elméletet 0, 1 jegyekkel

lekódoltuk, felülről becsülhetjük a bonyolultságát, azaz K(F)<=|F|<=f az x sorozat véletlen állítás pedig

szemantikailag azt jelenti, hogy K(x)>=|x|

Page 77:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

49 Created by XMLmind XSL-FO Converter.

Amikor a program kiírja az x-et, az if utasítás fejéből láthatjuk, hogy |x|>f, ezt felhasználva az indulásnál tett

felső becslésünknél K(F)<=|F|<=f<|x| adódik, azaz röviden K(F)<|x|. Ha a két bonyolultságos egyenlőtlenségre

pillantunk, szépen látszik az ellentmondás:

• K(F)<|x|

• K(F)>=|x|

Megjegyezhetjük, hogy az automatikus tételbizonyítással kapcsolatos logikai kutatások szülték az olyan, a

deklaratív programozási paradigmák alá sorolt programozási nyelveket, mint például a Prolog. A A

programozás egy filogenetikai törzsfája című pont alatt részletesebben olvashat a programozási paradigmákról.

1.1.2. A programozás evolúciója

„A BASIC után PASCAL következzék (felfelé) vagy ASSEMBLER (lefelé)? A

matematikusoknál a PASCAL-nak, a diákoknál az ASSEMBLER-nek van nagyobb tábora.” —Marx György

Ha a kedves Olvasó egy pillantást vet a [LEVÉNEZ IDŐVONALAK] programozási nyelveket bemutató

munkájára, akkor az a benyomása támadhat, hogy témánk, a programozás egy élő, önmagát szervező

diszciplína. A programozási nyelvek arra szolgálnak, hogy kommunikálhassunk új szervünkkel - egyik legújabb

játékszerünkkel - a gyors számításokat végző gépekkel. Ez sok ember számára nagyon rejtélyes, majd idővel

nagyon izgalmas tevékenység. De ennek a rejtélyből az izgalomig hatoló megismerési folyamatnak a

mellékterméke a fejlődés, s ami az egyik embernek valamikor izgalmas volt, úgy lesz már inkább csak

(történeti) érdekesség egy későbbi valakinek, de a sors igazságossága, hogy ez a lánc végtelenül folytatódik:

minden későbbi valaki valamikorivá válik. Amit közben felhalmoznak, az az informatikai kultúra.

És ki tudja milyen lesz a jövője ennek a kultúrának? Például a gépek átalakíthatják annyira a mindennapjainkat,

hogy egy program forrásszövegének elemzéséről szóló óra megjelenhet egy vers elemzéséről szóló középiskolai

óra mellett esélyes vetélytársként?

Kevésbé irodalmi, de költői kérdést felvetve: egyszerűbb ma a programozás, mint tegnap? Azonnal vágnánk rá,

hogy igen, pedig lehet, hogy inkább mégsem! Mi nem akarjuk eldönteni, csak egy további kérdéssel sugallni,

hogy szerintünk mi a válasz. Egy C vagy egy Java programozás tankönyv Chaitin-Kolmogorov bonyolultsága

nagyobb-e?

Meggyőződésünk, hogy amíg a számítógépeink nem az ember központi idegrendszerének emberi tudatot

létrehozó működése mintájára működnek, addig a programozást mindig tanulnunk kell. Márpedig máshogy

működnek és a jövő (például a lehetséges kvantum programozás?), vagy az azt követő jövő még jobb gépei,

méginkább máshogy működhetnek majd. Ismét csak egy sugalmazó kérdést feltéve: mit érezhetne egy 10 éve

napi gyakorlatban dolgozó imperatív programozó, amikor tegnapra Prolog fejlesztővé kellene átképeznie

magát?

1.1.3. A programozás egy filogenetikai törzsfája

„A matematika Wigner Jenőt lenyűgöző csodálatos hatékonysága a szem látáshoz való

alkalmazkodásához hasonlóan a szelektív evolúcióval magyarázható. Ha napjaink

matematikája hatékony, az csak azért van, mert a tegnap nem eléggé hatékony matematikáját

könyörtelenül kiirtották és kicserélték.”

Page 78:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

50 Created by XMLmind XSL-FO Converter.

—Stanislas Dehaene

1.1.3.1. Megjegyzések a törzsfához

A Turing kiszámítható programozás alatt azt értjük, hogy minden olyan dolgot, amit a belőle leszármazó

programozások alól származó programozási nyelveken meg lehet csinálni, azt Turing géppel is meg lehet

csinálni.

A DES törés a [DES TÖRÉS] cikkben ismertetett konkrét DNS számítás. A DNS számítások tipikusan a „brute

force” jellegű feladatmegoldásra alkalmasak, ahol az összes potenciálisan lehetséges megoldás megvizsgálása

során kapjuk a tényleges megoldásokat. A DNS számítások apropója, hogy a lehetséges összes megoldást

egyszerre, párhuzamosan próbálják ki. Az említett DES eljárással akkor találkozhat az Olvasó, amikor egy

UNIX vagy Linux rendszerű gépre bejelentkezik, ekkor a begépelt jelszaván, például a matyi2006

karaktersorozaton a bejelentkeztető program végrehajtja a DES algoritmusát, aminek eredménye, a példánál

maradva a $1$wZ3bMDHK$Xogj2CHjy4.o3MEB2nhp00 karaktersorozat. Jelszavunk ilyen kódolt képét tárolja a

gép, Linux alatt például a /etc/shadow állományban. A két minta összevetésétől függ, hogy a bejelentkeztető

program beenged-e minket a rendszerbe vagy sem. A DES törése annyit tesz, hogy meg tudjuk mondani a

kódolt képhez tartozó eredeti szót. Csak érdekességként jegyezzük meg és ez a megjegyzés nem kapcsolódik a

DNS számításokhoz, hogy a jelszavakat törő programok (ilyen például a cracklib) célja, hogy a rendszergazda

rávegye a felhasználókat, hogy - a teljes rendszer védelmében - megfelelően bonyolult jelszavakat válasszanak

Page 79:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

51 Created by XMLmind XSL-FO Converter.

maguknak. A [PROGRAMOZÓ PÁTERNOSZTER JEGYZET] jegyzetben arra láthatunk példát, hogyan

törhetjük, az említett céllal, a felhasználóink jelszavait egy másik, a John the Ripper programmal.

Az említett LEGO Mindstorms NXT korábbi változatát, a LEGO© Mindstorms® Robotics Invention System

robotot egyébként Javaban is lehetett programozni a [LEJOS JAVA] rendszer segítségével. A [JÁVÁCSKA

PORTÁL] és a [JÁVÁCSKA BARÁTAI] lapjain számos olyan előadás prezentációnk található, ahol ezt

mutatjuk be, ilyen például a [TANÁRKÉPZÉS EA.] bemutató.

1.1.3.2. Röviden az egyes programnyelvekről

1.1.3.2.1. Ada

Az Amerikai Hadügyminisztérium támogatásával tervezett eljárásorientált nyelv, a NATO egyik hivatalos

programozási nyelve. Bonyolult, az eljárásorientált paradigma minden eszközét tartalmazó nyelv. Az Ada 95

verzió óta objektumorientált konstrukciókat is tartalmaz.

1.1.3.2.2. C

Az egyik legsikeresebb eljárásorientált nyelv. Gépi kódú logikával és azt közelítő sebességgel rendelkező

programok írhatók benne. Speciális a mutató típusa. Nincs dinamikus szemantika ellenőrzés. A memóriát a

programozó kezeli. Rendszerprogramozásra is használják. Szabad felhasználású implementációi is léteznek (pl.

a gcc).

1.1.3.2.3. C++

Az egyik legsikeresebb objektumorientált nyelv, a C kiterjesztése. Többszörös öröklődést, dinamikus és statikus

kötést, általánosított referencia típust, speciális típuskényszerítést tartalmaz. A memóriát a programozó kezeli,

nincs automatikus szemétgyűjtögetés. Szabad felhasználású implementációi is léteznek (pl. a gcc).

1.1.3.2.4. C#

Az OO paradigmából Java-elveket megvalósító, a .NET keretrendszerbe integrált nyelv. Fejlett vizuális

eszközkészlettel és speciális hatásköri eszközkészlettel (névterek) rendelkezik.

1.1.3.2.5. Delphi

A Pascal objektumorientált változata, amelyben az adatbázis-programozás is lehetséges.

1.1.3.2.6. Java

A Java egy „majdnem” tiszta OO nyelv. A C++ egy továbbfejlesztett változataként jött létre a nyílt elosztott

rendszerek programozási nyelveként. Tartalmaz eljárásorientált elemeket, de programozni benne csak az OO

paradigma mentén lehet. Tervezésénél alapvető volt a biztonságos kód írásának követelménye. A Java egyszeres

öröklődést, késői kötést, automatikus memóriakezelést valósít meg. Vannak benne primitív típusok, ezek

megfelelnek az eljárásorientált egyszerű típusoknak. Van változója, ami primitív típusú értéket, vagy

objektumreferenciát vehet fel értékül. A referencia típusú változók mindig a hivatkozott objektumot adják.

Kifejezésfogalma teljesen C-szerű. A módszereket függvények segítségével, az attribútumokat változókkal lehet

megadni. Ismeri a csomagot, ez a fordítási egysége. Bezárási eszközrendszere négy szintű. A publikus, privát és

védett szintet explicit módon kell megadni. Alapértelmezett a csomag szintű láthatóság. A Javának hatékony

kivételkezelő és párhuzamos programozást lehetővé tevő eszközrendszere van, az 5-ös verzióba már beépítették

a generikust is. Az interfész egy speciális viselkedésmód absztrakció implementálását lehetővé tevő eszköz. A

Java fordítóprogram egy közbenső formára, az ún. bájtkódra fordít, amelyet aztán a Java Virtual Machine

(JVM) interpretál. Ez segíti a hordozhatóságot.

1.1.3.2.7. JavaScript

A web programozás kliens- és szerveroldali szkript nyelve. Objektumalapú és eseményvezérelt. HTML

dokumentumok kezelését teszi lehetővé.

1.1.3.2.8. Lisp

Page 80:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

52 Created by XMLmind XSL-FO Converter.

A funkcionális paradigmát bevezető nyelv. Nagyon sok verziója létezik, közülük a dinamikus objektum

fogalommal rendelkező CLOS a leghíresebb. Az eredeti Lisp sok imperatív jellegű eszközt tartalmazott, nem

volt tisztán funkcionális.

1.1.3.2.9. Perl

Az egyik legsikeresebb szkript nyelv. Objektumorientált. Reguláris kifejezései igen hatékony és tömör

programozást tesznek lehetővé. A webprogramozásban jelentősége igen nagy. A szerveroldali CGI programozás

alapeszköze.

1.1.3.2.10. PHP

A szerveroldali web programozás szkript nyelve. Nyílt forráskódú. Legfontosabb felhasználási területe az

adatbázis-elérés. Közel két tucat adatbázis-kezelőhöz rendelkezik vezérlőtámogatással.

1.1.3.2.11. Prolog

A logikai paradigma első és legelterjedtebb nyelve. Sok verziója létezik, köztük objektumorientált is. Az

elsőrendű predikátumkalkuluson alapul. A Prolog nyelvi rendszer középpontjában egy következtető gép áll. A

nyelvben vannak tiszta logikai, metalogikai és logikán túli eszközök is.

1.1.4. Bepillantás napjaink gyakorlatába

A [JAVA.SUN.COM] lapjain számos helyen találhatunk a Java technológia elterjedtségét bemutató adatokat.

Emeljünk ki néhányat, például a [JAVA MINDENÜTT] című lapról! Mit saccolunk, mennyi Java programozó

lehet világszerte? A hivatkozott lap szerint a Java nyelven fejlesztők családja, a Java fejlesztői közösség immár

több, mint 5 millió programozót tömörít. Ezzel a Java fejlesztői közösség a legnagyobb programozói közösség

az ember által ismert világegyetemben. Mit programoznak a közösség tagjai? Ugyancsak a lap adatainak

tanúságai szerint majdnem 2 milliárd Java kártyát, 800 millió Javával eladott személyi számítógépet és 1.2

milliárd Javas mobiltelefont! Érdemes azon elgondolkodni, hogy az Olvasó háztartásában mennyi Java Virtuális

Gép van? Van például Javas mobilja?

1.1.5. Néhány látomás: a jövő programozása

„Elképzelhető, hogy az emberi értelemnek ugyanúgy vannak határai, mint az állati

intellektusnak. Egy kutya sok mindent megtanulhat, de a szorzótáblát lehetetlen neki

megtanítani.” —Wigner Jenő

Kognitív értelemben sokszor közelebb érezzük magunkhoz a számítógépeket, mint az állatokat, talán éppen

azért, mert a gépek bármi nehézség nélkül kinyomtatják a szorzótáblát. Ezt az érzést több megfigyelésünk erősíti

meg nap mint nap: például amikor LEGO robotunk, végre már, éppen kitalál a padlón könyvhalmokból

rögtönzött labirintusból, vagy a híradó bemutatja az éppen legcsillogóbb humanoid robot kacsintását. Mégis

könnyen elképzelhetőnek tartjuk, hogy ebben az érzésben csalatkozni fogunk. Nemcsak azért, mert mi -

szemben a számítógépekkel, akik viszont nem - ugyancsak megküzdöttünk a szorzótáblával.

Érdekes, hogy a mesterséges intelligenciát, a mesterséges intelligencia kutatásában való hitelességet senki nem

vitatja el az informatikusoktól. De ez egyben annak is alátámasztása, hogy a mesterséges intelligencia tárgya

mára túlontúl eltávolodott a természetes intelligencia reprodukálásától, az „Asimovi gépek” [ASIMOV

REGÉNY], [ASIMOV MOZI] létrehozásától.

Ezért olvashatunk újongva az irodalomban az Orch OR, azaz Orchestrated Objective Reduction, [ORCH OR]

modellről, mert a modellezett jelenség a tudat. Egyébként a modell egyben az interdiszciplinaritás példamutató

zászlóshajója is, lévén egyik kidolgozója Roger Penrose fizikus, a másik Stuart Hameroff, aki aneszteziológus.

Fontos, hogy elméletük cáfolható, maguk adnak meg olyan a modellhez kapcsolódó tulajdonságokat, melyek

sérülése a modell módosítását vagy természetesen akár elvetését is implikálhatja.

Page 81:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

53 Created by XMLmind XSL-FO Converter.

A kvantum programozást azért származtattuk a Turing kiszámítható programozásnál bővebb nem Turing

kiszámítható programozás dobozból, mert a kvantum gépek képesek valódi véletlenszámok előállítására

[VÉLETLEN MŰSZER].

A Penrose-Hameroff Orch OR modell interdiszciplináris jellegét az adja, hogy a modell egyaránt operál

biológiai, számítástudományi és fizikai alapokon. Biológiai vonatkozás, hogy a modellbeli számításokat a

sejtváz mikrotubulusai végzik, mert a számítások alapvető kapcsolóeleme a mikrotubulus csövecskéket felépítő

tubulin fehérjék térbeli szerkezete. Számítástudományi vonatkozás, hogy ezek a globuláris fehérjék a modell

szerint egy hexagonális rácsba szervezett sejtautomata hálózatként működnek. S végül, de elsősorban fizikai

vonatkozás, hogy ennek a sejtautomatának van olyan periodikusan jelentkező működési fázisa, mely

közvetlenül kapcsolódik a természet legmélyebb ismert elméletéhez, a kvantummechanikához. Mert ebben a

fázisban a sejtautomata cella következő állapotát nem közvetlenül és lokálisan a hat hexagonális cella állapota,

hanem holisztikusan, a Penrose által bevezetett, a gravitációhoz feltételezetten kapcsolódó objektiv

állapotvektor redukció határozza meg.

1.1.5.1. A Penrose-Hameroff Orch OR tudat modell

„Ha most lennék fiatal kutató, akkor a szellem-test problémát tanulmányoznám. Ez a 21.

század nagy kihívása.” —Ilya Prigogine

Napjainkban igen népszerű az agy-számítógép, s ennek megfelelően a idegrendszer-szoftver analógia, aminek

gyökerei talán Neumann az agyat és a számítógépet összehasonlító [GÉP és AGY] könyvében gyökereznek.

Neumann itt említi, hogy az idegrendszer egy „rövid program”, avagy mai terminológiával egy interpreter

lehet.

Az interpreterek tipikusan egy magasabb absztrakciós szintet vezetnek be az őket futtató réteg felett.

Gondoljunk csak a Java Virtuális Gépre mint interpreterre! A Java platform című kép mutatja, hogy a Java

Virtuális Gép elrejti az őt futtató hardverek különbözőségeit. Ebben az értelemben a különböző hardvereket

most a fonalférgek, a patkányok, a kutyák végül a majmok agyán át az ember agyáig képzelhetnénk.

Az Orch OR modell is egy számításos modell, abban tér el az uralkodó neuron hálózatos számítási modelltől,

hogy alapvető szerepet kap benne két olyan jelenség, amit az ember a legelemibbnek ismer a természetben, ez a

kvantummechanika és a gravitáció. Kicsit sántító analógiával olyan ez, mintha a fent említett - s persze most

csak ezen analógia megfogalmazása miatt feltételezett - interpreterünkön futó programunkat gépi kódú

részekkel kéne kiegészítenünk, azaz a használt absztrakciós szintünknél - ami ebben az esetben a Java

programozás - mélyebb szinteken is kellene dolgoznunk, pontosabban a legmélyebb szinten, analógiánkban gépi

nyelven. Egyébként vannak, akik éppen ezen analógia miatt fejezik ki kételkedésüket az Orch OR modell

tekintetében. Persze e kritikájukat nem a jelen interpreteres analógiánk alakjában fogalmazzák meg a tézisük

védelmében, hogy a tudat működését a klasszikus fizika keretein belül kell megmagyarázni, vagy még inkább a

triviálisan a fizikára, kémiára, biokémiára épülő, de immár a saját maga szabályai alapján működő biológiára,

idegtudományra: „A tudat sem a kémia alagsorában, sem a fizika pincéjében nem lakik” [GONDOLKODÓ

KÖNYV].

Page 82:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

54 Created by XMLmind XSL-FO Converter.

Az Orch OR modell általános vitája köré épül a [PENROSE-HAWKING KÖNYV] könyv, melyből kritikus és

támogató hangokat is kiemelhetnénk, s mindenképpen ajánljuk az ebben az irányban érdeklődő kedves Olvasó

figyelmébe. A modell természetesen az előző bekezdés végének idézetétől eltérő indíttatású kritikákat is kap. A

leginkább idézett ilyen [TEGMARK DEKOHERENCIA CIKK].

Való igaz, hogy az Orch OR modell egy erősen spekulatív jellegű modell, de mint egy potenciálisan lehetséges

új paradigma minden olyan érdeklődőnek és főleg programozónak felkeltheti az érdeklődését, aki többre tartja a

tudatot egy Turing gépnél.

1.1.5.1.1. Hameroff mikrotubulus sejtautomatái

„Az ember ezt, ha egykor ellesi,

Vegykonyhájában szintén megteszi.”

—Madách Imre Az ember tragédiája

Hameroff már korábbi munkáiban felveti annak lehetőségét, hogy az agyi számítások alapvető kapcsolóeleme

nem az idegsejt, hanem a minden eukarióta sejtben megtalálható mikrotubulus [HAMEROFF

MIKROTUBULUS]. Penrose [CSÁSZÁR KÖNYV] ismeretterjesztő könyvének olvasása során [HAMEROFF

INTERJÚ] jött Hameroff ötlete, hogy az agyi kvantum számítások a mikrotubulusokban mehetnek végbe.

Az eukarióta sejtek citoszkeletonját, sejtvázát háromféle fehérjefonalakból felépülő hálózatok alkotják, egyikük

a mikrotubuláris hálózat. A citoszkeleton adja meg a sejt alakját, biztosítja a sejten belüli anyagszállítást, esetleg

adott esetben még a sejt mozgását is, ha például a csillókra gondolunk. A mikrotubulusok kétféle tubulin

fehérjéből felépülő csövecskék. A kétféle tubulin egymással tubulin dimernek nevezett egységet alkot, melyek

egymás után fűzve a protofilamentumokat alkotják. Tipikusan 13 ilyen protofilamentum szál egy hengerpaláston

párhuzamosan elhelyezkedve alkotja a mikrotubulust [SEJTBIO 1], [SEJTBIO 2]. A tubulin dimerek

elhelyezkedését hexagonális ráccsal modellezhetjük, ahol egy tubulin dimernek hat tubulin dimer szomszédja

van [MIKROTUBULUS 1].

Page 83:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

55 Created by XMLmind XSL-FO Converter.

A tubulin dimerek két egymáshoz nagyon hasonló, a fehérjemolekulák konformációja, térszerkezete

meghatározta állapotban léteznek. Ezért kétállapotú kvantummechanikai rendszereknek tekinthetők. Ahogy már

említettük, Hameroffnak éppen Penrose [CSÁSZÁR KÖNYV] ismeretterjesztő könyvének tanulmányozása

során jutott eszébe, hogy a mikrotubulusok ideális otthont biztosíthatnak a Penrose által javasolt objektív

redukciónak nevezett feltételezett folyamatnak.

1.1.5.1.2. Penrose objektív redukciója

„Így bármilyen furcsán hangzik, logikailag lehetséges, hogy magában az objektív világban a

fizikai mennyiségeknek soha nincs egy-egy jól definiált értékük; csak egy-egy eloszlásuk van,

amelyben a lehetséges értékek egyidejűleg léteznek. A tudat működik úgy, hogy ezekből az

eloszlásokból konkrét értékeket csinál.” —Vassy Zoltán

Page 84:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

56 Created by XMLmind XSL-FO Converter.

Az [ORCH OR] modell szerint a mikrotubulus tubulin dimerek alkotta hexagonális rácsa bizonyos

periódusokban klasszikus sejtautomataként végez számításokat, aminek során a rács egy csomópontjának

állapota 6 szomszédjának állapotától függ. Az ezzel szembeni fejlődési periódusokban viszont a rács egyre több

csomópontja kapcsolódik be egy komplex szuperponált kvantummechanikai állapotba, mely során a csomópont

állapotáról nem beszélhetünk, hanem csak azután, amikor ennek a fejlődési folyamatnak a Neumann féle 1-es

folyamat ([NEUMANN KVANTUM KÖNYV] 200. oldal, vagy ismeretterjesztő szinten a [CSÁSZÁR

KÖNYV] könyv - 276. oldal - terminológiájával az R, az állapotredukció folyamata), azaz a mérés véget vet és

a csomópontok a méréskor szóba jöhető valószínűségekkel az egyik vagy a másik állapotukba kerülnek. Az

Penrose-féle OR, objektív redukció szerint a kvantummechanikai unitér fejlődésnek végetvető mérés objektíven

- például a megfigyelő tudatától függetlenül - következik be, amikor a komplex szuperponált állapotban együtt

élő konformációk térbeli tömegeloszlásainak különbsége átlép egy, a Penrose által egy graviton határnak

nevezett értéket. Az [ORCH OR] cikkben ismertetett kalkulációk alapján a szerzők szerint 109 tubulin 500

miliszekundumos összefonódása kiválthatja az egy graviton határ elérését, azaz az objektív redukció

bekövetkeztét. Vagy ugyanígy 1010 tubulin 50 miliszekundumos összefonódása , s így tovább. Ugyancsak az

említett cikkben hivatkozott adatok szerint neurononként 107 tubulinnal számolva az objektív redukcióhoz így

109 / 107 = 100 neuron szükséges, vagy ha a neuron tubulin állományának csupán 1 százalékával - mint a

folyamatba bekapcsolódó tubulinokkal számolunk, akkor 109 / 105 = 10000 neuron fél másodperces

összefonódása szükséges. Ezek alapján a tudat megjelenését Hameroff és Penrose az [ORCH OR TUDAT]

cikkben valahol a C. elegans környékén húzzák meg, mert ennek a fonalféregnek 302 neuronja van [C.

ELEGANS], akár már képes lehet az objektív redukció futtatására.

Az alábbi szimuláció vagy pontosabban csupán - az [ORCH OR], [ORCH OR TUDAT] cikkek képei alapján

készített - demonstráció azt mutatja, hogy egyre több tubulin dimer kerül koherens állapotba, míg az objektív

redukció következtében egy előre nem kiszámítható módon ugranak a résztvevő cellák valamely lehetséges

állapotukba, az ehhez az állapothoz tartozó valószínűséggel.

1.30. példa - Mikrotubulus sejtautomata szimuláció

Ebben a pontban csupán a megfelelő szimulációs, vagy inkább csak demonstrációs programunk által generált

néhány pillanatfelvétel képet mutatunk be, a program részletes feldolgozását a Biológiai témájú programok

című pontban adjuk meg. A programot az [ORCH OR] cikkben közölt képek mintájára készítettük el. A képek

azt mutatják, hogy a hexa rácson egyre több tubulin dimer kapcsolódik be a közös kvantum szuperponált

állapotba. Egészen addig, amíg a bekapcsolódottak kvantum szuperponált állapotában együtt élő konformációk

tömegeloszlásainak különbsége el nem ér egy határt, amikor is bekövetkezik az állapot redukciója, azaz a hexa

rács rácspontjai megint egy meghatározott állapotba kerülnek és indul a sejtautomata klasszikus üzeme, s így

tovább.

1.5. táblázat - Mikrotubulus sejtautomata szimuláció.

Page 85:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

57 Created by XMLmind XSL-FO Converter.

Page 86:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

58 Created by XMLmind XSL-FO Converter.

A bekapcsolódottak kvantum szuperponált állapotában

együtt élő konformációk tömegeloszlásainak

különbsége elérte az egy graviton szintet.

Bekövetkezett az állapot redukció.

1.1.5.2. Kvantum számítások

„Hol van mindenki?” —Enrico Fermi

Terjedelmi okokból a kézikönyvben ezt a témát nem bontjuk ki, de fontossága miatt adunk egy rövid irodalmi

útmutatást.

A kvantum számítógép elképzelést bevető alapcikk David Deutsch 1985-ben megjelent [DEUTSCH

KVANTUMGÉP CIKK] cikke. Mára a téma igen kiterjedt. A jelenlegi matematikai háttér megértéséhez

elegendő a Hilbert-terek ismerete, ami a mai legtöbb, nem ismeretterjesztő könyv olvasásához is szükséges. (Itt

érdekességként jegyezhetjük meg, hogy a kvantummechanika matematikai alapjait éppen Neumann János fogta

egybe precíz matematikai szigorral a [NEUMANN KVANTUM KÖNYV] könyvében. Sajnos a programozók

Page 87:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

59 Created by XMLmind XSL-FO Converter.

reguláris képzése nem vértezi fel a hallgatókat azokkal a matematikai ismeretekkel, amik e könyv élvezéséhez

szükségesek lennének.)

A kvantum számítási téma megismerésére a Debreceni Egyetem Elméleti Fizika Tanszék vezetőjének tollából

származó [KVANTUMINFORMATIKA] jegyzetet ajánljuk.

A programozó Olvasóknak a [PROGRAMOZÓ PÁTERNOSZTER JEGYZET] jegyzetet ajánljuk, ahol két rés

kísérlettől indulva említjük a fontos kísérleti mérföldköveket és részletesen bemutatjuk a legfontosabb kvantum

algoritmusokat.

1.1.5.2.1. Pesszimista programozó optimista gondolata

Futurisztikus fejezetünk lezárásaként játsszunk el a korábbi, mottóként idézet Vassy gondolat [VASSY

JEGYZET] és Neumann utolsó munkájának utolsó oldalain megjelenő gondolat [GÉP és AGY]

összefésülésével! Az első így hangzott

„Így bármilyen furcsán hangzik, logikailag lehetséges, hogy magában az objektív világban a

fizikai mennyiségeknek soha nincs egy-egy jól definiált értékük; csak egy-egy eloszlásuk van,

amelyben a lehetséges értékek egyidejűleg léteznek. A tudat működik úgy, hogy ezekből az

eloszlásokból konkrét értékeket csinál.” —Vassy Zoltán

a második pedig a következő

„Szembe kell néznünk azzal, hogy a nyelv messzemenően történelmi esetlegességet alkot. Az

alapvető emberi nyelvek különböző formái hagyományszerűen jutottak el hozzánk, de már e

hagyományos formák sokfélesége is bizonyítja, hogy semmiféle feltétlenség vagy

szükségszerűség nem testesül meg bennük. S mint ahogy a görög vagy a szanszkrit nyelv

létezése történeti tény, nem pedig feltétlen logikai szükségszerűség, ugyanúgy józanul

feltételezhetjük, hogy a logika és a matematika is történeti eredetű és esetleges kifejezési

formák. Lehetnek a logikának és a matematikának lényegesen eltérő változatai is - mindkettő

más alakban is létezhetik, mint amit megszoktunk! ” —Neumann János

Honnan a pesszimizmus? Mert, ha a tudatunk is csupán történeti esetlegesség, akkor Fermi kérdésére a válasz,

hogy sehová nem tűntek, mert számunkra - abban az értelemben, melyben a kérdés fel lett téve - nem is

léteznek! Tehát elvben jóval könnyebb lenne olyan fordítóprogramot írni, ami a delfin-ember vagy a fonalféreg-

ember kommunikációt teszi lehetővé, semmint a „zöld fickók” - ember fordítót. Ha ez a pesszimista helyzet

állna fent, akkor csak abban bízhatunk, hogy a kvantuminformatikus programozók majd kifejlesztik a megfelelő

fordítót! De addig is a mi életünk csíráit küldenénk ki a világegyetembe, hogy idővel majd találkozhassunk

olyanokkal, akikkel kölcsönösen létezünk egymás számára.

1.1.5.3. Visszabeszélő gépek

Még a tanár-diák kontextusban kezdődött el a következő, idézett kérdés a kézikönyv szerzőpárosa között.

„Miért lenne az jó, ha az asztalon lévő gép visszaszólna?” Adekvát válasz még ma sincs, hanem csak ebbe

tudományos fantasztikus ihletésű részben merjük beírni, hogy „Mert az intelligens gépek azt is el tudják majd

képzelni, amit mi emberek már nem.”

1.2. Az OO világ, a programozó szűkebb hazája

„Több erőfeszítést fektetünk a tervezésbe és kódolásba (ami szórakozás), hogy csökkentsük a

jóval költségesebb tesztelést és hibajavítást (ami nem az).” —Kernighan-Plauger A programozás magasiskolája

Ha futása közben - egy koncepcionálisan elég magas nézőpontból - rápillantunk egy OO programra, akkor

egymással kölcsönható, együttműködő objektumokat látunk. Amit a nyolcvanas, kilencvenes évek tipikus

imperatív programozója gondolt egy egész programja futásáról: szépen szekvenciálisan megy a végrehajtás, jön

egy szelekció, azon az ágon megyünk tovább... igen, itt akkor következik egy iteráció... átkerült az

objektumokba. Ezért OO programra az esetleges jól olvasható jelző helyett szerencsésebb, találóbb lehet az

érthető világ, jól megérthető világ leírás jellemzés. Mert az OO programozó építette osztályoknak arra a

Page 88:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

60 Created by XMLmind XSL-FO Converter.

kihívásra kell válaszolniuk, hogy modellezni tudják-e a programozó előtt álló feladat világát? Ha igen, akkor a

feladat sikeres megoldása annyit tesz, hogy a modellezett világban megnézzük a választ a kérdéseinkre és a

válaszokat a valóságos világbeli válaszoknak tekintjük.

Például ha a következő ábrán bepillantunk az Órarend programba, akkor az azt mondja, hogy Bátfai Norbert

Linuxot és Operációs rendszereket fog tanítani. Illetve ugyanez a valóságban: a közelgő félév elején BN

megnézi majd ennek a programnak a grafikus felületét és onnan tudni fogja, hogy talán már éppen másnap

hányra és melyik terembe kell mennie megtartani melyik kedvenc óráját.

Az OO programozó tehát osztályokat épít, olyan osztályokat, amik lehetőség szerint jól modellezik a

megoldandó feladat világát. Ennek során a programozó tipikusan felhasznál már rendelkezésre álló osztályokat.

Az osztályoknak azt a körét, amik minden ilyen építkezésnél alapvető fontosságúak, illetve adott részirányokban

(ilyen részirány lehet - csak néhány példát megemlítve - a mobil, az adatbázis, a hálózati, az elosztott, a

konkurens, a web programozás) alapvető fontosságúak lehetnek, Alkalmazói Programozói Interfésznek, röviden

API-nak nevezzük. Így nem meglepő, hogy pusztán az OO nyelv ismerete az API nélkül mit sem ér!

Mint az ember minden bonyolult dolgot, az API-t is hierarchiába szervezi, esetünkben ez a hierarchia egy fa

szerkezet, aminek gyökere a Java. A fa leveleit nem tartalmazó utakat csomagnak is nevezik, a következő ábra

alapján például a java.lang egy csomag. A java.lang csomag azokat az osztályokat tartalmazza amik a nyelv

szempontjából alapvetők. A String osztálybeli objektumok karakterláncokat reprezentálnak, ezek fontosságát a

programozásban nem kell tovább ecsetelnünk, mint ahogyan a számok fontosságát sem: az Integer osztály

példányai például az egész számokat reprezentálják. Kevésbé egyértelmű az Object osztály, pedig - ahogyan

majd hamarosan látjuk - ő a legfontosabb, ő az osztályhierarchia gyökere, azaz minden Java osztály őse... De ne

aggódjon a kedves Olvasó, az API-t még véletlenül sem kell megtanulni, hanem csak nézegetése közben

hozzászokni, mert természetesen a platform azért platform, hogy biztosítson olyan eszközöket, amik lehetővé

teszik, illetve segítik a fejlesztést, esetünkben bemutatják az API hierarchiát. De távolodjunk el pár bevezető sor

Page 89:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

61 Created by XMLmind XSL-FO Converter.

erejéig most a fáktól és nézzük az erdőt. A fákhoz majd a következő néhány pont után, a Java SE OO világ című

pontban térünk vissza.

1.2.1. A Java platform

1. Mit gondol a kedves Olvasó, találkozott már valaha a Javával?

2. Van mobilja?

3. Igen, akkor az első kérdésre a válasz: biztosan! Hogy miért? Mert a telefonja nagy valószínűséggel Java

képes készülék.

Mi tehát a Java? A válasz attól függ, ki kérdezi. Mert mondjuk a földrajzosoknak lehet egy sziget az Indiai-

óceánon. A programozóknak lehet egy modern programozási nyelv, megélhetés vagy szerelem... Az általában

vett mobil tulajdonosnak, azaz most nekünk, egy program a telefonon: egy számítógépes program. Ha eddig

nem tekintettük számítógépnek is a mobilunkat, akkor kezdjünk barátkozni ezzel a gondolattal, mert bár nem

olyan erős sebességben, a kijelzője méretében vagy mondjuk memóriakapacitásában, mint az asztalainkon

használt, mára már jól megszokott személyi számítógépeink, de mégiscsak, számunkra most számítógép.

Visszatérve a Javahoz, ennek a programnak az a feladata, hogy más, éppen Java nyelven megírt programokat

futtasson, ezért is nevezik egyszerűen csak Java Virtuális Gépnek, vagy röviden JVM-nek ezt a futtató

programot. Tehát, ha például egy telefon javas, akkor az annyit tesz, hogy rajta van a Java VM program.

Jogos a kérdés, miért hasznos ez nekem mint mobiltelefontulajdonosnak? Mert a JVM elrejti a mobiltelefonok

sokféleségét azzal, hogy a fejlesztőknek elég a JVM-re megírni a programjaikat, azok pedig automatikusan

működni fognak minden JVM-el rendelkező, azaz Java képes mobilon is! Tehát végső soron én mint mobil

tulajdonos elvben több programhoz juthatok hozzá, többhöz, jobbhoz, gyorsabban, olcsóbban. Összefoglalva, a

Java erejét a mobiltelefonok világában (azon túl, hogy a Java az Java :) az adja, hogy az elkészített programom

elvben automatikusan minden Java képes eszközön működni fog. Ezt a tulajdonságot nevezzük

platformfüggetlenségnek: a Java programom futni fog mindenféle javas mobiltelefonon: Motorolán, Nokián,

Sony Ericssonon... vagyis minden olyan telefonon, amin rajta van a Java VM!

A mobilokról általánosítva a személyi számítógépekre, a szerver számítógépre, az egész internetre ugyanez adja

a Java erejét: a programozó egy nyelvet megtanulva, egy nyelvet használva tudja a legkülönfélébb

programozható eszközöket, például mobilokat, személyi számítógépeket, szervereket kezelni, anélkül, hogy

magukkal ezekkel a különböző hardver eszközökkel, vagy az eszközökön található szoftveres erőforrásokkal,

Page 90:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

62 Created by XMLmind XSL-FO Converter.

például a futó operációs rendszerekkel: Linux-szal, Windows-zal vagy Solarisszal foglalkoznia kéne.

Az ábra beszédes, de hogy pontos is legyen, még finomítanunk kell: a Java Virtuális Gépek bemenete nem

közvetlenül az emberi fogyasztásra alkalmas Java forrásszöveg, hanem egy olyan köztes forma, amit egy

fordítóprogrammal, a javac nevű Java fordítóprogrammal készítünk el. Ez már nem emberi fogyasztásra

alkalmas, szöveges állomány, hanem bináris. Ez a virtuális gépek bemenete, ez az a hordozható forma, amit a

Java Virtuális Gépek értelmeznek. Egészen konkrétan, ha készítek egy ilyen, mondjuk Java SE platformbeli

osztályt (programot) Linux alatt, amit most nevezzünk Osztály.class osztálynak, akkor egyszerűen egy

Windows rendszerű gépre átmásolva, ott átadva az ottani Java Virtuális Gépnek, azaz például a megfelelő

parancssorba beírva a java Osztály parancsot, futni fog a programom. A Java telepítés és futtatás kapcsán

lásd még A Java telepítése gépünkre és A példaprogramok futtatása című pontokat!

1.2.1.1. Az első Java osztály lefordítása

Függessze most fel a kedves Olvasó az olvasást és fordítsa, majd futtassa le első Java programját. Ehhez először

persze gépünkre installálnunk kell a megfelelő fejlesztői környezetet. Ezt sikeresen megtehetjük A Java

telepítése gépünkre és A példaprogramok futtatása című pontok alapján, tegyük hát most meg!

Page 91:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

63 Created by XMLmind XSL-FO Converter.

A kézikönyv eddigi olvasása során már sok Java nyelvű forrás programot láttunk, bármelyikkel

megpróbálkozhatunk most, mint első fordításunkkal, futtatásunkkal. De mi az alábbi, a Fibonacci sorozat

(amelyben a sorozat adott tagja az őt megelőző két tag összege) tagjait kiszámító program fordítását javasoljuk.

A program kódjára magára egyelőre csak egy pillantást vessünk, mert fő feladatunk most a fordítás, futtatás

folyamat technikai bemutatása.

public class Fibonacci {

int előző;

int aztMegelőző;

public Fibonacci() {

előző = 1;

aztMegelőző = 1;

}

public int következő() {

int vissza = előző + aztMegelőző;

aztMegelőző = előző;

előző = vissza;

return előző;

}

public static void main(String[] args) {

Fibonacci finobacci = new Fibonacci();

for(int i=0; i<10; ++i) {

System.out.print(finobacci.következő());

System.out.print(" ");

}

}

}

Vágjuk ki a fenti kódot, majd illesszük be a Fibonacci.java nevű állományba. Végül fordítsuk, majd futtassuk

az alábbiak szerint, például Linux alatt így:

[norbi@niobe ~]$ javac Fibonacci.java

[norbi@niobe ~]$ java Fibonacci

2 3 5 8 13 21 34 55 89 144

1.2.1.1.1. Bitfaragó feladat

Milyen bitmintával kezdődnek a Java bájtkódok, azaz a javac nevű Java fordító generálta .class kiterjesztésű

állományok? Ha a választ hexában nem találjuk kapcsolatosnak a Java gőzölgő kávéscsésze logójával, akkor

még dolgozzunk rajta! Nézzük meg például az imént elkészített Fibonacci.class állományt!

Tipp

Ha már nagyobb gyakorlattal rendelkezünk, akkor a 0,1 feladat feladata is segíthet.

1.31. példa - Java disassembler

Page 92:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

64 Created by XMLmind XSL-FO Converter.

Az előző feladatot nyilvánvalóan azonnal megoldotta az a kedves Olvasó, aki megnézte hexadecimálisban a

Fibonacci.class állományt. A Java fejlesztői környezet egyébként ad kényelmesebb eszközt, hogy a

bájtkódot nézegessük. Bár erre az eszközre az átlagos Java fejlesztőnek valószínűleg nem lesz szüksége, de

megemlíteni mindenképpen érdekes. Ez a program a javap, feladata a bájtkódból az assembly nyelvek

tokenjeihez hasonló kimenetet előállítani. A -c kapcsolóval indítva bemenetként a Fibonacci.class bájtkódot

átadva beszédesen mutatja be a Java bájtkódot.

[norbi@niobe ~]$ javap -c Fibonacci

Compiled from "Fibonacci.java"

public class Fibonacci extends java.lang.Object{

int előző;

int aztMegelőző;

public Fibonacci();

Code:

.

.

.

public int következő();

Code:

0: aload_0

1: getfield #2; //Field előző:I

4: aload_0

5: getfield #3; //Field aztMegelőző:I

8: iadd

9: istore_1

10: aload_0

11: aload_0

12: getfield #2; //Field előző:I

15: putfield #3; //Field aztMegelőző:I

18: aload_0

19: iload_1

20: putfield #2; //Field előző:I

23: aload_0

24: getfield #2; //Field előző:I

27: ireturn

public static void main(java.lang.String[]);

Code:

.

.

.

Csupán a következő() függvény bájtkódját emeltük ki a javap által készített kimenetből. Ami bár emberi

fogyasztásra nem oly alkalmas, mint következő() metódus Java forráskódja, de azért próbáljuk összevetni a

kettőt!

1.2.1.2.

Futtatható megjegyzés

Bár nem javasoljuk, de lehetőség van a Java forrásból futtatható állomány létrehozására is, az ez iránt

érdeklődőknek a [PROGRAMOZÓ PÁTERNOSZTER JEGYZET] jegyzetre hívjuk fel a figyelmét,

ahol Linux alatt a GNU gcc fordító használatával mutatunk erre példákat. Miért nem javasoljuk? Első

ok, hogy így elveszítjük a hordozhatóságot, a második, hogy ezt a tettet általában a sebesség kérdésben

sem tartjuk indokoltnak. A sebesség kapcsán érdekes lenne írni valamilyen benchmark programot,

hogy magunk is meggyőződjünk erről. Írjunk is! A Pi jegyeinek nyomában című pont BBP algoritmust

megvalósító PiBBP osztályunkat átírtuk objektumorientálttalanná, azaz gyakorlatilag nem készítettünk

benne objektumokat, hanem csak egy statikus main() függvényt használtunk, illetve az algoritmust

átírtuk C nyelvre is. Ekkor az alábbi futási eredményeket kaptuk az alábbi egyszerű mérésekkel

Javaban

Page 93:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

65 Created by XMLmind XSL-FO Converter.

long delta = System.currentTimeMillis();

/* SZÁMÍTÁS */

delta = System.currentTimeMillis() - delta;

System.out.println(delta/1000);

illetve C-ben

clock_t delta = clock();

/* SZÁMÍTÁS */

delta = clock() - delta;

printf("delta: %f\n", (double)delta/CLOCKS_PER_SEC);

a Pi hexadecimális kifejtésének (0. pozíciótól számított) adott poziciója hexa jegyének

meghatározására egy Fedora Linux Core 5 operációs rendszerrel felszerelt, 2.6.17.7 verziójú

kernellel ellátott Sun W1100Z Workstation gépen gcc (GCC) 4.1.0 20060304 (Red Hat 4.1.0-

3) verziójú gcc és java version "1.6.0-beta2" verziójú Java mellett. (A szóban forgó méréseket

végző, említett teljes programokat, illetve néhány további összehasonlítást a melléklet Egyszerű

összehasonlítások a sebesség kérdésében című pontjában találhat az érdeklődő Olvasó.)

1.6. táblázat - Java és C egyszerű sebesség összehasonlítása

Pozíció 0xJegy C [sec] Java [sec]

106 6 4.39 4.246

107 7 51.19 49.465

108 C 586.0 556.935

Linux alatt a gcc fordító használatával így készítünk futtatható állományt a fenti Fibonaccis

programunkból:

[norbi@niobe ~]$ gcj -o fibonacci --main=Fibonacci Fibonacci.java

[norbi@niobe ~]$ ./fibonacci

2 3 5 8 13 21 34 55 89 144

Lássuk, hogy valóban futtatható állomány készült

[norbi@niobe ~]$ file fibonacci

fibonacci: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV),

for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9,

not stripped

szemben a bájtkóddal:

Page 94:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

66 Created by XMLmind XSL-FO Converter.

[norbi@niobe ~]$ file Fibonacci.class

Fibonacci.class: compiled Java class data, version 50.0

1.2.1.3. Történet és oktatás

„A jövőt nem lehet megjósolni. Azt föl kell találni.” —Gábor Dénes

Patrick Naughton, Mike Sheridian és James Gosling részvételével 1990 végén, 91 elején mindenféle

potenciálisan új generációs informatikai termékek kifejleszthetőségének vizsgálatával indult meg egy

technológia-intenzív csoport, a Green Team munkája. A háztartásokban található mindenféle különböző

hardverű szórakoztató elektronika vezérlése, programozása akkor ilyennek tűnt.

Az időközben személyi állományban tucatnyira növő projekt 1992 szeptember harmadikán bemutatta az általuk

kifejlesztett termék prototípusát a *7-et, azaz a Csillag7-re keresztelt 5 colos érintőképernyős, vezeték nélküli

hálózati kapcsolattal ellátott PDA-t. A *7 feladata az volt, hogy vezérelni tudja az olyan szórakoztató

elektronikát, ami érti, interpretálja az ehhez kifejlesztett új nyelvet, az Oakot. (Az Oak, Tölgy név eredete, hogy

Gosling irodájának ablaka éppen egy ilyen fára nézett.)

A sikeres demó után a termék értékesítésére alakult a csoportból a FirstPerson, de a piac még nem állt készen.

Végül az interpretált Oak nyelv, 1995-ben, már mint Java jelent meg, a korábban megcélzott piac helyére pedig

a forradalomként terjedő internet került. A Java születési ideje: 1995. május 23, amikor a SunWorld

konferencián John Gage, a Sun kutatási igazgatója hivatalosan bemutatta a Javát és az azt értő HotJava

böngészőprogramot, továbbá a konferencián a Netscape bejelentette, hogy böngészőjében támogatni fogja a

Javát.

Véleményünk szerint ez a szerencsés Java+internet összefonódás is szerepet játszott abban a folyamatban, ami a

programozó közösség javát abba az irányba mozdította, hogy a Java nyelv átvegye az első számú általános

programozási nyelv helyét az elméjében. Mert egy új programozási nyelv elsajátítása komoly mentális

befektetést igényel, de az már egy egészen más dolog, ha ez a befektetés az új világhoz, azaz akkoriban az

internet programozásának világához is megadja a kulcsot. Nem befolyásolja a homokvihart a porszem

véleménye, de magunk annak szorítunk, hogy a Java nyelv napjaink római békéje legyen a programozásban.

Az oktatás területén - az elmúlt 15 évben - két birodalom tündöklését és bukását éltük meg, a ma harmincas

éveikben járó programozók még diákként a BASIC-ét, majd hallgatóként a PASCAL-ét. A hanyatlás oka

magának a nyelvhez kapcsolódó kultúrának, magának a nyelvhez tartozó civilizációnak a hanyatlása. Mert csak

az oktatás ezeket a mentális birodalmakat nem tarthatja fenn, mivel a tipikus tanuló a nyelvhez kapcsolható

kultúrához, civilizációhoz kötődik és nem csupán a tiszta nyelvhez, gondolkodásmódhoz magához. Ezért az a

meggyőződésünk, hogy amit az oktatási célokra szánt nyelvekkel alapelvekben meg lehet tanítani, azt már

korábban, a 10 éves kor környékén meg lehetne és meg kell majd tanítani mondjuk a LEGO Mindstorms™

robotos eszközök segítségével. Mert ez a robotos készlet az életkorban ide kapcsolható játékkultúrához,

gyermeki - építő játék - civilizációhoz kapcsolódik, s ennek a civilizációnak a fennmaradása hosszabb távon is

bíztató.

A LEGO Mindstorms Robotics Invention System csomag 1998-ban jelent meg. Ez alapvetően egy több száz

alkatrészből álló LEGO csomag, de több speciális téglát is tartalmaz. Legfontosabb ilyen a processzort is

tartalmazó tégla, de vannak motorokat tartalmazó, nyomás és fény érzékelésére alkalmas téglák is a csomagban.

Page 95:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

67 Created by XMLmind XSL-FO Converter.

A robot a szokásos építkező játékkal készíthető el, például az iménti ábra a RobIGOR névre keresztelt, a II.

Jávácska konferencia [II. JÁVÁCSKA] kabala LEGO robotját mutatja. Az robot megépítését egy PC-n történő

programozási rész követi. A programot grafikus környezetben készíthetik el a gyerekek, majd infra kapcsolaton,

illetve az új csomagban már Bluetooth kapcsolaton vagy USB kábelen keresztül küldhetik át a robotra, hogy

aztán azon futtathassák. A csomag új generációs változata, a LEGO Mindstorms NXT [LEGO

MINDSTORMS], 2006 elejétől elérhető.

De visszatérve a Java történelemhez, az időtengely a másik irányban érdekesebb: a közeli múlt (2004 vége,

2005 eleje) a Java 5, a Tiger. A jelen (2006 nyara) a Java 6, a Mustang. A közeli jövő (2008 második fele) a

Java 7, a Dolphin. Az appendix A Java verziók újdonságai című pontjában bontunk ki majd néhány

szívdobogtató finomságot, amiket majd rögtön alkalmazunk is labirintus példáinkra.

1.2.1.4. A Java OO világ

Már bevezettük: a Java OO világ térképe az API dokumentáció, az osztályok részletes leírásának egy fa

szerkezetbe rendezett rendszere. Érdekessége, hogy a programozás során a programozó által a forrásszövegbe

illesztett dokumentációs megjegyzésekből áll össze böngészhető HTML formátumban. A dokumentációs

megjegyzéseket a /** karakterek kezdte és a */ befejezte részben kell elhelyezni, amiként a következő példa is

mutatja, hogy hogyan kommentezzük be egy osztályunkat, az osztály példányváltozóit és a függvényeket. Ha a

program fejlesztése, írása közben a dokumentálást nem hanyagoljuk el, akkor amikorra a programunk kész,

akkorra egy jól használható dokumentáció is kész.

/**

* A labirintus kincseit jellemző osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.1

* @see javattanitok.labirintus.Labirintus

*/

public class Kincs extends Szereplő {

/** A kincs értéke. */

protected int érték;

/** Megtaláltak már? */

protected boolean megtalálva;

/**

* Létrehoz egy {@code Kincs} objektumot.

*

* @param labirintus amibe a kincset helyezzük.

* @param érték a kincs értéke.

*/

public Kincs(Labirintus labirintus, int érték) {

super(labirintus);

this.érték = érték;

}

Page 96:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

68 Created by XMLmind XSL-FO Converter.

A forrásokból Java platform javadoc nevű programja készíti el a böngészhető dokumentációt a fejlesztett

programunkról, de természetesen a NetBeans-ben is kattinthatunk a: Bulid/Generate Javadoc for... menüpontra.

A NetBeans kapcsán lásd még a A NetBeans integrált fejlesztői környezet használata című pontot!

A bal felső

keretben az osztályokat találjuk, ha kattintással kiválasztunk egyet, akkor ennek a csomagnak az osztályai,

interfészei, kivételei a bal alsó keretben bontódnak ki. Ha itt megintcsak kiválasztunk egy tételt, esetünkben

például a Hős osztályt, akkor annak részleteit a fő frame-ben ismehetjük meg.

Page 97:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

69 Created by XMLmind XSL-FO Converter.

De a Java dokumentáció erejét a következő pontban csodálhatjuk meg igazán.

1.2.1.5. Java SE OO világ

Akkor hát csodáljuk: a http://java.sun.com szájtról letölthető Java SE fejlesztői csomag, teljes nevén a Java

Platform, Standard Edition 6 Development Kit, JDK 6 - most a 6-os verziónál tartunk, mindig figyeljünk, hogy

a legújabbat használjuk! Immár két éves az 5-ös Java, a Tigris, most aktuális Java a 6-os, a Musztáng, de már

várjuk a 7-es Javát, a Delfint. A letöltéssel és a telepítéssel kapcsolatos további részletek tekintetében lásd A

Java telepítése gépünkre című pontot!

Visszatérve a csodáláshoz: a sikeres telepítés után a JDK könyvtárában találhatjuk az src.zip nevű állományt,

amiben megtaláljuk a Java SE OO világ (azaz a Java SE API) összes osztályának forráskódját. Ha nem csupán a

JDK-t töltöttük le, hanem a mellette felkínált dokumentációt is, akkor láthatjuk, hogy ez a dokumentáció éppen

ezekből a forrásokból készült, főleg az imént bemutatott dokumentációs megjegyzések felhasználásával. (Azért

érdemes a JDK mellől rögtön letölteni a dokumentációt is, mert így biztosan a megfelelő verziót használjuk

majd, a letöltés tekintetében lásd a A Java dokumentáció, azaz az API doksi letöltése című pontot!)

1.2.1.5.1. System.out feladat

Nézzük meg, hogy milyen osztálybeli objektum a System osztályban lévő out tag! A választ az imént említett

src.zip java/lang/System.java forrásában találjuk. Ha megvan, majd nézzük meg az API doksiban, azaz

szintén az imént említett, a JDK mellől letölthető dokumentációt is: a bal felső frame-ben java.lang csomagra

kattintás után a bal alsóban Classes-ok alól a System osztályra kattintva a jobb oldali fő frame-ben már

megtaláljuk. Ez utóbbit azért egy képen is megmutatjuk:

A Java SE API már hatalmas, ezért itt nem is teszünk mást, csak néhány olyan csomagjáról szólunk pár szót,

amelyet a későbbi példáink során mi magunk is használni fogunk.

Már tárgyaltuk, hogy az ember mint minden bonyolult dolgot, az API-t is hierarchiába szervezi. Megnéztük,

hogy esetünkben ez a hierarchia a fa szerkezet, aminek gyökere a java. A fában található, a gyökérből kiinduló

utak pedig a csomagok.

A java.lang csomag tartalmazza az Object osztályt, ez az osztály az öröklődés alapján tekintett

osztályhierarchia gyökere, avagy minden Java osztálynak ez az ős osztálya: apja, nagyapja, dédnagyapja,

üknagyapja stb. Így minden osztály örökli például a getClass() metódusát. A getClass() metódus

megmondja az objektumról, hogy mely osztálybeli. (A részleteket gyakorlásképpen nézze meg a kedves Olvasó

az API doksiban!) Lássunk egy példát a metódus használatára:

Page 98:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

70 Created by XMLmind XSL-FO Converter.

Labirintus labirintus = new Labirintus(6, 3);

Hős hős = new Hős(labirintus);

System.out.println(labirintus.getClass());

System.out.println(hős.getClass());

A kódrészlet produkálta output:

class javattanitok.labirintus.Labirintus

class javattanitok.labirintus.Hős

Magunk is próbálkozhatunk, a fenti kódrészletet a javattanitok.labirintus.Labirintus saját indító main()

metódusában találjuk meg.

1.2.1.6. Java ME OO világ

Egy magára valamit is adó mobilt árusító üzletben vagy mobilos katalógusban

ma már nem csupán azt láthatom a készülékek mellett, hogy Java képesek-e, hanem további lényeges

finomságokat is, például MIDP 1.0-ás vagy MIDP 2.0-ás a kiszemelt készülék? Ha megkérdezzük, hogy ez a

rövidítés mit jelent, akkor a választ az Java ME OO világban találjuk. Ebben a világban is minden objektum, így

már nem lehet meglepő, hogy programjaink itt is objektumokból állnak.

Nézzük meg mobilunkon a jegyzetben fejlesztett labirintus programot: egy elegendően magas koncepcionális

nézőpontból éppen egy vászon objektumot látunk. A vászon objektumok arra valók, hogy rajzolni tudjunk a

mobilunk kijelzőjére, most éppen a labirintusunkat láthatjuk rajta. Ha például azt szeretnénk, hogy a szereplők,

mondjuk a hős és a szörnyek valóságosabban mozogjanak, azaz lépkedjenek, akkor a vásznon további

objektumokat, sprite objektumokat is kellene használnunk. A sprite objektumok arra valók, hogy mozgó

dolgokat, például a szereplők animált mozgását készítsük el velük. A mozgások tipikusan animációkból állnak

össze, azaz lerajzoljuk a lépéseket mondjuk 8 fázisban és minden egyes fázist tartalmazó kép a sprite

animációjának egy frame-je lesz... egyelőre ne szaladjunk ennyire gyorsan!

Számtalan rendeltetésű objektumról beszélhetnénk még, de távolodjunk el a fáktól és nézzük az erdőt! A

telefonokon rendelkezésre álló objektumok összességét szabványok foglalják össze, ilyen szabvány a MIDP is.

A mobil téma gyors fejlődése persze magával hozza, hogy idővel egyre több objektum áll rendelkezésre, azaz

mind több és több objektummal gazdagodik ez a világ. Például a sprite objektumok a MIDP 2-ben jelentek meg,

a korábbi MIDP 1-ben még nem voltak, ekkor az animációkkal kapcsolatos apróságokat a programozónak

magának kellett összerakosgatnia, azaz a kép helyére a megfelelő fázist tartalmazó frame-t kirajzolnia.

Page 99:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

71 Created by XMLmind XSL-FO Converter.

Minden objektumnak megvannak a saját belső tulajdonságai (tagjai, példányváltozói, attribútumai) és az

ezekhez a tulajdonságokhoz tartozó saját viselkedési formái (függvényei, módszerei, metódusai, neki küldhető

üzenetei). Az objektumok viselkedési formáikon keresztül tudják változtatni belső tulajdonságaikat (tehát

változóik értékeit) és viszont: a belső tulajdonságok befolyásolják a viselkedést (metódusainak működését).

Például a mobiltelefonok Java Virtuális Gépében élni képes objektumok a MIDlet osztályból származó

objektumok. A MIDlet objektumok rendelkeznek azokkal a tulajdonságokkal és viselkedési formákkal, amik

lehetővé teszik, hogy a mobiltelefonok Java Virtuális Gépében élni, működni tudjanak. Ennek megfelelően, ha

mobiltelefonos programot akarunk készíteni, azaz olyan osztályt, amelyből példányosított objektumom majd a

mobilon futhat, akkor osztályunkkal ezt a MIDlet osztályt kell kiterjesztenünk, mert ekkor a saját osztályom is

kész lesz arra, hogy ebben a speciális környezetben éljen.

Ugyanezt elmondhatnánk a javax.microedition.MIDlet osztály helyett

i. a java.applet.Applet osztályt helyettesítve, ha ez a speciális környezet a webböngésző

ii. a javax.servlet.http.HttpServlet osztályt helyettesítve, ha ez a speciális környezet a webszerver.

Page 100:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

72 Created by XMLmind XSL-FO Converter.

A Java ME API, bár nagyságában

korántsem olyan hatalmas, mint a Java SE API, de a MIDP 2 igen jelentős növekedést hozott, ezért itt sem

teszünk mást, csak néhány olyan csomagjáról szólunk pár szót, amelyet a későbbi példáink során mi magunk is

használni fogunk. A java alól nyíló csomagok: a java.lang, java.util és a java.io a Java SE-ből lettek

leválogatva, tehát ezeknek a csomagoknak a tartalmát ugyanígy a Java SE API is tartalmazza. Erre utalva

hagytuk meg a következő ábrán a korábbi hasonló ábra tetejét. A javax alól nyíló csomagok közül csak a

javax.microedition.midlet, javax.microedition.lcdui csomagokat és a

javax.microedition.lcdui.game alcsomagot tüntettük fel.

1.2.1.6.1. MIDlet feladat

Az API doksiban (telepítésével kapcsolatban lásd a A Java dokumentáció, azaz az API doksi letöltése című

pontot) nézzük meg a javax.microedition.midlet csomagban található MIDlet osztály startApp(),

pauseApp(), destroyApp() módszereit! Milyen módosítókkal rendelkeznek?

Ezek a metódusok az absztrakt jelzővel vannak ellátva, ez azt jelenti, hogy ha ezt az osztályt kiterjesztjük, azaz

valamely saját osztályunkat ebből örököltetjük, akkor ezeket a metódusokat mindenképpen, akár üres törzzsel is,

de felül kell definiálnunk. E három metódus a MIDlet osztály életciklus metódusai, velük vezérelhetjük,

segíthetjük a mobilos objektumunkat, hogy meg tudjon élni az idegen környezetben. Mely környezet abban az

Page 101:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

73 Created by XMLmind XSL-FO Converter.

értelemben idegen, hogy fő célja nem biztos, hogy a mi alkalmazásunk futtatása, mert például programunkat

bármikor félbeszakítathatja egy éppen bejövő hívás vagy SMS. Az alábbi, a

javattanitok.LabirintusMIDlet MIDlet osztályból kiragadott kódrészlet azt mutatja, hogy a pauseApp()

módszert csupán üres testtel definiáltuk felül, ami azt is jelenti, hogy nem akarunk a programunkkal reagálni az

előbb említett, de a mobil platformon természetesen szokásos eseményekre. A startApp() metódusban viszont

dolgozunk, kitesszük a képernyőre labirintusunk már korábban elkészített vásznát.

public void startApp() {

// A kijelzőn a labirintus vászon legyen látható

kijelző.setCurrent(labirintusVászon);

}

public void pauseApp() {

}

A saját MIDlet (a MIDlet osztályból származó, azaz mondhatjuk, hogy MIDlet) osztályunk konstruktorának

lefutása után hívódik meg a startApp() metódus, ezzel a MIDlet objektumunk aktív állapotba került. Ebből az

állapotból időlegesen a pauseApp() módszer viheti ki, véglegesen pedig a destroyApp() módszer. Ennek

megfelelően vegyük figyelembe, hogy a startApp() metódus MIDlet objektumunk (programunk) élete során

többször is lefuthat. Ez konkrétan azt jelentheti - feltéve továbbá, hogy a labirintust és az azt kirajzoló vásznat a

startApp() metódusban hoznánk létre - hogy a játékos már javában labirintusozik, amikor érkezik egy bejövő

telefonhívás: meghívódik a pauseApp(), a játékos felveszi vagy sem, de amikor visszatér a játékhoz, akkor a

startApp() metódus hívódik meg és feltételünk értelmében újra elkészíti a labirintust. Tehát a játékos a régi

játékát gyakorlatilag elveszítette és egy új labirintussal újra kell kezdenie...

Az javax.microedition.lcdui csomag tartalmazza a GUI interfésszel kapcsolatos osztályokat, ezek a

szokásosak: űrlapok, nyomógombok, szövegbeviteli mezők stb. A javax.microedition.lcdui.game

alcsomag már kimondottan a játékfejlesztőket segíti. Többek között itt találhatjuk a Sprite osztályt is. A

GameCanvas egy olyan vászon, amiben egyben a játék időfejlődését is meg tudjuk adni. A későbbiek során erre

majd látjuk a példaprogramot: a LabirintusMIDlet és a LabirintusVaszon osztályainkat.

1.2.2. Objektumok mindenütt: a CORBA OO világ

A CORBA programozó a napjainkban elérhető legmagasabb szoftveres absztrakciós szinten dolgozik. Számára

az objektumok közötti kapcsolattartás immár transzparens. Ha a fejlesztő valamely CORBA objektum

szolgáltatását szeretné igénybe venni, azaz az objektum valamely metódusát meghívni, akkor csupán a CORBA

objektum referenciáját kell megszereznie és innentől a megszokott módon a kívánt szolgáltatásnak megfelelő

metódusát meghívnia. Megfordítva, ha a programozó egy szolgáltatást kíván nyújtani, akkor elég csupán a

szolgáltatásra magára koncentrálva megírnia a megfelelő CORBA objektumot. Mindkét esetben csakis a

szolgáltatásra kell koncentrálni, akár igénybe venni, akár szolgáltatni akarjuk azt. Hogy az objektumok

fizikailag hol vannak, az nem lényeges. Sőt még az sem lényeges, hogy ezeket a CORBA objektumokat milyen

programozási nyelven implementálja a fejlesztő. Természetesen mi a legjobb választással élve, Java nyelven

valósítjuk majd meg a példaként szolgáló CORBA objektumainkat.

Page 102:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

74 Created by XMLmind XSL-FO Converter.

Hogyan érjük el a szoftveres absztrakció ilyen magas fokát? Úgy, hogy a CORBA világában szereplő

objektumokat mindig egy interfészen, az objektum IDL (Interface Definition Language)interfészén keresztül

látjuk. Olyannyira mindig, hogy már magának a CORBA alapú rendszernek a tervezésekor is ezekben az

interfészekben gondolkozunk. Mert a CORBA objektumoknak olyan tulajdonságaik és viselkedéseik vannak,

amiket ezek az interfészek specifikálnak. Praktikusan egy CORBA objektum ORB brókeren keresztül elérhető

módszerei az objektum IDL interfészében definiált módszerek. További tárgyalásunkban a Java keretein belülre

szorítkozva: a Java platform biztosít olyan eszközöket - például az idlj fordítót - amik az IDL interfész

definíciókat Java nyelvre fordítják. Ezután nincs más dolgunk, mint az IDL interfészben megnevezett

metódusok - esetünkben Java nyelvi - megvalósítása.

Példaként nézzük meg, hogy CORBA labirintusos esettanulmányunkban miként fogalmazzuk majd meg, hogy a

szereplők a labirintus valamely oszlopában és sorában vannak. A labirintus hőse a labirintus egy olyan

szereplője, aki gyűjtögeti a labirintusban megtalált értékeket, van valahány élete, amik bizony akár el is

fogyhatnak:

interface Szereplo

{

attribute long oszlop;

attribute long sor;

};

interface Hos : Szereplo

{

attribute long megtalaltErtekek;

readonly attribute long eletek;

void megtalaltam(in Kincs kincs);

boolean megettek();

};

A CORBA objektumokat leíró IDL interfész definíciója az interface kulcsszóval kezdődik, amit a név, majd

nyitó és záró kapcsos zárójelek közé zárt példány- és módszerdeklarációk követnek. Az interfészek közötti

öröklődési kapcsolatot a kettőspont jelöli. Az attribute kulcsszóval kezdődik a példányok deklarációja. A

Page 103:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

75 Created by XMLmind XSL-FO Converter.

CORBA objektumnak majd minden példányához implementálnia kell egy lekérdező és egy beállító metódust,

illetve a readonly taghoz csak egy lekérdezőt. Az in szócska arra utal, hogy a kincs a CORBA objektum

bemenő adata.

Az imént említett példa egyébként része a Elosztott objektumok - Elosztott labirintus című ponthoz készített

CORBA objektumok IDL interfészeit tartalmazó elosztott.idl állománynak.

Az interfészek elkészítése után az említett idlj fordítóval elvégezzük a megfelelő Java nyelvi leképezést

C:\...> idlj -fall -falltie elosztott.idl

a parancsban felhasznált -fall -falltie kapcsolók arra utalnak, hogy mely kapcsolódó Java forrásokat, mely

CORBA objektum implementálási stratégia mentén kívánjuk legeneráltatni. A legenerált Java forrásokra -

esetünkben egy ilyen például a HosOperations.java állományra - támaszkodva implementáljuk a CORBA

objektum metódusait:

public class HősKiszolgáló

extends SzereplőKiszolgáló

implements HosOperations {

...

/**

* Jelzi, hogy éppen megettek.

*

* @return true ha a hősnek még van élete, ellenkező esetben,

* azaz ha az összes élete elfogyott már, akkor false.

*/

public boolean megettek() {

if(életekSzáma > 0) {

--életekSzáma;

return false;

} else

return true;

}

/**

* Gyüjtögeti a megtalált kincseket.

*

* @param kincs amit éppen magtalált a hős.

Page 104:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

76 Created by XMLmind XSL-FO Converter.

*/

public void megtalaltam(Kincs kincs) {

megtaláltÉrtékek += kincs.ertek();

}

és persze az IDL interfészben specifikált megtaláltErtekek taghoz készítünk egy lekérdező és egy beállító

módszert és az eletek taghoz egy lekérdezőt, mivel ez csak olvasható tagnak specifikáltuk. Ezek után jöhet a

klasszikus fordítás, majd a futtatás, de mindezzel a Elosztott objektumok - Elosztott labirintus című pontban

folytatjuk.

1.3. Az internet, a programozó tágabb hazája

„A gépek ilyenformán szakadatlanul együttműködő egységet alkotnak, s e nagy egységen

belül a nyilvántartott adatok és ellentmondások folytonos változása szükségszerűen megy

végbe.” —Wigner Jenő

Az internet megjelenéséig programjaink csak egy adott számítógépben éltek, léteztek. Napjainkban viszont már

olyan programokat is írhatunk, amik egy absztraktabb szinten sokkal tágasabb lakhelyet tudhatnak magukénak:

számos, a legkülönfélébb módon összekapcsolt mindenféle számítógép hálózatát.

Tekintsük például a SETI@Home projektet [SETI HOME], melyben az arecibói rádióteleszkóp vette adatokat

szétosztják az interneten keresztül jelentkező lelkes felhasználók között, akik gépidejükből szánnak a

SETI@Home projekttől kapott részadatok elemzésére. Olyan jeleket keresnek a rádióháttérben, amik idegen

civilizációk üzenetei lehetnek. Ezen a számításon a SETI@Home projekt sok millió felhasználója osztozik! (A

SETI témában általában a már eddig is többször hivatkozott [KAPCSOLAT REGÉNY] elolvasását javasoljuk

érzelmi megalapozásként az érdeklődő Olvasónak.)

A gépek hálózatának szoftveres alapja a 1969 végétől négy amerikai; az UCLA, UCSB, SRI és az utah-i

egyetemek között kiépülő és ébredő ARPANET hálózatra fejlesztett TCP/IP hálózati szoftver.

1.3.1. TCP/IP

„...míg az Internet szabványosítási konferencián a résztvevők farmert viselnek (kivéve a San

Diegóban megrendezett találkozókat, amikor rövidnadrágot és pólót).” —Andrew S. Tanenbaum

Page 105:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

77 Created by XMLmind XSL-FO Converter.

1. A fizikai réteg nem a programozók, inkább a mérnökök világa. Tipikusan mérnöki kérdések merülnek fel,

mert a réteg feladata a gépek valódi, fizikai összekapcsolása. Az e feletti rétegekre viszont már mint

szoftverekre gondoljunk.

2. A hálózati rétegben megjelenik az IP szám, amivel illetni tudunk egy gépet, pontosabban egy, a gépben lévő

hálókártyát.

3. A szállítási rétegben lehetővé válik egy IP számon belül disztingválni. Attól függően, hogy a „Megbízható

kommunikációt akarunk?” kérdésre a válasz igen, akkor 0-65535 számú TCP kapunk van. Ha a válasz nem,

akkor ugyanennyi UDP kapu.

4. Az alkalmazási rétegben találjuk az olyan ismert protokollokat, mint a HTTP - az internetes böngészés, vagy

az SMTP - az internetes levelezés protokollja. A továbbiakban mindkét említettel, demonstrációs céllal

részletesebben is foglalkozunk majd.

1.3.2. A kliens-szerver modell

A szerver az a program, aki valamilyen szolgáltatást nyújt, a kliensek pedig azok a programok, akik ezeket a

szerverek nyújtotta szolgáltatásokat igénybe veszik.

Nézzünk példákat sikeres szolgáltatásokra, azaz olyanokra, amik külön kaput (well-known port, jól ismert

portot) is kaptak szolgáltatásuk nyújtására. Ezek a kapuk az 1024 alatti tartományból kerülnek ki, a

http://www.iana.org/assignments/port-numbers címen, vagy Linuxunkon a /etc/services állományban lehet

csemegézni, hogy melyek is ezek.

[norbi@niobe ~]$ more /etc/services.

.

.

ftp 21/tcp

ftp 21/udp fsp fspd

ssh 22/tcp # SSH Remote Login Protocol

ssh 22/udp # SSH Remote Login Protocol

.

.

.

smtp 25/tcp mail

smtp 25/udp mail

.

.

.

http 80/tcp www www-http # WorldWideWeb HTTP

http 80/udp www www-http # HyperText Transfer Protocol

.

.

.

1.3.3. Bepillantás az alkalmazási rétegbe: a HTTP protokoll

Dolgozzunk egy kicsit az alkalmazási réteg szintjén, nézzük meg Linuxunkon működés közben a HTTP

protokollt! Fut a gépünkön a webszerver folyamat? Ezt egyszerű felhasználóként is megnézhetjük a webszerver

(http démon) SysV indítószkriptjének status kapcsolójával:

[norbi@niobe ~]$ /etc/rc.d/init.d/httpd status

A(z) httpd le van állítva

tehát nem megy. Futtassuk, mert vele tudunk majd TCP/IP-n keresztül HTTP párbeszédet folytatni.

Rendszergazdaként tudjuk lefuttatni a webszerver megfelelő elindítását elvégző szkriptet a start kapcsolóval

Page 106:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

78 Created by XMLmind XSL-FO Converter.

[root@niobe ~]# /etc/rc.d/init.d/httpd start

httpd indítása: [ OK ]

Megint csak egyszerű felhasználóként lépjünk kapcsolatba a gépünkön a 80-as TCP kapun a kliensek

kapcsolatfelvételeire váró webszerver folyamattal és kérjük el tőle a webterület gyökerének index.html

állományát:

[norbi@niobe ~]$ telnet localhost 80

Trying 127.0.0.1...

Connected to localhost.localdomain (127.0.0.1).

Escape character is '^]'.

a telnet programot, most mint TCP kliens programot használjuk arra, hogy TCP csatornán keresztül tudjunk

kommunikálni a webszerverrel. Össze kell állítanunk a HTTP kérést! Ennek első sora, hogy GET, azaz

szeretnénk elkérni a webterület gyökeréből az index.html állományt és mellesleg a HTTP/1.0 protokollt

beszéljük:

[norbi@niobe ~]$ telnet localhost 80

Trying 127.0.0.1...

Connected to localhost.localdomain (127.0.0.1).

Escape character is '^]'.

GET /index.html HTTP/1.0

Az első sort követhetik kulcs-érték párok, ha valamit szeretnénk közölni a szerverfolyamattal, de mivel most

semmit, jöhet a kérés törzse, ami most megint csak legyen üres, így gyakorlatilag két entert nyomunk és máris

jön a HTTP válasz a szervertől:

[norbi@niobe ~]$ telnet localhost 80

Trying 127.0.0.1...

Connected to localhost.localdomain (127.0.0.1).

Escape character is '^]'.

GET /index.html HTTP/1.0

HTTP/1.1 200 OK

Date: Sun, 10 Sep 2006 08:20:31 GMT

Server: Apache/2.2.0 (Fedora)

Last-Modified: Sun, 10 Sep 2006 08:17:16 GMT

ETag: "158540-6f-41d1511bd9b00"

Accept-Ranges: bytes

Content-Length: 111

Connection: close

Content-Type: text/html; charset=UTF-8

<html>

<head>

<title>Hello, Javat tanitok!</title>

</head>

<body>

Hello, Javat tanitok!

</body>

</html>Connection closed by foreign host.

Page 107:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

79 Created by XMLmind XSL-FO Converter.

A HTTP válasz első sora a protokoll, amit a szerver beszél, aztán a válasz kódja és rövid szöveges feloldása:

most OK, azaz OK! Ezt követi mindenféle kulcs-érték pár, majd a válasz testébe csomagolva a kért állomány. Ez

történik a háttérben, amikor böngészünk. Ha például egy honlapon egy pdf állományra kattintunk, akkor a

válaszban a küldött tartalom Content-Type: application/pdf típusa ez lenne, innen tudja majd a böngésző,

hogy nyitni kell a pdf megjelenítőt.

Persze ugyanezt Windows alatt is megnézhetjük egy Start/Kellékek/Parancssor parancsablakból, ha egy

webszervert futtató gép 80-as kapujára csatlakozunk:

C:\Documents and Settings\norbi>telnet www.inf.unideb.hu 80

Figyelmeztetés a Javaban kezdő Olvasóknak

A következő példa megint csak nem a teljesen kezdő Javasoknak szól, ők szokás szerint ugorják át és

majd például a Az első Java tapasztalatok című pont után térjenek ide vissza.

1.32. példa - Port szkennelő példa

Dolgozzunk egy kicsit az szállítási réteg szintjén! Írjunk egy a socket programozás absztrakciós szintjére

helyezhető példát!

Írjunk egy rövid példát, ami megnézi, hogy gépünk éppen milyen portokat figyel.

public class KapuSzkenner {

public static void main(String[] args) {

for(int i=0; i<1024; ++i)

try {

java.net.Socket socket = new java.net.Socket(args[0], i);

System.out.println(i + " figyeli");

socket.close();

} catch (Exception e) {

System.out.println(i + " nem figyeli");

}

}

}

Page 108:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A programozásról

80 Created by XMLmind XSL-FO Converter.

A program végigzongorázza a parancssorában megkapott nevű gép 1024 alatti számú TCP kapuit: megpróbál

egy TCP kapcsolatot

java.net.Socket socket = new java.net.Socket(args[0], i);

létrehozni, ha sikerül, akkor a célporton ül egy szerver folyamat, ha nem, azaz ha kivétel keletkezik, akkor nem.

Egyébként siker esetén sem csinálunk semmit, hanem csak bezárjuk az éppen elkészített kliensoldali

kommunikációs végpontot reprezentáló socket objektumot.

[norbi@omega ~]$ java KapuSzkenner niobe

.

.

.

19 nem figyeli

20 nem figyeli

21 figyeli

22 figyeli

23 nem figyeli

24 nem figyeli

25 figyeli

26 nem figyeli

.

.

.

79 nem figyeli

80 figyeli

81 nem figyeli

82 nem figyeli

.

.

.

Csak saját gépre

Fontos, hogy ezt a kapufigyelő programunkat ne szabadítsuk rá az internetre, azaz ne engedjük rá

tetszőleges gépre, hanem csak az otthonira. Mert egy túlérzékeny rendszergazda még (jogosan) úgy

érezné, hogy támadás fenyegeti a gépét. Ha ilyen gépen akarjuk kipróbálni, például az iskolában, azt

előtte beszéljük meg a megfelelő rendszergazdával.

1.33. példa - Jól ismert portok feladat

Milyen szolgáltatások futnak a fent leportszkennelt gépen?

Page 109:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

81 Created by XMLmind XSL-FO Converter.

2. fejezet - Saját világok teremtése és Java alapok

„Döcögő egyetértés és futó programok” — David Clark [HÁLÓZATOK KÖNYV] [INTERNET REGULATION]

„A tigrist előbb gondolatban el kell ejteni - a többi formalitás” — Konfuciusz

Az OO programozó mentális világokat teremt, mint ahogyan mi is ezt fogjuk tenni ebben a fejezetben.

Kifejlesztünk egy labirintus API interfészt, azaz megteremtjük a saját labirintus játékunk képzeletbeli világát. S

e fejlesztési munka során ismerkedünk meg a Java OO programozás alapjaival. Itteni munkánk gyümölcse, a

kifejlesztett labirintus API szolgál majd a következő fejezetek fejlesztendő esettanulmányainak alapjául.

Ebben a gyakorlati programozási részben

• elkezdünk egy saját labirintus OO világot teremteni

• miközben megismerjük az OO és konkrétan a Java OO programozás alapfogalmait

1. A Java világa

„Fel hát csatázni, fel hát lelkesülni

Az új tanért. Alkotni új világot,”

—Madách Imre Az ember tragédiája

Lépjünk hát be a Java világába! Első lépésünk a Java SE, ME fejlesztői csomag telepítése, beállítása legyen. Itt

általános szabály, hogy mindig a legfrissebb verziójú Java SE, ME fejlesztői csomagokat használjuk. A Java

telepítése gépünkre pontban részletes segítséget adunk a letöltésről, telepítésről és az esetleges további

beállításokról mind a Windows, mind a Linux operációs rendszereket futtató Olvasóknak egyaránt.

A továbbiakban tehát feltesszük, hogy a megfelelő Javát az előző bekezdés hivatkozta pont értelmében

beállítottuk és egyik kezünk mindig a billentyűzeten...

1.1. A Java nyelv

Minden programhoz kapcsolható egy sajátos világ, egy mikrokozmosz.

A kisebb, egyszerűbb programok esetén ez a mikrokozmosz általában nem külön létező, hanem csupán egy már

létező világ parányi, kiragadott része. Erre példaként tekintsük azt a szokásos C programot, ami a sztenderd

inputját másolja a sztenderd outputjára és a bemenet vége jelre kilép.

Figyelmeztetés a C-ben járatlan Olvasóknak

Az alábbi széles körben elterjedt, szokásos C bevezető példa a hasonló szerkezetű és működésű Java

példát vezeti be, rövid átfutása után akár át is ugorható.

#include <stdio.h>

int

main (void)

{

int c;

while ((c = getchar ()) != EOF)

putchar (c);

Page 110:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

82 Created by XMLmind XSL-FO Converter.

return 0;

}

Az Olvasó az alábbi módon fordíthatná és futtathatná ezt a masol.c forrásállományba illesztett másoló kódot.

[norbi@niobe ~]$ gcc masol.c -o masol

[norbi@niobe ~]$ ./masol

q

q

w

w

e

e

r

r

t

t

A gcc fordítóval lefordítottuk a masol.c forrást és a fordítás eredményéül kapott bináris futtatható állományt a

masol nevű állományba tetettük a fordító -o kapcsolójának segítségével. Majd az aktuális könyvtárból, azaz a

./állománynév alakban futtattuk a masol nevű állományt. A futás alatt a billentyűzetről beütött és enterrel

kísért q, w, e, r, t karaktereket a program a kimenetén, azaz a képernyőn visszhangozta, egészen a bemenet

vége, azaz a Ctrl+d billentyűkombináció megnyomásáig.

Ennek a C programnak a világát az stdin - most a billentyűzet, az stdout - most a képernyő, a UNIX világból

ismerős elemei, továbbá az egész számok, köztük az EOF jelnek megfelelő szám alkotják. Ebben a világban a

program szerint az történik, hogy számot olvasunk a program stdin bemenetről a getchar() függvénnyel és

írjuk a program stdout kimenetre, s mindaddig folytatjuk ezt, amíg az EOF számot nem olvassuk a bemeneten.

Hogyan fest az iménti C kódnak megfelelő Java program mikrokozmosza?

public class Másol {

public static void main(String[] args) throws Exception {

int i = 0;

while((i=System.in.read()) != -1)

System.out.printf("%c", i);

}

}

Az Olvasó az alábbi módon fordíthatná és futtathatná ezt a Másol.java forrásállományba illesztett másoló

osztályt.

[norbi@niobe ~]$ javac Másol.java

[norbi@niobe ~]$ java Másol

q

q

w

w

e

e

r

r

t

t

Page 111:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

83 Created by XMLmind XSL-FO Converter.

A javac fordítóval lefordítottuk a Másol.java forrást, a fordítás eredményéül kapott bináris bájtkód állományt

a Másol.class nevű állományba kaptuk. Amit a java Másol parancs kiadásával - a .class kiterjesztést soha

nem, mindig csupán az osztálynevet kiírva - adtunk át bemenetként a Java Virtuális Gépnek. A futás alatt

ugyancsak a billentyűzetről beütött és enterrel kísért q, w, e, r, t karaktereket a program a kimenetén, azaz a

képernyőn visszhangozta, egészen a bemenet vége, azaz a Ctrl+d billentyűkombináció megnyomásáig.

Ennek a Java programnak a világát csatornák, a System.in sztenderd bejövő és a System.out sztenderd

kimenő csatornák alkotják. Egészen pontosan a System osztály InputStream típusú in és PrintStream típusú,

azaz PrintStream osztálybeli out változója vagy tagja. Ezen felül a működés pedig megegyezik az imént

tárgyalttal annyi kiegészítéssel, hogy a System.in bejövő csatorna read() függvénye a -1 érték visszaadásával

jelzi a csatorna végét.

A nagyobb, bonyolultabb programok esetén maga a program, azaz a programozó építheti fel a mikrokozmoszt.

Példaként tekintsünk egy labirintus játék programot, amiben a világ maga a labirintus, kincsestől, szörnyestől,

hősöstől és a szokásos történik: a hős bolyong, a szörnyek próbálják megenni, a kincs várja, hogy rábukkanjanak

stb.

Az OO programozás ereje abban rejlik, hogy a programozó a fejlesztés során arra van utalva, hogy saját

világokat építsen, teremtsen! Építőelemei a választott OO platform API interfészének osztályai, habarcsa pedig

maga a választott OO nyelv.

A következőkben a Java nyelvvel egy labirintus játék világának felépítése során ismerkedünk meg.

1.1.1.

1.1.1.1.

1.1.1.1.1. Saját labirintus feladat

2.1. példa - Saját labirintusunk elképzelése

Mindenki képzelje el saját labirintusát! Egy négyzethálós lapon készítsünk vázlatos rajzot a szerkezetéről,

foglaljuk össze írásban, mik vannak egy labirintusban!

Mi a labirintusunkat a következőképpen képzeljük el.

Ez egy 10 cella széles és 10 cella magas labirintus. A falat tégla színnel jelöltük, a járatot világossárgával.

Persze olyan is lehetne, hogy jóval nagyobb labirintust készítenék és azt, hogy egy cella éppen járat vagy fal

véletlenül döntenénk el: minden egyes ilyen döntésnél fej vagy írás érmét használnánk, de legalábbis egy ennek

megfelelő véletlenszám generátort, azaz egy olyan programot (vagy éppen csak egy java.util.Random

osztálybeli objektumot) ami a fej vagy írás dobálást szimulálja.

Aztán legyenek a labirintusban kincsek, szörnyek és maga a hős. Sok értékes kincs, kevés szörny és egy hős. A

játék, hogy a hőssel minél gyorsabban össze kell gyűjteni a kincseket, miközben pedig el kell kerülni a

szörnyeket. A kincsek és a szörnyek minden játékban máshonnan induljanak!

Page 112:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

84 Created by XMLmind XSL-FO Converter.

1.1.2. Osztályok és objektumok

Milyenek is a labirintusok, milyen is a mi, az előző pontban elképzelt labirintusunk? Gyűjtsük most össze a

lényeges jellemzőit, tulajdonságait, részeit! Majd ezt követően Java nyelven írjuk le!

Mindenekelőtt a labirintusnak van mérete: szélessége és hosszúsága. Ez két szám, két egész szám. Javaban az

egész értékeket így írjuk le:

int szélesség;

int magasság;

és úgy olvassuk, hogy a szélesség és a magasság int típusú változók. Ezeknek a változóknak az értéke az előző

labirintus példánál maradva 10 és 10.

A labirintus lényegéhez tartozik a szerkezete, azaz, hogy hol van fala. Mert ahol nincs, ott ugye járata van. Ezt a

labirintus elképzelése során, a négyzethálós lapon egy kétdimenziós tömb alakjában rajzoltuk le. Javaban ha

nem egyetlen számot akarunk reprezentálni, hanem számok ilyen szabályos elrendezését, tömbjét, akkor ezt

írjuk:

int[][] szerkezet;

ahol a [5][6] majd például azt mondja meg, hogy az 5. sor 6. oszlopában fal van vagy járat, azaz az itt lévő

szám 0 vagy 1, most éppen járat, azaz 0. Az ábrán egyben azt is észrevételezhetjük, hogy a Java tömbök

elemeinek indexelése, azaz sorszámozása nullától indul.

Page 113:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

85 Created by XMLmind XSL-FO Converter.

Mivel labirintus terünk olyan, hogy itt csak ez a két érték jöhet szóba, az int típus használata jelen esetben

pazarló, mert az int értéke nem csupán 0 vagy 1 lehet, hanem a -231 számtól a 231-1 számig bármi, ami

búzaszemben nem olyan sok, mintha egy szemből indulva a sakktábla minden cellájában megdupláznánk a

szemeket, de azért jó nagy.

Használjunk helyette boolean típust, mert ennek csupán két értéke lehet: a hamis - Javaban false - vagy az igaz

- true. Esetünkben a tervben szereplő 0 értéket képzeljük a false boolean értéknek, az 1 értéket true boolean

értéknek. Ekkor a

boolean[][] szerkezet;

tömb [5][6] eleme majd arra a kérdésre válaszol, hogy fal van-e ezen a helyen a labirintusunkban?

A válasz hamis, azaz nem fal van ott, hanem járat.

Foglaljuk most össze, hogyan írtuk le labirintusunkat:

int szélesség;

int magasság;

boolean[][] szerkezet;

Java nyelven a fejlesztendő programunk világabeli dolgok tulajdonságait osztályokba foglalva írjuk le. Az

osztálynak van neve, ez utaljon magára arra a dologra, amit az osztály le akar írni és megegyezés szerint

kezdődjék nagy első betűvel. Ha több szóból áll, akkor minden alkotó rész szó kezdődjék nagy első betűvel. A

mi labirintus osztályunkat nevezzük egyszerűen Labirintus osztálynak és tartalmazza tehát azokat az általános

jellemzőket, amit a labirintusról éppen most összeszedtünk. A név elé írjuk a class kulcsszót, majd az osztály

nevét, végül az osztály tulajdonságait foglaljuk nyitó és záró kapcsos zárójelek közé.

class Labirintus {

int szélesség;

int magasság;

boolean[][] szerkezet;

}

Megvan általában a labirintusunk leírása, de nekünk egy konkrét játékban egy konkrét labirintusra lesz

szükségünk, azaz egy a Labirintus osztályból származó konkrét labirintusra, egy labirintus objektumra. Azt a

folyamatot, amikor egy osztályból konkrét példányt, egy objektum példányt hozunk létre, példányosításnak

Page 114:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

86 Created by XMLmind XSL-FO Converter.

nevezzük. A példányosítást egy speciális függvény, a konstruktor végzi. De mielőtt tovább folytatnánk,

elöljáróban következzék még néhány gondolat. A Java nyelv, bármennyire is csodálatos nyelv, de mégiscsak

egy nyelv. A következő pontban - egy rövid kitérő erejéig - ennek megfelelően közelítünk majd a Java

programozási nyelvhez. Ebben a tárgyalásban a beszélt nyelvek - mint például a magyar nyelv - felől közelítünk

a pogramozási nyelvhez, mint ahogyan hasonlóan ezt a megközelítést követtük - az egyébként gyermekeknek

szánt - [FANTASZTIKUS PROGRAMOZÁS] könyvben is. Csak érdekességként jegyezzük meg, hogy a

fordított folyamat, amely során a programozási nyelvek világa felől közelítünk a beszélt nyelvekhez, Noam

Chomsky nyelvész munkássága nyomán [CHOMSKY NYELVOSZTÁLYOK] ma az egyik legalapvetőbb

informatikai és fontos nyelvészeti diszciplina.

1.1.3. A programozás világnyelve a Java

A Java nyelv nem beszélt, hanem írott nyelv, amin a programozók „beszélnek”, azaz írnak. A Java nyelvnek

napjainkra három nagy nyelvjárása alakult ki, ezek a Java ME, a Java SE és a Java EE. Az ME (a Micro Edition

- mikro kiadás) a mobiltelefonokat programozók közösségében terjedt el, az EE (az Enterprise Edition - vállalati

kiadás) az ipari szférában hódít, az SE (a Standard Edition - általános kiadás) pedig az a közös gyökér, amiből

ezek a dialektusok mára kifejlődtek. De ne becsüljük le a Java SE-t, mert a Java SE API hatalmas. Csak egy

példával érzékeltetve: a Java nyelven implementáló CORBA programozó is a Java SE nyelvjárást beszéli! Ami

ezeket a nyelvjárásokat elidegeníthetetlenül összeköti, az maga a Java nyelv, a Java nyelv nyelvtana.

1.1.3.1. A Java nyelvtana

A Java nyelvben használt betűk lehetnek akár ékezetesek is, mert a Java forrásállományokban tetszőleges

Unicode karaktereket felhasználhatunk. Az egymás után írt betűket szavaknak nevezzük.

1.1.3.1.1. A Java szófajok

A Java szavak háromfélék lehetnek, ezek a

• kulcsszavak

• az azonosító szavak

• és a kifejezés szavak.

A Java szófajok legegyszerűbbike a kulcsszó, mert a Java kulcsszavak véges kevesen vannak. Könnyen

megadhatjuk őket egy egyszerű felsorolással. Ezt a felsorolást azzal segítjük, hogy a kulcsszavakat további

három alszófajba osztjuk, ezek a

• melléknevek

• a típus nevek

• és a vezérlő nevek

Figyelmeztetés a Javaban kezdő Olvasóknak

A következőkben valódi Java forráskódrészletek következnek. Ne értelmezni próbáljuk ezeket, hanem

csupán az említett szavak előfordulásait figyeljük meg bennük!

A Java melléknevek a következők:

• static jelentése, hogy nem példányhoz, hanem osztályhoz tartozó. Például a Labirintus osztálybeli

/** Normál működés, a hőssel időközben semmi nem történt. */

public static final int JÁTÉK_MEGY_HŐS_RENDBEN = 0;

sorok azt jelentik, hogy a JÁTÉK_MEGY_HŐS_RENDBEN egész típusú változó statikus, azaz nem a Labirintus

osztálybeli példányokhoz, hanem magához a Labirintus osztályhoz tartozik. Nem minden labirintus

Page 115:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

87 Created by XMLmind XSL-FO Converter.

objektumnak van meg ez az egész típusú változója, hanem az esetlegesen létrehozott több labirintus

objektumnak van egy közös JÁTÉK_MEGY_HŐS_RENDBEN nevű változójuk. Tehát - akár a Labirintus

osztályból való példány létrehozása nélkül - az osztálynévvel minősítve, a

Labirintus.JÁTÉK_MEGY_HŐS_RENDBEN formában használhatjuk ezt a változót. Így teszünk például a

LabirintusJáték osztályban:

switch(labirintus.bolyong(hős)) {

case Labirintus.JÁTÉK_MEGY_HŐS_RENDBEN:

break;

ahol a program szövegrészlet azt mondja, hogy a hős labirintusbeli bolyongása során nem csinálunk semmit,

ha a hőssel nem történik semmi.

• final jelentése, hogy nem módosítható. Például az előző Labirintus osztálybeli példánál maradva a

/** Normál működés, a hőssel időközben semmi nem történt. */

public static final int JÁTÉK_MEGY_HŐS_RENDBEN = 0;

sorokban a final melléknév azt jelenti, hogy a JÁTÉK_MEGY_HŐS_RENDBEN nem módosítható a futás során.

Ez azt jelenti, hogy a JÁTÉK_MEGY_HŐS_RENDBEN = 42; értékadást tartalmazó programot a fordító le sem

fordítja, hanem hibát jelez, mert a változót nem módosíthatónak mondtuk!

C:\...\Munkakönyvtár>javac javattanitok\labirintus\Labirintus.java

javattanitok\labirintus\Labirintus.java:44: cannot assign a value

to final variable JÁTÉK_MEGY_HŐS_RENDBEN

JÁTÉK_MEGY_HŐS_RENDBEN = 42;

^

1 error

• public jelentése, hogy bárhonnan látható. Próbáljuk ki, hogy az imént, a Labirintus osztályból idézett

sorokból kihagyjuk a public melléknevet:

/** Normál működés, a hőssel időközben semmi nem történt. */

static final int JÁTÉK_MEGY_HŐS_RENDBEN = 0;

Az így módosított javatanitok.labirintus csomagbeli labirintus API-val már nem fog lefordulni például

a javatanitok csomagbeli, a javatanitok.labirintus.Labirintus osztályt használó

LabirintusVilág program, mert nem látja az immár nem publikus tulajdonságú JÁTÉK_MEGY_HŐS_RENDBEN

tagot:

C:\...\Munkakönyvtár>javac javattanitok\LabirintusVilág.java

javattanitok\LabirintusVilág.java:83: JÁTÉK_MEGY_HŐS_RENDBEN is not public

in javattanitok.labirintus.Labirintus; cannot be accessed from outside package

case Labirintus.JÁTÉK_MEGY_HŐS_RENDBEN:

^

1 error

Page 116:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

88 Created by XMLmind XSL-FO Converter.

• private jelentése, hogy csak a saját osztályában látszik. Például az előző pont módosításához hasonlóan

végezzük el az alábbi átalakítást:

/** Normál működés, a hőssel időközben semmi nem történt. */

private static final int JÁTÉK_MEGY_HŐS_RENDBEN = 0;

ennek megfelelően fordításkor az alábbi hibát kapjuk:

C:\...\Munkakönyvtár>javac javattanitok\LabirintusVilág.java

javattanitok\LabirintusVilág.java:83: JÁTÉK_MEGY_HŐS_RENDBEN has private access

in javattanitok.labirintus.Labirintus

case Labirintus.JÁTÉK_MEGY_HŐS_RENDBEN:

^

1 error

ha ragaszkodnánk a privát tulajdonsághoz, akkor ezt a hibát csak úgy háríthatnánk el, ha csakis a

javatanitok.labirintus.Labirintus osztályban használnánk a továbbiakban a

JÁTÉK_MEGY_HŐS_RENDBEN tagot.

• protected jelentése, hogy csak a saját és a leszármazott osztályokban látszik. Például az előző pontok

módosításaihoz hasonlóan végezzük el az most az alábbi módosítást:

/** Normál működés, a hőssel időközben semmi nem történt. */

protected static final int JÁTÉK_MEGY_HŐS_RENDBEN = 0;

aminek megfelelően most fordításkor a

C:\...\Munkakönyvtár>javac javattanitok\LabirintusVilág.java

javattanitok\LabirintusVilág.java:83: JÁTÉK_MEGY_HŐS_RENDBEN has protected access

in javattanitok.labirintus.Labirintus

case Labirintus.JÁTÉK_MEGY_HŐS_RENDBEN:

^

1 error

hibát kapjuk. Ha ragaszkodnánk a védett tulajdonsághoz, akkor ezt a hibát csak úgy háríthatnánk el, ha csakis

a javatanitok.labirintus.Labirintus osztályban vagy annak leszármazottaiban használnánk a

továbbiakban a JÁTÉK_MEGY_HŐS_RENDBEN tagot.

Megjegyezhetjük, hogy a public, static, final jellemzésű változókat konstansoknak nevezzük. A JDK

könyvtárában található src.zip állományban - ahol megtaláljuk a Java SE OO világ összes osztályának

forráskódját - a src.zip/java/lang/Math.java forrásban leírt Math osztályban találjuk például a Pi

konstans definícióját: public static final double PI = 3.14159265358979323846;

• void jelentése, hogy nem ad vissza értéket. Például a LabirintusJáték osztályban a

/**

* Ébresztő az várakozó rajzolást végző szálnak, ki kell rajzolni a játék

* grafikus felületét.

*/

synchronized public void rajzolniKell() {

Page 117:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

89 Created by XMLmind XSL-FO Converter.

notify();

}

sorok azt mondják, hogy a rajzolniKell() függvény nem ad vissza semmit, mert hiszen nem is számol ki

semmit. Feladata csupán annyi, hogy az éppen egy wait() hívásban alvó végrehajtási szálat a notify();

függvény meghívásával felébressze.

• synchronized jelentése, hogy korlátozza, szabályozza a szálak futását. Az imént látott notify() függvény a

java.lang.Object osztály - minden Java osztály ősének - metódusa, ami egyben azt is jelenti, hogy ezzel a

metódussal minden Java osztály rendelkezik. Mint ahogyan a a függvény párjával, a wait() metódussal is.

Ez utóbbi függvény hívása elaltatja a hívást végrehajtó programszálunk futását, az előbbi pedig az ilyen alvó

szálakat ébreszti fel. Szabály, hogy egy objektum notify() függvényét szinkronizáltan hívjuk. Szinkronizált

a hívás, ha az objektum egy szinkronizált példány vagy az objektum osztályának szinkronizált osztály

metódusából, vagy az objektum egy szinkronizált programszöveg blokkjából történik. Ezt a szinkronizált

tulajdonságot jelöli a synchronized melléknév. A fenti példában a synchronized public void

rajzolniKell() { szinkronizált, példányhoz tartozó rajzolniKell() metódust láttuk.

A Java típusnevek a következők: int, long, byte, char, float, double, boolean. A típusnevek használatával a

Típusok és változók című pontban foglalkozunk részletesen.

A Java vezérlő nevek a következők:

• import jelentése, más osztályok használatának jelzése. Például a LabirintusVilág osztálybeli

import javattanitok.labirintus.*;

sor azt mondja, hogy az osztály használja a javattanitok.labirintus csomagot, a kézikönyvhöz

fejlesztett labirintus API-t. Ha ezt a sort kitörölnénk az osztály forráskódjából, akkor a

C:\...\Munkakönyvtár>javac javattanitok\LabirintusVilág.java

javattanitok\LabirintusVilág.java:31: cannot find symbol

symbol : class Labirintus

location: class javattanitok.LabirintusVilág

protected Labirintus labirintus;

^

javattanitok\LabirintusVilág.java:33: cannot find symbol

symbol : class Hős

location: class javattanitok.LabirintusVilág

protected Hős hős;

^

javattanitok\LabirintusVilág.java:47: cannot find symbol

symbol : class RosszLabirintusKivétel

location: class javattanitok.LabirintusVilág

throws RosszLabirintusKivétel {

...

11 errors

hibákat adná a fordító. Mivel nem jeleztük, hogy használjuk a javattanitok.labirintus csomagot, így a

fordító nem találja az ebben a csomagban elhelyezett Labirintus, Hős, RosszLabirintusKivétel stb.

használt osztályokat.

Az import utasításban a csillag a csomag összes osztályát jelenti. A LabirintusKiszolgáló osztálybeli

Page 118:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

90 Created by XMLmind XSL-FO Converter.

import java.util.List;

import java.util.Iterator;

sorok azt mondják, hogy a java.util csomagnak csupán a List és az Iterator osztályát használja a

LabirintusKiszolgáló osztály.

• package jelentése, hogy egy adott csomagba tartozó rész következik. Például a Labirintus osztály

Labirintus.java forrásának első

package javattanitok.labirintus;

utasátása azt mondja, hogy a Labirintus.java állomány tartalma a javattanitok.labirintus csomagba

fog kerülni. Fontos szabály, hogy ennek megfelelően a Labirintus.java állományt egy, a csomag nevének

megfelelő javattanitok\labirintus könyvtárban kell elhelyezni.

Ha a Labirintus.java forrásból a package javattanitok.labirintus; sort kitörölnénk, a következő

fordítási hibát kapnánk:

C:\...\Munkakönyvtár>javac javattanitok\LabirintusVilág.java

javattanitok\LabirintusVilág.java:31: cannot access javattanitok.labirintus.Labirintus

bad class file: .\javattanitok\labirintus\Labirintus.java

file does not contain class javattanitok.labirintus.Labirintus

Please remove or make sure it appears in the correct subdirectory of the classpath.

protected Labirintus labirintus;

mert a szóban forgó sor kivétele után a Labirintus osztály már nem tartja magát a

javattanitok.labirintus csomagba tartozónak.

• class jelentése, hogy osztály megadása következik. Például a Szereplő osztályt leíró Szereplő.java

állomány így kezdődik:

/*

* Szereplő.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.labirintus;

/**

* A labirintus szereplőit (kincsek, szörnyek, hős) absztraháló osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.labirintus.Labirintus

*/

public class Szereplő {

• extends jelentése, hogy egy osztály kiterjesztése következik. A Hős osztályunk kiterjeszti a Szereplő

osztályt, ennek megfelelően a Hős forrása így kezdődik:

Page 119:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

91 Created by XMLmind XSL-FO Converter.

/*

* Hős.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.labirintus;

/**

* A labirintus hősét leíró osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.labirintus.Labirintus

*/

public class Hős extends Szereplő {

• new jelentése, hogy egy új objektumot készít. A LabirintusVilág osztályban például így készül el a

labirintus:

// A labirintus elkészítése állományból

labirintus = new Labirintus(labirintusFájlNév);

A new használatát példányosításnak nevezzük. Itt a Labirintus osztály olyan konstruktor függvényét hívtuk,

amely egy állományból, a labirintusFájlNév nevű állományból építi fel a labirintust.

• try catch kijelöli a megfigyelt forrásszövegrész blokkot és a kivételkezelő blokkot. Például a

LabirintusVilág osztály szokásosan indul, a statikus main() függvényében készít önmagából egy

objektum példányt:

try {

new LabirintusVilág(args[0]);

} catch(RosszLabirintusKivétel rosszLabirintusKivétel) {

a try blokkban figyeli, hogy nem történt-e valami probléma (kivétel) a példányosítás során, ha igen -

mondjuk nincs meg az args[0] megnevezte, a labirintus tervét tartalmazó állomány - akkor a program futása

a catch kivételkezelő RosszLabirintusKivétel ágán folytatódik.

• this jelentése: hivatkozás egy osztály aktuális példányára. A this használatára triviális példa a példánytagok

beállítása

public Labirintus(int szélesség, int magasság,

int kincsekSzáma, int szörnyekSzáma) {

this.magasság = magasság;

this.szélesség = szélesség;

...

Kevésbé egyszerű példa a MandelbrotHalmazNagyító osztályunkban szereplő

Page 120:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

92 Created by XMLmind XSL-FO Converter.

public void mouseReleased(java.awt.event.MouseEvent m) {

if(m.getButton() == java.awt.event.MouseEvent.BUTTON1 ) {

double dx = (MandelbrotHalmazNagyító.this.b

- MandelbrotHalmazNagyító.this.a)

/MandelbrotHalmazNagyító.this.szélesség;

mert itt egy egéreseményekre reagáló addMouseListener(new java.awt.event.MouseAdapter() {

névtelen objektumon belül vagyunk, így a this önmagában ezt az eseménykezelő objektumot jelentené, ezért

minősítjük a MandelbrotHalmazNagyító osztálynévvel, mert nekünk az aktuális

MandelbrotHalmazNagyító objektumra van éppen szükségünk, hogy hozzáférjünk annak a, b és szélesség

tagjaihoz.

Részletesebben olvashat a this kulcsszóról a Vissza az OO-hoz [105] című részben.

• super hivatkozik egy osztály szülőjének aktuális példányára. Példáink közül a Pontmátrix osztályban

találkozunk a használatával:

/** A pontmátrixot tartalmazó kép kirajzolása. */

public void paintComponent(java.awt.Graphics g) {

super.paintComponent(g);

if(pontmátrixKép != null)

g.drawImage(pontmátrixKép, 0, 0, this);

}

• implements jelzi, hogy egy osztály megvalósítja egy interfész módszereit.

class Kiszolgáló implements Runnable {

A fenti, a Kiszolgáló osztályból származó osztálydefiníció feje mutatja, hogy a Kiszolgáló osztály

megvalósítja a Runnable - egyébként egyetlen - run() metódusát. Ennek megfelelően a Kiszolgáló

osztálynak rendelkeznie kell a run() függvény implementációjával, mint ahogyan rendelkezik is:

public void run() {

try {

java.io.BufferedReader bejövőCsatorna =

new java.io.BufferedReader(

new java.io.InputStreamReader(socket.getInputStream()));

java.io.PrintWriter kimenőCsatorna =

new java.io.PrintWriter(socket.getOutputStream());

String sor = null;

while((sor = bejövőCsatorna.readLine()) != null) {

kimenőCsatorna.println(sor);

kimenőCsatorna.flush();

}

socket.close();

} catch(java.io.IOException ioE) {

ioE.printStackTrace();

}

}

Page 121:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

93 Created by XMLmind XSL-FO Converter.

• return jelentése: visszatérés függvényből.

public class Kincs extends Szereplő {

/** A kincs értéke. */

protected int érték;

...

/**

* Megmondja, hogy megtalálták-e már a kincset?

*

* @return true ha a kincset már megtalálták,

* ha még nem akkor false.

*/

public boolean megtalálva() {

return megtalálva;

}

A fenti, a Kincs osztályból származó kódcsipet jól mutatja, hogy a return utasítás nemcsak kiugrik a hívott

függvény végrehajtásából, hanem - és ez a tipikus használata - visszaadja a függvény által kiszámolt,

megfelelő típusú értéket.

• for jelentése az előírt lépésszámú ciklus bevezetése. A következő, a LabirintusKiszolgáló osztályból

származó példa végiglépked a kincsek lista kincsein.

for(Kincs kincs : kincsek) {

if(kincs.megtalalt(hős))

hős.megtalaltam(kincs);

}

Klasszikusabb használatot mutat a Labirintus osztályból kicsippentett, alábbi kódtöredék:

// Szörnyek létrehozása

szörnyek = new Szörny[szörnyekSzáma];

for(int i=0; i<szörnyek.length; ++i)

szörnyek[i] = new Szörny(this);

ami a szörnyek tömbön lépked végig.

• while jelentése, az elől tesztelő ciklus bevezetése. Az alábbi, a TCAG2Hexa osztálybeli ciklus

int i = 0;

while((i=System.in.read()) != -1) {

switch(i) {

case 'T':

második = 0;

break;

case 'C':

Page 122:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

94 Created by XMLmind XSL-FO Converter.

második = 1;

break;

case 'A':

második = 2;

break;

case 'G':

második = 3;

break;

}

addig olvas a System.in bemenetről, tipikusan a billentyűzetről, ameddig csak lehet, tehát amíg a while után

szereplő feltétel kiértékelése igazat ad.

• do while jelentése a hátul tesztelő ciklus bevezetése. A Szereplő osztálybeli alábbi ciklus

// Többször próbálkozunk elhelyezni a szereplőt a labirintusban,

// számolja, hol tartunk ezekkel a próbálkozásokkal:

int számláló = 0;

do {

// itt +2,-2-k, hogy a bal alsó saroktól távol tartsuk

// a szereplőket, mert majd ezt akarjuk a hős kezdő pozíciójának

oszlop = 2+véletlenGenerátor.nextInt(maxSzélesség-2);

sor = véletlenGenerátor.nextInt(maxMagasság-2);

// max. 10-szer próbálkozunk, de ha sikerül nem "falba tenni" a

// szereplőt, akkor máris kilépünk:

} while(++számláló<10 && labirintus.fal(oszlop, sor));

addig próbálja elhelyezni a szereplőt a labirintusban, amíg nem falba teszi, de maximum 10 alkalommal

próbálkozik. Tehát addig megy vissza a do-ra, amíg a while után szereplő feltétel kiértékelése igazat ad.

• if else jelentése egy villa elágazás a végrehajtásban.

// Sejt cella kirajzolása

if(rács[i][j] == ÉLŐ)

g.setColor(java.awt.Color.BLACK);

else

g.setColor(java.awt.Color.WHITE);

g.fillRect(j*cellaSzélesség, i*cellaMagasság,

cellaSzélesség, cellaMagasság);

azaz vagy feketével vagy fehérrel töltjük ki a j*cellaSzélesség, i*cellaMagasság, cellaSzélesség,

cellaMagasság (bal felső sarok oszlop, sor és szélesség, magasság) adatokkal jellemzett téglalapot.

• if else if else jelentése egy többirányú elágaztatás a végrehajtásban.

// A billentyűzetről érkező események feldolgozása

addKeyListener(new java.awt.event.KeyAdapter() {

// Az 'k', 'n', 'l', 'g' és 's' gombok lenyomását figyeljük

public void keyPressed(java.awt.event.KeyEvent e) {

if(e.getKeyCode() == java.awt.event.KeyEvent.VK_K) {

// Felezük a cella méreteit:

cellaSzélesség /= 2;

cellaMagasság /= 2;

setSize(Sejtautomata.this.szélesség*cellaSzélesség,

Sejtautomata.this.magasság*cellaMagasság);

validate();

} else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_N) {

Page 123:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

95 Created by XMLmind XSL-FO Converter.

// Duplázzuk a cella méreteit:

cellaSzélesség *= 2;

cellaMagasság *= 2;

setSize(Sejtautomata.this.szélesség*cellaSzélesség,

Sejtautomata.this.magasság*cellaMagasság);

validate();

} else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_S)

pillanatfelvétel = !pillanatfelvétel;

else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_G)

várakozás /= 2;

else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_L)

várakozás *= 2;

repaint();

}

});

a kódrészlet megállapítja, hogy a program által figyelt gombokat nyomtuk-e le és igenlő esetben végrehajtja a

megfelelő feladatot. Ha nem a figyelt gombok valamelyikét nyomtuk volna, akkor az utolsó if nélküli else

teljesülne, de ezt most elhagytuk.

• switch case jelentése több lehetőség közüli választás a végrehajtásban. A korábban bemutatott kódrészletbeli

switch utasítás

switch(i) {

case 'T':

második = 0;

break;

case 'C':

második = 1;

break;

case 'A':

második = 2;

break;

case 'G':

második = 3;

break;

}

eldönti, hogy az i a 'T', 'C', 'A', 'G' betűk közül esetlegesen melyik éppen az i.

• break jelentése kiugrás a tartalmazó blokkból. Az alábbi ElosztottKliens osztályból származó sorok addig

ismétlik a billentyűzetről való olvasást, amígcsak k billentyűt nem nyomunk, mert

String parancs = null;

while((parancs = konzol.readLine()) != null) {

// A Hos CORBA objektum kilép a labirintusból

if("k".equals(parancs))

break;

}

annak hatására a break utasítás kilépteti a végrehajtást a ciklusból.

• throws jelzi, hogy egy függvény milyen kivételeket dob. Például a Labirintus osztály a labirintust

állományból felépítő konstruktor függvénye ilyen:

/**

Page 124:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

96 Created by XMLmind XSL-FO Converter.

* Egy megfelelő szerkezetű szöveges állományból elkészít egy új a

* <code>Labirintus</code> objektumot.

*

* @param labirintusFájlNév a labirintust definiáló, megfelelő

* szerkezetű szöveges állomány neve.

* @exception RosszLabirintusKivétel ha a labirintust definiáló állomány

* nincs meg, nem a megfelelő szerkezetű,

* vagy gond van az olvasásával.

*/

public Labirintus(String labirintusFájlNév) throws RosszLabirintusKivétel {

Ezzel befejeztük a kulcsszavak ismertetését, a következő bekezdésben az azonosító szavak tárgyalásával

folytatjuk a Java nyelvtanának ismertetését.

A nem számmal kezdődő és nem kulcsszó szavakat azonosítóknak nevezzük. Az azonosító szavak szerepe -

mint nevük is mutatja - valaminek az azonosítása. Például a változók nevei azonosítók. A korábbi

kódrészletekből idézve a public static final int JÁTÉK_MEGY_HŐS_RENDBEN = 0; sorban a

JÁTÉK_MEGY_HŐS_RENDBEN szó azonosító. A int i = 0; sorban az i egybetűs szó azonosító, vagy mondjuk a

labirintus = new Labirintus(labirintusFájlNév); sorban a labirintus, a Labirintus és a

labirintusFájlNév szavak azonosítók. A labirintus változó értéke egy referencia, az újonnan létrehozott

Labirintus osztálybeli objektum referenciája. Tehát a labirintus azonosító értékével ezt az új objektumot

azonosítja. Ha például ezt az objektumot törölni akarjuk, akkor majd azt írjuk, hogy labirintus = null; azaz

a labirintus azonosítónak azt a null értéket adjuk, ami egyetlen objektumnak sem referenciája. A Labirintus

azonosító egy osztály, a labirintusunkat absztraháló osztály neve, ez az azonosító például nem változó. A

labirintusFájlNév nevű azonosító megint csak egy változó, értéke a labirintus tervrajzát hordozó állomány

nevét tartalmazó karaktersorozat objektum referenciája.

A Java kifejezés szavak lehetnek egyszerűek vagy összetettek.

Az egyszerű kifejezés szavak

• a számok, például a 42, -42 vagy mondjuk a LabirintusVaszon osztálybeli sorokban

// A kijelző törlése

g.setColor(0x00FFFFFF);

g.fillRect(0, 0, getWidth(), getHeight());

// A labirintus kirajzolása

g.setColor(0x00ed7703);

a hexadecimális 0x00FFFFFF a fehér és 0x00ed7703 a vörös=237(10), zöld=119(10), kék=3(10) színeket kódoló

számok.

• a karakterláncok, minden idézőjelek közé zárt szöveg karakterlánc. Például a LabirintusServlet

osztálybeli alábbi sorokban

// A válasz csatornán küldött adatokat a böngésző

// mint html oldalt értelmezze

httpVálasz.setContentType("text/html;charset=UTF-8");

a text/html;charset=UTF-8 egy karakterlánc.

• a logikai igaz és hamis literál értékek, az igaz true és a hamis false.

• az azonosítók (például változó, függvény vagy osztály nevek) is egyszerű kifejezés szavak.

Page 125:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

97 Created by XMLmind XSL-FO Converter.

Az összetett kifejezés szavakat egyszerű és összetett kifejezés szavakból építjük fel a műveleti és zárójelek

felhasználásával.

Az alábbi, a LabirintusKiszolgáló osztályból kiragadott metódus soraiból

/**

* A labirintus sztring reprezentációja.

*

* @return String labirintus sztring reprezentációja.

*/

public String toString() {

return " Idő:" + idő

+ " hős:" + hősök.size()

+ " kincs:" + kincsek.size()

+ " szörny:" + szörnyek.size();

}

a következő kiragadott szó

" Idő:" + idő

+ " hős:" + hősök.size()

+ " kincs:" + kincsek.size()

+ " szörny:" + szörnyek.size();

egy összetett kifejezés szó. Az + jellel összekapcsolt Idő:, hős:, kincs:, szörny: karakterláncokból, az

idő változónévből, mint egyszerű kifejezés szavakból és három változónév.függvénynév() alakú, a .

hivatkozó és a zárójellel összekapcsolt összetett kifejezés szavakból épül fel.

A kifejezés szavak értéket is hordoznak, a program futása során a most tárgyalt kifejezés szó értéke egy

karakterlánc, mondjuk lehet éppen az Idő:325 hős:1 kincs:2 szörny:1.

Az alábbi, a Hisztogram osztályból kiragadott sorokban

// Egy doboz kirajzolása

g.setColor(java.awt.Color.YELLOW);

if(maxDobozÉrték/képMagasság != 0)

g.fillRect(i*dobozSzélesség,

képMagasság-dobozok[i]/(maxDobozÉrték/képMagasság),

képSzélesség/dobozok.length,

dobozok[i]/(maxDobozÉrték/képMagasság));

például a maxDobozÉrték/képMagasság != 0 egy összetett kifejezés szó. A /, a szokásos aritmetikai és a !=

logikai, a nem egyenlőséget vizsgáló jellel összekapcsolt két változónévből és egy számból, a nullából áll.

Értékeljük ki a szóban forgó maxDobozÉrték/képMagasság != 0 összetett kifejezés szót! A két változó

értékének maxDobozÉrték/képMagasság hányadosa egy szám, ha ez nullától különböző, akkor a kifejezés

értéke true, különben false.

1.1.3.1.2. A Java mondattana

Java nyelven, hasonlóan, mint például a beszélt, mondjuk magyar nyelven, sokféle mondat szerkeszthető. A

legegyszerűbb mondatokat - ahogy már fentebb láthattuk is - pontosvessző zárja le, a bonyolultabb mondatokat

pedig az egyszerűbb mondatokból lehet felépíteni.

Page 126:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

98 Created by XMLmind XSL-FO Converter.

Figyelmeztetés a Javaban kezdő Olvasóknak

A következőkben valódi Java forráskódrészletek következnek. Ne próbáljuk erőlködve értelmezni őket,

a minden erőfeszítés nélküli olvasásuk majd az egész kézikönyv feldolgozása után valósul meg - a

szerzők látomása szerint.

A Java nyelv egyszerű mondatai a következők:

• a deklaráló mondatok azt mondják, hogy valami legyen ez, az, ilyen, olyan. Például a Pontmátrix

osztálybeli

/** A pontmátrixot tartalmazó kép. */

java.awt.image.BufferedImage pontmátrixKép;

sorok java.awt.image.BufferedImage pontmátrixKép; deklarációja azt mondja, hogy a

pontmátrixKép nevű változó legyen egy olyan változó, ami értékeként képes hordozni egy

java.awt.image.BufferedImage osztálybeli objektum referenciáját. Röviden a Java programozó azt

mondja majd ilyenkor, hogy a pontmátrixKép egy BufferedImage.

• az értékadó mondatok azt mondják el, hogy valaminek az értéke legyen ez, az, ennyi, annyi. Például a

Sejtautomata osztálybeli alábbi sorok

// Cellaméretek kezdetben

cellaSzélesség = 10;

10 pixel szélesre állítják a sejtautomata kirajzolt celláinak szélességét.

• a metódushívó mondatok függvényt hívnak,

socket.close();

a fenti, a LabirintusKiszolgálóSzál osztálybeli sor lezárja a kommunikációs kaput.

• a deklaráló, értékadó és metódusmondatokat kombinálhatjuk is. A Pontmátrix osztálybeli induló

// A panel mérete

java.awt.Dimension mátrixMéret =

new java.awt.Dimension(800, 800);

mátrixMéret egy Dimension és rögtön megadunk egy ilyen 800x800-as pixelméretű példányt is a megfelelő

konstruktor meghívásával.

De azt is megtehetjük, hogy egyszerűen csak létrehozunk egy példányt

new ElosztottLabirintus();

Page 127:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

99 Created by XMLmind XSL-FO Converter.

mint ahogyan például a ElosztottLabirintus osztályban tettük.

Vagy létrehozunk egy példányt és rögtön hívjuk is egy módszerét:

new Thread(this).start();

mint a LabirintusKiszolgálóSzál osztályban a hálózati kommunikációt elvégző szál elkészítésénél és

indításánál tettük.

Avagy éppen egy metódus visszatérési értékével inicializálunk egy változót, erre az alábbi példát a

// Elkérjük a böngészőbe menő csatornát

java.io.PrintWriter csatornaBöngészőbe = httpVálasz.getWriter();

LabirintusServlet osztályból kicsípve közöltük.

Végül lássunk egy komplexebb példát is:

// Vagy új vagy régi a hős, a hős neve = "hoszt IP : név"

Hős hős = hálózatiLabirintus.hős(socket.getInetAddress().getHostAddress()

+

" : " + játékostól);

amint a LabirintusKiszolgálóSzál osztályban a hős() függvénynek átadott paramétert egy összetett

kifejezés szóval írtuk le, a hős() függvénynek aktuális paraméterként majd ennek a szónak az értéke, például

a 192.168.1.1 : Herkules karaktersorozat objektum referenciája adódik át, amit a HálózatiLabirintus

osztály

/**

* A hálózaton keresztül jelentkező hős elkészítése.

*

* @param név a hős neve (= "hoszt IP : név").

* @return Hős a névhez tartozó, esetleg újonan létrehozott hős.

*/

public Hős hős(String név) {

// Ha már létező hős jelentkezett be újra a játékba

if(hősök.containsKey(név))

return (Hős)hősök.get(név);

// Vagy új játékos jön

else {

// aki még nincs a hősök között

// akkor új hősként létrehozzuk

Hős hős = new Hős(labirintus);

// A hős kezdő pozíciója

hős.sor(9);

hős.oszlop(0);

// Felvétele a hősök közé

hősök.put(név, hős);

return hős;

}

}

Page 128:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

100 Created by XMLmind XSL-FO Converter.

majd a String típusú, név nevű formális paraméterében kap meg.

A Java nyelv összetett mondatai egyszerű és összetett mondatokból néhány kulcsszóval és a kapcsos zárójelek

használatával képezhetők. Főbb összetett mondat típusok a következők:

• a ha-akkor-különben mondatok a program végrehajtásának villa elágazásait írják le. A korábban említett

// Sejt cella kirajzolása

if(rács[i][j] == ÉLŐ)

g.setColor(java.awt.Color.BLACK);

else

g.setColor(java.awt.Color.WHITE);

g.fillRect(j*cellaSzélesség, i*cellaMagasság,

cellaSzélesség, cellaMagasság);

példánál maradva a g Graphics objektum setColor() színbeállító függvénye a java.awt.Color.BLACK

értékkel fog meghívódni, ha a rács i. sorának, j. oszlopának sejtje élő, azaz a rács[i][j] == ÉLŐ feltétel

értéke igaz, és java.awt.Color.WHITE színnel, ha nem igaz.

Ha valamelyik ágon egynél több mondatot szeretnénk írni, akkor ezeket a mondatokat egy kapcsos zárójelek

határolta blokkba kell szerveznünk, mint ahogyan például az alábbi, a HálózatiLabirintus osztálybeli

sorokban láthatjuk:

// Ha már létező hős jelentkezett be újra a játékba

if(hősök.containsKey(név))

return (Hős)hősök.get(név);

// Vagy új játékos jön

else {

// aki még nincs a hősök között

// akkor új hősként létrehozzuk

Hős hős = new Hős(labirintus);

// A hős kezdő pozíciója

hős.sor(9);

hős.oszlop(0);

// Felvétele a hősök közé

hősök.put(név, hős);

return hős;

}

Nézzünk meg egy komplikáltabb példát is alább, a LabirintusVaszon osztályból!

if(kincsKép != null) {

if(!kincsek[i].megtalálva())

g.drawImage(kincsKép,

kincsek[i].oszlop()*téglaSzélesség,

kincsek[i].sor()*téglaMagasság,

javax.microedition.lcdui.Graphics.LEFT

|javax.microedition.lcdui.Graphics.TOP);

} else {

// Ha már megvan a kics, akkor szürkébbel rajzoljuk

if(kincsek[i].megtalálva())

g.setColor(0x00d2cfb7);

else // Különben sárgábbal

g.setColor(0x00fbe101);

g.fillRect(kincsek[i].oszlop()*téglaSzélesség,

kincsek[i].sor()*téglaMagasság,

téglaSzélesség/2, téglaMagasság);

Page 129:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

101 Created by XMLmind XSL-FO Converter.

}

• a ha-különben-ha mondatok hasonlóak az előzőekhez, de több ága lehet a villának, a lehetőségek közül egy,

az első fog lefutni:

// A kurzor gomboknak megfelelő irányba lépéssel

if ((billentyű & LEFT_PRESSED) != 0) {

hős.lépBalra();

} else if ((billentyű & RIGHT_PRESSED) != 0) {

hős.lépJobbra();

} else if ((billentyű & UP_PRESSED) != 0) {

hős.lépFöl();

} else if ((billentyű & DOWN_PRESSED) != 0) {

hős.lépLe();

}

ebben a LabirintusVaszon osztálybeli példában a kapcsos zárójelekre nem is lett volna szükség, mert

minden villa ágon csupán egyetlen utasítás van, de soha ne szégyelljünk bőven bezárójelezni egy kódot.

Mivel a programok tipikusan bonyolódni szoktak, a bőséges zárójelezés sokszor egyértelműbbé és

átláthatóbbá teszi a forrást, ami egyben könnyedebb továbbfejleszthetőséget is jelent! Visszatérve a példára,

az else ágat itt elhagytuk.

• az ellenőrzött mondatok végrehajtása speciális, mert ha a mondat értelmezése során valamilyen kivétel

keletkezik, akkor azt kezelhetjük. Például a Labirintus osztály kódjából kiragadott alábbi kódrészletben

while(sor.startsWith("//"))

sor = szövegesCsatorna.readLine();

try {

kincsekSzáma = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

szörnyekSzáma = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

szélesség = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

magasság = Integer.parseInt(sor);

szerkezet = new boolean[magasság][szélesség];

} catch(java.lang.NumberFormatException e) {

throw new RosszLabirintusKivétel("Hibás a kincsek, szörnyek száma,

szélesség, magasság megadási rész.");

}

addig olvasunk be sorokat a szövegesCsatorna csatornáról, amíg a // megjegyzés jellel kezdődő sorok el

nem fogynak a labirintusunkat leíró

//

// labirintus.txt

//

// DIGIT 2005, Javat tanítok

Page 130:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

102 Created by XMLmind XSL-FO Converter.

// Bátfai Norbert, [email protected]

//

// A labirintus szerkezetét megadó állomány, szerkezete a következő:

// a kincsek száma

// a szörnyek száma

// a labirintus szélessége

// magassága

// fal=1 járat=0 ...

// .

// .

// .

6

3

10

10

0 0 0 1 0 1 0 1 1 1

...

állományunk elejéről. A try { vezeti be a megfigyelt forráskód blokk kezdetét. Itt olvassuk be a 6, 3, 10, 10

számokat. Ha a második 10-et elírjuk például q0-ra, akkor a magasság = Integer.parseInt(sor); sor

értelmezésekor egy hiba keletkezik, egy NumberFormatException kivétel objektum, ami után a vezérlés már

nem kerül a következő, a szerkezet = new boolean[magasság][szélesség]; sorra, hanem az ennek

megfelelő } catch(java.lang.NumberFormatException e) { kivételkezelő ágon folytatódik, ahol

megtörténik a kivétel kezelése. Jelen esetünkben ez a kivétel tovább dobását jelenti a jelen kódunkat hívó

függvénynek... a kivételkezelés részletes tárgyalását majd a Kivételkezelés című pontban folytathatja a kedves

Olvasó.

• a ciklus mondatokkal a ciklusokat írjuk le, csak az előírt lépésszámú ciklusra kitérve a korábbi

for(Kincs kincs : kincsek) {

if(kincs.megtalalt(hős))

hős.megtalaltam(kincs);

}

példában a ciklus kapcsos zárójelek közé zárt magja vagy törzse a kincsek, egyébként Kincs objektumokat

tartalmazó lista objektum minden tagjára lefut. Gyakorlatilag minden kincstől megkérdezzük, hogy rátalált-e

a hősünk?

A szintúgy korábbi kódtöredékben

// Szörnyek létrehozása

szörnyek = new Szörny[szörnyekSzáma];

for(int i=0; i<szörnyek.length; ++i)

szörnyek[i] = new Szörny(this);

az i ciklusváltozót a 0 kezdőértékkel inicializáljuk, ha a i<szörnyek.length igaz, akkor ezzel az i=0

értékkel végrehajtjuk a magot, majd következik a ++i, azaz az i értékének eggyel való megnövelése, miután

újra megvizsgáljuk a i<szörnyek.length feltételt. Ha igaz, végrehajtjuk a magot , s így tovább, egészen

addig, amíg hamis nem lesz, mert akkor már nem hajtjuk végre a magot és a vezérlés a ciklus mondat utáni

következő mondatra kerül.

• a függvény mondatok egy függvényt definiálnak. A függvény nevét melléknevek előzik meg, majd kerek

zárójelek között a formális paraméterei szerepelnek, amit a kapcsos zárójelek közé zárt függvénytörzs vagy

test követ. A LabirintusMIDlet osztály

Page 131:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

103 Created by XMLmind XSL-FO Converter.

/**

* A MIDletet felfüggesztő életciklus metódus, azaz mit tegyünk,

* ha egy bejövő hívás vagy SMS megzavarja a programunk futását?

* (Most semmit, mert csupán üres testes implementációját adtuk a

* függvénynek.)

*/

public void pauseApp() {}

függvénye az üres paraméterlistára () és az üres testre {} is példát mutat.

Nem ennyire triviális példa a Pontmátrix osztály

public void pillanatfelvétel(String fájlNév) {

// png formátumú képet mentünk

try {

javax.imageio.ImageIO.write(pontmátrixKép, "png",

new java.io.File(fájlNév));

} catch(java.io.IOException e) {

e.printStackTrace();

}

}

függvénye, melynek már van egyetlen formális paramétere, a String fájlNév, és a törzse sem üres: png

képformátumban elmenti az osztály pontmátrixKép BufferedImage példányát a paraméterként kapott

állománynéven a javax.imageio.ImageIO osztály statikus write() függvényével. Érdekességként

megjegyezhetjük, hogy a formális paramétert a hívás helyén úgy aktualizáljuk, hogy az átadott aktuális

paraméter karaktersorozat objektumot a felhasználói felület egy állománykiválasztó párbeszédablakában

jelöljük ki:

} else if("Mentés...".equals(menü)) {

javax.swing.JFileChooser betöltő = new javax.swing.JFileChooser();

betöltő.showSaveDialog(getContentPane());

pillanatfelvétel(betöltő.getSelectedFile().getAbsolutePath());

• az osztály mondatok a legbővebb összetett mondatok, velük definiáljuk az osztályokat. Az osztály nevét

melléknevek előzik meg, közvetlenül előtte a class áll, illetve az osztálynév után néhány szóba jöhető

kulcsszó után, a kapcsos zárójelek között következik az osztály törzse vagy teste. Egyszerű példaként álljon

itt a korábbi Szereplő osztály:

public class Szereplő {

Az öröklés, kiterjesztés jelzésére pedig például a Hős osztály:

public class Hős extends Szereplő {

Az Olvasó az öröklődéssel Az osztályok fejlődése: az öröklődés című pontban ismerkedhet majd meg

részletesen. Végül tekintsünk egy komplexebb példát a LabirintusKiszolgáló osztályt!

Page 132:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

104 Created by XMLmind XSL-FO Converter.

public class LabirintusKiszolgáló

extends javattanitok.labirintus.TöbbHősösLabirintus

implements LabirintusOperations, Runnable {

Kiterjesztjük a másik csomagbeli TöbbHősösLabirintus osztályt és implementáljuk a

LabirintusOperations és a Runnable interfészeket.

1.1.3.2. A Java nyelv és a Java programozás között

Alapvető fontosságú - az iménti pontok terminológiájával: függvény - mondat lesz a következő.

függvényNév(változók felsorolása) {

}

Az ilyen mondatokat függvényeknek vagy metódusoknak nevezzük.

A függvényNév a függvény neve, ezt követi egy kerek zárójelek közötti változó-felsorolás - a függvény

formális paramétereinek megadása - ami ugyan akár el is maradhat, majd egy kapcsos zárójelpár következik,

ami további mondatokat tartalmazhat.

A függvények tipikus hivatása, hogy kiszámoljanak és visszaadjanak hívóiknak valamilyen típusú eredményt.

Ezt így írjuk le:

EredményTípus függvényNév(változók felsorolása) {

}

Ha a függvény nem ad vissza értéket a hívónak, akkor azt a void kulcsszó szerepeltetésével kell jeleznünk:

void függvényNév(változók felsorolása) {

}

Még a függvények leírásánál is alapvetőbb mondatok az osztályok definícióját leíróak - mint ahogyan a

Labirintus osztály kapcsán az imént láttunk erre egy konkrét példát - ezeknek a mondatoknak általános

szerkezete a következő:

class OsztályNév {

}

A kapcsos zárójelek közé jöhetnek az osztály által leírt dolog tulajdonságait megadó egyszerű Java nyelvű

mondatok, vagy függvények.

1.1.4. Vissza az OO-hoz

1.1.4.1. Objektumok létrehozása: a konstruktor

Page 133:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

105 Created by XMLmind XSL-FO Converter.

Egy osztály függvényei között a konstruktornak nevezett függvények speciális rendeltetésűek, feladatuk az

osztályból származó objektumok felépítése.

A konstruktor függvény neve megegyezik az osztály nevével:

Labirintus(int szélesség, int magasság) {

}

Vegyük észre, hogy a konstruktor függvényeknek nincs valamely kiszámolt értéket visszaadó visszatérési

értéke, s a void kulcsszó sem szerepel a függvény fejének leírásában.

A paraméterként kapott két egész szám a létrehozandó új Labirintus objektum szélessége és magassága.

Tegyük fel, hogy van egy programunk, ami használni akar egy labirintust és a program éppen most érkezik

ahhoz a ponthoz, ahol szüksége van a labirintusra! Ekkor példányosít a Labirintus osztályból, azaz le fog futni

a Labirintus osztály konstuktora. Gondoljunk bele, mit kell végrehajtania a konstruktornak?

A paraméterként kapott szélességet és magasságot be kell állítania a létrehozandó új labirintus objektumban,

majd létre kell hoznia az ennek a két számnak megfelelő méretű labirintus szerkezetet. A kapott szélesség és

magasság tulajdonság beállítása azért fontos feladat, mert a létrehozandó új labirintus objektumnak ezt a két

számot tudnia kell magáról, mindig tudnia, nem csupán a megfelelő méretű labirintus szerkezet létrehozásakor.

Írjuk le ezt Java nyelven:

Labirintus(int szélesség, int magasság) {

this.szélesség = szélesség;

this.magasság = magasság;

szerkezet = new boolean[szélesség][magasság];

}

Látható, hogy az osztály definíciójában szereplő szélesség és magasság változónevek megegyeznek a

konstruktor függvény paramétereinek nevével, hogy biztosan a létrehozandó új labirintus objektum szélességét

és magasságát állítsuk be. Ezért az első két értékadásnál a this operátorral minősítjük a változóneveket, ami

annyit jelent, hogy a változónév elé írjuk, hogy this: ezzel megkülönböztetve a függvényben lévő ugyanilyen

nevű változóktól. A this mindig az aktuális, azaz jelen esetben a létrehozandó új objektumot jelenti. Hiszen a

fejlesztés során a programozó szinte mindig valamely osztály viselkedését írja, eközben az jár a fejében, hogy

ebből az osztályból egy példány fog létrejönni, akinek az éppen programozott élethelyzetében a most éppen

Page 134:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

106 Created by XMLmind XSL-FO Converter.

begépelt viselkedést kell mutatnia... - ez az „akinek példány” a this.

A következő, a new operátort használó utasítás létrehozza a megfelelő méretű kétdimenziós logikai tömböt, azaz

a memóriában lefoglal annyi helyet, ahol ez a szerkezet elfér, és logikai celláit automatikusan feltölti hamis

értékekkel. (De az igazi paranoiás programozó az ilyen automatikus értékekkel nem foglalkozik, hanem mindig

maga adja meg azokat... de erre még nem most, hanem majd később látunk példát!)

szerkezet = new boolean[szélesség][magasság];

Saját labirintus osztályunkból ugyancsak a new operátorral tudunk példányosítani. Visszatérve feltevésünkhöz,

hogy van egy programunk, ami használni akar egy labirintust... és a program éppen most érkezik ahhoz a

ponthoz, ahol szüksége van a labirintusra, ekkor éppen a következő sort hajtja végre:

Labirintus labirintus = new Labirintus(10, 10);

Ekkor a kis labirintus azonosítót a létrehozott, új labirintus objektum referenciájának is nevezzük (egészen

pontosan az azonosító, a labirintus nevű változó értéke a referencia). Az objektum tulajdonságaira a

referencia után írt ponttal hivatkozhatunk, azaz a labirintus.szélesség a létrehozott, új labirintus

objektumbeli szélességet jelenti.

Összegezzük eddigi erőfeszítéseinket egyetlen forrásban:

class Labirintus {

int szélesség;

int magasság;

boolean[][] szerkezet;

Labirintus(int szélesség, int magasság) {

Page 135:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

107 Created by XMLmind XSL-FO Converter.

this.szélesség = szélesség;

this.magasság = magasság;

szerkezet = new boolean[szélesség][magasság];

}

static main() {

Labirintus labirintus = new Labirintus(10, 10);

}

}

Java programjaink végrehajtása a main() függvénnyel kezdődik - most egyetlen feladataként - benne

példányosítjuk a létrehozandó új labirintus objektumunkat. Tehát mivel most akarjuk létrehozni a labirintus

objektumot, így nyilván még nem létezik, akkor mégis hogyan futhat a main() metódus? Ezért van a static

módosító kulcsszó! A static kulcsszó azt jelenti, hogy a függvény nem az osztály példányaihoz, hanem

magához az osztályhoz tartozik, azaz anélkül is meg lehet hívni, hogy az őt tartalmazó osztályból

példányosítanánk.

Készítsük most el programunk olyan változatát, amit akár már le is fordíthatunk, futtathatunk:

class Labirintus {

int szélesség;

int magasság;

boolean[][] szerkezet;

Labirintus(int szélesség, int magasság) {

this.szélesség = szélesség;

this.magasság = magasság;

szerkezet = new boolean[szélesség][magasság];

}

public static void main(String[] args) {

Labirintus labirintus = new Labirintus(10, 10);

}

}

A main() függvényt most abban a formában használtuk, amelyben mindig szerepelnie kell, a void kulcsszó

jelzi, hogy a függvény nem ad vissza semmilyen értéket. A public módosító kulcsszó pedig arra utal, hogy

hogyan látszik az osztályunkon kívülről a függvény. A public azt jelenti, hogy mindenhonnan látszik. A

finomságokat majd később részletezzük, most annyit jegyezzünk meg, hogy a main() függvényt mindig így

használjuk. Azt persze még megemlíthetjük, hogy más formában nem is használhatjuk, mert eltérés esetén az

osztályunkat nem tudjuk lefordítani. A main() paraméterét a következő feladat után tárgyaljuk.

Tehát itt az idő, próbáljuk is ki ezt az osztályt!

C:\...> javac Labirintus.java

C:\...> java Labirintus

Page 136:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

108 Created by XMLmind XSL-FO Converter.

Sok látványos dolog nem történt, a program indítása után gyorsan visszaadta a promptot és kész. Megérte

feldolgozni ezt a sok oldalt eddig, ennyiért? Hogyne, hiszen pici módosítással szóra bírhatjuk a Labirintus

osztálybeli objektumunkat. Módosítsuk így az indítófüggvényt:

public static void main(String[] args) {

Labirintus labirintus = new Labirintus(10, 10);

System.out.println(labirintus.magasság);

}

A Labirintus.java forrásállomány módosítása után azt újra lefordítva és az osztályt futtatva:

C:\...> javac Labirintus.java

C:\...> java Labirintus

10

Sikerrel kiírattuk a labirintus magasságát.

1.1.4.1.1. Példánytag elérése osztályszintű függvényből feladat

A fordítás-futtatás-(bosszankodás) munkamenet begyakorlásaképpen, írassuk ki a labirintus szélességét is,

módosítsuk a main() függvényt így:

public static void main(String[] args) {

Labirintus labirintus = new Labirintus(10, 10);

System.out.println(labirintus.szélesség);

System.out.println(labirintus.magasság);

}

Mi történik az alábbi módosítás esetén, azaz ha a méretet megadó változóneveket nem a labirintus példány

referenciája után írjuk, hanem csak úgy egyszerűen ki akarjuk íratni őket:

public static void main(String[] args) {

Labirintus labirintus = new Labirintus(10, 10);

System.out.println(szélesség);

System.out.println(magasság);

}

Ekkor a futtatásig már el sem jutunk, mert a forrás nem fordul! A NetBeans környezet rögtön a leírása után jelzi

a hibát, a parancssort használó pedig ezt fogja látni, amikor megpróbálja lefordítani a forrást:

C:\Documents and Settings\norbi> javac Labirintus.java

Page 137:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

109 Created by XMLmind XSL-FO Converter.

Labirintus.java:19: non-static variable szélesség cannot be referenced from

a static context

System.out.println(szélesség);

^

Ez fontos hiba, amibe eleinte sokszor belefut a kezdő Java OO programozó Olvasó, de gyorsan ki lehet nőni.

Pontosan azt mondja, hogy a Labirintus.java forrásállományom 19. sorában a példányokhoz, és nem az

osztályhoz tartozó változót osztályhoz, és nem példányhoz kapcsolódó környezetben akarok használni. Ez

valóban nem értelmezhető, hiszen az indító függvényem egyetlen példányhoz sem tartozik, sőt direkt azért van,

mert amikor ő indul, akkor még nincsenek példányok, majd pont ő hozza létre az elsőt vagy az elsőket. Ha pedig

nincs példányom, akkor hogyan is akarhatom kiíratni egy példány szélességét! Mindaddig, amíg ezt a hibát nem

érezzük logikusnak, filozofáljunk el a példány és az osztály különbözőségén!

Visszatérve a példa fősodrához: a létrehozandó új labirintus objektum már tudja magáról saját méretét, megvan

az ennek a méretnek megfelelő méretű labirintus szerkezetet hordozni képes adatszerkezet, azaz a megfelelő

kétdimenziós logikai tömb, de maga a szerkezet még nincs meg. Megadhatnánk ezt téglánként:

Labirintus(int szélesség, int magasság) {

this.szélesség = szélesség;

this.magasság = magasság;

szerkezet = new boolean[szélesség][magasság];

szerkezet[0][0] = true; szerkezet[0][1] = true; ...

szerkezet[1][0] = true; szerkezet[1][1] = false; ...

.

.

.

}

De ezzel több probléma is van. Láthatóan nagy méret esetén egyik a nehézkesség, nem is beszélve a labirintus

szerkezetének módosíthatóságáról. A másik alapvetőbb, hogy előre a forrásszöveg írásakor nem tudjuk, hogy a

...-ok helyére hány oszlopnyi és hány sornyi konkrét szerkezeti cella megadás kellene. Mert ez nem dől el a

fordítási, hanem csak a futási időben, amikor a Java Virtuális Gép végrehajtja a

Labirintus labirintus = new Labirintus(10, 10);

példányosítást, a konkrét labirintus létrehozását.

Válasszunk más megoldást! Nem túl általános, de annál egyszerűbb megoldásként lássuk el az osztályt egy

olyan konstruktorral is, ami fix méretű labirintust csinál. Mivel a méret fix, így a konstruktornak nem

szükségesek paraméterek:

Labirintus() {

szerkezet = new boolean[][]{

{false,false,false,true,false,true,false,true,true,true},

{false,false,false,false,false,false,false,false,false,false},

{true,false,true,false,true,false,true,false,true,false},

{false,false,false,false,true,false,true,false,false,false},

{false,true,true,false,false,false,true,true,false,true},

{false,false,false,false,true,false,false,false,false,false},

{false,true,false,false,false,true,false,true,true,false},

{false,false,false,true,false,true,false,true,false,false},

Page 138:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

110 Created by XMLmind XSL-FO Converter.

{false,true,false,false,false,false,false,false,false,true},

{false,false,false,false,true,false,false,false,true,true}

};

magasság = szerkezet.length;

szélesség = szerkezet[0].length;

}

Most a logikai tömb elkészítésekor azt is megmondtuk, hogy a tömb logikai celláit milyen logikai értékkel

akarjuk feltölteni. Amikor a tömb elkészült, a szélességet és a magasságot már tőle kérjük el:

magasság = szerkezet.length;

szélesség = szerkezet[0].length;

Hogy teljesen világos legyen, jöjjön a következő ábrán egy kis tömbológia.

A kétdimenziós tömb egydimenziós tömbökből áll, példánknál maradva: a szerkezet egy olyan tömb, aminek

elemei (az ábrán a sorok) megint csak tömbök, így jön ki a két dimenzió.

A

szerkezet.length;

megadja a tömb méretét, hogy hány eleme van, azaz most, hogy hány sora van, hogy hány tömb eleme van. A

szerkezet[0].length;

megadja az első (azaz a 0.) elem méretét, az elem most tömb, mérete annyi, ahány eleme van, azaz most, ahány

logikai érték van egy sorban: tehát az oszlopok száma.

Begyakorolandó a kétdimenziós tömb bejárását a Vezérlési szerkezetek című pontban azzal folytatjuk, hogy

kiíratjuk az argumentum nélküli konstruktorral készített tömb szerkezetét.

A konstruktorokhoz visszatérve, válasszunk további más megoldást! A labirintus elképzelése során, a

négyzethálós lapon egy kétdimenziós tömb alakjában rajzoltuk le a labirintus szerkezetét. Készítsünk el egy

ennek a rajznak megfelelő szöveges állományt és osztályunkat lássuk el egy olyan konstruktorral, ami képes ezt

beolvasni! Ekkor majd így példányosítjuk a labirintus objektumunkat:

Page 139:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

111 Created by XMLmind XSL-FO Converter.

Labirintus labirintus = new Labirintus("labirintus.txt");

A szélességgel, magassággal kapcsolatban nem adunk át infót a konstruktornak, hiszen ezt a két számot a

labirintus rajzából, azaz majd az állományból is meg tudja állapítani maga a konstruktor is. Viszont

paraméterként adjuk a konstruktornak a tervrajznak megfelelő szöveges állomány nevét. Ennek az új

konstruktornak az elkészítését A labirintust állományból felépítő konstruktor című pontjában folytatjuk.

1.1.4.1.2. Saját szereplők feladat

A labirintusunk kincseit, szörnyeit és hősünket az a közös tulajdonság jellemzi, hogy valahol vannak a

labirintusban. Helyzetüket egy számpárral írhatjuk le:

int oszlop;

int sor;

ennek megfelelően, például a Szereplő nevű Java osztályba foglalva írhatjuk, hogy

class Szereplő {

int oszlop;

int sor;

}

Milyen lényeges jellemzőik legyenek még a szereplőknek? Azaz hogyan alakítsuk ki, álmodjuk meg a játék

világát, a labirintus játék programunk mikrokozmoszát? Milyen szereplőink lesznek, avagy amiért szép a

játékfejlesztés, e kérdés itt így is feltehető: milyen szereplőink legyenek?

A kincsnek mondjuk legyen értéke:

int érték;

a hősnek pontszáma, amiben a már összeszedett kincsek értékeit gyűjti majd:

int megtaláltÉrtékek;

Adott kincsről azt is tudnunk kell, hogy megtalálta-e már a hős vagy sem?

boolean megtalálva;

S lehet hosszan tervezgetni, rajzolgatni..., megint áttervezni, az egészet a papírkosárba dobni és párszor ezt újra

elismételni.

Page 140:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

112 Created by XMLmind XSL-FO Converter.

Ha azt akarjuk, hogy a Kincs osztályunk objektumai minden olyan jellemzővel rendelkezzenek, mint amikkel

az általánosabb Szereplő osztálybeli objektumok (vagy aki fonákkal gondolkozik: a Kincs nem más, mint egy

speciális Szereplő), akkor a Kincs osztállyal ki kell terjesztenünk a Szereplő osztályt, ekkor Javaban ezt

írjuk:

class Kincs extends Szereplő {

int érték;

boolean megtalálva;

}

Ekkor a Kincs osztályból példányosított objektumok a Szereplő osztály tulajdonságaival is rendelkezni

fognak, így végeredményben egy Kincs osztálybeli objektum a következő tulajdonság tagokkal fog rendelkezni:

int oszlop;

int sor;

int érték;

boolean megtalálva;

Ilyenkor azt is szoktuk mondani, hogy a Kincs osztály gyermeke a Szereplő osztálynak, vagy megfordítva,

hogy a Szereplő osztály őse a Kincs osztálynak.

A szereplők feladat arról szól, hogy mindenki képzelje el saját labirintusa szereplőit! Milyen további

tulajdonságokat tudunk elképzelni? Válaszunkat a saját Kincs, Hős, Szörny osztályainkban fogalmazzuk meg!

Mi magunk ennek a feladatnak a megoldását Az osztályok fejlődése: az öröklődés című fejezetben adjuk meg,

folytatva az itt megkezdett öröklődéssel kapcsolatos kérdések boncolgatását.

Milyen konstruktorral szereljük fel a Szereplő osztályt? Először is, a labirintus szereplőit el kell valahová

helyeznünk a labirintusban, ezt nehezíti, hogy nem tehetjük őket bárhová, legalábbis a falba nem, hanem csak

járatba, azaz a labirintus olyan pozíciójára, ami nem fal! Ebből a gondolatból következően már érezzük, hogy a

Szereplő és a Labirintus között van egy erős kapcsolat. A programtervező feladata ezt a kapcsolatot

valamilyen formában elkészíteni. Mi most azt a megoldást választjuk, hogy a Szereplő osztálybeli

objektumnak átadjuk annak a Labirintus osztálybeli objektumnak a referenciáját, amibe éppen bele akarjuk

helyezni, azaz a Szereplő osztálybeli konstruktorunkat így írjuk meg:

class Szereplő {

int oszlop;

int sor;

Labirintus labirintus;

Szereplő(Labirintus labirintus) {

this.labirintus = labirintus;

szereplőHelyeKezdetben();

}

}

1.1.4.2. Objektumok kommunikációja: a metódushívás

Page 141:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

113 Created by XMLmind XSL-FO Converter.

A tipikus OO program az egymással kölcsönható objektumok összessége. Az objektumok közötti kölcsönhatás,

kommunikáció az objektumok metódusainak hívásán keresztül valósul meg. Ha egy objektumnak üzenni

akarunk, ha egy objektum valamely szolgáltatását akarjuk igénybe venni vagy egészen egyszerűen szólva meg

akarjuk hívni egy objektum valamely függvényét, metódusát, akkor nem kell mást tennünk, mint leírni az

objektum referenciáját, azt követően egy pontot, majd a metódus nevét magát. Például korábban tárgyaltuk,

hogy a System.out, azaz a System osztálybeli out tag egy PrintStream osztálybeli objektum referenciáját,

azaz a mindenkori programunkhoz rendelt sztenderd kimenő csatorna objektum referenciáját tartalmazza. Ha

ennek az objektumnak akarok üzenni, például mondjuk azt, hogy írja ki a Helló, Világ! szöveget, akkor a

PrintStream osztály println() függvényét kell használnom a referencia utáni pontot követően írva tehát:

System.out.println("Helló, Világ!");

Nézzünk még néhány további példát a metódushívásra a Labirintus osztályból! Az i. kincstől megkérdezzük,

hogy megtalálta-e a hős.

// A hős rátalált valamelyik kincsre?

if(kincsek[i].megtalált(hős))

hős.megtaláltam(kincsek[i]);

Ha igen, akkor a hősnek átadjuk a megtalált kincset. A következő ciklusban az összes szörny lép egyet a hős

felé:

for(int i=0; i < szörnyek.length; ++i) {

szörnyek[i].lép(hős);

1.1.4.3. Az osztályok fejlődése: az öröklődés

Folytatjuk a játék világát absztraháló, a Saját szereplők feladat feladatban megkezdett osztályhierarchia

felépítését. Ott hagytuk abba, hogy a hős a megtalált kincsek értékeit a megtaláltÉrtékek változójában

gyűjtögeti majd.

class Hős extends Szereplő {

int megtaláltÉrtékek;

Hős(Labirintus labirintus) {

super(labirintus);

megtaláltÉrtékek = 0;

}

public void megtaláltam(Kincs kincs) {

megtaláltÉrtékek += kincs.érték();

}

A Hős osztály példányát felépítő Hős(Labirintus labirintus) konstruktor első dolga az ős, a Szereplő

osztály Szereplő(Labirintus labirintus) konstruktorának meghívása - ezt eredményezi a

super(labirintus); hívást tartalmazó első sor. Az ős korábban bemutatott konstruktora beállítja a

labirintus-t és elhelyezi a hős szereplőt valahová ebbe a labirintusba. Majd a Hős osztály megtaláltÉrtékek

tagja kapja meg a 0 kezdőértékét. A megtaláltÉrtékek tagot az osztály megtaláltam() módszerével növeli a

paraméterként jövő, épp megtalált kincs értékével.

Page 142:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

114 Created by XMLmind XSL-FO Converter.

Építsük tovább a hősünket absztraháló osztályt! Legyen a hősnek néhány élete, kezdetben mondjuk

ÉLETEK_SZÁMA darab, és minden esetben, amikor hősünket megeszik a labirintusban, ez az érték csökkenjen

eggyel! Ennek a tulajdonságnak a hordozására felveszünk egy életekSzáma egész típusú változót, amit az

ÉLETEK_SZÁMA = 5 konstans értékkel inicializálunk:

class Hős extends Szereplő {

int megtaláltÉrtékek;

public static final int ÉLETEK_SZÁMA = 5;

int életekSzáma = ÉLETEK_SZÁMA;

Hős(Labirintus labirintus) {

super(labirintus);

megtaláltÉrtékek = 0;

}

public void megtaláltam(Kincs kincs) {

megtaláltÉrtékek += kincs.érték();

}

public boolean megettek() {

if(életekSzáma > 0) {

--életekSzáma;

return false;

} else

return true;

}

Az osztály a megettek() nevű viselkedésében kezeli a felvett életekSzáma tagját. A függvény visszatérési

értékével jelzi, hogy él-e még egyáltalán a hős.

A Hős osztály végleges formáját a A Hős osztály című pontban tanulmányozhatja az Olvasó.

A például a [SOMMERVILLE KÖNYV] könyvben bemutatott UML jelöléseit használva az alábbi

osztálydiagrammal foglaljuk össze és fejlesztjük tovább terveinket.

Page 143:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

115 Created by XMLmind XSL-FO Converter.

A kézikönyvhöz készített osztályok közötti összes öröklési kapcsolatot könnyen megtalálhatja az érdeklődő

Olvasó, ha elugrik A csomagok szervezése című pontra, ahol az osztálynevek (a javadoc paranccsal készített

Java dokumentáció mintájára) tabulált szedésével jeleztük az öröklődést:

java.lang.Object

javattanitok.labirintus.Labirintus

javattanitok.labirintus.GenerikusLabirintus

javattanitok.labirintus.TöbbHősösLabirintus

javattanitok.labirintus.Szereplő

javattanitok.labirintus.Hős

javattanitok.labirintus.Kincs

javattanitok.labirintus.Szörny

java.lang.Throwable (implements java.io.Serializable)

java.lang.Exception

javattanitok.labirintus.RosszLabirintusKivétel

vagy ugyaninnen, de néhány oldallal későbbről idézve:

javax.microedition.lcdui.game.GameCanvas

javattanitok.LabirintusVaszon (implements java.lang.Runnable)

javattanitok.HálózatiLabirintus (implements java.lang.Runnable)

javattanitok.KorbásLabirintus

javattanitok.TávoliLabirintus (implements javattanitok.TávoliHősíthető)

javax.servlet.http.HttpServlet

javattanitok.LabirintusServlet

Page 144:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

116 Created by XMLmind XSL-FO Converter.

A labirintus példák absztrahálta világok bonyolódásával a világokat leíró osztályokat is fejlesztenünk kellett

egészen addig, hogy a hálózati labirintus világában az addig használt labirintus már nem volt megfelelő. Mivel

ebben a világban egy hős halála immár nem jelentette egyben a labirintus játék végét is, hiszen a hálózaton

keresztül jövő többi hős egyikük halálától függetlenül még nyugodtan bolyongana tovább a labirintusban. A

hálózati labirintus részletes kifejtését a TCP/IP - Hálózati Labirintus című pontban találjuk meg.

Természetes az a gondolat, hogy ennek a bonyolultabb világnak az absztrahálásához szükségünk lenne a

szokásos labirintusra, de annyi módosítással, hogy most már a bolyongó hős halála ne jelentse a labirintus

állapotának drasztikus megváltozását. A megoldás, hogy a régi osztály kiterjesztésével új osztályt készítünk,

azaz új osztályunkat a TöbbHősösLabirintus osztályt a Labirintus osztályból örököltetjük, majd a

Labirintus public int bolyong(Hős hős) viselkedését a TöbbHősösLabirintus osztályban

felüldefiniáljuk. Figyelje meg a kedves Olvasó, hogy a A TöbbHősösLabirintus osztály című pontban bemutatott

kód mennyivel rövidebb a A Labirintus osztály című pontba foglalt ős labirintus kódjától!

Ha összehasonlítjuk az ős public int bolyong(Hős hős) függvényének megfelelő

for(int i=0; i < szörnyek.length; ++i) {

szörnyek[i].lép(hős);

if(szörnyek[i].megesz(hős)) {

játékÁllapot = JÁTÉK_MEGY_MEGHALT_HŐS;

if(hős.megettek())

játékÁllapot = JÁTÉK_VÉGE_MEGHALT_HŐS;

return játékÁllapot;

}

}

részletét a származtatott osztály public int bolyong(Hős hős) megfelelő részletével:

for(int i=0; i < szörnyek.length; ++i) {

szörnyek[i].lép(hős);

if(szörnyek[i].megesz(hős)) {

if(hős.megettek())

// De ez a játék vége csak a hős végét

// jelenti, a labirintusét nem!

return JÁTÉK_VÉGE_MEGHALT_HŐS;

else

return JÁTÉK_MEGY_MEGHALT_HŐS;

}

}

akkor láthatjuk, hogy a felüldefiniált viselkedés már nincs hatással a játék állapotára, azaz új osztályunkban egy

hős halála a labirintus világára már nincs hatással.

1.1.4.3.1. Többalakúság

A többalakúságra (polimorfizmusra) példát láthatunk, ha a HálózatiLabirintus osztályban a labirintusunkat

így vesszük fel:

public class HálózatiLabirintus implements Runnable {

Page 145:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

117 Created by XMLmind XSL-FO Converter.

/** A játék aktuális labirintusa, minden hálózati hős ebben mozog. */

// TöbbHősösLabirintus labirintus;

Labirintus labirintus;

viszont a továbbfejlesztett TöbbHősösLabirintus osztálybeli objektumként hozzuk létre, azaz a

HálózatiLabirintus konstruktorban így példányosítjuk a labirintust:

public HálózatiLabirintus(String labirintusFájlNév) throws

RosszLabirintusKivétel {

// A labirintus elkészítése állományból

labirintus = new TöbbHősösLabirintus(labirintusFájlNév);

példánkban a többalakúság az, hogy a Labirintus labirintus nem egy Labirintus osztálybeli objektum,

hanem a Labirintus osztály egy leszármazottjabeli, a TöbbHősösLabirintus osztálybeli objektum. Ha ennek

a labirintus objektumnak meghívjuk a public int bolyong(Hős hős) metódusát, akkor a felüldefiniáló,

azaz a TöbbHősösLabirintus osztálybeli public int bolyong(Hős hős) függvény fog lefutni.

Melyik metódus hívódik?

Szúrjunk be két logoló sort a Labirintus (szülő) és a TöbbHősösLabirintus (gyermek) osztálybeli

public int bolyong(Hős hős) függvénybe:

System.out.println("A gyermekbeli hívódott");

System.out.flush();

System.out.println("A szülőbeli hívódott");

System.out.flush();

majd a HálózatiLabirintus osztályt futtatva győződjünk meg róla, hogy a gyermekbeli módszer

hívódik!

1.1.5. Mi történik a metódusokban?

Az OO program osztályainak, az osztályok közötti kapcsolatok megállapításának folyamata inkább egy

szervezési és átfogó jellegű stratégiai tervezési feladat. Ezzel szemben az osztály metódusainak implementálása

taktikai jellegű. Ez az a hely, ahová a klasszikus imperatív programozó visszaszorult az OO paradigmaváltás

sikere után. Itt programozzuk be azt, amit csinál a program, az osztály vagy az osztálybeli objektum. Alapvető

imperatív eszközeink ebben, a programunk tipikusan kódolási szakaszában a változók.

1.1.5.1. Típusok és változók

Javaban általában a típusok osztályok, a változók pedig tipikusan valamilyen osztálybeli objektum referenciáját

hordozzák értékként. Kivételt képeznek viszont az úgynevezett primitív típusok, melyek a boolean, byte, char,

double, float, int, long.

Az ilyen típusú változókat osztályok-objektumok nélkül használhatjuk, ők az imperatív programozásban

klasszikusan megszokott változók. Javaban a primitív típusok változóinak értéktartománya meghatározott,

ahogy ezt a következőkben részletesen ismertetjük.

2.1. táblázat - A Java primitív típusai

Típus Minimum Maximum

Page 146:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

118 Created by XMLmind XSL-FO Converter.

Típus Minimum Maximum

boolean false true

byte -27 27-1

char \u0000 \uffff

double 2-1074 (2-2-52)*21023

float 2-149 (2-2-23)*2127

int -231 231-1

long -263 263-1

1.1.5.2. Vezérlési szerkezetek

A vezérlési szerkezetek tipikusan az iteráció és a szelekció megszervezésére adnak lehetőséget programjaink

forrásszövegében. Előbbivel, azaz a ciklusok szervezésével, a for, while és do while kulcsszavak említése

során A Java szófajok, illetve kicsit bővebben A Java mondattana című pontokban ismerkedtünk, itt folytatjuk a

téma tárgyalását. A szelekció kapcsán Javaban az if else, if else if else és switch case szerkezeteket

említhetjük, e konstrukciók megismerését is az imént hivatkozott pontokban kezdtük meg.

1.1.5.2.1. toString()

Elegáns szokás osztályainkat ellátni egy toString() nevű, sztringet visszaadó, paraméter nélküli metódussal.

A visszaadott sztring hivatása, hogy szemléltesse valamilyen értelmes formában az objektumot. Labirintus

osztályunk tekintetében ez a forma lehet a labirintus szélessége, magassága és esetleg a szerkezete is.

public String toString() {

StringBuffer stringBuffer = new StringBuffer();

for(int i=0; i<magasság; ++i) {

for(int j=0; j<szélesség; ++j) {

if(szerkezet[i][j])

stringBuffer.append("X");

else

stringBuffer.append("+");

}

stringBuffer.append("\n");

}

return stringBuffer.toString();

}

A külső

for(int i=0; i<magasság; ++i) {

Page 147:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

119 Created by XMLmind XSL-FO Converter.

ciklus i indexe a tömb sorain fut majd végig (nullától a magasság-1 értékig), s egy adott i. soron belül ebbe a

külső ciklusba ágyazott belső

for(int j=0; j<szélesség; ++j) {

ciklus j indexe a tömb oszlopain fut majd végig (nullától a szélesség-1 értékig). Ennek megfelelően a belső

ciklus magjában az

if(szerkezet[i][j])

...

else

...

elágazó utasítás, ha az i. sor j. oszlopában igaz érték (azaz nálunk fal és ennek megfelelően az if utasítás

fejében lévő szerkezet[i][j] kifejezés szó értéke igaz) van, akkor az X-et nyomtató ágra, ha hamis, akkor a +

jelet nyomtató ágra viszi a vezérlést.

Az így implementált toString() függvényünk tipikusan a következő formájú sztringet adja vissza, melyen a

labirintus felépítményét tanulmányozhatjuk, ahol az X betű jelzi a járatot és a + betű a falat.

+++X+X+XXX

++++++++++

X+X+X+X+X+

++++X+X+++

+XX+++XX+X

++++X+++++

+X+++X+XX+

+++X+X+X++

+X+++++++X

++++X+++XX

1.1.5.2.2. A labirintust állományból felépítő konstruktor

Itt egyben folytatjuk az Objektumok létrehozása: a konstruktor című fejezetben megkezdett - olyan

konstruktorral szereljük fel a Labirintus osztályt, ami egy állományból is képes felépíteni a labirintus

szerkezetét - példánkat. A labirintus szerkezetét leíró szöveges állomány nevét a konstruktor paraméterként

kapja meg, labirintusFájlNév nevű formális paraméterében.

public Labirintus(String labirintusFájlNév) {

}

Először kitaláljuk annak az állománynak a szerkezetét, amiben leírjuk a labirintusunkat: mondjuk a dupla

perjelek utáni sorokkal nem foglalkozunk, itt lehetnek majd a kommentek. Aztán jöjjön négy szám: a kincsek

száma, a szörnyek száma és a labirintus szélessége, magassága. Végül következzék maga a labirintus 0, 1

jegyekkel lekódolva: az 1 jelentse a falat, a 0 a járatot! S íme a mi példánk erre a szöveges állományra:

Page 148:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

120 Created by XMLmind XSL-FO Converter.

//

// labirintus.txt

//

// DIGIT 2005, Javat tanítok

// Bátfai Norbert, [email protected]

//

// A labirintus szerkezetét megadó állomány,

// szerkezete a következő:

//

// a kincsek száma

// a szörnyek száma

// a labirintus szélessége

// magassága

// fal=1 járat=0 ...

// .

// .

// .

6

3

10

10

0 0 0 1 0 1 0 1 1 1

0 0 0 0 0 0 0 0 0 0

1 0 1 0 1 0 1 0 1 0

0 0 0 0 1 0 1 0 0 0

0 1 1 0 0 0 1 1 0 1

0 0 0 0 1 0 0 0 0 0

0 1 0 0 0 1 0 1 1 0

0 0 0 1 0 1 0 1 0 0

0 1 0 0 0 0 0 0 0 1

0 0 0 0 1 0 0 0 1 1

Állományból beolvasni egy Java I/O csatorna objektumon keresztül tudunk, tehát első lépésünk ennek

létrehozása

java.io.BufferedReader szövegesCsatorna = new java.io.BufferedReader(

new java.io.FileReader(labirintusFájlNév));

a nevével megadott állomány fölött nyitunk egy karakteres állományokat Olvasó FileReader bejövő csatornát,

majd most e fölött rögtön egy BufferedReader csatornát. Ezen keresztül akarunk olvasni az állományból, mert

ettől a csatorna objektumtól lehet soronkénti olvasást (readLine() függvénye) kérni, ami számunkra most

kényelmes megoldásnak tűnik. Mert a dupla perjellel kezdődő sorok figyelmen kívül hagyása után beolvassuk

az első négy sort és a megfelelő számmá alakítjuk, majd beolvasunk magasságnyi sort és soronként letördeljük,

hogy az adott cella éppen fal vagy járat-e.

String sor = szövegesCsatorna.readLine();

while(sor.startsWith("//"))

sor = szövegesCsatorna.readLine();

kincsekSzáma = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

szörnyekSzáma = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

szélesség = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

Page 149:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

121 Created by XMLmind XSL-FO Converter.

magasság = Integer.parseInt(sor);

Ha a program eddig sikerrel futott, akkor tudjuk, hogy milyen széles és magas a labirintusunk, azaz mekkora

logikai tömböt kell létrehoznunk, hogy ezt az adatszerkezetet el tudjuk tárolni

szerkezet = new boolean[magasság][szélesség];

Jöhet a szövegállományban megadott labirintus szerkezet beolvasása és ez alapján a szerkezetet leíró logikai

tömb megfelelő értékeinek megadása. Amilyen magas a labirintusunk, annyi sort kell feldolgoznunk

for(int i=0; i<magasság; ++i) {

sor = szövegesCsatorna.readLine();

java.util.StringTokenizer st =

new java.util.StringTokenizer(sor);

A StringTokenizer objektum segítségével tudjuk a beolvasott sort darabjaira tördelni, mely szövegdarabokat

szóközök választanak el egymástól. A következő darabot a nextToken() metódussal lehet elkérni.

for(int i=0; i<magasság; ++i) {

sor = szövegesCsatorna.readLine();

java.util.StringTokenizer st =

new java.util.StringTokenizer(sor);

for(int j=0; j<szélesség; ++j) {

String tegla = st.nextToken();

if(Integer.parseInt(tegla) == 0)

szerkezet[i][j] = false;

else

szerkezet[i][j] = true;

A Integer osztály statikus parseInt() módszerével a beolvasott szövegdarabból számot készítünk, s majd

attól függően, hogy ez a szám 0 vagy 1, beállítjuk a labirintus szerkezetét reprezentáló tömb megfelelő elemét,

hamisra vagy igazra, azaz falra vagy járatra.

Az állományból beolvasó konstruktor csontvázát ezzel átvettük, a hús-vér konstruktort majd A tiszta OO

labirintus - Labirintus Világ című pontban folytatva adjuk meg.

1.1.5.2.3. String hasonlító feladat

Olvassuk be a labirintus szerkezetét anélkül, hogy a tégla referenciájú szövegdarabokat számmá alakítanánk!

Megoldásként használjuk a String osztály equals() módszerét:

if("0".equals(tegla))

szerkezet[i][j] = false;

else

szerkezet[i][j] = true;

Page 150:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

122 Created by XMLmind XSL-FO Converter.

1.1.5.2.4. null referencia feladat

Miért szerencsésebb általában a "0".equals(tegla) utasítás, mint a tegla.equals("0")?

Mert mi történik, ha a tegla értéke éppen null? Megtudja az Olvasó, ha az alábbi osztályt kipróbálja!

public class Tégla {

public static void main(String[] args) {

String tegla = "QWERT";

if(tegla.equals("QWERT"))

System.out.println("A tegla tartalma most QWERT");

tegla = null;

if(tegla.equals("QWERT"))

System.out.println("A tegla tartalma most QWERT");

}

}

Fordítás és futtatás után

C:\...> javac Tégla.java

C:\...> java Tégla

A tegla tartalma most QWERT

Exception in thread "main" java.lang.NullPointerException

at Tégla.main(Tégla.java:12)

Olvassuk el a hibaüzeneteket

Akár a fordítás, akár a futtatás során igaz, hogy mindig érdemes és fontos a kiírt hibát gondosan

tanulmányozni. Az egyik legalapvetőbb információ, hogy a hiba hol keletkezett, mert a program

szövegének ezt a jelzett helyét megtekintve az idővel kialakuló rutinos szem már könnyen észreveheti a

hibát. Egy futási hibával megáll a programunk, mivel működése közben egy java.lang.NullPointerException

kivétel váltódik ki, mert olyan objektumra hivatkoztunk, amikor a - valójában null és nem egy vélt sztring

objektum referencia értékű - tegla-nak hívni akartuk az equals() metódusát, ami gyakorlatilag nem is létezik.

Persze most könnyű észrevenni, hogy nem létezik, hiszen a tegla = null; utasítással mi magunk töröltük, de

egy bonyolultabb programban ez nem mindig látszik, ezért érdemes a sztring literálként megadott, ezért mindig

létező „0” sztring objektumnak hívni esetünkben az equals() metódusát. Ezzel tipikusan megspórolunk egy

if(tegla != null) jellegű feltételvizsgálatot, amivel persze az ilyen típusú problémákat szintén orvosolni

lehetne:

public class Tégla {

public static void main(String[] args) {

String tegla = "QWERT";

if(tegla.equals("QWERT"))

System.out.println("A tegla tartalma most QWERT");

tegla = null;

Page 151:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

123 Created by XMLmind XSL-FO Converter.

if(tegla != null)

if(tegla.equals("QWERT"))

System.out.println("A tegla tartalma most QWERT");

}

}

de láthatóan jóval hatékonyabb az alábbi módon megszervezni a kódot.

public class Tégla {

public static void main(String[] args) {

String tegla = "QWERT";

if(tegla.equals("QWERT"))

System.out.println("A tegla tartalma most QWERT");

tegla = null;

if("QWERT".equals(tegla))

System.out.println("A tegla tartalma most QWERT");

}

}

A RuntimeException típusú hibák kezeléséről 1.

A hamarosan következő Kivételkezelés című pontban látjuk majd, hogy a kivéteket hogyan kezelhetjük

programunkból, hogyan kaphatjuk el őket. Ott fogunk egy rossz példát mutatni arra a rossz gyakorlatra,

amikor például ezt a RuntimeException kivételt kezelni próbálja a programozó. (A kapott

NullPointerException kivétel osztály a RuntimeException gyermeke.) Már itt hangsúlyozzuk,

hogy az ilyen típusú hibákat a program szövegének gondosabb kifejlesztésével kell elkerülni és nem a

kivételkezelést mint tüneti kezelést alkalmazni erre.

1.1.6. Eseménykezelés

Esemény alatt azt értjük, mint a köznyelvben is: esemény az, amikor történik valami. Speciálisan, amikor a

program világában történik valami. Például megmozdítjuk az egeret, becsukjuk a program ablakát stb. Az

események, mint Javaban minden, maguk is objektumok.

Az események kezelése az adott eseménytípusnak megfelelő interfészeken keresztül történik. A programozó

azokban az osztályaiban, ahol az események keletkeznek, jelzi, hogy melyik objektum dolgozza majd fel az

eseményeket. Ennek a feldolgozó objektumnak pedig tudni kell fogadnia a megfelelő eseményobjektumokat.

Például a mobilos labirintus példánkban egy LabirintusVaszon vászon objektum uralja a mobil kijelzőjét,

amit a LabirintusMIDlet osztályban készítünk el:

labirintusVászon = new LabirintusVaszon();

// A kilépés parancs elkészítése

kilépésParancs = new javax.microedition.lcdui.Command("Kilép",

javax.microedition.lcdui.Command.EXIT, 1);

// és a labirintus vászonra helyezése

labirintusVászon.addCommand(kilépésParancs);

// az eseményeket (most kilépés parancs) itt dolgozzuk fel

labirintusVászon.set(this);

Page 152:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

124 Created by XMLmind XSL-FO Converter.

A telefon Kilép gombnak megfelelő szoftbillentyűjét megnyomva a megfelelő Command objektummal

meghívódik a labirintusVászon-ba a labirintusVászon.setCommandListener(this); parancs

eseményfigyelőt beállító hívással bejegyzett objektum commandAction() eseménykezelő függvénye. Ez a this

objektum most maga a LabirintusMIDlet osztály, aminek fejét ennek megfelelően így írtuk:

public class LabirintusMIDlet extends javax.microedition.midlet.MIDlet

implements javax.microedition.lcdui.CommandListener {

azaz implementálja a CommandListener parancsokat figyelő interfészt. Ennek az interfésznek egyetlen

metódusa van, az említett commandAction(). Tehát a LabirintusMIDlet osztályban implementálnunk kell ezt

a függvényt:

/**

* A labirintus játék parancsainak (jelen esetben egy ilyen van,

* a kilépés) kezelése.

*

* @param command parancs, ami keletkezett

* @param displayable valamelyik képernyőn

*/

public void commandAction(javax.microedition.lcdui.Command parancs,

javax.microedition.lcdui.Displayable képernyő) {

if (képernyő == labirintusVászon) {

if (parancs == kilépésParancs) {

// Leállítjuk a labirintus játék szálát

labirintusVászon.játékKilép();

// Leállítjuk a programot

kijelző.setCurrent(null);

destroyApp(true);

notifyDestroyed();

}

}

}

Ha a használni kívánt eseménykezelő interfészben több metódus van, akkor sokszor kényelmetlen a függvény

fejében jelezni az interfész implementálását, mert ekkor az osztályban az interfész minden metódusának meg

kell adni az implementációját. Amivel persze éppen nem akarunk foglalkozni, azt üres testtel implementálva.

Mégis kényelmesebb az úgynevezett adapter osztályok használata, akik a megfelelő interfész minden

módszerének megadják az üres testű implementációját, mi pedig ezt az osztályt kiterjesztjük és a minket érintő

módszereit felüldefiniáljuk: így nekünk nem kell lélekölően a számos üres testű függvény implementációt

begépelnünk. Erre számos példát tudunk mutatni a kézikönyv forrásaiban, például a LabirintusJáték

osztályban a billentyűzet eseményeket dolgozzuk fel a java.awt.event.KeyAdapter adapter osztállyal:

// A hős mozgatása a KURZOR billenytűkkel, ESC kilép

addKeyListener(new java.awt.event.KeyAdapter() {

public void keyPressed(java.awt.event.KeyEvent billentyűEsemény) {

int billentyű = billentyűEsemény.getKeyCode();

if(!játékVége)

switch(billentyű) { // hős mozgatása

case java.awt.event.KeyEvent.VK_UP:

hős.lépFöl();

break;

case java.awt.event.KeyEvent.VK_DOWN:

hős.lépLe();

Page 153:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

125 Created by XMLmind XSL-FO Converter.

break;

case java.awt.event.KeyEvent.VK_RIGHT:

hős.lépJobbra();

break;

case java.awt.event.KeyEvent.VK_LEFT:

hős.lépBalra();

break;

}

// Kilépés a játékból

if(billentyű == java.awt.event.KeyEvent.VK_ESCAPE)

játékKilép = true;

// A játékban történt változások a képernyőn

// is jelenjenek meg

rajzolniKell();

};

});

vagy a MandelbrotHalmazNagyító osztályunkban az egéreseményeket dolgozzuk fel a

java.awt.event.MouseAdapter adapterrel:

// Egér kattintó események feldolgozása:

addMouseListener(new java.awt.event.MouseAdapter() {

// Egérkattintással jelöljük ki a nagyítandó terület

// bal felső sarkát vagy ugyancsak egér kattintással

// vizsgáljuk egy adott pont iterációit:

public void mousePressed(java.awt.event.MouseEvent m) {

// Az egérmutató pozíciója

x = m.getX();

y = m.getY();

// Az 1. egér gombbal a nagyítandó terület kijelölését

// végezzük:

if(m.getButton() == java.awt.event.MouseEvent.BUTTON1 ) {

// A nagyítandó kijelölt terület bal felső sarka: (x,y)

// és szélessége (majd a vonszolás növeli)

mx = 0;

my = 0;

repaint();

} else {

// Nem az 1. egér gombbal az egérmutató mutatta c

// komplex számból indított iterációkat vizsgálhatjuk

MandelbrotIterációk iterációk =

new MandelbrotIterációk(

MandelbrotHalmazNagyító.this, 50);

new Thread(iterációk).start();

}

}

// Vonszolva kijelölünk egy területet...

// Ha felengedjük, akkor a kijelölt terület

// újraszámítása indul:

public void mouseReleased(java.awt.event.MouseEvent m) {

if(m.getButton() == java.awt.event.MouseEvent.BUTTON1 ) {

...

avagy ugyanitt az egérmozgásával kapcsolatos eseményeket a java.awt.event.MouseMotionAdapter

adapterrel:

// Egér mozgás események feldolgozása:

addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {

// Vonszolással jelöljük ki a négyzetet:

public void mouseDragged(java.awt.event.MouseEvent m) {

Page 154:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

126 Created by XMLmind XSL-FO Converter.

// A nagyítandó kijelölt terület szélessége és magassága:

mx = m.getX() - x;

my = m.getY() - y;

repaint();

}

});

Számos további példát említhetnénk még, de csak a további fő típusokra utalva: a GaltonDeszka osztályban

foglalkozunk az ablakkal kapcsolatos eseményekkel:

// Az ablak bezárásakor kilépünk a programból.

addWindowListener(new java.awt.event.WindowAdapter() {

public void windowClosing(java.awt.event.WindowEvent e) {

setVisible(false);

System.exit(0);

}

});

illetve a például az ExorTitkositoGUI osztályban nyomógombon való kattintást dolgozunk fel:

kódolButton.addActionListener(

new java.awt.event.ActionListener() {

public void actionPerformed(java.awt.event.ActionEvent

e) {

Továbbá érdekességként említjük, hogy például a rendszer értesítési területéről érkező eseményeket dolgoz fel a

LabirintusAlkalmazás osztály. A Pontmátrix osztályban pedig egy legördülő menüből vesszük át a

felhasználói inputot.

1.1.7. Kivételkezelés

Ha a program futása közben nem azt csinálja, amit a normális működése során a programozója feltételezett,

hanem valami más ritkán bekövetkezőt, nem vártat, szokatlant, hibásat - egyszóval valami kivételeset -, akkor

azt mondjuk, hogy kivétel keletkezett. A kivételek, mint Javaban minden, maguk is objektumok. A program

szövegének azt a részét, amit a programozó figyelni akar, hogy a végrehajtása közben keletkezik-e kivétel, egy

try kulcsszóval bevezetett blokkba kell foglalni. Ha bekövetkezik egy kivétel, akkor a program végrehajtása a

tartalmazó try blokknak megfelelő catch kulcsszóval bevezetett blokkban folytatódik.

Egyszerű példaként folytassuk a Vezérlési szerkezetek pontban megkezdett, állományból olvasó konstruktor

írását! A labirintus szerkezetét leíró állomány a programon kívüli erőforrás, ezért is könnyű vele a játékot

variálni, mert nem kell a programhoz nyúlnunk, ha a labirintusnak más szerkezetet szeretnénk. Viszont ez a

programon kívüliség számos probléma (vagy jelen terminológiánkban: kivétel) forrása lehet. Gondoljunk arra

például, hogy hogyan viselkedjen a program akkor, ha nincs meg ez az állomány! Ha a labirintus felépítése

során valami gondunk támad, azaz a konstruktor futása során kivétel keletkezik, akkor az ilyen nagyobb

problémákra való válaszadást a hívóra, azaz arra bízzuk, aki létre akarta hozni ily módon a labirintust. Ezért a

konstruktor fejében jelezzük, hogy megszakíthatja futását és egy RosszLabirintusKivétel objektumot dobhat

a hívónak, amely objektumba becsomagoltuk ennek a valamilyen nagyobb hibának a leírását.

public Labirintus(String labirintusFájlNév) throws RosszLabirintusKivétel {

}

Page 155:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

127 Created by XMLmind XSL-FO Converter.

Vegyük most szemügyre a br referenciájú, BufferedReader osztálybeli objektum példányosításának pontos

forráskódrészletét!

java.io.BufferedReader szövegesCsatorna = null;

try {

szövegesCsatorna = new java.io.BufferedReader(

new java.io.FileReader(labirintusFájlNév));

Ez az objektum a labirintusunkat leíró szöveges állományra nyitott csatorna objektum, amin keresztül

beolvassuk a labirintus szerkezetének sorait a BufferedReader osztálybeli objektum readLine() metódusával

a külső for ciklusban. Itt a program feltételezett normális működésétől való eltérés, azaz kivétel például az

lehet, hogy a program nyitni akarja a szöveges állományra a csatorna objektumot, de a szöveges állomány nem

létezik, mert például nem megfelelő helyre másoljuk.

De más kivételekbe is beleszaladhat a program, például a beolvasott első 4 adat nem szám, hanem egy egyszerű

elírás miatt példának okáért egy betű

try {

kincsekSzáma = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

szörnyekSzáma = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

szélesség = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

magasság = Integer.parseInt(sor);

szerkezet = new boolean[magasság][szélesség];

} catch(java.lang.NumberFormatException e) {

throw new RosszLabirintusKivétel("Hibás a kincsek, szörnyek száma, "

+"szélesség, magasság megadási rész.");

}

Ha itt a try blokkba foglalt kódrészletnek bármely pontján kivétel keletkezik, akkor a végrehajtás a catch

blokknál folytatódik, s ha ez a kivétel a szövegdarabok számmá konvertálása kapcsán keletkezett (amit az mutat

meg, hogy a kivétel objektum a NumberFormatException osztálybeli) akkor a vezérlés ebben a catch

blokkban folytatódik. Ha a kincsek vagy szörnyek számával lenne a baj, akkor azt itt még értelmesen is tudnánk

kezelni, mert például azt mondanánk, hogy legyen 3 kincs, ha a szöveges állományban a szám helyett mondjuk

tévedésből egy „a” betűt adtunk meg. Viszont a labirintus szélességénél és magasságánál már nem tudunk ilyen

jó hibajavítást javasolni, mert ha itt mondunk egy számot hasraütésre, az biztos nem lesz éppen annyi, ahány

oszlop és sor adat szerepel lejjebb. Ezért érdekes megoldást alkalmazunk kezelésként: nem kezelünk, hanem

tovább dobunk egy kivételt.

throw new RosszLabirintusKivétel("Hibás a kincsek, szörnyek száma,

szélesség, magasság megadási rész.");

ne feledjük, hogy try-catch blokkunk egy másik ilyen blokkba van ágyazva

Page 156:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

128 Created by XMLmind XSL-FO Converter.

try {

szövegesCsatorna = new java.io.BufferedReader(

new java.io.FileReader(labirintusFájlNév));

String sor = szövegesCsatorna.readLine();

while(sor.startsWith("//"))

sor = szövegesCsatorna.readLine();

try {

kincsekSzáma = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

szörnyekSzáma = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

szélesség = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

magasság = Integer.parseInt(sor);

szerkezet = new boolean[magasság][szélesség];

} catch(java.lang.NumberFormatException e) {

throw new RosszLabirintusKivétel("Hibás a kincsek, szörnyek száma,

szélesség, magasság megadási rész.");

}

// ITT VAN A SOROK OSZLOPOK FELDOLGOZÁSA

} catch(java.io.FileNotFoundException e1) {

throw new RosszLabirintusKivétel("Nincs meg a fájl: " + e1);

} catch(java.io.IOException e2) {

throw new RosszLabirintusKivétel("IO kivétel történt: "+e2);

} catch(java.util.NoSuchElementException e3) {

throw new RosszLabirintusKivétel("Nem jó a labirintus szerkezete: "+e3);

} finally {

if(szövegesCsatorna != null) {

try{

szövegesCsatorna.close();

} catch(Exception e) {}

}

}

A befoglaló try blokk valamely catch ága elkapja a dobott RosszLabirintusKivétel kivételünket? Nem,

mert nincs ilyen ága! Ezért ez a kivétel tovább dobódik a hívónak. Nézzük mit csinál ezzel a továbbdobott

kivétellel a LabirintusVilág példaprogram mint hívó. A LabirintusVilág konstruktora készíti el a

labirintust, de a RosszLabirintusKivétel kivételt ő sem kezeli, csak jelzi, hogy ha ilyen lenne, akkor ő dobná

tovább a hívónak.

public LabirintusVilág(String labirintusFájlNév) throws RosszLabirintusKivétel {

Page 157:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

129 Created by XMLmind XSL-FO Converter.

// A labirintus elkészítése állományból

labirintus = new Labirintus(labirintusFájlNév);

A hívó main()-jében van a megfelelő kezelő:

public static void main(String[] args) {

try {

new LabirintusVilág(args[0]);

} catch(RosszLabirintusKivétel rosszLabirintusKivétel) {

System.out.println(rosszLabirintusKivétel);

}

}

s itt találjuk a kezelést is: kiírjuk, hogy mi volt a probléma a labirintus elkészítése során, majd a program leáll.

Milyen kivételek váltódhatnak itt ki? Ugye nem az elvárt normális működés, ha a labirintust leíró szöveges

állományunk nincs meg, ekkor egy java.io.FileNotFoundException kivétel objektum keletkezik még az

elején, amikor a csatornát ki akarjuk nyitni az állomány felett. Ha sikerül megnyitni az állomány felett csatornát,

a sorok olvasása vagy a csatorna lezárása során keletkezhet java.io.IOException kivétel. Ha mondjuk

elrontjuk ezt a szöveges állományt, az egyik sorában letöröljük az utolsó számot, akkor amikor éppen ezt a

hiányzó számot kellene beolvasni, azaz a

String tegla = st.nextToken();

utasítás végrehajtásakor egy java.util.NoSuchElementException kivétel fog kiváltódni. Ha nem kitörölünk,

hanem csak mondjuk átírjuk egy „a” betűre, akkor (lást az imént végigjátszott esetet) egy

java.lang.NumberFormatException kivétel váltódik ki, amikor számmá próbáljuk alakítani a már beolvasott

szövegdarabot.

Nézzünk egy olyan részt, ahol valódi kezelést alkalmaztunk, a sorok és oszlopok feldolgozásánál:

for(int i=0; i<magasság; ++i) {

sor = szövegesCsatorna.readLine();

java.util.StringTokenizer st =

new java.util.StringTokenizer(sor);

for(int j=0; j<szélesség; ++j) {

String tegla = st.nextToken();

try {

if(Integer.parseInt(tegla) == 0)

szerkezet[i][j] = false;

else

szerkezet[i][j] = true;

} catch(java.lang.NumberFormatException e) {

System.out.println(i+". sor "+j+". oszlop "+e);

Page 158:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

130 Created by XMLmind XSL-FO Converter.

szerkezet[i][j] = false;

}

}

}

Itt azt is meg tudjuk mondani, hogy a labirintust leíró állomány melyik része volt hibás és menet közben javítjuk

is, azaz azt tételezzük fel, hogy ott 0 áll, ezért a kezelő blokkban hamisra állítjuk a tömb megfelelő elemét.

Továbbá egy ilyen hiba miatt nem szakad meg a állomány további feldolgozása!

2.2. példa - A RuntimeException típusú hibák kezeléséről 2.

A korábbi, A RuntimeException típusú hibák kezeléséről 1. című pontban említett elkerülendő és rossz

gyakorlatot mutatjuk be itt. Úgy módosítjuk a Tégla osztályt, hogy elkapjuk a NullPointerException

kivételt:

public class Tégla {

public static void main(String[] args) {

String tegla = "QWERT";

if(tegla.equals("QWERT"))

System.out.println("A tegla tartalma most QWERT");

tegla = null;

try {

if(tegla.equals("QWERT"))

System.out.println("A tegla tartalma most QWERT");

} catch(RuntimeException e) {

e.printStackTrace(System.out);

System.out.flush();

}

System.out.println("A végén vagyok.");

}

}

Láthatóan programunk nem állt le, a kivételt kezeltük, de mégis: ennek a gyakorlatnak nincs értelme! Mert a

példaként tárgyalt hiba, hogy egy (már vagy még) nem létező objektum metódusát akarjuk meghívni, szinte

bárhol előfordulhat a programunk szövegében, így melyik részét figyelnénk try-catch blokkjainkkal? Az ilyen

típusú hibákat a program szövegének gondos kifejlesztésével, megírásával kerülhetjük el értelmesen!

1.1.8. Párhuzamos végrehajtás

Javaban a párhuzamos végrehajtás szál objektumok formájában valósul meg. A szálak az alapvető, azaz a

java.lang csomagbeli Thread osztály leszármazottai.

1.1.8.1. Thread objektumok

A párhuzamosan végezhető, végezendő tevékenységeket tehát olyan osztályokban implementáljuk, amik

kiterjesztik a java.lang.Thread osztályt. Nincs más dolgunk, mint a párhuzamosan végrehajtatni óhajtott

tevékenységet az osztály run() módszerében implementálni. Viszont mivel Javaban az öröklődés egyszeres,

azaz csak egy osztályt szerepeltethetünk az extends kulcsszó után, így a

Page 159:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

131 Created by XMLmind XSL-FO Converter.

public class Párhuzamos extends Thread {

osztályt például már nem tudnánk egy másik osztályból is származtatni. Ebben segít a Runnable interfész.

1.1.8.2. Runnable objektumok

A Runnable interfésznek egyetlen metódusa a run() metódus. A Runnable interfészt implementáló osztályokat

szoktuk Runnable objektumoknak is nevezni. Az osztályunkat származtatjuk onnan, ahonnan származtatnunk

kell, jelezzük, hogy osztályunkban implementáljuk a szóban forgó interfészt és osztályunk run() módszerében

implementáljuk a párhuzamosan végrehajtandó tevékenységet. Például Sejtautomata osztályunk örököl a

java.awt.Frame osztályból, de a sejtautomata szimulációt egy párhuzamos programszálában végzi.

public class Sejtautomata extends java.awt.Frame implements Runnable {

Ehhez, ennél a Runnable interfészt kiterjesztő módszernél is készítünk szálat, aminek paramétereként adjuk

meg a Runnable objektum referenciáját, például az említett osztály konstruktorában:

new Thread(this).start();

ahol a start() metódus meghívásával rögtön indítottuk is az elkészített szálat. Ez a run(), a párhuzamosan

végrehajtandó kódot tartalmazó módszer implicit meghívását jelenti:

/** A sejttér időbeli fejlődése. */

public void run() {

while(true) {

try {

Thread.sleep(várakozás);

} catch (InterruptedException e) {}

időFejlődés();

repaint();

}

}

A kézikönyv példái között számos további esetben láthatjuk és tanulmányozhatjuk a Runnable interfész

használatát. Csak néhányat kiragadva, például a LabirintusKiszolgáló osztályból:

public class LabirintusKiszolgáló

extends javattanitok.labirintus.TöbbHősösLabirintus

implements LabirintusOperations, Runnable {

vagy a LabirintusVaszon osztályt megnézve:

public class LabirintusVaszon extends javax.microedition.lcdui.game.GameCanvas

implements Runnable {

Page 160:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

132 Created by XMLmind XSL-FO Converter.

1.1.9. Interfészek

Már számos interfésszel találkoztunk eddig is a gyakorlatban, az iménti Runnable interfészt megelőzően az

eseménykezelési részben például, ahol az Eseménykezelés című pontban megismerkedtünk a CommandListener

interfész használatával. Az API dokumentációt fellapozva láthatjuk, hogy ez az interfész egyetlen metódus

specifikációját tartalmazza:

void commandAction(javax.microedition.lcdui.Command c,

javax.microedition.lcdui.Displayable d);

A CommandListener interfészt implementáló osztály feladata, hogy ezt a függvényt implementációval lássa el,

erre láthattunk példát a A LabirintusMIDlet osztály című pontba foglalt LabirintusMIDlet osztály kódjában.

Az interfészek az osztályokhoz hasonlóak, lehetnek tulajonságaik, de a függvényeiket maguk csak deklarálják,

testtel nem látják el őket. Nézzük meg például a JDK könyvtárában található src.zip állományban - ahol ugye

megtaláljuk a Java SE OO világ összes osztályának forráskódját - az src.zip/java/lang/Runnable.java

forrásban a Runnable interfészt! A Runnable interfészt számos saját példánkban kiterjesztjük, ilyenek például

az önálló időfejlődéssel ellátott labirintus példáink vagy a grafikus felületet és egyben számítást vagy

szimulációt tartalmazó példáink is, mint a Mandelbrot halmaz vagy a Galton deszka kísérlet vagy éppen a

Sejtautomata szimuláció programja.

Az interfészek tipikus felhasználási területe az előző pontban említett többszörös öröklődés hiányának

orvoslása. A kezdő fejlesztő legtöbbször az eseménykezelés és a párhuzamosság implementálása során

találkozik velük, de idővel saját programjait is megtanulja általánosabbá tenni az interfészek használatával, mert

ahová például egy formális paraméterként interfészt írunk, oda aktuálisan bármilyen objektumot átadhatunk,

aminek példányosító osztálya ezt az interfészt implementálja.

1.1.10. Csomagok

Ha OO világunk leírása során fejlesztett osztályaink száma megszaporodik, akkor ezeket az osztályokat érdemes

csoportokba szervezni. Így tettünk mi is, amikor például a labirintus absztahálásával kapcsolatos osztályainkat a

javattanitok.labirintus csomagba szerveztük. A csomagokkal kapcsolatos alapismereteket a A Java

szófajok című fejezetben, a package ismertetésénél tárgyaltuk.

1.2. A Java nyelv használata

A programozás megtanulásához programok írásán keresztül vezet az út, a konkrét programozási nyelvhez -

esetünkben a Javahoz - kapcsolódó gyakorlati tapasztalatok ebben a tanulási folyamatban nélkülözhetetlenek.

Ezeknek a tapasztalatoknak a megszerzését akartuk segíteni a könyvhöz készített esettanulmányokkal és a

szereplő további, mindenféle - általunk érdekesnek ítélt - példákkal. Ezeken túl még azt tudjuk javasolni az

érdeklődő Olvasónak, hogy folyamatosan tanulmányozza a fejlesztői portálok cikkeit, például Java tekintetében

a [SUN JAVA CIKKEK] portál cikkeit, vagy például mobil programozás tekintetében a [FORUM NOKIA

CIKKEK] portál fejlesztői cikkeit.

1.2.1. Bepillantás a GUI programozásba

Grafikus felület építésére a Java SE keretein belül az AWT, java.awt.* és a Swing javax.swing.* csomagok

szolgálnak. Az előbbi a kezdetek óta része a Javanak, az utóbbi a Java 1.3-tól része a JDK-nak, azaz a Java 2

platform 1.3 verziójától.

A Java ME, MIDP keretein belül sem az AWT, sem a Swing csomag nem elérhető, a mobilokon a grafikus

felület felépítésére a javax.microedition.lcdui.* csomag használandó. Ennek a csomagnak a bevezetését a

Java a mobiltelefonokban: MIDlet objektumok - Labirintus MIDlet című pont alatt tárgyaljuk.

Az AWT programozása egyszerűbb, de az AWT-vel felépített felület kinézete platformfüggő. A Swing

programozása - a párhuzamosság, azaz a szálkezelés - miatt némileg bonyolultabb. A kézikönyvben számos

AWT-s felületű példát találunk, ilyenek például a Galton deszka kísérlet, a Sejtautomata szimuláció programja

Page 161:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

133 Created by XMLmind XSL-FO Converter.

vagy például a Mandelbrot halmaz programja című pontokban fejlesztett osztályok. Ebben a pontban Swinges

példákat fogunk fejleszteni.

A Java felületépítés erőssége, hogy nem kell pixel pontossággal megterveznünk a grafikus felület kinézetét -

például egy nyomógomb komponens méretét, helyzetét -, hanem mindenféle elhelyezési stratégiát követhetünk,

amik helyettünk meghatározzák a komponensek pontos elhelyezést. Kellemes ez, ha arra gondolunk, hogy

programunk ablakának természetes tulajdonsága az átméretezhetősége. Mi mégis egy olyan példával indítunk

most, ahol nem használunk elhelyezési stratégiát, hanem magunk írjuk elő a használt komponensek méretét és

helyzetét. Ezt azért is tehetjük meg bátran, mert az integrált fejlesztői környezetek, mint például az általunk

használni javasolt NetBeans is, hatékony támogatást adnak a felület egérrel történő összehúzogatására,

miközben eleve azt a felületet látjuk, amit építünk éppen. Ezért térünk most vissza az ősi módszerhez:

négyzethálós, matekfüzet lapján tervezzük meg a felületet. Egy ilyen skiccet mutatunk a következő ábrán, a

korábban, a Kizáró vagyos titkosítás című pontban tárgyalt exor titkosítást megvalósító programunkat látjuk

most el grafikus felülettel.

public class ExorTitkositoGUI extends javax.swing.JFrame {

public ExorTitkositoGUI() {

// Az ablak adatai, fejléce:

super("Javat tanitok példa");

// az ablakot ne lehessen átméretezni, mert

setResizable(false);

// nem használunk elhelyezési stratégiát (hanem majd mi mondjuk meg,

// melyik komponens melyik pozíción és mekkora legyen).

getContentPane().setLayout(null);

// az ablak mérete

setBounds(100, 50, 210, 250);

// az ablak szokásos bezár gombjára kilép a program:

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

// a titkosító kulcs szövegmezője

final javax.swing.JTextField kulcsTextField

= new javax.swing.JTextField();

kulcsTextField.setText("kulcs");

kulcsTextField.setBounds(5, 5, 130, 20);

kulcsTextField.setToolTipText("Titkosító kulcs");

getContentPane().add(kulcsTextField);

Page 162:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

134 Created by XMLmind XSL-FO Converter.

// a tiszta szöveg doboza

final javax.swing.JTextArea tisztaTextArea

= new javax.swing.JTextArea();

javax.swing.JScrollPane tisztaScrollPane

= new javax.swing.JScrollPane();

tisztaScrollPane.setViewportView(tisztaTextArea);

tisztaScrollPane.setBounds(5, 30, 190, 80);

tisztaScrollPane.setToolTipText("A kódolandó/dekódolandó szöveget írd ide!");

getContentPane().add(tisztaScrollPane);

// a titkos szöveg doboza

final javax.swing.JTextArea titkosTextArea

= new javax.swing.JTextArea();

javax.swing.JScrollPane titkosScrollPane

= new javax.swing.JScrollPane();

titkosScrollPane.setViewportView(titkosTextArea);

titkosScrollPane.setBounds(5, 125, 190, 80);

titkosScrollPane.setToolTipText("Itt kapod az eredményt.");

getContentPane().add(titkosScrollPane);

// a kódoló/dekódoló gomb

javax.swing.JButton kódolButton

= new javax.swing.JButton();

kódolButton.setText("K/D");

kódolButton.setBounds(140, 5, 55, 20);

kódolButton.setToolTipText("Kódolás/Dekódolás");

kódolButton.addActionListener(

new java.awt.event.ActionListener() {

public void actionPerformed(java.awt.event.ActionEvent

e) {

byte [] kulcs = kulcsTextField.getText().getBytes();

byte [] buffer = tisztaTextArea.getText().getBytes();

int kulcsIndex = 0;

for(int i=0; i<buffer.length; ++i) {

buffer[i] = (byte)(buffer[i] ^ kulcs[kulcsIndex]);

kulcsIndex = (kulcsIndex+1) % kulcs.length;

}

System.out.println(new String(buffer));

titkosTextArea.setText(new String(buffer));

}

});

getContentPane().add(kódolButton);

// Lássuk!

setVisible(true);

}

public static void main(String [] args) {

new ExorTitkositoGUI();

}

}

Az exor titkosítós, immár grafikus köntösbe öltöztetett példánk kódol.

Page 163:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

135 Created by XMLmind XSL-FO Converter.

A kódolt szöveget visszamásoltuk a tiszta szöveg dobozába, majd újra kódolva dekódoltuk.

A Swinges programozási tapasztalatainkat a Genomi, aminosav vagy akár tetszőleges szekvenciák

összehasonlítása című pont tanulmányozásával növelhetjük, ahol egy menüsorral is felszerelt felületű programot

írunk. Továbbá rámutatunk a Swing programozásban leginkább szem előtt tartandó programozási gyakorlatra,

miszerint ne csináltassunk időigényes dolgokat az eseménykezelőkben, mert ez a felület lefagyását okozhatja.

Mivel az eseménykezelést és a megjelenítést ugyanaz a programszál végzi, így ha az eseménykezelőt egy

hosszadalmas számítással blokkoljuk, akkor ezzel egyben a felület megjelenítését is blokkoljuk! (Amit tipikusan

a program lefagyásaként szoktunk értékelni.)

1.2.2. Bepillantás a hálózati programozásba

Javaban hálózati programozás tekintetében a TCP/IP jelölte absztrakciós szinten és a felett URL osztályokkal,

Java szervletekkel, a Java távoli metódushívásával vagy CORBA szinten dolgozhatunk.

A TCP/IP-nek megfelelő osztályok absztrakciós szintje alá Javaban nem hatolhatunk, csak érdekességként

jegyezzük meg, hogy ennek megfelelően például Javaban nem tudunk ICMP ping jellegű programot írni. A ping

programot szoktuk használni, ha arra vagyunk kíváncsiak, hogy egy távoli gép elérhető-e egyáltalán. Elérhető

például a niobe?

C:\Documents and Settings\norbi> ping niobe

niobe [192.168.1.1] pingelése 32 bájt méretű adatokkal:

Válasz 192.168.1.1: bájt=32 idő<10 ezredmp. TTL=64

Válasz 192.168.1.1: bájt=32 idő<10 ezredmp. TTL=64

Page 164:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

136 Created by XMLmind XSL-FO Converter.

Válasz 192.168.1.1: bájt=32 idő<10 ezredmp. TTL=64

Válasz 192.168.1.1: bájt=32 idő<10 ezredmp. TTL=64

192.168.1.1 ping-statisztikája:

Csomagok: küldött = 4, fogadott = 4, elveszett = 0 (0% veszteség),

Oda-vissza út ideje közelítőlegesen, milliszekundumban:

minimum = 0ms, maximum = 0ms, átlag = 0ms

A ping jellegű programok és általában a nyers socketek használata tekintetében a [PROGRAMOZÓ

PÁTERNOSZTER JEGYZET] jegyzetet ajánljuk az érdeklődő Olvasó figyelmébe, ahol e mélység felett, a

socket interfész absztrakciós szintjén nemcsak TCP-s, hanem UDP-s Java példákat is találhatunk.

Ugyancsak érdekességként jegyezzük meg, hogy az 1.4 Java változatban megjelenő java.nio csomag

felhasználásával már Javaban is írhatunk nem blokkolódó, multiplexelt szervereket! E téma kapcsán ugyancsak

a [PROGRAMOZÓ PÁTERNOSZTER JEGYZET] jegyzetet ajánljuk az érdeklődő Olvasók figyelmébe.

1.2.2.1. A kézikönyv hálózati programjai

Az első Java tapasztalatok című pontban egy egyszerű, a socket interfész absztrakciós szintjén üzemelő TCP-s

kliens-szerver modellt mutattunk be. A Java és a C Sharp összehasonlítása című pontban ugyanez a példánk

már többszálú változatban jelenik meg. Ugyanezen az absztrakciós szinten működik egy labirintusos

esettanulmányunk, illetve egyre magasabb szintekre épülnek az alábbi labirintusos példák.

• Szerveroldali Java

a. java.net csomag

b. Java Servlet

c. Java RMI

d. Java IDL

• CORBA - elosztott programozás heterogén OO környezetben

1.2.3. Esettanulmány: egy chat program

A következő rész labirintusos esettanulmányainak technikai bevezetéseként készítsünk ebben a pontban egy

csevegő (chat) programot. Pontosabban egy TCP/IP és egy CORBA szinten üzemelő változatot. Vegyük majd

észre, hogy a CORBA implementáció mennyivel kevesebb és egyszerűbb programozási munkát igényel a

fejlesztőtől!

Figyelmeztetés a Javaban kezdő Olvasóknak

A következő Java nyelvű példák bevezetők a labirintusos esettanulmányokhoz.

Ezen példák forrásait csupán fussa át a kezdő Olvasó, hogy szeme szokja a Java nyelvet, vagy éppen a

CORBA architektúrát. Ha eközben a források megértésében bármi zavar támadna - és a teljesen

kezdőknél nyilvánvalóan támadni fog - akkor most bátran hagyja ki őket, s ha majd feldolgozta a Saját

világok teremtése és Java alapok című fejezetet, az után, tehát a labirintusos esettanulmányok előtt

térjen vissza ide és írja meg (próbálja ki) ezeket a programokat.

1.2.3.1. TCP/IP alapú csevegő

A Java és a C Sharp összehasonlítása című pontban feldolgozott Szerver osztályt fejlesztjük itt tovább. Arra

kell figyelnünk, hogy az említett példa párhuzamos szálait együttesen el kell tudni érnünk, mert a csevegő

lényege, hogy az egyik klienstől érkező üzenetet továbbítjuk az összes éppen csatlakoztatott klienshez. Tehát a

kommunikáció immár nem lehet a Kiszolgáló szál objektum és a kliens csak kettejüket érintő magánügye.

A csatlakozott csevegőket a csevegők List osztálybeli lista objektumban tartjuk nyilván. A szerver

működésének szervezésében részben követjük a [JAVA PÉLDA WEBSZERVER] cikkben is olvasható ötletet,

Page 165:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

137 Created by XMLmind XSL-FO Converter.

miszerint a szerver indulásakor előre több kiszolgáló szálat készítünk, amiket azonnal el is altatunk. Ha egy

kliens jelentkezik, akkor a vele való kommunikációhoz felébresztünk egy ilyen előre elkészített és elaltatott

szálat. A hivatkozott cikkel szemben viszont, ha esetünkben elfogynak a hadra fogható szálak, akkor nem igény

szerint készítünk újakat, hanem egy rövid üzenetben közöljük a klienssel, hogy a csevegő szoba tele van, azaz

nem tesszük számára lehetővé a jelen pillanatbeli csevegésbe való bekapcsolódást.

Egészen pontosan két listát is üzemben tartunk. A csevegők listában az éppen dolgozó hálózati szálakat, azaz

az éppen csevegést bonyolító szálakat tartjuk. Míg a nemCsevegők listában az éppen nem dolgozó, azaz alvó

szálakat tartjuk.

/** Itt tartjuk az éppen csevegést lebonyolító szálakat. */

private java.util.List<Kiszolgáló> csevegők;

/** Itt tartjuk az éppen csevegést nem bonyolító szálakat. */

private java.util.List<Kiszolgáló> nemCsevegők;

Kezdetben minden elkészített és alvó szál ebben a listában kap helyet.

nemCsevegők = new java.util.ArrayList<Kiszolgáló>();

csevegők = new java.util.ArrayList<Kiszolgáló>();

// Csevegő szálak elkészítése

for(int i=0; i<MAX_CSEVEGŐ; ++i)

nemCsevegők.add(new Kiszolgáló(this));

A listák kezelését pedig az alábbi három, objektum szinten szinkronizált metódusra korlátozzuk:

/**

* Egy szálat átteszünk a nem csevegők közül a csevegőkbe.

* Az alábbi három, az adott szerverhez tartozó nem csevegőket

* a csevegőket kezelő módszer közül mindig csak egy futhat, ezt

* az objektum szintű szinkronizált módszerek használatával

* biztosítottuk.

*/

public synchronized Kiszolgáló beszáll() {

if(!nemCsevegők.isEmpty()) {

Kiszolgáló kiszolgáló = nemCsevegők.remove(0);

csevegők.add(kiszolgáló);

return kiszolgáló;

}

return null;

}

/**

* Egy szál aktuális működése végének leadminisztrálása.

*

* @param csevegő szál, aki éppen befejezte működését.

*/

public synchronized void kiszáll(Kiszolgáló csevegő) {

csevegők.remove(csevegő);

nemCsevegők.add(csevegő);

}

/**

* Üzenet küldése a csevegő klienseknek.

*

* @param üzenet amit minden kliensnek el kell küldeni.

*/

public synchronized void mindenkihez(String üzenet) {

for(Kiszolgáló csevegő: csevegők)

csevegő.üzenet(üzenet);

Page 166:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

138 Created by XMLmind XSL-FO Converter.

}

Ezzel biztosítjuk, hogy adott CsevegőSzerver objektum e három metódusa közül egyszerre csak egy fusson, s

így ne zavarodjon össze a csevegő és a nem csevegő szálak adminisztrálása!

1.2.3.1.1. A CsevegőSzerver és a Kiszolgáló osztály

/*

* CsevegőSzerver.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* Egy csevegőt kiszolgáló szál.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

class Kiszolgáló implements Runnable {

/** A csevegő szerver, aki ezt a kiszolgáló szálat készítette és

* használja. */

CsevegőSzerver szerver;

/** A kiszolgálást ezen a TCP/IP kapcsolatot absztraháló

* objektumon kersztül végezzük éppen. */

java.net.Socket socket;

/** A kapcsolat feletti kimenő csatorna (látnia kell a többi

* kiszolgálást végző szálnak is) */

java.io.PrintWriter kimenőCsatorna;

/** Dolgozik éppen vagy sem az objektum? */

boolean kiszolgál = false;

/**

* A {@code Kiszolgáló} objektumot felépítő konstruktor.

*

* @param szerver a csevegő szálakat összefogó szerver.

*/

public Kiszolgáló(CsevegőSzerver szerver) {

this.szerver = szerver;

// Készítjük a szálat és indítjuk, az ennek

// megfelelő run() módszerben pedig azonnal

// altatjuk majd az indított szálat.

new Thread(this).start();

}

/**

* A szál kiszolgálását indító függvény.

*

* @param socket kapcsolat a TCP/IP-s klienssel.

*/

public synchronized void kiszolgál(java.net.Socket socket) {

this.socket = socket;

kiszolgál = true;

// A run()-ban alvó szálat ébresztjük, az ott a

// wait()-nál várakozó végrehajtási szál elindul.

notify();

}

/**

* Üzenet a kliensnek.

*

* @param üzenet amit el köldünk a kliensnek.

*/

public void üzenet(String üzenet) {

kimenőCsatorna.println(üzenet);

kimenőCsatorna.flush();

}

Page 167:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

139 Created by XMLmind XSL-FO Converter.

/**

* A kliensek kiszolgálását végző szál.

*/

public synchronized void run() {

for(;;) {

// Tétlenül várakozik addig, amig nincs kliens

while(!kiszolgál)

try{

// a várakozásból a notify() hívás ébreszti majd fel.

wait();

} catch(InterruptedException e) {}

// Kimenő és bejövő csatorna objektumokat elkészítjük.

try {

java.io.BufferedReader bejövőCsatorna =

new java.io.BufferedReader(

new java.io.InputStreamReader(socket.getInputStream()));

kimenőCsatorna =

new java.io.PrintWriter(socket.getOutputStream());

// Addig olvasunk, amig ki nem lép a kliens

// a vege parancs begépelésével.

String sor = bejövőCsatorna.readLine();

do {

if("vege".equals(sor))

break;

// Visszahívjuk a szervert, hogy a klienstől

// beolvasott üzenetet eljutassa minden csevegőhöz:

szerver.mindenkihez(sor);

} while((sor = bejövőCsatorna.readLine()) != null);

} catch(java.io.IOException ioE) {

ioE.printStackTrace();

} finally {

try{

socket.close();

szerver.kiszáll(this);

kiszolgál = false;

} catch(java.io.IOException ioE) {}

}

}

}

}

/**

* A csevegő szerver.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

public class CsevegőSzerver {

/** Maximum hány csevegő fér be. */

public static final int MAX_CSEVEGŐ = 20;

/** Itt tartjuk az éppen csevegést lebonyolító szálakat. */

private java.util.List<Kiszolgáló> csevegők;

/** Itt tartjuk az éppen csevegést nem bonyolító szálakat. */

private java.util.List<Kiszolgáló> nemCsevegők;

/** A <code>CsevegőSzerver</code> objektumot felépítő konstruktor. */

public CsevegőSzerver() {

nemCsevegők = new java.util.ArrayList<Kiszolgáló>();

csevegők = new java.util.ArrayList<Kiszolgáló>();

// Csevegő szálak elkészítése

for(int i=0; i<MAX_CSEVEGŐ; ++i)

nemCsevegők.add(new Kiszolgáló(this));

// Szerver indítása

try {

java.net.ServerSocket serverSocket =

new java.net.ServerSocket(2006);

while(true) {

Page 168:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

140 Created by XMLmind XSL-FO Converter.

java.net.Socket socket = serverSocket.accept();

Kiszolgáló szál = beszáll();

if(szál == null) {

// Ha betelt a csevegő szoba, akkor egy

// rövid tájékoztató üzenet a kliensnek:

java.io.PrintWriter kimenőCsatorna =

new java.io.PrintWriter(socket.getOutputStream());

kimenőCsatorna.println("A csevegő szoba tele van!");

socket.close();

} else // Ha van szabad csevegő szál, akkor

// azzal elkezdődik a csevegő kliens kiszolgálása.

szál.kiszolgál(socket);

}

} catch(java.io.IOException ioE) {

ioE.printStackTrace();

}

}

/**

* Egy szálat átteszünk a nem csevegők közül a csevegőkbe.

* Az alábbi három, az adott szerverhez tartozó nem csevegőket

* a csevegőket kezelő módszer közül mindig csak egy futhat, ezt

* az objektum szintű szinkronizált módszerek használatával

* biztosítottuk.

*/

public synchronized Kiszolgáló beszáll() {

if(!nemCsevegők.isEmpty()) {

Kiszolgáló kiszolgáló = nemCsevegők.remove(0);

csevegők.add(kiszolgáló);

return kiszolgáló;

}

return null;

}

/**

* Egy szál aktuális működése végének leadminisztrálása.

*

* @param csevegő szál, aki éppen befejezte működését.

*/

public synchronized void kiszáll(Kiszolgáló csevegő) {

csevegők.remove(csevegő);

nemCsevegők.add(csevegő);

}

/**

* Üzenet küldése a csevegő klienseknek.

*

* @param üzenet amit minden kliensnek el kell küldeni.

*/

public synchronized void mindenkihez(String üzenet) {

for(Kiszolgáló csevegő: csevegők)

csevegő.üzenet(üzenet);

}

/** A csevegő szerver elindítása. */

public static void main(String [] args) {

new CsevegőSzerver();

}

}

1.2.3.1.2. A csevegő kipróbálása

Az imént ismertetett Kiszolgáló és CsevegőSzerver osztályok forráskódját a CsevegőSzerver.java

állományba helyezése után fordítunk, majd futtatunk:

C:\Documents and Settings\norbi> javac CsevegőSzerver.java

C:\Documents and Settings\norbi> java CsevegőSzerver

Page 169:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

141 Created by XMLmind XSL-FO Converter.

Egy másik ablakból a telnet localhost 2006 parancs kiadásával csatlakozunk a szerverhez:

C:\Documents and Settings\norbi> telnet localhost 2006

egyik vagyok

egyik vagyok

Udv egyik, en a masik vagyok

Szia masik

Szia masik

Amiközben egy további másik ablakból is, ugyancsak a telnet localhost 2006 parancs kiadásával csatlakozunk a

szerverhez:

C:\Documents and Settings\norbi> telnet localhost 2006

egyik vagyok

Udv egyik, en a masik vagyok

Udv egyik, en a masik vagyok

Szia masik

1.2.3.2. CORBA alapú csevegő

A CORBA alapú megoldásunkat a CORBA objektumok megtervezésével kezdjük. Itt természetesen az előző

pont tapasztalataiból indulunk ki: a szerverbe a kliensek be/ki tudjanak lépni és tudjanak üzenni. A szerver pedig

tudjon üzenni az összes bent lévő kliensnek. Egyszerű elképzelésünket az alábbi IDL interfészekkel írjuk le.

A Kliens interfésszel a kliens oldali, a Szerver interfésszel a szerver oldali CORBA objektumot írjuk le. A

Kliens objektumoknak csak üzenni lehet, a Szerver objektumba be és kilépni is.

1.2.3.2.1. A szerver és a kliens oldali IDL interfészek

module korba

{

interface Kliens

{

void uzenet(in string uzenet);

};

interface Szerver

{

void beszall(in Kliens kliens);

void kiszall(in Kliens kliens);

void uzenet(in string uzenet);

};

};

Az in szócska annyit jelent az IDL nyelven, hogy az utána szereplő paraméter a CORBA objektumba befelé

megy. A beszall(in Kliens kliens); metódus deklaráció például azt jelenti, hogy a Szerver CORBA

objektumnak átadjuk a kliens oldali Kliens CORBA objektum referenciáját.

A sikeres tervezőmunka után kiválaszthatjuk azt a programozási nyelvet, melyen az IDL interfészekben

megálmodott CORBA OO világunkat életre szeretnénk kelteni. A szóba jöhető nyelveket a [NYELVI

LEKÉPEZÉS] című lapon tanulmányozhatjuk. Esetünkben ez természetesen a Java. A JDK csomag részeként

kapott idlj fordító használatával tudjuk elvégezni a nyelvi leképezést, aminek során az idlj legenerálja a

Page 170:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

142 Created by XMLmind XSL-FO Converter.

megfelelő CORBA specifikus Java forrásállományokat. Az IDL-Java leképezés például azt mondja, hogy az

IDL modul Java csomag lesz. Ennek megfelelően az idlj -fall csevego.idl parancs kiadása után korba

könyvtárban keletkeznek a POA objektumadaptereknek megfelelő SzerverPOA és KliensPOA osztályok. (A -

fall kapcsoló azt mondja a fordítónak, hogy a CORBA alapú kommunikációhoz szükséges, a kliens és a

szerveroldali Java forrásállományokat is generálja le.) Tipikus megoldás, hogy a CORBA objektumok

implementációit úgy készítjük el, hogy kiterjesztjük a megfelelő POA osztályokat. A következő két pontban is

ezt a módszert követjük.

1.2.3.2.2. A SzerverKiszolgáló osztály

A CORBA objektum elkészítésénél nincs más dolga a fejlesztőnek, mint a korba.SzerverPOA osztály

kiterjesztésében implementációt írni a Szerver interfészben deklarált három metódushoz:

void beszall(in Kliens kliens);

void kiszall(in Kliens kliens);

void uzenet(in string uzenet);

Vizsgáljuk meg például az elsőnek megfelelő Java metódus szignatúráját:

void beszall(korba.Kliens kliens);

A leképezést leginkább a szintén az idlj fordító generálta SzerverOperations Java interfészben érdemes

megfigyelni. Következzék most a CORBA kiszolgáló objektum teljes kódja:

/*

* SzerverKiszolgáló.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* A <code>csevego.idl</code> leírta Szerver CORBA

* kiszolgáló objektum megvalósítása.

*

* A <code>csevego.idl</code> interfész:

* <pre>

* module korba

* {

* interface Kliens

* {

* void uzenet(in string uzenet);

* };

*

* interface Szerver

* {

* void beszall(in Kliens kliens);

* void kiszall(in Kliens kliens);

* void uzenet(in string uzenet);

* };

* };

* </pre>

* A <code>korba.*</code> csomag legenerálása:

* <pre>

* idlj -fall csevego.idl

* </pre>

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

Page 171:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

143 Created by XMLmind XSL-FO Converter.

* @see KorbaCsevegő

* @see korba.Szerver

* @see csevego.idl

*/

public class SzerverKiszolgáló

extends korba.SzerverPOA {

/** Itt tartjuk az éppen csevegő klienseket. */

private java.util.List<korba.Kliens> csevegők;

/** A <code>SzerverKiszolgáló</code> objektum elkászítése. */

public SzerverKiszolgáló() {

csevegők = new java.util.ArrayList<korba.Kliens>();

}

/**

* Egy CORBA kliens belép a csevegésbe.

*

* @param kliens a kliens CORBA objektum.

*/

public void beszall(korba.Kliens kliens) {

csevegők.add(kliens);

}

/**

* Egy CORBA kliens kilép a csevegésből.

*

* @param kliens a kliens CORBA objektum.

*/

public void kiszall(korba.Kliens kliens) {

csevegők.remove(kliens);

}

/**

* Egy CORBA kliens üzen a csevegőknek.

*

* @param üzenet az üzenet.

*/

public void uzenet(String üzenet) {

for(korba.Kliens csevegő: csevegők)

csevegő.uzenet(üzenet);

}

}

1.2.3.2.3. A KliensKiszolgáló osztály

Az osztály implementálásánál az előző ponthoz hasonlóan járunk el. Figyeljük meg: a királyi úton járást jelzi, ha

a kódban jóval több a megjegyzés, mint maga a tényleges kód!

/*

* KliensKiszolgáló.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* A <code>csevego.idl</code> leírta Kliens CORBA

* kiszolgáló objektum megvalósítása.

*

* A <code>csevego.idl</code> interfész:

* <pre>

* module korba

* {

* interface Kliens

* {

* void uzenet(in string uzenet);

Page 172:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

144 Created by XMLmind XSL-FO Converter.

* };

*

* interface Szerver

* {

* void beszall(in Kliens kliens);

* void kiszall(in Kliens kliens);

* void uzenet(in string uzenet);

* };

* };

* </pre>

* A <code>korba.*</code> csomag legenerálása:

* <pre>

* idlj -fall csevego.idl

* </pre>

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see KorbaCsevegőKliens

* @see korba.Kliens

* @see csevego.idl

*/

public class KliensKiszolgáló

extends korba.KliensPOA {

/**

* Üzenetet kap a kliens, visszahívták.

*

* @param üzenet az üzenet.

*/

public void uzenet(String üzenet) {

System.out.println(üzenet);

}

}

1.2.3.2.4. A KorbaCsevegő osztály

A KorbaCsevegő a csevegőnk szerver oldala. Végrehajtja a szerver szokásos, a A KorbásLabirintus osztály

című pontban külön is részletezett teendőit: felveszi a kapcsolatot az ORB szoftverrel, elkészíti a kiszolgáló

CORBA objektumot, aminek tulajdonságait beállítja az objektumot éltető - POA - adapter segítségével, majd az

elkészített objektumot bejegyzi a CORBA objektumok telefonkönyvébe: a névszolgáltatóba.

/*

* KorbaCsevegő.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* Létrehozza és bejegyzi a névszolgáltatóba

* a CORBA Szervert kiszolgáló objektumot.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see KorbaCsevegőKliens

* @see korba.Szerver

* @see SzerverKiszolgáló

* @see csevego.idl

*/

public class KorbaCsevegő {

/** A <code>KorbaCsevegő</code> szerver indítása. */

public KorbaCsevegő() {

// A CORBA szerver indítása

try{

// Az ORB tulajdonságainak megadása

java.util.Properties orbTulajdonságok = new java.util.Properties();

orbTulajdonságok.put("org.omg.CORBA.ORBInitialHost", "localhost");

orbTulajdonságok.put("org.omg.CORBA.ORBInitialPort", "2006");

Page 173:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

145 Created by XMLmind XSL-FO Converter.

// Az ORB (a metódushívások közvetítőjének) inicializálása

org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init((String [])null,

orbTulajdonságok);

// A gyökér POA CORBA objektum referenciájának megszerzése

org.omg.CORBA.Object corbaObjektum =

orb.resolve_initial_references("RootPOA");

// CORBA-s típuskényszerítéssel a megfelelőre

org.omg.PortableServer.POA gyökérPoa =

org.omg.PortableServer.POAHelper.narrow(corbaObjektum);

// A POA kiszolgáló állapotba kapcsolása:

gyökérPoa.the_POAManager().activate();

// A kiszolgáló objektum létrehozása

SzerverKiszolgáló szerverKiszolgáló =

new SzerverKiszolgáló();

// CORBA objektum referencia elkészítése

corbaObjektum =

gyökérPoa.servant_to_reference(szerverKiszolgáló);

// CORBA-s típuskényszerítéssel a megfelelőre

korba.Szerver szerver =

korba.SzerverHelper.narrow(corbaObjektum);

// A névszolgáltató gyökerének, mint CORBA objektum

// referenciájának megszerzése

corbaObjektum =

orb.resolve_initial_references("NameService");

org.omg.CosNaming.NamingContextExt névszolgáltatóGyökere

= org.omg.CosNaming.NamingContextExtHelper

.narrow(corbaObjektum);

// A kiszolgáló objektum bejegyzése a névszolgáltatóba

org.omg.CosNaming.NameComponent név[] =

névszolgáltatóGyökere.to_name("Csevego");

névszolgáltatóGyökere.rebind(név, szerver);

// Várakozás a csevegők jelentkezésére

orb.run();

} catch (Exception e) {

e.printStackTrace();

System.exit(-1);

}

}

/** Elindítja a CORBA csevegő szervert. */

public static void main(String[] args) {

new KorbaCsevegő();

}

}

1.2.3.2.5. A KorbaCsevegőKliens osztály

A KorbaCsevegőKliens a csevegőnk kliens oldala. A kliensek szokásos: „a névszolgáltatáson keresztül

megszerzem a kívánt szolgáltatást nyújtó CORBA objektum referenciáját” tevékenységén túl a kód érdekessége,

hogy maga is elkészít és éltet egy CORBA objektumot, a visszahívható kliensoldali CORBA objektumot.

/*

* KorbaCsevegőKliens.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* Csatlakozika a CORBA szerverhez és elkészíti a klienst

* reprezentáló CORBA Kliens kiszolgáló objektumot.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see KorbaCsevegő

* @see korba.Kliens

Page 174:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

146 Created by XMLmind XSL-FO Converter.

* @see KliensKiszolgáló

* @see csevego.idl

*/

public class KorbaCsevegőKliens {

/**

* Csatlakozik a névszolgáltatáson keresztül a

* szerverhez és elkészíti a visszahívható kliens objektumot.

*

* @param args[0] a csevegő beceneve.

*/

public static void main(String[] args) {

String becenév = null;

// ha nem adtuk meg a parancssor-argumentumot,

// akkor ez az alapértelmezés:

if(args.length != 1)

becenév = "Matyi";

else

becenév = args[0];

try {

// Az ORB tulajdonságainak megadása

java.util.Properties orbTulajdonságok = new java.util.Properties();

orbTulajdonságok.put("org.omg.CORBA.ORBInitialHost", "localhost");

orbTulajdonságok.put("org.omg.CORBA.ORBInitialPort", "2006");

// Az ORB (a metódushívások közvetítőjének) inicializálása

org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init((String [])null,

orbTulajdonságok);

// A névszolgáltató gyökerének, mint CORBA objektum

// referenciájának megszerzése

org.omg.CORBA.Object corbaObjektum =

orb.resolve_initial_references("NameService");

org.omg.CosNaming.NamingContextExt névszolgáltatóGyökere

= org.omg.CosNaming.

NamingContextExtHelper.narrow(corbaObjektum);

// A Szerver szolgáltatást nyújtó CORBA objektum

// referenciájának megszerzése

korba.Szerver szerver =

korba.SzerverHelper.narrow(

névszolgáltatóGyökere.resolve_str("Csevego"));

// A kliens CORBA objektum létrehozása:

// A gyökér POA CORBA objektum referenciájának megszerzése

corbaObjektum =

orb.resolve_initial_references("RootPOA");

// CORBA-s típuskényszerítéssel a megfelelőre

org.omg.PortableServer.POA gyökérPoa =

org.omg.PortableServer.POAHelper.narrow(corbaObjektum);

// A POA kiszolgáló állapotba kapcsolása:

gyökérPoa.the_POAManager().activate();

// A kiszolgáló objektum létrehozása

KliensKiszolgáló kliensKiszolgáló =

new KliensKiszolgáló();

// CORBA objektum referencia elkészítése

corbaObjektum =

gyökérPoa.servant_to_reference(kliensKiszolgáló);

// CORBA-s típuskényszerítéssel a megfelelőre

korba.Kliens kliens =

korba.KliensHelper.narrow(corbaObjektum);

// A kliens átadja magát a szervernek

szerver.beszall(kliens);

// Olvasunk majd ezen a csatornán a csevegő billentyűzetéről

java.io.BufferedReader inputCsatorna =

new java.io.BufferedReader(

new java.io.InputStreamReader(System.in));

// amig a vege parancsot nem gépeli

String sor = inputCsatorna.readLine();

do {

if("vege".equals(sor))

break;

szerver.uzenet(becenév+"> "+sor);

Page 175:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

147 Created by XMLmind XSL-FO Converter.

} while((sor = inputCsatorna.readLine()) != null );

// Kijelentkeztetjük magunkat

szerver.kiszall(kliens);

} catch (Exception e) {

e.printStackTrace();

}

}

}

1.2.3.2.6. A csevegő kipróbálása

Elvégezzük az IDL-Java leképezést, majd lefordítjuk a forrásokat:

C:\... > idlj -fall csevego.idl

C:\... > javac KorbaCsevegő.java KorbaCsevegőKliens.java korba\*.java

Note: Some input files use unchecked or unsafe operations.

Note: Recompile with -Xlint:unchecked for details.

Indítjuk az ORB szoftvert:

C:\Documents and Settings\neuro>start orbd -ORBInitialPort 2006

Futtatjuk a csevegő szerverünket:

C:\... > java KorbaCsevegő

Egy másik ablakban egy klienst:

C:\... > java KorbaCsevegőKliens

Van bent valaki?

Matyi> Van bent valaki?

Erika> Igen, en itt vagyok!

miközben egy másik, további klienst is indítottunk:

C:\... > java KorbaCsevegőKliens Erika

Matyi> Van bent valaki?

Igen, en itt vagyok!

Erika> Igen, en itt vagyok!

Megjegyezhetjük, hogy a Java IDL használata mellett lehetőségünk van olyan kiszolgáló CORBA objektumok

létrehozására is, melyek túlélhetik az őket létrehozó szerverek élettartamát, ezek az úgynevezett perzisztens

objektumok. A majd ebben vagy általában a CORBA világa iránt mélyebben érdeklődő Olvasónak a Java

Page 176:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Saját világok teremtése és Java

alapok

148 Created by XMLmind XSL-FO Converter.

dokumentáció docs\technotes\guides\idl\index.html, „Java IDL Technology” című lapját ajánljuk. (A

Java dokumentáció telepítéséről A Java dokumentáció, azaz az API doksi letöltése című pontban olvashatunk.)

Page 177:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Created by XMLmind XSL-FO Converter.

II. rész - Programozás gépen

Ebben a részben nemcsak fejben és papíron, hanem főképp gépen dolgozunk! A következő labirintus példák

között találunk olyan, ami egy gépen, egy mobiltelefonon vagy akár több internetes gépen futtatható.

Page 178:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

150 Created by XMLmind XSL-FO Converter.

3. fejezet - Java esettanulmányok

„Tapasztalatunk szerint a program minőségének legjobb kritériuma az olvashatóság: ha egy program könnyen

olvasható, valószínűleg jó; ha nehezen olvasható, valószínűleg nem jó.” — Kernighan-Plauger A programozás magasiskolája

Az előző fejezetben kifejlesztett labirintus API számos használati esetét dolgozzuk fel ennek a résznek az

esettanulmányaiban. Kezdetben elkészítünk egy a „tiszta” teremtett OO világunkat bemutató karakteres példát,

majd egy böngészős, egy mobiltelefonos és számos más, különböző absztrakciós szinteken működő hálózati

példát.

Ebben a gyakorlati programozási részben a következő esettanulmányokat tárgyaljuk:

• tiszta OO labirintus

• böngészős és alkalmazásbeli labirintus

• játékszerű teljes képernyős labirintus

• mobiltelefonos labirintus

• szerveroldali

• TCP/IP

• Java Servlet

• Java RMI

• CORBA labirintus

• elosztott CORBA labirintus

1. Labirintus esettanulmányok Java nyelven

A fejezet esettanulmányaival való konkrét, gyakorlati tapasztalatszerzés első lépése a labirintusunk

mikrovilágának leírását tartalmazó javattanitok.labirintus csomagunk felélesztése, ennek menetét a

következő A labirintus API felélesztése című alpontban találjuk meg. Minden további esettanulmány ezt a

csomagot használja. A csomag kifejlesztését a következő pont részeként írjuk le.

1.1. A tiszta OO labirintus - Labirintus Világ

A példát az Előzetes a példaprogramokból című részben vezettük be. Majd a korábbi, a Java programozást

bevezető pontok példáiban már ennek a fejlesztési munkának a - sokszor leegyszerűsített - forráskód részleteit

mutattuk be. Itt elkészítjük labirintusunk végleges világát: magát a labirintust, kincsestől, szörnyestől, hősöstől,

a szokásos történettel: miszerint a hős bolyong, a szörnyek próbálják megenni, a kincs várja, hogy

rábukkanjanak. A megfelelő osztályokat a javattanitok.labirintus csomagba foglaljuk, azaz ebben a

csomagban fejlesztjük ki labirintusunk API interfészét.

1.1.1. A labirintus API felélesztése

Tetszőleges munkakönyvtárunkban hozzuk létre a javattanitok könyvtárat és azon belül a labirintus

könyvtárat!

C:\...\Munkakönyvtár> mkdir javattanitok

C:\...\Munkakönyvtár> mkdir javattanitok\labirintus

Page 179:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

151 Created by XMLmind XSL-FO Converter.

Ezzel a javattanitok.labirintus Java csomagot leképeztük a munkakönyvtárunkra, a kifejlesztendő

osztályokat ide, a javattanitok/labirintus könyvtárban írjuk majd meg, azaz gyűjtük most össze. Másoljuk

ide a következő Szereplő.java, Hős.java, Kincs.java, Szörny.java, Labirintus.java,

RosszLabirintusKivétel.java állományokat!

Az alábbi állományok kimásolása után a A labirintus API fordítása című pontban folytatjuk a labirintus API

lefordításával. (Az állományok A példaprogramok forrásainak letöltése című pontban ismertetett archívumban

is megtalálhatóak.)

1.1.1.1. A Szereplő osztály

A Szereplő osztály írását a Saját szereplők feladat című pontban kezdtük el fejleszteni. Íme itt a teljes kód:

/*

* Szereplő.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.labirintus;

/**

* A labirintus szereplőit (kincsek, szörnyek, hős) absztraháló osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.labirintus.Labirintus

*/

public class Szereplő {

/** A szereplő oszlop pozíciója. */

protected int oszlop;

/** A szereplő sor pozíciója. */

protected int sor;

/** A labirintus, melyben a szereplő van. */

protected Labirintus labirintus;

/** A labirintus szélessége. */

protected int maxSzélesség;

/** A labirintus magassága. */

protected int maxMagasság;

/** Véletlenszám generátor a szereplők mozgatásához. */

protected static java.util.Random véletlenGenerátor

= new java.util.Random();

/**

* Létrehoz egy <code>Szereplő</code> objektumot.

*

* @param labirintus amibe a szereplőt helyezzük.

*/

public Szereplő(Labirintus labirintus) {

this.labirintus = labirintus;

maxSzélesség = labirintus.szélesség();

maxMagasság = labirintus.magasság();

// A szereplő kezdő pozíciója a labirintusban

szereplőHelyeKezdetben();

}

/**

* A szereplő labirintusbeli kezdő pozíciójának meghatározása.

*/

void szereplőHelyeKezdetben() {

// Többször próbálkozunk elhelyezni a szereplőt a labirintusban,

// számolja, hol tartunk ezekkel a próbálkozásokkal:

int számláló = 0;

do {

// itt +2,-2-k, hogy a bal alsó saroktól távol tartsuk

// a szereplőket, mert majd ezt akarjuk a hős kezdő pozíciójának

oszlop = 2+véletlenGenerátor.nextInt(maxSzélesség-2);

sor = véletlenGenerátor.nextInt(maxMagasság-2);

// max. 10-szer próbálkozunk, de ha sikerül nem "falba tenni" a

Page 180:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

152 Created by XMLmind XSL-FO Converter.

// szereplőt, akkor máris kilépünk:

} while(++számláló<10 && labirintus.fal(oszlop, sor));

}

/**

* A szereplő felfelé lép. Ha nem tud, helyben marad.

*/

public void lépFöl() {

if(sor > 0)

if(!labirintus.fal(oszlop, sor-1))

--sor;

}

/**

* A szereplő lefelé lép. Ha nem tud, helyben marad.

*/

public void lépLe() {

if(sor < maxMagasság-1)

if(!labirintus.fal(oszlop, sor+1))

++sor;

}

/**

* A szereplő balra lép. Ha nem tud, helyben marad.

*/

public void lépBalra() {

if(oszlop > 0)

if(!labirintus.fal(oszlop-1, sor))

--oszlop;

}

/**

* A szereplő jobbra lép. Ha nem tud, helyben marad.

*/

public void lépJobbra() {

if(oszlop < maxSzélesség-1)

if(!labirintus.fal(oszlop+1, sor))

++oszlop;

}

/**

* A szereplő (Euklideszi) távolsága egy másik szereplőtől a labirintusban.

*

* @param szereplő a másik szereplő

* @return int távolság a másik szereplőtől.

*/

public int távolság(Szereplő szereplő) {

return (int)Math.sqrt((double)

(oszlop - szereplő.oszlop)*(oszlop - szereplő.oszlop)

+ (sor - szereplő.sor)*(sor - szereplő.sor)

);

}

/**

* Egy pozíció (Euklideszi) távolsága egy másik szereplőtől a

* labirintusban.

*

* @param oszlop a pozíció oszlop koordinátája

* @param sor a pozíció sor koordinátája

* @param szereplő a másik szereplő

* @return int távolság a másik szereplőtől.

*/

public int távolság(int oszlop, int sor, Szereplő szereplő) {

if(!(oszlop >= 0 && oszlop <= maxSzélesség-1

&& sor >= 0 && sor <= maxMagasság-1))

return Integer.MAX_VALUE;

else

Page 181:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

153 Created by XMLmind XSL-FO Converter.

return (int)Math.sqrt((double)

(oszlop - szereplő.oszlop)*(oszlop - szereplő.oszlop)

+ (sor - szereplő.sor)*(sor - szereplő.sor)

);

}

/**

* Beállítja a szereplő labirintusbeli pozíciójának oszlop

* koordinátáját.

*

* @param oszlop a szereplő labirintusbeli pozíciójának oszlop

* koordinátája.

*/

public void oszlop(int oszlop) {

this.oszlop = oszlop;

}

/**

* Beállítja a szereplő labirintusbeli pozíciójának sor koordinátáját.

*

* @param sor a szereplő labirintusbeli pozíciójának sor koordinátája.

*/

public void sor(int sor) {

this.sor = sor;

}

/**

* Megadja a szereplő labirintusbeli pozíciójának oszlop koordinátáját.

*

* @return int a szereplő labirintusbeli pozíciójának oszlop koordinátája.

*/

public int oszlop() {

return oszlop;

}

/**

* Megadja a szereplő labirintusbeli pozíciójának sor koordinátáját.

*

* @return int a szereplő labirintusbeli pozíciójának sor koordinátája.

*/

public int sor() {

return sor;

}

public String toString() {

return "SZEREPLŐ oszlop = "

+ oszlop

+ " sor = "

+ sor;

}

}

A Szereplő osztály tagként tartalmazza annak a labirintusnak a referenciáját, amelybe belehelyezzük. Ez furcsa

lehet annak az Olvasónak, aki gondolkodása szerint a labirintusnak van szereplője és nem a szereplőnek

labirintusa. Viszont az első esetben, tehát ha a Szereplő osztályunk ezt a tagot nem tartalmazná, akkor a

szereplő mozgását adó metódusoknak mindig át kellene adni a labirintus referenciáját is, hogy ezek a mozgató

függvények tudják, le tudják kérdezni, hogy hová léptethetik a szereplőt.

1.1.1.2. A Hős osztály

Ez a pont folytatása Az osztályok fejlődése: az öröklődés című pontban megkezdett, a labirintus hősét

boncolgató gondolatmenetnek.

Page 182:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

154 Created by XMLmind XSL-FO Converter.

/*

* Hős.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.labirintus;

/**

* A labirintus hősét leíró osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.labirintus.Labirintus

*/

public class Hős extends Szereplő {

/** A labirintusban megtalált kincsek értékei. */

protected int megtaláltÉrtékek;

/** A hős életeinek maximális száma. */

public static final int ÉLETEK_SZÁMA = 5;

/** A hős életeinek száma. */

protected int életekSzáma = ÉLETEK_SZÁMA;

/**

* Létrehoz egy <code>Hős</code> objektumot.

*

* @param labirintus amelyben a hős bolyongani fog.

*/

public Hős(Labirintus labirintus) {

super(labirintus);

megtaláltÉrtékek = 0;

}

/**

* Gyüjtögeti a megtalált kincseket.

*

* @param kincs amit éppen magtalált a hős.

*/

public void megtaláltam(Kincs kincs) {

megtaláltÉrtékek += kincs.érték();

}

/**

* Jelzi, hogy éppen megettek.

*

* @return true ha a hősnek még van élete, ellenkező esetben,

* azaz ha az összes élete elfogyott már, akkor false.

*/

public boolean megettek() {

if(életekSzáma > 0) {

--életekSzáma;

return false;

} else

return true;

}

/**

* megmondja, hogy élek-e még?

*

* @return true ha a hősnek még van élete, ellenkező esetben, azaz

* ha az összes élete elfogyott már, akkor false.

*/

public boolean él() {

return életekSzáma > 0;

}

/**

* Megadja az életek számát.

*

Page 183:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

155 Created by XMLmind XSL-FO Converter.

* @return int az életek száma.

*/

public int életek() {

return életekSzáma;

}

/**

* Megadja a megtalált kincsek összegyüjtögetett értékeit.

*

* @return int a megtalált kincsek összegyüjtögetett értékei.

*/

public int pontszám() {

return megtaláltÉrtékek;

}

/**

* A labirintus, amiben a hős mozog.

*

* @return Labirintus a labirintus.

*/

public Labirintus labirintus() {

return labirintus;

}

}

1.1.1.3. A Kincs osztály

A Kincs osztály írását a Saját szereplők feladat című pontban kezdtük el fejleszteni. Íme itt a teljes kód:

/*

* Kincs.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.labirintus;

/**

* A labirintus kincseit jellemző osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.labirintus.Labirintus

*/

public class Kincs extends Szereplő {

/** A kincs értéke. */

protected int érték;

/** Megtaláltak már? */

protected boolean megtalálva;

/**

* Létrehoz egy {@code Kincs} objektumot.

*

* @param labirintus amibe a kincset helyezzük.

* @param érték a kincs értéke.

*/

public Kincs(Labirintus labirintus, int érték) {

super(labirintus);

this.érték = érték;

}

/**

* A szereplő (pl. hős, szörnyek) megtalálta a kincset?

*

* @param hős aki keresi a kincset.

Page 184:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

156 Created by XMLmind XSL-FO Converter.

* @return true ha a kincset éppen most megtalálta a szereplő,

* ha éppen nem, vagy már eleve megvan találva a kincs, akkor false.

*/

public boolean megtalált(Szereplő szereplő) {

if(megtalálva)

// mert egy kicset csak egyszer lehet megtalálni

return false;

if(oszlop == szereplő.oszlop()

&& sor == szereplő.sor())

megtalálva = true;

return megtalálva;

}

/**

* Megadja a kincs értékét.

*

* @return int a kincs értéke.

*/

public int érték() {

return érték;

}

/**

* Megmondja, hogy megtalálták-e már a kincset?

*

* @return true ha a kincset már megtalálták,

* ha még nem akkor false.

*/

public boolean megtalálva() {

return megtalálva;

}

/**

* A {@code Kincs} objektum sztring reprezentációját adja

* meg.

*

* @return String az objektum sztring reprezentációja.

*/

public String toString() {

return "KINCS érték = "

+ érték

+ " megtalálva = "

+ megtalálva;

}

}

1.1.1.4. A Szörny osztály

A Szörny osztály írását a Saját szereplők feladat című pontban kezdtük el fejleszteni. Íme itt a teljes kód:

/*

* Szörny.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.labirintus;

/**

* A labirintus szörnyeit megadó osztály.

*

* @author Bátfai Norbert, [email protected]

Page 185:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

157 Created by XMLmind XSL-FO Converter.

* @version 0.0.1

* @see javattanitok.labirintus.Labirintus

*/

public class Szörny extends Szereplő {

/** A megevett hősök száma. */

int megevettHősökSzáma;

/** A megevett kincsek száma. */

int megevettKincsekSzáma;

/**

* Létrehoz egy <code>Szörny</code> objektumot.

*

* @param labirintus amibe a szörnyet helyezzük.

*/

public Szörny(Labirintus labirintus) {

super(labirintus);

}

/**

* A szörnyek mozgásának vezérlése, ami szerint szörnyek

* a hős felés igyekeznek.

*

* @param hős aki felé a szörny igyekszik

*/

public void lép(Hős hős) {

int távolság = távolság(hős);

// Abba az irányba lévő pozícióra lép, amelyben közelebb kerül a hős.

if(!labirintus.fal(oszlop, sor-1))

if(távolság(oszlop, sor-1, hős) < távolság) {

lépFöl();

return;

}

if(!labirintus.fal(oszlop, sor+1))

if(távolság(oszlop, sor+1, hős) < távolság) {

lépLe();

return;

}

if(!labirintus.fal(oszlop-1, sor))

if(távolság(oszlop-1, sor, hős) < távolság) {

lépBalra();

return;

}

if(!labirintus.fal(oszlop+1, sor))

if(távolság(oszlop+1, sor, hős) < távolság) {

lépJobbra();

return;

}

}

/**

* A szörny megette a hőst?

*

* @param hős aki bolyong a labirintusban.

*/

public boolean megesz(Hős hős) {

if(oszlop == hős.oszlop()

&& sor == hős.sor()) {

++megevettHősökSzáma;

return true;

} else

return false;

}

/**

Page 186:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

158 Created by XMLmind XSL-FO Converter.

* Számolgatja a megevett kincseket.

*

* @param kincs amit éppen megettem.

*/

public void megtaláltam(Kincs kincs) {

++megevettKincsekSzáma;

}

/**

* A {@code Szörny} objektum sztring reprezentációját adja

* meg.

*

* @return String az objektum sztring reprezentációja.

*/

public String toString() {

return "SZÖRNY megevett hősök = "

+ megevettHősökSzáma

+ "megevett kincsek = "

+ megevettKincsekSzáma;

}

}

1.1.1.5. A Labirintus osztály

A Labirintus osztály írását a Saját labirintus feladat című pontban kezdtük el fejleszteni. Íme itt a teljes kód:

/*

* Labirintus.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.labirintus;

/**

* A labirintust leíró osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

public class Labirintus {

/** A labirintus szélessége. */

protected int szélesség;

/** A labirintus magassága. */

protected int magasság;

/** A labirintus szerkezete: hol van fal, hol járat. */

protected boolean[][] szerkezet;

/** A falat a true érték jelenti. */

final static boolean FAL = true;

/** Milyen állapotban van éppen a játék. */

protected int játékÁllapot = 0;

/** Normál működés, a hőssel időközben semmi nem történt. */

public static final int JÁTÉK_MEGY_HŐS_RENDBEN = 0;

/** A hőst éppen megették, de még van élete. */

public final static int JÁTÉK_MEGY_MEGHALT_HŐS = 1;

/** Vége a játéknak, a játékos győzött. */

public final static int JÁTÉK_VÉGE_MINDEN_KINCS_MEGVAN = 2;

/** Vége a játéknak, a játékos vesztett. */

public final static int JÁTÉK_VÉGE_MEGHALT_HŐS = 3;

/** A labirintus kincsei. */

protected Kincs [] kincsek;

/** A labirintus szörnyei. */

protected Szörny [] szörnyek;

/**

* Létrehoz egy megadott szerkezetű

Page 187:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

159 Created by XMLmind XSL-FO Converter.

* {@code Labirintus} objektumot.

*/

public Labirintus() {

szerkezet = new boolean[][]{

{false, false, false, true, false, true, false, true, true, true },

{false, false, false, false, false, false, false, false, false, false},

{true, false, true, false, true, false, true, false, true, false},

{false, false, false, false, true, false, true, false, false, false},

{false, true, true, false, false, false, true, true, false, true },

{false, false, false, false, true, false, false, false, false, false},

{false, true, false, false, false, true, false, true, true, false},

{false, false, false, true, false, true, false, true, false, false},

{false, true, false, false, false, false, false, false, false, true },

{false, false, false, false, true, false, false, false, true, true }

};

magasság = szerkezet.length;

szélesség = szerkezet[0].length;

}

/**

* Létrehoz egy paraméterben kapott szerkezetű <code>Labirintus</code>

* objektumot.

*

* @param kincsekSzáma a kincsek száma a labirintusban.

* @param szörnyekSzáma a szörnyek száma a labirintusban.

* @exception RosszLabirintusKivétel ha a labirintust definiáló tömb

* nincs elkészítve.

*/

public Labirintus(boolean[][] szerkezet, int kincsekSzáma, int szörnyekSzáma)

throws RosszLabirintusKivétel {

if(szerkezet == null)

throw new RosszLabirintusKivétel("A labirintust definiáló tömb nincs

elkészítve.");

this.szerkezet = szerkezet;

magasság = szerkezet.length;

szélesség = szerkezet[0].length;

kincsekSzörnyek(kincsekSzáma, szörnyekSzáma);

}

/**

* Létrehoz egy megadott méretű, véletlen szerkezetű

* <code>Labirintus</code> objektumot.

*

* @param szélesség a labirintus szélessége.

* @param magasság a labirintus magassága.

* @param kincsekSzáma a kincsek száma a labirintusban.

* @param szörnyekSzáma a szörnyek száma a labirintusban.

*/

public Labirintus(int szélesség, int magasság,

int kincsekSzáma, int szörnyekSzáma) {

this.magasság = magasság;

this.szélesség = szélesség;

szerkezet = new boolean[magasság][szélesség];

java.util.Random véletlenGenerátor = new java.util.Random();

for(int i=0; i<magasság; ++i)

for(int j=0; j<szélesség; ++j)

if(véletlenGenerátor.nextInt()%3 == 0)

// a labirintus egy harmada lesz fal

szerkezet[magasság][szélesség] = false;

else

// két harmada pedig járat

szerkezet[magasság][szélesség] = true;

Page 188:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

160 Created by XMLmind XSL-FO Converter.

kincsekSzörnyek(kincsekSzáma, szörnyekSzáma);

}

/**

* Létrehoz egy 10x10-es, beépített szerkezetű <code>Labirintus</code>

* objektumot.

*

* @param kincsekSzáma a kincsek száma a labirintusban.

* @param szörnyekSzáma a szörnyek száma a labirintusban.

*/

public Labirintus(int kincsekSzáma, int szörnyekSzáma) {

this();

magasság = szerkezet.length;

szélesség = szerkezet[0].length;

kincsekSzörnyek(kincsekSzáma, szörnyekSzáma);

}

/**

* Egy megfelelő szerkezetű szöveges állományból elkészít egy új a

* <code>Labirintus</code> objektumot.

* A szöveges állomány szerkezete a következő:

* <pre>

* // A labirintus szerkezetét megadó állomány, szerkezete a következő:

* // a kincsek száma

* // a szörnyek száma

* // a labirintus szélessége

* // magassága

* // fal=1 járat=0 ...

* // .

* // .

* // .

* 6

* 3

* 10

* 10

* 0 0 0 1 0 1 0 1 1 1

* 0 0 0 0 0 0 0 0 0 0

* 1 0 1 0 1 0 1 0 1 0

* 0 0 0 0 1 0 1 0 0 0

* 0 1 1 0 0 0 1 1 0 1

* 0 0 0 0 1 0 0 0 0 0

* 0 1 0 0 0 1 0 1 1 0

* 0 0 0 1 0 1 0 1 0 0

* 0 1 0 0 0 0 0 0 0 1

* 0 0 0 0 1 0 0 0 1 1

* </pre>

*

* @param labirintusFájlNév a labirintust definiáló, megfelelő

* szerkezetű szöveges állomány neve.

* @exception RosszLabirintusKivétel ha a labirintust definiáló állomány

* nincs meg, nem a megfelelő szerkezetű, vagy gond van az olvasásával.

*/

public Labirintus(String labirintusFájlNév) throws RosszLabirintusKivétel {

int kincsekSzáma = 6; // ezeknek a kezdőértékeknek nincs jelentősége,

int szörnyekSzáma = 3; // mert majd a fájlból olvassuk be, amiben ha a

// négy fő adat hibás, akkor nem is építjük fel a labirintust.

// Csatorna a szöveges állomány olvasásához

java.io.BufferedReader szövegesCsatorna = null;

try {

szövegesCsatorna = new java.io.BufferedReader(

new java.io.FileReader(labirintusFájlNév));

String sor = szövegesCsatorna.readLine();

while(sor.startsWith("//"))

Page 189:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

161 Created by XMLmind XSL-FO Converter.

sor = szövegesCsatorna.readLine();

try {

kincsekSzáma = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

szörnyekSzáma = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

szélesség = Integer.parseInt(sor);

sor = szövegesCsatorna.readLine();

magasság = Integer.parseInt(sor);

szerkezet = new boolean[magasság][szélesség];

} catch(java.lang.NumberFormatException e) {

throw new RosszLabirintusKivétel("Hibás a kincsek, szörnyek száma,

szélesség, magasság megadási rész.");

}

for(int i=0; i<magasság; ++i) {

sor = szövegesCsatorna.readLine();

java.util.StringTokenizer st =

new java.util.StringTokenizer(sor);

for(int j=0; j<szélesség; ++j) {

String tegla = st.nextToken();

try {

if(Integer.parseInt(tegla) == 0)

szerkezet[i][j] = false;

else

szerkezet[i][j] = true;

} catch(java.lang.NumberFormatException e) {

System.out.println(i+". sor "+j+". oszlop "+e);

szerkezet[i][j] = false;

}

}

}

} catch(java.io.FileNotFoundException e1) {

throw new RosszLabirintusKivétel("Nincs meg a fájl: " + e1);

} catch(java.io.IOException e2) {

throw new RosszLabirintusKivétel("IO kivétel történt: "+e2);

} catch(java.util.NoSuchElementException e3) {

throw new RosszLabirintusKivétel("Nem jó a labirintus szerkezete: "

+e3);

} finally {

if(szövegesCsatorna != null) {

try{

szövegesCsatorna.close();

} catch(Exception e) {}

}

Page 190:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

162 Created by XMLmind XSL-FO Converter.

}

// Ha ide eljutottunk, akkor felépült a labirintus,

// lehet benépesíteni:

kincsekSzörnyek(kincsekSzáma, szörnyekSzáma);

}

/**

* Létrehozza a kincseket és a szörnyeket.

*

* @param kincsekSzáma a kincsek száma a labirintusban.

* @param szörnyekSzáma a szörnyek száma a labirintusban.

*/

private void kincsekSzörnyek(int kincsekSzáma, int szörnyekSzáma) {

// Kincsek létrehozása

kincsek = new Kincs[kincsekSzáma];

for(int i=0; i<kincsek.length; ++i)

kincsek[i] = new Kincs(this, (i+1)*100);

// Szörnyek létrehozása

szörnyek = new Szörny[szörnyekSzáma];

for(int i=0; i<szörnyek.length; ++i)

szörnyek[i] = new Szörny(this);

}

/**

* Megadja a játék aktuális állapotát.

*

* @return int a játék aktuális állapota.

*/

public int állapot() {

return játékÁllapot;

}

/**

* A labirintus mikrovilág életének egy pillanata: megnézi, hogy a bolyongó

* hős rátalált-e a kincsekre, vagy a szörnyek a hősre. Ennek megfelelően

* megváltozik a játék állapota.

*

* @param hős aki a labirintusban bolyong.

* @return int a játék állapotát leíró kód.

*/

public int bolyong(Hős hős) {

boolean mindMegvan = true;

for(int i=0; i < kincsek.length; ++i) {

// A hős rátalált valamelyik kincsre?

if(kincsek[i].megtalált(hős))

hős.megtaláltam(kincsek[i]);

// ha ez egyszer is teljesül, akkor nincs minden kincs megtalálva

if(!kincsek[i].megtalálva())

mindMegvan = false;

}

if(mindMegvan) {

játékÁllapot = JÁTÉK_VÉGE_MINDEN_KINCS_MEGVAN;

return játékÁllapot;

}

for(int i=0; i < szörnyek.length; ++i) {

szörnyek[i].lép(hős);

if(szörnyek[i].megesz(hős)) {

játékÁllapot = JÁTÉK_MEGY_MEGHALT_HŐS;

Page 191:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

163 Created by XMLmind XSL-FO Converter.

if(hős.megettek())

játékÁllapot = JÁTÉK_VÉGE_MEGHALT_HŐS;

return játékÁllapot;

}

}

return JÁTÉK_MEGY_HŐS_RENDBEN;

}

/**

* Madadja, hogy fal-e a labirintus adott oszlop, sor pozíciója.

*

* @param oszlop a labirintus adott oszlopa

* @param sor a labirintus adott sora

* @return true ha a pozíció fal vagy nincs a labirintusban.

*/

public boolean fal(int oszlop, int sor) {

if(!(oszlop >= 0 && oszlop <= szélesség-1

&& sor >= 0 && sor <= magasság-1))

return FAL;

else

return szerkezet[sor][oszlop] == FAL;

}

/**

* Madadja a labirintus szélességét.

*

* @return int a labirintus szélessége.

*/

public int szélesség() {

return szélesség;

}

/**

* Madadja a labirintus magasságát.

*

* @return int a labirintus magassága.

*/

public int magasság() {

return magasság;

}

/**

* Megadja a labirintus szerkezetét.

*

* @return boolean[][] a labirintus szerkezete.

*/

public boolean[][] szerkezet() {

return szerkezet;

}

/**

* Megadja a labirintus kincseit.

*

* @return Kincs[] a labirintus kincsei.

*/

public Kincs[] kincsek() {

return kincsek;

}

/**

* Megadja a labirintus szörnyeit.

*

* @return Szörny[] a labirintus szörnyei.

*/

Page 192:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

164 Created by XMLmind XSL-FO Converter.

public Szörny[] szörnyek() {

return szörnyek;

}

/**

* Kinyomtatja a labirintus szerkezetét a System.out-ra.

*/

public void nyomtat() {

for(int i=0; i<magasság; ++i) {

for(int j=0; j<szélesség; ++j) {

if(szerkezet[i][j])

System.out.print("|FAL");

else

System.out.print("| ");

}

System.out.println();

}

}

/**

* Kinyomtatja a labirintus szerkezetét és szereplőit a System.out-ra.

*

* @param hős akit szintén belenyomtat a labirintusba.

*/

public void nyomtat(Hős hős) {

for(int i=0; i<magasság; ++i) {

for(int j=0; j<szélesség; ++j) {

boolean vanSzörny = vanSzörny(i, j);

boolean vanKincs = vanKincs(i, j);

boolean vanHős = (i == hős.sor() && j == hős.oszlop());

if(szerkezet[i][j])

System.out.print("|FAL");

else if(vanSzörny && vanKincs && vanHős)

System.out.print("|SKH");

else if(vanSzörny && vanKincs)

System.out.print("|SK ");

else if(vanKincs && vanHős)

System.out.print("|KH ");

else if(vanSzörny && vanHős)

System.out.print("|SH ");

else if(vanKincs)

System.out.print("|K ");

else if(vanHős)

System.out.print("|H ");

else if(vanSzörny)

System.out.print("|S ");

else

System.out.print("| ");

}

System.out.println();

}

}

/**

* Kinyomtatja a labirintus szerkezetét és szereplőit egy

* karakteres csatornába.

*

* @param hős akit szintén belenyomtat a labirintusba.

* @param csatorna ahova nyomtatunk.

*/

Page 193:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

165 Created by XMLmind XSL-FO Converter.

public void nyomtat(Hős hős, java.io.PrintWriter csatorna) {

for(int i=0; i<magasság; ++i) {

for(int j=0; j<szélesség; ++j) {

boolean vanSzörny = vanSzörny(i, j);

boolean vanKincs = vanKincs(i, j);

boolean vanHős = (i == hős.sor() && j == hős.oszlop());

if(szerkezet[i][j])

csatorna.print("|FAL");

else if(vanSzörny && vanKincs && vanHős)

csatorna.print("|SKH");

else if(vanSzörny && vanKincs)

csatorna.print("|SK ");

else if(vanKincs && vanHős)

csatorna.print("|KH ");

else if(vanSzörny && vanHős)

csatorna.print("|SH ");

else if(vanKincs)

csatorna.print("|K ");

else if(vanHős)

csatorna.print("|H ");

else if(vanSzörny)

csatorna.print("|S ");

else

csatorna.print("| ");

}

csatorna.println();

}

}

/**

* Kinyomtatja a labirintus szerkezetét és szereplőit egy sztringbe.

*

* @param hős akit szintén belenyomtat a labirintusba.

* @return String a kinyomtatott labirintus

*/

public String kinyomtat(Hős hős) {

StringBuffer stringBuffer = new StringBuffer();

for(int i=0; i<magasság; ++i) {

for(int j=0; j<szélesség; ++j) {

boolean vanSzörny = vanSzörny(i, j);

boolean vanKincs = vanKincs(i, j);

boolean vanHős = (i == hős.sor() && j == hős.oszlop());

if(szerkezet[i][j])

stringBuffer.append("|FAL");

else if(vanSzörny && vanKincs && vanHős)

stringBuffer.append("|SKH");

else if(vanSzörny && vanKincs)

stringBuffer.append("|SK ");

else if(vanKincs && vanHős)

stringBuffer.append("|KH ");

else if(vanSzörny && vanHős)

stringBuffer.append("|SH ");

else if(vanKincs)

stringBuffer.append("|K ");

else if(vanHős)

stringBuffer.append("|H ");

else if(vanSzörny)

stringBuffer.append("|S ");

else

stringBuffer.append("| ");

}

Page 194:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

166 Created by XMLmind XSL-FO Converter.

stringBuffer.append("\n");

}

return stringBuffer.toString();

}

/**

* Madadja, hogy van-e megtalálható kincs a labirintus

* adott oszlop, sor pozíciója.

*

* @param oszlop a labirintus adott oszlopa

* @param sor a labirintus adott sora

* @return true ha van.

*/

boolean vanKincs(int sor, int oszlop) {

boolean van = false;

for(int i=0; i<kincsek.length; ++i)

if(sor == kincsek[i].sor()

&& oszlop == kincsek[i].oszlop()

&& !kincsek[i].megtalálva()) {

van = true;

break;

}

return van;

}

/**

* Madadja, hogy van-e szörny a labirintus adott oszlop,

* sor pozíciója.

*

* @param oszlop a labirintus adott oszlopa

* @param sor a labirintus adott sora

* @return true ha van.

*/

boolean vanSzörny(int sor, int oszlop) {

boolean van = false;

for(int i=0; i<szörnyek.length; ++i)

if(sor == szörnyek[i].sor()

&& oszlop == szörnyek[i].oszlop()) {

van = true;

break;

}

return van;

}

/**

* A labirintussal kapcsolatos apróságok önálló kipróbálására

* szolgál ez az indító metódus.

*

* @param args parancssor-argumentumok nincsenek.

*/

public static void main(String[] args) {

Labirintus labirintus = new Labirintus(6, 3);

Hős hős = new Hős(labirintus);

System.out.println(labirintus.getClass());

System.out.println(hős.getClass());

}

}

1.1.1.6. A RosszLabirintusKivétel osztály

Page 195:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

167 Created by XMLmind XSL-FO Converter.

A RosszLabirintusKivétel osztály írását a Kivételkezelés című pontban kezdtük el fejleszteni. Íme itt a teljes

kód:

/*

* RosszLabirintusKivétel.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.labirintus;

/**

* Ha állomány alapján készítjük a labirintust, akkor az állomány szerkezetének

* hibáit jelzi ez az osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.labirintus.Labirintus

*/

public class RosszLabirintusKivétel extends java.lang.Exception {

/**

* Elkészít egy <code>RosszLabirintusKivétel</code> kivétel objektumot.

*

* @param hiba a hiba leírása

*/

public RosszLabirintusKivétel(String hiba) {

super(hiba);

}

}

1.1.1.7. A labirintus API fordítása

C:\...\Munkakönyvtár> javac javattanitok\labirintus\*.java

Ha a korábbi Java osztályok kódját hiba nélkül jelöltük ki és illesztettük be a megfelelő állományokba, akkor ez

a fordítási parancs gond nélkül lefutott és a javattanitok/labirintus könyvtárban létrejöttek az

osztályoknak megfelelő .class állományok.

1.1.2. A LabirintusVilág osztály

Ebben a LabirintusVilág nevű osztályban keltjük életre az előző pontban kifejlesztett

javattanitok.labirintus API csomagot. Csupán egy karakteres megjelenést készítünk, ami jól mutatja,

hogyan kel életre a teremtett tiszta OO mikrovilágunk: a labirintus.

Nincs más dolgunk, mint a következő LabirintusVilág osztályt a javattanitok könyvtárba bemásolni.

(Általában is úgy szervezzük a kódokat, hogy a javattanitok.labirintus API csomagot használó

esettanulmányok osztályait a javattanitok csomagba helyezzük el.)

1.1.2.1. A LabirintusVilág osztály

/*

* LabirintusVilág.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

Page 196:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

168 Created by XMLmind XSL-FO Converter.

import javattanitok.labirintus.*;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának egy

* "tiszta" életre keltésére ad példát ez az osztály. Ennek megfelelően

* csak egyszerű karakteres megjelenítést biztosít. Fő feladata a

* kialakított labirintus OO mikrovilágunk API interfésze használatának

* bemutatása. Továbbá az egyszerűség megtartása miatt ebben a példában

* még nem vesz át adatokat a játékostól a program.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.LabirintusApplet

* @see javattanitok.LabirintusJáték

* @see javattanitok.LabirintusMIDlet

* @see javattanitok.LabirintusServlet

* @see javattanitok.HálózatiLabirintus

* @see javattanitok.TávoliLabirintus

* @see javattanitok.KorbásLabirintus

* @see javattanitok.ElosztottLabirintus

*/

public class LabirintusVilág implements Runnable {

/** A labirintus. */

protected Labirintus labirintus;

/** A hős. */

protected Hős hős;

/** A játékbeli idő mérésére.*/

private long idő = 0;

public LabirintusVilág() {

}

/**

* A <code>LabirintusVilág</code> objektum elkészítése.

*

* @param labirintusFájlNév a labirintust definiáló, megfelelő

* szerkezetű szöveges állomány neve.

* @exception RosszLabirintusKivétel ha a labirintust definiáló állomány nem

* a megfelelő szerkezetű

*/

public LabirintusVilág(String labirintusFájlNév)

throws RosszLabirintusKivétel {

// A labirintus elkészítése állományból

labirintus = new Labirintus(labirintusFájlNév);

// A hős elkészítése és a kezdő pozíciójának beállítása

hős = new Hős(labirintus);

hős.sor(9);

hős.oszlop(0);

// A játékbeli idő folyását biztosító szál elkészítése és indítása

new Thread(this).start();

}

/**

* A játék időbeli fejlődésének vezérlése. A labirintus mikrovilágának

* jelen osztálybeli életre keltésében max. 10 időpillanatig játszunk,

* mialatt a hős igyekszik mindig jobbra lépni.

*/

public void run() {

labirintus.nyomtat();

boolean játékVége = false;

while(!játékVége) {

idoegyseg();

if(idő<10)

hős.lépJobbra();

else

break;

Page 197:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

169 Created by XMLmind XSL-FO Converter.

switch(labirintus.bolyong(hős)) {

case Labirintus.JÁTÉK_MEGY_HŐS_RENDBEN:

break;

case Labirintus.JÁTÉK_MEGY_MEGHALT_HŐS:

hős.sor(9);

hős.oszlop(0);

System.out.println("Megettek a(z) " + idő + ". lépésben!");

break;

case Labirintus.JÁTÉK_VÉGE_MINDEN_KINCS_MEGVAN:

System.out.println("Megvan minden kincs a(z) " + idő

+ ". lépésben!");

játékVége = true;

break;

case Labirintus.JÁTÉK_VÉGE_MEGHALT_HŐS:

System.out.println("Minden életem elfogyott a(z) " + idő

+ ". lépésben!");

játékVége = true;

break;

}

System.out.println("A labirintus a(z) " + idő + ". lépésben:");

labirintus.nyomtat(hős);

}

System.out.println("Megtalált értékek: " + hős.pontszám());

System.out.println("Játékidő: " + idő + " lépés");

System.out.println("Hányszor ettek meg: "

+ (Hős.ÉLETEK_SZÁMA - hős.életek()));

}

/** Megadja, hogy milyen gyorsan telik az idő a játékban. */

private void idoegyseg() {

++idő;

try {

Thread.sleep(1000);

} catch(InterruptedException e) {}

}

/**

* Átveszi a játék indításához szükséges paramétereket, majd

* elindítja a játék világának működését.

*

* @param args a labirintus tervét tartalmazó állomány neve az első

* parancssor-argumentum.

*/

public static void main(String[] args) {

if(args.length != 1) {

System.out.println("Indítás: java LabirintusVilág labirintus.txt");

System.exit(-1);

}

try {

new LabirintusVilág(args[0]);

} catch(RosszLabirintusKivétel rosszLabirintusKivétel) {

System.out.println(rosszLabirintusKivétel);

}

}

}

Page 198:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

170 Created by XMLmind XSL-FO Converter.

Minden esettanulmányra igaz lesz, hogy a játék időfejlődését egy külön szálba programozzuk be. Jelen esetben

ezt a szálat is a LabirintusVilág osztályban

public class LabirintusVilág implements Runnable {

implementáltuk, ennek megfelelően az időfejlődést a run() módszerbe helyeztük.

1.1.2.2. A tiszta OO labirintus fordítása, futtatása

C:\...\Munkakönyvtár> javac javattanitok\LabirintusVilág.java

C:\...\Munkakönyvtár>java javattanitok.LabirintusVilág

Indítás: java LabirintusVilág labirintus.txt

A program sikeres futtatásához még például az alábbi, A labirintust állományból felépítő konstruktor című

pontban megtárgyalt labirintus.txt állományt kell a Munkakönyvtár munkakönyvtárukba bemásolnunk.

//

// labirintus.txt

//

// DIGIT 2005, Javat tanítok

// Bátfai Norbert, [email protected]

//

// A labirintus szerkezetét megadó állomány, szerkezete a következő:

// a kincsek száma

// a szörnyek száma

// a labirintus szélessége

// magassága

// fal=1 járat=0 ...

// .

// .

// .

6

3

10

10

0 0 0 1 0 1 0 1 1 1

0 0 0 0 0 0 0 0 0 0

1 0 1 0 1 0 1 0 1 0

0 0 0 0 1 0 1 0 0 0

0 1 1 0 0 0 1 1 0 1

0 0 0 0 1 0 0 0 0 0

0 1 0 0 0 1 0 1 1 0

0 0 0 1 0 1 0 1 0 0

0 1 0 0 0 0 0 0 0 1

0 0 0 0 1 0 0 0 1 1

Ezután már bizonyosan sikeresen futtathatja a kedves Olvasó ezt a példát:

C:\...\Munkakönyvtár>java javattanitok.LabirintusVilág labirintus.txt

| | | |FAL| |FAL| |FAL|FAL|FAL

Page 199:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

171 Created by XMLmind XSL-FO Converter.

| | | | | | | | | |

|FAL| |FAL| |FAL| |FAL| |FAL|

| | | | |FAL| |FAL| | |

| |FAL|FAL| | | |FAL|FAL| |FAL

| | | | |FAL| | | | |

| |FAL| | | |FAL| |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

| | | | |FAL| | | |FAL|FAL

A labirintus a(z) 1. lépésben:

| | | |FAL| |FAL| |FAL|FAL|FAL

| | |S | | | | | | |

|FAL| |FAL| |FAL| |FAL| |FAL|

| | |K | |FAL| |FAL|S |K |

| |FAL|FAL| |SK | |FAL|FAL| |FAL

| | | | |FAL|K | |K | |

| |FAL|K | | |FAL| |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

| |H | | |FAL| | | |FAL|FAL

A labirintus a(z) 2. lépésben:

| | | |FAL| |FAL| |FAL|FAL|FAL

| | |S | | | | | | |

|FAL| |FAL| |FAL| |FAL| |FAL|

| | |K | |FAL| |FAL|S |K |

| |FAL|FAL| |SK | |FAL|FAL| |FAL

| | | | |FAL|K | |K | |

| |FAL|K | | |FAL| |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

| | |H | |FAL| | | |FAL|FAL

A labirintus a(z) 3. lépésben:

| | | |FAL| |FAL| |FAL|FAL|FAL

| | |S | | | | | | |

|FAL| |FAL| |FAL| |FAL| |FAL|

| | |K | |FAL| |FAL|S |K |

| |FAL|FAL| |SK | |FAL|FAL| |FAL

| | | | |FAL|K | |K | |

| |FAL|K | | |FAL| |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

| | | |H |FAL| | | |FAL|FAL

A labirintus a(z) 4. lépésben:

| | | |FAL| |FAL| |FAL|FAL|FAL

| | |S | | | | | | |

|FAL| |FAL| |FAL| |FAL| |FAL|

| | |K | |FAL| |FAL|S |K |

| |FAL|FAL| |SK | |FAL|FAL| |FAL

| | | | |FAL|K | |K | |

| |FAL|K | | |FAL| |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

| | | |H |FAL| | | |FAL|FAL

A labirintus a(z) 5. lépésben:

| | | |FAL| |FAL| |FAL|FAL|FAL

| | |S | | | | | | |

|FAL| |FAL| |FAL| |FAL| |FAL|

| | |K | |FAL| |FAL|S |K |

| |FAL|FAL| |SK | |FAL|FAL| |FAL

| | | | |FAL|K | |K | |

| |FAL|K | | |FAL| |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

| | | |H |FAL| | | |FAL|FAL

A labirintus a(z) 6. lépésben:

| | | |FAL| |FAL| |FAL|FAL|FAL

| | |S | | | | | | |

|FAL| |FAL| |FAL| |FAL| |FAL|

| | |K | |FAL| |FAL|S |K |

| |FAL|FAL| |SK | |FAL|FAL| |FAL

| | | | |FAL|K | |K | |

| |FAL|K | | |FAL| |FAL|FAL|

Page 200:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

172 Created by XMLmind XSL-FO Converter.

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

| | | |H |FAL| | | |FAL|FAL

A labirintus a(z) 7. lépésben:

| | | |FAL| |FAL| |FAL|FAL|FAL

| | |S | | | | | | |

|FAL| |FAL| |FAL| |FAL| |FAL|

| | |K | |FAL| |FAL|S |K |

| |FAL|FAL| |SK | |FAL|FAL| |FAL

| | | | |FAL|K | |K | |

| |FAL|K | | |FAL| |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

| | | |H |FAL| | | |FAL|FAL

A labirintus a(z) 8. lépésben:

| | | |FAL| |FAL| |FAL|FAL|FAL

| | |S | | | | | | |

|FAL| |FAL| |FAL| |FAL| |FAL|

| | |K | |FAL| |FAL|S |K |

| |FAL|FAL| |SK | |FAL|FAL| |FAL

| | | | |FAL|K | |K | |

| |FAL|K | | |FAL| |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

| | | |H |FAL| | | |FAL|FAL

A labirintus a(z) 9. lépésben:

| | | |FAL| |FAL| |FAL|FAL|FAL

| | |S | | | | | | |

|FAL| |FAL| |FAL| |FAL| |FAL|

| | |K | |FAL| |FAL|S |K |

| |FAL|FAL| |SK | |FAL|FAL| |FAL

| | | | |FAL|K | |K | |

| |FAL|K | | |FAL| |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

| | | |H |FAL| | | |FAL|FAL

Megtalált értékek: 0

Játékidő: 10 lépés

Hányszor ettek meg: 0

1.1.3. A labirintus API és a LabirintusVilág a NetBeans IDE környezetben

A példa felélesztését most a NetBeans IDE fejlesztői környezetben is elvégezzük. Az a kedves Olvasó, aki eddig

esetleg még nem telepítette fel gépére a NetBeans IDE-t, A NetBeans integrált fejlesztői környezet használata

című pontban kaphat segítséget ehhez. A File/New Project... pont kiválasztása után a kinyíló New Project

ablakban első lépésként válasszuk a General kategóriát, azon belül a Java Application projektet.

A Next gombra következő ablakban elég a projekt nevét megadni, ez legyen mondjuk a JavatTanitokPeldak.

Ugyanitt még deaktiváljuk (szüntessük meg a kipipálását) a Create Main Class opciót.

Page 201:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

173 Created by XMLmind XSL-FO Converter.

A Finish gomb nyomásával a projekt létrehozását befejeztük.

A Source Packages/default package csomagon egy jobb egérgombot nyomva válasszuk a New/Java Package...

menüpontot! A kinyíló ablakban adjuk meg a javattanitok csomag nevet.

Page 202:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

174 Created by XMLmind XSL-FO Converter.

Miután a Finish gombbal befejezzük a létrehozást, a projekt forráskönyvtárában, esetünkben a C:\Documents

and Settings\norbi\JavatTanitokPeldak\src könyvtárban megjelenik a javattanitok alkönyvtár.

Másoljuk ide a kézikönyv LabirintusVilág.java forrását. Továbbá másoljuk ide a labirintus API-t, azaz a

labirintus könyvtárat, ami tartalmazza a korábban ismertetett Szereplő.java, Hős.java, Kincs.java,

Szörny.java, Labirintus.java, RosszLabirintusKivétel.java állományokat. Ha ezzel megvagyunk,

akkor a NetBeans IDE projektek füle a következőket kell mutassa:

Page 203:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

175 Created by XMLmind XSL-FO Converter.

A NetBeans IDE projektek fülében a JavatTanitokPeldak projekt néven egy jobb egérgombot nyomva a

tulajdonságok Properties menüpontot választva a kinyíló ablak Run pontját kérve a Main Class és az

Arguments mezőket kell beállítanunk.

Az Arguments mező értékének megfelelően a labirintus.txt állományt még be kell másolnunk a

C:\Documents and Settings\norbi\JavatTanitokPeldak könyvtárba. Ha ezzel megvagyunk, jöhet a

tesztelés, egyszerűen nyomjunk F6 funkcióbillentyűt, vagy a Run/Run Main Projekt menüpontot!

1.2. Java a játékokban: egy teljes képernyős példa - Labirintus Játék

A példát az Előzetes a példaprogramokból című pontban vezettük be, majd az előző esettanulmány A labirintus

API felélesztése című pontjában a labirintus API világát már életre keltettük, a jelen példában közelítünk a PC-s

játékokhoz, melyek tipikusan a teljes képernyőt uralják, a kifejlesztendő LabirintusJáték osztály a labirintus

mikrovilágának egy olyan életre keltését adja, ami hasonlóan képes erre, azaz a teljes képernyőn működik!

A példa kipróbálásához a LabirintusJáték osztályt a javattanitok könyvtárba kell bemásolnunk.

1.2.1. A LabirintusJáték osztály

Az osztály működése lényegében megegyezik az előző példáéval, de ránézésre bonyolultabbnak tűnhet, mivel itt

már grafikus felületen fut a program, ennek megfelelően valódi képeket - BufferedImage objektumokat -

használunk, amiket be kell tölteni, ki kell rajzolni. De annyiban valóban komplikáltabb a kód, hogy a nem

egyszerűen grafikus felületen, hanem teljes képernyős módban is dolgozik, ahol a képek kirajzolásának

hatékonyságát azzal is fokozzuk, hogy a kompatibilisKép függvénnyel a grafikus rendszerünkkel kompatibilis

formába is konvertáljuk őket. Továbbá a játékostól átvesszük a hőst mozgató billentyűzet inputot, amit a

KeyAdapter - névtelen belső, a konstruktorban definiált - adapter osztállyal kezelünk: az adott kurzor nyilaknak

megfelelő irányokba mozgatjuk a hőst, illetve az ESC billentyű nyomására kilépünk a programból.

/*

* LabirintusJáték.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

import javattanitok.labirintus.*;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának egy

* "teljes képernyős" (Full Screen Exclusive Mode API-s) életre

Page 204:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

176 Created by XMLmind XSL-FO Converter.

* keltésére ad példát ez az osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.LabirintusVilág

* @see javattanitok.LabirintusApplet

* @see javattanitok.LabirintusServlet

* @see javattanitok.LabirintusMIDlet

* @see javattanitok.HálózatiLabirintus

* @see javattanitok.TávoliLabirintus

* @see javattanitok.KorbásLabirintus

* @see javattanitok.ElosztottLabirintus

*/

public class LabirintusJáték extends java.awt.Frame

implements Runnable {

/** A labirintus. */

Labirintus labirintus;

/** A hős. */

Hős hős;

/** A játékbeli idő mérésére.*/

private long idő = 0;

/** Jelzi a játék végét, ezután a játék álapota már nem változik. */

private boolean játékVége = false;

/** A játék végén a játékost tájékoztató üzenet. */

String végeÜzenet = "Vége a játéknak!";

/** Jelzi, hogy a program terminálhat. */

private boolean játékKilép = false;

/** A labirintus szereplőihez rendelt képek. Ebben a példában már

* BufferedImage képeket használunk, mert majd a teljesítmény javitás

* apropóján ezeket a grafikus konfigurációnkhoz igazítjuk. */

java.awt.image.BufferedImage falKép;

java.awt.image.BufferedImage járatKép;

java.awt.image.BufferedImage hősKép;

java.awt.image.BufferedImage szörnyKép;

java.awt.image.BufferedImage kincsKép;

// A fullscreenbe kapcsoláshoz

java.awt.GraphicsDevice graphicsDevice;

// A megjelenítéshez

java.awt.image.BufferStrategy bufferStrategy;

/**

* A <code>LabirintusJáték</code> objektum elkészítése.

*

* @param labirintusFájlNév a labirintust definiáló, megfelelő

* szerkezetű szöveges állomány neve.

* @exception RosszLabirintusKivétel ha a labirintust definiáló állomány nem

* a megfelelő szerkezetű

*/

public LabirintusJáték(String labirintusFájlNév)

throws RosszLabirintusKivétel {

/* A labirintus felépítése. */

// A labirintus elkészítése állományból

labirintus = new Labirintus(labirintusFájlNév);

// A hős elkészítése és a kezdő pozíciójának beállítása

hős = new Hős(labirintus);

// A hős kezdő pozíciója

hős.sor(9);

hős.oszlop(0);

/* Teljes képernyős módba próbálunk váltani. */

// A lokális grafikus környezet elkérése

java.awt.GraphicsEnvironment graphicsEnvironment

= java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment();

// A grafikus környzetből a képernyővel dolgozunk

graphicsDevice = graphicsEnvironment.getDefaultScreenDevice();

// Próbálunk teljes képernyős, most speciálisan 1024x768-ba váltani

teljesKépernyősMód(graphicsDevice);

// Átadjuk a grafikus konfigurációt a kompatibilis képek elkészítéséhez

képErőforrásokBetöltése(graphicsDevice.getDefaultConfiguration());

// A hős mozgatása a KURZOR billenytűkkel, ESC kilép

addKeyListener(new java.awt.event.KeyAdapter() {

public void keyPressed(java.awt.event.KeyEvent billentyűEsemény) {

int billentyű = billentyűEsemény.getKeyCode();

Page 205:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

177 Created by XMLmind XSL-FO Converter.

if(!játékVége)

switch(billentyű) { // hős mozgatása

case java.awt.event.KeyEvent.VK_UP:

hős.lépFöl();

break;

case java.awt.event.KeyEvent.VK_DOWN:

hős.lépLe();

break;

case java.awt.event.KeyEvent.VK_RIGHT:

hős.lépJobbra();

break;

case java.awt.event.KeyEvent.VK_LEFT:

hős.lépBalra();

break;

}

// Kilépés a játékból

if(billentyű == java.awt.event.KeyEvent.VK_ESCAPE)

játékKilép = true;

// A játékban történt változások a képernyőn

// is jelenjenek meg

rajzolniKell();

};

});

// A játékbeli idő folyását biztosító szál elkészítése és indítása

new Thread(this).start();

}

/** A játék időbeli fejlődésének vezérlése. */

synchronized public void run() {

while(!játékKilép) {

// Aktív renderelés

rajzol();

idoegyseg();

switch(labirintus.bolyong(hős)) {

case Labirintus.JÁTÉK_MEGY_HŐS_RENDBEN:

break;

case Labirintus.JÁTÉK_MEGY_MEGHALT_HŐS:

// Még van élete, visszatesszük a kezdő pozícióra

hős.sor(9);

hős.oszlop(0);

break;

case Labirintus.JÁTÉK_VÉGE_MINDEN_KINCS_MEGVAN:

végeÜzenet = "Győztél, vége a játéknak!";

játékVége = true;

break;

case Labirintus.JÁTÉK_VÉGE_MEGHALT_HŐS:

végeÜzenet = "Vesztettél, vége a játéknak!";

játékVége = true;

break;

}

}

// Kilépés a játékból

setVisible(false);

graphicsDevice.setFullScreenWindow(null);

System.exit(0);

}

/**

* Ébresztő az várakozó rajzolást végző szálnak, ki kell rajzolni a játék

* grafikus felületét.

Page 206:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

178 Created by XMLmind XSL-FO Converter.

*/

synchronized public void rajzolniKell() {

notify();

}

/**

* Megadja, hogy milyen gyorsan telik az idő a játékban.

*/

private void idoegyseg() {

++ idő;

try {

wait(1000);

} catch (InterruptedException e) {}

}

/**

* Kép erőforrások betöltése.

*

* @param graphicsConfiguration a grafikus komfigurációval kompatibilis

* képek készítéséhez.

*/

public void képErőforrásokBetöltése(java.awt.GraphicsConfiguration

graphicsConfiguration) {

falKép = kompatibilisKép("fal.png", graphicsConfiguration);

járatKép = kompatibilisKép("járat.png", graphicsConfiguration);

hősKép = kompatibilisKép("hős.png", graphicsConfiguration);

szörnyKép = kompatibilisKép("szörny.png", graphicsConfiguration);

kincsKép = kompatibilisKép("kincs.png", graphicsConfiguration);

}

/**

* A grafikus konfigurációhoz igazítot kép.

*

* @param képNév a kép állomány neve

* @param graphicsConfiguration a grafikus komfigurációval kompatibilis

* képek készítéséhez.

*/

public java.awt.image.BufferedImage kompatibilisKép(String képNév,

java.awt.GraphicsConfiguration graphicsConfiguration) {

// Képet legegyszerűben a Swing-beli ImageIcon-al tölthetünk be:

java.awt.Image kép = new javax.swing.ImageIcon

(képNév).getImage();

// ebből BufferedImage-et készítünk, hogy hozzáférjünk a transzparencia

// értékhez (pl. a hős, a kincs és a szörny transzparens nálunk)

java.awt.image.BufferedImage bufferedImage =

new java.awt.image.BufferedImage(kép.getWidth(null),

kép.getHeight(null),

java.awt.image.BufferedImage.TYPE_INT_ARGB);

java.awt.Graphics2D g0 = bufferedImage.createGraphics();

g0.drawImage(kép, 0, 0, null);

g0.dispose();

// Az előző lépéshez hasonló lépésben most egy olyan BufferedImage-et,

// készítünk, ami kompatibilis a grafikus konfigurációnkkal

java.awt.image.BufferedImage kompatibilisKép

= graphicsConfiguration.createCompatibleImage(

bufferedImage.getWidth(), bufferedImage.getHeight(),

bufferedImage.getColorModel().getTransparency());

java.awt.Graphics2D g = kompatibilisKép.createGraphics();

g.drawImage(bufferedImage, 0, 0, null);

g.dispose();

return kompatibilisKép;

}

/**

Page 207:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

179 Created by XMLmind XSL-FO Converter.

* A játék grafikus felületének aktív renderelése.

*/

public void rajzol() {

java.awt.Graphics g = bufferStrategy.getDrawGraphics();

// A labirintus kirajzolása

for(int i=0; i<labirintus.szélesség(); ++i) {

for(int j=0; j<labirintus.magasság(); ++j) {

if(labirintus.szerkezet()[j][i])

g.drawImage(falKép, i*falKép.getWidth(),

j*falKép.getHeight(), null);

else

g.drawImage(járatKép, i*járatKép.getWidth(),

j*járatKép.getHeight(), null);

}

}

// A kincsek kirajzolása

Kincs[] kincsek = labirintus.kincsek();

for(int i=0; i<kincsek.length; ++i) {

g.drawImage(kincsKép,

kincsek[i].oszlop()*kincsKép.getWidth(),

kincsek[i].sor()*kincsKép.getHeight(), null);

// Ha már megvan a kics, akkor áthúzzuk

if(kincsek[i].megtalálva()) {

g.setColor(java.awt.Color.red);

g.drawLine(kincsek[i].oszlop()*kincsKép.getWidth(),

kincsek[i].sor()*kincsKép.getHeight(),

kincsek[i].oszlop()*kincsKép.getWidth()

+ kincsKép.getWidth(),

kincsek[i].sor()*kincsKép.getHeight()

+ kincsKép.getHeight());

g.drawLine(kincsek[i].oszlop()*kincsKép.getWidth()

+kincsKép.getWidth(),

kincsek[i].sor()*kincsKép.getHeight(),

kincsek[i].oszlop()*kincsKép.getWidth(),

kincsek[i].sor()*kincsKép.getHeight()

+ kincsKép.getHeight());

} else {

// ellenkező esetben kiírjuk az értékét

g.setColor(java.awt.Color.yellow);

g.drawString(""+kincsek[i].érték(),

kincsek[i].oszlop()*kincsKép.getWidth()

+ kincsKép.getWidth()/2,

kincsek[i].sor()*kincsKép.getHeight()

+ kincsKép.getHeight()/2);

}

}

// A szörnyek kirajzolása

Szörny[] szörnyek = labirintus.szörnyek();

for(int i=0; i<szörnyek.length; ++i)

g.drawImage(szörnyKép,

szörnyek[i].oszlop()*szörnyKép.getWidth(),

szörnyek[i].sor()*szörnyKép.getHeight(), null);

// A hős kirajzolása

g.drawImage(hősKép,

hős.oszlop()*hősKép.getWidth(),

hős.sor()*hősKép.getHeight(), null);

// A játék aktuális adataiból néhány kiíratása

g.setColor(java.awt.Color.black);

g.drawString("Életek száma: "+hős.életek(), 10, 40);

g.drawString("Gyűjtött érték: "+hős.pontszám(), 10, 60);

g.drawString("Idő: "+idő, 10, 80);

if(játékVége)

Page 208:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

180 Created by XMLmind XSL-FO Converter.

g.drawString(végeÜzenet, 420, 350);

g.dispose();

if (!bufferStrategy.contentsLost())

bufferStrategy.show();

}

/**

* Teljes képernyős módba (Full Screen Exclusive Mode) kapcsolás.

* Ha nem támogatott, akkor sima ablak fejléc és keret nélkül.

*/

public void teljesKépernyősMód(java.awt.GraphicsDevice graphicsDevice) {

int szélesség = 0;

int magasság = 0;

// Nincs ablak fejléc, keret.

setUndecorated(true);

// Mi magunk fogunk rajzolni.

setIgnoreRepaint(true);

// Nincs átméretezés

setResizable(false);

// Át tudunk kapcsolni fullscreenbe?

boolean fullScreenTamogatott = graphicsDevice.isFullScreenSupported();

// Ha tudunk, akkor Full-Screen exkluzív módba váltunk

if(fullScreenTamogatott) {

graphicsDevice.setFullScreenWindow(this);

// az aktuális képernyő jellemzök (szélesség, magasság, színmélység,

// frissítési frekvencia) becsomagolt elkérése

java.awt.DisplayMode displayMode

= graphicsDevice.getDisplayMode();

// és kiíratása

szélesség = displayMode.getWidth();

magasság = displayMode.getHeight();

int színMélység = displayMode.getBitDepth();

int frissítésiFrekvencia = displayMode.getRefreshRate();

System.out.println(szélesség

+ "x" + magasság

+ ", " + színMélység

+ ", " + frissítésiFrekvencia);

// A lehetséges képernyő beállítások elkérése

java.awt.DisplayMode[] displayModes

= graphicsDevice.getDisplayModes();

// Megnézzük, hogy támogatja-e az 1024x768-at, mert a

// példa játékunkhoz ehhez a felbontáshoz készítettük a képeket

boolean dm1024x768 = false;

for(int i=0; i<displayModes.length; ++i) {

if(displayModes[i].getWidth() == 1024

&& displayModes[i].getHeight() == 768

&& displayModes[i].getBitDepth() == színMélység

&& displayModes[i].getRefreshRate()

== frissítésiFrekvencia) {

graphicsDevice.setDisplayMode(displayModes[i]);

dm1024x768 = true;

break;

}

}

if(!dm1024x768)

System.out.println("Nem megy az 1024x768, de a példa képméretei ehhez a

felbontáshoz vannak állítva.");

} else {

setSize(szélesség, magasság);

validate();

setVisible(true);

}

createBufferStrategy(2);

bufferStrategy = getBufferStrategy();

Page 209:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

181 Created by XMLmind XSL-FO Converter.

}

/**

* Átveszi a játék indításához szükséges paramétereket, majd

* elindítja a játék világának működését.

*

* @param args a labirintus tervét tartalmazó állomány neve az első

* parancssor-argumentum.

*/

public static void main(String[] args) {

if(args.length != 1) {

System.out.println("Indítás: java LabirintusJáték labirintus.txt");

System.exit(-1);

}

try {

new LabirintusJáték(args[0]);

} catch(RosszLabirintusKivétel rosszLabirintusKivétel) {

System.out.println(rosszLabirintusKivétel);

}

}

}

Az osztály teljesKépernyősMód() függvénye végzi el a program teljes képernyős módba léptetését. Itt mi

konkrétan egy 1024x768 felbontású üzemmódba akarunk kapcsolni. Az Olvasó ezt a felbontást a saját

monitorjához tudja igazítani, illetve a a displayModes tömbbe lekérdezett lehetséges grafikus módok közül

választhat is.

1.2.2. A teljes képernyős labirintus fordítása, futtatása

A program sikeres futtatásához az alábbi, egyenként 102x76 pixel méretű képeket

a fal.png, a járat.png, a hős.png, a kincs.png és a szörny.png állományokat kell a Munkakönyvtár

munkakönyvtárukba bemásolnunk. (Ezek a képek A példaprogramok forrásainak letöltése című pontban

ismertetett archívumban is megtalálhatóak.) E képállományok elkészítése után már bizonyosan sikeresen

futtathatja a kedves Olvasó ezt a példát is:

C:\...\Munkakönyvtár> javac javattanitok\LabirintusJáték.java

C:\...\Munkakönyvtár> java javattanitok.LabirintusJáték labirintus.txt

Page 210:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

182 Created by XMLmind XSL-FO Converter.

1.3. Java a böngészőkben: Applet objektumok - Labirintus Applet

A példát az Előzetes a példaprogramokból című pontban vezettük be.

1.3.1. A LabirintusApplet osztály

Ennek az osztálynak a lényegi működése az előző kettővel, funkcionális működése pedig az előző osztályéval

egyezik meg. A grafikus felület kezelését nagyban egyszerűsíti, hogy nem teljes képernyős módban dolgozunk.

Látszólag viszont bonyolítja, hogy az osztály letölthető appletként és különálló alkalmazásként is kész a futásra.

Ha a programot a böngésző tölti le, azaz appletként fog futni, akkor nem a main(), hanem az init() függvénye

végrehajtásával indul, azaz miután a böngésző példányosított a LabirintusApplet osztályból egy objektumot,

akkor annak init() módszere hívódik. Ez esetben tehát nem mi magunk példányosítottunk az appletből.

/*

* LabirintusApplet.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

import javattanitok.labirintus.*;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának egy

* appletbeli életre keltésére ad példát ez az osztály. Ennek megfelelően

* appletként a böngészőben, alkalmazásként külön ablakban történő

* megjelenítést biztosít.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.LabirintusVilág

* @see javattanitok.LabirintusJáték

* @see javattanitok.LabirintusMIDlet

* @see javattanitok.LabirintusServlet

Page 211:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

183 Created by XMLmind XSL-FO Converter.

* @see javattanitok.HálózatiLabirintus

* @see javattanitok.TávoliLabirintus

* @see javattanitok.KorbásLabirintus

* @see javattanitok.ElosztottLabirintus

*/

public class LabirintusApplet extends java.applet.Applet

implements java.awt.event.KeyListener {

/** A labirintus. */

Labirintus labirintus;

/** A hős. */

Hős hős;

/** A játék vége után már nem veszünk át inputot a játékostól,

* illetve a játék világának állapota sem változik. */

boolean játékVége = false;

/** A játék vége után megjelenő üzenet. */

String végeÜzenet = "Vége a játéknak!";

// Ha nam appletként indítjuk a programot, hanem alkalmazásként, akkor

// ez lesz az alkalmazás ablaka

java.awt.Frame ablak;

// A labirintus szereplőihez rendelt képek

java.awt.Image falKép;

java.awt.Image járatKép;

java.awt.Image hősKép;

java.awt.Image szörnyKép;

java.awt.Image kincsKép;

/**

* Az applet életciklusának indítása, csak akkor fut le, ha appletként

* indítotuk a programot.

*/

public void init() {

addKeyListener(this);

indul(true);

}

/**

* Akár appletként, akár alkalmazásként indítjuk a programot, itt

* végezzük el az inicializálás javát.

*/

public void indul(boolean appletként) {

ClassLoader classLoader = this.getClass().getClassLoader();

falKép = new javax.swing.ImageIcon

(classLoader.getResource("fal.png")).getImage();

járatKép = new javax.swing.ImageIcon

(classLoader.getResource("járat.png")).getImage();

hősKép = new javax.swing.ImageIcon

(classLoader.getResource("hős.png")).getImage();

szörnyKép = new javax.swing.ImageIcon

(classLoader.getResource("szörny.png")).getImage();

kincsKép = new javax.swing.ImageIcon

(classLoader.getResource("kincs.png")).getImage();

labirintus = new Labirintus(6, 3);

hős = new Hős(labirintus);

hős.sor(9);

hős.oszlop(0);

// ha nem appletként indítottuk a programot

if(!appletként) {

// akkor nyitunk neki egy ablakot

ablak = new java.awt.Frame("Labirintus applet alkalmazásként");

// amit be is lehet csukni

ablak.addWindowListener(new java.awt.event.WindowAdapter() {

public void windowClosing(java.awt.event.WindowEvent e) {

ablak.setVisible(false);

System.exit(0);

}

});

ablak.add(this);

ablak.addKeyListener(this);

Page 212:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

184 Created by XMLmind XSL-FO Converter.

ablak.setSize(1024, 768);

ablak.setVisible(true);

}

}

/**

* A játékostól (aki a játék világában a hős) jövő input feldolgozása:

* a hős mozgatása a KURZOR billenytűkkel, illetve a játék világának

* állapot változásait is innen irányítjuk.

*/

public void keyPressed(java.awt.event.KeyEvent billentyűEsemény) {

// Mit nyomott le?

int billentyű = billentyűEsemény.getKeyCode();

if(!játékVége) {

// Merre lép a hős?

switch(billentyű) {

// A KURZOR billentyűkkel foglalkozunk, a megfelelő irányba

// lépünk

case java.awt.event.KeyEvent.VK_UP:

hős.lépFöl();

break;

case java.awt.event.KeyEvent.VK_DOWN:

hős.lépLe();

break;

case java.awt.event.KeyEvent.VK_RIGHT:

hős.lépJobbra();

break;

case java.awt.event.KeyEvent.VK_LEFT:

hős.lépBalra();

break;

}

// A játék világának állapot változása: azaz a játék többi

// szereplője is lép. Ha ezzel a lépéssel a játék világában

// történt valami lényeges: pl. vége a játéknak vagy egy szörny

// elkapta a hőst, akkor reagálunk:

switch(labirintus.bolyong(hős)) {

case Labirintus.JÁTÉK_MEGY_HŐS_RENDBEN:

break;

case Labirintus.JÁTÉK_MEGY_MEGHALT_HŐS:

// Még van élete, visszatesszük a kezdő pozícióra

hős.sor(9);

hős.oszlop(0);

break;

case Labirintus.JÁTÉK_VÉGE_MINDEN_KINCS_MEGVAN:

végeÜzenet = "Győztél, vége a játéknak!";

játékVége = true;

break;

case Labirintus.JÁTÉK_VÉGE_MEGHALT_HŐS:

végeÜzenet = "Vesztettél, vége a játéknak!";

játékVége = true;

break;

}

// Amíg nincs vége a játéknak, újra rajzoljuk a

// játék felületét, hogy látszódjanak a játék állapotában

// bekövetkezett változások

repaint();

}

}

/**

* A KeyListener számunkra most érdektelen további metódusait üres

* testtel definiáljuk felül.

*/

public void keyTyped(java.awt.event.KeyEvent billentyűEsemény) {}

public void keyReleased(java.awt.event.KeyEvent billentyűEsemény) {}

/**

* Kajzolja a játék felületét, azaz a labirintust és a benne szereplőket:

* a hőst, a kincseket és a szörnyeket.

*/

Page 213:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

185 Created by XMLmind XSL-FO Converter.

public void paint(java.awt.Graphics g) {

// A labirintus kirajzolása

for(int i=0; i<labirintus.szélesség(); ++i) {

for(int j=0; j<labirintus.magasság(); ++j) {

if(labirintus.szerkezet()[j][i])

g.drawImage(falKép, i*falKép.getWidth(this),

j*falKép.getHeight(this), null);

else

g.drawImage(járatKép, i*járatKép.getWidth(this),

j*járatKép.getHeight(this), null);

}

}

// A kincsek kirajzolása

Kincs[] kincsek = labirintus.kincsek();

for(int i=0; i<kincsek.length; ++i) {

g.drawImage(kincsKép,

kincsek[i].oszlop()*kincsKép.getWidth(this),

kincsek[i].sor()*kincsKép.getHeight(this), null);

// Ha már megvan a kics, akkor áthúzzuk

if(kincsek[i].megtalálva()) {

g.setColor(java.awt.Color.red);

g.drawLine(kincsek[i].oszlop()*kincsKép.getWidth(this),

kincsek[i].sor()*kincsKép.getHeight(this),

kincsek[i].oszlop()*kincsKép.getWidth(this)

+ kincsKép.getWidth(this),

kincsek[i].sor()*kincsKép.getHeight(this)

+ kincsKép.getHeight(this));

g.drawLine(kincsek[i].oszlop()*kincsKép.getWidth(this)

+ kincsKép.getWidth(this),

kincsek[i].sor()*kincsKép.getHeight(this),

kincsek[i].oszlop()*kincsKép.getWidth(this),

kincsek[i].sor()*kincsKép.getHeight(this)

+ kincsKép.getHeight(this));

} else {

// ellenkező esetben kiírjuk az értékét

g.setColor(java.awt.Color.yellow);

g.drawString(""+kincsek[i].érték(),

kincsek[i].oszlop()*kincsKép.getWidth(this)

+ kincsKép.getWidth(this)/2,

kincsek[i].sor()*kincsKép.getHeight(this)

+ kincsKép.getHeight(this)/2);

}

}

// A szörnyek kirajzolása

Szörny[] szörnyek = labirintus.szörnyek();

for(int i=0; i<szörnyek.length; ++i)

g.drawImage(szörnyKép,

szörnyek[i].oszlop()*szörnyKép.getWidth(this),

szörnyek[i].sor()*szörnyKép.getHeight(this), null);

// A hős kirajzolása

g.drawImage(hősKép,

hős.oszlop()*hősKép.getWidth(this),

hős.sor()*hősKép.getHeight(this), null);

// A játék aktuális adataiból néhány kiíratása

g.setColor(java.awt.Color.black);

g.drawString("Életek száma: "+hős.életek(), 10, 40);

g.drawString("Gyűjtött érték: "+hős.pontszám(), 10, 60);

if(játékVége) {

g.setColor(java.awt.Color.black);

g.drawString(végeÜzenet, 420, 350);

}

}

Page 214:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

186 Created by XMLmind XSL-FO Converter.

/**

* A játék felületének kirajzolásakor ne legyen villogás, ezért

* az eredeti, a felület törlését elvégző update metódust felüldefiniáljuk.

*/

public void update(java.awt.Graphics g) {

paint(g);

}

/**

* A program alkalmazásként való indíthatóságát szolgálja.

*/

public static void main(String[] args) {

// Ha itt van a vezérlés, akkor nem igaz az, hogy appletként indítottuk

new LabirintusApplet().indul(false);

}

}

1.3.2. A labirintus applet fordítása, futtatása

A LabirintusApplet osztályt fordítása után

C:\...\Munkakönyvtár> javac javattanitok\LabirintusApplet.java

alkalmazásként is futtathatjuk:

C:\...\Munkakönyvtár> java javattanitok.LabirintusApplet

de izgalmasabb hozzá egy HTML dokumentumot készíteni, mondjuk a labirintus.html néven a

Munkakönyvtár nevű munkakönyvtárunkban az alábbi tartalommal.

<applet code="javattanitok/LabirintusApplet.class"

width="1024" height="768">

</applet>

Az appletet ezután az appletek tesztelésére használható, a JDK-beli appletviewer parancsot használva

tesztelhetjük:

C:\...\Munkakönyvtár> appletviewer labirintus.html

S a legizgalmasabb magában a böngészőben való kipróbálás, ehhez futtassuk a szintén a JDK részeként kapott

HtmlConverter.exe nevű programot a JDK bin könyvtárából, ahol a kinyíló Swinges ablakban a Specify a file

or a directory path: szövegmezőbe böngésszük be a C:\Documents and

Settings\norbi\Dokumentumok\Javat_tanitok\Munkakönyvtár munkakönyvtárunkat, majd végezzük el a

konvertálást, ami a labirintus.html állományunkat a következőre alakítja át:

<!--"CONVERTED_APPLET"-->

<!-- HTML CONVERTER -->

Page 215:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

187 Created by XMLmind XSL-FO Converter.

<object

classid = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"

codebase = "http://java.sun.com/update/1.6.0/jinstall-1_6-windows-

i586.cab#Version=6,0,0,86"

WIDTH = "1024" HEIGHT = "768" >

<PARAM NAME = CODE VALUE = "javattanitok/LabirintusApplet.class" >

<param name = "type" value = "application/x-java-applet;version=1.6">

<param name = "scriptable" value = "false">

<comment>

<embed

type = "application/x-java-applet;version=1.6" \

CODE = "javattanitok/LabirintusApplet.class" \

WIDTH = "1024" \

HEIGHT = "768"

scriptable = false

pluginspage = "http://java.sun.com/products/plugin/index.html#download">

<noembed>

</noembed>

</embed>

</comment>

</object>

<!--

<APPLET CODE = "javattanitok/LabirintusApplet.class" WIDTH = "1024" HEIGHT = "768">

</APPLET>

-->

<!--"END_CONVERTED_APPLET"-->

majd ezt a konvertálás után kapott állományt nyissuk ki a böngészőnkkel:

Page 216:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

188 Created by XMLmind XSL-FO Converter.

1.4. Java a mobiltelefonokban: MIDlet objektumok - Labirintus MIDlet

Az Előzetes a példaprogramokból című pontban bevezetett esettanulmány végleges kódját adjuk meg itt.

A példa fejlesztését a NetBeans IDE környezetben végezzük. A File/New Project... pont kiválasztása után a

kinyíló New Project ablakban első lépésként válaszuk a Mobile kategóriát, azon belül a Mobil Application

projektet. A Next gombra következő ablakban elég a projekt nevét megadni, ez legyen mondjuk a

JavatTanitokMobilLabirintus. Ugyanitt még deaktiváljuk (szüntessük meg a kipipálását) a Create Hello

MIDlet opciót. Majd a felkínált alapértelmezések elfogadása mellett nyomjunk újabb Next gombokat a Finish

gomb megjelenéséig, melynek nyomásával a projekt létrehozását befejeztük.

A default package csomagon egy jobb egérgombot nyomva válasszuk a New/Java Package... menüpontot! A

kinyíló ablakban adjuk meg a javattanitok csomag nevet. A jobb egérgomb újbóli nyomásával válasszuk a

New/MIDlet... menüpontot! A kinyíló ablakban adjuk meg a nevét - ez tetszőleges lehet. Viszont a MIDP Class

Name megadásánál nagyon gondosan járjunk el, egészen pontosan azt a nevet adjuk meg (kis-nagybetű

helyesen) amely osztály azt mondja magáról, hogy extends MIDlet, esetünkben ez az osztály a

LabirintusMIDlet osztály. Miután a Finish gombbal befejezzük a létrehozást, a projekt forráskönyvtárában,

esetünkben a C:\Documents and Settings\norbi\JavatTanitokMobilLabirintus\src\javattanitok

könyvtárban megjelenik a LabirintusMIDlet.java forrásállomány. Most annyit tegyünk még, hogy ezt az

állomány írjuk felül a kézikönyv alább bemutatott LabirintusMIDlet.java állományával és e mellé másoljuk

még be a kézikönyv, szintén a következőkben bemutatott LabirintusVaszon.java forrását. Továbbá másoljuk

ide a labirintus API-t, azaz a labirintus könyvtárat, ami tartalmazza a korábban ismertetett Szereplő.java,

Hős.java, Kincs.java, Szörny.java, Labirintus.java, RosszLabirintusKivétel.java állományokat.

Ha ezzel megvagyunk, akkor a NetBeans IDE projektek füle a következőket kell mutassa:

Page 217:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

189 Created by XMLmind XSL-FO Converter.

Sajnos itt a labirintus API ékezetes osztálynevei problémát okoznak a projekt fordítása után, így ezeket, azaz a

Szereplő.java, Hős.java, Szörny.java, RosszLabirintusKivétel.java állományokat átírjuk ékezet

nélküli nevekre. Mielőtt belekezdenénk ebbe a sziszifuszi munkába, van királyi út is: nyomjunk jobb

egérgombot ezeken a neveken a projektek fülben, majd a Refactor/Rename... menüpont választása után kinyíló

ablakban adjuk meg a megfelelő ékezet nélküli osztálynevet. A Next, majd a Do Refactoring gombokat

nyomva az átnevezés (és minden hivatkozás átnevezése) kész. Ha ezzel is megvagyunk, akkor a NetBeans IDE

projektek füle a következőket kell mutassa:

Page 218:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

190 Created by XMLmind XSL-FO Converter.

Már majdnem készen állunk a projekt fordítására és futtatására. Annyi van hátra, hogy a Labirintus osztály

tartalmaz olyan osztályokat, melyek csak a Java SE részei, így ezeket a jelen Java ME platformbeli munkánk

során módosítanunk kell! A legegyszerűbb eljárást választjuk, ezeket töröljük, egészen pontosan kommentbe

tesszük a Labirintus.java állományban az állományból építő konstruktort, mert ebben számos, csak a Java

SE-ben létező objektum, például a java.io.BufferedReader, java.util.StringTokenizer,

java.io.FileNotFoundException vagy a java.io.FileReader van.

public Labirintus(String labirintusFájlNév) throws RosszLabirintusKivetel {

Továbbá ugyancsak kommentezzük a java.io.PrintWriter nem Java ME osztály használatából bekövetkező,

hasonló problémát okozó

public void nyomtat(Hos hős, java.io.PrintWriter csatorna) {

függvényt.

Ezzel elkészültünk, jöhet a tesztelés, egyszerűen nyomjunk F6 funkcióbillentyűt, vagy a Run/Run Main Projekt

menüpontot!

Page 219:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

191 Created by XMLmind XSL-FO Converter.

A Launch-nek megfelelő telefon szoftbillentyűre kattintva elindul a mobil labirintus játékunk.

Page 220:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

192 Created by XMLmind XSL-FO Converter.

Még a játék képeit tartalmazó png állományokat kell megadnunk a projektnek, másoljuk be a hos.png,

kincs.png és a szorny.png állományokat például a C:\Documents and

Settings\norbi\JavatTanitokMobilLabirintus\res könyvtárba, majd a NetBeans IDE projektek fülében

a JavatTanitokMobilLabirintus néven egy jobb egérgombot nyomva a tulajdonságok Properties

menüpontot választva a kinyíló ablak Libraries & Resources pontját kérve, az Add Folder... gombbal a

C:\Documents and Settings\norbi\JavatTanitokMobilLabirintus\res könyvtárat hozzáadva immár,

ahogyan a következő kép is mutatja, a képeinket is elérjük.

1.4.1. A LabirintusMIDlet osztály

A LabirintusMIDlet osztályból a mobiltelefon példányosít, a konstruktor lefutása után meghívódik a

startApp() indító életciklus függvény. A MIDlet életciklussal a MIDlet feladat című pontban foglalkoztunk.

A LabirintusMIDlet osztály eseménykezelését pedig az Eseménykezelés című pontban tárgyaltuk.

/*

* LabirintusMIDlet.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának egy

* mobiltelefonos életre keltésére ad példát ez az osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.LabirintusVilág

* @see javattanitok.LabirintusApplet

* @see javattanitok.LabirintusJáték

Page 221:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

193 Created by XMLmind XSL-FO Converter.

* @see javattanitok.LabirintusServlet

* @see javattanitok.HálózatiLabirintus

* @see javattanitok.TávoliLabirintus

* @see javattanitok.KorbásLabirintus

* @see javattanitok.ElosztottLabirintus

* @see javattanitok.LabirintusVaszon

*/

public class LabirintusMIDlet extends javax.microedition.midlet.MIDlet

implements javax.microedition.lcdui.CommandListener {

/** A MIDlethez tartozó kijelző. */

private javax.microedition.lcdui.Display kijelző;

/** Parancs a kilépéshez. */

private javax.microedition.lcdui.Command kilépésParancs;

/** A labirintus életre keltése és megjelenítése. */

private LabirintusVaszon labirintusVászon;

/**

* A <code>LabirintusMIDlet</code> objektum elkészítése.

*/

public LabirintusMIDlet() {

// A MIDlethez tartozó kijelző elkérése

kijelző = javax.microedition.lcdui.Display.getDisplay(this);

// A labirintus elkészítése

labirintusVászon = new LabirintusVaszon();

// A kilépés parancs elkészítése

kilépésParancs = new javax.microedition.lcdui.Command("Kilép",

javax.microedition.lcdui.Command.EXIT, 1);

// és a labirintus vászonra helyezése

labirintusVászon.addCommand(kilépésParancs);

// az eseményeket (most kilépés parancs) itt dolgozzuk fel

labirintusVászon.setCommandListener(this);

}

/** A MIDletet indító életciklus metódus. */

public void startApp() {

// A kijelzőn a labirintus vászon legyen látható

kijelző.setCurrent(labirintusVászon);

}

/**

* A MIDletet felfüggesztő életciklus metódus, azaz mit tegyünk,

* ha egy bejövő hívás vagy SMS megzavarja a programunk futását?

* (Most semmit, mert csupán üres testes implementációját adtuk a

* függvénynek.)

*/

public void pauseApp() {

}

/**

* A MIDletet befejező életciklus metódus, azaz mit tegyünk,

* ha programunk befejezi futását? (Most semmit, mert csupán

* üres testes implementációját adtuk a függvénynek.)

*/

public void destroyApp(boolean unconditional) {

// Leállítjuk a labirintus játék szálát

if(labirintusVászon != null)

labirintusVászon.játékKilép();

}

/**

* A labirintus játék parancsainak (jelen esetben egy ilyen van,

* a kilépés) kezelése.

*

* @param command parancs, ami keletkezett

* @param displayable valamelyik képernyőn

*/

public void commandAction(javax.microedition.lcdui.Command parancs,

javax.microedition.lcdui.Displayable képernyő) {

if (képernyő == labirintusVászon) {

if (parancs == kilépésParancs) {

// Leállítjuk a labirintus játék szálát

labirintusVászon.játékKilép();

// Leállítjuk a programot

kijelző.setCurrent(null);

destroyApp(true);

notifyDestroyed();

Page 222:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

194 Created by XMLmind XSL-FO Converter.

}

}

}

}

1.4.2. A LabirintusVaszon osztály

Mobil környezetben a GUI felépítésére - ahogyan a Bepillantás a GUI programozásba című pontban említettük

- a javax.microedition.lcdui csomag szolgál. A MIDlet objektumunkhoz tartozó kijelzőt már az iménti

MIDlet osztályunk konstruktorában elkértük a csomag Display osztályának statikus getDisplay()

függvényével, majd a MIDlet indulásakor

/** A MIDletet indító életciklus metódus. */

public void startApp() {

// A kijelzőn a labirintus vászon legyen látható

kijelző.setCurrent(labirintusVászon);

}

egy azt a LabirintusVaszon osztálybeli vásznunkat tettünk a kijelzőre, aminek a következő teljes kódját

közöljük. Vásznunk egy javax.microedition.lcdui.game csomagbeli GameCanvas. Az ilyen játék-vásznak

egyik előnye, hogy könnyen teljes kijelzős módba kapcsolhatók, amikor is a kijelzőn a szoftbillentyűknek

fenntartott hellyel is a programozó rendelkezhet és főleg, hogy ezen a vásznon könnyű a szálkezelést

összeegyeztetni a játék állapotváltozásaival és a vászon kirajzolásával. Mert még a klasszikus vászon használata

esetén felül kell definiálnunk a vászon paint() módszerét és ezt a program vezérlő szálából ciklikusan implicit

hívogatnunk a repaint() függvény hívásával, addig itt mindent: az eseménykezelést, a játék állapotának

változását és az ennek a változásnak megfelelő kirajzolást is egy helyen végezhetjük, a kódunkban is jól látható

run() módszerünkben.

/*

* LabirintusVaszon.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

import javattanitok.labirintus.*;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának egy

* mobiltelefonos életre keltésére ad példát ez az osztály: elkészíti,

* vezérli és megjeleníti a labirintust.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.LabirintusMIDlet

*/

public class LabirintusVaszon extends javax.microedition.lcdui.game.GameCanvas

implements Runnable {

/** A vászon szélessége. */

private int szélesség;

/** A vászon magassága. */

private int magasság;

/** A labirintus. */

Labirintus labirintus;

/** A hős. */

Hos hős;

/** A játékbeli idő folyását biztosító szál. */

Page 223:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

195 Created by XMLmind XSL-FO Converter.

private Thread játékSzál;

/** A játékbeli idő mérésére.*/

private long idő = 0;

/** Jelzi a játék végét, ezután a játék álapota már nem változik. */

private boolean játékVége = false;

/** A játék végén a játékost tájékoztató üzenet. */

String végeÜzenet = "Vége a játéknak!";

/** Jelzi, hogy a program terminálhat. */

private boolean játékKilép = false;

/** A labirintus egy fal vagy járat cellájának szélessége. */

private int téglaSzélesség;

/** A labirintus egy fal vagy járat cellájának magassága. */

private int téglaMagasság;

/** A szereplőkhöz rendelt képek. */

javax.microedition.lcdui.Image hősKép, szörnyKép, kincsKép;

/**

* A <code>LabirintusVászon</code> objektum elkészítése.

*/

public LabirintusVaszon() {

super(false);

// A mobil kijelzője teljes képernyős módba

setFullScreenMode(true);

// Milyenek ekkor a méretek?

szélesség = getWidth();

magasság = getHeight();

// A labirintus elkészítése

labirintus = new Labirintus(6, 3);

hős = new Hos(labirintus);

hős.sor(9);

hős.oszlop(0);

// A labirintusnak a telefon kijelző méretéhez igazítása

téglaSzélesség = szélesség/labirintus.szélesség();

téglaMagasság = magasság/labirintus.magasság();

try {

// A szereplőkhöz rendelt képek betöltése

hősKép =

javax.microedition.lcdui.Image.createImage("/hos.png");

kincsKép =

javax.microedition.lcdui.Image.createImage("/kincs.png");

szörnyKép =

javax.microedition.lcdui.Image.createImage("/szorny.png");

} catch(Exception e) {

hősKép = null;

kincsKép = null;

szörnyKép = null;

}

// A játékbeli idő folyását biztosító szál elkészítése

játékSzál = new Thread(this);

// és indítása

játékSzál.start();

}

/** A játék időbeli fejlődésének vezérlése. */

public void run() {

javax.microedition.lcdui.Graphics g = getGraphics();

while(!játékKilép) {

if(!játékVége) { // Ha még nincs vége, akkor érdemben

// reagálunk a billentyűzet lenyomásokra

int billentyű = getKeyStates();

// A kurzor gomboknak megfelelő irányba lépéssel

if ((billentyű & LEFT_PRESSED) != 0) {

hős.lépBalra();

} else if ((billentyű & RIGHT_PRESSED) != 0) {

hős.lépJobbra();

} else if ((billentyű & UP_PRESSED) != 0) {

Page 224:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

196 Created by XMLmind XSL-FO Converter.

hős.lépFöl();

} else if ((billentyű & DOWN_PRESSED) != 0) {

hős.lépLe();

}

}

switch(labirintus.bolyong(hős)) {

case Labirintus.JÁTÉK_MEGY_HŐS_RENDBEN:

break;

case Labirintus.JÁTÉK_MEGY_MEGHALT_HŐS:

// Még van élete, visszatesszük a kezdő pozícióra

hős.sor(9);

hős.oszlop(0);

break;

case Labirintus.JÁTÉK_VÉGE_MINDEN_KINCS_MEGVAN:

végeÜzenet = "Győztél, vége a játéknak!";

játékVége = true;

break;

case Labirintus.JÁTÉK_VÉGE_MEGHALT_HŐS:

végeÜzenet = "Vesztettél, vége a játéknak!";

játékVége = true;

break;

}

// A kijelző törlése

g.setColor(0x00FFFFFF);

g.fillRect(0, 0, getWidth(), getHeight());

// A labirintus kirajzolása

g.setColor(0x00ed7703);

for(int i=0; i<labirintus.szélesség(); ++i)

for(int j=0; j<labirintus.magasság(); ++j)

if(labirintus.szerkezet()[j][i])

g.fillRect(i*téglaSzélesség, j*téglaMagasság,

téglaSzélesség, téglaMagasság);

// A kincsek kirajzolása

Kincs[] kincsek = labirintus.kincsek();

for(int i=0; i<kincsek.length; ++i) {

if(kincsKép != null) {

if(!kincsek[i].megtalálva())

g.drawImage(kincsKép,

kincsek[i].oszlop()*téglaSzélesség,

kincsek[i].sor()*téglaMagasság,

javax.microedition.lcdui.Graphics.LEFT

|javax.microedition.lcdui.Graphics.TOP);

} else {

// Ha már megvan a kics, akkor szürkébbel rajzoljuk

if(kincsek[i].megtalálva())

g.setColor(0x00d2cfb7);

else // Különben sárgábbal

g.setColor(0x00fbe101);

g.fillRect(kincsek[i].oszlop()*téglaSzélesség,

kincsek[i].sor()*téglaMagasság,

téglaSzélesség/2, téglaMagasság);

}

}

// A szörnyek kirajzolása

g.setColor(0x00ff0000);

Szorny[] szörnyek = labirintus.szörnyek();

for(int i=0; i<szörnyek.length; ++i)

if(szörnyKép != null)

g.drawImage(szörnyKép,

szörnyek[i].oszlop()*téglaSzélesség,

szörnyek[i].sor()*téglaMagasság,

javax.microedition.lcdui.Graphics.LEFT

|javax.microedition.lcdui.Graphics.TOP);

else

g.fillRect(szörnyek[i].oszlop()*téglaSzélesség

+ téglaSzélesség/2,

szörnyek[i].sor()*téglaMagasság,

Page 225:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

197 Created by XMLmind XSL-FO Converter.

téglaSzélesség/2, téglaMagasság);

// A hős kirajzolása

if(hősKép != null)

g.drawImage(hősKép,

hős.oszlop()*téglaSzélesség,

hős.sor()*téglaMagasság,

javax.microedition.lcdui.Graphics.LEFT

|javax.microedition.lcdui.Graphics.TOP);

else {

g.setColor(0x0000ff00);

g.drawRect(hős.oszlop()*téglaSzélesség,

hős.sor()*téglaMagasság,

téglaSzélesség, téglaMagasság);

}

// A játék aktuális adataiból néhány kiíratása

g.setColor(0x000000ff);

g.drawString("Életek száma: "+hős.életek(), 10, 15,

javax.microedition.lcdui.Graphics.LEFT

|javax.microedition.lcdui.Graphics.BOTTOM);

g.drawString("Gyűjtött érték: "+hős.pontszám(), 10, 30,

javax.microedition.lcdui.Graphics.LEFT

|javax.microedition.lcdui.Graphics.BOTTOM);

g.drawString("Idő: "+idő/5, 10, 45,

javax.microedition.lcdui.Graphics.LEFT

|javax.microedition.lcdui.Graphics.BOTTOM);

if(játékVége)

g.drawString(végeÜzenet, 10, magasság-20,

javax.microedition.lcdui.Graphics.LEFT

|javax.microedition.lcdui.Graphics.BOTTOM);

flushGraphics();

idoegyseg();

}

}

/** A játék szál leállítása. */

public void játékKilép() {

játékKilép = true;

játékSzál = null;

}

/** Megadja, hogy milyen gyorsan telik az idő a játékban. */

private void idoegyseg() {

++ idő;

try {

Thread.sleep(200);

} catch(InterruptedException e) {}

}

}

A [PROGRAMOZÓ PÁTERNOSZTER JEGYZET] jegyzetben számos további mobil programozási példát talál

az érdeklődő Olvasó. Jelen vászon osztályunk triviális továbbfejlesztési lehetősége, hogy a szereplőket nem

képpel, hanem a javax.microedition.lcdui.game csomagbeli Sprite objektumokkal reprezentálnánk.

Ebben a feladatban is segít az imént hivatkozott jegyzet.

1.5. Java a webszerverekben: Servlet objektumok - Labirintus Servlet

Az Előzetes a példaprogramokból című pontban bevezetett esettanulmány végleges kódját adjuk meg itt.

Ennek a példának a fejlesztését is a NetBeans IDE fejlesztői környezetben végezzük. A File/New Project... pont

kiválasztása után a kinyíló New Project ablakban első lépésként válasszuk a Web kategóriát, azon belül a Web

Application projektet. A Next gombra következő ablakban elég a projekt nevét megadni, ez legyen mondjuk a

Page 226:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

198 Created by XMLmind XSL-FO Converter.

JavatTanitokWebes. Majd a felkínált alapértelmezések elfogadása mellett nyomjunk újabb Next gombokat a

Finish gomb megjelenéséig, melynek nyomásával a projekt létrehozását befejeztük.

Az előző esettanulmányok felélesztéséhez hasonlóan a Source Packages/default package csomagon egy jobb

egérgombot nyomva válasszuk a New/Java Package... menüpontot! A kinyíló ablakban adjuk meg a

javattanitok csomag nevet. Miután a Finish gombbal befejezzük a csomag létrehozását, a projekt

forráskönyvtárában, esetünkben a C:\Documents and Settings\norbi\JavatTanitokWebes\src\java

könyvtárban megjelenik a javattanitok alkönyvtár. Másoljuk ebbe a frissen létrejött könyvtárba a kézikönyv

LabirintusServlet.java forrását. A labirintus API-t most nem másoljuk ide, hanem csak megmondjuk a

NetBeans IDE környezetnek, hogy hol találja a használni kívánt labirintus API-t, azaz a

javattanitok.labirintus csomagot. Például a korábban elkészített javattanitokPeldak.jar Java

archívum állományban. Ehhez a NetBeans IDE projektek fülében a JavatTanitokWebes projekt néven egy

jobb egérgombot nyomva a tulajdonságok Properties menüpontot választva a kinyíló ablak Libraries pontját

kérve, az Add JAR/Folder... gombbal a C:\Documents and

Settings\norbi\JavatTanitokPeldak\dist\JavatTanitokPeldak.jar jar állományt hozzáadva a projekt

fordítása már menni fog.

Page 227:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

199 Created by XMLmind XSL-FO Converter.

A projekt futtatásához azonban még a projekt webalkalmazásként való létét is konfigurálnunk kell. Ehhez a

NetBeans IDE projektek fülében a JavatTanitokWebes projekt Configuration Files pontját lenyitva a

web.xml állomány kell kinyitnunk. Itt a Servlet fülre kattintva az alábbi beállításokat végezzük el:

Itt az Add Servlet Element gomb nyomása után a Servlet Class böngészéssel való megadása és a URL

Pattern(s) tetszőleges magadása fontos. A jelen beállítással a javattanitok.LabirintusServlet osztályt a

weben, azaz egy böngészőprogramon keresztül majd a

http://localhost:8084/JavatTanitokWebes/labirintus URL címen érjük el.

Ha ezzel megvagyunk, jöhet a tesztelés, egyszerűen nyomjunk F6 funkcióbillentyűt, vagy a Run/Run Main

Projekt menüpontot! Majd az internetes böngészőnkben keressük fel a

http://localhost:8084/JavatTanitokWebes/labirintus URL címet.

Page 228:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

200 Created by XMLmind XSL-FO Converter.

A megfelelő linkek választásával a böngészőben akár győzhetünk is!

Page 229:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

201 Created by XMLmind XSL-FO Converter.

1.5.1. A LabirintusServlet osztály

Ha szervletünket a HTTP protokoll GET kérésével felkeressük, akkor a HttpServlet osztály doGet metódusa

fog meghívódni. A hívásban az aktuális paraméterként kapott HttpServletRequest és HttpServletResponse

Page 230:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

202 Created by XMLmind XSL-FO Converter.

objektumok reprezentálják a HTTP kérést és választ szervletünk mikrovilágában. A válasz objektumtól elkért

csatorna érdekessége, hogy a másik vége a szervletünket felkereső böngészőben van. Ennek megfelelően a

csatornát karakteresre nyitjuk és szöveget, HTML szöveget nyomunk ki rá. A példa további érdekessége, hogy

arra is példát mutat, hogyan tudunk a szerver oldalon információt megőrizni az egyébként független - de egy

játékostól jövő - HTTP kérések között.

/*

* LabirintusServlet.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

import javattanitok.labirintus.*;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának egy

* HTTP szervletes életre keltésére ad példát ez az osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.LabirintusVilág

* @see javattanitok.LabirintusApplet

* @see javattanitok.LabirintusJáték

* @see javattanitok.LabirintusMIDlet

* @see javattanitok.HálózatiLabirintus

* @see javattanitok.TávoliLabirintus

* @see javattanitok.KorbásLabirintus

*/

public class LabirintusServlet extends javax.servlet.http.HttpServlet {

/**

* A HTTP GET kérés kiszolgálása.

*

* @param httpKérés a HTTP kérést reprezentáló objektum

* @param httpVálasz a HTTP választ reprezentáló objektum

*/

protected void doGet(javax.servlet.http.HttpServletRequest httpKérés,

javax.servlet.http.HttpServletResponse httpVálasz)

throws javax.servlet.ServletException, java.io.IOException {

// A válasz csatornán küldött adatokat a böngésző

// mint html oldalt értelmezze

httpVálasz.setContentType("text/html;charset=UTF-8");

// Elkérjük a böngészőbe menő csatornát

java.io.PrintWriter csatornaBöngészőbe = httpVálasz.getWriter();

// Elkezdjük beleírni válaszunkat html-ben

csatornaBöngészőbe.println("<html>");

csatornaBöngészőbe.println("<head>");

// A böngészőablek címe

csatornaBöngészőbe.println("<title>Javat tanítok LabirintusServlet</title>");

csatornaBöngészőbe.println("</head>");

csatornaBöngészőbe.println("<body>");

// Ez a böngésző kapcsolatban van már a szerverünkkel?

javax.servlet.http.HttpSession session = httpKérés.getSession();

// A hőst és a labirintust majd ebben a kapcsolatot

// reprezentáló objektumban tároljuk.

Labirintus labirintus = null;

Hős hős = null;

// Ha a kapcsolat most épült fel

if(session.isNew()) {

// akkor elkészítünk egy új labirintust és hőst

csatornaBöngészőbe.println("Helló, új játékot kezdünk!<br>");

labirintus = new Labirintus(6, 3);

hős = new Hős(labirintus);

hős.sor(9);

hős.oszlop(0);

// majd betesszük a kapcsolatot reprezentáló objektumba, hogy a

// legközelebbi kérésével jövő ugyanazon játékos ki tudja venni

session.setAttribute("labirintus", labirintus);

Page 231:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

203 Created by XMLmind XSL-FO Converter.

session.setAttribute("hos", hős);

// Különben, azaz, ha már volt kapcslat

} else {

// akkor kivesszük a kapcsolatot reprezentáló objektumból

csatornaBöngészőbe.println("Helló, régi játékot folytatjuk<br>");

labirintus = (Labirintus)session.getAttribute("labirintus");

hős = (Hős)session.getAttribute("hos");

if(hős == null || labirintus == null) {

// Ha esetleg a tesztelés során gond lenne a session kezeléssel...

log("Új labirintust készítettünk...");

labirintus = new Labirintus(6, 3);

hős = new Hős(labirintus);

hős.sor(9);

hős.oszlop(0);

session.setAttribute("labirintus", labirintus);

session.setAttribute("hos", hős);

}

}

// A válasz lapra kiírjuk a hős lépésénél a választási lehetőségeket

// a ?lepes= megfelelő irány formában

csatornaBöngészőbe.println("<br>Merre lépjen a hős?<br>");

csatornaBöngészőbe.println("<a href=\"/JavatTanitokWebes/" +

"labirintus?lepes=fol\">Föl</a>");

csatornaBöngészőbe.println("<br>");

csatornaBöngészőbe.println("<a href=\"/JavatTanitokWebes/" +

"labirintus?lepes=le\">Le</a>");

csatornaBöngészőbe.println("<br>");

csatornaBöngészőbe.println("<a href=\"/JavatTanitokWebes/" +

"labirintus?lepes=jobbra\">Jobbra</a>");

csatornaBöngészőbe.println("<br>");

csatornaBöngészőbe.println("<a href=\"/JavatTanitokWebes/" +

"labirintus?lepes=balra\">Balra</a>");

// A mostani kérésben jött valami infó a lépéssel kapcsolatban?

String lepesString = httpKérés.getParameter("lepes");

// Ha igen, akkor annak megfelelően lépünk

if("fol".equals(lepesString))

hős.lépFöl();

else if("le".equals(lepesString))

hős.lépLe();

else if("jobbra".equals(lepesString))

hős.lépJobbra();

else if("balra".equals(lepesString))

hős.lépBalra();

// Történt ezzel a lépéssel valami érdekes a labirintusban?

switch(labirintus.bolyong(hős)) {

case Labirintus.JÁTÉK_MEGY_HŐS_RENDBEN:

break;

case Labirintus.JÁTÉK_MEGY_MEGHALT_HŐS:

// Még van élete, visszatesszük a kezdő pozícióra

hős.sor(9);

hős.oszlop(0);

break;

case Labirintus.JÁTÉK_VÉGE_MINDEN_KINCS_MEGVAN:

csatornaBöngészőbe.println("<h1>GYŐZTÉL</h1>");

session.invalidate();

break;

case Labirintus.JÁTÉK_VÉGE_MEGHALT_HŐS:

session.invalidate();

csatornaBöngészőbe.println("<h1>VESZTETTÉL</h1>");

break;

}

// Kinyomtatjuk a labirintus aktuális állapotát

csatornaBöngészőbe.println("<pre>");

csatornaBöngészőbe.println(labirintus.kinyomtat(hős));

csatornaBöngészőbe.println("</pre>");

Page 232:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

204 Created by XMLmind XSL-FO Converter.

// és néhány infót a játék aktuális adataiból

csatornaBöngészőbe.println("<br>");

csatornaBöngészőbe.println("<br>Életek száma: " + hős.életek());

csatornaBöngészőbe.println("<br>Gyűjtött érték: "+hős.pontszám());

csatornaBöngészőbe.println("</body>");

csatornaBöngészőbe.println("</html>");

// Zárjuk a böngészőbe irányuló csatornát.

csatornaBöngészőbe.close();

}

}

1.6. Java a hálózaton

A következő példák a socket programozás absztrakciós szintjéről indulva egyre magasabb szinteken üzemelnek.

1.6.1. TCP/IP - Hálózati Labirintus

Az Előzetes a példaprogramokból című pontban bevezetett esettanulmány végleges kódját adjuk meg itt.

A példa kipróbálásához szükségünk van a A labirintus API felélesztése című pontban beállított labirintus API-ra,

sőt, ezt ebben a pontban tovább is kell fejlesztenünk. A javattanitok.labirintus csomagbeli Labirintus

osztályt kiterjesztjük a TöbbHősösLabirintus osztállyal, amelyben egy hős halála immár nem jelenti a

labirintus játék végét is egyben.

A HálózatiLabirintus.java és a LabirintusKiszolgálóSzál.java forrásokat másoljuk a

Munkakönyvtár nevű munkakönyvtárunkból nyíló javattanitok könyvtárba, mert ezek az osztályok a

javattanitok csomag részei. A TöbbHősösLabirintus osztályt a javattanitok.labirintus csomag

részeként fejlesztettük ki, ezért a TöbbHősösLabirintus.java állományt a javattanitok/labirintus

könyvtárba másoljuk be.

1.6.1.1. A HálózatiLabirintus osztály

Az osztály elindítja a szerver programot és a játék a LABIRINTUS_PORT kapunál várakozik a kliensekre.

Mindeközben a szokásos párhuzamosan indított programszálon vezérli a labirintus mikrovilágának életét.

Fontos továbbfejlesztés, hogy ugyanabban a - Labirintus osztály továbbfejlesztéseként megírt

TöbbHősösLabirintus osztálybeli - labirintusunkban több hősünk lehet, akiket egy Hashtable

adatszerkezetben foglal csokorba a szerver.

public class HálózatiLabirintus implements Runnable {

/** A játék aktuális labirintusa, minden hálózati hős ebben mozog. */

TöbbHősösLabirintus labirintus;

/** A hősök. */

java.util.Hashtable hősök;

/** Melyik porton megy a játék. */

private static final int LABIRINTUS_PORT = 2006;

A hősök adminisztrációját a HálózatiLabirintus osztály hős() módszere intézi, ami a szerver és a kliensei

közötti kommunikációt lebonyolító LabirintusKiszolgálóSzál a szerver végrehajtási szálával párhuzamosan

futó run() metódusából hívódik.

/*

* HálózatiLabirintus.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

Page 233:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

205 Created by XMLmind XSL-FO Converter.

import javattanitok.labirintus.*;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának egy

* TCP/IP-s hálózati életre keltésére ad példát ez az osztály.

* Tesztelése például a telnet TCP klienssel:

* <pre>

* telnet niobe 2006

* A hős neve?

* Matyi

* Parancsok: l = le, f = föl, j = jobbra, b = balra k = kilép

* sima ENTER = megmutatja a labirintust

*

* --- Labirintusszerinti idő: 13. pillanat -------

* --- Összes hősök száma: 1

* --- Életek száma: 5

* --- Gyűjtött érték: 0

* --- A labirintus: (13. pillanat) -------

* | | | |FAL| |FAL| |FAL|FAL|FAL

* | | | | |K | | | | |

* |FAL| |FAL| |FAL| |FAL| |FAL|

* | | | |K |FAL| |FAL| | |S

* | |FAL|FAL|S | | |FAL|FAL| |FAL

* | | | | |FAL|K | | | |

* | |FAL| | | |FAL|K |FAL|FAL|

* | | |K |FAL| |FAL|S |FAL| |

* | |FAL| | | | | | | |FAL

* |H | | | |FAL| | | |FAL|FAL

* </pre>

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.LabirintusVilág

* @see javattanitok.LabirintusApplet

* @see javattanitok.LabirintusJáték

* @see javattanitok.LabirintusMIDlet

* @see javattanitok.LabirintusServlet

* @see javattanitok.TávoliLabirintus

* @see javattanitok.KorbásLabirintus

* @see javattanitok.ElosztottLabirintus

* @see LabirintusKiszolgálóSzál

*/

public class HálózatiLabirintus implements Runnable {

/** A játék aktuális labirintusa, minden hálózati hős ebben mozog. */

TöbbHősösLabirintus labirintus;

/** A hősök. */

java.util.Hashtable hősök;

/** Melyik porton megy a játék. */

private static final int LABIRINTUS_PORT = 2006;

/** A játékbeli idő mérésére.*/

private long idő = 0;

/** Jelzi a játék végét, ezután a játék álapota már nem változik. */

private boolean játékVége = false;

/**

* Argumentum nélküli konstruktor, gyerekek implicit super()-éhez.

*/

public HálózatiLabirintus(){}

/**

* A <code>HálózatiLabirintus</code> objektum elkészítése.

*

* @param labirintusFájlNév a labirintust definiáló, megfelelő

* szerkezetű szöveges állomány neve.

* @exception RosszLabirintusKivétel ha a labirintust definiáló állomány

* nem a megfelelő szerkezetű

*/

public HálózatiLabirintus(String labirintusFájlNév) throws

RosszLabirintusKivétel {

// A labirintus elkészítése állományból

labirintus = new TöbbHősösLabirintus(labirintusFájlNév);

// A hős elkészítése és a kezdő pozíciójának beállítása

hősök = new java.util.Hashtable();

// A játékbeli idő folyását biztosító szál elkészítése és indítása

Page 234:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

206 Created by XMLmind XSL-FO Converter.

new Thread(this).start();

// A TCP szerver indítása

try {

java.net.ServerSocket serverSocket =

new java.net.ServerSocket(LABIRINTUS_PORT);

while(true) {

// Várakozás a játékosok jelentkezésére

java.net.Socket socket = serverSocket.accept();

// akiket külön szálban szolgálunk ki

new LabirintusKiszolgálóSzál(socket, this);

}

} catch(java.io.IOException e) {

e.printStackTrace();

}

}

/**

* A hálózaton keresztül jelentkező hős elkészítése.

*

* @param név a hős neve (= "hoszt IP : név").

* @return Hős a névhez tartozó, esetleg újonan létrehozott hős.

*/

public Hős hős(String név) {

// Ha már létező hős jelentkezett be újra a játékba

if(hősök.containsKey(név))

return (Hős)hősök.get(név);

// Vagy új játékos jön

else {

// aki még nincs a hősök között

// akkor új hősként létrehozzuk

Hős hős = new Hős(labirintus);

// A hős kezdő pozíciója

hős.sor(9);

hős.oszlop(0);

// Felvétele a hősök közé

hősök.put(név, hős);

return hős;

}

}

/**

* A valamikor hálózaton keresztül jelentkező hős törlése.

*

* @param név a hős neve (= "hoszt IP : név").

*/

public void hősMeghalt(String név) {

// Törlés a hősök közül

hősök.remove(név);

}

/**

* A hősök száma.

*

* @return int a hősök száma.

*/

public int hősökSzáma() {

return hősök.size();

}

/**

* A labirintus játék világának ideje.

*

* @return long labirintus játék világának ideje.

*/

public long idő() {

return idő;

}

/**

* A játék aktuális labirintusa, minden hálózati hős ebben mozog.

*

Page 235:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

207 Created by XMLmind XSL-FO Converter.

* @return Labirintus a labirintus.

*/

public Labirintus labirintus() {

return labirintus;

}

/** A játék időbeli fejlődésének vezérlése. */

public void run() {

while(!játékVége) {

idoegyseg();

System.out.println("Hősök száma: " + hősök.size());

java.util.Enumeration e = hősök.elements();

while(e.hasMoreElements()) {

Hős hős = (Hős)e.nextElement();

switch(labirintus.bolyong(hős)) {

case TöbbHősösLabirintus.JÁTÉK_MEGY_HŐS_RENDBEN:

break;

case Labirintus.JÁTÉK_MEGY_MEGHALT_HŐS:

hős.sor(9);

hős.oszlop(0);

System.out.println("Megettek a(z) " + idő

+ ". lépésben!");

break;

case Labirintus.JÁTÉK_VÉGE_MINDEN_KINCS_MEGVAN:

System.out.println("Megvan minden kincs a(z) "

+ idő + ". lépésben!");

játékVége = true;

break;

case Labirintus.JÁTÉK_VÉGE_MEGHALT_HŐS:

System.out.println("Minden életem elfogyott a(z) "

+ idő + ". lépésben!");

// Ebben a változatban több hős bolyong,

// így immár egyikük halála nem jelenti a

// játék végét is:

// játékVége = true;

break;

}

}

}

}

/** Megadja, hogy milyen gyorsan telik az idő a játékban. */

private void idoegyseg() {

++idő;

try {

Thread.sleep(1000);

} catch(InterruptedException e) {}

}

/**

* Átveszi a játék indításához szükséges paramétereket, majd

* elindítja a játék világának működését.

*

* @param args a labirintus tervét tartalmazó állomány neve az első

* parancssor-argumentum.

*/

public static void main(String[] args) {

if(args.length != 1) {

System.out.println("Indítás: " +

"java javattanitok.HálózatiLabirintus labirintus.txt");

System.exit(-1);

}

try {

Page 236:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

208 Created by XMLmind XSL-FO Converter.

new HálózatiLabirintus(args[0]);

} catch(RosszLabirintusKivétel rosszLabirintusKivétel) {

System.out.println(rosszLabirintusKivétel);

}

}

}

A HálózaiLabirintus szerver accept() függvényében megjelenő kliensekkel a következő osztály

foglalkozik.

1.6.1.2. A LabirintusKiszolgálóSzál osztály

Ez az osztály kommunikál a bejelentkező TCP-s kliensekkel.

/*

* LabirintusKiszolgálóSzál.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

import javattanitok.labirintus.*;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának

* TCP/IP-s hálózati életre keltését bemutató

* <code>javattanitok.HálózatiLabirintus</code> osztály hálózati

* kiszolgálását végző szál. A kommunikációs socket kapcsolattól

* elkéri a kimeneti és bemeneti csatornát, majd a játékos inputját

* átvéve végtehajtja a hős mozgatását.

*

* Egy pillanatfelvétel a kiszolgálásról:

* <pre>

* telnet niobe 2006

* A hős neve?

* Matyi

* Parancsok: l = le, f = föl, j = jobbra, b = balra k = kilép

* sima ENTER = megmutatja a labirintust

*

* --- Labirintusszerinti idő: 13. pillanat -------

* --- Összes hősök száma: 1

* --- Életek száma: 5

* --- Gyűjtött érték: 0

* --- A labirintus: (13. pillanat) -------

* | | | |FAL| |FAL| |FAL|FAL|FAL

* | | | | |K | | | | |

* |FAL| |FAL| |FAL| |FAL| |FAL|

* | | | |K |FAL| |FAL| | |S

* | |FAL|FAL|S | | |FAL|FAL| |FAL

* | | | | |FAL|K | | | |

* | |FAL| | | |FAL|K |FAL|FAL|

* | | |K |FAL| |FAL|S |FAL| |

* | |FAL| | | | | | | |FAL

* |H | | | |FAL| | | |FAL|FAL

* </pre>

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.HálózatiLabirintus

*/

public class LabirintusKiszolgálóSzál implements Runnable {

/** TCP-s kommunikációs kapcsolat a játékossal. */

Page 237:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

209 Created by XMLmind XSL-FO Converter.

java.net.Socket socket;

HálózatiLabirintus hálózatiLabirintus;

/**

* A <code>LabirintusKiszolgálóSzál</code> objektum elkészítése.

*

* @param socket TCP socket kapcsolat a játékossal.

* @param hálózatiLabirintus A labirintust tartalmazó TCP szerver

* <code>javattanitok.HálózatiLabirintus</code> osztály

*/

public LabirintusKiszolgálóSzál(java.net.Socket socket,

HálózatiLabirintus hálózatiLabirintus) {

this.socket = socket;

this.hálózatiLabirintus = hálózatiLabirintus;

new Thread(this).start();

}

/** A jelentkező játékosokat párhuzamosan kiszolgáló szál. */

public void run() {

try {

// A socket kapcsolat feletti bejövő csatorna elkérése

java.io.BufferedReader bejövőCsatorna =

new java.io.BufferedReader(

new java.io.InputStreamReader(socket.

getInputStream()));

// A socket kapcsolat feletti kimenő csatorna elkérése

java.io.PrintWriter kimenőCsatorna =

new java.io.PrintWriter(socket.getOutputStream());

// A hős nevének beolvasása

kimenőCsatorna.println("A hős neve?");

kimenőCsatorna.flush();

String játékostól = bejövőCsatorna.readLine();

// Vagy új vagy régi a hős, a hős neve = "hoszt IP : név"

String hősNév = socket.getInetAddress().getHostAddress() +

" : " + játékostól;

Hős hős = hálózatiLabirintus.hős(hősNév);

// Informáljuk a játékost a játék használatáról

kimenőCsatorna.println("Parancsok: l = le, f = föl, " +

"j = jobbra, b = balra k = kilép");

kimenőCsatorna.println(" sima ENTER = " +

"megmutatja a labirintust");

kimenőCsatorna.flush();

játékostól = bejövőCsatorna.readLine();

while(játékostól != null) {

// A játékostól érkező parancsok feldolgozása

if("l".equals(játékostól))

hős.lépLe();

else if("f".equals(játékostól))

hős.lépFöl();

else if("j".equals(játékostól))

hős.lépJobbra();

else if("b".equals(játékostól))

hős.lépBalra();

else if("k".equals(játékostól))

break;

kimenőCsatorna.println("--- Labirintusszerinti idő: "

+ hálózatiLabirintus.idő() + ". pillanat -------");

kimenőCsatorna.println("--- Összes hősök száma: "

+ hálózatiLabirintus.hősökSzáma());

kimenőCsatorna.println("--- Életek száma: " + hős.életek());

kimenőCsatorna.println("--- Gyűjtött érték: " + hős.pontszám());

kimenőCsatorna.println("--- A labirintus: ("

+ hálózatiLabirintus.idő()+". pillanat) -------");

// Megmutatjuk a labirintus aktuális állapotát

hálózatiLabirintus.labirintus().nyomtat(hős, kimenőCsatorna);

kimenőCsatorna.flush();

if(hős.életek() <= 0) {

hálózatiLabirintus.hősMeghalt(hősNév);

break;

}

játékostól = bejövőCsatorna.readLine();

Page 238:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

210 Created by XMLmind XSL-FO Converter.

}

socket.close();

} catch(java.io.IOException e) {

e.printStackTrace();

} finally {

if(socket != null) {

try{

socket.close();

} catch(Exception e) {}

}

}

}

}

1.6.1.3. A TöbbHősösLabirintus osztály

Ebben az osztályban felüldefiniáljuk az ős Labirintus osztály vezérlő bolyong() módszerét, itt egy hős halála

már nincs hatással a játék állapotára.

/*

* TöbbHősösLabirintus.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.labirintus;

/**

* A több hősös labirintust leíró osztály, ahol egy hős halála

* már nem jelenti a labirintus játék végét. A játék állapotát

* a korábbi játékokban a labirintushoz kapcsoltuk, most, hogy

* olyan továbbfejlesztett labirintust akarunk, amiben több hős

* is bolyonghat, úgy érezzük, hogy a játék vége inkább a hőshöz

* tartozik, semmint a labirintushoz. Mindkettő igaz: mert, ha a

* kincsek fogynak el, akkor a labirintus oldaláról van vége a

* játéknak.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

public class TöbbHősösLabirintus extends Labirintus {

/**

* Argumentum nélküli konstruktor, gyerekek implicit super()-éhez.

*/

public TöbbHősösLabirintus() {}

/**

* A <code>TöbbHősösLabirintus</code> objektum elkészítése.

*

* @param labirintusFájlNév a labirintust definiáló, megfelelő

* szerkezetű szöveges állomány neve.

* @exception RosszLabirintusKivétel ha a labirintust definiáló állomány nem

* a megfelelő szerkezetű

*/

public TöbbHősösLabirintus(String labirintusFájlNév) throws

RosszLabirintusKivétel {

super(labirintusFájlNév);

}

/**

Page 239:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

211 Created by XMLmind XSL-FO Converter.

* Az ős megfelelő metódusának elfedése, mert ez a JÁTÉK_VÉGE_MEGHALT_HŐS

* csak a hős végét jelenti, a labirintusét nem!

*

* @see Labirintus#bolyong(Hős hős)

* @param hős aki a labirintusban bolyong.

* @return int a játék állapotát leíró kód.

*/

public int bolyong(Hős hős) {

boolean mindMegvan = true;

for(int i=0; i < kincsek.length; ++i) {

// A hős rátalált valamelyik kincsre?

if(kincsek[i].megtalált(hős))

hős.megtaláltam(kincsek[i]);

// ha ez egyszer is teljesül, akkor nincs minden kincs megtalálva

if(!kincsek[i].megtalálva())

mindMegvan = false;

}

if(mindMegvan) {

játékÁllapot = JÁTÉK_VÉGE_MINDEN_KINCS_MEGVAN;

return játékÁllapot;

}

for(int i=0; i < szörnyek.length; ++i) {

szörnyek[i].lép(hős);

if(szörnyek[i].megesz(hős)) {

if(hős.megettek())

// De ez a játék vége csak a hős végét

// jelenti, a labirintusét nem!

return JÁTÉK_VÉGE_MEGHALT_HŐS;

else

return JÁTÉK_MEGY_MEGHALT_HŐS;

}

}

return JÁTÉK_MEGY_HŐS_RENDBEN;

}

}

1.6.1.4. A HálózatiLabirintus fordítása, futtatása

A szerver oldalon fordítunk és futtatjuk a programot.

[norbi@niobe Munkakönyvtár]$ javac javattanitok/HálózatiLabirintus.java

Note: javattanitok/HálózatiLabirintus.java uses unchecked or unsafe operations.

Note: Recompile with -Xlint:unchecked for details.

[norbi@niobe Munkakönyvtár]$ java javattanitok.HálózatiLabirintus labirintus.txt

Hősök száma: 0

Hősök száma: 0

Hősök száma: 0

...

Page 240:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

212 Created by XMLmind XSL-FO Converter.

A szerver futtattása után egy másik ablakban (vagy akár egy másik gépen) futtassuk a klienst, ami most

egyszerűen a telnet program. A telnet parancs után a szerver programot futtató hoszt nevét írjuk, ha ez ugyanaz

a gép, mint amelyiken a klienst is éppen futtatni akarjuk, akkor - akár Windows, akár Linux alatt - a localhost

nevet írhatjuk. A második megadott parancssor-argumentum annak a TCP kapunak a sorszáma, amin a szerver

figyeli a kliensek kapcsolatfelvételi kérelmeit, most a 2006.

[norbi@niobe ~]$ telnet localhost 2006

Trying 127.0.0.1...

Connected to localhost.localdomain (127.0.0.1).

Escape character is '^]'.

A hős neve?

Matyi

Parancsok: l = le, f = föl, j = jobbra, b = balra k = kilép

sima ENTER = megmutatja a labirintust

--- Labirintusszerinti idő: 36. pillanat -------

--- Összes hősök száma: 1

--- Életek száma: 5

--- Gyűjtött érték: 0

--- A labirintus: (36. pillanat) -------

| | |K |FAL| |FAL| |FAL|FAL|FAL

| | | | | |K |K | | |K

|FAL| |FAL| |FAL| |FAL| |FAL|

| | | | |FAL| |FAL| | |

| |FAL|FAL|SK | | |FAL|FAL| |FAL

| | | | |FAL|K | | |S |

| |FAL| | | |FAL|S |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

|H | | | |FAL| | | |FAL|FAL

A szerver oldalon a kliens belépésének megfelelően látjuk, hogy nőtt a hősök száma.

...

Hősök száma: 1

Hősök száma: 1

Hősök száma: 1

...

A játékos a fenti ENTER alkalmazása után most az f felfelé léptető parancsot adja ki:

f

--- Labirintusszerinti idő: 415. pillanat -------

--- Összes hősök száma: 2

--- Életek száma: 5

--- Gyűjtött érték: 0

--- A labirintus: (415. pillanat) -------

| | |K |FAL| |FAL| |FAL|FAL|FAL

| | | | | |K |K | | |K

|FAL| |FAL| |FAL| |FAL| |FAL|

| | | | |FAL| |FAL| | |

| |FAL|FAL|SK | | |FAL|FAL| |FAL

| | | | |FAL|K | | |S |

| |FAL| | | |FAL|S |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

|H |FAL| | | | | | | |FAL

| | | | |FAL| | | |FAL|FAL

Page 241:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

213 Created by XMLmind XSL-FO Converter.

Majd a k billentyűvel lépjünk ki a jelen Matyi nevű hősös kliensünkből. Ha újra jelentkezünk egy klienssel

ugyanerről a gépről és a Matyi hősnevet adjuk meg, akkor a szerver emlékezni fog a hős aktuális pozíciójára.

Léptessünk be további hősöket, megint csak egy másik ablakban, vagy akár egy másik gépen! Figyeljük meg,

hogy a szerver tovább növeli a hősök számát. Vegyük észre, hogy a kliensek kilépésétől függetlenül a hősök a

labirintusban maradnak, csak akkor kerülnek ki, ha minden életük elfogy és pusztán akkor nem, ha a játékos

éppen kilép a kliens programból és ennek megfelelően nem jön létre új hős, ha ugyanarról a gépről, ugyanazzal

a hős névvel jelentkezik egy kliens. Mindezt a HálózatiLabirintus osztály hős() módszere intézi, ami a

kommunikációt végző LabirintusKiszolgálóSzál run() metódusából hívódik.

1.6.2. Java RMI - Távoli Labirintus

Az Előzetes a példaprogramokból című pontban bevezetett esettanulmány végleges kódját adjuk meg itt.

A példa kipróbálásához szükségünk van a A labirintus API felélesztése című pontban beállított labirintus API-ra

és az előző pontban továbbfejlesztésként készített TöbbHősösLabirintus osztályra. Sőt, a - szintén az előző

pontbeli - HálózatiLabirintus osztályra is, mert jelen TávoliLabirintus osztályunkat ennek

kiterjesztéseként fogjuk elkészíteni.

Az új TávoliLabirintus.java, TávoliHősíthető.java és a TávoliKliens.java forrásokat másoljuk a

Munkakönyvtár nevű munkakönyvtárunkból nyíló javattanitok könyvtárba, mert ezeket az osztályokat

szokásosan a javattanitok csomag részeiként írjuk meg.

1.6.2.1. A TávoliLabirintus osztály

Az osztály indítja az RMI szervert és TavoliLabirintus néven bejegyzi a távolról elérhető, a

TávoliHősíthatő interfészt implementáló objektumot. Miközben a szokásos párhuzamos programszálon

vezényli a labirintus mikrovilágának életét.

/*

* TávoliLabirintus.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

import javattanitok.labirintus.*;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának egy

* Java RMI-s hálózati, szerver oldali életre keltésére ad példát

* ez az osztály: a hősök távolról történő jelentkezését és

* mozgatását biztosítja.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.LabirintusVilág

* @see javattanitok.LabirintusApplet

* @see javattanitok.LabirintusJáték

* @see javattanitok.LabirintusMIDlet

* @see javattanitok.LabirintusServlet

* @see javattanitok.HálózatiLabirintus

* @see javattanitok.KorbásLabirintus

* @see javattanitok.ElosztottLabirintus

* @see TávoliKliens

* @see TávoliHősíthető

*/

public class TávoliLabirintus extends HálózatiLabirintus

implements TávoliHősíthető {

/**

* A <code>TávoliLabirintus</code> objektum elkészítése.

*

* @param labirintusFájlNév a labirintust definiáló, megfelelő

* szerkezetű szöveges állomány neve.

Page 242:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

214 Created by XMLmind XSL-FO Converter.

* @exception RosszLabirintusKivétel ha a labirintust definiáló állomány

* nem a megfelelő szerkezetű

*/

public TávoliLabirintus(String labirintusFájlNév) throws

RosszLabirintusKivétel {

// A labirintus elkészítése állományból

labirintus = new TöbbHősösLabirintus(labirintusFájlNév);

// A hős elkészítése és a kezdő pozíciójának beállítása

hősök = new java.util.Hashtable();

// A játékbeli idő folyását biztosító szál elkészítése és indítása

new Thread(this).start();

// Az RMI szerver indítása

try {

// A távoli objektum

TávoliHősíthető távoliHősíthető = (TávoliHősíthető)

java.rmi.server.UnicastRemoteObject.exportObject(this, 0);

// bejegyzése a névszolgáltatóba

java.rmi.registry.Registry registry =

java.rmi.registry.LocateRegistry.getRegistry();

registry.bind("TavoliLabirintus", távoliHősíthető);

} catch (java.rmi.AlreadyBoundException be) {

be.printStackTrace();

System.exit(-1);

} catch (java.rmi.RemoteException re) {

re.printStackTrace();

System.out.println("Fut az rmiregistry?");

System.exit(-1);

}

}

/**

* Az RMI-n keresztül jelenetkező hős lépése.

*

* @param hősNév a hős neve.

* @return String a labirintus állapotát bemutató string.

*/

public String lépLe(String hősNév) throws java.rmi.RemoteException {

Hős hős = null;

try {

// a hős neve (= "hoszt IP : név")

hős = hős(java.rmi.server.RemoteServer.getClientHost() +

" : " + hősNév);

} catch(java.rmi.server.ServerNotActiveException e) {

e.printStackTrace();

}

hős.lépLe();

return labirintus.kinyomtat(hős);

}

/**

* Az RMI-n keresztül jelenetkező hős lépése.

*

* @param hősNév a hős neve.

* @return String a labirintus állapotát bemutató string.

*/

public String lépFöl(String hősNév) throws java.rmi.RemoteException {

Hős hős = null;

try {

hős = hős(java.rmi.server.RemoteServer.getClientHost() +

" : " + hősNév);

} catch(java.rmi.server.ServerNotActiveException e) {

e.printStackTrace();

}

hős.lépFöl();

return labirintus.kinyomtat(hős);

Page 243:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

215 Created by XMLmind XSL-FO Converter.

}

/**

* Az RMI-n keresztül jelenetkező hős lépése.

*

* @param hősNév a hős neve.

* @return String a labirintus állapotát bemutató string.

*/

public String lépJobbra(String hősNév) throws java.rmi.RemoteException {

Hős hős = null;

try {

hős = hős(java.rmi.server.RemoteServer.getClientHost() +

" : " + hősNév);

} catch(java.rmi.server.ServerNotActiveException e) {

e.printStackTrace();

}

hős.lépJobbra();

return labirintus.kinyomtat(hős);

}

/**

* Az RMI-n keresztül jelenetkező hős lépése.

*

* @param hősNév a hős neve.

* @return String a labirintus állapotát bemutató string.

*/

public String lépBalra(String hősNév) throws java.rmi.RemoteException {

Hős hős = null;

try {

hős = hős(java.rmi.server.RemoteServer.getClientHost() +

" : " + hősNév);

} catch(java.rmi.server.ServerNotActiveException e) {

e.printStackTrace();

}

hős.lépBalra();

return labirintus.kinyomtat(hős);

}

/**

* Átveszi a játék indításához szükséges paramétereket, majd

* elindítja a játék világának működését.

*

* @param args a labirintus tervét tartalmazó állomány neve az első

* parancssor-argumentum.

*/

public static void main(String[] args) {

if(args.length != 1) {

System.out.println("Indítás: " +

"java javattanitok.TávoliLabirintus labirintus.txt");

System.exit(-1);

}

try {

new TávoliLabirintus(args[0]);

} catch(RosszLabirintusKivétel rosszLabirintusKivétel) {

System.out.println(rosszLabirintusKivétel);

}

}

}

Page 244:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

216 Created by XMLmind XSL-FO Converter.

1.6.2.2. A TávoliHősíthető osztály

Az interfész a távolról meghívható függvényeket deklarálja.

/*

* TávoliHősíthető.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

/**

* A labirintusba távolról történő jelentkezést biztosít a hősök számára.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see TávoliKliens

* @see TávoliLabirintus

*/

public interface TávoliHősíthető extends java.rmi.Remote {

/**

* Az RMI-n keresztül jelenetkező hős lépése.

*

* @param hősNév a hős neve.

*/

public String lépLe(String hősNév) throws java.rmi.RemoteException;

/**

* Az RMI-n keresztül jelenetkező hős lépése.

*

* @param hősNév a hős neve.

*/

public String lépFöl(String hősNév) throws java.rmi.RemoteException;

/**

* Az RMI-n keresztül jelenetkező hős lépése.

*

* @param hősNév a hős neve.

*/

public String lépJobbra(String hősNév) throws java.rmi.RemoteException;

/**

* Az RMI-n keresztül jelenetkező hős lépése.

*

* @param hősNév a hős neve.

*/

public String lépBalra(String hősNév) throws java.rmi.RemoteException;

}

1.6.2.3. A TávoliKliens osztály

Az osztály a TavoliLabirintus név feloldásával megszerzi a távoli Java RMI objektum referenciáját és (innen

távolról) meghívja például a lépJobbra() módszerét.

/*

* TávoliKliens.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

Page 245:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

217 Created by XMLmind XSL-FO Converter.

import javattanitok.labirintus.*;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának egy

* Java RMI-s hálózati, kliens oldali életre keltésére ad példát

* ez az osztály: a hős távolról történő mozgatását biztosítja.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see TávoliLabirintus

* @see TávoliHősíthető

*/

public class TávoliKliens {

/**

* Elindítja a távolról jelentkező hős klienst.

*

* @param args a hős neve.

*/

public static void main(String[] args) {

String hősNév = null;

// ha nem adtuk meg a parancssor-argumentumot,

// akkor ez az alapértelmezés:

if(args.length != 1)

hősNév = "Matyi";

else

hősNév = args[0];

// Megszerezzük a távoli labirintus (TávoliHősíthető) referenciáját

try {

java.rmi.registry.Registry registry =

java.rmi.registry.LocateRegistry.getRegistry();

TávoliHősíthető távoliHősíthető =

(TávoliHősíthető) registry.lookup("TavoliLabirintus");

// és jobbra mozgatjuk a labirintusban a hősünket

System.out.println(távoliHősíthető.lépJobbra(hősNév));

} catch (java.rmi.NotBoundException be) {

be.printStackTrace();

} catch (java.rmi.RemoteException re) {

re.printStackTrace();

}

}

}

1.6.2.4. A TávoliLabirintus fordítása és futtatása

Egyelőre egy gépen futtatjuk a példát, így lefordítjuk a szervert és a klienst is.

C:\...\Munkakönyvtár> javac javattanitok\TávoliLabirintus.java

C:\...\Munkakönyvtár> javac javattanitok\TávoliKliens.java

Elindítjuk az RMI registry programot, ez a program szolgáltatja a szerveren távolról elérhető objetumok

referenciáit. A távoli objektum referenciájához a bejegyzett - esetünkben a TavoliLabirintus - név szerint

jutunk.

C:\...\Munkakönyvtár> start rmiregistry

Majd futtatjuk a szervert és a klienst.

Page 246:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

218 Created by XMLmind XSL-FO Converter.

C:\...\Munkakönyvtár> java javattanitok.TávoliLabirintus labirintus.txt

Hősök száma: 0

Hősök száma: 0

Hősök száma: 0

...

C:\...\Munkakönyvtár> java javattanitok.TávoliKliens

| | | |FAL| |FAL| |FAL|FAL|FAL

| | | | | | |S | | |

|FAL| |FAL| |FAL| |FAL|K |FAL|

| | | | |FAL|K |FAL| | |

| |FAL|FAL| | |K |FAL|FAL| |FAL

| | | | |FAL| | | |S |K

| |FAL| |S |K |FAL| |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

| |H | | |FAL| | | |FAL|FAL

C:\...\Munkakönyvtár> java javattanitok.TávoliKliens

| | | |FAL| |FAL| |FAL|FAL|FAL

| | | | | |S | | | |

|FAL| |FAL| |FAL| |FAL|K |FAL|

| | | | |FAL|K |FAL| | |

| |FAL|FAL| | |K |FAL|FAL| |FAL

| | | | |FAL| | | | |K

| |FAL| |S |K |FAL|S |FAL|FAL|

| | | |FAL| |FAL| |FAL| |

| |FAL| | | | | | | |FAL

| | |H | |FAL| | | |FAL|FAL

Másoljuk át egy Linuxos gépre a példát és a TávoliKliens.java forrást módosítsuk, hogy ne a localhost-hoz

akarjon kapcsolódni, hanem a távoli, a kalapacs nevű, természetesen a szervert futtató gépen keresse az

rmiregistry programot:

java.rmi.registry.Registry registry =

java.rmi.registry.LocateRegistry.getRegistry("kalapacs");

[norbi@niobe Munkakönyvtár]$ javac javattanitok/TávoliKliens.java

[norbi@niobe Munkakönyvtár]$ java javattanitok.TávoliKliens

| | | |FAL| |FAL| |FAL|FAL|FAL

| | | | | | | | | |

|FAL| |FAL| |FAL| |FAL|K |FAL|

| | | | |FAL|K |FAL| | |

| |FAL|FAL| | |SK |FAL|FAL| |FAL

| | | | |FAL| | | | |K

| |FAL| |S |K |FAL| |FAL|FAL|

| | | |FAL| |FAL|S |FAL| |

| |FAL| | | | | | | |FAL

| |H | | |FAL| | | |FAL|FAL

[norbi@niobe Munkakönyvtár]$ java javattanitok.TávoliKliens

| | | |FAL| |FAL| |FAL|FAL|FAL

| | | | | | | | | |

|FAL| |FAL| |FAL| |FAL|K |FAL|

| | | | |FAL|K |FAL| | |

Page 247:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

219 Created by XMLmind XSL-FO Converter.

| |FAL|FAL| | |K |FAL|FAL| |FAL

| | | | |FAL|S | | | |K

| |FAL| |S |K |FAL| |FAL|FAL|

| | | |FAL| |FAL|S |FAL| |

| |FAL| | | | | | | |FAL

| | |H | |FAL| | | |FAL|FAL

1.6.3. CORBA - Korbás Labirintus

Az Előzetes a példaprogramokból című pontban bevezetett esettanulmány végleges kódját adjuk meg itt.

1.6.3.1. A KorbásLabirintus osztály

Az osztály elindítja a CORBA szervert: elkészíti a kiszolgáló CORBA objektumot, amit TavoliHos néven a

CORBA névszolgáltatóba is bejegyez. Miközben a szokásosan indított párhuzamos programszálban vezérli a

labirintus mikrovilágának életét.

A szerver CORBA specifikus logikáját külön is részletezzük. A CORBA világában a programok az ORB

szoftveren, az Object Request Broker, a metódushívások közvetítőjén keresztül tudnak kapcsolódni. A szerver

első dolga ezért - az esetünkben a localhost 2006-os kapujánál futó - ORB szerverrel felvenni a kapcsolatot.

// Az ORB tulajdonságainak megadása

java.util.Properties orbTulajdonságok = new java.util.Properties();

orbTulajdonságok.put("org.omg.CORBA.ORBInitialHost", "localhost");

orbTulajdonságok.put("org.omg.CORBA.ORBInitialPort", "2006");

// Az ORB (a metódushívások közvetítőjének) inicializálása

org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init((String [])null,

orbTulajdonságok);

A CORBA környezetben méginkább igaz, ami Javaban is igaz volt: minden objektum. S ez itt szinte minden

programsorban következetesen tetten érhető. Mert például a szerver következő lépése egy objektum adapter

elérése. Az objektum adapterek éltetik a kiszolgáló CORBA objektumainkat, s itt jön a következetesség: ezek az

adapterek maguk is CORBA objektumok. Az adapterek fába szervezhetők, attól függően, hogy milyen

tulajdonságokkal akarjuk felruházni őket, most a gyökér POA-t használjuk.

// A gyökér POA CORBA objektum referenciájának megszerzése

org.omg.CORBA.Object corbaObjektum =

orb.resolve_initial_references("RootPOA");

Az ORB-től elkért objektumok általános org.omg.CORBA.Object osztálybeli objektumok, amiket a CORBA

világában honos típuskényszerítéssel a megfelelő típusúra kasztolunk a céltípus Helper osztályának narrow

módszerét használva:

// CORBA-s típuskényszerítéssel a megfelelőre

org.omg.PortableServer.POA gyökérPoa =

org.omg.PortableServer.POAHelper.narrow(corbaObjektum);

Majd a közben elkészített kiszolgáló CORBA objektumunkat TavoliHos néven bejegyezzük a

névszolgáltatóba.

Page 248:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

220 Created by XMLmind XSL-FO Converter.

A CORBA OO világ telefonkönyve a CORBA névszolgáltató. Ez a szolgáltatás is CORBA objektumként került

megvalósításra. A névszolgáltatás egy fa szerkezetbe van szervezve, ahol a gyökeret reprezentáló CORBA

objektum referenciáját ugyanúgy szerezzük meg, mint az imént a POA adapterét.

// A névszolgáltató gyökerének, mint CORBA objektum

// referenciájának megszerzése

corbaObjektum =

orb.resolve_initial_references("NameService");

org.omg.CosNaming.NamingContextExt névszolgáltatóGyökere

= org.omg.CosNaming.NamingContextExtHelper

.narrow(corbaObjektum);

A CORBA névszolgáltatása

Mint már említettük, CORBA-ban is minden objektum, maga a névszolgáltatás is. Ennek megfelelően

a névszolgáltatást a megfelelő IDL nyelvű interfész megismerésén keresztül is tanulmányozhatja az

érdeklődő Olvasó. Ezt a cosnaming.idl állományban találjuk meg a

http://www.omg.org/docs/formal/04-10-07.txt címen.

/*

* KorbásLabirintus.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

import javattanitok.labirintus.*;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának egy

* CORBA-s, szerver oldali életre keltésére ad példát ez az osztály:

* a hősök távolról történő jelentkezését és mozgatását biztosítja.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.LabirintusVilág

* @see javattanitok.LabirintusApplet

* @see javattanitok.LabirintusJáték

* @see javattanitok.LabirintusMIDlet

* @see javattanitok.LabirintusServlet

* @see javattanitok.HálózatiLabirintus

* @see javattanitok.TávoliLabirintus

* @see javattanitok.ElosztottLabirintus

* @see TávoliHősKiszolgáló

* @see KorbásKliens

* @see tavolihos.idl

*/

public class KorbásLabirintus extends HálózatiLabirintus {

/**

* A <code>TávoliLabirintus</code> objektum elkészítése.

*

* @param labirintusFájlNév a labirintust definiáló, megfelelő

* szerkezetű szöveges állomány neve.

* @exception RosszLabirintusKivétel ha a labirintust definiáló állomány nem

* a megfelelő szerkezetű

*/

public KorbásLabirintus(String labirintusFájlNév) throws

RosszLabirintusKivétel {

// A labirintus elkészítése állományból

labirintus = new TöbbHősösLabirintus(labirintusFájlNév);

// A hősöket tartalmazó adatszerkezet elkészítése

hősök = new java.util.Hashtable();

// A játék valóságának (világának) indítása:

Page 249:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

221 Created by XMLmind XSL-FO Converter.

new Thread(this).start();

// A CORBA szerver indítása

try{

// Az ORB tulajdonságainak megadása

java.util.Properties orbTulajdonságok = new java.util.Properties();

orbTulajdonságok.put("org.omg.CORBA.ORBInitialHost", "localhost");

orbTulajdonságok.put("org.omg.CORBA.ORBInitialPort", "2006");

// Az ORB (a metódushívások közvetítőjének) inicializálása

org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init((String [])null,

orbTulajdonságok);

// A gyökér POA CORBA objektum referenciájának megszerzése

org.omg.CORBA.Object corbaObjektum =

orb.resolve_initial_references("RootPOA");

// CORBA-s típuskényszerítéssel a megfelelőre

org.omg.PortableServer.POA gyökérPoa =

org.omg.PortableServer.POAHelper.narrow(corbaObjektum);

// A POA kiszolgáló állapotba kapcsolása:

gyökérPoa.the_POAManager().activate();

// A kiszolgáló objektum létrehozása

TávoliHősKiszolgáló távoliHősKiszolgáló =

new TávoliHősKiszolgáló(this);

// CORBA objektum referencia elkészítése

corbaObjektum =

gyökérPoa.servant_to_reference(távoliHősKiszolgáló);

// CORBA-s típuskényszerítéssel a megfelelőre

javattanitok.korbas.TavoliHos távoliHős =

javattanitok.korbas.TavoliHosHelper.narrow(corbaObjektum);

// A névszolgáltató gyökerének, mint CORBA objektum

// referenciájának megszerzése

corbaObjektum =

orb.resolve_initial_references("NameService");

org.omg.CosNaming.NamingContextExt névszolgáltatóGyökere

= org.omg.CosNaming.NamingContextExtHelper

.narrow(corbaObjektum);

// A kiszolgáló objektum bejegyzése a névszolgáltatóba

org.omg.CosNaming.NameComponent név[] =

névszolgáltatóGyökere.to_name("TavoliHos");

névszolgáltatóGyökere.rebind(név, távoliHős);

// Várakozás a játékosok jelentkezésére

orb.run();

} catch (Exception e) {

e.printStackTrace();

System.exit(-1);

}

}

/**

* Átveszi a játék indításához szükséges paramétereket, majd

* elindítja a játék világának működését.

*

* @param args a labirintus tervét tartalmazó állomány neve az első

* parancssor-argumentum.

*/

public static void main(String[] args) {

if(args.length != 1) {

System.out.println("Indítás: " +

"java javattanitok.KorbásLabirintus labirintus.txt");

System.exit(-1);

}

try {

new KorbásLabirintus(args[0]);

} catch(RosszLabirintusKivétel rosszLabirintusKivétel) {

System.out.println(rosszLabirintusKivétel);

}

}

Page 250:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

222 Created by XMLmind XSL-FO Converter.

}

1.6.3.2. A KorbásKliens osztály

A kliens a szerverhez hasonlóan felveszi a kapcsolatot az ORB szoftverrel, majd azon keresztül megszerzi a

névszolgáltató objektum referenciáját, akitől elkéri a TavoliHos névhez bejegyzett kiszolgáló CORBA

objetumunk referenciáját, akitől a hős jobbra léptetését kéri.

/*

* KorbásKliens.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

import javattanitok.labirintus.*;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának egy

* CORBA-s hálózati, kliens oldali életre keltésére ad példát ez az osztály:

* a hős távolról történő mozgatását biztosítja.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see KorbásLabirintus

* @see TávoliHősKiszolgáló

*/

public class KorbásKliens {

/**

* Elindítja a távolról jelentkező hős klienst.

*

* @param args a hős neve.

*/

public static void main(String[] args) {

String hősNév = null;

// ha nem adtuk meg a parancssor-argumentumot,

// akkor ez az alapértelmezés:

if(args.length != 1)

hősNév = "Matyi";

else

hősNév = args[0];

try {

// Az ORB tulajdonságainak megadása

java.util.Properties orbTulajdonságok = new java.util.Properties();

orbTulajdonságok.put("org.omg.CORBA.ORBInitialHost", "localhost");

orbTulajdonságok.put("org.omg.CORBA.ORBInitialPort", "2006");

// Az ORB (a metódushívások közvetítőjének) inicializálása

org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init((String [])null,

orbTulajdonságok);

// A névszolgáltató gyökerének, mint CORBA objektum

// referenciájának megszerzése

org.omg.CORBA.Object corbaObjektum =

orb.resolve_initial_references("NameService");

org.omg.CosNaming.NamingContextExt névszolgáltatóGyökere

= org.omg.CosNaming.

NamingContextExtHelper.narrow(corbaObjektum);

// A TavoliHos szolgáltatást nyújtó CORBA objektum

// referenciájának megszerzése

javattanitok.korbas.TavoliHos távoliHős =

javattanitok.korbas.TavoliHosHelper.narrow(

névszolgáltatóGyökere.resolve_str("TavoliHos"));

System.out.println(távoliHős.lépJobbra(hősNév));

Page 251:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

223 Created by XMLmind XSL-FO Converter.

} catch (Exception e) {

e.printStackTrace();

}

}

}

1.6.3.3. A TavoliHos interfész

A kiszolgáló CORBA objektum távolról is elérhető módszereit egy IDL nyelvű interfészben deklaráljuk, az

alábbi tavolihos.idl állományban.

module javattanitok

{

module korbas

{

interface TavoliHos

{

string lépLe(in string hosNev);

string lépFöl(in string hosNev);

string lépJobbra(in string hosNev);

string lépBalra(in string hosNev);

};

};

};

Az egymásba ágyazott két IDL modul a javattanitok.korbas Java csomagra képeződik majd le. Az idlj

fordító majd az ennek megfelelő javattanitok/korbas könyvtárba generálja le a CORBA specifikus Java

forrásokat.

1.6.3.4. A TávoliHősKiszolgáló osztály

Ebben az osztályban kell megadnunk az IDL interfészben deklarált módszerek implementációját. A kiszolgáló

objektum megvalósítására több lehetőség adódik, most azt választjuk, hogy az osztályt az interfésznek

megfelelő POA osztályból, esetünkben a TavoliHosPOA osztályból származtatjuk.

/*

* TávoliHősKiszolgáló.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

import javattanitok.labirintus.*;

/**

* A <code>tavolihos.idl</code> leírta TávoliHős CORBA

* kiszolgáló objektum megvalósítása.

*

* A <code>tavolihos.idl</code> interfész:

* <pre>

* module javattanitok

* {

* module korbas

* {

* interface TavoliHos

* {

* string lépLe(in string hosNev);

* string lépFöl(in string hosNev);

* string lépJobbra(in string hosNev);

* string lépBalra(in string hosNev);

Page 252:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

224 Created by XMLmind XSL-FO Converter.

* };

* };

* };

* </pre>

* A <code>javattanitok.korbas.*</code> csomag legenerálása:

* <pre>

* idlj -fall tavolihos.idl

* </pre>

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see KorbásLabirintus

* @see KorbásKliens

*/

public class TávoliHősKiszolgáló

extends javattanitok.korbas.TavoliHosPOA {

/** A labirintus játékot futtató osztály. */

KorbásLabirintus korbásLabirintus;

/**

* A <code>TávoliHősKiszolgáló</code> objektum elkészítése.

*

* @param korbásLabirintus A labirintus játékot futtató osztály.

*/

public TávoliHősKiszolgáló(KorbásLabirintus korbásLabirintus) {

this.korbásLabirintus = korbásLabirintus;

}

/**

* Az ORB-n keresztül jelenetkező hős lépése.

*

* @param hősNév a hős neve.

* @return String a labirintus állapotát bemutató string.

*/

public String lépLe(String hősNév) {

Hős hős = null;

hős = korbásLabirintus.hős(hősNév);

hős.lépLe();

return korbásLabirintus.labirintus().kinyomtat(hős);

}

/**

* Az ORB-n keresztül jelenetkező hős lépése.

*

* @param hősNév a hős neve.

* @return String a labirintus állapotát bemutató string.

*/

public String lépFöl(String hősNév) {

Hős hős = null;

hős = korbásLabirintus.hős(hősNév);

hős.lépFöl();

return korbásLabirintus.labirintus().kinyomtat(hős);

}

/**

* Az ORB-n keresztül jelenetkező hős lépése.

*

* @param hősNév a hős neve.

* @return String a labirintus állapotát bemutató string.

*/

public String lépJobbra(String hősNév) {

Hős hős = null;

hős = korbásLabirintus.hős(hősNév);

hős.lépJobbra();

return korbásLabirintus.labirintus().kinyomtat(hős);

}

Page 253:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

225 Created by XMLmind XSL-FO Converter.

/**

* Az ORB-n keresztül jelenetkező hős lépése.

*

* @param hősNév a hős neve.

* @return String a labirintus állapotát bemutató string.

*/

public String lépBalra(String hősNév) {

Hős hős = null;

hős = korbásLabirintus.hős(hősNév);

hős.lépBalra();

return korbásLabirintus.labirintus().kinyomtat(hős);

}

}

1.6.3.5. A KorbásLabirintus fordítása és futtatása

Az idlj fordító használatát a Objektumok mindenütt: a CORBA OO világ című pontban vezettük be.

C:\...\Munkakönyvtár> idlj -fall tavolihos.idl

A tavolihos.idl modul szerkezetének megfelelően a kliens és a szerveroldali CORBA specifikus Java

források megjelentek a javattanitok/korbas könyvtárban. Lefordítjuk a szervert

C:\...\Munkakönyvtár> javac javattanitok\KorbásLabirintus.java

Note: Some input files use unchecked or unsafe operations.

Note: Recompile with -Xlint:unchecked for details.

és a kliens oldalt

C:\...\Munkakönyvtár> javac javattanitok\KorbásKliens.java

Indítjuk az ORB szoftvert:

C:\Documents and Settings\norbi> start orbd -ORBInitialPort 2006

Majd a szerveroldalt:

C:\...\Munkakönyvtár> java javattanitok.KorbásLabirintus labirintus.txt

Hősök száma: 0

Hősök száma: 0

Hősök száma: 0

...

és a kliens oldalt:

Page 254:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

226 Created by XMLmind XSL-FO Converter.

C:\...\Munkakönyvtár> java javattanitok.KorbásKliens

| | |K |FAL| |FAL| |FAL|FAL|FAL

| | | |S | | | |S | |

|FAL| |FAL| |FAL|K |FAL| |FAL|K

| | | | |FAL| |FAL| | |

| |FAL|FAL| | | |FAL|FAL| |FAL

| | | | |FAL| | | | |

| |FAL|K | | |FAL| |FAL|FAL|

| | |SK |FAL| |FAL| |FAL| |K

| |FAL| | | | | | | |FAL

| |H | | |FAL| | | |FAL|FAL

C:\...\Munkakönyvtár> java javattanitok.KorbásKliens

| | |K |FAL| |FAL| |FAL|FAL|FAL

| | | | | | | | | |

|FAL| |FAL| |FAL|K |FAL| |FAL|K

| | | | |FAL| |FAL|S | |

| |FAL|FAL| | | |FAL|FAL| |FAL

| | | | |FAL| | | | |

| |FAL|K |S | |FAL| |FAL|FAL|

| | |K |FAL| |FAL| |FAL| |K

| |FAL|S | | | | | | |FAL

| | |H | |FAL| | | |FAL|FAL

Izgalmasabb a tesztelés, ha a klienst átmásoljuk egy másik gépre, s az alábbi módosítás

orbTulajdonságok.put("org.omg.CORBA.ORBInitialHost", "kalapacs");

majd fordítás után futtatjuk ezen a másik gépen, a niobén:

[norbi@niobe Munkakönyvtár]$ java javattanitok.KorbásKliens Herkules

| | | |FAL| |FAL| |FAL|FAL|FAL

| | |K | |K | | | | |

|FAL| |FAL| |FAL| |FAL| |FAL|

| | | | |FAL|K |FAL| | |

| |FAL|FAL| | | |FAL|FAL|S |FAL

| | | |K |FAL|K | | | |

| |FAL| | | |FAL| |FAL|FAL|S

| | |K |FAL| |FAL| |FAL|S |

| |FAL| | | | | | | |FAL

| |H | | |FAL| | | |FAL|FAL

[norbi@niobe Munkakönyvtár]$ java javattanitok.KorbásKliens Herkules

| | | |FAL| |FAL| |FAL|FAL|FAL

| | |K | |K | | | | |

|FAL| |FAL| |FAL| |FAL| |FAL|

| | | | |FAL|K |FAL| | |

| |FAL|FAL| | | |FAL|FAL|S |FAL

| | | |K |FAL|K | | | |

| |FAL| | | |FAL| |FAL|FAL|S

| | |K |FAL| |FAL| |FAL|S |

| |FAL| | | | | | | |FAL

| | |H | |FAL| | | |FAL|FAL

1.7. Elosztott objektumok - Elosztott labirintus

Az Előzetes a példaprogramokból című pontban bevezetett esettanulmány végleges kódját adjuk meg itt.

Page 255:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

227 Created by XMLmind XSL-FO Converter.

1.7.1. Az elosztott labirintus API felélesztése

Feltesszük, hogy a korábbi esettanulmányok alapján a labirintus API-t már felélesztettük, sőt a hálózati

példáknál kifejlesztett TöbbHősösLabirintus osztállyal is bővítettük már ezt az API-t. Az alábbiakban az

elosztott labirintus API-t állítjuk be.

Tetszőleges munkakönyvtárunkban hozzuk létre - a labirintus API rendelkezésre állása miatt már létező -

javattanitok könyvtáron belül az elosztott könyvtárat.

C:\...\Munkakönyvtár> mkdir javattanitok\elosztott

Ezzel a javattanitok.elosztott Java csomagot leképeztük a munkakönyvtárunkba, a kifejlesztendő

osztályokat ide, a javattanitok/elosztott könyvtárban írjuk majd meg, azaz gyűjtük most össze. Másoljuk

ide a következő SzereplőKiszolgáló.java, HősKiszolgáló.java, KincsKiszolgáló.java,

SzörnyKiszolgáló.java, LabirintusKiszolgáló.java állományokat! A következő pontokban ismertetjük

ezeknek - az elosztott.idl interfészben deklarált CORBA objektumoknak - az implementációit.

1.7.1.1. A SzereplőKiszolgáló osztály

A kiszolgáló objektumokban implementálnunk kell az elosztott.idl interfészben specifikált metódusokat,

illetve lekérdező és beállító módszereket kell írnunk a szereplő attribútumokhoz. A Szereplo IDL interfésznek

nincsenek módszerei, így csupán az oszlop, sor attribútumaihoz kell egy-egy, a tulajdonságokkal megegyező

nevű beállító és lekérdező függvényt implementálnunk az interfészt kiszolgáló CORBA objektum, a

SzereplőKiszolgáló osztály testében.

/*

* SzereplőKiszolgáló.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.elosztott;

/**

* Az <code>elosztott.idl</code> leírta Szereplő CORBA objektumot

* kiszolgáló objektum megvalósítása.

*

* Az <code>elosztott.idl</code> interfész:

* <pre>

* module javattanitok

* {

* module elosztott

* {

* module objektumok

* {

* interface Szereplo

* {

* attribute long oszlop;

* attribute long sor;

* };

* interface Kincs;

* interface Hos : Szereplo

* {

* attribute long megtalaltErtekek;

* readonly attribute long eletek;

* void megtalaltam(in Kincs kincs);

* boolean megettek();

* };

* interface Kincs : Szereplo

* {

* attribute long ertek;

* readonly attribute boolean megtalalva;

Page 256:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

228 Created by XMLmind XSL-FO Converter.

* boolean megtalalt(in Hos hos);

* };

* interface Szorny : Szereplo

* {

* boolean lep(in Hos hos);

* };

* interface Labirintus

* {

* wstring belepHos(in Hos hos);

* wstring belepKincs(in Kincs kincs);

* wstring belepSzorny(in Szorny szorny);

* };

* };

* };

* };

* </pre>

* A <code>javattanitok.elosztott.objektumok.*</code> csomag legenerálása:

* <pre>

* idlj -fall -falltie elosztott.idl

* </pre>

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see ElosztottLabirintus

* @see ElosztottKliens

* @see LabirintusKiszolgáló

* @see HősKiszolgáló

* @see SzörnyKiszolgáló

* @see KincsKiszolgáló

*/

public class SzereplőKiszolgáló

extends javattanitok.elosztott.objektumok.SzereploPOA {

/** A szereplő oszlop pozíciója. */

int oszlop;

/** A szereplő sor pozíciója. */

int sor;

/** A <code>SzereplőKiszolgáló</code> objektum elkészítése. */

public SzereplőKiszolgáló() {}

/**

* Beállítja a szereplő labirintusbeli pozíciójának oszlop

* koordinátáját.

*

* @param oszlop a szereplő labirintusbeli pozíciójának oszlop

* koordinátája.

*/

public void oszlop(int oszlop) {

this.oszlop = oszlop;

System.out.println("SZEREPLŐ> Beállították a pozíciómat.");

}

/**

* Megadja a szereplő labirintusbeli pozíciójának oszlop koordinátáját.

*

* @return int a szereplő labirintusbeli pozíciójának oszlop koordinátája.

*/

public int oszlop() {

System.out.println("SZEREPLŐ> Lekérdezték a pozíciómat.");

return oszlop;

}

/**

* Beállítja a szereplő labirintusbeli pozíciójának sor koordinátáját.

*

* @param sor a szereplő labirintusbeli pozíciójának sor koordinátája.

*/

public void sor(int sor) {

this.sor = sor;

}

Page 257:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

229 Created by XMLmind XSL-FO Converter.

/**

* Megadja a szereplő labirintusbeli pozíciójának sor koordinátáját.

*

* @return int a szereplő labirintusbeli pozíciójának sor koordinátája.

*/

public int sor() {

return sor;

}

}

1.7.1.2. A HősKiszolgáló osztály

Az osztályt a SzereplőKiszolgáló osztályból szeretnénk származtatni, s mivel Javaban nincs többszörös

öröklődés, így nem tudjuk a CORBA objektum implementációjánál a szokásos utunkat követni: a HosPOA idlj

generálta osztályt kiterjeszteni. Ezért a Hos IDL interfészt kiszolgáló CORBA objektum elkészítésénél a tie

delegációs modellt követjük: kiterjesztjük a SzereplőKiszolgáló-t és implementáljuk a HosOperations idlj

generálta, az IDL interfészben deklarált metódusok specifikációját tartalmazó Java interfészt.

/*

* HősKiszolgáló.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.elosztott;

// Itt vannak a CORBA objektumaink, bár nem szokásunk,

// most importálunk, mert a teljes csomagnévvel

// való osztálynév minősítést, a hossza miatt nehézkes

// lenne kezelni a könyv kapcsán a szövegszerkesztőnkben.

import javattanitok.elosztott.objektumok.*;

/**

* Az <code>elosztott.idl</code> leírta Hős CORBA objektumot

* kiszolgáló objektum megvalósítása.

*

* Az <code>elosztott.idl</code> interfész:

* <pre>

* module javattanitok

* {

* module elosztott

* {

* module objektumok

* {

* interface Szereplo

* {

* attribute long oszlop;

* attribute long sor;

* };

* interface Kincs;

* interface Hos : Szereplo

* {

* attribute long megtalaltErtekek;

* readonly attribute long eletek;

* void megtalaltam(in Kincs kincs);

* boolean megettek();

* };

* interface Kincs : Szereplo

* {

* attribute long ertek;

* readonly attribute boolean megtalalva;

* boolean megtalalt(in Hos hos);

* };

* interface Szorny : Szereplo

* {

Page 258:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

230 Created by XMLmind XSL-FO Converter.

* boolean lep(in Hos hos);

* };

* interface Labirintus

* {

* wstring belepHos(in Hos hos);

* wstring belepKincs(in Kincs kincs);

* wstring belepSzorny(in Szorny szorny);

* };

* };

* };

* };

* </pre>

* A <code>javattanitok.elosztott.objektumok.*</code> csomag legenerálása:

* <pre>

* idlj -fall -falltie elosztott.idl

* </pre>

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see ElosztottLabirintus

* @see ElosztottKliens

* @see LabirintusKiszolgáló

* @see SzereplőKiszolgáló

* @see HősKiszolgáló

* @see SzörnyKiszolgáló

* @see KincsKiszolgáló

*/

public class HősKiszolgáló

extends SzereplőKiszolgáló

implements HosOperations {

/** A labirintusban megtalált kincsek értékei. */

protected int megtaláltÉrtékek;

/** A hős életeinek maximális száma. */

public static final int ÉLETEK_SZÁMA = 5;

/** A hős életeinek száma. */

protected int életekSzáma = ÉLETEK_SZÁMA;

/** A <code>HősKiszolgáló</code> objektum elkészítése. */

public HősKiszolgáló() {}

/**

* Életek számának lekérdezése.

*

* @return int az életek száma.

*/

public int eletek() {

return életekSzáma;

}

/**

* A megtalált értékek beállítása.

*

* @param megtaláltÉrtékek a megtalált értékek.

*/

public void megtalaltErtekek(int megtaláltÉrtékek) {

this.megtaláltÉrtékek = megtaláltÉrtékek;

}

/**

* A megtalált értékek lekérdezése.

*

* @return int a megtalált értékek.

*/

public int megtalaltErtekek() {

return megtaláltÉrtékek;

}

/**

* Jelzi, hogy éppen megettek.

*

* @return true ha a hősnek még van élete, ellenkező esetben,

* azaz ha az összes élete elfogyott már, akkor false.

*/

Page 259:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

231 Created by XMLmind XSL-FO Converter.

public boolean megettek() {

if(életekSzáma > 0) {

--életekSzáma;

return false;

} else

return true;

}

/**

* Gyüjtögeti a megtalált kincseket.

*

* @param kincs amit éppen magtalált a hős.

*/

public void megtalaltam(Kincs kincs) {

megtaláltÉrtékek += kincs.ertek();

System.out.println("HŐS> Kincset találtam.");

}

}

1.7.1.3. A KincsKiszolgáló osztály

Az osztály megvalósításánál a HősKiszolgáló osztálynál is alkalmazott módszert követjük.

/*

* KincsKiszolgáló.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.elosztott;

/**

* Az <code>elosztott.idl</code> leírta Kincs CORBA objektumot

* kiszolgáló objektum megvalósítása.

*

* Az <code>elosztott.idl</code> interfész:

* <pre>

* module javattanitok

* {

* module elosztott

* {

* module objektumok

* {

* interface Szereplo

* {

* attribute long oszlop;

* attribute long sor;

* };

* interface Kincs;

* interface Hos : Szereplo

* {

* attribute long megtalaltErtekek;

* readonly attribute long eletek;

* void megtalaltam(in Kincs kincs);

* boolean megettek();

* };

* interface Kincs : Szereplo

* {

* attribute long ertek;

* readonly attribute boolean megtalalva;

* boolean megtalalt(in Hos hos);

* };

* interface Szorny : Szereplo

* {

Page 260:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

232 Created by XMLmind XSL-FO Converter.

* boolean lep(in Hos hos);

* };

* interface Labirintus

* {

* wstring belepHos(in Hos hos);

* wstring belepKincs(in Kincs kincs);

* wstring belepSzorny(in Szorny szorny);

* };

* };

* };

* };

* </pre>

* A <code>javattanitok.elosztott.objektumok.*</code> csomag legenerálása:

* <pre>

* idlj -fall -falltie elosztott.idl

* </pre>

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see ElosztottLabirintus

* @see ElosztottKliens

* @see LabirintusKiszolgáló

* @see SzereplőKiszolgáló

* @see HősKiszolgáló

* @see SzörnyKiszolgáló

*/

public class KincsKiszolgáló

extends SzereplőKiszolgáló

implements javattanitok.elosztott.objektumok.KincsOperations {

/** A kincs értéke. */

protected int érték;

/** Megtaláltak már? */

protected boolean megtalálva;

/** A <code>KincsKiszolgáló</code> objektum elkészítése. */

public KincsKiszolgáló() {}

/**

* Az érték beállítása.

*

* @param érték az a kincs értéke.

*/

public void ertek(int érték) {

this.érték = érték;

}

/**

* Az érték lekérdezése.

*

* @return int az érték.

*/

public int ertek() {

return érték;

}

/**

* Megtalált ez a hős?

*

* @param hős aki rámbukkant éppen.

* @return boolean megtalál?

*/

public boolean megtalalt(javattanitok.elosztott.objektumok.Hos hős) {

if(megtalálva) {

System.out.println("KINCS> Már korábban rámtalált egy hős.");

// mert egy kicset csak egyszer lehet megtalálni

return false;

}

if(oszlop == hős.oszlop() && sor == hős.sor()) {

megtalálva = true;

System.out.println("KINCS> Rámtalált.");

Page 261:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

233 Created by XMLmind XSL-FO Converter.

} else

System.out.println("KINCS> Nem talált rám.");

return megtalálva;

}

/**

* Megmondja, hogy megtalálták-e már a kincset?

*

* @return true ha a kincset már megtalálták,

* ha még nem akkor false.

*/

public boolean megtalalva() {

return megtalálva;

}

}

1.7.1.4. A SzörnyKiszolgáló osztály

Az osztály megvalósításánál a HősKiszolgáló osztálynál is alkalmazott módszert követjük.

/*

* SzörnyKiszolgáló.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.elosztott;

/**

* Az <code>elosztott.idl</code> leírta Szörny CORBA objektumot

* kiszolgáló objektum megvalósítása.

*

* Az <code>elosztott.idl</code> interfész:

* <pre>

* module javattanitok

* {

* module elosztott

* {

* module objektumok

* {

* interface Szereplo

* {

* attribute long oszlop;

* attribute long sor;

* };

* interface Kincs;

* interface Hos : Szereplo

* {

* attribute long megtalaltErtekek;

* readonly attribute long eletek;

* void megtalaltam(in Kincs kincs);

* boolean megettek();

* };

* interface Kincs : Szereplo

* {

* attribute long ertek;

* readonly attribute boolean megtalalva;

* boolean megtalalt(in Hos hos);

* };

* interface Szorny : Szereplo

* {

* boolean lep(in Hos hos);

* };

* interface Labirintus

* {

Page 262:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

234 Created by XMLmind XSL-FO Converter.

* wstring belepHos(in Hos hos);

* wstring belepKincs(in Kincs kincs);

* wstring belepSzorny(in Szorny szorny);

* };

* };

* };

* };

* </pre>

* A <code>javattanitok.elosztott.objektumok.*</code> csomag legenerálása:

* <pre>

* idlj -fall -falltie elosztott.idl

* </pre>

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see ElosztottLabirintus

* @see ElosztottKliens

* @see LabirintusKiszolgáló

* @see SzereplőKiszolgáló

* @see HősKiszolgáló

* @see SzereplőKiszolgáló

* @see KincsKiszolgáló

*/

public class SzörnyKiszolgáló

extends SzereplőKiszolgáló

implements javattanitok.elosztott.objektumok.SzornyOperations {

/** A <code>SzörnyKiszolgáló</code> objektum elkészítése. */

public SzörnyKiszolgáló() {}

/**

* Lépek a hős felé.

*

* @param hős aki felé mozgok.

* @return boolean elkaptam ez a hőst?

*/

public boolean lep(javattanitok.elosztott.objektumok.Hos hos) {

// ... a hős felé lépést nem implementáltuk ebben a példában.

System.out.println("SZÖRNY> Lépek egy hős felé.");

// ... soha nem eszem meg ebben az implementációban.

return false;

}

}

1.7.1.5. A LabirintusKiszolgáló osztály

/*

* LabirintusKiszolgáló.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok.elosztott;

import java.util.List;

import java.util.Iterator;

// Itt vannak a CORBA objektumaink, bár nem szokásunk,

// most importálunk, mert a teljes csomagnévvel

// való osztálynév minősítést, a hossza miatt nehézkes

// lenne kezelni a könyv kapcsán a szövegszerkesztőnkben.

import javattanitok.elosztott.objektumok.*;

/**

* Az <code>elosztott.idl</code> leírta Labirintus CORBA objektumot

* kiszolgáló objektum megvalósítása.

*

* Az <code>elosztott.idl</code> interfész:

* <pre>

* module javattanitok

Page 263:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

235 Created by XMLmind XSL-FO Converter.

* {

* module elosztott

* {

* module objektumok

* {

* interface Szereplo

* {

* attribute long oszlop;

* attribute long sor;

* };

* interface Kincs;

* interface Hos : Szereplo

* {

* attribute long megtalaltErtekek;

* readonly attribute long eletek;

* void megtalaltam(in Kincs kincs);

* boolean megettek();

* };

* interface Kincs : Szereplo

* {

* attribute long ertek;

* readonly attribute boolean megtalalva;

* boolean megtalalt(in Hos hos);

* };

* interface Szorny : Szereplo

* {

* boolean lep(in Hos hos);

* };

* interface Labirintus

* {

* wstring belepHos(in Hos hos);

* wstring belepKincs(in Kincs kincs);

* wstring belepSzorny(in Szorny szorny);

* };

* };

* };

* };

* </pre>

* A <code>javattanitok.elosztott.objektumok.*</code> csomag legenerálása:

* <pre>

* idlj -fall -falltie elosztott.idl

* </pre>

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see ElosztottLabirintus

* @see ElosztottKliens

* @see SzereplőKiszolgáló

* @see HősKiszolgáló

* @see SzörnyKiszolgáló

* @see KincsKiszolgáló

*/

public class LabirintusKiszolgáló

extends javattanitok.labirintus.TöbbHősösLabirintus

implements LabirintusOperations, Runnable {

/** A labirintus szörnyei, elemei távoli CORBA objektumok. */

protected List<Szorny> szörnyek;

/** A labirintus kincsei, elemei távoli CORBA objektumok. */

protected List<Kincs> kincsek;

/** A labirintus hősei, elemei távoli CORBA objektumok. */

protected List<Hos> hősök;

/** A játékbeli idő mérésére.*/

private long idő = 0;

/** Véletlenszám generátor a szereplők mozgatásához. */

protected static java.util.Random véletlenGenerátor =

new java.util.Random();

/** A <code>LabirintusKiszolgáló</code> objektum elkészítése. */

public LabirintusKiszolgáló() {

// Az ős megfelelő konstruktorának hívása

super();

// A kincseket tartalmazó adatszerkezet létrehozása,

// elemei majd távoli CORBA objektumok lesznek

Page 264:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

236 Created by XMLmind XSL-FO Converter.

kincsek = new java.util.ArrayList<Kincs>();

// A kincseket tartalmazó adatszerkezet létrehozása,

// elemei majd távoli CORBA objektumok lesznek

szörnyek = new java.util.ArrayList<Szorny>();

// A kincseket tartalmazó adatszerkezet létrehozása,

// elemei majd távoli CORBA objektumok lesznek

hősök = java.util.Collections.synchronizedList(

new java.util.ArrayList<Hos>());

// A játékbeli idő folyását biztosító szál elkészítése és indítása

new Thread(this).start();

}

/**

* A Hos CORBA objektum az ORB-n keresztül belép a labirintusba.

*

* @param hős a Hos CORBA objektum referenciája.

* @return String a labirintus állapotát bemutató string.

*/

public String belepHos(Hos hős) {

System.out.println("LABIRINTUS> Belépett egy hős: " + hős);

hősök.add(hős);

szereplőHelyeKezdetben(hős);

return toString();

}

/**

* A Kincs CORBA objektum az ORB-n keresztül belép a labirintusba.

*

* @param hős a Kincs CORBA objektum referenciája.

* @return String a labirintus állapotát bemutató string.

*/

public String belepKincs(Kincs kincs) {

System.out.println("LABIRINTUS> Belépett egy kincs.");

kincsek.add(kincs);

szereplőHelyeKezdetben(kincs);

return toString();

}

/**

* A Szorny CORBA objektum az ORB-n keresztül belép a labirintusba.

*

* @param hős a Szorny CORBA objektum referenciája.

* @return String a labirintus állapotát bemutató string.

*/

public String belepSzorny(Szorny szörny) {

System.out.println("LABIRINTUS> Belépett egy szörny.");

szörnyek.add(szörny);

szereplőHelyeKezdetben(szörny);

return toString();

}

/**

* A szereplő labirintusbeli kezdő pozíciójának meghatározása.

*/

void szereplőHelyeKezdetben(Szereplo szereplő) {

// Többször próbálkozunk elhelyezni a szereplőt a labirintusban,

// számolja, hol tartunk ezekkel a próbálkozásokkal:

int számláló = 0, oszlop = 0, sor = 0;

do {

// itt +2,-2-k, hogy a bal alsó saroktól távol tartsuk

// a szereplőket, mert majd ezt akarjuk a hős kezdő pozíciójának

oszlop = 2+véletlenGenerátor.nextInt(szélesség-2);

sor = véletlenGenerátor.nextInt(magasság-2);

// max. 10-szer próbálkozunk, de ha sikerül nem "falba tenni" a

// szereplőt, akkor máris kilépünk:

} while(++számláló<10 && fal(oszlop, sor));

Page 265:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

237 Created by XMLmind XSL-FO Converter.

szereplő.oszlop(oszlop);

szereplő.sor(sor);

}

/** A játék időbeli fejlődésének vezérlése. */

public void run() {

while(true) {

idoegyseg();

System.out.println(this);

synchronized(hősök) {

Iterator i = hősök.iterator();

while(i.hasNext()) {

Hos hős = (Hos)i.next();

try {

switch(bolyong(hős)) {

case JÁTÉK_MEGY_HŐS_RENDBEN:

break;

case JÁTÉK_MEGY_MEGHALT_HŐS:

break;

case JÁTÉK_VÉGE_MEGHALT_HŐS:

i.remove();

break;

}

} catch (org.omg.CORBA.SystemException e) {

i.remove();

System.out.println("LABIRINTUS> " +

"Egy hőst eltávolítottam.");

}

}

}

}

}

/**

* Az ős megfelelő metódusának elfedése, az új CORBA szereplőket

* használva.

*

* @see TöbbHősösLabirintus#bolyong(Hős hős)

* @param hős aki a labirintusban bolyong.

* @return int a játék állapotát leíró kód.

*/

public int bolyong(Hos hős) {

for(Kincs kincs : kincsek) {

if(kincs.megtalalt(hős))

hős.megtalaltam(kincs);

}

for(Szorny szörny : szörnyek) {

if(szörny.lep(hős)) {

if(hős.megettek())

return JÁTÉK_VÉGE_MEGHALT_HŐS;

else

return JÁTÉK_MEGY_MEGHALT_HŐS;

}

}

return JÁTÉK_MEGY_HŐS_RENDBEN;

Page 266:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

238 Created by XMLmind XSL-FO Converter.

}

/**

* Megadja, hogy milyen gyorsan telik az idő a játékban.

*/

private void idoegyseg() {

++idő;

try {

Thread.sleep(1000);

} catch(InterruptedException e) {}

}

/**

* Madadja, hogy van-e szörny a labirintus adott oszlop,

* sor pozíciója.

*

* @param oszlop a labirintus adott oszlopa

* @param sor a labirintus adott sora

* @return true ha van.

*/

boolean vanSzörny(int sor, int oszlop) {

boolean van = false;

for(Szorny szörny: szörnyek)

if(sor == szörny.sor()

&& oszlop == szörny.oszlop()) {

van = true;

break;

}

return van;

}

/**

* Madadja, hogy van-e megtalálható kincs a labirintus

* adott oszlop, sor pozíciója.

*

* @param oszlop a labirintus adott oszlopa

* @param sor a labirintus adott sora

* @return true ha van.

*/

boolean vanKincs(int sor, int oszlop) {

boolean van = false;

for(Kincs kincs: kincsek)

if(sor == kincs.sor()

&& oszlop == kincs.oszlop()

&& !kincs.megtalalva()) {

van = true;

break;

}

return van;

}

/**

* Kinyomtatja a labirintus szerkezetét és szereplőit a System.out-ra.

*

* @param hős akit szintén belenyomtat a labirintusba.

*/

public void nyomtat(Hos hős) {

for(int i=0; i<magasság; ++i) {

for(int j=0; j<szélesség; ++j) {

boolean vanSzörny = vanSzörny(i, j);

boolean vanKincs = vanKincs(i, j);

boolean vanHős = (i == hős.sor() && j == hős.oszlop());

if(szerkezet[i][j])

System.out.print("|FAL");

else if(vanSzörny && vanKincs && vanHős)

Page 267:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

239 Created by XMLmind XSL-FO Converter.

System.out.print("|SKH");

else if(vanSzörny && vanKincs)

System.out.print("|SK ");

else if(vanKincs && vanHős)

System.out.print("|KH ");

else if(vanSzörny && vanHős)

System.out.print("|SH ");

else if(vanKincs)

System.out.print("|K ");

else if(vanHős)

System.out.print("|H ");

else if(vanSzörny)

System.out.print("|S ");

else

System.out.print("| ");

}

System.out.println();

}

}

/**

* A labirintus sztring reprezentációja.

*

* @return String labirintus sztring reprezentációja.

*/

public String toString() {

return " Idő:" + idő

+ " hős:" + hősök.size()

+ " kincs:" + kincsek.size()

+ " szörny:" + szörnyek.size();

}

}

1.7.1.6. A CORBA interfész definíciók

Az előző pontokban ismertetett öt Java osztály a elosztott.idl interfész definíciós állományban leírt öt

CORBA objektum kiszolgálói. A valóságban persze ezzel kezdődik a tervezés. A játék OO világát ezekkel az

IDL nyelvű interfészekkel feszítjük ki. Ezt követheti az implementációs nyelv kiválasztása, ami esetünkben a

Java, majd az ennek a választásnak megfelelő fordítót, esetünkben a JDK-beli idlj fordítót használva a CORBA

kommunikációhoz szükséges Java források legenerálása és a saját kiszolgáló objektumok megírása. Ez királyi

út, csupán az implementálandó szolgáltatások megvalósítására kell figyelnünk.

module javattanitok

{

module elosztott

{

module objektumok

{

interface Szereplo

{

attribute long oszlop;

attribute long sor;

};

interface Kincs;

interface Hos : Szereplo

{

attribute long megtalaltErtekek;

readonly attribute long eletek;

void megtalaltam(in Kincs kincs);

boolean megettek();

};

interface Kincs : Szereplo

{

attribute long ertek;

readonly attribute boolean megtalalva;

Page 268:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

240 Created by XMLmind XSL-FO Converter.

boolean megtalalt(in Hos hos);

};

interface Szorny : Szereplo

{

boolean lep(in Hos hos);

};

interface Labirintus

{

wstring belepHos(in Hos hos);

wstring belepKincs(in Kincs kincs);

wstring belepSzorny(in Szorny szorny);

};

};

};

};

1.7.1.7. Az ElosztottLabirintus osztály

Ez az osztály tölti be leginkább a szerver szerepét, mert ő élteti a labirintust kiszolgáló objektumot.

/*

* ElosztottLabirintus.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

import javattanitok.elosztott.*;

/**

* Az elosztott CORBA-s labirintus csomag absztrahálta elosztott labirintus

* mikrovilágának egy szerver oldali (delegációs POA/Tie leképezéses) életre

* keltésére ad példát ez az osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.LabirintusVilág

* @see javattanitok.LabirintusApplet

* @see javattanitok.LabirintusJáték

* @see javattanitok.LabirintusMIDlet

* @see javattanitok.LabirintusServlet

* @see javattanitok.HálózatiLabirintus

* @see javattanitok.TávoliLabirintus

* @see ElosztottKliens

* @see LabirintusKiszolgáló

* @see elosztott.idl

*/

public class ElosztottLabirintus {

/** A <code>ElosztottLabirintus</code> objektum elkészítése. */

public ElosztottLabirintus() {

// A CORBA szerver indítása

try{

// Az ORB tulajdonságainak megadása

java.util.Properties orbTulajdonságok =

new java.util.Properties();

orbTulajdonságok.put("org.omg.CORBA.ORBInitialPort", "2006");

orbTulajdonságok.put("org.omg.CORBA.ORBInitialHost", "localhost");

// Az ORB (a metódushívások közvetítőjének) inicializálása

org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init((String [])null,

orbTulajdonságok);

// A gyökér POA CORBA objektum referenciájának megszerzése

org.omg.CORBA.Object corbaObjektum = orb.

resolve_initial_references("RootPOA");

// CORBA-s típuskényszerítéssel a megfelelőre

org.omg.PortableServer.POA gyökérPoa =

org.omg.PortableServer.POAHelper.narrow(corbaObjektum);

Page 269:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

241 Created by XMLmind XSL-FO Converter.

// A POA kiszolgáló állapotba kapcsolása:

gyökérPoa.the_POAManager().activate();

// A Labirintus kiszolgáló objektum elkészítése,

// a delegációs/POA/Tie modell szerinti leképezéssel

javattanitok.elosztott.objektumok.LabirintusPOATie tie =

new javattanitok.elosztott.objektumok.LabirintusPOATie(

new LabirintusKiszolgáló(), gyökérPoa);

// A Labirintus CORBA objektum

javattanitok.elosztott.objektumok.Labirintus labirintus =

tie._this(orb);

// A névszolgáltató gyökerének, mint CORBA objektum

// referenciájának megszerzése

corbaObjektum =

orb.resolve_initial_references("NameService");

org.omg.CosNaming.NamingContextExt névszolgáltatóGyökere

= org.omg.CosNaming.

NamingContextExtHelper.narrow(corbaObjektum);

// A kiszolgáló objektum bejegyzése a névszolgáltatóba

org.omg.CosNaming.NameComponent név[] =

névszolgáltatóGyökere.to_name("ElosztottLabirintus");

névszolgáltatóGyökere.rebind(név, labirintus);

// Várakozás a szereplők (hősök, kincsek, szörnyek) jelentkezésére

orb.run();

} catch (Exception e) {

e.printStackTrace();

System.exit(-1);

}

}

/**

* Elindítja az elosztott labirintust világának labirintus részét.

*

* @param args nincsenek parancssor-argumentumok.

*/

public static void main(String[] args) {

new ElosztottLabirintus();

}

}

1.7.1.8. Az ElosztottKliens osztály

Ez az osztály tölti be leginkább a kliens szerepét, mert ő élteti a labirintust szereplőit kiszolgáló objektumokat,

akiket számtalan esetben hívnak vissza más szereplők vagy a labirintus: ebben az értelemben viszont szerver.

/*

* ElosztottKliens.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

import javattanitok.elosztott.*;

/**

* Az elosztott CORBA-s labirintus csomag absztrahálta elosztott labirintus

* mikrovilágának egy kliens oldali életre keltésére ad példát ez az osztály,

* mely egyben a szereplő objektumok visszahívható szervere is.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see ElosztottLabirintus

* @see SzereplőKiszolgáló

Page 270:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

242 Created by XMLmind XSL-FO Converter.

* @see HősKiszolgáló

* @see SzörnyKiszolgáló

* @see KincsKiszolgáló

*/

public class ElosztottKliens implements Runnable {

org.omg.CORBA.ORB orb; // hogy a run()-ból elérjük őket

javattanitok.elosztott.objektumok.Labirintus labirintus;

/**

* Elkészíti a távol gépre bejelentkező hős, szörny vagy

* kincs visszahívható kliens CORBA objektumot. Hősként

* való indításakor feldolgozza a játékostól jövő billentyű

* parancsokat.

*

* @param args első tagja "hős" - Hos objektum, "kincs" -

* Kincs objektum, "szörny" - Szorny objektum lesz a kliens,

* alapértelmezés a "kincs".

*/

public ElosztottKliens(String[] args) {

String ki = null;

// ha nem adtuk meg a parancssor-argumentumot,

// akkor ez az alapértelmezés:

if(args.length != 1)

ki = "Kincs";

else

ki = args[0];

try {

// Az ORB tulajdonságainak megadása

java.util.Properties orbTulajdonságok = new java.util.Properties();

orbTulajdonságok.put("org.omg.CORBA.ORBInitialHost",

"172.21.0.152");

orbTulajdonságok.put("org.omg.CORBA.ORBInitialPort", "2006");

// Az ORB (a metódushívások közvetítőjének) inicializálása

orb = org.omg.CORBA.ORB.init((String [])null,

orbTulajdonságok);

// A névszolgáltató gyökerének, mint CORBA objektum

// referenciájának megszerzése

org.omg.CORBA.Object corbaObjektum =

orb.resolve_initial_references("NameService");

org.omg.CosNaming.NamingContextExt névszolgáltatóGyökere

= org.omg.CosNaming.

NamingContextExtHelper.narrow(corbaObjektum);

// A labirintus CORBA objektum referenciájának megszerzése

labirintus =

javattanitok.elosztott.objektumok.

LabirintusHelper.narrow(névszolgáltatóGyökere.

resolve_str("ElosztottLabirintus"));

// A gyökér POA CORBA objektum referenciájának megszerzése

corbaObjektum = orb.resolve_initial_references("RootPOA");

// CORBA-s típuskényszerítéssel a megfelelőre

org.omg.PortableServer.POA gyökérPoa =

org.omg.PortableServer.POAHelper.narrow(corbaObjektum);

// A POA kiszolgáló állapotba kapcsolása:

gyökérPoa.the_POAManager().activate();

// Miként indították ezt a klienst?

if("hős".equals(ki)) {

// Ha a kliens hősként működik

// A Hos kiszolgáló objektum elkészítése,

// a delegációs/POA/Tie modell szerinti leképezéssel

javattanitok.elosztott.objektumok.HosPOATie tie =

new javattanitok.elosztott.objektumok.HosPOATie(

new HősKiszolgáló(), gyökérPoa);

// A Hos CORBA objektum

javattanitok.elosztott.objektumok.Hos hős = tie._this(orb);

System.out.println("HŐS> ELkészültem: " + hős);

// Távoli metódus hívása, a távoli CORBA labirintus

// objektumnak átadkuk a Hos CORBA objektum referenciáját

System.out.println(labirintus.belepHos(hős));

Page 271:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

243 Created by XMLmind XSL-FO Converter.

new Thread(this).start();

// CORBA szerverként is üzemelünk, mert a Hos

// objektumot a Labirintus objektum majd visszahívogatja

orb.run();

} else if("szörny".equals(ki)) {

// Ha a kliens szörnyként működik

javattanitok.elosztott.objektumok.SzornyPOATie tie =

new javattanitok.elosztott.objektumok.SzornyPOATie(

new SzörnyKiszolgáló(), gyökérPoa);

javattanitok.elosztott.objektumok.Szorny szörny =

tie._this(orb);

System.out.println(labirintus.belepSzorny(szörny));

orb.run();

} else {

// Ha a kliens kincsként működik

javattanitok.elosztott.objektumok.KincsPOATie tie =

new javattanitok.elosztott.objektumok.KincsPOATie(

new KincsKiszolgáló(), gyökérPoa);

javattanitok.elosztott.objektumok.Kincs kincs =

tie._this(orb);

System.out.println(labirintus.belepKincs(kincs));

orb.run();

}

} catch (Exception e) {

e.printStackTrace();

}

}

/** A hős játékostól jövő billentyűzet input feldolgozása. */

public void run() {

try {

// Feldolgozzuk a játékostól jövő billentyű parancsokat

java.io.BufferedReader konzol =

new java.io.BufferedReader(

new java.io.InputStreamReader(System.in));

String parancs = null;

while((parancs = konzol.readLine()) != null) {

System.out.println(parancs);

// A Hos CORBA objektum kilép a labirintusból

if("k".equals(parancs))

break;

// További lépés parancsok itt implemetálva: föl, le stb. ...

}

} catch(java.io.IOException e) {

System.out.println(e);

}

orb.shutdown(false);

System.exit(0);

}

/** Az elosztott labirintus klienseinek indítása.

*

* @param args első tagja "hős" - Hos objektum, "kincs" -

* Kincs objektum, "szörny" - Szorny objektum lesz a kliens,

* alapértelmezés a "kincs".

*/

public static void main(String[] args) {

new ElosztottKliens(args);

Page 272:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

244 Created by XMLmind XSL-FO Converter.

}

}

1.7.2. Az Elosztott labirintus fordítása és futtatása

A 172.21.0.152 gépen egy parancsablakban futtatjuk az idlj fordítót, hogy megkapjuk az alkalmazásunkhoz

tartozó CORBA specifikus Java forrásokat. Ezek az elosztott.idl interfész definíciós állomány modul

szerkezetének megfelelően a javattanitok\elosztott\objektumok könyvtárba íródnak ki. Ezután az egész

projektünket lefordítjuk.

C:\...\Munkakönyvtár> idlj -fall -falltie elosztott.idl

C:\...\Munkakönyvtár> javac javattanitok\*.java javattanitok\labirintus\*.java

javattanitok\elosztott\*.java

Note: Some input files use unchecked or unsafe operations.

Note: Recompile with -Xlint:unchecked for details.

A 172.21.0.152 gépen, mondjuk egy másik parancsablakban elindítjuk az orbd ORB démont. A démonnal

együtt a névszolgáltatás is elindul. Az ElosztottLabirintus szerver objektum a kiszolgáló

LabirintusKiszolgáló CORBA objektumot majd ElosztottLabirintus néven jegyzi be ide. Annak a

CORBA kliens alkalmazásnak, aki el akarja érni ezt a bejegyzett LabirintusKiszolgáló CORBA objektumot,

nem kell mást tennie, mint megszerezni a 172.21.0.152 hoszt 2006-os kapujánál figyelő ORB névszolgáltatást

végző objektumának referenciáját és ettől az objektumtól elkérni a nála bejegyzett ElosztottLabirintus

névhez tartozó CORBA objektum eferenciát, de ne szaladjunk ennyire messzire, egyelőre indítsuk tehát az ORB

démont!

C:\Documents and Settings\norbi> start orbd -ORBInitialPort 2006 -ORBInitialHost

172.21.0.152

Az elosztott labirintus egy gépen

Ha a kedves Olvasó egyetlen gépen szeretné tesztelni a példát, akkor a parancssorban és a

ElosztottKliens.java forrásban a 172.21.0.152 helyett használja a localhost-ot!

Ugyancsak a 172.21.0.152 gépen, mondjuk abban a parancsablakban, melyben a fordítást végeztük, indítsuk

el a labirintus CORBA objektumot, pontosabban az objektumot elkészítő és a névszolgáltatóban bejegyző

szervert, az ElosztottLabirintus osztályt!

C:\...\Munkakönyvtár> java javattanitok.ElosztottLabirintus

Idő:1 hős:0 kincs:0 szörny:0

Idő:2 hős:0 kincs:0 szörny:0

Idő:3 hős:0 kincs:0 szörny:0

...

A labirintusunk időfejlődésének minden pillanatában kiírja fő jellemzőit, hogy éppen hány hős, kincs és szörny

van benne.

Még mindig ugyanazon a 172.21.0.152 gépen, de egy másik parancsablakban futtassunk egy kincset!

C:\...\Munkakönyvtár> java javattanitok.ElosztottKliens

Page 273:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

245 Created by XMLmind XSL-FO Converter.

SZEREPLŐ> Beállították a pozíciómat.

Idő:12 hős:0 kincs:1 szörny:0

A parancssor paraméter nélkül induló ElosztottKliens CORBA kliens KincsKiszolgáló objektumot készít,

a névszolgáltatón keresztül megszerzi a labirintus referenciáját, majd átadja a kliensként - a most éppen

kincsként - elkészített CORBA objektum referenciáját a labirintusnak. Aki immár majd ezt a referenciát

felhasználva anélkül tudja visszahívni a kincs klienst, hogy a kincs bármely névszolgáltatóba be lenne jegyezve.

Közben a Parancssor - java javattanitok.ElosztottLabirintus ablakban a labirintus logolja a

bejelentkező klienst.

...

Idő:10 hős:0 kincs:0 szörny:0

Idő:11 hős:0 kincs:0 szörny:0

LABIRINTUS> Belépett egy kincs.

Idő:12 hős:0 kincs:1 szörny:0

Idő:13 hős:0 kincs:1 szörny:0

...

Továbbra is ugyanazon a 172.21.0.152 gépen, de megint egy újabb parancsablakban futtassunk most egy

szörnyet!

C:\...\Munkakönyvtár> java javattanitok.ElosztottKliens szörny

SZEREPLŐ> Beállították a pozíciómat.

Idő:42 hős:0 kincs:1 szörny:1

...

Közben megint csak a Parancssor - java javattanitok.ElosztottLabirintus ablakban a labirintus

logolja az éppen bejelentkett szörny klienst.

...

Idő:40 hős:0 kincs:1 szörny:0

Idő:41 hős:0 kincs:1 szörny:0

LABIRINTUS> Belépett egy szörny.

Idő:42 hős:0 kincs:1 szörny:1

Idő:43 hős:0 kincs:1 szörny:1

...

Még továbbra is ugyanazon a 172.21.0.152 gépen, de megint csak egy újabb parancsablakban futtassunk most

egy hőst!

C:\...\Munkakönyvtár> java javattanitok.ElosztottKliens hős

HŐS> ELkészültem: IOR:000000000000002e49444c3a6a6176617474616e69746f6b2f656c6f73

7a746f74742f6f626a656b74756d6f6b2f486f733a312e3000000000000001000000000000008600

0102000000000e3137322e31372e3133352e3631000d7800000031afabcb0000000020ffe655a100

000001000000000000000100000008526f6f74504f41000000000800000001000000001400000000

00000200000001000000200000000000010001000000020501000100010020000101090000000100

01010000000026000000020002

SZEREPLŐ> Beállították a pozíciómat.

Idő:68 hős:1 kincs:1 szörny:1

SZEREPLŐ> Lekérdezték a pozíciómat.

SZEREPLŐ> Lekérdezték a pozíciómat.

Page 274:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

246 Created by XMLmind XSL-FO Converter.

Interoperable Object Reference

Csupán az érdekesség kedvéért kiírattuk a (kliens) hős objektum referenciáját (címét).

Közben a Parancssor - java javattanitok.ElosztottLabirintus ablakban a labirintus logolja a

bejelentkező hőst.

...

Idő:66 hős:0 kincs:1 szörny:1

Idő:67 hős:0 kincs:1 szörny:1

LABIRINTUS> Belépett egy hős: IOR:000000000000002e49444c3a6a6176617474616e69746

f6b2f656c6f737a746f74742f6f626a656b74756d6f6b2f486f733a312e300000000000000100000

00000000086000102000000000e3137322e31372e3133352e3631000d7800000031afabcb0000000

020ffe655a100000001000000000000000100000008526f6f74504f4100000000080000000100000

00014000000000000020000000100000020000000000001000100000002050100010001002000010

109000000010001010000000026000000020002

Idő:68 hős:1 kincs:1 szörny:1

Idő:69 hős:1 kincs:1 szörny:1

...

Interoperable Object Reference

Nem meglepő módon ezt az IOR referenciát ismeri a szerver oldal is.

A hős belépését követően - programozásunknak megfelelően - felélednek az eddig szunnyadó kliens ablakok. A

Parancssor - java javattanitok.ElosztottKliens ablakban a kincs logolását látjuk.

...

KINCS> Nem talált rám.

KINCS> Nem talált rám.

KINCS> Nem talált rám.

...

A Parancssor - java javattanitok.ElosztottKliens szörny ablakban a szörny objektum logolását

látjuk.

...

SZÖRNY> Lépek egy hős felé.

SZÖRNY> Lépek egy hős felé.

SZÖRNY> Lépek egy hős felé.

...

Most beléptetünk néhány további szereplőt egy másik, a 172.21.0.17 gépről. Hasonlóan itt is futtatjuk az idlj

fordítót és lefordítjuk a projektet.

C:\...\Munkakönyvtár> idlj -fall -falltie elosztott.idl

C:\...\Munkakönyvtár> javac javattanitok\*.java java ttanitok\labirintus\*.java

javattanitok\elosztott\*.java

Note: Some input files use unchecked or unsafe operations.

Note: Recompile with -Xlint:unchecked for details.

Page 275:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

247 Created by XMLmind XSL-FO Converter.

Majd most ebből az ablakból is indítunk egy kincset.

C:\...\Munkakönyvtár> java javattanitok.ElosztottKliens

SZEREPLŐ> Beállították a pozíciómat.

KINCS> Nem talált rám.

Idő:293 hős:1 kincs:2 szörny:1

KINCS> Nem talált rám.

KINCS> Nem talált rám.

KINCS> Nem talált rám.

Közben a másik, a 172.21.0.152 gép Parancssor - java javattanitok.ElosztottLabirintus ablakban

a labirintus logolja a most bejelentkező kincs klienst.

...

Idő:291 hős:1 kincs:1 szörny:1

Idő:292 hős:1 kincs:1 szörny:1

LABIRINTUS> Belépett egy kincs.

Idő:293 hős:1 kincs:2 szörny:1

Idő:294 hős:1 kincs:2 szörny:1

...

Továbbra is a 172.21.0.17 gépen, de megint egy újabb parancsablakban futtassunk most egy szörnyet!

C:\...\Munkakönyvtár> java javattanitok.ElosztottKliens szörny

SZEREPLŐ> Beállították a pozíciómat.

SZÖRNY> Lépek egy hős felé.

Idő:327 hős:1 kincs:2 szörny:2

SZÖRNY> Lépek egy hős felé.

SZÖRNY> Lépek egy hős felé.

...

Közben megint csak a 172.21.0.152 gép, Parancssor - java javattanitok.ElosztottLabirintus

ablakban a labirintus logolja ezt az éppen bejelentkezett szörny klienst.

...

Idő:325 hős:1 kincs:2 szörny:1

Idő:326 hős:1 kincs:2 szörny:1

LABIRINTUS> Belépett egy szörny.

Idő:327 hős:1 kincs:2 szörny:2

Idő:328 hős:1 kincs:2 szörny:2

...

Még továbbra is a 172.21.0.17 gépen maradva, egy újabb parancsablakból léptessünk be most egy hőst!

C:\...\Munkakönyvtár> java javattanitok.ElosztottKliens hős

HŐS> ELkészültem: IOR:000000000000002e49444c3a6a6176617474616e69746f6b2f656c6f73

7a746f74742f6f626a656b74756d6f6b2f486f733a312e3000000000000001000000000000008600

0102000000000e3137322e31372e3133352e353300055d00000031afabcb0000000020ffebeff400

Page 276:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java esettanulmányok

248 Created by XMLmind XSL-FO Converter.

000001000000000000000100000008526f6f74504f41000000000800000001000000001400000000

00000200000001000000200000000000010001000000020501000100010020000101090000000100

01010000000026000000020002

SZEREPLŐ> Beállították a pozíciómat.

Idő:359 hős:2 kincs:2 szörny:2

SZEREPLŐ> Lekérdezték a pozíciómat.

...

Interoperable Object Reference

A referenciát gondosan összehasonlítva az előzővel, a harmadik sor környékén látható a különbség.

A hős belépésének megfelelően a szerver oldal, azaz a 172.21.0.152 gép, a Parancssor - java

javattanitok.ElosztottLabirintus ablakban a labirintus logolja ezt az éppen bejelentkezett hős

objektumot.

...

Idő:357 hős:1 kincs:2 szörny:2

Idő:358 hős:1 kincs:2 szörny:2

LABIRINTUS> Belépett egy hős: .IOR:000000000000002e49444c3a6a6176617474616e69746

f6b2f656c6f737a746f74742f6f626a656b74756d6f6b2f486f733a312e300000000000000100000

00000000086000102000000000e3137322e31372e3133352e353300055d00000031afabcb0000000

020ffebeff400000001000000000000000100000008526f6f74504f4100000000080000000100000

00014000000000000020000000100000020000000000001000100000002050100010001002000010

109000000010001010000000026000000020002

Idő:359 hős:2 kincs:2 szörny:2

Idő:360 hős:2 kincs:2 szörny:2

...

Beléptethetünk további szereplőket, vagy a hősökkel ki is léphetünk a játékból. A játék programja ezt a legtöbb

esetben tolerálja:

...

Idő:369 hős:2 kincs:3 szörny:2

Idő:370 hős:2 kincs:3 szörny:2

LABIRINTUS> Egy hőst eltávolítottam.

Idő:371 hős:1 kincs:3 szörny:2

Idő:372 hős:1 kincs:3 szörny:2

...

de könnyen előfordulhatnak kivételek, amikor már nem létező CORBA objektumoknak akarunk üzenetet

küldeni.

Page 277:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

249 Created by XMLmind XSL-FO Converter.

4. fejezet - Példaprogramok

1. A csomagok szervezése

Jelen fejezetben összefoglaljuk az esettanulmányok osztályait. Az előző fejezetben bemutattuk ezeknek az

osztályoknak a - megjegyzésekkel gazdagon ellátott - forráskódjait. Az előzőt megelőző fejezetek ezekből a

forrásokból tartalmaznak kiragadott és sokszor leegyszerűsített forráskód részleteket. Illetve ebben a fejezetben

találjuk a labirintus példák olyan forrásait, amit eddig még nem közöltünk, például a LabirintusAlkalmazás

forrását.

1.1. A példaprogramok forrásainak letöltése

A könyvhöz készített források használatára azt javasoljuk, hogy az Olvasó a kézikönyv böngészhető

változatából jelölje ki a kívánt kódot majd - követve a kód mellett szereplő, erre vonatkozó instrukcióinkat -

illessze be a megfelelő forrásállományba! Így kerülhetők el legnagyobb valószínűséggel a különböző

platformokon (például Windows vagy Linux) való felhasználás során esetlegesen jelentkező karakterkódolási

problémák. De jelen javaslatunk ellenére egy zip tömörített állományban is letölthetővé tettük a megfelelő

csomagokba szervezett forrásokat. Ezt a javat_tanitok_forrasok.zip állományt - a kézikönyv böngészhető

változatában - a következő linket követve érheti el a kedves Olvasó:

• javat_tanitok_forrasok.zip

A javat_tanitok_forrasok.zip tömör állományba gyűjtött források elkészítésénél úgy jártunk el, hogy a

forrásokat magából a kézikönyvből másoltuk (és próbáltuk) ki, így a kedves Olvasónak nem lehet gondja a

példák kipróbálásával, ha követi a kézikönyv utasításait.

A javattanitok könyvtárban találjuk a labirintusos példákat. Ezek közül azokat gyűjtöttük ki ide a

kézikönyvből, amelyek kipróbálása a kézikönyv fő sodrában van leírva. (De például a szintén labirintusos

LabirintusAlkalmazás.java forrást nem vettük ide, az csak a kézikönyvben szerepel.

A nehany_egyeb_pelda könyvtárba pedig a kézikönyv számos egyéb példája közül csupán néhány

kiválasztottat válogattunk be. A többi esetén azt az általános elvet kövessük, hogy a forrást vágjuk ki a

kézikönyv (pl. böngészhető) változatából és a kipróbálással kövessük a kézikönyv utasításait.

Az esettanulmányokban használt ikonokat, egyszerű képeket a javat_tanitok_kepek.zip archívumba

gyűjtöttük össze, ezt hasonlóan a következő linket követve érheti el:

• javat_tanitok_kepek.zip

1.2. javattanitok.labirintus csomag

Egy labirintus mikrovilágának leírására mutatnak példát ennek a csomagnak az osztályai. A csomagban

megszervezett osztályhierarchia a következő:

java.lang.Object

javattanitok.labirintus.Labirintus

javattanitok.labirintus.GenerikusLabirintus

javattanitok.labirintus.TöbbHősösLabirintus

javattanitok.labirintus.Szereplő

javattanitok.labirintus.Hős

javattanitok.labirintus.Kincs

javattanitok.labirintus.Szörny

java.lang.Throwable (implements java.io.Serializable)

java.lang.Exception

javattanitok.labirintus.RosszLabirintusKivétel

Page 278:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Példaprogramok

250 Created by XMLmind XSL-FO Converter.

1.3. javattanitok.elosztott csomag

Egy elosztott labirintus mikrovilágának leírására mutatnak példát ennek a csomagnak az osztályai. A csomagban

megszervezett osztályhierarchia a következő:

java.lang.Object

javattanitok.labirintus.Labirintus

javattanitok.labirintus.TöbbHősösLabirintus

javattanitok.elosztott.LabirintusKiszolgáló

(implements java.lang.Runnable)

javattanitok.elosztott.objektumok.SzereploPOA

javattanitok.elosztott.SzereplőKiszolgáló

javattanitok.elosztott.HősKiszolgáló

javattanitok.elosztott.KincsKiszolgáló

javattanitok.elosztott.SzörnyKiszolgáló

A CORBA objektumok hierarchiája a következő:

javattanitok.elosztott.objektumok.Szereplo

javattanitok.elosztott.objektumok.Hos

javattanitok.elosztott.objektumok.Kincs

javattanitok.elosztott.objektumok.Szorny

javattanitok.elosztott.objektumok.Labirintus

1.4. javattanitok csomag

A labirintus és az elosztott labirintus mindenféle életre keltésére példát mutató osztályokat szerveztük ebbe a

csomagba. A javattanitok.labirintus és a javattanitok.elosztott csomagok absztrahálta labirintusok

mikrovilágainak a legfőbb életre keltései következők:

1. Tiszta objektumorientált

2. Appletes

3. Teljes képernyős (Full Screen Exclusive Mode API)

4. MIDlet-es (mobiltelefonos)

5. Szervletes,

6. TCP/IP-s,

7. Java RMI-s,

8. CORBA-s

9. Elosztott

A csomagban megszervezett osztályhierarchia a következő:

java.lang.Object

java.awt.Component (implements

java.awt.image.ImageObserver, java.awt.MenuContainer,

java.io.Serializable)

java.awt.Container

java.awt.Panel (implements

Page 279:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Példaprogramok

251 Created by XMLmind XSL-FO Converter.

javax.accessibility.Accessible)

java.applet.Applet

javattanitok.LabirintusApplet

(implements

java.awt.event.KeyListener)

java.awt.Window (implements

javax.accessibility.Accessible)

java.awt.Frame (implements

java.awt.MenuContainer)

javattanitok.LabirintusAlkalmazás

(implements java.awt.event.KeyListener)

javattanitok.LabirintusJáték

(implements java.lang.Runnable)

javattanitok.ElosztottKliens

javattanitok.ElosztottLabirintus

javax.microedition.lcdui.game.GameCanvas

javattanitok.LabirintusVaszon (implements java.lang.Runnable)

javattanitok.HálózatiLabirintus (implements java.lang.Runnable)

javattanitok.KorbásLabirintus

javattanitok.TávoliLabirintus (implements javattanitok.TávoliHősíthető)

javax.servlet.http.HttpServlet

javattanitok.LabirintusServlet

javattanitok.KorbásKliens

javattanitok.LabirintusKiszolgálóSzál (implements java.lang.Runnable)

javattanitok.LabirintusVilág (implements java.lang.Runnable)

javattanitok.GenerikusLabirintusVilág

javax.microedition.midlet.MIDlet

javattanitok.LabirintusMIDlet

javattanitok.korbas.TavoliHosPOA

javattanitok.TávoliHősKiszolgáló

javattanitok.TávoliKliens

java.rmi.Remote

javattanitok.TávoliHősíthető

1.4.1. A LabirintusAlkalmazás osztály

Az alábbi LabirintusAlkalmazás osztály kódját A Musztáng című pontban tárgyaljuk részletesen.

/*

* LabirintusAlkalmazás.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

package javattanitok;

import java.awt.event.ActionEvent;

import javattanitok.labirintus.*;

/**

* A labirintus csomag absztrahálta labirintus mikrovilágának egy

* alkalmazásbeli életre keltésére ad példát ez az osztály, miközben

* bemutatja a Java 6 (Musztáng) néhány újdonságát.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

* @see javattanitok.LabirintusVilág

* @see javattanitok.LabirintusJáték

* @see javattanitok.LabirintusMIDlet

* @see javattanitok.LabirintusServlet

* @see javattanitok.HálózatiLabirintus

* @see javattanitok.TávoliLabirintus

* @see javattanitok.ElosztottLabirintus

*/

public class LabirintusAlkalmazás extends java.awt.Frame

Page 280:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Példaprogramok

252 Created by XMLmind XSL-FO Converter.

implements java.awt.event.KeyListener {

/** A labirintus. */

Labirintus labirintus;

/** A hős. */

Hős hős;

/** A játék vége után már nem veszünk át inputot a játékostól,

* illetve a játék világának állapota sem változik. */

boolean játékVége = false;

/** A játék vége után megjelenő üzenet. */

String végeÜzenet = "Vége a játéknak!";

// A labirintus szereplőihez rendelt képek

java.awt.Image falKép;

java.awt.Image járatKép;

java.awt.Image hősKép;

java.awt.Image szörnyKép;

java.awt.Image kincsKép;

/** Konstruktor.

*/

public LabirintusAlkalmazás() {

super("Labirintus alkalmazás");

/* itt kezdenénk, de most majd lejjebb

java.awt.SplashScreen indítóKépernyő

= java.awt.SplashScreen.getSplashScreen();

java.awt.Graphics2D g = indítóKépernyő.createGraphics(); ...

*/

labirintus = new Labirintus(6, 3);

hős = new Hős(labirintus);

hős.sor(9);

hős.oszlop(0);

falKép = new javax.swing.ImageIcon

("fal.png").getImage();

járatKép = new javax.swing.ImageIcon

("járat.png").getImage();

hősKép = new javax.swing.ImageIcon

("hős.png").getImage();

szörnyKép = new javax.swing.ImageIcon

("szörny.png").getImage();

kincsKép = new javax.swing.ImageIcon

("kincs.png").getImage();

// Ha a rendszerben támogatott az értesítési terület

if (java.awt.SystemTray.isSupported()) {

// akkor egy kis 16x16 pixel méretű

java.awt.Image ikonKép = new javax.swing.ImageIcon

("ikon.png").getImage();

// értesítő ikont

java.awt.TrayIcon értesítőIkon =

new java.awt.TrayIcon(ikonKép,

"Javat tanítok labirintus");

// most mi is kiteszünk

try {

java.awt.SystemTray.getSystemTray().

add(értesítőIkon);

} catch (java.awt.AWTException e) {

System.out.println("Értesítő ikon kitétele: "

+ e);

}

// amire ha duplán kattintunk, akkor

értesítőIkon.addActionListener(

new java.awt.event.ActionListener() {

public void actionPerformed(ActionEvent e) {

// például szorult helyzetéből kimenekítve a

// hőst, visszadobjuk a kiindulási pozíciójába

hős.sor(9);

hős.oszlop(0);

repaint();

}

});

}

Page 281:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Példaprogramok

253 Created by XMLmind XSL-FO Converter.

// amit be is lehet csukni

addWindowListener(new java.awt.event.WindowAdapter() {

public void windowClosing(java.awt.event.WindowEvent e) {

setVisible(false);

System.exit(0);

}

});

addKeyListener(this);

setSize(1024, 768);

// Hozzáférünk az indító képernyőhöz

java.awt.SplashScreen indítóKépernyő

= java.awt.SplashScreen.getSplashScreen();

// Ha sikerül, azaz, ha java -splash:kép állomány neve

// formában indítottuk és még látszik a kép

if(indítóKépernyő != null) {

// akkor rajzolni fogunk rá

java.awt.Graphics2D g = indítóKépernyő.createGraphics();

// némi szöveget, amit akár a rajzolóprogrammal is

// ráírhattunk volna

java.awt.Font font1 = new java.awt.Font("Sans",

java.awt.Font.BOLD, 20);

java.awt.Font font2 = new java.awt.Font("Monospaced",

java.awt.Font.BOLD, 12);

g.setFont(font1);

// világosabb sárgával

g.setColor(new java.awt.Color(250, 255, 138));

g.drawString("Javat tanítok labirintus", 8, 240);

g.setFont(font2);

g.drawString("Bátfai Norbert", 10, 265);

g.drawString("[email protected]", 10, 280);

// és rajzolunk egy a konkrét kép méretéhez igazított

// progress bar szerűséget (kommentben az indító

// képernyő méretéhez relatív adatok)

int sz = 382; // indítóKépernyő.getSize().width-10;

int barSzélesség = sz/10;

int m = 10; // indítóKépernyő.getSize().height;

int barMagasság = 6;

// itt szimuláljuk a játék időigényes dolgainak

// betöltését, 10 x fél másodperig altatjuk majd

// a szálunkat

for(int i = 0; i<10; ++i) {

// és ennek megfelelően frissítjük mit

// mutasson a progress bar-unk

g.setColor(java.awt.Color.WHITE);

g.drawRect(8, 285, //5, m-20,

10*barSzélesség, barMagasság);

g.fillRect(8, 285, //5, m-20,

10*barSzélesség, barMagasság);

g.setColor(java.awt.Color.YELLOW);

g.drawRect(8, 285, //5, m-20,

10*barSzélesség, barMagasság);

g.fillRect(8, 285, //5, m-20,

(i+1)*barSzélesség, barMagasság);

indítóKépernyő.update();

try {

// a fél másodperces altatás

// ez szimulálja pl., hogy töltjük be

// a már hatalmas labirintus játékunk

// képerőforrásait, készítjük a megfelelő

// adatszerkezeteket stb.

Thread.sleep(500);

} catch(Exception e) {}

}

}

setVisible(true);

}

/**

* A játékostól (aki a játék világában a hős) jövő input feldolgozása:

* a hős mozgatása a KURZOR billenytűkkel, illetve a játék világának

Page 282:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Példaprogramok

254 Created by XMLmind XSL-FO Converter.

* állapot változásait is innen irányítjuk.

*/

public void keyPressed(java.awt.event.KeyEvent billentyűEsemény) {

// Mit nyomott le?

int billentyű = billentyűEsemény.getKeyCode();

if(!játékVége) {

// Merre lép a hős?

switch(billentyű) {

// A KURZOR billentyűkkel foglalkozunk, a megfelelő irányba

// lépünk

case java.awt.event.KeyEvent.VK_UP:

hős.lépFöl();

break;

case java.awt.event.KeyEvent.VK_DOWN:

hős.lépLe();

break;

case java.awt.event.KeyEvent.VK_RIGHT:

hős.lépJobbra();

break;

case java.awt.event.KeyEvent.VK_LEFT:

hős.lépBalra();

break;

}

// A játék világának állapot változása: azaz a játék többi

// szereplője is lép. Ha ezzel a lépéssel a játék világában

// történt valami lényeges: pl. vége a játéknak vagy egy szörny

// elkapta a hőst, akkor reagálunk:

switch(labirintus.bolyong(hős)) {

case Labirintus.JÁTÉK_MEGY_HŐS_RENDBEN:

break;

case Labirintus.JÁTÉK_MEGY_MEGHALT_HŐS:

// Még van élete, visszatesszük a kezdő pozícióra

hős.sor(9);

hős.oszlop(0);

break;

case Labirintus.JÁTÉK_VÉGE_MINDEN_KINCS_MEGVAN:

végeÜzenet = "Győztél, vége a játéknak!";

játékVége = true;

break;

case Labirintus.JÁTÉK_VÉGE_MEGHALT_HŐS:

végeÜzenet = "Vesztettél, vége a játéknak!";

játékVége = true;

break;

}

// Amíg nincs vége a játéknak, újra rajzoljuk a

// játék felületét, hogy látszódjanak a játék állapotában

// bekövetkezett változások

repaint();

}

}

/**

* A KeyListener számunkra most érdektelen további metódusait üres

* testtel definiáljuk felül.

*/

public void keyTyped(java.awt.event.KeyEvent billentyűEsemény) {}

public void keyReleased(java.awt.event.KeyEvent billentyűEsemény) {}

/**

* Kirajzolja a játék felületét, azaz a labirintust és a benne szereplőket:

* a hőst, a kincseket és a szörnyeket.

*/

public void paint(java.awt.Graphics g) {

// A labirintus kirajzolása

for(int i=0; i<labirintus.szélesség(); ++i) {

for(int j=0; j<labirintus.magasság(); ++j) {

if(labirintus.szerkezet()[j][i])

g.drawImage(falKép, i*falKép.getWidth(this),

Page 283:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Példaprogramok

255 Created by XMLmind XSL-FO Converter.

j*falKép.getHeight(this), null);

else

g.drawImage(járatKép, i*járatKép.getWidth(this),

j*járatKép.getHeight(this), null);

}

}

// A kincsek kirajzolása

Kincs[] kincsek = labirintus.kincsek();

for(int i=0; i<kincsek.length; ++i) {

g.drawImage(kincsKép,

kincsek[i].oszlop()*kincsKép.getWidth(this),

kincsek[i].sor()*kincsKép.getHeight(this), null);

// Ha már megvan a kics, akkor áthúzzuk

if(kincsek[i].megtalálva()) {

g.setColor(java.awt.Color.red);

g.drawLine(kincsek[i].oszlop()*kincsKép.getWidth(this),

kincsek[i].sor()*kincsKép.getHeight(this),

kincsek[i].oszlop()*kincsKép.getWidth(this)

+ kincsKép.getWidth(this),

kincsek[i].sor()*kincsKép.getHeight(this)

+ kincsKép.getHeight(this));

g.drawLine(kincsek[i].oszlop()*kincsKép.getWidth(this)

+ kincsKép.getWidth(this),

kincsek[i].sor()*kincsKép.getHeight(this),

kincsek[i].oszlop()*kincsKép.getWidth(this),

kincsek[i].sor()*kincsKép.getHeight(this)

+ kincsKép.getHeight(this));

} else {

// ellenkező esetben kiírjuk az értékét

g.setColor(java.awt.Color.yellow);

g.drawString(""+kincsek[i].érték(),

kincsek[i].oszlop()*kincsKép.getWidth(this)

+ kincsKép.getWidth(this)/2,

kincsek[i].sor()*kincsKép.getHeight(this)

+ kincsKép.getHeight(this)/2);

}

}

// A szörnyek kirajzolása

Szörny[] szörnyek = labirintus.szörnyek();

for(int i=0; i<szörnyek.length; ++i)

g.drawImage(szörnyKép,

szörnyek[i].oszlop()*szörnyKép.getWidth(this),

szörnyek[i].sor()*szörnyKép.getHeight(this), null);

// A hős kirajzolása

g.drawImage(hősKép,

hős.oszlop()*hősKép.getWidth(this),

hős.sor()*hősKép.getHeight(this), null);

// A játék aktuális adataiból néhány kiíratása

g.setColor(java.awt.Color.black);

g.drawString("Életek száma: "+hős.életek(), 10, 40);

g.drawString("Gyűjtött érték: "+hős.pontszám(), 10, 60);

if(játékVége) {

g.setColor(java.awt.Color.black);

g.drawString(végeÜzenet, 420, 350);

}

}

/**

* A játék felületének kirajzolásakor ne legyen villogás, ezért

* az eredeti, a felület törlését elvégző update metódust felüldefiniáljuk.

*/

public void update(java.awt.Graphics g) {

paint(g);

}

/**

* A program alkalmazásként való indíthatóságát szolgálja.

*/

Page 284:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Példaprogramok

256 Created by XMLmind XSL-FO Converter.

public static void main(String[] args) {

// Ha itt van a vezérlés, akkor nem igaz az, hogy appletként indítottuk

new LabirintusAlkalmazás();

}

}

1.4.1.1. A LabirintusAlkalmazás kipróbálása

A Munkakönyvtár nevű munkakönyvtárunkba másoljuk be a 16x16 vagy 32x32 pixeles ikon.png ikont és A

Musztáng, a Java 6 újdonságait bemutató pontban részletesen tárgyalt inditokep.png indítóképet. Majd -

feltéve, hogy a labirintus API-t a korábbi pontokban már felélesztettük - fordíthatjuk és futtathatjuk az alábbiak

szerint:

$ javac javattanitok/LabirintusAlkalmazás.java

$ java -splash:inditokep.png javattanitok.LabirintusAlkalmazás

A futásról pillanatfelvételeket ugyancsak A Musztáng című pontban talál a kedves Olvasó.

A hős szorult helyzetben

A LabirintusAlkalmazás osztály az értesítési területen elhelyezett ikonon való kattintási

eseményeket is feldolgozza: példaként a szorult helyzetbe került hőst teleportálja a kezdeti pozícióba:

// amire ha duplán kattintunk, akkor

értesítőIkon.addActionListener(

new java.awt.event.ActionListener() {

public void actionPerformed(ActionEvent e) {

// például szorult helyzetéből kimenekítve a

// hőst, visszadobjuk a kiindulási pozíciójába

hős.sor(9);

hős.oszlop(0);

repaint();

}

});

Az API doksit figyelmesen tanulmányozó Olvasó a java.awt.TrayIcon osztály leírásánál láthatja,

hogy a jelen példán túl, az értesítési ikonhoz egy előugró menü is rendelhető.

Page 285:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

257 Created by XMLmind XSL-FO Converter.

5. fejezet - A példák kipróbálása

1. A Java telepítése gépünkre

1.1. A Java SE, Java ME fejlesztői csomag letöltése és beállítása

Mindig a legfrissebb verziójú Java SE, ME fejlesztői csomagokat használjuk. A Java telepítését az aktuális

Musztáng verzióval mutatjuk be. A Musztáng verzió teljes és hivatalos neve: Java Platform, Standard Edition 6,

röviden Java SE 6. Az ennek a platformnak megfelelő Java fejlesztői csomag a Java SE Development Kit 6,

röviden a JDK 6. Ezt kell letöltenünk, ha fejleszteni akarunk, márpedig mi fejleszteni akarunk. A Java

programok futtatásához a Java SE Runtime Environment 6 - Java Futtató Környezet, JRE 6 is elegendő, de ez

nem ad eszközöket, azaz lehetőséget a Java programozásra. Természetesen a JDK 6 használata esetén nincs

szükségünk a JRE-re.

Alapvetően két lehetőségünk van: vagy parancssorban dolgozunk, vagy egy integrált fejlesztői környezetet

használunk Java programjaink írásához. Az előbbi lehetőség bemutatásával kezdjük, de mindenkinek a

másodikat, a fejlesztői környezet használatát ajánljuk. Nemcsak a programozás kényelmi, hanem praktikus

szempontjai miatt is. Ezekre a NetBeans fejlesztői környezet telepítésének leírásakor majd rámutatunk.

Megjegyezhetjük, hogy a NetBeans letöltése kapcsán van olyan opciónk is, hogy egy olyan NetBeans IDE-t

töltünk le, ami mellé be van téve egy komplett JDK is, erről a kombinált lehetőségről írunk majd a NetBeans

IDE 5.5 című pontban.

1.1.1. Java SE Linux környezetben

Keressük fel a SUN Java fejlesztőknek szánt webhelyét: http://java.sun.com, itt néhány kattintás után a

„Downloads” alatt megtaláljuk a JDK 6-ot, vagy akár eggyel is a lap bal oldalának „Popular Downloads”

ablakában, a „Java SE 6 Beta 2” link választásával a http://java.sun.com/javase/downloads/ea.jsp korai

hozzáférés (mert a Musztáng még éppen béta) lapra jutunk, ahol a „JDK 6 Beta 2” letöltését választjuk.

A letöltési feltételek elfogadásának bekattintása után letölthetjük a mi gépünkre szánt Javat. Mivel mi most

éppen egy 64 bites Linuxon (egy Fedora Core 5 Linux operációs rendszerrel futó Sun W1100z Workstation

gépen akarunk dolgozni, ami már egy 64 bites rendszer) így a „Linux x64 Platform - Java(TM) SE Development

Kit 6 Beta 2” alól Linux környezetre a „Linux x64 in self-extracting file”, jdk-6-beta2-linux-amd64.bin

letöltését választjuk.

Tegyük fel, hogy a jdk-6-beta2-linux-amd64.bin állományt a /home/norbi/Java könyvtárba mentettük,

ekkor futási jogot adunk a letöltött állományra, majd lefuttatjuk.

[norbi@niobe Java]$ ls -l

total 48740

-rw-r--r-- 1 norbi norbi 49854400 Sep 9 11:32 jdk-6-beta2-linux-amd64.bin

[norbi@niobe Java]$ chmod +x jdk-6-beta2-linux-amd64.bin

[norbi@niobe Java]$ ./jdk-6-beta2-linux-amd64.bin

Lelkes SPACE billentyű nyomkodás, majd a yes begépelése után majdnem készen is vagyunk. Még azt kell

közölnünk a rendszerrel, hogy hol van az éppen most kicsomagolt Java: mindig a kicsomagolt

/home/norbi/Java/jdk1.6.0 könyvtár bin könyvtárával kell bővíteni az elérési utat

[norbi@niobe Java]$ export PATH=/home/norbi/Java/jdk1.6.0/bin:$PATH

[norbi@niobe Java]$ java -version

java version "1.6.0-beta2"

Java(TM) SE Runtime Environment (build 1.6.0-beta2-b86)

Java HotSpot(TM) 64-Bit Server VM (build 1.6.0-beta2-b86, mixed mode)

Page 286:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A példák kipróbálása

258 Created by XMLmind XSL-FO Converter.

igen, ez már a mi frissen feltett 6-os Javank.

Java kényelmesen

Ha nem akarjuk a fenti PATH beállítást minden olyan ablakban külön kiadni, ahol Javazni szeretnénk,

akkor ezt a parancsot érdemes bevenni egyszerű felhasználóként a .bash_profile állományunkba,

vagy esetleg rendszergazdaként a /etc/profile állományba. Például ezt írjuk az említett állományok

valamelyikének végére:

export PATH=/home/norbi/Java/jdk1.6.0/bin:$PATH

ezután, az újbóli bejelentkezésekkor már bármely kinyitott parancsablakból látszanak majd a Javas

parancsok, például a javac, a fordítót indító, vagy a java, a Java Virtuális Gépet indító parancs, az idlj,

az IDL fordítót, vagy az orbd, az ORB szoftvert indító parancsok.

1.1.2. Java SE Windows környezetben

Keressük fel a SUN Java fejlesztőknek szánt webhelyét: http://java.sun.com, itt néhány kattintás után a

„Downloads” alatt megtaláljuk a JDK 6-ot, vagy akár eggyel is a lap bal oldalának „Popular Downloads”

ablakában, a „Java SE 6 Beta 2” link választásával a http://java.sun.com/javase/downloads/ea.jsp korai

hozzáférés (mert a Musztáng még éppen béta) lapra jutunk, ahol a „JDK 6 Beta 2” letöltését választjuk.

A letöltési feltételek elfogadásának bekattintása után letölthetjük a mi gépünkre szánt Javat. Most éppen egy

Windowsra, így a „Windows Platform - Java(TM) SE Development Kit 6 Beta 2” Windows környezetre a

„Windows Offline Installation, Multi-language”, jdk-6-beta2-windows-i586.exe letöltését választjuk.

A letöltés után a letöltött exe állományt lefuttatjuk. Tegyük fel, hogy e futtatáskor a c:\Program

Files\Java\jdk1.6.0 könyvtárba telepítettük a Javat. Ha (Start/Kellékek/)Parancssor-ból akarjuk használni a

Javat, akkor még azt kell közölnünk a rendszerrel, hogy hol van az éppen most telepített Java: mindig a

kicsomagolt c:\Program Files\Java\jdk1.6.0 könyvtár bin könyvtárával kell bővíteni az elérési utat

C:\...> set PATH="c:\Program Files\Java\jdk1.6.0\bin";%PATH%

C:\Documents and Settings\norbi> java -version

java version "1.6.0-beta2"

Java(TM) SE Runtime Environment (build 1.6.0-beta2-b86)

Java HotSpot(TM) Client VM (build 1.6.0-beta2-b86, mixed mode, sharing)

igen, ez már a mi frissen feltett 6-os Javank.

Ha nem akarjuk a fenti PATH beállítást minden olyan ablakban külön kiadni, ahol Javazni szeretnénk, akkor a

PATH bővítését érdemes bevenni a Start/Vezérlőpult/Teljesítmény és karbantartás/ Rendszer/Speciális

fül/Környezeti változók gomb kattintása után a felhasználói vagy a rendszerváltozók közé.

Java 6

A kézikönyv írása végén vált elérhetővé a - béta2 és az RC után a - stabil Java 6.

Keressük fel a SUN Javas webhelyét: http://java.sun.com, itt néhány kattintás után (a „Downloads”

menüpont alatt a „Java SE” link választásával) a http://java.sun.com/javase/downloads/index.jsp, a

„Java SE Downloads” című lapra jutunk, ahonnan letölthetjük a parancssoros „JDK 6”-ot vagy a

NetBeans fejlesztői környezettel együtt elérhető „JDK 6 with NetBeans 5.5” név alatt belinkelt JDK-t.

A feltételek elfogadásának beixelése után letölthetjük a kívánt platformhoz (operációs rendszerhez)

tartozó Javat.

1.1.3. A Java dokumentáció, azaz az API doksi letöltése

Page 287:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A példák kipróbálása

259 Created by XMLmind XSL-FO Converter.

A fejlesztői csomag letöltésénél arra figyeltünk, hogy mindig a legfrissebb verziójú Java SE, ME fejlesztői

csomagokat használjuk. A dokumentációnál pedig arra kell tekintettel lennünk, hogy megfeleljen a használt

csomag verziójának. Ez nem nehéz, mert azon a lapon, ahonnan a fejlesztői csomagot letöltjük, megtaláljuk a

dokumentációt is.

Keressük fel a SUN webhelyét: http://java.sun.com, itt néhány kattintás után a „Downloads” alatt megtaláljuk a

JDK 6-ot, vagy akár eggyel is a lap bal oldalának „Popular Downloads” ablakában, a „Java SE 6 Beta 2” link

választásával a http://java.sun.com/javase/downloads/ea.jsp korai hozzáférés (mert a Musztáng még éppen béta)

lapra jutunk, ahol a „Java SE 6 Beta 2 Documentation” letöltését választjuk.

A letöltési feltételek elfogadásának bekattintása után letölthetjük a természetesen platformfüggetlen

dokumentációt. „Platform - Java(TM) SE Development Kit Documentation 6 Beta 2” Linux környezetre a „Java

SE Development Kit Documentation 6 Beta 2”, jdk-6-beta2-doc.zip letöltését választjuk.

Ezt a letöltött állományt kicsomagolva megtaláljuk benne a HTML dokumentációt, azaz egy böngészővel tudjuk

nézegetni. Ha az api könyvtárának index.html állományát kinyitjuk, akkor máris látjuk a szokásos három

frame-be szervezett Java SE API dokumentációt.

A SUN Javas http://java.sun.com webhelyén természetesen böngészhetjük on-line is a Java ME, SE vagy EE

dokumentációt. Illetve arra hívjuk még fel a figyelmet, hogy a NetBeans Mobility telepítése után a Java ME API

dokumentációt a netbeans-5.5\mobility7.3\emulators-inst\wtk22_win.zip és ezen a zip állományon

belül belül az emulator\wtk22\docs\api\midp könyvtárban is megtaláljuk.

1.1.4. Java ME

A Java ME beállításának egyik módja a Sun Java Wireless Toolkit letöltése, de mi inkább a NetBeans

környezeten belüli Netbeans Mobility használatát javasoljuk a mobilos fejlesztésekhez. Számos okból, amiket

majd a következő, a NetBeans beállításáról szóló részben bontunk ki, miközben kitérünk a Netbeans Mobility

letöltésére.

A Sun Java Wireless Toolkit letöltése kapcsán keressük fel a SUN webhelyét: http://java.sun.com, itt a

„Downloads” alatt a „Java ME” linket követve a http://java.sun.com/javame/downloads/index.jsp lapra jutunk,

ahonnan mindig a legfrissebb, most éppen a „Sun Java Wireless Toolkit 2.5 for CLDC, Beta” csomagot töltsük

le.

Külön állományt kell letöltenünk attól függően, hogy Linux vagy Windows környezetben akarunk-e dolgozni.

Mindkét esetben a Java SE telepítéséhez hasonlóan kell eljárnunk, azaz futtatni kell a letöltött állományt. De itt

nincs szükség az elérési út (azaz a PATH környezeti változó) állítására.

1.1.5. A NetBeans integrált fejlesztői környezet letöltése és használata

„Egy jó ideje már, hogy áttértem a NetBeans IDE használatára.” — James Gosling [GOSLING INTERJÚ]

A NetBeans integrált fejlesztői környezetet (NetBeans IDE) a http://www.netbeans.org/ webhelyről tölthetjük

le. De a NetBeans IDE letöltés be szokott lenni linkelve a SUN Javas http://java.sun.com webhelyére is, a lap

bal oldalának „Popular Downloads” ablakába. Itt a „NetBeans IDE” linket választva a

http://www.netbeans.org/downloads/index.html lapra kerülünk. Ha itt a „NetBeans IDE, Mobility Pack and

Profiler 5.0 downloads” 5.0 verziójú NetBeans IDE-t választjuk, akkor a

http://www.netbeans.info/downloads/download.php?type=5.0 lapra kerülve a kívánt operációs rendszer

kiválasztása után a „NetBeans IDE 5.5 Beta 2 Installer”-t és a „NetBeans Mobility Pack 5.0 Installer”-t töltsük

le. Mindkettő futtatható, nincs más dolgunk, mint (a fenti sorendben) lefuttatni őket. De inkább a már elérhető

5.5 változatot töltsük le! A http://www.netbeans.org/downloads/index.html lapon a „NetBeans IDE 5.5 Beta 2”

választásával, a http://www.netbeans.info/downloads/download.php?type=5.5b2 lapra kerülve a kívánt

operációs rendszer kiválasztása után a „NetBeans IDE 5.5 Beta 2 Installer”-t és a „NetBeans Mobility 5.5 Beta 2

Installer”-t töltsük le.

A NetBeans letöltése kapcsán van olyan opciónk is, hogy egy olyan NetBeans IDE-t töltünk le, ami mellé be

van téve egy komplett JDK is, erről a kombinált lehetőségről írunk majd a következő NetBeans IDE 5.5 című

pontban.

Page 288:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A példák kipróbálása

260 Created by XMLmind XSL-FO Converter.

Miért válasszuk a fejlesztéshez a NetBeans IDE-t a parancssoros fejlesztéssel szemben? Számos okból.

Ismertessünk ezek közül néhányat:

• a fordítási hibák figyelése és jelzése a szövegszerkesztőben folyamatos

• a szövegszerkesztő adja a szokásos kényelmi szolgáltatásokat, mint például a csomag és osztálynevek,

példány és metódusnevek automatikus beírása

• szervletek írásánál könnyű tesztelési (menüből kattintható) lehetőséget biztosít

• mobil fejlesztéseknél különösen fontos, hogy az IDE tartalmazzon egy megfelelő verziójú obfuszkátort, amit

így nem kell külön letölteni és beállítani.

1.1.6. A NetBeans IDE 5.5

A kézikönyv írása közben vált elérhetővé a NetBeans IDE 5.5 immár nem béta verziója. Ezt a

http://java.sun.com/javase/downloads/index.jsp lapon a „JDK 5.0 Update 9 with NetBeans 5.5” linket követve,

vagy közvetlenül a http://java.sun.com/j2se/1.5.0/download-netbeans.html, a „Download J2SE Development Kit

5.0 Update 9 with NetBeans IDE 5.5 Bundle” lapról tölthetjük le. Ennek az érdekessége, mint ahogyan az a link

nevéből is kiderül, hogy nemcsak a NetBeans környezetet, hanem egyben a megfelelő JDK 5 csomagot is

letölthetjük. A linket követve Linux alá a „J2SE(TM) and NetBeans(TM) IDE Cobundle (J2SE 1.5.0 U9 / NB

5.5) Linux”, a jdk-1_5_0_09-nb-5_5-linux.bin 114.40 megás állományt töltsük le. Windows alá pedig a

„J2SE(TM) and NetBeans(TM) IDE Cobundle (J2SE 1.5.0 U9 / NB 5.5) Windows”, a jdk-1_5_0_09-nb-5_5-

win.exe 114.27 megás állományt.

Az 5.5 IDE környezetnek megfelelő NetBeans Mobility csomagot a

http://www.netbeans.info/downloads/index.php lap „NetBeans Mobility Pack 5.5 Download” linkjét követve

érhetjük el.

2. A példaprogramok futtatásáról általában

A példák teljes kódját közöljük a kézikönyvben. Tipikusan a közlés helyén példát mutatunk a programok

felélesztésére és futtatására is. Általában annyit mondhatunk, hogy - tapasztalataink szerint - az Olvasónak a

példák kipróbálásával kapcsolatban az a jellemző problémája, hogy a közölt forráskódrészleteket nem kellő

gondossággal jelöli ki és illeszti be kedvenc szövegszerkesztőjébe, amiből fordítási hibák következnek.

Tipikusan ilyen, hogy a több oldalas programból csak részeket jelöl ki Olvasó, vagy lehagyja néhány sor végét a

kijelölésből. Illetve, ha a kijelölés a pdf olvasóban történik, akkor az olvasótól és a beállításaitól függően akár

oldalszámok is lehetnek a kijelölésben, amik a program szövegében idegen elemek, így természetesen fordítási

hibát okoznak. Ezért javasoljuk, hogy a kézikönyv böngészhető változatából másolja ki az Olvasó a

forráskódokat.

Fordítás Linux alatt

Kérdés: Linux (Fedora Core 5) alatt nem tudom lefordítani az ékezetes betűket tartalmazó osztályokat.

Válasz: Rendszergazdaként a /etc/sysconfig/i18n állományban állítsuk magyarra a lokális

környezetet! Tehát a /etc/sysconfig/i18n állomány a következőket tartalmazza:

LANG="hu_HU.ISO-8859-2"

LC_ALL="hu_HU.ISO-8859-2"

Kérdés: Linux (Fedora Core 6) alatt nem tudom lefordítani az ékezetes betűket tartalmazó osztályokat.

Válasz: Ha maguk az állomány nevek rendben vannak, mert mondjuk eleve Linux alatt készítettük el

őket, akkor elegendő a fordításnál az encoding kapcsoló használata, például:

Page 289:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

A példák kipróbálása

261 Created by XMLmind XSL-FO Converter.

$ javac -encoding ISO-8859-2 javattanitok/LabirintusAlkalmazás.java

Page 290:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

262 Created by XMLmind XSL-FO Converter.

A. függelék - Java mellékletek

1. A Java verziók újdonságai a tigristől a delfinig

Most részletesebben kibontjuk a Java történelemről szóló korábbi részt abban az esetben, amikor időtengelyen

előre haladunk: a közeli múlt (2004 vége, 2005 eleje) a Java 5, a Tiger. A jelen (2006 nyara - 2007 tavasza) a

Java 6, a Mustang. A közeli jövő (2008 második fele) a Java 7, a Dolphin. A következő három pontban

mindhárom verzió esetén megnézünk néhány szívdobogtató finomságot.

1.1. A tigris

A Java platformnak ez a verziója már a közeli múlt, így részletesebben nem is foglalkozunk vele, hanem csak az

általa bevezetett újdonságokat említjük röviden. Ezt viszont meg kell tennünk, mert nagy dolgok történtek ennek

a verziónak a bevezetésével.

A Java Tigris verziója nemcsak az API világában hozott újdonságokat, maga a nyelv is új elemekkel bővült:

i. megjelent a generikus,

ii. egy újfajta for ciklus: az iteráló ciklus,

iii. immár a primitív Java típusok automatikusan csomagolódnak be és vissza csomagoló osztályaikba,

iv. megjelent a felsorolásos típus,

v. lehetőség nyílt változó paraméterszámú függvények írására,

vi. és statikus tagok olyan importjára, ami elhagyhatóvá teszi a tagra vonatkozó osztálynév minősítést.

A generikus használatával olyan új típusokat (osztályokat) hozhatunk létre, melyek még maguknál a típusoknál

(osztályoknál) is általánosabb szintet hoznak programunk világába. Mert a generikus típus egy olyan általános

típus, amit egy típussal lehet paraméterezni, azaz konkréttá tenni. Például ha van egy generikus (általános) lista

típusom, akkor annak típus paramétere az lehet, hogy ennek a listának az elemei milyen típusúak, tehát az

általános lista típusból konkretizált listám milyen típusokkal működjön majd... Vagy készíthetek olyan saját

generikus (általános) számológép típust, ami ugyanúgy teszi a dolgát: összead, szoroz, de egyszer egészekkel,

máskor törtekkel, attól függően, hogy az Integer vagy a Double típussal paraméterezve, konkretizálva

készítettem-e el. (A generikusról általános olvasmányként lásd a [PICI PROGRAMOZÁS I JEGYZET]

jegyzetet.)

A Tigris előtti Javaban a (java.util.)List objektumba bármilyen más objektumot betehettem, akár

különbözőeket is, de amikor ki akartam venni az elemeket, akkor tudnom kellett, hogy milyen típusúak. Ha

ennek kapcsán valami hiba történt, például mégsem az volt betéve a listába, amit gondolt a programozó... hát,

akkor az csak a program futása közben derült ki. A Tigristől ez a List egy generikus interfész, tehát immár egy

típussal paraméterezhető, konkretizálható lista. Ez azért jó, mert már a fordítási időben kiderül, ha nem

megfelelő típusú elemeket akarunk betenni a listába vagy kivenni abból.

Játsszunk egy kicsit a generikussal, terjesszük ki a javattanitok.labirintus.Labirintus osztályt úgy,

hogy a labirintusunk szereplői ne tömbök, hanem listák legyenek. Mi ezt a kiterjesztést a

javattanitok.labirintus.GenerikusLabirintus osztályban tettük meg. A példánytagokat bemutató

részben a Labirintus osztály

protected Kincs [] kincsek;

protected Szörny [] szörnyek;

kincseit és szörnyeit így módosítottuk a GenerikusLabirintus osztályban:

Page 291:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

263 Created by XMLmind XSL-FO Converter.

protected java.util.List<Kincs> kincsek;

protected java.util.List<Szörny> szörnyek;

Például a kincsek referenciát egy kincs objektumokat tartalmazó listaként deklaráljuk, az által, hogy a generikus

lista típus paramétere itt a Kincs típus, ezt jelöli a <Kincs>. Tehát a generikus listát a Kincs típussal

konkretizáltuk.

Az elkészített GenerikusLabirintus osztályt a javattanitok.GenerikusLabirintusVilág osztályban

keltettük életre. A GenerikusLabirintus osztályba bevettünk néhány olyan metódust is, aminek a labirintus

tekintetében nincs gyakorlati funkciója, de játszik kicsit a bevezetett generikus listáinkkal:

public void nyomtat1(java.util.List<?> lista) {

for(Object objektum: lista)

System.out.println(objektum);

}

public void nyomtat2(java.util.List<? extends Szereplő> lista) {

for(Szereplő szereplő: lista)

System.out.println(szereplő);

}

public <E> void nyomtat3(java.util.List<E> lista) {

for(E e: lista)

System.out.println(e);

}

az osztályt elláttuk indító main függvénnyel is, arra az esetre, ha nem a labirintusban akarjuk kipróbálni a fenti

három módszert. Mit csinálnak?

Az előző pontban a GenerikusLabirintus osztály írásakor már ezt a ciklust használtuk, külön kiemelhető az

ilyen egymásba ágyazás esetén a jó olvashatóság:

for(Szörny szörny: szörnyek)

for(Kincs kincs: kincsek)

if(kincs.megtalált(szörny))

szörny.megtaláltam(kincs);

Az iteráló ciklus egyébként tömbökre is alkalmazható, erre is példát mutat a GenerikusLabirintus azzal,

ahogyan a Labirintus

boolean vanKincs(int sor, int oszlop) {

boolean van = false;

for(int i=0; i<kincsek.length; ++i)

if(sor == kincsek[i].sor()

&& oszlop == kincsek[i].oszlop()

&& !kincsek[i].megtalálva()) {

van = true;

break;

}

return van;

}

Page 292:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

264 Created by XMLmind XSL-FO Converter.

módszerét felüldefiniálja:

boolean vanKincs(int sor, int oszlop) {

boolean van = false;

for(Kincs kincs: kincsek)

if(sor == kincs.sor()

&& oszlop == kincs.oszlop()

&& !kincs.megtalálva()) {

van = true;

break;

}

return van;

}

ami felüldefiniálást egyébként kénytelen is megtenni, hiszen a GenerikusLabirintus osztálynak már az új

szörny és kincs listákkal kell dolgoznia!

1.2. A Musztáng

Azaz a teljes és hivatalos nevén: Java Platform, Standard Edition 6, röviden Java SE 6. Az ennek a platformnak

megfelelő Java fejlesztői csomag a Java SE Development Kit 6, röviden a JDK 6. Ezt kell letöltenünk, ha

fejleszteni akarunk, a letöltés tekintetében lásd A Java telepítése gépünkre című pontot.

A Musztángban - szemben az előzővel, a Tigrissel - nem történtek változások magát a Java nyelvet illetően,

ellenben például a Musztáng Java OO világ gyarapodott. Ezt a gyarapodást mi a GUI kapcsán tekintjük át, ahol

több látványos újításról tudunk örömhírt adni. Részletesebben az értesítési területhez való hozzáféréssel és az

indítóképernyő használatával foglalkozunk a következő pontokban.

A Musztángtól lehetőségünk van a programunkhoz a szokásos menüvel ellátható gyorsindító ikont

(java.awt.TrayIcon) elhelyezni az értesítési területen (java.awt.SystemTray). Arra az egyszerű esetre

mutatunk példát, amikor a programunk futásakor elhelyezi ide a megfelelő ikonját és feldolgozza az ikonról

érkező legegyszerűbb eseményt: példaként tehát, ha duplán kattintunk, akkor kimenti hősünket esetleges szorult

helyzetéből és visszadobja a labirintus kezdő pontjába.

// Ha a rendszerben támogatott az értesítési terület

if (java.awt.SystemTray.isSupported()) {

// akkor egy kis 16x16 pixel méretű

java.awt.Image ikonKép = new javax.swing.ImageIcon

("ikon.png").getImage();

// értesítő ikont

java.awt.TrayIcon értesítőIkon =

new java.awt.TrayIcon(ikonKép,

"Javat tanítok labirintus");

// most mi is kiteszünk

try {

java.awt.SystemTray.getSystemTray().

add(értesítőIkon);

} catch (java.awt.AWTException e) {

System.out.println("Értesítő ikon kitétele: "

+ e);

}

// amire ha duplán kattintunk, akkor

értesítőIkon.addActionListener(

new java.awt.event.ActionListener() {

public void actionPerformed(ActionEvent e) {

// például szorult helyzetéből kimenekítve a

// hőst, visszadobjuk a kiindulási pozíciójába

hős.sor(9);

hős.oszlop(0);

Page 293:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

265 Created by XMLmind XSL-FO Converter.

repaint();

}

});

}

Ha programunk indulása a szokásostól több időt vesz igénybe, mert sok erőforrást, például képeket kell

betöltenie, bonyolult adatszerkezeteket, inicializálásokat elvégeznie, akkor elegáns ennek az időnek a múlását

demonstráló képernyővel informálni, szórakoztatni a felhasználót. A Mustang erre lehetőséget ad. A

legegyszerűbb módja ennek, hogy amikor a programunkat átadjuk a Java Virtuális Gépnek, akkor a -splash

kapcsolót használva az indító képernyőnek (java.awt.SplashScreen) szánt képet is átadjuk. A

következőkben példaként a LabirintusAlkalmazás programunkat ruházzuk fel ezzel a lehetőséggel.

Ezt az indító képet készítettük, alul a folyamatjelzőt (progress bar) pusztán a rajzolóprogrammal tettük rá, hogy

le tudjuk olvasni a kívánt koordinátákat.

Minél közelebb járunk ahhoz, hogy programunk befejezze az indulás kapcsán elvégzett időigényes dolgait,

annál nagyobb sárga, hosszú, lapos téglalapot rajzolunk majd. Szükségünk lesz a téglalap bal felső sarkának a

koordinátáira és a téglalap szélességére, magasságára. Ezeket a következő ábra szerint olvassuk le.

A 8. oszlop 285. sora lesz a téglalap bal felső sarka, a szélessége 382 , a magassága pedig 10 pixel.

// Hozzáférünk az indító képernyőhöz

java.awt.SplashScreen indítóKépernyő

= java.awt.SplashScreen.getSplashScreen();

// Ha sikerül, azaz, ha java -splash:kép állomány neve

// formában indítottuk és még látszik a kép

if(indítóKépernyő != null) {

// akkor rajzolni fogunk rá

java.awt.Graphics2D g = indítóKépernyő.createGraphics();

// némi szöveget, amit akár a rajzolóprogrammal is

// ráírhattunk volna

java.awt.Font font1 = new java.awt.Font("Sans",

java.awt.Font.BOLD, 20);

java.awt.Font font2 = new java.awt.Font("Monospaced",

java.awt.Font.BOLD, 12);

g.setFont(font1);

// világosabb sárgával

g.setColor(new java.awt.Color(250, 255, 138));

g.drawString("Javat tanítok labirintus", 8, 240);

Page 294:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

266 Created by XMLmind XSL-FO Converter.

g.setFont(font2);

g.drawString("Bátfai Norbert", 10, 265);

g.drawString("[email protected]", 10, 280);

// és rajzolunk egy a konkrét kép méretéhez igazított

// progress bar szerűséget (kommentben az indító

// képernyő méretéhez relatív adatok)

int sz = 382; // indítóKépernyő.getSize().width-10;

int barSzélesség = sz/10;

int m = 10; // indítóKépernyő.getSize().height;

int barMagasság = 6;

// itt szimuláljuk a játék időigényes dolgainak

// betöltését, 10 x fél másodperig altatjuk majd

// a szálunkat

for(int i = 0; i<10; ++i) {

// és ennek megfelelően frissítjük mit

// mutasson a progress bar-unk

g.setColor(java.awt.Color.WHITE);

g.drawRect(8, 285, //5, m-20,

10*barSzélesség, barMagasság);

g.fillRect(8, 285, //5, m-20,

10*barSzélesség, barMagasság);

g.setColor(java.awt.Color.YELLOW);

g.drawRect(8, 285, //5, m-20,

10*barSzélesség, barMagasság);

g.fillRect(8, 285, //5, m-20,

(i+1)*barSzélesség, barMagasság);

indítóKépernyő.update();

try {

// a fél másodperces altatás

// ez szimulálja pl., hogy töltjük be

// a már hatalmas labirintus játékunk

// képerőforrásait, készítjük a megfelelő

// adatszerkezeteket stb.

Thread.sleep(500);

} catch(Exception e) {}

}

}

Végül lássuk munkánk eredményét! Például Linuxon az XFCE felület alatt nézzük meg az indítóképernyőt az

alábbi képeken.

Page 295:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

267 Created by XMLmind XSL-FO Converter.

Page 296:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

268 Created by XMLmind XSL-FO Converter.

Illetve ugyancsak Linuxon a GNOME felületet használva az indítóikont.

1.3. A delfin

A Delfint 2008 második félévére várjuk, de a http://java.sun.com lapjain előzetesen olvashatunk az

újdonságokról. A nyelv változása tekintetében a metódus referenciák bevezetését nagyon izgalmasnak tartjuk.

(Ezeket a bevezetendő metódus referenciákat például a C nyelvbeli függvény mutatókkal érezzük rokonnak.) A

programok szervezése területén a csomagszerkezet és a jar állományok újítása várható... és még sorolhatnánk a

finomságokat: a http://mustang.dev.java.net lapot figyelve lehetünk naprakészek.

2. Az első Java tapasztalatok

Ebben a mellékletben ismertetjük az egyetemünkön a levelező informatika tanárképzésbeli WWW alkalmazások

fejlesztése című tárgy első óráját. Ennek a tárgynak a példái jelen pillanatban a Java nyelv használatára épülnek.

De napjainkban, egy átmeneti állapotban, amikor a hallgatók (akik tipikusan továbbképzésként résztvevő

gyakorló pedagógusok) a képzés során már nem Pascalban programoznak, de még nem is Javaban, szükséges

némi gyakorlati Java programozás alapozás is. Ezt az alapozást ismertetjük ebben a mellékletben, mint a

programozásban egyébként járatos informatikusoknak szánt Java bevezetőt.

A következő Szerver osztály kódját másoljuk a Szerver.java állományba!

public class Szerver {

public static void main(String [] args) {

try {

java.net.ServerSocket serverSocket =

new java.net.ServerSocket(2006);

Page 297:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

269 Created by XMLmind XSL-FO Converter.

while(true) {

java.net.Socket socket = serverSocket.accept();

java.io.PrintWriter kimenőCsatorna =

new java.io.PrintWriter(socket.getOutputStream());

kimenőCsatorna.println("Helló, Világ!\n");

kimenőCsatorna.flush();

socket.close();

}

} catch(java.io.IOException ioE) {

ioE.printStackTrace();

}

}

}

A következő Kliens osztály kódját pedig másoljuk a Kliens.java állományba!

public class Kliens {

public static void main(String[] args) {

try {

java.net.Socket socket

= new java.net.Socket("localhost", 2006);

java.io.BufferedReader bejövőCsatorna =

new java.io.BufferedReader(

new java.io.InputStreamReader(socket.getInputStream()));

System.out.println(bejövőCsatorna.readLine());

socket.close();

} catch(java.io.IOException ioE) {

ioE.printStackTrace();

}

}

}

Most két külön ablakban lépjünk be abba a könyvtárba, ahová a fenti két forrásállományt másoltuk, legyen ez

most mondjuk a Munkakönyvtár nevű munkakönyvtár, majd az egyik ablakban a szervert, a másikban a klienst

fordítsuk és futtassuk!

[norbi@omega Munkakönyvtár]$ javac Szerver.java

[norbi@omega Munkakönyvtár]$ java Szerver

[norbi@omega Munkakönyvtár]$ javac Kliens.java

[norbi@omega Munkakönyvtár]$ java Kliens

Helló, Világ!

[norbi@omega Munkakönyvtár]$ java Kliens

Helló, Világ!

[norbi@omega Munkakönyvtár]$ java Kliens

Helló, Világ!

Page 298:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

270 Created by XMLmind XSL-FO Converter.

Most pedig röviden beszéljük át a forrásokat! Tartsuk közben szem előtt A források olvasásáról című pont

felhívását. Az API dokumentáció telepítésének leírását A Java dokumentáció, azaz az API doksi letöltése című

pontban találjuk meg.

Az internet születésének hajnalán, valamikor az ARPANET korszakban vált de facto szabvánnyá a TCP/IP,

amihez a Berkeley egyetemen kifejlesztettek egy programozói interfészt, ez a socket interfész. A Java is

lehetőséget ad ezen az absztrakciós szinten dolgozni, az ezt lehetővé tevő osztályok a java.net csomagban

kaptak helyet. Az API dokumentációval párhuzamosan olvassuk a program szövegét!

A Szerver osztály indító main() függvényében megpróbáljuk lefoglalni a 2006 számú szerver socketet,

megpróbálunk létrehozni egy ServerSocket, vagyis egy szerver socketet absztraháló Java objektumot a 2006

sorszámú

try {

java.net.ServerSocket serverSocket =

new java.net.ServerSocket(2006);

TCP kapu felett. Ha nem sikerül, akkor egy kivétel keletkezik, s a program végrehajtása egy megfelelő, most a

catch ággal bevezetett kivételkezelő blokkban folytatódik, amivel most nem foglalkozunk.

Tehát ha sikerrel ráültetjük a 2006-os TCP kapura a ServerSocket objektumunkat, akkor programunk egy

végtelen ciklusba kezd, melyben nem tesz mást, mint a szerver socket felett blokkolódva várakozik a kliensek

kapcsolatfelvételi kérelmeinek beérkezésére:

while(true) {

java.net.Socket socket = serverSocket.accept();

Ha egy kliens kapcsolatfelvételi kérelme érkezik a 2006 sorszámú kapuhoz, akkor az eddig blokkolódott

accept() metódus visszaadja a kliens socketet.

Amelytől megpróbálunk elkérni egy kimenő csatorna objektumot, amelyre írni akarjuk a kliensnek küldeni

kívánt adatokat, most a Helló, Világ!\n karaktersorozatot.

java.io.PrintWriter kimenőCsatorna =

new java.io.PrintWriter(socket.getOutputStream());

kimenőCsatorna.println("Helló, Világ!\n");

Majd lezárjuk a kliensre mutató kaput:

socket.close();

A kliens működése egyszerűbb: megpróbál csatlakozni a szerverhez, majd a kapcsolattól egy bejövő csatornát

kérni és egy sort beolvasni.

3. Egyszerű összehasonlítások

3.1. Egyszerű összehasonlítások a sebesség kérdésében

Page 299:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

271 Created by XMLmind XSL-FO Converter.

A sebességek egyszerű összevetésére a PiBBP osztályunkból egyszerűsített PiBBPBench osztályt és annak C

illetve C Sharp nyelvi átíratait használjuk, illetve a Java osztályból a bináris futtathatóval is számolunk. A

következő két táblázatban tehát a a Pi hexadecimális kifejtésének (0. pozíciótól számított) 106., 107., 108. hexa

jegyét határozzuk meg és közben megmérjük az ehhez szükséges időt.

Az első táblázat számításait egy Fedora Linux Core 5 operációs rendszerrel felszerelt, 2.6.17.7 verziójú

kernellel ellátott Sun W1100Z Workstation (AMD Opteron Mhz processzor, 1G memória) gépen gcc (GCC)

4.1.0 20060304 (Red Hat 4.1.0-3) verziójú gcc (gij (GNU libgcj) version 4.1.0 20060304 (Red

Hat 4.1.0-3)) és java version "1.6.0-beta2" verziójú Sun-os Java, a Java Platform, Standard Edition 6

Development Kit mellett végeztük el.

A második táblázat számításait egy Windows XP operációs rendszerrel ellátott Intel Celeron 1.7Ghz

processzoros, 768 M memóriával felszerelt gépen C Sharp tekintetében a Microsoft .NET Framework Software

Development Kit 2.0 és Java tekintetében a java version "1.6.0-beta2" verziójú Sun-os Java, a Java

Platform, Standard Edition 6 Development Kit mellett végeztük el.

A C forrásból készítünk bináris futtathatót, majd a Java forrásból ugyancsak bináris futtathatót, végül a Java

forrásból a hagyományos class bájtkódot. A fordítások után mindhármat futtatjuk egymás után.

[norbi@niobe ~]$ gcc pi_bbp_bench.c -o pi_bbp_bench -lm

[norbi@niobe ~]$ gcj -o pibbpbench --main=PiBBPBench PiBBPBench.java

[norbi@niobe ~]$ javac PiBBPBench.java

[norbi@niobe ~]$ ./pi_bbp_bench

6

4.390000

[norbi@niobe ~]$ ./pibbpbench

6

6.386

[norbi@niobe ~]$ java PiBBPBench

6

4.246

A forrásokban megemeljük a d értékét, most a 107. jegyet vizsgáljuk. Újra fordítunk, majd futtatunk.

[norbi@niobe ~]$ gcc pi_bbp_bench.c -o pi_bbp_bench -lm

[norbi@niobe ~]$ gcj -o pibbpbench --main=PiBBPBench PiBBPBench.java

[norbi@niobe ~]$ javac PiBBPBench.java

[norbi@niobe ~]$ ./pi_bbp_bench

7

51.190000

[norbi@niobe ~]$ ./pibbpbench

7

74.503

[norbi@niobe ~]$ java PiBBPBench

7

49.465

A forrásokban tovább emeljük a d értékét, most a 108. jegyet vizsgáljuk. Megint újra fordítunk, majd futtatunk.

[norbi@niobe ~]$ gcc pi_bbp_bench.c -o pi_bbp_bench -lm

[norbi@niobe ~]$ gcj -o pibbpbench --main=PiBBPBench PiBBPBench.java

[norbi@niobe ~]$ javac PiBBPBench.java

[norbi@niobe ~]$ ./pi_bbp_bench

12

586.000000

[norbi@niobe ~]$ ./pibbpbench

12

854.993

Page 300:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

272 Created by XMLmind XSL-FO Converter.

[norbi@niobe ~]$ java PiBBPBench

12

556.935

Az alábbi táblázatba foglaljuk eredményeinket.

A.1. táblázat - Java, gcj és C egyszerű sebesség összehasonlítása

Pozíció 0xJegy C [sec] gcj [sec] Java [sec]

106 6 4.39 6.386 4.246

107 7 51.19 74.503 49.465

108 C 586.0 854.993 556.935

C:\...> csc PiBBPBench.cs

C:\...> javac PiBBPBench.java

C:\...> PiBBPBench

6

10,65625

C:\...> java PiBBPBench

6

12.578

A forrásokban megemeljük a d értékét, most a 107. jegyet vizsgáljuk. Újra fordítunk, majd futtatunk.

C:\...> csc PiBBPBench.cs

C:\...> javac PiBBPBench.java

C:\...> PiBBPBench

7

125,0625

C:\...> java PiBBPBench

7

147.407

Az alábbi táblázatba foglaljuk eredményeinket.

A.2. táblázat - Java és C# egyszerű sebesség összehasonlítása

Pozíció 0xJegy C# [sec] Java [sec]

106 6 10,65625 12.578

107 7 125,0625 147.407

3.1.1. A PiBBPBench Java osztály

A PiBBPBench.java állomány kódja.

Page 301:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

273 Created by XMLmind XSL-FO Converter.

/*

* PiBBPBench.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* A PiBBP.java-ból kivettük az "objektumorientáltságot", így kaptuk

* ezt az osztályt.

*

* (A PiBBP osztály a BBP (Bailey-Borwein-Plouffe) algoritmust a Pi hexa

* jegyeinek számolását végző osztály. A könnyebb olvahatóság

* kedvéért a változó és metódus neveket megpróbáltuk az algoritmust

* bemutató [BBP ALGORITMUS] David H. Bailey: The BBP Algorithm for Pi.

* cikk jelöléseihez.)

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

public class PiBBPBench {

/**

* BBP algoritmus a Pi-hez, a [BBP ALGORITMUS] David H. Bailey: The

* BBP Algorithm for Pi. alapján a {16^d Sj} részlet kiszámítása.

*

* @param d a d+1. hexa jegytől számoljuk a hexa jegyeket

* @param j Sj indexe

*/

public static double d16Sj(int d, int j) {

double d16Sj = 0.0d;

for(int k=0; k<=d; ++k)

d16Sj += (double)n16modk(d-k, 8*k + j) / (double)(8*k + j);

/* (bekapcsolva a sorozat elejen az első utáni jegyekben növeli pl.

a pontosságot.)

for(int k=d+1; k<=2*d; ++k)

d16Sj += Math.pow(16.0d, d-k) / (double)(8*k + j);

*/

return d16Sj - Math.floor(d16Sj);

}

/**

* Bináris hatványozás mod k, a 16^n mod k kiszámítása.

*

* @param n kitevő

* @param k modulus

*/

public static long n16modk(int n, int k) {

int t = 1;

while(t <= n)

t *= 2;

long r = 1;

while(true) {

if(n >= t) {

r = (16*r) % k;

n = n - t;

}

t = t/2;

if(t < 1)

break;

r = (r*r) % k;

}

Page 302:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

274 Created by XMLmind XSL-FO Converter.

return r;

}

/**

* A [BBP ALGORITMUS] David H. Bailey: The

* BBP Algorithm for Pi. alapján a

* {16^d Pi} = {4*{16^d S1} - 2*{16^d S4} - {16^d S5} - {16^d S6}}

* kiszámítása, a {} a törtrészt jelöli. A Pi hexa kifejtésében a

* d+1. hexa jegytől

*/

public static void main(String args[]) {

double d16Pi = 0.0d;

double d16S1t = 0.0d;

double d16S4t = 0.0d;

double d16S5t = 0.0d;

double d16S6t = 0.0d;

int jegy = 0;

long delta = System.currentTimeMillis();

for(int d=1000000; d<1000001; ++d) {

d16Pi = 0.0d;

d16S1t = d16Sj(d, 1);

d16S4t = d16Sj(d, 4);

d16S5t = d16Sj(d, 5);

d16S6t = d16Sj(d, 6);

d16Pi = 4.0d*d16S1t - 2.0d*d16S4t - d16S5t - d16S6t;

d16Pi = d16Pi - Math.floor(d16Pi);

jegy = (int)Math.floor(16.0d*d16Pi);

}

System.out.println(jegy);

delta = System.currentTimeMillis() - delta;

System.out.println(delta/1000.0);

}

}

3.1.2. A pi_bbp_bench forrás

A pi_bbp_bench.c állomány kódja.

#include <stdio.h>

#include <math.h>

#include <time.h>

/*

* pi_bbp_bench.c

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

* A PiBBP.java-ból kivettük az "objektumorientáltságot", így kaptuk

* a PiBBPBench osztályt, amit pedig átírtuk C nyelvre.

*

*/

/*

* 16^n mod k

* [BBP ALGORITMUS] David H. Bailey: The

Page 303:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

275 Created by XMLmind XSL-FO Converter.

* BBP Algorithm for Pi. alapján.

*/

long

n16modk (int n, int k)

{

long r = 1;

int t = 1;

while (t <= n)

t *= 2;

for (;;)

{

if (n >= t)

{

r = (16 * r) % k;

n = n - t;

}

t = t / 2;

if (t < 1)

break;

r = (r * r) % k;

}

return r;

}

/* {16^d Sj}

* [BBP ALGORITMUS] David H. Bailey: The

* BBP Algorithm for Pi. alapján.

*/

double

d16Sj (int d, int j)

{

double d16Sj = 0.0;

int k;

for (k = 0; k <= d; ++k)

d16Sj += (double) n16modk (d - k, 8 * k + j) / (double) (8 * k + j);

/*

for(k=d+1; k<=2*d; ++k)

d16Sj += pow(16.0, d-k) / (double)(8*k + j);

*/

return d16Sj - floor (d16Sj);

}

/*

* {16^d Pi} = {4*{16^d S1} - 2*{16^d S4} - {16^d S5} - {16^d S6}}

* [BBP ALGORITMUS] David H. Bailey: The

* BBP Algorithm for Pi. alapján.

*/

main ()

{

double d16Pi = 0.0;

double d16S1t = 0.0;

double d16S4t = 0.0;

double d16S5t = 0.0;

double d16S6t = 0.0;

int jegy;

int d;

Page 304:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

276 Created by XMLmind XSL-FO Converter.

clock_t delta = clock ();

for (d = 1000000; d < 1000001; ++d)

{

d16Pi = 0.0;

d16S1t = d16Sj (d, 1);

d16S4t = d16Sj (d, 4);

d16S5t = d16Sj (d, 5);

d16S6t = d16Sj (d, 6);

d16Pi = 4.0 * d16S1t - 2.0 * d16S4t - d16S5t - d16S6t;

d16Pi = d16Pi - floor (d16Pi);

jegy = (int) floor (16.0 * d16Pi);

}

printf ("%d\n", jegy);

delta = clock () - delta;

printf ("%f\n", (double) delta / CLOCKS_PER_SEC);

}

3.1.3. A PiBBPBench C Sharp osztály

A PiBBPBench.cs állomány kódja.

/*

* FileName: PiBBPBench.cs

* Author: Bátfai Norbert, [email protected]

* DIGIT 2005, Javat tanítok

*/

/// <summary>

/// A PiBBPBench C# átírata.

/// </summary>

/// <remark>

/// A PiBBP.java-ból kivettük az "objektumorientáltságot", így kaptuk

/// a PiBBPBench osztályt, amit pedig átírtuk C# nyelvre.

///

/// (A PiBBP osztály a BBP (Bailey-Borwein-Plouffe) algoritmust a Pi hexa

/// jegyeinek számolását végző osztály. A könnyebb olvahatóság

/// kedvéért a változó és metódus neveket megpróbáltuk az algoritmust

/// bemutató [BBP ALGORITMUS] David H. Bailey: The BBP Algorithm for Pi.

/// cikk jelöléseihez.)

/// </remark>

public class PiBBPBench {

/// <remark>

/// BBP algoritmus a Pi-hez, a [BBP ALGORITMUS] David H. Bailey: The

/// BBP Algorithm for Pi. alapján a {16^d Sj} részlet kiszámítása.

/// </remark>

/// <param>

/// d a d+1. hexa jegytől számoljuk a hexa jegyeket

/// </param>

/// <param>

/// j Sj indexe

/// </param>

public static double d16Sj(int d, int j) {

double d16Sj = 0.0d;

for(int k=0; k<=d; ++k)

d16Sj += (double)n16modk(d-k, 8*k + j) / (double)(8*k + j);

/*

for(int k=d+1; k<=2*d; ++k)

Page 305:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

277 Created by XMLmind XSL-FO Converter.

d16Sj += System.Math.pow(16.0d, d-k) / (double)(8*k + j);

*/

return d16Sj - System.Math.Floor(d16Sj);

}

/// <summary>

/// Bináris hatványozás mod k, a 16^n mod k kiszámítása.

/// </summary>

/// <param>

/// n kitevő

/// </param>

/// <param>

/// k modulus

/// </param>

public static long n16modk(int n, int k) {

int t = 1;

while(t <= n)

t *= 2;

long r = 1;

while(true) {

if(n >= t) {

r = (16*r) % k;

n = n - t;

}

t = t/2;

if(t < 1)

break;

r = (r*r) % k;

}

return r;

}

/// <remark>

/// A [BBP ALGORITMUS] David H. Bailey: The

/// BBP Algorithm for Pi. alapján a

/// {16^d Pi} = {4*{16^d S1} - 2*{16^d S4} - {16^d S5} - {16^d S6}}

/// kiszámítása, a {} a törtrészt jelöli. A Pi hexa kifejtésében a

/// d+1. hexa jegytől

/// </remark>

public static void Main(System.String[]args) {

double d16Pi = 0.0d;

double d16S1t = 0.0d;

double d16S4t = 0.0d;

double d16S5t = 0.0d;

double d16S6t = 0.0d;

int jegy = 0;

System.DateTime kezd = System.DateTime.Now;

for(int d=1000000; d<1000001; ++d) {

d16Pi = 0.0d;

d16S1t = d16Sj(d, 1);

d16S4t = d16Sj(d, 4);

d16S5t = d16Sj(d, 5);

d16S6t = d16Sj(d, 6);

d16Pi = 4.0d*d16S1t - 2.0d*d16S4t - d16S5t - d16S6t;

d16Pi = d16Pi - System.Math.Floor(d16Pi);

Page 306:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

278 Created by XMLmind XSL-FO Converter.

jegy = (int)System.Math.Floor(16.0d*d16Pi);

}

System.Console.WriteLine(jegy);

System.TimeSpan delta = System.DateTime.Now.Subtract(kezd);

System.Console.WriteLine(delta.TotalMilliseconds/1000.0);

}

}

3.2. A Java és a C Sharp nyelvi szintű összehasonlítása

Az elmaradhatatlan, alább bemutatásra kerülő „Helló, világ!” programok jól mutatják, hogy érdekesebb és

érdemesebb az összehasonlítást a két nyelv közötti hasonlóságokkal kezdeni.

public class HellóVilág {

public static void main(String args[]) {

System.out.println("Helló Világ!");

}

}

A HellóVilág osztály statikus, azaz nem az osztályból származtatott példányokhoz, hanem magához az

osztályhoz tartozó indító main függvényének egyetlen utasítása arról szól, hogy a meghívjuk a System osztály

out tagjának println() metódusát, aminek paraméteréül a "Helló Világ!" sztringet adjuk. A megszólított

out tag a System osztály egy PrintStream osztálybeli (típusú) változója, s mint ilyen egy kimeneti csatorna; a

programhoz rendelt sztenderd kimeneti csatorna: tipikusan a képernyő. Tehát a programot a javac nevű Java

fordítóprogrammal lefordítva és futtatva, azaz az osztályt a javac Java Virtuális Gépnek átadva, a kimenet a

parancsablakban jelenik meg:

C:\...> javac HellóVilág.java

C:\...> java HellóVilág

Helló Világ!

A Java számtalan osztályt biztosít a fejlesztő rendelkezésére, amiket az egyszerűbb kezelés érdekében egy fa

szerkezetbe szervez. Ezt a fa szerkezetet nevezzük Java API-nak. A System osztály például a java alól nyíló

lang ágban van, amit a Java terminológia egyébként csomagnak nevez és röviden, ponttal minősítve a

java.lang alakban ír. Tehát a System osztály teljes neve java.lang.System, de ez a csomag annyira

általános, hogy eltekinthetünk és szokás szerint el is tekintünk a kiírásától.

Ránézésre a megfelelő C Sharp programunk megegyezik a Java változattal, de itt a System nem osztály, hanem

egy névtér. Ami jelen összehasonlításunkban a java.lang csomaggal állítható rokonságba. A Console viszont

már egy osztály, a konzolt absztraháló osztály, minek WriteLine() metódusával tudunk a sztenderd kimenetre

írni. (Ebben az értelemben a System.Console.WriteLine("Helló Világ!"); utasításnak Javaban a

java.lang.System.out.println("Helló Világ!"); utasítás felel meg formálisan.)

public class HellóVilág {

public static void Main() {

System.Console.WriteLine("Helló Világ!");

Page 307:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

279 Created by XMLmind XSL-FO Converter.

}

}

A programot a csc nevű C Sharp fordítóprogrammal [.NET Framework SDK 2.0] lefordítva és futtatva a

kimenet az ablakban jelenik meg:

C:\...> csc HellóVilág.cs

C:\...> HellóVilág.exe

Helló Világ!

A következő példával nagyot ugrunk, a bemutatásra kerülő többszálú szerveroldali TCP kiszolgáló programmal

továbbra is az a célunk, hogy kihangsúlyozzuk a nyelvek közötti hasonlóságokat.

Figyelmeztetés a Javaban kezdő Olvasóknak

A következő Java és C Sharp nyelvű hálózati példát csak felületesen fussa át a kezdő Olvasó. De most

akár ki is hagyhatja, s az olvasást a következő, az alapvető programnyelvi konstrukciókat bemutató

résznél folytathatja. Ez esetben a hálózati alapfogalmakat és a Java programozást bevezető tárgyaló

rész után érdemes ide visszalapozni. A részletesebb tárgyalás előtt vessünk egy pillantást a Java megvalósításunk alábbi fő osztályára!

public class Szerver {

public static void main(String [] args) {

try {

java.net.ServerSocket serverSocket =

new java.net.ServerSocket(2006);

while(true) {

java.net.Socket socket = serverSocket.accept();

new Thread(new Kiszolgáló(socket)).start();

}

} catch(java.io.IOException ioE) {

ioE.printStackTrace();

}

}

}

A Szerver osztály indító függvényében megpróbáljuk lefoglalni a 2006 számú szerver socketet, azaz OO

nyelven: megpróbálunk létrehozni egy ServerSocket, egy szerver socketet absztraháló Java objektumot a 2006

sorszámú

try {

java.net.ServerSocket serverSocket =

new java.net.ServerSocket(2006);

TCP kapu felett. Ha nem sikerül, akkor egy kivétel, OO terminológiában kivétel objektum keletkezik, s a

program végrehajtása egy megfelelő kivételkezelő keresésével folytatódik. Ez a kivétel objektum tipikusan egy

Page 308:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

280 Created by XMLmind XSL-FO Converter.

BindException osztálybeli objektum szokott lenni, ami azt jelöli, hogy a lefoglalni óhajtott 2006 sorszámú

kapu éppen foglalt. Ez a kivétel osztály leszármazottja az IOException osztálynak, így a kivétel objektum

kezelésére a

} catch(java.io.IOException ioE) {

ioE.printStackTrace();

}

kivételkezelő blokk alkalmas, ahol egyébként nem teszünk mást, mint kiírjuk, hogy hogyan került ebbe a

helyzetbe a programunk. Majd programunk a kivételkezelő blokk utáni résszel folytatódik, azaz gyakorlatilag

véget ér.

Ha viszont sikerrel járunk, akkor programunk egy végtelen ciklusba kezd, melyben nem tesz mást, mint a

szerver socket felett blokkolódva várakozik a kliensek kapcsolatfelvételi kérelmeinek beérkezésére:

while(true) {

java.net.Socket socket = serverSocket.accept();

ha egy kliens kapcsolatfelvételi kérelme érkezik a 2006 sorszámú kapuhoz, akkor az eddig blokkolódott

accept() metódus visszaadja a kliens socketet. A jelentkező kliens kiszolgálására külön szálat, azaz

programunk eddig tekintett fő szálával párhuzamosan futó külön szálat készítünk. Mivel minden, így a

párhuzamosan futó szálak is objektumok, ezek a Thread osztálybeli objektumok. A példányosításkor a szálnak

átadjuk a párhuzamosan végrehajtani kívánt kódot implementáló objektumot, egy a kliens socket fölött éppen

létrehozott Kiszolgáló objektumot.

new Thread(new Kiszolgáló(socket)).start();

A létrehozott szál objektumot start() metódusával rögtön el is indítjuk, miután programunk végrehajtása ketté

vált:

• a program fő szálában a vezérlés a végtelen ciklusban folytatódik tovább, azaz program újra várakozni kezd

az accept() metódusban.

• az indított szálban a párhuzamosan végrehajtani kívánt kódot implementáló objektum run() metódusának

végrehajtása kezdődik meg.

De mielőtt a Kiszolgáló objektumot és annak run() metódusát megvizsgálnánk, nézzük meg az eddig

bemutatott szerverünk C Sharp nyelvi megvalósítását!

public class Szerver {

public static void Main(System.String[]args) {

try {

System.Net.Sockets.TcpListener tcpListener =

new System.Net.Sockets.TcpListener(

System.Net.IPAddress.Loopback, 2006);

tcpListener.Start();

while (true) {

Page 309:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

281 Created by XMLmind XSL-FO Converter.

System.Net.Sockets.TcpClient socket =

tcpListener.AcceptTcpClient();

Kiszolgáló kiszolgáló = new Kiszolgáló(socket);

System.Threading.ThreadStart threadStart =

new System.Threading.ThreadStart(kiszolgáló.run);

System.Threading.Thread szál =

new System.Threading.Thread(threadStart);

szál.Start();

}

} catch (System.Exception e) {

System.Console.WriteLine(e);

}

}

}

Jól láthatóan a C Sharp megvalósítás dallama ugyanaz, mint a Java megvalósításé volt.

Folytassuk az iménti C Sharp kitérő miatt felfüggesztett Java nyelven implementált Kiszolgáló osztály

tárgyalását. A részletek előtt megint csak vessünk egy pillantást az egész osztályra!

class Kiszolgáló implements Runnable {

java.net.Socket socket;

public Kiszolgáló(java.net.Socket socket) {

this.socket = socket;

}

public void run() {

try {

java.io.BufferedReader bejövőCsatorna =

new java.io.BufferedReader(

new java.io.InputStreamReader(socket.getInputStream()));

java.io.PrintWriter kimenőCsatorna =

new java.io.PrintWriter(socket.getOutputStream());

String sor = null;

while((sor = bejövőCsatorna.readLine()) != null) {

kimenőCsatorna.println(sor);

kimenőCsatorna.flush();

}

socket.close();

} catch(java.io.IOException ioE) {

ioE.printStackTrace();

}

}

}

Az osztály a Runnable interfész implementálásával jelzi, hogy tartalmaz egy párhuzamosan végrehajtható

run() metódust.

class Kiszolgáló implements Runnable {

Page 310:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

282 Created by XMLmind XSL-FO Converter.

A run() metódusban megpróbálunk két szöveges csatorna objektumot készíteni a kliens kapu fölött, egy

bemenetit, amelyről olvasni szeretnénk a klienstől érkező adatokat és egy kimenetit, amelyre írni akarjuk a

kliensnek küldeni kívánt adatokat.

try {

java.io.BufferedReader bejövőCsatorna =

new java.io.BufferedReader(

new java.io.InputStreamReader(socket.getInputStream()));

java.io.PrintWriter kimenőCsatorna =

new java.io.PrintWriter(socket.getOutputStream());

A csatorna objektumok sikeres elkészítése után a bejövő csatornáról a BufferedReader osztály readLine()

módszerével sorokat olvasunk be, egészen addig, ameddig csak tudunk. Ha már nem tudunk, akkor ezt a

readLine() metódus majd a null érték visszaadásával jelzi.

while((sor = bejövőCsatorna.readLine()) != null) {

kimenőCsatorna.println(sor);

kimenőCsatorna.flush();

}

A bejövő csatornáról olvasó ciklus testében nem teszünk mást, mint a beolvasott sztring visszaírását a kimenő

csatornára. Tehát szerverünk egy echo szerver jelleggel működik. Ha már nincs több olvasható sor a bejövő

csatornán, akkor kilépünk az Olvasó ciklusból és lezárjuk a kliensre mutató kaput.

socket.close();

Nézzük meg az imént Java nyelven implementált Kiszolgáló osztály C Sharp nyelven készített megvalósítását!

class Kiszolgáló {

System.Net.Sockets.TcpClient socket;

public Kiszolgáló(System.Net.Sockets.TcpClient socket) {

this.socket = socket;

}

public void run() {

System.IO.StreamReader bejövőCsatorna =

new System.IO.StreamReader(socket.GetStream());

System.IO.StreamWriter kimenőCsatorna =

new System.IO.StreamWriter(socket.GetStream());

System.String sor;

while((sor = bejövőCsatorna.ReadLine()) != null) {

kimenőCsatorna.WriteLine(sor);

Page 311:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

283 Created by XMLmind XSL-FO Converter.

kimenőCsatorna.Flush();

}

socket.Close();

}

}

Ismét jól látható, hogy a C Sharp megvalósítás dallama ugyanaz, mint ami a Java megvalósításé volt.

3.2.1. Az alapvető nyelvi elemek összehasonlítása

Ebben a pontban - csupán demonstrációs céllal - néhány nyelvi elem leírására vetünk egy-egy pillantást.

Alapvetően a Java nyelvi konstrukciókat tárgyaljuk, de ha külön nem emeljük ki a C Sharp nyelvbeli

különbséget, akkor az megegyezik a Java konstrukcióval.

Osztályt a

public class OsztályNév {

}

alakban definiálunk. Javaban fontos, hogy ezt a publikus OsztályNév osztály definíciót tartalmazó szöveges

forrásállomány neve megegyezzen ezzel a publikus osztálynévvel, azaz az állomány neve OsztályNév.java

legyen.

Nem javasoljuk, de egyetlen forrásállomány több, nem publikus osztály definícióját is tartalmazhatja.

public class OsztályNév {

}

class MásikOsztályNév {

}

Ezek az osztálydefiníciók (akár a most tárgyalt üresek is) lefordíthatók a javac nevű Java fordítóprogrammal.

C:\...> javac OsztályNév.java

C Sharpban az osztály lefordításához egy belépési pontra is szükség van, ez a C örökségnek megfelelően a

main() függvény.

public class OsztályNév {

public static void Main() {

}

}

public class MásikOsztályNév {

Page 312:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

284 Created by XMLmind XSL-FO Converter.

}

Javaban ugyancsak, de itt az esetleges parancssor argumentumok átvételét szolgáló String[] args sztring

tömböt is szerepeltetnünk kell a belépési függvény formális paraméter listájában.

public class OsztályNév {

public static void main(String[] args) {

}

}

class MásikOsztályNév {

}

De ugyanezzel a konstrukcióval vesszük át a parancssor argumentumokat C Sharpban is:

public static void Main(System.String[] args) {

}

A main() függvényben rendszerint példányosítunk, azaz a new operátorral objektumot, objektumokat hozunk

létre.

public static void main(String[] args) {

OsztályNév példányReferencia = new OsztályNév("Hello");

}

Itt az OsztályNév osztályból példányosítottunk, azaz létrehoztunk egy konkrét, a továbbiakban a

példányReferencia névvel azonosított objektumot. Ez azt jelenti, hogy lefutott a OsztályNév osztály

megfelelő konstruktora:

public class OsztályNév {

String példányTagReferencia;

public OsztályNév(String példányTagReferencia) {

this.példányTagReferencia = példányTagReferencia;

}

ami nem csinált mást, mint a new OsztályNév("Hello"); hívásban érkező aktuális "Hello" paraméter sztring

objektum referenciáját értékül adja az osztály aktuális példánya példányTagReferencia nevű változójának.

A referenciák neve után egy pontot írva tudjuk megszólítani az objektum példányokat, tagjaikra vagy

módszereikre hivatkozhatunk. Előbbire lássuk az alábbi példát, utóbbira majd a következő feladatot!

Page 313:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

285 Created by XMLmind XSL-FO Converter.

public class OsztályNév {

String példányTagReferencia;

public OsztályNév(String példányTagReferencia) {

this.példányTagReferencia = példányTagReferencia;

}

public static void main(String[] args) {

OsztályNév osztályPéldány = new OsztályNév("Hello");

System.out.println(osztályPéldány.példányTagReferencia);

}

}

A.1. példa - Írjunk az OsztályNév osztályunkhoz egy példánymetódust, ami visszaadja az

osztály String tagját!

public class OsztályNév {

String példányTagReferencia;

public OsztályNév(String példányTagReferencia) {

this.példányTagReferencia = példányTagReferencia;

}

public String példányMetódus() {

return példányTagReferencia;

}

public static void main(String[] args) {

OsztályNév osztályPéldány = new OsztályNév("Hello");

System.out.println(osztályPéldány.példányTagReferencia);

System.out.println(osztályPéldány.példányMetódus());

}

}

Ha a kedves Olvasó lefordítaná és futtatná a példát, akkor az alábbi eredményeket kapná.

C:\...> javac OsztályNév.java

C:\...> java OsztályNév

Hello

Hello

Adjuk meg a megoldást C Sharp nyelven is:

Page 314:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Java mellékletek

286 Created by XMLmind XSL-FO Converter.

public class OsztályNév {

System.String példányTagReferencia;

public OsztályNév(System.String példányTagReferencia) {

this.példányTagReferencia = példányTagReferencia;

}

public System.String példányMetódus() {

return példányTagReferencia;

}

public static void Main() {

OsztályNév osztályPéldány = new OsztályNév("Hello");

System.Console.WriteLine(osztályPéldány.példányTagReferencia);

System.Console.WriteLine(osztályPéldány.példányMetódus());

}

}

A Java példához hasonlóan, ha a kedves Olvasó lefordítaná és futtatná a példát, akkor az alábbi eredményeket

kapná.

C:\...> csc Osztály.java

C:\...> Osztály.exe

Hello

Hello

A Java és a C Sharp összehasonlítása iránt tovább érdeklődő kedves Olvasónak a [JAVA ás C SHARP], [C

SHARP J--] cikkeket ajánljuk.

Page 315:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

287 Created by XMLmind XSL-FO Converter.

B. függelék - Számítási mellékletek

„Mégis kitartok a remény mellett, hogy az értelem megértésében a természettudományokon és a matematikán

keresztül kell komoly előrehaladásnak létrejönnie.” —Roger Penrose A császár új elméje

1. Biológiai témájú programok

1.1. Genomi, aminosav vagy akár tetszőleges szekvenciák összehasonlítása

Ebben a pontban egy olyan (Swinges) grafikus felülettel ellátott pontmátrixot kiszámoló/megmutató/kimentő

programot készítünk, amivel tetszőleges sorozatokat, de főleg genomi vagy fehérje szekvenciákat tudunk

összehasonlítani. A pontmátrix részletes leírását a [BIOINFOMATIKA] könyvben találjuk. A pontmátrix

egyszerűen a mátrix, ami i. oszlopának és j. sorának értéke fekete, azaz az alábbi kódban 0x00000000, ha az

egyik minta i. eleme és a másik minta j. eleme megegyezik, különben 0x00ffffff fehér.

// A pontmátrix számítása:

for(int i=0; i<egyikMinta.length; ++i) {

for(int j=0; j<másikMinta.length; ++j) {

pontmátrixKép.setRGB(i,j, 0x00ffffff);

if(egyikMinta[i] == másikMinta[j])

pontmátrixKép.setRGB(i,j, 0x00000000);

}

}

A pontmátrix arról ad tehát tájékoztatást, hogy a két vizsgált minta mennyire egyezik meg. Ha például mindkét

mintának ugyanazt a sorozatot adjuk meg, akkor egy átlós egyenes jól láthatóvá válik a pontmátrixon.

A fejlesztendő pontmátrixos programot legördülő menüvel készítjük el, e menün keresztül vesszük át a

felhasználói inputot: a minták betöltését, a pontmátrix számításának indítását stb.

Page 316:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

288 Created by XMLmind XSL-FO Converter.

A minta szekvenciákat tartalmazó állományok betöltését és a kiszámolt pontmátrix képek mentését a

javax.swing.JFileChooser osztály segítségével végezzük. Az alábbi ábra egy ilyen objektum üzemét

mutatja az egyik minta betöltésénél.

A javax.swing.JFileChooser osztály használata kényelmes és egyszerű, például a kimentést megvalósító

kódunk az alábbi lesz.

} else if("Mentés...".equals(menü)) {

javax.swing.JFileChooser betöltő = new javax.swing.JFileChooser();

betöltő.showSaveDialog(getContentPane());

Page 317:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

289 Created by XMLmind XSL-FO Converter.

pillanatfelvétel(betöltő.getSelectedFile().getAbsolutePath());

}

ahol a betöltő.getSelectedFile().getAbsolutePath() a

ablakban megadott Ember_egér_tubulin_összehasonlítása.png állománynevet adja vissza, a

pillanatfelvétel() függvény pedig ebbe a paraméterként kapott nevű állományba menti majd a pontmátrix

képét.

A következő ábra üzem közben mutatja a példaprogramunkat. Éppen az

• ember http://www.expasy.org/uniprot/Q13748 (UniProtKB-Swiss-Prot entry Q13748 [TBA2_HUMAN]

Tubulin alpha-2 chain)

• és az egér http://www.expasy.org/uniprot/P05213 (UniProtKB-Swiss-Prot entry P05213 [TBA2_MOUSE]

Tubulin alpha-2 chain)

alfa tubulin 2 fehérjéjének kódját hasonlítjuk össze.

Page 318:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

290 Created by XMLmind XSL-FO Converter.

A kapott kép láthatóan zajos, ezért implementáltuk a Pontmátrix/Szűrés menüpontot is, amely annyiban több az

egyszerű számításnál, hogy az egyezéseket nem csupán a vizsgált szekvenciák egyedi tagjainál, hanem kis

csoportjaiban vizsgáljuk. Azaz nem csupán az i. és j. elemnek kell megegyeznie, hanem környezetükből többnek

is.

Page 319:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

291 Created by XMLmind XSL-FO Converter.

// A pontmátrix szűrése:

int ablakMéret = 7;

for(int i=0; i<egyikMinta.length; ++i) {

for(int j=0; j<másikMinta.length; ++j) {

int egyforma = 0;

for(int k = -ablakMéret; k<ablakMéret; ++k) {

if( i+k > 0 && i+k < egyikMinta.length

&& j+k > 0 && j+k < másikMinta.length)

if(egyikMinta[i+k] == másikMinta[j+k])

++egyforma;

}

pontmátrixKép.setRGB(i,j, 0x00ffffff);

if(egyforma > 2*ablakMéret-2)

pontmátrixKép.setRGB(i,j, 0x00000000);

}

}

A programmal végzett számítás (és szűrés) jól mutatja,

• az ember http://www.expasy.org/uniprot/Q13748

• és egér http://www.expasy.org/uniprot/P05213

• és az ember és C. elegans fonalféreg a http://www.expasy.org/uniprot/P34690

alfa tubulin 2 fehérjéjének hasonlóságát:

Page 320:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

292 Created by XMLmind XSL-FO Converter.

Láthatóan az emberé és az egéré sokkal inkább hasonló, mint alább, az emberé és a fonalféregé.

1.1.1. A Pontmátrix osztály

/*

* Pontmátrix.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

Page 321:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

293 Created by XMLmind XSL-FO Converter.

/**

* A pontmátrixot tartalmazó képet kirajzoló osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

class PontmátrixVászon extends javax.swing.JPanel {

/** A pontmátrixot tartalmazó kép. */

java.awt.image.BufferedImage pontmátrixKép;

// A panel mérete

java.awt.Dimension mátrixMéret =

new java.awt.Dimension(800, 800);

// A panel mérete

public java.awt.Dimension getPreferredSize() {

return mátrixMéret;

}

/** A pontmátrixot tartalmazó kép kirajzolása. */

public void paintComponent(java.awt.Graphics g) {

super.paintComponent(g);

if(pontmátrixKép != null)

g.drawImage(pontmátrixKép, 0, 0, this);

}

/** A pontmátrixot tartalmazó kép beállítása. */

public void beállítKép(java.awt.image.BufferedImage pontmátrixKép) {

this.pontmátrixKép = pontmátrixKép;

mátrixMéret.setSize(pontmátrixKép.getWidth(),

pontmátrixKép.getHeight());

}

}

/**

* A pontmátrixot számoló osztály.

* A pontmátrix leírását lásd a [BIOINFORMATIKA] hivatkozásban:

* (Maróti Péter: Információelmélet a biológiában, JATEPress 2003.)

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

public class Pontmátrix extends javax.swing.JFrame

implements java.awt.event.ActionListener {

/** Az egyik minta. */

byte [] egyikMinta;

/** A másik minta. */

byte [] másikMinta;

/** A pontmátrix képe. */

java.awt.image.BufferedImage pontmátrixKép;

/** A pontmátrix képét tartalmazó panel. */

PontmátrixVászon pontmátrixVászon;

/** A pontmátrix képét tartalmazó panelt tartalmazó görgető objektum. */

javax.swing.JScrollPane pontmátrixGörgető;

/** Informáló szövegdoboz. */

javax.swing.JTextArea infóTextArea;

/** A GUI felépítése. */

public Pontmátrix() {

// Az ablak adatai, fejléce:

super("Mindenféle szekvenciák összehasonlítása.");

// Pozíció és méret

java.awt.Dimension képernyőMéret =

java.awt.Toolkit.getDefaultToolkit().getScreenSize();

// Középre tesszük:

setBounds((int)képernyőMéret.getWidth()/2-300,

(int)képernyőMéret.getHeight()/2-200,

600, 400);

// Az ablak komponenseinek elhelyezési stratégiája:

// középen lesz a kép (CENTER), alatta (SOUTH) az

// informáló szövegdoboz.

getContentPane().setLayout(new java.awt.BorderLayout());

// Az ablak szokásos bezár gombjára is kilép a program:

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

// Legördülő menü elkészítése.

Page 322:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

294 Created by XMLmind XSL-FO Converter.

// A Menüsor:

javax.swing.JMenuBar menüSor = new javax.swing.JMenuBar();

// A Fájl menü

javax.swing.JMenu menü = new javax.swing.JMenu("Fájl");

menüSor.add(menü);

javax.swing.JMenuItem menüPont

= new javax.swing.JMenuItem("Egyik minta...");

menüPont.addActionListener(this);

menü.add(menüPont);

menüPont = new javax.swing.JMenuItem("Másik minta...");

menüPont.addActionListener(this);

menü.add(menüPont);

menüPont = new javax.swing.JMenuItem("Mentés...");

menüPont.addActionListener(this);

menü.add(menüPont);

menüPont = new javax.swing.JMenuItem("Kilépés");

menüPont.addActionListener(this);

menü.add(menüPont);

// A Pontmárix menü

menü = new javax.swing.JMenu("Pontmátrix");

menüPont.addActionListener(this);

menüSor.add(menü);

menüPont = new javax.swing.JMenuItem("Számol");

menüPont.addActionListener(this);

menü.add(menüPont);

menüPont = new javax.swing.JMenuItem("Szűrés");

menüPont.addActionListener(this);

menü.add(menüPont);

// A névjegy menü

menü = new javax.swing.JMenu("Névjegy");

menüPont.addActionListener(this);

menüSor.add(menü);

menüPont = new javax.swing.JMenuItem("Névjegy");

menüPont.addActionListener(this);

menü.add(menüPont);

// A menü hozzáadása az ablakhoz

setJMenuBar(menüSor);

// A pontmátrix képet erre a vászonra (panelre) rajzoljuk majd

pontmátrixVászon = new PontmátrixVászon();

pontmátrixVászon.setSize(800, 800);

// legyen görgethető

pontmátrixGörgető = new javax.swing.JScrollPane(pontmátrixVászon);

getContentPane().add(pontmátrixGörgető,

java.awt.BorderLayout.CENTER);

// Az informáló szövegdoboz

infóTextArea = new javax.swing.JTextArea();

// ez is legyen görgethető

javax.swing.JScrollPane infóScrollPane

= new javax.swing.JScrollPane();

infóScrollPane.setViewportView(infóTextArea);

infóScrollPane.setPreferredSize(new java.awt.Dimension(400, 100));

getContentPane().add(infóScrollPane, java.awt.BorderLayout.SOUTH);

// Kezdeti informáló szöveg

infóTextArea.append("Ez a Javat tanítok kézikönyv pontmátrix " +

"példaprogramja\nA pontmátrix leírását lásd a " +

"[BIOINFORMATIKA] hivatkozásban\n\n" +

"A Fájl/Egyik minta... Másik minta... " +

"menüpontok kiválasztásával tölts be a két mintát,\n" +

"majd alkalmazhatod a Pontmátrix/Számol menüpontot.\n");

// Lássuk!

setVisible(true);

}

/** Eseménykezelés. */

public void actionPerformed(java.awt.event.ActionEvent e) {

String menü = e.getActionCommand();

if("Egyik minta...".equals(menü)) {

egyikMinta = betöltMinta();

} else if("Másik minta...".equals(menü)) {

Page 323:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

295 Created by XMLmind XSL-FO Converter.

másikMinta = betöltMinta();

} else if("Számol".equals(menü)) {

if(egyikMinta == null) {

infóTextArea.append("A egyik minta nincs betöltve.\n");

return;

}

if(másikMinta == null) {

infóTextArea.append("A másik minta nincs betöltve.\n");

return;

}

pontmátrixKép =

new java.awt.image.BufferedImage(egyikMinta.length,

másikMinta.length,

java.awt.image.BufferedImage.TYPE_INT_RGB);

// A pontmátrix számítása:

for(int i=0; i<egyikMinta.length; ++i) {

for(int j=0; j<másikMinta.length; ++j) {

pontmátrixKép.setRGB(i,j, 0x00ffffff);

if(egyikMinta[i] == másikMinta[j])

pontmátrixKép.setRGB(i,j, 0x00000000);

}

}

infóTextArea.append("Pontrátrix számítása kész.\n");

// A kiszámolt pontmátrix megjelenítése

pontmátrixVászon.beállítKép(pontmátrixKép);

pontmátrixGörgető.setViewportView(pontmátrixVászon);

} else if("Névjegy".equals(menü)) {

// Egy informáló dialógus ablakot nyitunk a névjegynek:

javax.swing.JOptionPane.showMessageDialog(null,

"Pontmátrix, 0.0.1 verzió\nJavat tanítok példaprogram",

"Névjegy", javax.swing.JOptionPane.INFORMATION_MESSAGE);

} else if("Szűrés".equals(menü)) {

if(pontmátrixKép == null) {

infóTextArea.append("A pontmátrix nincs kiszámítva.\n");

return;

}

// A pontmátrix szűrése:

int ablakMéret = 7;

for(int i=0; i<egyikMinta.length; ++i) {

for(int j=0; j<másikMinta.length; ++j) {

int egyforma = 0;

for(int k = -ablakMéret; k<ablakMéret; ++k) {

if( i+k > 0 && i+k < egyikMinta.length

&& j+k > 0 && j+k < másikMinta.length)

if(egyikMinta[i+k] == másikMinta[j+k])

++egyforma;

}

pontmátrixKép.setRGB(i,j, 0x00ffffff);

if(egyforma > 2*ablakMéret-2)

pontmátrixKép.setRGB(i,j, 0x00000000);

}

}

infóTextArea.append("Pontrátrix szűrése kész.\n");

// A szűrt pontmátrix megjelenítése

pontmátrixVászon.beállítKép(pontmátrixKép);

pontmátrixGörgető.setViewportView(pontmátrixVászon);

} else if("Mentés...".equals(menü)) {

javax.swing.JFileChooser betöltő = new javax.swing.JFileChooser();

betöltő.showSaveDialog(getContentPane());

pillanatfelvétel(betöltő.getSelectedFile().getAbsolutePath());

Page 324:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

296 Created by XMLmind XSL-FO Converter.

} else if("Kilépés".equals(menü)) {

System.exit(0);

}

}

/**

* Fájl betöltése fájl kiválasztó ablakkal.

*

* @return byte [] a fájl tartalma, mint minta.

*/

public byte [] betöltMinta() {

javax.swing.JFileChooser betöltő = new javax.swing.JFileChooser();

betöltő.showOpenDialog(getContentPane());

java.io.File fájl = betöltő.getSelectedFile().getAbsoluteFile();

byte [] buffer = new byte[(int)fájl.length()];

try {

java.io.FileInputStream fájlCsatorna =

new java.io.FileInputStream(fájl);

fájlCsatorna.read(buffer, 0, buffer.length);

} catch(java.io.IOException e) {

e.printStackTrace();

}

infóTextArea.append("A " + fájl.getName() + " minta betöltve.\n");

return buffer;

}

/** Pillanatfelvételek készítése. */

public void pillanatfelvétel(String fájlNév) {

// png formátumú képet mentünk

try {

javax.imageio.ImageIO.write(pontmátrixKép, "png",

new java.io.File(fájlNév));

} catch(java.io.IOException e) {

e.printStackTrace();

}

}

/** Példányosít egy Pontmátrix obektumot.*/

public static void main(String [] args) {

new Pontmátrix();

}

}

B.1. példa - Pontmátrix osztály kiegészítése

A pontmátrix programunk névjegye mintájára dialógusablakokban is közöljük a program hibaüzeneteit a

felhasználó felé. Ezt a módszert alkalmaztuk a névjegy információk megjelenítésénél:

} else if("Névjegy".equals(menü)) {

// Egy informáló dialógus ablakot nyitunk a névjegynek:

javax.swing.JOptionPane.showMessageDialog(null,

"Pontmátrix, 0.0.1 verzió\nJavat tanítok példaprogram",

"Névjegy", javax.swing.JOptionPane.INFORMATION_MESSAGE);

Page 325:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

297 Created by XMLmind XSL-FO Converter.

Ha például valamelyik minta még nincs betöltve, akkor ezt ne csak az

if(egyikMinta == null) {

infóTextArea.append("A egyik minta nincs betöltve.\n");

return;

}

informáló ablakban, hanem egy dialógus ablakban is közöljük.

javax.swing.JOptionPane.showMessageDialog(null,

"A egyik minta nincs betöltve.",

"Hiba", javax.swing.JOptionPane.ERROR_MESSAGE);

B.2. példa - További kísérletek a Pontmátrix osztályunkkal

A Pi jegyeinek nyomában pont programját felhasználva legenerálhatjuk a Pi hexadecimális kifejtésének

mondjuk első és második ezer hexa jegyét, majd ezeket a pontmátrix módszerrel összehasonlíthatjuk. De

mindkét mintának az első ezer jegyet átadva afelől tudakolódhatunk, hogy mennyire van ismétlődés ebben az

ezer hexa jegyes szekvenciában önmagában.

A következő TCAG2Hexa osztálybeli rövid kóddal az előző pontban említett emberi 2. kromoszóma genomjának

egy részét hexadecimális számjegyekké alakítva összevethetjük a humán genom e részét például a Pi

hexadecimális kifejtésének számjegyeivel!

A TCAG2Hexa osztály a bemenetéről olvasott T, C, A, G betűket kettessével - mert 4 féle * 4 féle éppen 16 -

hexa számjegyekké alakítja:

public class TCAG2Hexa {

public static void main(String[] args) throws Exception {

Character hexaJegyek[] = {'A', 'B', 'C', 'D', 'E', 'F'};

boolean páratlan = false;

int első=0, második=0;

int i = 0;

while((i=System.in.read()) != -1) {

switch(i) {

case 'T':

második = 0;

break;

case 'C':

második = 1;

Page 326:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

298 Created by XMLmind XSL-FO Converter.

break;

case 'A':

második = 2;

break;

case 'G':

második = 3;

break;

}

if(páratlan) {

int jegy = 4*első + második;

if(jegy<10)

System.out.print(jegy);

else

System.out.print(hexaJegyek[jegy-10]);

}

páratlan = !páratlan;

első = második;

}

}

}

A hexába konvertáló TCAG2Hexa osztályt fordítva és futtatáskor a humán genom említett, most 1875 betűt részét

tartalmazó 2cgenom1875.fasta állomány tartalmát beleirányítva a kimenetet a genom.hexa állományban

kapjuk.

C:\...> javac TCAG2Hexa.java

C:\...> java TCAG2Hexa <2cgenom1875.fasta > genom.hexa

A kapott genom.hexa állományt és a Pi első ezer jegyét tartalmazó állományt adjuk majd át a pontmátrix

programunknak. Ez persze egy erősen spekulatív példánk volt, de ha kirajzolódott volna egy átlós egyenes a

pontmártixon, akkor talán hasonló élményünk lehetett volna, mint Mandelbrotnak, amikor rábukkant híres

halmazára.

1.1.2. A Swinges felület építésének alapszabálya

A Swinges felületek építésének alapszabálya, hogy ne csináltassunk időigényes dolgokat az

eseménykezelőkben, mivel az eseménykezelést és a megjelenítést ugyanaz a programszál végzi, így ha az

eseménykezelőt egy hosszadalmas számítással blokkoljuk, akkor ezzel egyben a felület megjelenítését is

blokkoljuk, azaz lefagyasztjuk a programunk felületét!

Szerezzünk most konkrét tapasztalatot az említett szabállyal kapcsolatban! Például pontmátrix számoló

programunknak inputként adjuk meg a 2. emberi kromoszóma egy hozzávetőlegesen 2000 (T, C, A, G)

nukleotid betűs részletét, az egyik és a másik mintaként is. Ebben az esetben a szekvenciában az ismétlődő

részeket tudjuk megfigyelni. Az érdeklődő Olvasó a Humán Genom Projekt keretében meghatározott emberi

DNS adatokat a http://www.ncbi.nlm.nih.gov/genome/seq címen találhatja meg. Erre a nagy, közel 2000x2000

pixel méretű képre a Szűrés menüpontot alkalmazva, amíg a szűrés be nem fejeződik, addig a felület lefagyott

állapotban van, nem frissül és felhasználói eseményekre sem reagál, azaz hiába kattintunk például a Névjegy

menüpontra, semmi nem történik, amíg be nem fejeződik a szűrés.

Page 327:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

299 Created by XMLmind XSL-FO Converter.

1.2. Sejtautomata szimuláció programja

Egy konkrét sejtautomatával - talán a legismertebb ilyennel - a John Horton Conway-féle életjátékkal ([MATEK

JÁTÉK], [ÉLET CIKK]) foglalkozunk részletesen. Itt egy sejt egy sejttér eleme, a sejt állapota lehet élő vagy

halott. A diszkrét időben működő sejttér adott sejtjének állapotát a következő időpillanatban a következő

átmeneti szabályok alapján számolhatjuk ki:

• Élő sejt élő marad, ha kettő vagy három élő szomszédja van, különben halott lesz.

• Halott sejt halott marad, ha három élő szomszédja van, különben élő lesz.

Ezeket az átmeneti szabályokat az időFejlődés() függvényben fogalmaztuk meg:

public void időFejlődés() {

boolean [][] rácsElőtte = rácsok[rácsIndex];

boolean [][] rácsUtána = rácsok[(rácsIndex+1)%2];

for(int i=0; i<rácsElőtte.length; ++i) { // sorok

for(int j=0; j<rácsElőtte[0].length; ++j) { // oszlopok

int élők = szomszédokSzáma(rácsElőtte, i, j, ÉLŐ);

if(rácsElőtte[i][j] == ÉLŐ) {

/* Élő élő marad, ha kettő vagy három élő

Page 328:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

300 Created by XMLmind XSL-FO Converter.

szomszedja van, különben halott lesz. */

if(élők==2 || élők==3)

rácsUtána[i][j] = ÉLŐ;

else

rácsUtána[i][j] = HALOTT;

} else {

/* Halott halott marad, ha három élő

szomszedja van, különben élő lesz. */

if(élők==3)

rácsUtána[i][j] = ÉLŐ;

else

rácsUtána[i][j] = HALOTT;

}

}

}

rácsIndex = (rácsIndex+1)%2;

}

/*

* Sejtautomata.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* Sejtautomata osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

public class Sejtautomata extends java.awt.Frame implements Runnable {

/** Egy sejt lehet élő */

public static final boolean ÉLŐ = true;

/** vagy halott */

public static final boolean HALOTT = false;

/** Két rácsot használunk majd, az egyik a sejttér állapotát

* a t_n, a másik a t_n+1 időpillanatban jellemzi. */

protected boolean [][][] rácsok = new boolean [2][][];

/** Valamelyik rácsra mutat, technikai jellegű, hogy ne kelljen a

* [2][][]-ból az első dimenziót használni, mert vagy az egyikre

* állítjuk, vagy a másikra. */

protected boolean [][] rács;

/** Megmutatja melyik rács az aktuális: [rácsIndex][][] */

protected int rácsIndex = 0;

/** Pixelben egy cella adatai. */

protected int cellaSzélesség = 20;

protected int cellaMagasság = 20;

/** A sejttér nagysága, azaz hányszor hány cella van? */

protected int szélesség = 20;

protected int magasság = 10;

/** A sejttér két egymást követő t_n és t_n+1 diszkrét időpillanata

közötti valós idő. */

protected int várakozás = 1000;

// Pillanatfelvétel készítéséhez

private java.awt.Robot robot;

/** Készítsünk pillanatfelvételt? */

private boolean pillanatfelvétel = false;

/** A pillanatfelvételek számozásához. */

private static int pillanatfelvételSzámláló = 0;

/**

* Létrehoz egy <code>Sejtautomata</code> objektumot.

*

* @param szélesség a sejttér szélessége.

* @param magasság a sejttér szélessége.

*/

public Sejtautomata(int szélesség, int magasság) {

Page 329:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

301 Created by XMLmind XSL-FO Converter.

this.szélesség = szélesség;

this.magasság = magasság;

// A két rács elkészítése

rácsok[0] = new boolean[magasság][szélesség];

rácsok[1] = new boolean[magasság][szélesség];

rácsIndex = 0;

rács = rácsok[rácsIndex];

// A kiinduló rács minden cellája HALOTT

for(int i=0; i<rács.length; ++i)

for(int j=0; j<rács[0].length; ++j)

rács[i][j] = HALOTT;

// A kiinduló rácsra "élőlényeket" helyezünk

//sikló(rács, 2, 2);

siklóKilövő(rács, 5, 60);

// Az ablak bezárásakor kilépünk a programból.

addWindowListener(new java.awt.event.WindowAdapter() {

public void windowClosing(java.awt.event.WindowEvent e) {

setVisible(false);

System.exit(0);

}

});

// A billentyűzetről érkező események feldolgozása

addKeyListener(new java.awt.event.KeyAdapter() {

// Az 'k', 'n', 'l', 'g' és 's' gombok lenyomását figyeljük

public void keyPressed(java.awt.event.KeyEvent e) {

if(e.getKeyCode() == java.awt.event.KeyEvent.VK_K) {

// Felezük a cella méreteit:

cellaSzélesség /= 2;

cellaMagasság /= 2;

setSize(Sejtautomata.this.szélesség*cellaSzélesség,

Sejtautomata.this.magasság*cellaMagasság);

validate();

} else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_N) {

// Duplázzuk a cella méreteit:

cellaSzélesség *= 2;

cellaMagasság *= 2;

setSize(Sejtautomata.this.szélesség*cellaSzélesség,

Sejtautomata.this.magasság*cellaMagasság);

validate();

} else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_S)

pillanatfelvétel = !pillanatfelvétel;

else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_G)

várakozás /= 2;

else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_L)

várakozás *= 2;

repaint();

}

});

// Egér kattintó események feldolgozása:

addMouseListener(new java.awt.event.MouseAdapter() {

// Egér kattintással jelöljük ki a nagyítandó területet

// bal felső sarkát vagy ugyancsak egér kattintással

// vizsgáljuk egy adott pont iterációit:

public void mousePressed(java.awt.event.MouseEvent m) {

// Az egérmutató pozíciója

int x = m.getX()/cellaSzélesség;

int y = m.getY()/cellaMagasság;

rácsok[rácsIndex][y][x] = !rácsok[rácsIndex][y][x];

repaint();

}

});

// Egér mozgás események feldolgozása:

addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {

// Vonszolással jelöljük ki a négyzetet:

public void mouseDragged(java.awt.event.MouseEvent m) {

int x = m.getX()/cellaSzélesség;

int y = m.getY()/cellaMagasság;

rácsok[rácsIndex][y][x] = ÉLŐ;

repaint();

}

});

// Cellaméretek kezdetben

Page 330:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

302 Created by XMLmind XSL-FO Converter.

cellaSzélesség = 10;

cellaMagasság = 10;

// Pillanatfelvétel készítéséhez:

try {

robot = new java.awt.Robot(

java.awt.GraphicsEnvironment.

getLocalGraphicsEnvironment().

getDefaultScreenDevice());

} catch(java.awt.AWTException e) {

e.printStackTrace();

}

// A program ablakának adatai:

setTitle("Sejtautomata");

setResizable(false);

setSize(szélesség*cellaSzélesség,

magasság*cellaMagasság);

setVisible(true);

// A sejttér életrekeltése:

new Thread(this).start();

}

/** A sejttér kirajzolása. */

public void paint(java.awt.Graphics g) {

// Az aktuális

boolean [][] rács = rácsok[rácsIndex];

// rácsot rajzoljuk ki:

for(int i=0; i<rács.length; ++i) { // végig lépked a sorokon

for(int j=0; j<rács[0].length; ++j) { // s az oszlopok

// Sejt cella kirajzolása

if(rács[i][j] == ÉLŐ)

g.setColor(java.awt.Color.BLACK);

else

g.setColor(java.awt.Color.WHITE);

g.fillRect(j*cellaSzélesség, i*cellaMagasság,

cellaSzélesség, cellaMagasság);

// Rács kirajzolása

g.setColor(java.awt.Color.LIGHT_GRAY);

g.drawRect(j*cellaSzélesség, i*cellaMagasság,

cellaSzélesség, cellaMagasság);

}

}

// Készítünk pillanatfelvételt?

if(pillanatfelvétel) {

// a biztonság kedvéért egy kép készítése után

// kikapcsoljuk a pillanatfelvételt, hogy a

// programmal ismerkedő Olvasó ne írja tele a

// fájlrendszerét a pillanatfelvételekkel

pillanatfelvétel = false;

pillanatfelvétel(robot.createScreenCapture

(new java.awt.Rectangle

(getLocation().x, getLocation().y,

szélesség*cellaSzélesség,

magasság*cellaMagasság)));

}

}

/**

* Az kérdezett állapotban lévő nyolcszomszédok száma.

*

* @param rács a sejttér rács

* @param sor a rács vizsgált sora

* @param oszlop a rács vizsgált oszlopa

* @param állapor a nyolcszomszédok vizsgált állapota

* @return int a kérdezett állapotbeli nyolcszomszédok száma.

*/

public int szomszédokSzáma(boolean [][] rács,

int sor, int oszlop, boolean állapot) {

int állapotúSzomszéd = 0;

// A nyolcszomszédok végigzongorázása:

for(int i=-1; i<2; ++i)

for(int j=-1; j<2; ++j)

// A vizsgált sejtet magát kihagyva:

if(!((i==0) && (j==0))) {

// A sejttérből szélének szomszédai

Page 331:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

303 Created by XMLmind XSL-FO Converter.

// a szembe oldalakon ("periódikus határfeltétel")

int o = oszlop + j;

if(o < 0)

o = szélesség-1;

else if(o >= szélesség)

o = 0;

int s = sor + i;

if(s < 0)

s = magasság-1;

else if(s >= magasság)

s = 0;

if(rács[s][o] == állapot)

++állapotúSzomszéd;

}

return állapotúSzomszéd;

}

/**

* A sejttér időbeli fejlődése a John H. Conway féle

* életjáték sejtautomata szabályai alapján történik.

* A szabályok részletes ismertetését lásd például a

* [MATEK JÁTÉK] hivatkozásban (Csákány Béla: Diszkrét

* matematikai játékok. Polygon, Szeged 1998. 171. oldal.)

*/

public void időFejlődés() {

boolean [][] rácsElőtte = rácsok[rácsIndex];

boolean [][] rácsUtána = rácsok[(rácsIndex+1)%2];

for(int i=0; i<rácsElőtte.length; ++i) { // sorok

for(int j=0; j<rácsElőtte[0].length; ++j) { // oszlopok

int élők = szomszédokSzáma(rácsElőtte, i, j, ÉLŐ);

if(rácsElőtte[i][j] == ÉLŐ) {

/* Élő élő marad, ha kettő vagy három élő

szomszedja van, különben halott lesz. */

if(élők==2 || élők==3)

rácsUtána[i][j] = ÉLŐ;

else

rácsUtána[i][j] = HALOTT;

} else {

/* Halott halott marad, ha három élő

szomszedja van, különben élő lesz. */

if(élők==3)

rácsUtána[i][j] = ÉLŐ;

else

rácsUtána[i][j] = HALOTT;

}

}

}

rácsIndex = (rácsIndex+1)%2;

}

/** A sejttér időbeli fejlődése. */

public void run() {

while(true) {

try {

Thread.sleep(várakozás);

} catch (InterruptedException e) {}

időFejlődés();

repaint();

}

}

/**

* A sejttérbe "élőlényeket" helyezünk, ez a "sikló".

* Adott irányban halad, másolja magát a sejttérben.

* Az élőlény ismertetését lásd például a

* [MATEK JÁTÉK] hivatkozásban (Csákány Béla: Diszkrét

Page 332:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

304 Created by XMLmind XSL-FO Converter.

* matematikai játékok. Polygon, Szeged 1998. 172. oldal.)

*

* @param rács a sejttér ahová ezt az állatkát helyezzük

* @param x a befoglaló tégla bal felső sarkának oszlopa

* @param y a befoglaló tégla bal felső sarkának sora

*/

public void sikló(boolean [][] rács, int x, int y) {

rács[y+ 0][x+ 2] = ÉLŐ;

rács[y+ 1][x+ 1] = ÉLŐ;

rács[y+ 2][x+ 1] = ÉLŐ;

rács[y+ 2][x+ 2] = ÉLŐ;

rács[y+ 2][x+ 3] = ÉLŐ;

}

/**

* A sejttérbe "élőlényeket" helyezünk, ez a "sikló ágyú".

* Adott irányban siklókat lő ki.

* Az élőlény ismertetését lásd például a

* [MATEK JÁTÉK] hivatkozásban /Csákány Béla: Diszkrét

* matematikai játékok. Polygon, Szeged 1998. 173. oldal./,

* de itt az ábra hibás, egy oszloppal told még balra a

* bal oldali 4 sejtes négyzetet. A helyes ágyú rajzát

* lásd pl. az [ÉLET CIKK] hivatkozásban /Robert T.

* Wainwright: Life is Universal./ (Megemlíthetjük, hogy

* mindkettő tartalmaz két felesleges sejtet is.)

*

* @param rács a sejttér ahová ezt az állatkát helyezzük

* @param x a befoglaló tégla bal felső sarkának oszlopa

* @param y a befoglaló tégla bal felső sarkának sora

*/

public void siklóKilövő(boolean [][] rács, int x, int y) {

rács[y+ 6][x+ 0] = ÉLŐ;

rács[y+ 6][x+ 1] = ÉLŐ;

rács[y+ 7][x+ 0] = ÉLŐ;

rács[y+ 7][x+ 1] = ÉLŐ;

rács[y+ 3][x+ 13] = ÉLŐ;

rács[y+ 4][x+ 12] = ÉLŐ;

rács[y+ 4][x+ 14] = ÉLŐ;

rács[y+ 5][x+ 11] = ÉLŐ;

rács[y+ 5][x+ 15] = ÉLŐ;

rács[y+ 5][x+ 16] = ÉLŐ;

rács[y+ 5][x+ 25] = ÉLŐ;

rács[y+ 6][x+ 11] = ÉLŐ;

rács[y+ 6][x+ 15] = ÉLŐ;

rács[y+ 6][x+ 16] = ÉLŐ;

rács[y+ 6][x+ 22] = ÉLŐ;

rács[y+ 6][x+ 23] = ÉLŐ;

rács[y+ 6][x+ 24] = ÉLŐ;

rács[y+ 6][x+ 25] = ÉLŐ;

rács[y+ 7][x+ 11] = ÉLŐ;

rács[y+ 7][x+ 15] = ÉLŐ;

rács[y+ 7][x+ 16] = ÉLŐ;

rács[y+ 7][x+ 21] = ÉLŐ;

rács[y+ 7][x+ 22] = ÉLŐ;

rács[y+ 7][x+ 23] = ÉLŐ;

rács[y+ 7][x+ 24] = ÉLŐ;

rács[y+ 8][x+ 12] = ÉLŐ;

rács[y+ 8][x+ 14] = ÉLŐ;

rács[y+ 8][x+ 21] = ÉLŐ;

rács[y+ 8][x+ 24] = ÉLŐ;

rács[y+ 8][x+ 34] = ÉLŐ;

rács[y+ 8][x+ 35] = ÉLŐ;

rács[y+ 9][x+ 13] = ÉLŐ;

Page 333:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

305 Created by XMLmind XSL-FO Converter.

rács[y+ 9][x+ 21] = ÉLŐ;

rács[y+ 9][x+ 22] = ÉLŐ;

rács[y+ 9][x+ 23] = ÉLŐ;

rács[y+ 9][x+ 24] = ÉLŐ;

rács[y+ 9][x+ 34] = ÉLŐ;

rács[y+ 9][x+ 35] = ÉLŐ;

rács[y+ 10][x+ 22] = ÉLŐ;

rács[y+ 10][x+ 23] = ÉLŐ;

rács[y+ 10][x+ 24] = ÉLŐ;

rács[y+ 10][x+ 25] = ÉLŐ;

rács[y+ 11][x+ 25] = ÉLŐ;

}

/** Pillanatfelvételek készítése. */

public void pillanatfelvétel(java.awt.image.BufferedImage felvetel) {

// A pillanatfelvétel kép fájlneve

StringBuffer sb = new StringBuffer();

sb = sb.delete(0, sb.length());

sb.append("sejtautomata");

sb.append(++pillanatfelvételSzámláló);

sb.append(".png");

// png formátumú képet mentünk

try {

javax.imageio.ImageIO.write(felvetel, "png",

new java.io.File(sb.toString()));

} catch(java.io.IOException e) {

e.printStackTrace();

}

}

// Ne villogjon a felület (mert a "gyári" update()

// lemeszelné a vászon felületét).

public void update(java.awt.Graphics g) {

paint(g);

}

/**

* Példányosít egy Conway-féle életjáték szabályos

* sejttér obektumot.

*/

public static void main(String[] args) {

// 100 oszlop, 75 sor mérettel:

new Sejtautomata(100, 75);

}

}

Könnyen végezhetünk saját szimulációkat az osztály imént megadott kódjával. Jelöljük ki a forrásszöveget és

illesszük be egy Sejtautomata.java nevű állományba, majd fordítsuk az állományt és futtassuk a számítást:

C:\...> javac Sejtautomata.java

C:\...> java Sejtautomata

A program futása alatt az s billentyűt lenyomva a sejttér aktuális pillanatbeli állapotáról egy felvételt készít a

program. A készített képeket abban a könyvtárban találjuk, ahonnan a programot a fent ajánlott módon

elindítottuk.

Korábbi tárgyalásunknak megfelelően a program a következő inputokat dolgoza fel:

• Az s billentyű lenyomásával egy felvétel kép készül a sejttér aktuális állapotáról.

• Az n billentyű lenyomásával növeljük a sejtek méretét.

• A k billentyű lenyomásával csökkentjük a sejtek méretét.

Page 334:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

306 Created by XMLmind XSL-FO Converter.

• A g billentyű lenyomásával csökkentjük a sejttér két diszkrét állapota közötti valóságos időt, azaz gyorsítjuk a

szimulációt.

• Az l billentyű lenyomásával lassítjuk a szimulációt.

• Az egérmutató jobb vagy bal gombjával egy sejt állapotát az ellenkezőjére változtatjuk.

• Az egérmutató vonszolásával az érintett sejteket élő állapotba kapcsoljuk.

A következő ábrasorozaton bemutatjuk az R. W. Gosper találta [MATEK JÁTÉK], [ÉLET CIKK] „sikló ágyú”

élőlényt üzem közben (az első hivatkozásban közölt ágyú picit hibás, ezért csak három lövést ad le, de mindkét

hivatkozás tartalmaz két felesleges sejtet).

B.1. táblázat - Az R. W. Gosper-féle sikló ágyú élőlény bemutatása

Page 335:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

307 Created by XMLmind XSL-FO Converter.

Page 336:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

308 Created by XMLmind XSL-FO Converter.

Page 337:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

309 Created by XMLmind XSL-FO Converter.

Page 338:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

310 Created by XMLmind XSL-FO Converter.

Page 339:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

311 Created by XMLmind XSL-FO Converter.

Page 340:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

312 Created by XMLmind XSL-FO Converter.

1.3. Orch OR demonstrációk

A mikrotubulus sejtautomata - szemben az előző pont példájával - nem négy vagy nyolc szomszéddal dolgozik,

hanem amint a Hameroff mikrotubulus sejtautomatái című pontban megmutattuk, egy hexagonális rácson, ahol

egy adott sejtnek hat szomszédja van.

1.3.1. Hexagonális rács

Ilyen hexagonális rácsot geometriailag könnyen kaphatunk, ha klasszikus tömbünket (rácsunkat) lerajzoljuk és

minden második oszlopát egy rajzolt cella felével eltoljuk. Azért használjuk ezt a triviális szemléletbeli képet,

mert a klasszikus tömbök kezelése - lévén, hogy elemei a Java nyelvnek - egyszerű.

Page 341:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

313 Created by XMLmind XSL-FO Converter.

Tehát, ha klasszikus tömböket akarunk használni a szimuláció

programozásánál, csak arra kell figyelni, hogy az eltolt rácson lévő adott sejt hat szomszédai kik lesznek a

klasszikusra visszatolt rácson?

Az ábráról

leolvasható, hogy triviálisan tudunk szokásos tömböket használni, amiket majd a megjelenítés során, második

oszloponként eltolva rajzolunk ki. A szomszédok pozíciója pedig attól függ, hogy eltolt vagy nem eltolt

oszlopban van-e a vizsgált sejt.

1.3.1.1. A Mikrotubulus osztály

GUI programozási szempontból tartjuk fontosnak megjegyezni, hogy a Mikrotubulus osztály közvetlenül

önmagára rajzol, jobb gyakorlat egy az ablakra helyezett vászonra vagy képre rajzolni. Az utóbbira például a

kézikönyv Mandelbrot halmaz című pontjában láthatunk példát. Itt a MandelbrotHalmaz osztály

pillanatfelvétel() pillanatfelvételt készítő függvényében használjuk ki például a képre rajzolást.

Page 342:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

314 Created by XMLmind XSL-FO Converter.

/*

* Mikrotubulus.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* Orch OR sejtautomata demonstráció.

* A jelen szimulációs vagy pontosabban csupán - az [ORCH OR] Stuart

* Hameroff és Roger Penrose, Orchestrated Objective Reduction of

* Quantum Coherence in Brain Microtubules: The “Orch OR” Model for

* Consciousmess,

* http://www.quantumconsciousness.org/penrose-hameroff/orchOR.html

* [ORCH OR TUDAT] Stuart Hameroff és Roger Penrose, Conscious Events

* as Orchestrated Space-Time Selections,

* http://www.quantumconsciousness.org/penrosehameroff/consciousevents.html

* cikkek képei alapján készített - demonstrációs osztály azt mutatja,

* hogy egyre több tubulin dimer kerül koherens állapotba, míg az

* objektív redukció következtében egy előre nem kiszámítható módon

* ugranak a résztvevő cellák valamely lehetséges állapotukba,

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

public class Mikrotubulus extends java.awt.Frame implements Runnable {

/** Rácspont az egyik állapotában. */

public static final int EGYIK = 0;

/** Rácspont a másik állapotában. */

public static final int MÁSIK = 1;

/** Rácspont az összefonódott állapotban. */

public static final int SZUPER = 2;

/** Hány összefonódott rácspont indítja be az OR-t? */

public static final int EGY_GRAVITON_SZINTNYI = 235;

/** Két ráccsal dolgozunk: a diszkrét időskála adott

* pillanata előtti és utáni rácsot írjuk le velük. */

int [][][] hexagonálisRácsok = new int [2][][];

/** Melyik az éppen aktuális rács? */

int [][] hexagonálisRács;

/** A 0. vagy az 1. ? */

int rácsIndex = 0;

/* A kirajzolás adatai: */

int cellaSzélesség = 20;

int cellaMagasság = 20;

/* A rács adatai: */

int szélesség = 13;

int magasság = 20;

// Technikai:

java.util.Random random = new java.util.Random();

/* Képek a kirajzoláshoz */

java.awt.Image fehérKép;

java.awt.Image feketeKép;

java.awt.Image pirosKép;

// A pillanatfelvételekhez, technikai:

java.awt.Robot robot;

/**

* Az adott méretű {@code Mikrotubulus} objektumot

* felépítő konstruktor.

*

* @param szélesség tubulin-dimerek száma vízszintesen

* @param magasság tubulin-dimerek száma függőlegesen

*/

public Mikrotubulus(int szélesség, int magasság) {

this.szélesség = szélesség;

this.magasság = magasság;

// A diszkrét időskála adott

// pillanata előtti és utáni rácsok:

hexagonálisRácsok[0] = new int[magasság][szélesség];

hexagonálisRácsok[1] = new int[magasság][szélesség];

Page 343:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

315 Created by XMLmind XSL-FO Converter.

hexagonálisRács = hexagonálisRácsok[rácsIndex];

// a rácspontok egy véletlen állapotából indul a sejtautomata

for(int i=0; i<hexagonálisRács.length; ++i)

for(int j=0; j<hexagonálisRács[0].length; ++j)

hexagonálisRács[i][j] = random.nextInt(2);

// innen indul ki egy összefonódás

hexagonálisRács[10][6] = SZUPER;

// a program ablaka, amit be is lehet csukni

addWindowListener(new java.awt.event.WindowAdapter() {

public void windowClosing(java.awt.event.WindowEvent e) {

setVisible(false);

System.exit(0);

}

});

// Képek betöltése

fehérKép = new javax.swing.ImageIcon

("fehér.png").getImage();

feketeKép = new javax.swing.ImageIcon

("fekete.png").getImage();

pirosKép = new javax.swing.ImageIcon

("piros.png").getImage();

cellaSzélesség = fehérKép.getWidth(this);

cellaMagasság = fehérKép.getHeight(this);

// a lokális grafikus környezet elkérése

java.awt.GraphicsEnvironment graphicsEnvironment

= java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment();

// a grafikus környzetből a képernyővel dolgozunk

java.awt.GraphicsDevice graphicsDevice

= graphicsEnvironment.getDefaultScreenDevice();

try {

robot = new java.awt.Robot(graphicsDevice);

} catch(java.awt.AWTException e) {

e.printStackTrace();

}

// Ablak jellemzőinek beállítása

setTitle("Mikrotubulus");

setResizable(false);

//setUndecorated(true);

setSize(szélesség*cellaSzélesség,

magasság*cellaMagasság);

setVisible(true);

// Szimulációs (demonstrációs) szál elkészítése és beindítása

new Thread(this).start();

}

/* A felület kirajzolása */

public void paint(java.awt.Graphics g) {

// Éppen melyik rácsot kell rajzolnunk:

int [][] hexagonálisRács = hexagonálisRácsok[rácsIndex];

// "Töröljük" a felületet (ha villog, töröljünk a

// következő ciklusban kis darabokat)

g.setColor(java.awt.Color.GRAY);

g.fillRect(0,0, szélesség*cellaSzélesség,

magasság*cellaMagasság);

// Végigmegyünk a rácspontokon:

for(int i=0; i<hexagonálisRács.length; ++i) { // sorok

for(int j=0; j<hexagonálisRács[0].length; ++j) { // oszlopok

/* Csak a rácsot rajzolja

g.setColor(java.awt.Color.BLACK);

g.drawRect(j*20, i*20+(j%2)*10, 20, 20);

Csak a rácsot rajzolja */

/* Nem képeket, színes téglalapokat rajzol

Page 344:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

316 Created by XMLmind XSL-FO Converter.

if(hexagonálisRács[i][j] == EGYIK)

g.setColor(java.awt.Color.BLACK);

else if(hexagonálisRács[i][j] == MÁSIK)

g.setColor(java.awt.Color.WHITE);

else

g.setColor(java.awt.Color.RED);

// a +(j%2)*10 a páratlanadik oszlopokat

// lefelé tolja

g.fillRect(j*20, i*20+(j%2)*10, 20, 20);

Nem képeket, színes téglalapokat rajzol */

// A szimulációs képeket rajzolja

if(hexagonálisRács[i][j] == EGYIK)

g.drawImage(fehérKép, j*fehérKép.getWidth(this),

i*fehérKép.getHeight(this)

+(j%2)*(fehérKép.getHeight(this)/2), null);

else if(hexagonálisRács[i][j] == MÁSIK)

g.drawImage(feketeKép, j*feketeKép.getWidth(this),

i*feketeKép.getHeight(this)

+(j%2)*(fehérKép.getHeight(this)/2), null);

else

g.drawImage(pirosKép, j*pirosKép.getWidth(this),

i*pirosKép.getHeight(this)

+(j%2)*(fehérKép.getHeight(this)/2), null);

// A szimulációs képeket rajzolja

}

}

boolean pillanatfelvetel = false;

if(pillanatfelvetel) {

pillanatfelvetel = false;

pillanatfelvetel(robot.createScreenCapture

(new java.awt.Rectangle

(0, 0, szélesség*cellaSzélesség,

magasság*cellaMagasság)));

}

}

/* Technikai a villogás ellen (nem meszeli le a hátteret az update(),

mert most felüldefiniáljuk meszelés nélkül). */

public void update(java.awt.Graphics g) {

paint(g);

}

// A pillanatfelvételek számozásához

public static int fotoSzamlalo = 0;

/** ScreenShot készítése. */

public void pillanatfelvetel(java.awt.image.BufferedImage felvetel) {

// tech. a sztringezéshez: a képfájl nevének előállítása

StringBuffer sb = new StringBuffer();

sb = sb.delete(0, sb.length());

sb.append("mikrotubulus");

sb.append(++fotoSzamlalo);

sb.append(".png");

// a kép mentése

try {

// png-t mentünk

javax.imageio.ImageIO.write(felvetel, "png",

new java.io.File(sb.toString()));

} catch(java.io.IOException e) {

e.printStackTrace();

}

}

/**

* A rács adott cellájának hány szomszéda van a kérdezett állapotban?

*/

public int szomszédokSzáma(int [][] hexagonálisRács,

int sor, int oszlop, int állapot) {

Page 345:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

317 Created by XMLmind XSL-FO Converter.

int állapotúSzomszéd = 0;

if(oszlop%2 == 1) {

if(sor-1>0)

if(hexagonálisRács[sor-1][oszlop] == állapot)

++állapotúSzomszéd;

if(sor+1<magasság)

if(hexagonálisRács[sor+1][oszlop] == állapot)

++állapotúSzomszéd;

if(oszlop-1>0) {

if(hexagonálisRács[sor][oszlop-1] == állapot)

++állapotúSzomszéd;

if(sor+1<magasság)

if(hexagonálisRács[sor+1][oszlop-1] == állapot)

++állapotúSzomszéd;

}

if(oszlop+1<szélesség) {

if(hexagonálisRács[sor][oszlop+1] == állapot)

++állapotúSzomszéd;

if(sor+1<magasság)

if(hexagonálisRács[sor+1][oszlop+1] == állapot)

++állapotúSzomszéd;

}

} else {

if(sor-1>0)

if(hexagonálisRács[sor-1][oszlop] == állapot)

++állapotúSzomszéd;

if(sor+1<magasság)

if(hexagonálisRács[sor+1][oszlop] == állapot)

++állapotúSzomszéd;

if(oszlop-1>0) {

if(hexagonálisRács[sor][oszlop-1] == állapot)

++állapotúSzomszéd;

if(sor-1>0)

if(hexagonálisRács[sor-1][oszlop-1] == állapot)

++állapotúSzomszéd;

}

if(oszlop+1<szélesség) {

if(hexagonálisRács[sor][oszlop+1] == állapot)

++állapotúSzomszéd;

if(sor-1>0)

if(hexagonálisRács[sor-1][oszlop+1] == állapot)

++állapotúSzomszéd;

}

}

return állapotúSzomszéd;

}

/** Van összefonódott állapotban lévő szomszédja a rács

* adott cellájának? */

public boolean vanSzuperSzomszéd(int [][] hexagonálisRács,

int sor, int oszlop) {

if(oszlop%2 == 1) {

if(sor-1>0)

if(hexagonálisRács[sor-1][oszlop] == SZUPER)

return true;

if(sor+1<magasság)

if(hexagonálisRács[sor+1][oszlop] == SZUPER)

return true;

if(oszlop-1>0) {

if(hexagonálisRács[sor][oszlop-1] == SZUPER)

Page 346:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

318 Created by XMLmind XSL-FO Converter.

return true;

if(sor+1<magasság)

if(hexagonálisRács[sor+1][oszlop-1] == SZUPER)

return true;

}

if(oszlop+1<szélesség) {

if(hexagonálisRács[sor][oszlop+1] == SZUPER)

return true;

if(sor+1<magasság)

if(hexagonálisRács[sor+1][oszlop+1] == SZUPER)

return true;

}

} else {

if(sor-1>0)

if(hexagonálisRács[sor-1][oszlop] == SZUPER)

return true;

if(sor+1<magasság)

if(hexagonálisRács[sor+1][oszlop] == SZUPER)

return true;

if(oszlop-1>0) {

if(hexagonálisRács[sor][oszlop-1] == SZUPER)

return true;

if(sor-1>0)

if(hexagonálisRács[sor-1][oszlop-1] == SZUPER)

return true;

}

if(oszlop+1<szélesség) {

if(hexagonálisRács[sor][oszlop+1] == SZUPER)

return true;

if(sor-1>0)

if(hexagonálisRács[sor-1][oszlop+1] == SZUPER)

return true;

}

}

return false;

}

/** A szimuláció időfejlődése, diszkrét időskálán dolgozunk. */

public void időFejlődés() {

/* Két ráccsal dolgozunk: a diszkrét időskála adott

pillanata előtti és utáni ráccsal: */

int [][] hexagonálisRácsElőtte = hexagonálisRácsok[rácsIndex];

int [][] hexagonálisRácsUtána = hexagonálisRácsok[(rácsIndex+1)%2];

// Hány összefonódott van ebben az időpillanatban?

int szuperszámláló = 0;

for(int i=0; i<hexagonálisRácsElőtte.length; ++i) { // sorok

for(int j=0; j<hexagonálisRácsElőtte[0].length; ++j) { // oszlopok

if(hexagonálisRácsElőtte[i][j] == SZUPER) {

// Összefonódott az is marad

hexagonálisRácsUtána[i][j] = hexagonálisRácsElőtte[i][j];

++szuperszámláló;

} else {

// Egyébként a következő, hasraütésre vett

// átmeneti szabályokat alkalmazzuk:

if(vanSzuperSzomszéd(hexagonálisRácsElőtte, i, j)) {

if(random.nextInt(4) > 0) {

hexagonálisRácsUtána[i][j] = SZUPER;

++szuperszámláló;

}

Page 347:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

319 Created by XMLmind XSL-FO Converter.

} else if(random.nextInt(125) == 0) {

hexagonálisRácsUtána[i][j] = SZUPER;

++szuperszámláló;

} else {

int egyik = szomszédokSzáma(hexagonálisRácsElőtte,

i, j, EGYIK);

int másik = szomszédokSzáma(hexagonálisRácsElőtte,

i, j, MÁSIK);

if(hexagonálisRácsElőtte[i][j] == EGYIK) {

if(egyik == másik)

hexagonálisRácsUtána[i][j] = MÁSIK;

} else {

if(másik < egyik)

hexagonálisRácsUtána[i][j] = EGYIK;

else

hexagonálisRácsUtána[i][j] = MÁSIK;

}

}

}

// ha elértük az egy graviton szintet, akkor

// bekövetkezik

if(szuperszámláló >= EGY_GRAVITON_SZINTNYI) {

// az OR folyamat:

állapotvektorRedukció();

szuperszámláló = 0;

}

}

}

// a régi rács lesz az új:

rácsIndex = (rácsIndex+1)%2;

}

/** Az OR folyamat demonstrációja. */

public void állapotvektorRedukció() {

int [][] hexagonálisRács1 = hexagonálisRácsok[rácsIndex];

for(int i=0; i<hexagonálisRács.length; ++i)

for(int j=0; j<hexagonálisRács[0].length; ++j) {

if(hexagonálisRácsok[0][i][j] == SZUPER ||

hexagonálisRácsok[1][i][j] == SZUPER) {

hexagonálisRácsok[0][i][j] = random.nextInt(2);

hexagonálisRácsok[1][i][j] = hexagonálisRácsok[0][i][j];

}

}

hexagonálisRácsok[0][2+random.nextInt(magasság-2)]

[2+random.nextInt(szélesség-2)] = SZUPER;

hexagonálisRácsok[1][2+random.nextInt(magasság-2)]

[2+random.nextInt(szélesség-2)] = SZUPER;

}

/** A szimulációs szál időfejlődése. */

public void run() {

while(true) {

try {

Thread.sleep(500);

} catch (InterruptedException e) {}

időFejlődés();

repaint();

}

Page 348:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

320 Created by XMLmind XSL-FO Converter.

}

public static void main(String[] args) {

new Mikrotubulus(13, 20);

}

}

Megjegyezhetjük, hogy ha az időfejlődésben a Thread.sleep(50); mósodított utasítást alkalmazzuk, akkor -

az általunk alkalmazott öszefonódási fejlődés mellett, ami körülbelül 10 diszkrét időpillanat - hozzávetőlegesen

fél másodpercenként látjuk bekövetkezni az OR folyamatot.

A demonstrációs programot magunk is kipróbálhatjuk. Ehhez ne fejeljtsük el a tubulin fehérjék konformációs

állapotait reprezentáló fehér.png, fekete.png és piros.png képeket a munkakönyvtárunkba másolni. Ezeket

a A példaprogramok forrásainak letöltése című pontban ismertetett és belinkelt javat_tanitok_kepek.zip

állományban találja meg a kedves Olvasó. Ezután jelöljük ki az iménti forrásszöveget és illesszük be egy

Mikrotubulus.java nevű állományba, aztán fordítsuk az állományt és futtassuk a számítást:

C:\...> javac Mikrotubulus.java

C:\...> java Mikrotubulus

Eredményül a kézikönyvben már korábban, a Mikrotubulus sejtautomata szimuláció című pontban tárgyalt

képekhez hasonlóakat kapunk.

2. Matematikai témájú programok

2.1. Galton deszka kísérlet programja

Magát a kísérletet a Galton deszka kísérlet című pontban ismertettük. Most megadjuk a kísérleti elrendezést

absztraháló, általunk készített osztály kódját is.

/*

* GaltonDeszka.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* A Galton deszka kísérletet szimuláló osztály.

* A kísérlet leírását lásd a [RÉNYI VALSÉG KÖNYV] (Rényi

* Alfréd: Valószínűségszámítás, Tankönyvkiadó, 1973, 144 o.)

* könyvben.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

public class GaltonDeszka extends java.awt.Frame implements Runnable {

/** Melyik oszlopban van éppen az eső golyó? */

private int oszlop = 0;

/** Melyik sorban van éppen az eső golyó? */

private int sor = 0;

/** Hová hány golyó esett, az i. helyre hisztogram[i] */

private int [] hisztogram;

/** Hány pixel magas legyen egy deszkasor. */

private int sorMagasság;

/** Hány pixel széles legyen a kísérleti elrendezés ablaka? */

private int ablakSzélesség;

/** Hány pixel magas legyen a kísérleti elrendezés ablaka? */

private int ablakMagasság;

Page 349:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

321 Created by XMLmind XSL-FO Converter.

// Véletlenszám generátor

private java.util.Random random = new java.util.Random();

// Pillanatfelvétel készítéséhez

private java.awt.Robot robot;

/** Készítsünk pillanatfelvételt? */

private boolean pillanatfelvétel = false;

/** A pillanatfelvételek számozásához. */

private static int pillanatfelvételSzámláló = 0;

/**

* Létrehoz egy Galton deszka kísérleti elrendezést

* absztraháló <code>GaltonDeszka</code> objektumot.

*

* @param magasság a deszkasorok száma.

* @param sorMagasság a deszkasorok magassága pixelben.

*/

public GaltonDeszka(int magasság, int sorMagasság) {

// Hová hány golyó esett, az i. helyre hisztogram[i]

hisztogram = new int [magasság];

// Nullázzuk a hisztogram elemeit (nem lenne szükséges, de ez a

// biztonságos taktika)

for(int i=0; i<hisztogram.length; ++i)

hisztogram[i] = 0;

this.sorMagasság = sorMagasság;

// Az ablak bezárásakor kilépünk a programból.

addWindowListener(new java.awt.event.WindowAdapter() {

public void windowClosing(java.awt.event.WindowEvent e) {

setVisible(false);

System.exit(0);

}

});

// Az s gomb benyomásával ki/bekapcsoljuk a

// pillanatfelvétel készítést a kísérletről:

addKeyListener(new java.awt.event.KeyAdapter() {

public void keyPressed(java.awt.event.KeyEvent e) {

if(e.getKeyCode() == java.awt.event.KeyEvent.VK_S)

pillanatfelvétel = !pillanatfelvétel;

}

});

// Pillanatfelvétel készítéséhez:

try {

robot = new java.awt.Robot(

java.awt.GraphicsEnvironment.

getLocalGraphicsEnvironment().

getDefaultScreenDevice());

} catch(java.awt.AWTException e) {

e.printStackTrace();

}

// Ablak tulajdonságai

setTitle("Galton deszka kísérlet");

setResizable(false);

ablakSzélesség = magasság*sorMagasság*2;

ablakMagasság = magasság*sorMagasság+400;

setSize(ablakSzélesség, ablakMagasság);

setVisible(true);

// A kísérlet indul:

new Thread(this).start();

}

/**

* A kísérlet aktuális állapotának kirajzolása.

*/

public void paint(java.awt.Graphics g) {

// A deszkasorok és a golyó kirajzolása

for(int i=0; i<hisztogram.length; ++i) {

// Deszkák kirajzolása

g.setColor(java.awt.Color.BLACK);

for(int j=0; j<i; ++j)

g.fillRect(getWidth()/2

-((i-1)*sorMagasság+sorMagasság/2)

+j*2*sorMagasság+sorMagasság/3,

50+i*sorMagasság, sorMagasság/3, sorMagasság);

// Minden lehetséges pozícióra egy fehér

// golyó kirajzolása (törli a korábbi piros golyókat)

Page 350:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

322 Created by XMLmind XSL-FO Converter.

g.setColor(java.awt.Color.WHITE);

for(int j=0; j<=i; ++j)

g.fillArc(getWidth()/2

-(i*sorMagasság+sorMagasság/2)+j*2*sorMagasság,

50+i*sorMagasság,

sorMagasság,

sorMagasság, 0, 360);

// A most éppen aláhulló golyó kirajzolása

if(i == sor) {

g.setColor(java.awt.Color.RED);

g.fillArc(getWidth()/2

-(i*sorMagasság+sorMagasság/2)+oszlop*2*sorMagasság,

50+i*sorMagasság, sorMagasság, sorMagasság, 0, 360);

}

}

// A hisztogram kirajzolása

g.setColor(java.awt.Color.GREEN);

for(int j=0; j<hisztogram.length; ++j)

g.fillRect(getWidth()/2

-((hisztogram.length-1)*sorMagasság

+sorMagasság/2)+j*2*sorMagasság,

50+hisztogram.length*sorMagasság,

sorMagasság, sorMagasság*hisztogram[j]/10);

// Készítünk pillanatfelvételt?

if(pillanatfelvétel) {

// a biztonság kedvéért egy kép készítése után

// kikapcsoljuk a pillanatfelvételt, hogy a

// programmal ismerkedő Olvasó ne írja tele a

// fájlrendszerét a pillanatfelvételekkel

pillanatfelvétel = false;

pillanatfelvétel(robot.createScreenCapture

(new java.awt.Rectangle

(getLocation().x, getLocation().y,

ablakSzélesség, ablakMagasság)));

}

}

// Ne villogjon a felület (mert a "gyári" update()

// lemeszelné a vászon felületét).

public void update(java.awt.Graphics g) {

paint(g);

}

/**

* Pillanatfelvételek készítése.

*/

public void pillanatfelvétel(java.awt.image.BufferedImage felvetel) {

// A pillanatfelvétel kép fájlneve

StringBuffer sb = new StringBuffer();

sb = sb.delete(0, sb.length());

sb.append("GaltonDeszkaKiserlet");

sb.append(++pillanatfelvételSzámláló);

sb.append(".png");

// png formátumú képet mentünk

try {

javax.imageio.ImageIO.write(felvetel, "png",

new java.io.File(sb.toString()));

} catch(java.io.IOException e) {

e.printStackTrace();

}

}

/**

* A kísérlet időbeli fejlődésének vezérlése.

*/

public void run() {

// Végtelen ciklus, azaz végtelen sok golyót

// dobunk le a deszkák között.

while(true) {

// Kezdetben a golyó a legfelső deszka felett.

oszlop = 0;

// A ciklus minden iterációja egy deszkasornyi

// esést jelent a golyó életében

for(int i=0; i<hisztogram.length; ++i) {

Page 351:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

323 Created by XMLmind XSL-FO Converter.

// Melyik sorban van éppen az eső golyó?

sor = i;

// Ha növelni akarjuk a sebességet (a

// látvány rovására) akkor kommentezzük be

// ezt a várakozó try blokkot (de ekkor

// ne felejtsük el a hisztogram oszlopainak

// magasságát sorMagasság*hisztogram[j]/10-ről

// például sorMagasság*hisztogram[j]/10000-re állítani).

try {

Thread.sleep(50);

} catch (InterruptedException e) {}

// Az tetején a golyó az első deszka felett

if(i>0)

// ha nem a tetején, akkor 50%-50%, hogy

// jobbra vagy balra esik tovább.

// Melyik oszlopban van éppen az eső golyó?

oszlop = oszlop + random.nextInt(2);

// Rajzoljuk ki a kísérlet aktuális állapotát!

repaint();

}

// Ha kilép a golyó a ciklusból, akkor

// végig esett a deszkasorokon és valamelyik

// tárolóba esett

++hisztogram[oszlop];

}

}

/**

* Példányosít egy Galton deszkás kísérleti

* elrendezés obektumot.

*/

public static void main(String[] args) {

// Legyen 30 sor, soronként 10 pixellel

new GaltonDeszka(30, 10);

}

}

Könnyen végezhetünk saját kísérleteket az osztály imént megadott kódjával. Jelöljük ki a forrásszöveget és

illesszük be egy GaltonDeszka.java nevű állományba, majd fordítsuk az állományt és futtassuk a kísérletet:

C:\...> javac GaltonDeszka.java

C:\...> java GaltonDeszka

A program futása alatt az s billentyűt lenyomva a kísérletről egy pillanatfelvétel képet készít a program. A

készített képeket abban a könyvtárban találjuk, ahonnan a programot a fent ajánlott módon elindítottuk. Ilyen

kép például az alábbi GaltonDeszkaKiserlet1.png kép.

Page 352:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

324 Created by XMLmind XSL-FO Converter.

Végezzünk néhány további kísérletet a programmal! Például legyen soronként 5 pixel magas, 100 deszkasor,

ennek megfelelően módosítsuk a kísérleti elrendezést (paraméterezzük a konstruktort), majd fordítsuk újra a

programot és futtassuk!

new GaltonDeszka(100, 5);

B.3. példa - A Galton deszka kísérlet programjának kiegészítései

Végezze el az Olvasó az alábbi továbbfejlesztéseket a programon!

• A kísérleti elrendezés ablakában jelenjen meg, hogy eddig hány golyó esett le a kísérlet során!

Ha csak ezzel az egy sorral bővítjük a paint() függvényt

Page 353:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

325 Created by XMLmind XSL-FO Converter.

g.drawString("golyók száma" + golyóSzámláló, 20, 100);

akkor az egymást követő kiírások, mivel nem törlődik a képernyő ezen része, a változó számok miatt

olvashatatlanok lesznek. Számos megoldás kínálkozik ennek elkerülésére, de nézzünk egy olyat, ami nem

használ fel olyan osztályokat az API-ból, amit még eddig nem használtunk. Az új kiírás előtt a háttérszínnel

újra kiírjuk a régi golyószámot.

StringBuffer golyókSb = new StringBuffer();

public void paint(java.awt.Graphics g) {

// Lemeszeljük az előző kiírást:

g.setColor(java.awt.Color.WHITE);

g.drawString(golyókSb.toString(), 20, 100);

// Összerakjuk az új kiírást:

golyókSb.delete(0, golyókSb.length());

golyókSb.append("golyók száma: ");

golyókSb.append(golyóSzámláló);

// és zölddel kiírjuk:

g.setColor(java.awt.Color.GREEN);

g.drawString(golyókSb.toString(), 20, 100);

// A deszkasorok és a golyó kirajzolása

...

• A kísérleti elrendezés ablakában jelenjen meg, hogy be van-e kapcsolva a pillanatfelvétel készítés.

• Az s billentyűt lenyomva a leeső golyó minden deszkasorbeli jobb vagy bal oldalra esési választásáról

készítsen a program egy pillanatfelvétel képet, majd maga kapcsolja ki e fotósorozat elkészítése után a

pillanatfelvétel készítést!

2.2. Mandelbrot halmaz programja

Az előző pont programját alakítjuk most át, a Mandelbrot halmazt fogjuk kiszámolni és kirajzolni. A

Mandelbrot halmaz, vagy a halmaz nagyításainak látható szépsége még azokat is megérinti, akik egyébként a

matematikai jellegű élmények befogadására nincsenek ráhangolva.

A Mandelbrot halmazt a [BARNSLEY KÖNYV] vagy ismeretterjesztő szinten a [CSÁSZÁR KÖNYV]

könyvekből ismerhetjük meg, de az algoritmust itt is ismertetjük, mert gyakorlásképpen be akarjuk programozni

Javaban! Az algoritmussal és az őt implementáló Java programmal párhuzamosan ismerkedünk meg, de az

alábbi tárgyalás után összefoglalásul a teljes program kódját is bevágjuk. Az algoritmus komplex számsíkon

működik. A komplex számsíkot benépesítő komplex számoknak könnyű geometriai interpretációt tulajdonítani,

amiután már barátságos velük dolgozni. Egy komplex számnak két része van, az egyik valós, a másik

imaginárius, azaz képzetesnek nevezett.

Page 354:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

326 Created by XMLmind XSL-FO Converter.

A Mandelbrot halmazt a komplex sík a, b, c, d határolta tartományára húzott

/** A komplex sík vizsgált tartománya [a,b]x[c,d]. */

protected double a, b, c, d;

/** A komplex sík vizsgált tartományára feszített

* háló szélessége és magassága. */

protected int szélesség, magasság;

szélesség széles és magasság magas rács pontjaiban számoljuk.

Ennek a rácsnak minden pontjában

// Végigzongorázzuk a szélesség x magasság hálót:

for(int j=0; j<magasság; ++j) {

sor = j;

for(int k=0; k<szélesség; ++k) {

Page 355:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

327 Created by XMLmind XSL-FO Converter.

elkezdjük számolni a zn+1 = zn2 + c iterációt a z0 = 0 és c a megfelelő rácspont kezdő értékekkel. A c komplex

szám reC + imC*i alakja alapján a rácspontnak megfelelő komplex szám valós része reC = a+k*dx, képzetes

része pedig imC = d-j*dy. Arra kell még figyelnünk, hogy a komplex számok szorzása rendhagyó, mert az

alábbi szabályt mindig szem előtt kell tartanunk i*i = -1, azaz a z2 = z*z = (reZ+imZ*i)*(reZ+imZ*i)= reZ*reZ

+ reZ*imZ*i + imZ*i*reZ + imZ*i*imZ*i = reZ*reZ - imZ*imZ + 2*reZ*imZ*i

// Végigzongorázzuk a szélesség x magasság hálót:

for(int j=0; j<magasság; ++j) {

sor = j;

for(int k=0; k<szélesség; ++k) {

// c = (reC, imC) a háló rácspontjainak

// megfelelő komplex szám

reC = a+k*dx;

imC = d-j*dy;

// z_0 = 0 = (reZ, imZ)

reZ = 0;

imZ = 0;

iteráció = 0;

// z_{n+1} = z_n * z_n + c iterációk

// számítása, amíg |z_n| < 2 vagy még

// nem értük el a 255 iterációt, ha

// viszont elértük, akkor úgy vesszük,

// hogy a kiinduláci c komplex számra

// az iteráció konvergens, azaz a c a

// Mandelbrot halmaz eleme

while(reZ*reZ + imZ*imZ < 4 && iteráció < iterációsHatár) {

// z_{n+1} = z_n * z_n + c

ujreZ = reZ*reZ - imZ*imZ + reC;

ujimZ = 2*reZ*imZ + imC;

reZ = ujreZ;

imZ = ujimZ;

++iteráció;

}

Az iterációk során azt figyeljük, hogy a zn mennyire távolodik el az induló z0 ponttól, azaz a koordinátarendszer

középpontjától, az origótól. Ha ez a távolság nagyobb lesz kettőnél, akkor azt mondjuk, hogy a vizsgált c

pontban az iteráció nem sűrűsödik be az origóhoz közeli valamelyik pontba. Ellenkező esetben, tehát ha az

iterációs határ elérése miatt lépünk ki a

while(reZ*reZ + imZ*imZ < 4 && iteráció < iterációsHatár) {

ciklusból, akkor azt tételezzük fel, hogy ebben a pontban az iteráció konvergens és a Mandelbrot halmaz

elemének tekintjük, feketére színezzük:

// sorozat konvergens, azaz iteráció = iterációsHatár

// ekkor az iteráció %= 256 egyenlő 255, mert az esetleges

// nagyítasok során az iteráció = valahány * 256 + 255

iteráció %= 256;

// így a halmaz elemeire 255-255 értéket használjuk,

// azaz (Red=0,Green=0,Blue=0) fekete színnel:

rgb = (255-iteráció)|

((255-iteráció) << 8) |

((255-iteráció) << 16);

// rajzoljuk a képre az éppen vizsgált pontot:

kép.setRGB(k, j, rgb);

Page 356:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

328 Created by XMLmind XSL-FO Converter.

A Mandelbrot halmazt kiszámoló, kirajzoló programunk teljes kódja a következő.

/*

* MandelbrotHalmaz.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* A Mandelbrot halmazt kiszámoló és kirajzoló osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

public class MandelbrotHalmaz extends java.awt.Frame implements Runnable {

/** A komplex sík vizsgált tartománya [a,b]x[c,d]. */

protected double a, b, c, d;

/** A komplex sík vizsgált tartományára feszített

* háló szélessége és magassága. */

protected int szélesség, magasság;

/** A komplex sík vizsgált tartományára feszített hálónak megfelelő kép.*/

protected java.awt.image.BufferedImage kép;

/** Max. hány lépésig vizsgáljuk a z_{n+1} = z_n * z_n + c iterációt?

* (tk. most a nagyítási pontosság) */

protected int iterációsHatár = 255;

/** Jelzi, hogy éppen megy-e a szamítás? */

protected boolean számításFut = false;

/** Jelzi az ablakban, hogy éppen melyik sort számoljuk. */

protected int sor = 0;

/** A pillanatfelvételek számozásához. */

protected static int pillanatfelvételSzámláló = 0;

/**

* Létrehoz egy a Mandelbrot halmazt a komplex sík

* [a,b]x[c,d] tartománya felett kiszámoló

* <code>MandelbrotHalmaz</code> objektumot.

*

* @param a a [a,b]x[c,d] tartomány a koordinátája.

* @param b a [a,b]x[c,d] tartomány b koordinátája.

* @param c a [a,b]x[c,d] tartomány c koordinátája.

* @param d a [a,b]x[c,d] tartomány d koordinátája.

* @param szélesség a halmazt tartalmazó tömb szélessége.

* @param iterációsHatár a számítás pontossága.

*/

public MandelbrotHalmaz(double a, double b, double c, double d,

int szélesség, int iterációsHatár) {

this.a = a;

this.b = b;

this.c = c;

this.d = d;

this.szélesség = szélesség;

this.iterációsHatár = iterációsHatár;

// a magasság az (b-a) / (d-c) = szélesség / magasság

// arányból kiszámolva az alábbi lesz:

this.magasság = (int)(szélesség * ((d-c)/(b-a)));

// a kép, amire rárajzoljuk majd a halmazt

kép = new java.awt.image.BufferedImage(szélesség, magasság,

java.awt.image.BufferedImage.TYPE_INT_RGB);

// Az ablak bezárásakor kilépünk a programból.

addWindowListener(new java.awt.event.WindowAdapter() {

public void windowClosing(java.awt.event.WindowEvent e) {

setVisible(false);

System.exit(0);

}

});

// A billentyűzetről érkező események feldolgozása

addKeyListener(new java.awt.event.KeyAdapter() {

// Az 's', 'n' és 'm' gombok lenyomását figyeljük

public void keyPressed(java.awt.event.KeyEvent e) {

if(e.getKeyCode() == java.awt.event.KeyEvent.VK_S)

Page 357:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

329 Created by XMLmind XSL-FO Converter.

pillanatfelvétel();

// Az 'n' gomb benyomásával pontosabb számítást végzünk.

else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_N) {

if(számításFut == false) {

MandelbrotHalmaz.this.iterációsHatár += 256;

// A számítás újra indul:

számításFut = true;

new Thread(MandelbrotHalmaz.this).start();

}

// Az 'm' gomb benyomásával pontosabb számítást végzünk,

// de közben sokkal magasabbra vesszük az iterációs

// határt, mint az 'n' használata esetén

} else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_M) {

if(számításFut == false) {

MandelbrotHalmaz.this.iterációsHatár += 10*256;

// A számítás újra indul:

számításFut = true;

new Thread(MandelbrotHalmaz.this).start();

}

}

}

});

// Ablak tulajdonságai

setTitle("A Mandelbrot halmaz");

setResizable(false);

setSize(szélesség, magasság);

setVisible(true);

// A számítás indul:

számításFut = true;

new Thread(this).start();

}

/**

* A halmaz aktuális állapotának kirajzolása.

*/

public void paint(java.awt.Graphics g) {

// A Mandelbrot halmaz kirajzolása

g.drawImage(kép, 0, 0, this);

// Ha éppen fut a számítás, akkor egy vörös

// vonallal jelöljük, hogy melyik sorban tart:

if(számításFut) {

g.setColor(java.awt.Color.RED);

g.drawLine(0, sor, getWidth(), sor);

}

}

// Ne villogjon a felület (mert a "gyári" update()

// lemeszelné a vászon felületét).

public void update(java.awt.Graphics g) {

paint(g);

}

/**

* Pillanatfelvételek készítése.

*/

public void pillanatfelvétel() {

// Az elmentendő kép elkészítése:

java.awt.image.BufferedImage mentKép =

new java.awt.image.BufferedImage(szélesség, magasság,

java.awt.image.BufferedImage.TYPE_INT_RGB);

java.awt.Graphics g = mentKép.getGraphics();

g.drawImage(kép, 0, 0, this);

g.setColor(java.awt.Color.BLUE);

g.drawString("a=" + a, 10, 15);

g.drawString("b=" + b, 10, 30);

g.drawString("c=" + c, 10, 45);

g.drawString("d=" + d, 10, 60);

g.drawString("n=" + iterációsHatár, 10, 75);

g.dispose();

// A pillanatfelvétel képfájl nevének képzése:

StringBuffer sb = new StringBuffer();

sb = sb.delete(0, sb.length());

sb.append("MandelbrotHalmaz_");

sb.append(++pillanatfelvételSzámláló);

sb.append("_");

Page 358:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

330 Created by XMLmind XSL-FO Converter.

// A fájl nevébe belevesszük, hogy melyik tartományban

// találtuk a halmazt:

sb.append(a);

sb.append("_");

sb.append(b);

sb.append("_");

sb.append(c);

sb.append("_");

sb.append(d);

sb.append(".png");

// png formátumú képet mentünk

try {

javax.imageio.ImageIO.write(mentKép, "png",

new java.io.File(sb.toString()));

} catch(java.io.IOException e) {

e.printStackTrace();

}

}

/**

* A Mandelbrot halmaz számítási algoritmusa.

* Az algoritmus részletes ismertetését lásd például a

* [BARNSLEY KÖNYV] (M. Barnsley: Fractals everywhere,

* Academic Press, Boston, 1986) hivatkozásban vagy

* ismeretterjesztő szinten a [CSÁSZÁR KÖNYV] hivatkozásban.

*/

public void run() {

// A [a,b]x[c,d] tartományon milyen sűrű a

// megadott szélesség, magasság háló:

double dx = (b-a)/szélesség;

double dy = (d-c)/magasság;

double reC, imC, reZ, imZ, ujreZ, ujimZ;

int rgb;

// Hány iterációt csináltunk?

int iteráció = 0;

// Végigzongorázzuk a szélesség x magasság hálót:

for(int j=0; j<magasság; ++j) {

sor = j;

for(int k=0; k<szélesség; ++k) {

// c = (reC, imC) a háló rácspontjainak

// megfelelő komplex szám

reC = a+k*dx;

imC = d-j*dy;

// z_0 = 0 = (reZ, imZ)

reZ = 0;

imZ = 0;

iteráció = 0;

// z_{n+1} = z_n * z_n + c iterációk

// számítása, amíg |z_n| < 2 vagy még

// nem értük el a 255 iterációt, ha

// viszont elértük, akkor úgy vesszük,

// hogy a kiinduláci c komplex számra

// az iteráció konvergens, azaz a c a

// Mandelbrot halmaz eleme

while(reZ*reZ + imZ*imZ < 4 && iteráció < iterációsHatár) {

// z_{n+1} = z_n * z_n + c

ujreZ = reZ*reZ - imZ*imZ + reC;

ujimZ = 2*reZ*imZ + imC;

reZ = ujreZ;

imZ = ujimZ;

++iteráció;

}

// ha a < 4 feltétel nem teljesült és a

// iteráció < iterációsHatár sérülésével lépett ki, azaz

// feltesszük a c-ről, hogy itt a z_{n+1} = z_n * z_n + c

// sorozat konvergens, azaz iteráció = iterációsHatár

// ekkor az iteráció %= 256 egyenlő 255, mert az esetleges

// nagyítasok során az iteráció = valahány * 256 + 255

iteráció %= 256;

// így a halmaz elemeire 255-255 értéket használjuk,

// azaz (Red=0,Green=0,Blue=0) fekete színnel:

Page 359:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

331 Created by XMLmind XSL-FO Converter.

rgb = (255-iteráció)|

((255-iteráció) << 8) |

((255-iteráció) << 16);

// rajzoljuk a képre az éppen vizsgált pontot:

kép.setRGB(k, j, rgb);

}

repaint();

}

számításFut = false;

}

/**

* Példányosít egy Mandelbrot halmazt kiszámoló obektumot.

*/

public static void main(String[] args) {

// A halmazt a komplex sík [-2.0, .7]x[-1.35, 1.35] tartományában

// keressük egy 400x400-as hálóval:

new MandelbrotHalmaz(-2.0, .7, -1.35, 1.35, 600, 255);

}

}

Könnyen végezhetünk saját számításokat az osztály imént megadott kódjával. Jelöljük ki a forrásszöveget és

illesszük be egy MandelbrotHalmaz.java nevű állományba, majd fordítsuk a állományt és futtassuk a

számítást:

C:\...> javac MandelbrotHalmaz.java

C:\...> java MandelbrotHalmaz

A program futása alatt az s billentyűt lenyomva a kiszámolt halmazról egy felvételt készít a program. A készített

képeket abban a könyvtárban találjuk, ahonnan a programot a fent ajánlott módon elindítottuk. Ilyen kép például

az alábbi MandelbrotHalmaz_1_-2.0_0.7_-1.35_1.35.png kép.

Page 360:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

332 Created by XMLmind XSL-FO Converter.

A program alább bemutatott ablakában a kép adatait nem írattuk ki, illetve a kép tetejéből az ablak fejléce

néhány pixelsort eltakar.

Page 361:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

333 Created by XMLmind XSL-FO Converter.

2.3. Mandelbrot halmaz nagyító programja

Az előző pont programját fejlesztjük most tovább, a program által kiszámolt és kirajzolt Mandelbrot halmaz

valamely részét fogjuk kinagyítani és annak valamely részét ... és így tovább. Az áhított nagyító programot úgy

valósítjuk meg, hogy a fejlesztendő MandelbrotHalmazNagyító osztállyal kiterjesztjük a MandelbrotHalmaz

osztályunkat.

/*

* MandelbrotHalmazNagyító.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* A Mandelbrot halmazt nagyító és kirajzoló osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

public class MandelbrotHalmazNagyító extends MandelbrotHalmaz {

/** A nagyítandó kijelölt területet bal felső sarka. */

private int x, y;

/** A nagyítandó kijelölt terület szélessége és magassága. */

private int mx, my;

/**

Page 362:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

334 Created by XMLmind XSL-FO Converter.

* Létrehoz egy a Mandelbrot halmazt a komplex sík

* [a,b]x[c,d] tartománya felett kiszámoló és nygítani tudó

* <code>MandelbrotHalmazNagyító</code> objektumot.

*

* @param a a [a,b]x[c,d] tartomány a koordinátája.

* @param b a [a,b]x[c,d] tartomány b koordinátája.

* @param c a [a,b]x[c,d] tartomány c koordinátája.

* @param d a [a,b]x[c,d] tartomány d koordinátája.

* @param szélesség a halmazt tartalmazó tömb szélessége.

* @param iterációsHatár a számítás pontossága.

*/

public MandelbrotHalmazNagyító(double a, double b, double c, double d,

int szélesség, int iterációsHatár) {

// Az ős osztály konstruktorának hívása

super(a, b, c, d, szélesség, iterációsHatár);

setTitle("A Mandelbrot halmaz nagyításai");

// Egér kattintó események feldolgozása:

addMouseListener(new java.awt.event.MouseAdapter() {

// Egér kattintással jelöljük ki a nagyítandó területet

// bal felső sarkát:

public void mousePressed(java.awt.event.MouseEvent m) {

// A nagyítandó kijelölt területet bal felső sarka:

x = m.getX();

y = m.getY();

mx = 0;

my = 0;

repaint();

}

// Vonszolva kijelölünk egy területet...

// Ha felengedjük, akkor a kijelölt terület

// újraszámítása indul:

public void mouseReleased(java.awt.event.MouseEvent m) {

double dx = (MandelbrotHalmazNagyító.this.b

- MandelbrotHalmazNagyító.this.a)

/MandelbrotHalmazNagyító.this.szélesség;

double dy = (MandelbrotHalmazNagyító.this.d

- MandelbrotHalmazNagyító.this.c)

/MandelbrotHalmazNagyító.this.magasság;

// Az új Mandelbrot nagyító objektum elkészítése:

new MandelbrotHalmazNagyító(MandelbrotHalmazNagyító.this.a+x*dx,

MandelbrotHalmazNagyító.this.a+x*dx+mx*dx,

MandelbrotHalmazNagyító.this.d-y*dy-my*dy,

MandelbrotHalmazNagyító.this.d-y*dy,

600,

MandelbrotHalmazNagyító.this.iterációsHatár);

}

});

// Egér mozgás események feldolgozása:

addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {

// Vonszolással jelöljük ki a négyzetet:

public void mouseDragged(java.awt.event.MouseEvent m) {

// A nagyítandó kijelölt terület szélessége és magassága:

mx = m.getX() - x;

my = m.getY() - y;

repaint();

}

});

}

/**

* Pillanatfelvételek készítése.

*/

public void pillanatfelvétel() {

// Az elmentendő kép elkészítése:

java.awt.image.BufferedImage mentKép =

new java.awt.image.BufferedImage(szélesség, magasság,

java.awt.image.BufferedImage.TYPE_INT_RGB);

java.awt.Graphics g = mentKép.getGraphics();

g.drawImage(kép, 0, 0, this);

g.setColor(java.awt.Color.BLUE);

g.drawString("a=" + a, 10, 15);

g.drawString("b=" + b, 10, 30);

g.drawString("c=" + c, 10, 45);

Page 363:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

335 Created by XMLmind XSL-FO Converter.

g.drawString("d=" + d, 10, 60);

g.drawString("n=" + iterációsHatár, 10, 75);

if(számításFut) {

g.setColor(java.awt.Color.RED);

g.drawLine(0, sor, getWidth(), sor);

}

g.setColor(java.awt.Color.GREEN);

g.drawRect(x, y, mx, my);

g.dispose();

// A pillanatfelvétel képfájl nevének képzése:

StringBuffer sb = new StringBuffer();

sb = sb.delete(0, sb.length());

sb.append("MandelbrotHalmazNagyitas_");

sb.append(++pillanatfelvételSzámláló);

sb.append("_");

// A fájl nevébe belevesszük, hogy melyik tartományban

// találtuk a halmazt:

sb.append(a);

sb.append("_");

sb.append(b);

sb.append("_");

sb.append(c);

sb.append("_");

sb.append(d);

sb.append(".png");

// png formátumú képet mentünk

try {

javax.imageio.ImageIO.write(mentKép, "png",

new java.io.File(sb.toString()));

} catch(java.io.IOException e) {

e.printStackTrace();

}

}

/**

* A nagyítandó kijelölt területet jelző négyzet kirajzolása.

*/

public void paint(java.awt.Graphics g) {

// A Mandelbrot halmaz kirajzolása

g.drawImage(kép, 0, 0, this);

// Ha éppen fut a számítás, akkor egy vörös

// vonallal jelöljük, hogy melyik sorban tart:

if(számításFut) {

g.setColor(java.awt.Color.RED);

g.drawLine(0, sor, getWidth(), sor);

}

// A jelző négyzet kirajzolása:

g.setColor(java.awt.Color.GREEN);

g.drawRect(x, y, mx, my);

}

/**

* Példányosít egy Mandelbrot halmazt nagyító obektumot.

*/

public static void main(String[] args) {

// A kiinduló halmazt a komplex sík [-2.0, .7]x[-1.35, 1.35]

// tartományában keressük egy 600x600-as hálóval és az

// aktuális nagyítási pontossággal:

new MandelbrotHalmazNagyító(-2.0, .7, -1.35, 1.35, 600, 255);

}

}

Ezzel a továbbfejlesztéssel ugyancsak könnyen végezhetünk saját nagyításokat az osztály imént megadott

kódjával. Jelöljük ki a forrásszöveget és illesszük be egy MandelbrotHalmazNagyító.java nevű állományba -

amit ugyanabba a könyvtárba helyezünk, mint az előző MandelbrotHalmaz.java állományt - majd fordítsuk a

állományt és futtassuk a számítást:

C:\...> javac MandelbrotHalmazNagyító.java

C:\...> java MandelbrotHalmazNagyító

Page 364:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

336 Created by XMLmind XSL-FO Converter.

Nézzünk meg néhány, a program futása alatt az s billentyű lenyomásával készített felvételt a nagyított

Mandelbrot halmazokról:

A bal egérgomb lenyomásával kijelöljük a nagyítandó területet. A MandelbrotHalmazNagyító osztályban ezt

egy beágyazott, a MouseAdapter adapter osztályt kiterjesztő névtelen osztálybeli eseménykezelő objektummal

oldjuk meg:

// Egér kattintó események feldolgozása:

addMouseListener(new java.awt.event.MouseAdapter() {

// Egér kattintással jelöljük ki a nagyítandó területet

// bal felső sarkát:

public void mousePressed(java.awt.event.MouseEvent m) {

// A nagyítandó kijelölt területet bal felső sarka:

x = m.getX();

y = m.getY();

mx = 0;

my = 0;

repaint();

}

A kijelölő, zölddel kirajzolt, nagyítandó területet kijelölő téglalap bal felső sarkának koordinátái az osztály x és

y tagjai. A kijelölő téglalap szélessége és magassága az mx és az my tagok.

/** A nagyítandó kijelölt területet bal felső sarka. */

private int x, y;

/** A nagyítandó kijelölt terület szélessége és magassága. */

private int mx, my;

Ezek állítása történik az eseménykezelő egérkattintást feldolgozó mousePressed() módszerében. A függvény

aktuális paramétereként megkapott eseményobjektumtól megkérdezzük a kattintás helyét:

x = m.getX();

y = m.getY();

mx = 0;

my = 0;

repaint();

}

Page 365:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

337 Created by XMLmind XSL-FO Converter.

az mx és my szélességet, magasságot nullára állítjuk, ezeket majd az egérgomb nyomvatartása melletti vonszolás

állítja be a vonszolás méretének megfelelő értékre. Az egérmutató vonszolásának megfigyelését ugyancsak egy

beágyazott, de most a MouseMotionAdapter adapter osztályt kiterjesztő névtelen osztálybeli eseménykezelő

objektummal oldjuk meg:

// Egér mozgás események feldolgozása:

addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {

// Vonszolással jelöljük ki a négyzetet:

public void mouseDragged(java.awt.event.MouseEvent m) {

// A nagyítandó kijelölt terület szélessége és magassága:

mx = m.getX() - x;

my = m.getY() - y;

repaint();

}

});

Az x és y példányok tárolják a négyzet bal felső sarkának oszlop és sor koordinátáját, ezeket az egérmutató

aktuális helyéből kivonva kapjuk a kijelölt terület szélességét, illetve magasságát, például: mx = m.getX() -

x;. A repaint() hívása biztosítja, hogy a megváltozott példánytagoknak megfelelő zöld tégla kirajzolásra

kerüljön, azaz a paint() függvény meghívódjon, ahol

// A jelző négyzet kirajzolása:

g.setColor(java.awt.Color.GREEN);

g.drawRect(x, y, mx, my);

Page 366:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

338 Created by XMLmind XSL-FO Converter.

Page 367:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

339 Created by XMLmind XSL-FO Converter.

Ha úgy érezzük, hogy a nagyítások során leromlott a pontosság, akkor az n gomb nyomásával növelni tudjuk a

számítások iterációs határát. Ezt a billenytűzet eseményt egy beágyazott, a KeyAdapter adapter osztályt

kiterjesztő névtelen osztálybeli eseménykezelő objektummal oldjuk meg:

// A billentyűzetről érkező események feldolgozása

addKeyListener(new java.awt.event.KeyAdapter() {

// Az 's', 'n' és 'm' gombok lenyomását figyeljük

public void keyPressed(java.awt.event.KeyEvent e) {

...

// Az 'n' gomb benyomásával pontosabb számítást végzünk.

else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_N) {

if(számításFut == false) {

MandelbrotHalmaz.this.iterációsHatár += 256;

Page 368:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

340 Created by XMLmind XSL-FO Converter.

// A számítás újra indul:

számításFut = true;

new Thread(MandelbrotHalmaz.this).start();

}

Ha éppen nem fut számítás, akkor növeljük a számítások iterációsHatár iterációs határát, majd készítünk egy

számítást végző new Thread(MandelbrotHalmaz.this).start(); szálat. Ez a pontosabb számítás ekkor jól

megfigyelhető, de egy vörös csíkkal is jeleztük

// Ha éppen fut a számítás, akkor egy vörös

// vonallal jelöljük, hogy melyik sorban tart:

if(számításFut) {

g.setColor(java.awt.Color.RED);

g.drawLine(0, sor, getWidth(), sor);

}

a rajzolást végző paint() függvényekben.

Page 369:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

341 Created by XMLmind XSL-FO Converter.

Page 370:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

342 Created by XMLmind XSL-FO Converter.

Page 371:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

343 Created by XMLmind XSL-FO Converter.

Page 372:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

344 Created by XMLmind XSL-FO Converter.

Page 373:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

345 Created by XMLmind XSL-FO Converter.

Page 374:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

346 Created by XMLmind XSL-FO Converter.

B.4. példa - A Mandelbrot halmaz nagyító programjának kiegészítései

Végezze el az Olvasó az alábbi továbbfejlesztéseket a programon! Próbálkozzunk például mindenféle más

színezési stratégiákkal!

• Az alábbi módosítás pontosabb, de kevésbé látványos színezést produkál:

iteráció = iteráció / (iterációsHatár / 255);

rgb = (255-iteráció)|

(255-iteráció) << 8 |

((255-iteráció) << 16);

• Ezzel a színezéssel már a vörös árnyalataiban pompáznak a nagyítások:

if(iteráció == iterációsHatár)

rgb = 0;

else {

iteráció = iteráció % 255;

rgb = 0|

0 << 8 |

((255-iteráció) << 16);

}

Page 375:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

347 Created by XMLmind XSL-FO Converter.

• Nemcsak egyfajta szín árnyalatait használva:

if(iteráció == iterációsHatár)

rgb = 0;

else {

iteráció = iteráció % 255;

rgb = (255-iteráció%16)|

(255-iteráció%64) << 8 |

((255-iteráció) << 16);

}

Page 376:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

348 Created by XMLmind XSL-FO Converter.

2.4. Mandelbrot halmaz pontjait grafikusan iteráló program

Az előző pontban kifejlesztett nagyító program már jól használható matematikai kísérleti eszközünk volt, erről

tanúskodtott az imént bemutatott nagyítási fotósorozat is. Ebben a részben a nagyítóhoz egy olyan számoló szál

objektumot készítünk, ami képes a felhasználó kérésére a halmaz egy tetszőleges pontjából megvizsgálni a zn+1 =

zn2 + c iteráció lépéseit: kirajzoljuk a komplex síkra az iteráció bejárta z0, z1, z3 ... komplex számokat és az

egymást követőeket egy egyenessel kötjük majd össze:

g.drawLine(

(int)((reZ - a)/dx),

(int)((d - imZ)/dy),

(int)((ujreZ - a)/dx),

(int)((d - ujimZ)/dy)

);

A program felhasználója a bal egér gombbal jelöli ki azt a pontot, amelyből az iterációban szereplő pontokat

meg akarja tekinteni. A jobb egér gomb nyomása továbbra is a nagyítandó terület bal felső sarkának

koordinátája.

// Egér kattintó események feldolgozása:

addMouseListener(new java.awt.event.MouseAdapter() {

// Egér kattintással jelöljük ki a nagyítandó területet

// bal felső sarkát vagy ugyancsak egér kattintással

// vizsgáljuk egy adott pont iterációit:

public void mousePressed(java.awt.event.MouseEvent m) {

Page 377:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

349 Created by XMLmind XSL-FO Converter.

// Az egérmutató pozíciója

x = m.getX();

y = m.getY();

// Az 1. egér gombbal a nagyítandó terület kijelölését

// végezzük:

if(m.getButton() == java.awt.event.MouseEvent.BUTTON1 ) {

// A nagyítandó kijelölt területet bal felső sarka: (x,y)

// és szélessége (majd a vonszolás növeli)

mx = 0;

my = 0;

repaint();

} else {

// Nem az 1. egér gombbal az egérmutató mutatta c

// komplex számból indított iterációkat vizsgálhatjuk

MandelbrotIterációk iterációk =

new MandelbrotIterációk(

MandelbrotHalmazNagyító.this, 50);

new Thread(iterációk).start();

}

}

Most fejlesztendő szál osztályunkat a MandelbrotIterációk osztályban implementáljuk:

public class MandelbrotIterációk implements Runnable{

Az osztály hozzáfér Mandelbrot halmazunk adataihoz, párhuzamosan végrehajtandó run() metódusa is

majdnem ugyanaz, mint a MandelbrotHalmaz osztályé, de itt nem az egész rácson kell az iterációt vizsgálnunk,

hanem csupán a MandelbrotHalmazNagyító futó objektumon az egérmutató mutatta rácspontban.

/** Az vizsgált pontból induló iterációk bemutatása. */

public void run() {

/* Az alábbi kód javarészt a MandelbrotHalmaz.java számolást

végző run() módszeréből származik, hiszen ugyanazt csináljuk,

csak most nem a hálón megyünk végig, hanem a háló adott a

példányosításunkkor az egérmutató mutatta csomópontjában (ennek

felel meg a c kompelx szám) számolunk, tehát a két külső for

ciklus nem kell. */

// A [a,b]x[c,d] tartományon milyen sűrű a

// megadott szélesség, magasság háló:

double dx = (b-a)/szélesség;

double dy = (d-c)/magasság;

double reC, imC, reZ, imZ, ujreZ, ujimZ;

// Hány iterációt csináltunk?

int iteráció = 0;

// c = (reC, imC) a háló rácspontjainak

// megfelelő komplex szám

reC = a+k*dx;

imC = d-j*dy;

// z_0 = 0 = (reZ, imZ)

reZ = 0;

imZ = 0;

iteráció = 0;

// z_{n+1} = z_n * z_n + c iterációk

// számítása, amíg |z_n| < 2 vagy még

// nem értük el a 255 iterációt, ha

// viszont elértük, akkor úgy vesszük,

// hogy a kiinduláci c komplex számra

// az iteráció konvergens, azaz a c a

// Mandelbrot halmaz eleme

while(reZ*reZ + imZ*imZ < 4 && iteráció < 255) {

// z_{n+1} = z_n * z_n + c

ujreZ = reZ*reZ - imZ*imZ + reC;

ujimZ = 2*reZ*imZ + imC;

Page 378:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

350 Created by XMLmind XSL-FO Converter.

// az iteráció (reZ, imZ) -> (ujreZ, ujimZ)

// ezt az egyenest kell kirajzolnunk, de most

// a komplex számokat vissza kell transzformálnunk

// a rács oszlop, sor koordinátájává:

java.awt.Graphics g = kép.getGraphics();

g.setColor(java.awt.Color.WHITE);

g.drawLine(

(int)((reZ - a)/dx),

(int)((d - imZ)/dy),

(int)((ujreZ - a)/dx),

(int)((d - ujimZ)/dy)

);

g.dispose();

nagyító.repaint();

reZ = ujreZ;

imZ = ujimZ;

++iteráció;

// Várakozunk, hogy közben csodálhassuk az iteráció

// látványát:

try {

Thread.sleep(várakozás);

} catch (InterruptedException e) {}

}

}

Page 379:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

351 Created by XMLmind XSL-FO Converter.

A következő ábrán egy olyan futó MandelbrotHalmazNagyító objektumot látunk, ahol néhány pontban

megnéztük az iterációkban szereplő pontokat.

2.5. A Mandelbrot halmazzal kapcsolatos osztályaink összefoglalása

A Mandelbrot halmazos programozási gyakorlatunkhoz három osztályt fejlesztettünk ki, a MandelbrotHalmaz,

a MandelbrotHalmazNagyító és a MandelbrotIterációk osztályokat. Az osztályokkal való kísérletezéshez

az alább közölt megfelelő MandelbrotHalmaz.java, a MandelbrotHalmazNagyító.java és a

MandelbrotIterációk.java forrásállományokat helyezzük egy könyvtárba, majd egy olyan parancsablakból,

ahol a Java megfelelően be van állítva, fordítsuk az osztályokat és futtassuk a programot így:

C:\...> javac MandelbrotHalmazNagyító.java

C:\...> java MandelbrotHalmazNagyító

Korábbi tárgyalásunknak megfelelően a program ablakok a következő inputokat dolgozzák fel:

• Az s billentyű lenyomásával egy felvétel kép készül az aktív ablakban számolt fraktálról.

• Az n billentyű lenyomásával növeljük a halmaz kiszámolásának pontosságát, 256-al megnöveljük az iterációk

számát.

Page 380:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

352 Created by XMLmind XSL-FO Converter.

• Az m billentyű lenyomásával nagyobb ugrással növeljük a halmaz kiszámolásának pontosságát, 10*256-al

megnöveljük az iterációk számát.

• Az egérmutató bal gombjával kijelöljük a nagyítandó terület bal felső sarkát, az egér vonszolásával megadjuk

a terület nagyságát, az egérgomb felengedésére új ablakban megkezdődik a kijelölt terület nagyítása.

• Az egérmutató jobb gombjával kijelölt pontból végzett iterációkat grafikusan kirajzolja a program.

A következő ábrán mutatjuk be kifejlesztett programunk tipikus használati esetét: számos ablakban

nagyítgatunk, visszatérünk egy korábbihoz, pontosítjuk a számítást stb.

2.5.1. A MandelbrotHalmaz osztály

A korábbi pontok fejlesztései eredményeképpen a MandelbrotHalmaz osztály alábbi, a 0.0.2 verziója az

aktuális. Az alábbi forrásszöveget kijelölve a MandelbrotHalmaz.java forrásállományba kell beillesztenie az

Olvasónak a felhasználáshoz.

/*

* MandelbrotHalmaz.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* A Mandelbrot halmazt kiszámoló és kirajzoló osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.2

Page 381:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

353 Created by XMLmind XSL-FO Converter.

*/

public class MandelbrotHalmaz extends java.awt.Frame implements Runnable {

/** A komplex sík vizsgált tartománya [a,b]x[c,d]. */

protected double a, b, c, d;

/** A komplex sík vizsgált tartományára feszített

* háló szélessége és magassága. */

protected int szélesség, magasság;

/** A komplex sík vizsgált tartományára feszített hálónak megfelelő kép.*/

protected java.awt.image.BufferedImage kép;

/** Max. hány lépésig vizsgáljuk a z_{n+1} = z_n * z_n + c iterációt?

* (tk. most a nagyítási pontosság) */

protected int iterációsHatár = 255;

/** Jelzi, hogy éppen megy-e a szamítás? */

protected boolean számításFut = false;

/** Jelzi az ablakban, hogy éppen melyik sort számoljuk. */

protected int sor = 0;

/** A pillanatfelvételek számozásához. */

protected static int pillanatfelvételSzámláló = 0;

/**

* Létrehoz egy a Mandelbrot halmazt a komplex sík

* [a,b]x[c,d] tartománya felett kiszámoló

* <code>MandelbrotHalmaz</code> objektumot.

*

* @param a a [a,b]x[c,d] tartomány a koordinátája.

* @param b a [a,b]x[c,d] tartomány b koordinátája.

* @param c a [a,b]x[c,d] tartomány c koordinátája.

* @param d a [a,b]x[c,d] tartomány d koordinátája.

* @param szélesség a halmazt tartalmazó tömb szélessége.

* @param iterációsHatár a számítás pontossága.

*/

public MandelbrotHalmaz(double a, double b, double c, double d,

int szélesség, int iterációsHatár) {

this.a = a;

this.b = b;

this.c = c;

this.d = d;

this.szélesség = szélesség;

this.iterációsHatár = iterációsHatár;

// a magasság az (b-a) / (d-c) = szélesség / magasság

// arányból kiszámolva az alábbi lesz:

this.magasság = (int)(szélesség * ((d-c)/(b-a)));

// a kép, amire rárajzoljuk majd a halmazt

kép = new java.awt.image.BufferedImage(szélesség, magasság,

java.awt.image.BufferedImage.TYPE_INT_RGB);

// Az ablak bezárásakor kilépünk a programból.

addWindowListener(new java.awt.event.WindowAdapter() {

public void windowClosing(java.awt.event.WindowEvent e) {

setVisible(false);

System.exit(0);

}

});

// A billentyűzetről érkező események feldolgozása

addKeyListener(new java.awt.event.KeyAdapter() {

// Az 's', 'n' és 'm' gombok lenyomását figyeljük

public void keyPressed(java.awt.event.KeyEvent e) {

if(e.getKeyCode() == java.awt.event.KeyEvent.VK_S)

pillanatfelvétel();

// Az 'n' gomb benyomásával pontosabb számítást végzünk.

else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_N) {

if(számításFut == false) {

MandelbrotHalmaz.this.iterációsHatár += 256;

// A számítás újra indul:

számításFut = true;

new Thread(MandelbrotHalmaz.this).start();

}

// Az 'm' gomb benyomásával pontosabb számítást végzünk,

// de közben sokkal magasabbra vesszük az iterációs

// határt, mint az 'n' használata esetén

} else if(e.getKeyCode() == java.awt.event.KeyEvent.VK_M) {

if(számításFut == false) {

MandelbrotHalmaz.this.iterációsHatár += 10*256;

// A számítás újra indul:

Page 382:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

354 Created by XMLmind XSL-FO Converter.

számításFut = true;

new Thread(MandelbrotHalmaz.this).start();

}

}

}

});

// Ablak tulajdonságai

setTitle("A Mandelbrot halmaz");

setResizable(false);

setSize(szélesség, magasság);

setVisible(true);

// A számítás indul:

számításFut = true;

new Thread(this).start();

}

/** A halmaz aktuális állapotának kirajzolása. */

public void paint(java.awt.Graphics g) {

// A Mandelbrot halmaz kirajzolása

g.drawImage(kép, 0, 0, this);

// Ha éppen fut a számítás, akkor egy vörös

// vonallal jelöljük, hogy melyik sorban tart:

if(számításFut) {

g.setColor(java.awt.Color.RED);

g.drawLine(0, sor, getWidth(), sor);

}

}

// Ne villogjon a felület (mert a "gyári" update()

// lemeszelné a vászon felületét).

public void update(java.awt.Graphics g) {

paint(g);

}

/** Pillanatfelvételek készítése. */

public void pillanatfelvétel() {

// Az elmentendő kép elkészítése:

java.awt.image.BufferedImage mentKép =

new java.awt.image.BufferedImage(szélesség, magasság,

java.awt.image.BufferedImage.TYPE_INT_RGB);

java.awt.Graphics g = mentKép.getGraphics();

g.drawImage(kép, 0, 0, this);

g.setColor(java.awt.Color.BLUE);

g.drawString("a=" + a, 10, 15);

g.drawString("b=" + b, 10, 30);

g.drawString("c=" + c, 10, 45);

g.drawString("d=" + d, 10, 60);

g.drawString("n=" + iterációsHatár, 10, 75);

g.dispose();

// A pillanatfelvétel képfájl nevének képzése:

StringBuffer sb = new StringBuffer();

sb = sb.delete(0, sb.length());

sb.append("MandelbrotHalmaz_");

sb.append(++pillanatfelvételSzámláló);

sb.append("_");

// A fájl nevébe belevesszük, hogy melyik tartományban

// találtuk a halmazt:

sb.append(a);

sb.append("_");

sb.append(b);

sb.append("_");

sb.append(c);

sb.append("_");

sb.append(d);

sb.append(".png");

// png formátumú képet mentünk

try {

javax.imageio.ImageIO.write(mentKép, "png",

new java.io.File(sb.toString()));

} catch(java.io.IOException e) {

e.printStackTrace();

}

}

/**

* A Mandelbrot halmaz számítási algoritmusa.

Page 383:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

355 Created by XMLmind XSL-FO Converter.

* Az algoritmus részletes ismertetését lásd például a

* [BARNSLEY KÖNYV] (M. Barnsley: Fractals everywhere,

* Academic Press, Boston, 1986) hivatkozásban vagy

* ismeretterjesztő szinten a [CSÁSZÁR KÖNYV] hivatkozásban.

*/

public void run() {

// A [a,b]x[c,d] tartományon milyen sűrű a

// megadott szélesség, magasság háló:

double dx = (b-a)/szélesség;

double dy = (d-c)/magasság;

double reC, imC, reZ, imZ, ujreZ, ujimZ;

int rgb;

// Hány iterációt csináltunk?

int iteráció = 0;

// Végigzongorázzuk a szélesség x magasság hálót:

for(int j=0; j<magasság; ++j) {

sor = j;

for(int k=0; k<szélesség; ++k) {

// c = (reC, imC) a háló rácspontjainak

// megfelelő komplex szám

reC = a+k*dx;

imC = d-j*dy;

// z_0 = 0 = (reZ, imZ)

reZ = 0;

imZ = 0;

iteráció = 0;

// z_{n+1} = z_n * z_n + c iterációk

// számítása, amíg |z_n| < 2 vagy még

// nem értük el a 255 iterációt, ha

// viszont elértük, akkor úgy vesszük,

// hogy a kiinduláci c komplex számra

// az iteráció konvergens, azaz a c a

// Mandelbrot halmaz eleme

while(reZ*reZ + imZ*imZ < 4 && iteráció < iterációsHatár) {

// z_{n+1} = z_n * z_n + c

ujreZ = reZ*reZ - imZ*imZ + reC;

ujimZ = 2*reZ*imZ + imC;

reZ = ujreZ;

imZ = ujimZ;

++iteráció;

}

// ha a < 4 feltétel nem teljesült és a

// iteráció < iterációsHatár sérülésével lépett ki, azaz

// feltesszük a c-ről, hogy itt a z_{n+1} = z_n * z_n + c

// sorozat konvergens, azaz iteráció = iterációsHatár

// ekkor az iteráció %= 256 egyenlő 255, mert az esetleges

// nagyítasok során az iteráció = valahány * 256 + 255

iteráció %= 256;

// így a halmaz elemeire 255-255 értéket használjuk,

// azaz (Red=0,Green=0,Blue=0) fekete színnel:

rgb = (255-iteráció)|

((255-iteráció) << 8) |

((255-iteráció) << 16);

// rajzoljuk a képre az éppen vizsgált pontot:

kép.setRGB(k, j, rgb);

}

repaint();

}

számításFut = false;

}

/** Az aktuális Mandelbrot halmaz [a,b]x[c,d] adatai.

* @return double a */

public double getA() {

return a;

}

/** Az aktuális Mandelbrot halmaz [a,b]x[c,d] adatai.

* @return double b */

public double getB() {

return b;

}

Page 384:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

356 Created by XMLmind XSL-FO Converter.

/** Az aktuális Mandelbrot halmaz [a,b]x[c,d] adatai.

* @return double c */

public double getC() {

return c;

}

/** Az aktuális Mandelbrot halmaz [a,b]x[c,d] adatai.

* @return double d */

public double getD() {

return d;

}

/** Az aktuális Mandelbrot halmaz feletti rács adatai.

* @return int szélesség */

public int getSz() {

return szélesség;

}

/** Az aktuális Mandelbrot halmaz feletti rács adatai.

* @return int magasság */

public int getM() {

return magasság;

}

/** Az aktuális Mandelbrot halmazt tartalmazó kép.

* @return BufferedImage kép */

public java.awt.image.BufferedImage kép() {

return kép;

}

/** Példányosít egy Mandelbrot halmazt kiszámoló obektumot. */

public static void main(String[] args) {

// A halmazt a komplex sík [-2.0, .7]x[-1.35, 1.35] tartományában

// keressük egy 400x400-as hálóval:

new MandelbrotHalmaz(-2.0, .7, -1.35, 1.35, 600, 255);

}

}

2.5.2. A MandelbrotHalmazNagyító osztály

A korábbi pontok fejlesztései eredményeképpen a MandelbrotHalmazNagyító osztály alábbi, a 0.0.2 verziója

az aktuális. Az alábbi forrásszöveget kijelölve a MandelbrotHalmazNagyító.java forrásállományba kell

beillesztenie az Olvasónak a felhasználáshoz.

/*

* MandelbrotHalmazNagyító.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* A Mandelbrot halmazt nagyító és kirajzoló osztály.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.2

*/

public class MandelbrotHalmazNagyító extends MandelbrotHalmaz {

/** A nagyítandó kijelölt területet bal felső sarka. */

private int x, y;

/** A nagyítandó kijelölt terület szélessége és magassága. */

private int mx, my;

/**

* Létrehoz egy a Mandelbrot halmazt a komplex sík

* [a,b]x[c,d] tartománya felett kiszámoló és nygítani tudó

* <code>MandelbrotHalmazNagyító</code> objektumot.

*

* @param a a [a,b]x[c,d] tartomány a koordinátája.

* @param b a [a,b]x[c,d] tartomány b koordinátája.

* @param c a [a,b]x[c,d] tartomány c koordinátája.

* @param d a [a,b]x[c,d] tartomány d koordinátája.

* @param szélesség a halmazt tartalmazó tömb szélessége.

Page 385:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

357 Created by XMLmind XSL-FO Converter.

* @param iterációsHatár a számítás pontossága.

*/

public MandelbrotHalmazNagyító(double a, double b, double c, double d,

int szélesség, int iterációsHatár) {

// Az ős osztály konstruktorának hívása

super(a, b, c, d, szélesség, iterációsHatár);

setTitle("A Mandelbrot halmaz nagyításai");

// Egér kattintó események feldolgozása:

addMouseListener(new java.awt.event.MouseAdapter() {

// Egér kattintással jelöljük ki a nagyítandó területet

// bal felső sarkát vagy ugyancsak egér kattintással

// vizsgáljuk egy adott pont iterációit:

public void mousePressed(java.awt.event.MouseEvent m) {

// Az egérmutató pozíciója

x = m.getX();

y = m.getY();

// Az 1. egér gombbal a nagyítandó terület kijelölését

// végezzük:

if(m.getButton() == java.awt.event.MouseEvent.BUTTON1 ) {

// A nagyítandó kijelölt területet bal felső sarka: (x,y)

// és szélessége (majd a vonszolás növeli)

mx = 0;

my = 0;

repaint();

} else {

// Nem az 1. egér gombbal az egérmutató mutatta c

// komplex számból indított iterációkat vizsgálhatjuk

MandelbrotIterációk iterációk =

new MandelbrotIterációk(

MandelbrotHalmazNagyító.this, 50);

new Thread(iterációk).start();

}

}

// Vonszolva kijelölünk egy területet...

// Ha felengedjük, akkor a kijelölt terület

// újraszámítása indul:

public void mouseReleased(java.awt.event.MouseEvent m) {

if(m.getButton() == java.awt.event.MouseEvent.BUTTON1 ) {

double dx = (MandelbrotHalmazNagyító.this.b

- MandelbrotHalmazNagyító.this.a)

/MandelbrotHalmazNagyító.this.szélesség;

double dy = (MandelbrotHalmazNagyító.this.d

- MandelbrotHalmazNagyító.this.c)

/MandelbrotHalmazNagyító.this.magasság;

// Az új Mandelbrot nagyító objektum elkészítése:

new MandelbrotHalmazNagyító(

MandelbrotHalmazNagyító.this.a+x*dx,

MandelbrotHalmazNagyító.this.a+x*dx+mx*dx,

MandelbrotHalmazNagyító.this.d-y*dy-my*dy,

MandelbrotHalmazNagyító.this.d-y*dy,

600,

MandelbrotHalmazNagyító.this.iterációsHatár);

}

}

});

// Egér mozgás események feldolgozása:

addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {

// Vonszolással jelöljük ki a négyzetet:

public void mouseDragged(java.awt.event.MouseEvent m) {

// A nagyítandó kijelölt terület szélessége és magassága:

mx = m.getX() - x;

my = m.getY() - y;

repaint();

}

});

}

/**

* Pillanatfelvételek készítése.

*/

public void pillanatfelvétel() {

// Az elmentendő kép elkészítése:

java.awt.image.BufferedImage mentKép =

Page 386:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

358 Created by XMLmind XSL-FO Converter.

new java.awt.image.BufferedImage(szélesség, magasság,

java.awt.image.BufferedImage.TYPE_INT_RGB);

java.awt.Graphics g = mentKép.getGraphics();

g.drawImage(kép, 0, 0, this);

g.setColor(java.awt.Color.BLACK);

g.drawString("a=" + a, 10, 15);

g.drawString("b=" + b, 10, 30);

g.drawString("c=" + c, 10, 45);

g.drawString("d=" + d, 10, 60);

g.drawString("n=" + iterációsHatár, 10, 75);

if(számításFut) {

g.setColor(java.awt.Color.RED);

g.drawLine(0, sor, getWidth(), sor);

}

g.setColor(java.awt.Color.GREEN);

g.drawRect(x, y, mx, my);

g.dispose();

// A pillanatfelvétel képfájl nevének képzése:

StringBuffer sb = new StringBuffer();

sb = sb.delete(0, sb.length());

sb.append("MandelbrotHalmazNagyitas_");

sb.append(++pillanatfelvételSzámláló);

sb.append("_");

// A fájl nevébe belevesszük, hogy melyik tartományban

// találtuk a halmazt:

sb.append(a);

sb.append("_");

sb.append(b);

sb.append("_");

sb.append(c);

sb.append("_");

sb.append(d);

sb.append(".png");

// png formátumú képet mentünk

try {

javax.imageio.ImageIO.write(mentKép, "png",

new java.io.File(sb.toString()));

} catch(java.io.IOException e) {

e.printStackTrace();

}

}

/**

* A nagyítandó kijelölt területet jelző négyzet kirajzolása.

*/

public void paint(java.awt.Graphics g) {

// A Mandelbrot halmaz kirajzolása

g.drawImage(kép, 0, 0, this);

// Ha éppen fut a számítás, akkor egy vörös

// vonallal jelöljük, hogy melyik sorban tart:

if(számításFut) {

g.setColor(java.awt.Color.RED);

g.drawLine(0, sor, getWidth(), sor);

}

// A jelző négyzet kirajzolása:

g.setColor(java.awt.Color.GREEN);

g.drawRect(x, y, mx, my);

}

/**

* Hol áll az egérmutató?

* @return int a kijelölt pont oszlop pozíciója.

*/

public int getX() {

return x;

}

/**

* Hol áll az egérmutató?

* @return int a kijelölt pont sor pozíciója.

*/

public int getY() {

return y;

}

/**

Page 387:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

359 Created by XMLmind XSL-FO Converter.

* Példányosít egy Mandelbrot halmazt nagyító obektumot.

*/

public static void main(String[] args) {

// A kiinduló halmazt a komplex sík [-2.0, .7]x[-1.35, 1.35]

// tartományában keressük egy 600x600-as hálóval és az

// aktuális nagyítási pontossággal:

new MandelbrotHalmazNagyító(-2.0, .7, -1.35, 1.35, 600, 255);

}

}

2.5.3. A MandelbrotIterációk osztály

A MandelbrotIterációk osztály alábbi, a 0.0.1 verziója az aktuális. Az alábbi forrásszöveget kijelölve a

MandelbrotIterációk.java forrásállományba kell beillesztenie az Olvasónak a felhasználáshoz.

/*

* MandelbrotIterációk.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* A nagyított Mandelbrot halmazok adott pontjában képes

* nyomonkövetni az z_{n+1} = z_n * z_n + c iterációt.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

public class MandelbrotIterációk implements Runnable{

/** Mennyi időt várakozzunk két iteráció bemutatása között? */

private int várakozás;

// Kissé igaz redundánsan, s nem szépen, de kényelmesen:

private MandelbrotHalmazNagyító nagyító;

private int j, k;

private double a, b, c, d;

private int szélesség, magasság;

private java.awt.image.BufferedImage kép;

/**

* Létrehoz egy iterációkat vizsgáló <code>MandelbrotIterációk</code>

* szál objektumot egy adott <code>MandelbrotHalmaznagyító</code>

* objektumhoz.

*

* @param nagyító egy <code>MandelbrotHalmazNagyító</code> objektum

* @param várakozás várakozási idő

*/

public MandelbrotIterációk(MandelbrotHalmazNagyító nagyító, int várakozás) {

this.nagyító = nagyító;

this.várakozás = várakozás;

j = nagyító.getY();

k = nagyító.getX();

a = nagyító.getA();

b = nagyító.getB();

c = nagyító.getC();

d = nagyító.getD();

kép = nagyító.kép();

szélesség = nagyító.getSz();

magasság = nagyító.getM();

}

/** Az vizsgált pontból induló iterációk bemutatása. */

public void run() {

/* Az alábbi kód javarészt a MandelbrotHalmaz.java számolást

végző run() módszeréből származik, hiszen ugyanazt csináljuk,

csak most nem a hálón megyünk végig, hanem a háló adott a

példányosításunkkor az egérmutató mutatta csomópontjában (ennek

felel meg a c kompelx szám) számolunk, tehát a két külső for

ciklus nem kell. */

Page 388:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

360 Created by XMLmind XSL-FO Converter.

// A [a,b]x[c,d] tartományon milyen sűrű a

// megadott szélesség, magasság háló:

double dx = (b-a)/szélesség;

double dy = (d-c)/magasság;

double reC, imC, reZ, imZ, ujreZ, ujimZ;

// Hány iterációt csináltunk?

int iteráció = 0;

// c = (reC, imC) a háló rácspontjainak

// megfelelő komplex szám

reC = a+k*dx;

imC = d-j*dy;

// z_0 = 0 = (reZ, imZ)

reZ = 0;

imZ = 0;

iteráció = 0;

// z_{n+1} = z_n * z_n + c iterációk

// számítása, amíg |z_n| < 2 vagy még

// nem értük el a 255 iterációt, ha

// viszont elértük, akkor úgy vesszük,

// hogy a kiinduláci c komplex számra

// az iteráció konvergens, azaz a c a

// Mandelbrot halmaz eleme

while(reZ*reZ + imZ*imZ < 4 && iteráció < 255) {

// z_{n+1} = z_n * z_n + c

ujreZ = reZ*reZ - imZ*imZ + reC;

ujimZ = 2*reZ*imZ + imC;

// az iteráció (reZ, imZ) -> (ujreZ, ujimZ)

// ezt az egyenest kell kirajzolnunk, de most

// a komplex számokat vissza kell transzformálnunk

// a rács oszlop, sor koordinátájává:

java.awt.Graphics g = kép.getGraphics();

g.setColor(java.awt.Color.WHITE);

g.drawLine(

(int)((reZ - a)/dx),

(int)((d - imZ)/dy),

(int)((ujreZ - a)/dx),

(int)((d - ujimZ)/dy)

);

g.dispose();

nagyító.repaint();

reZ = ujreZ;

imZ = ujimZ;

++iteráció;

// Várakozunk, hogy közben csodálhassuk az iteráció

// látványát:

try {

Thread.sleep(várakozás);

} catch (InterruptedException e) {}

}

}

}

Jar készítése

Kérdés: Hogyan készíthetek olyan Java programot, mely Windows XP alatt az asztalra helyezett

ikonjára kattintva indul el?

Válasz: Készítsünk jar állományt és küldjünk az asztalra egy erre a jar állományra mutató

parancsikont!

C:\...\Munkakönyvtár> javac MandelbrotHalmaz.java

C:\...\Munkakönyvtár> jar cmf manifest.mf mandelbrotos.jar *.class

Page 389:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

361 Created by XMLmind XSL-FO Converter.

A fenti fordítás után a jar parancsot használva készítettük el a mandelbrotos.jar Java archívum

állományt. (A jar parancs része a JDK csomagnak.)

2.6. A Pi jegyeinek nyomában

Ez a rész azt segíti, hogy a kedves Olvasó a [KAPCSOLAT REGÉNY] olvasásának befejezésekor keletkezett

lelkesítő feszültségét át tudja vezetni a Pi jegyeinek önálló keresésébe.

A Pi közelítése című pontban megkezdett gombolyag fonalát követjük tovább. A [PI KÖNYV] könyv hívja fel a

figyelmet, hogy Penrose - általunk is sokat hivatkozott - [CSÁSZÁR KÖNYV] könyvében azt valószínűsíti,

hogy a „van-e tíz egymást követő hetes számjegy a Pi tizedes kifejtésében?” kérdésre a választ nem egy konkrét

számítás és keresés, hanem egy egzisztencia bizonyítás adja majd meg. S ezzel szemben 1997-ben Kanada

megtalált egy 7777777777 részsztringet a kifejtésben, ami egyébként a 22.869.046.249. pozíciótól kezdődik!

A következőkben olyan algoritmusokat ismertetünk, amihez a 64 bites lebegőpontos aritmetika is elegendő. Ez

az 1995-ben talált Bailey-Borwein-Plouffe [PI SZÁMÍTÁS], [BBP ALGORITMUS], [PI KÜLDETÉS], [PI

KÖNYV] féle (röviden BBP) algoritmus, aminek további meglepő érdekessége, hogy a Pi hexadecimális

kifejtésében egy adott pozíciótól tudunk jegyeket meghatározni, a korábbi jegyek ismerete nélkül!

/*

* PiBBP.java

*

* DIGIT 2005, Javat tanítok

* Bátfai Norbert, [email protected]

*

*/

/**

* A BBP (Bailey-Borwein-Plouffe) algoritmust a Pi hexa

* jegyeinek számolását végző osztály. A könnyebb olvahatóság

* kedvéért a változó és metódus neveket megpróbáltuk az algoritmust

* bemutató [BBP ALGORITMUS] David H. Bailey: The BBP Algorithm for Pi.

* cikk jelöléseihez.

*

* @author Bátfai Norbert, [email protected]

* @version 0.0.1

*/

public class PiBBP {

/** A Pi hexa kifejtésében a d+1. hexa jegytől néhány hexa jegy.*/

String d16PiHexaJegyek;

/**

* Létrehoz egy <code>PiBBP</code>, a BBP algoritmust a Pi-hez

* alkalmazó objektumot. A [BBP ALGORITMUS] David H. Bailey: The

* BBP Algorithm for Pi. alapján a

* {16^d Pi} = {4*{16^d S1} - 2*{16^d S4} - {16^d S5} - {16^d S6}}

* kiszámítása, a {} a törtrészt jelöli.

*

* @param d a Pi hexa kifejtésében a d+1. hexa jegytől

* számoljuk a hexa jegyeket

*/

public PiBBP(int d) {

double d16Pi = 0.0d;

double d16S1t = d16Sj(d, 1);

double d16S4t = d16Sj(d, 4);

double d16S5t = d16Sj(d, 5);

double d16S6t = d16Sj(d, 6);

d16Pi = 4.0d*d16S1t - 2.0d*d16S4t - d16S5t - d16S6t;

d16Pi = d16Pi - StrictMath.floor(d16Pi);

StringBuffer sb = new StringBuffer();

Page 390:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

362 Created by XMLmind XSL-FO Converter.

Character hexaJegyek[] = {'A', 'B', 'C', 'D', 'E', 'F'};

while(d16Pi != 0.0d) {

int jegy = (int)StrictMath.floor(16.0d*d16Pi);

if(jegy<10)

sb.append(jegy);

else

sb.append(hexaJegyek[jegy-10]);

d16Pi = (16.0d*d16Pi) - StrictMath.floor(16.0d*d16Pi);

}

d16PiHexaJegyek = sb.toString();

}

/**

* BBP algoritmus a Pi-hez, a [BBP ALGORITMUS] David H. Bailey: The

* BBP Algorithm for Pi. alapján a {16^d Sj} részlet kiszámítása.

*

* @param d a d+1. hexa jegytől számoljuk a hexa jegyeket

* @param j Sj indexe

*/

public double d16Sj(int d, int j) {

double d16Sj = 0.0d;

for(int k=0; k<=d; ++k)

d16Sj += (double)n16modk(d-k, 8*k + j) / (double)(8*k + j);

/* (bekapcsolva a sorozat elejen az első utáni jegyekben növeli pl.

a pontosságot.)

for(int k=d+1; k<=2*d; ++k)

d16Sj += StrictMath.pow(16.0d, d-k) / (double)(8*k + j);

*/

return d16Sj - StrictMath.floor(d16Sj);

}

/**

* Bináris hatványozás mod k, a 16^n mod k kiszámítása.

*

* @param n kitevő

* @param k modulus

*/

public long n16modk(int n, int k) {

int t = 1;

while(t <= n)

t *= 2;

long r = 1;

while(true) {

if(n >= t) {

r = (16*r) % k;

n = n - t;

}

t = t/2;

if(t < 1)

break;

r = (r*r) % k;

}

return r;

}

/**

Page 391:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

363 Created by XMLmind XSL-FO Converter.

* A kiszámolt néhány hexa jegy visszaadása. A használt lebegőpontos

* aritmentia függvényében mondjuk az első 6 pontos peldául

* d=1000000 esetén.

*

* @return String a kiszámolt néhány hexa jegy

*/

public String toString() {

return d16PiHexaJegyek;

}

/** Példányosít egy BBP algoritmust implementáló obektumot.*/

public static void main(String args[]) {

System.out.print(new PiBBP(1000000));

}

}

Fordítva és futtatva a példát azt kapjuk, hogy a Pi hexadecimális kifejtése az 1000001. jegytől a következő:

...6C65E5308...

[norbi@niobe ~]$ javac PiBBP.java

[norbi@niobe ~]$ java PiBBP

6C65E5308

(C-ben a long double típus használata mellett ugyanezzel a futtatással több jegy pontosság érhető el:

...6C65E52CB858...)

A PiBBP osztály felhasználásával elkezdhetjük folyamatosan vizsgálni adott pozíciótól a Pi hexadecimális

kifejtésének jegyeit, az osztály main() indítófüggvényét módosítva:

public static void main(String args[]) {

for(int i=1000000; i<1001000; i+=2) {

PiBBP piBBP = new PiBBP(i);

System.out.print(piBBP.toString().charAt(0));

System.out.print(piBBP.toString().charAt(1));

}

}

Fordítás és futtatás után

[norbi@niobe ~]$ javac PiBBP.java

[norbi@niobe ~]$ java PiBBP

6C65E52CB459350050E4BB178F4C67A0FCF7BF27206290FBE70F93B828CD939C475C728F2FDB0CB9

23CF52C40D631D4DB2E98340AA25A6F07DB685C0A9C04F3F6E667CFD6E1764C83ECA94E79661FC18

0E6AEF581987E79E13278712CB01255E8CE4D9E048F782D756370548FB0778323CF2074C2716D121

639F1DD5A31EF6C242676B3783AD528852CCA52A9B4F999C526B0750859AEEC9CE6635B30996A210

CD419D5FD47A4E7AAF906E26A4CCF99A2E493BBB5E7D5E0B94F15196DA8CD1A0C57FE03A629B2D58

42317C173D163EA8717B46930EE0FE82FEC4B01016F155FB446AA6958EAD9265EC0C914CB84755DD

1BCE5100C23804D67A787BEC57CD7D8E190B3F55E3D2558927215504F141AC8B0BA836F7781E1966

4EFA8B22BEB3816A70F7210E4784A1F37762361286448CD051BCE3A4CE156D70CDBA256C1A36C386

48633C8F13A53405795635084A2DEAF3B9066BC3863BB07447DDDBDE5644034A6893E3E1CFDB3696

31BAA4240D93F17F667F7C51ABF076F7C1BB35DECC240153F4817A579CBD1DAC895E8555929D1ADA

3C787A0BF2881BBC44C4BE505E91FE5A28B9BA47D4845B7639239AD71D8B63BF9D23B2CC88C9D39C

033B0482F5F801D778BBB734EA8B1BE878D129514BFA5C4A6D60E80CF4B14A2A5673992B18397230

54BD44F767B03245F2873973EF6D84B2B96EFC9A

Page 392:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Számítási mellékletek

364 Created by XMLmind XSL-FO Converter.

kaptuk például a Pi hexadecimális kifejtésének 1000001. pozíciójától a kifejtés 1000 hexadecimális számjegyét.

A PiBBP osztály felhasználásával természetesen elölről is elkezdhetjük folyamatosan vizsgálni a Pi

hexadecimális kifejtésének jegyeit, az osztály main() indítófüggvényét ehhez így módosítva:

public static void main(String args[]) {

for(int i=0; i<3000; i+=1) {

PiBBP piBBP = new PiBBP(i);

System.out.print(piBBP.toString().charAt(0));

}

}

Fordítás és futtatás után

[norbi@niobe ~]$ javac PiBBP.java

[norbi@niobe ~]$ java PiBBP

243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89452821E638D01377

BE5466CF34E90C6CC0AC29B7C97C50DD3F84D5B5B54709179216D5D98979FB1BD1310BA698DFB5AC

2FFD72DBD01ADFB7B8E1AFED6A267E96BA7C9045F12C7F9924A19947B3916CF70801F2E2858EFC16

636920D871574E69A458FEA3F4933D7E0D95748F728EB658718BCD5882154AEE7B54A41DC25A59B5

9C30D5392AF26013C5D1B023286085F0CA417918B8DB38EF8E79DCB0603A180E6C9E0E8BB01E8A3E

D71577C1BD314B2778AF2FDA55605C60E65525F3AA55AB945748986263E8144055CA396A2AAB10B6

B4CC5C341141E8CEA15486AF7C72E993B3EE1411636FBC2A2BA9C55D741831F6CE5C3E169B87931E

AFD6BA336C24CF5C7A325381289586773B8F48986B4BB9AFC4BFE81B6628219361D809CCFB21A991

487CAC605DEC8032EF845D5DE98575B1DC262302EB651B8823893E81D396ACC50F6D6FF383F44239

2E0B4482A484200469C8F04A9E1F9B5E21C66842F6E96C9A670C9C61ABD388F06A51A0D2D8542F68

960FA728AB5133A36EEF0B6C137A3BE4BA3BF0507EFB2A98A1F1651D39AF017666CA593E82430E88

8CEE8619456F9FB47D84A5C33B8B5EBEE06F75D885C12073401A449F56C16AA64ED3AA62363F7706

1BFEDF72429B023D37D0D724D00A1248DB0FEAD349F1C09B075372C980991B7B25D479D8F6E8DEF7

E3FE501AB6794C3B976CE0BD04C006BAC1A94FB6409F60C45E5C9EC2196A246368FB6FAF3E6C53B5

1339B2EB3B52EC6F6DFC511F9B30952CCC814544AF5EBD09BEE3D004DE334AFD660F2807192E4BB3

C0CBA85745C8740FD20B5F39B9D3FBDB5579C0BD1A60320AD6A100C6402C7279679F25FEFB1FA3CC

8EA5E9F8DB3222F83C7516DFFD616B152F501EC8AD0552AB323DB5FAFD23876053317B483E00DF82

9E5C57BBCA6F8CA01A87562EDF1769DBD542A8F6287EFFC3AC6732C68C4F5573695B27B0BBCA58C8

E1FFA35DB8F011A010FA3D98FD2183B84AFCB56C2DD1D35B9A53E479B6F84565D28E49BC4BFB9790

E1DDF2DAA4CB7E3362FB1341CEE4C6E8EF20CADA36774C01D07E9EFE2BF11FB495DBDA4DAE909198

EAAD8E716B93D5A0D08ED1D0AFC725E08E3C5B2F8E7594B78FF6E2FBF2122B648888B812900DF01C

4FAD5EA0688FC31CD1CFF191B3A8C1AD2F2F2218BE0E1777EA752DFE8B021FA1E5A0CC0FB56F74E8

18ACF3D6CE89E299B4A84FE0FD13E0B77CC43B81D2ADA8D9165FA2668095770593CC7314211A1477

E6AD206577B5FA86C75442F5FB9D35CFEBCDAF0C7B3E89A0D6411BD3AE1E7E4900250E2D2071B35E

226800BB57B8E0AF2464369BF009B91E5563911D59DFA6AA78C14389D95A537F207D5BA202E5B9C5

832603766295CFA911C819684E734A41B3472DCA7B14A94A1B5100529A532915D60F573FBC9BC6E4

2B60A47681E6740008BA6FB5571BE91FF296EC6B2A0DD915B6636521E7B9F9B6FF34052EC5855664

53B02D5DA99F8FA108BA47996E85076A4B7A70E9B5B32944DB75092EC4192623AD6EA6B049A7DF7D

9CEE60B88FEDB266ECAA8C71699A17FF5664526CC2B19EE1193602A575094C29A0591340E4183A3E

3F54989A5B429D656B8FE4D699F73FD6A1D29C07EFE830F54D2D38E6F0255DC14CDD20868470EB26

6382E9C6021ECC5E09686B3F3EBAEFC93C9718146B6A70A1687F358452A0E286B79C5305AA500737

3E07841C7FDEAE5C8E7D44EC5716F2B8B03ADA37F0500C0DF01C1F040200B3FFAE0CF51A3CB574B2

25837A58DC0921BDD19113F97CA92FF69432477322F547013AE5E58137C2DADCC8B576349AF3DDA7

A94461460FD0030EECC8C73EA4751E41E238CD993BEA0E2F3280BBA1183EB3314E548B384F6DB908

6F420D03F60A04BF2CB8129024977C795679B072BCAF89AFDE9A771FD9930810B38BAE12DCCF3F2E

5512721F2E6B7124501ADDE69F84CD877A5847187408DA17BC9F9ABCE94B7D8CEC7AEC3ADB851DFA

63094366C464C3D2EF1C18473215D908DD433B3724C2BA1612A14D432A65C45150940002133AE4DD

71DFF89E10314E5581AC77D65F11199B043556F1

megkapjuk a Pi hexadecimális kifejtésének 3000 jegyét, azaz hexában a 3.243F6....

Hosszabb számítások végzéséhez a kevésbé objektumorientált jellegű PiBBPBench osztály használatát

javasoljuk, az osztályt az Egyszerű összehasonlítások a sebesség kérdésében című pontban találja meg az

érdeklődő Olvasó.

Page 393:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

365 Created by XMLmind XSL-FO Converter.

Irodalomjegyzék

Idézetek, bevezető részek

[MÁTRIX MOZI] Wachowski, Andy és Wachowski, Larry. The Matrix. http://www.imdb.com/title/tt0133093/

. 1999.

[KVANTUM MOZI] Arntz, William és Chasse, Betsy. What the #$*! Do We (K)now!? Mi a csudát tudunk a

világról?. http://www.imdb.com/title/tt0399877/ http://www.whatthebleep.com/ . 2004.

[DOOM JÁTÉK] DOOM. http://www.idsoftware.com/ .

[MARX KÖNYV] Marx, György. Gyorsuló idő. Typotex. 2005.

[DOOM KÖNYV] Kushner, David. A DOOM LEGENDÁJA. VogelBurda. 2004.

[SZÁMÉRZÉK KÖNYV] Dehaene, Stanislas. A számérzék. Osiris. 2003.

[VASSY JEGYZET] Vassy, Zoltán. Schrödingerék macskája és más történetek.

http://vmek.oszk.hu/00500/00571/html/ .

[KERNIGHAN PROG KÖNYV] Kernighan, Brian W. és Plauger, P. J.. A programozás magasiskolája.

Műszaki. 1982.

[KERNIGHAN C KÖNYV] Kernighan, Brian W. és Ritchie, Dennis M.. A C programozási nyelv. Műszaki.

1993.

[WIGNER KÖNYV] Wigner, Jenő. Szimmetriák és reflexiok. Gondolat. 1972.

[TELLER LEVÉL] Jones, Eric M.. „Where is everybody”An Account of Fermi's Question.

http://www.fas.org/sgp/othergov/doe/lanl/la-10311-ms.pdf .

Informatikai, fizikai, matematikai jellegű ismeretterjesztés

[CSÁSZÁR KÖNYV] Penrose, Roger. A császár új elméje. Akadémiai. 1993.

[PENROSE-HAWKING KÖNYV] Penrose, Roger és Hawking, Stephen. A nagy, a kicsi és az emberi elme.

Akkord. 2003.

[STEWART KÖNYV] Stewart, Ian. A matematika problémái. Akadémiai. 1991.

[SZÁMÉRZÉK KÖNYV] Dehaene, Stanislas. A számérzék. Osiris. 2003.

[PARADOXON KÖNYV] Székely J., Gábor. Paradoxonok a véletlen matematikájában. Typotex. 2004.

[PÉNZ KÖNYV] Mérő, László. Az élő pénz. Tercium. 2004.

[ISTEN KÖNYV] Davies, Paul. Isten gondolatai. Kulturtrade. 1995.

Automata, algoritmus és információelmélet

[ALGORITMUSOK KÖNYV] Rónyai, Lajos. ALGORITMUSOK. Typotex. 1998.

[LOVÁSZ KÖNYV] Lovász, László. Algoritmusok bonyolultsága. Nemzeti. 1994.

Page 394:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Irodalomjegyzék

366 Created by XMLmind XSL-FO Converter.

[CHAITIN OMEGA] Chaitin, Gregory. A theory of program size formally identical to information theory.

Journal of the ACM http://www.cs.auckland.ac.nz/CDMTCS/chaitin/acm75.pdf

http://citeseer.ist.psu.edu/chaitin75theory.html . 22. 329-340. 1975.

[CHAITIN OMEGA 1] Chaitin, Gregory. META MATH! The Quest for Omega.

http://www.cs.auckland.ac.nz/CDMTCS/chaitin/omega.html .

[CHAITIN OMEGA 2] Chaitin, Gregory. THE LIMITS OF REASON.

http://www.cs.auckland.ac.nz/CDMTCS/chaitin/sciamer3.html .

[CHAITIN OMEGA n] Chaitin, Gregory. Omega and why maths has no TOEs.

http://plus.maths.org/issue37/features/omega/ .

[CALUDE KÖNYV] Calude, Cristian S.. Information and Randomness An Algorithmic Perspective. Springer.

2002.

[JAVA PROG és OMEGA] Calude, Cristian S., Dinneen, Michael J., és Shu, Chi-Kou. Computing a Glimpse of

Randomness. Experimental Mathematics http://www.cs.auckland.ac.nz/~cristian/Calude361_370.pdf

http://arxiv.org/abs/nlin.cd/0112022 . 2002.

[JAVA PROG és OMEGA 2] Shu, Chi-Kou. Computing Exact Approximations of a Chaitin Omega Number.

Ph.D. Thesis, University of Auckland, New Zealand . 2003.

[BENNETT CIKK] Bennett, Charles H.. On Random and Hard-to-Describe Numbers.

http://citeseer.ist.psu.edu/429077.html . 1979.

[VITÁNYI KÖNYV] Li, Ming és Vitányi, Paul. An Introduction to Kolmogorov Complexity and its

Applications. Springer. 1993.

[VITÁNYI HASONLÓSÁG CIKK] Chen, Xin, Li, Xin, Ma, Bin, és Vitányi, Paul. The Similarity Metric. IEEE

Transactions on Information Theory http://www.cwi.nl/~paulv/papers/similarity.pdf

http://arxiv.org/abs/cs.CC/0111054 . 50. 12. 2004.

[TURING CIKK] Turing, Alan. On computable numbers, with an application to the Entscheidungsproblem.

Proceedings of the London Mathematical Society http://web.comlab.ox.ac.uk/oucl/research/areas/ieg/e-

library/sources/tp2-ie.pdf . 2. 42. 1936.

[TURING GÉP REPREZENTÁCIÓ] Juhász, István és Szalai, Ferenc. Turing gép az általános iskolában. Frey

Tamás Vándorgyűlés, Kecskemét.. 1989.

[DRAGÁLIN KÖNYV] Dragálin, Albert és Búzási, Szvetlána. Bevezetés a matematikai logikába. Kossuth

Egyetemi Kiadó. 1996.

[MOBIL JÁTÉK ÉLMÉNY] Bátfai, Norbert és Bátfai, Erika. A mobil játékfejlesztés elméleti és gyakorlati

momentumai. Híradástechnika. LX. 34-36. 2005/5.

[BENCZÚR CIKK] Benczúr, András. The Evolution of Human Communication and the Information Revolution

- A Mathematical Perspective. Mathematical and Computer Modeling. 38. 691-708. 2003.

[SHANNON INFÓELM CIKK] Shannon, C. E.. A Mathematical Theory of Communication. The Bell System

Tech. Journal http://cm.bell-labs.com/cm/ms/what/shannonday/paper.html . 27. 379-423. 1984.

[DEMETROVICS KÖNYV] Demetrovics, János, Jordan, Denev, és Radiszlav, Pavlov. A számítástudomány

matematikai alapjai. Nemzeti Tankönyvkiadó. 1985.

[CHOMSKY NYELVOSZTÁLYOK] Chomsky, Noam. Three Models For The Description of Language.

http://www.chomsky.info/articles.htm .

Programozás

Page 395:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Irodalomjegyzék

367 Created by XMLmind XSL-FO Converter.

[PROGRAMOZÓ PÁTERNOSZTER JEGYZET] Bátfai, Norbert. Programozó Pátermoszter jegyzet.

http://www.javacska.hu/ProgramozoPaternoszter.pdf

http://www.inf.unideb.hu/~nbatfai/ProgramozoPaternoszter.pdf .

[PICI PROGRAMOZÁS I JEGYZET] Juhász, István. Programozás 1 egyetemi jegyzet.

http://infotech.inf.unideb.hu/juhasz/ .

[PICI PROGRAMOZÁS II JEGYZET] Juhász, István. Programozás 2 egyetemi jegyzet.

http://infotech.inf.unideb.hu/juhasz/ .

[PROGRAMOZÁS KÖNYV] Nyékyné Gaizler, Judit. Programozási nyelvek. Kiskapu. 2003.

[LEVÉNEZ IDŐVONALAK] Lévénez, Éric. Programming Languages. http://www.levenez.com/lang/ .

[SEBESTA KÖNYV] Sebesta, Robert W.. Concepts of programming languages. The Benjamin/Cumming.

1993.

[SEBESTA ÚJ KÖNYV] Sebesta, Robert W.. Concepts of programming languages. Addison-Wesley. 2004.

[JAVA ás C SHARP] Chandra, Shyamal Suhana és Chandra, Kailash. A comparison of Java and C Sharp.

Journal of Computing Sciences in Colleges http://portal.acm.org/ . 20. 3. 238-254. 2005.

[C SHARP J--] Johnson, Mark. C Sharp: A language alternative or just J--?.

http://www.javaworld.com/javaworld/jw-11-2000/jw-1122-csharp1.html . 2000.

[.NET Framework SDK 2.0] .NET Framework Developer Center. http://www.microsoft.com/netframework .

[C SHARP ALAP KÖNYV] Hejlsberg, Anders, Wiltamuth, Scott, és Golde, Peter. The C Sharp Programming

Language. Addison-Wesley. 2006.

[C SHARP KÖNYV] Illés, Zoltán. Programozás C Sharp nyelven. Jedlik Oktatási Stúdió. 2004.

[C SHARP KÖNYV 2] Mayo, Joseph. C Sharp Unleashed. SAMS. 2002.

[C SHARP KÖNYV 3] Sharp, John és Jagger, Jon. Microsoft Visual C Sharp .NET. Microsoft Press. 2002.

[SOMMERVILLE KÖNYV] Sommerville, Ian. Szoftverrendszerek fejlesztése. Panem. 2002.

Java programozás

[JAVA.SUN.COM] Java Technology. http://java.sun.com .

[JAVA.COM] java.com: Hot Games, Cool Apps. http://java.com .

[JAVA KÖNYV] Nyékyné Gaizler, Judit. Java 2 útikalauz programozóknak. ELTE TTK Hallgatói Alapítvány.

2000.

[JAVA EE KÖNYV] Nyékyné Gaizler, Judit. J2EE Útikalauz Java programozóknak. ELTE TTK Hallgatói

Alapítvány. 2002.

[JAVA 5 KÖNYV] Gaddis, Tony. Starting out with Java 5 Early Objects. Addison Wesley. 2005.

[KILLER KÖNYV] Davison, Andrew. Killer Game Programming. O'Reilly. 2005.

[J2ME KÖNYV] Piroumian, Vartan. Wireless J2ME Platform Programming. Prentice Hall. 2005.

[JAVA EE 5] Jendrock, Eric és al., et.. The Java EE 5 Tutorial . http://java.sun.com/javaee/5/docs/tutorial/doc .

2006.

[JAVA JÁTÉK] Twilleager, Doug, Kesselman, Jeff, Goldberg, Athomas, Petersen, Daniel, Soto, Juan Carlos, és

Melissinos, Chris. Java Technologies for Games. ACM Computers in Entartainment

http://portal.acm.org . 2. 2. 2004.

Page 396:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Irodalomjegyzék

368 Created by XMLmind XSL-FO Converter.

[MIDP 2.0 JÁTÉKOK] Mahmoud, Qusay. Getting Started With the MIDP 2.0 Game API.

http://developers.sun.com/techtopics/mobility/midp/articles/gameapi .

[JAVA PÉLDA WEBSZERVER] Brown, David. A Simple Multithreaded Web Server.

http://java.sun.com/developer/technicalArticles/Networking/Webserver/index.html .

[OAK] Byous, Jon. Java Technology: the Early Years. http://java.sun.com/features/1998/05/birthday.html .

[JAVA MINDENÜTT] Java Everywhere. http://www.sun.com/java/everywhere .

[GOSLING INTERJÚ] Eckstein, Robert. James Gosling on Open Sourcing Sun's Java Platform

Implementations. http://java.sun.com/developer/technical/Articles/Intervoews/gosling_os1_qa.html .

2000.

[HÁLÓZATI JAVA] Reilly, David és Reilly, Michael. Java Network Programming and Distributed Computing.

Addison-Wesley. 2002.

[JAVA DOKUMENTÁCIÓ] JDK 6 Documentation. http://java.sun.com/javase/6/download.jsp#docs .

[SUN JAVA CIKKEK] Core Java Technologies Tech Tips. http://java.sun.com/developer/JDCTechTips/ .

[SUN JAVA MOBIL CIKKEK] J2ME Technical Articles and Tips.

http://developers.sun.com/techtopics/mobility/reference/techart/index.html .

[FORUM NOKIA CIKKEK] Forum Nokia - resources for mobile application developers.

http://forum.nokia.com/ .

[MOBIL PROG EA] Bátfai, Norbert. A mobil játékfejlesztés elméleti és gyakorlati momentumai. Gyires Béla

Informatikai Nap, Debrecen http://www.inf.unideb.hu/kutatas/gybin/gybin04/Batfai_Norbert.pdf .

2005.

[MOBIL PROG SUN EA] Bátfai, Norbert és Bátfai, Erika. A Java mobiljáték-fejlesztés elmélete és gyakorlata

és a kék (JSR 82) játékok. 5. Sun Java Fejlesztői Nap, Budapest. 2005.

[JAVA START] Vég, Csaba és Juhász, István. Java Start!. Logos 2000. 1999.

Hálózatok, internet

[HÁLÓZATOK KÖNYV] Tanenbaum, Andrew S.. Számítógép-hálózatok. Panem. 2004.

[HÁLÓZATOS JAVA KÖNYV] Csizmazia, Balázs. Hálózati alkalmazások készítése : CORBA, Java, WWW.

Kalibán BT. 1998.

[CORBA SPECIFIKÁCIÓ] CORBA. http://www.omg.org/technology/documents/formal/corba_iiop.htm .

[COSNAMING IDL] cosnaming.idl. http://www.omg.org/docs/formal/04-10-07.txt .

[NYELVI LEKÉPEZÉS] Catalog of OMG IDL / Language Mappings Specifications.

http://www.omg.org/technology/documents/idl2x_spec_catalog.htm

http://www.omg.org/docs/formal/02-08-05.pdf .

[INTERNET REGULATION] Clark, David. Social Protocols, Design Principles, and Analytic Methods.

http://www.w3.org/Talks/1999/0105-Regulation/all.htm .

[PORTOK] IANA port assignments. http://www.iana.org/assignments/port-numbers .

[RFC] Request for Comments. http://www.ietf.org/rfc .

[RFC 822] STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES. http://www.ietf.org/rfc

.

[RFC 2616] Hypertext Transfer Protocol - HTTP/1.1. http://www.ietf.org/rfc .

Page 397:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Irodalomjegyzék

369 Created by XMLmind XSL-FO Converter.

Máselvű programozás

[DES TÖRÉS] Boneh, Dan. Breaking DES Using a Molecular Computer.

http://citeseer.ist.psu.edu/boneh95breaking.html .

[DNA SZÁMÍTÁS] Adleman, Leonard M.. Molecular Computation Of Solutions To Combinatorial Problems.

http://citeseer.ist.psu.edu/adleman94molecular.html .

Kvantum számítások

[ORCH OR] Hameroff, Stuart és Penrose, Roger. Orchestrated Objective Reduction of Quantum Coherence in

Brain Microtubules: The „Orch OR” Model for Consciousmess.

http://www.quantumconsciousness.org/penrose-hameroff/orchOR.html .

[ORCH OR TUDAT] Hameroff, Stuart és Penrose, Roger. Conscious Events as Orchestrated Space-Time

Selections. http://www.quantumconsciousness.org/penrose-hameroff/consciousevents.html .

[TEGMARK DEKOHERENCIA CIKK] Tegmark, M.. Importance of quantum decoherence in brain processes.

Physical Review E. http://prola.aps.org/abstract/PRE/v61/i4/p4194_1 . 65. 2002.

[TEGMARK DEKOHERENCIA VÁLASZ CIKK] Hameroff, Stuart R.. Quantum computation in brain

microtubules: Decoherence and biological feasibility. Physical Review E.

http://prola.aps.org/abstract/PRE/v65/i6/e061901 http://arxiv.org/abs/quant-ph/0005025 . 65. 2002.

[VÉLETLEN MŰSZER] Quantum Random Numbers Generator.

http://www.gapoptic.unige.ch/Prototypes/QRNG/ .

[KVANTUM TUDAT] atmanspacher, Harald. Quantum Theory and Consciousness: an Overview with Selected

Examples. 1. Discrete Dynamics in Nature and Society

http://www.hindawi.com/GetArticle.aspx?doi=10.1155/S102602260440106X . 2004.

[DEUTSCH KVANTUMGÉP CIKK] Deutsch, David. Quantum theory, the Church-Turing principle and the

universal quantum computer. Proceedings of the Royal Society of London A

http://citeseer.ist.psu.edu/deutsch85quantum.html . 400. 97-117. 1985.

[KVANTUMINFORMATIKA] Sailer, Kornél. Kvantuminformatika. http://dtp.atomki.hu/HOME-

PAGE/lectures/kvinfl.pdf http://dtp.science.unideb.hu/hun/jegyzetek.php . 1985.

Biológiai jellegű

[GÉP és AGY] Neumann, János. A számológép és az agy. Gondolat. 1964.

[HAMEROFF MIKROTUBULUS] Hameroff, Stuart R. és Watt, Richard C.. Information Processing in

Microtubules. Journal of Theoretical Biology http://www.ncbi.nlm.nih.gov/entrez/ . 98. 549-561.

1982.

[HAMEROFF INTERJÚ] Hameroff, Stuart R. és Gabora, Liane. Microtubules, Anesthetics, and Quantum

Consciousness: An Interview with Stuart Hameroff. Foundations of Science

http://www.springerlink.com/index/X55154J16754W370.pdf . 4. 205-223. 1999.

[HANGYÁK és KOLMOGOROV CIKK] Ryabko, Boris és Reznikova, Zhanna. Using Shannon Entropy and

Kolmogorov Complexity To Study the Communicative System and Cognitive Capacities in Ants.

http://boris.ryabko.net/papers.html .

[C. ELEGANS] Kitano, Hiroaki, Hamahashi, Shugo, Kitazawa, Jun, és Luke, Sean. The Perfect C. elegans

Project: An Initial Report. http://citeseer.ist.psu.edu/120528.html .

[UniProtKB/Swiss-Prot] ExPASy Proteomics Server. http://www.expasy.org .

[HUMÁN GENOM PROJEKT] Humán Genom Projekt. http://www.ncbi.nlm.nih.gov/genome/seq .

Page 398:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Irodalomjegyzék

370 Created by XMLmind XSL-FO Converter.

[SEJTBIO 1] Csaba, György. Sejtbiológia. Medicina. 1990.

[SEJTBIO 2] Szeberényi, József. Molekuláris sejtbiológia. Dialóg Campus. 1999.

[MIKROTUBULUS 1] Karafyllidis, Ioannis G. és Lagoudas, Dimitris C.. Microtubules as mechanical force

sensors. BioSystems http://www.ncbi.nlm.nih.gov/entrez PMID: 16806669 . 2006.

[BIOINFORMATIKA] Maróti, Péter. Információelmélet a biológiában. JATEPress. 2003.

[PROTEOMIKA] Campbell, A. Malcolm és Heyer, Laurie J.. Genomika, proteomika, bioinformatika. Medicina.

2004.

[GONDOLKODÓ KÖNYV] Calvin, William H.. A gondolkodó agy. Kulturtrade. 1996.

Matematikai jellegű

[KNUTH 2. KÖNYV] Knuth, Donald E.. A számítógép programozás művészete 2.. Műszaki. 1994.

[MATEK JÁTÉK] Csákány, Béla. Diszkrét matematikai játékok. Polygon. 171-173. 1998.

[ÉLET CIKK] Wainwright, Robert T.. Life is Universal. http://portal.acm.org/citation.cfm?id=800290.811303 .

1974.

[VÉLETLEN VÉLETLEN] Révész, Pál. Mennyire véletlen a véletlen?. Akadémiai. 14. 1984.

[VÉLETLEN KÖNYV] Deák, István. Véletlenszám generátorok és alkalmazásuk. Akadémiai. 1986.

[BARNSLEY KÖNYV] Barnsley, M.. Fractals everywhere. Academic Press, Boston. 1986.

[FRAKT. SZAKDOLG.] Bátfai, Norbert. Szimultán számrendszerekkel generált fraktálok ábrázolása. KLTE

szakdolgozat, témavezető Boros Zoltán. 1996.

[PI KÖNYV] Berggren, J. Lennart, Borwein, Jonathan M., és Borwein, Peter B.. A Pamphlet on Pi serving as a

Supplement for the Third Edition of Pi: A Source Book. http://citeseer.ist.psu.edu/589901.html . 2003.

[PI SZÁMÍTÁS] Bailey, David H., Borwein, Peter B., és Plouffe, Simon. On The Rapid Computation of

Various Polylogarithmic Constants. Mathematics of Computation

http://citeseer.ist.psu.edu/bailey96rapid.html . 66. 218. 903-913. 1997.

[PI KÜLDETÉS] Bailey, David H., Borwein, Jonathan M., Borwein, Peter B., és Plouffe, Simon. The Quest for

Pi. Mathematical Intelligencer http://citeseer.ist.psu.edu/bailey96quest.html . 19. 1. 50-57. 1996.

[BBP ALGORITMUS] Bailey, David H.. The BBP Algorithm for Pi.

http://crd.lbl.gov/~dhbailey/dhbpapers/bbp-alg.pdf . 2006.

[NEUMANN KVANTUM KÖNYV] Neumann, János. A kvantummechanika matematikai alapjai. Akadémiai.

1980.

[RÉNYI VALSÉG KÖNYV] Rényi, Alfréd. Valószínűségszámítás. Tankönyvkiadó. 144. 1973.

Informatika gyerekeknek, diákoknak

[JÁVÁCSKA BARÁTAI] Bátfai, Norbert. Jávácska Barátai, Gyermek - Robot Barátság.

http://www.javacska.hu .

[JÁVÁCSKA PORTÁL] Bátfai, Norbert és Bátfai, Erika. Jávácska Portál. http://javacska.lib.unideb.hu .

[II. JÁVÁCSKA] , . II. Jávácska Konferencia. http://javacska.lib.unideb.hu/konf2 .

[TANÁRKÉPZÉS EA.] Bátfai, Norbert és Bátfai, Erika. Jávácska és az informatika tanárképzés.

http://javacska.lib.unideb.hu/ea/IF_2005/Javacska_InfoTanarkepzes_If2005.pdf .

Page 399:  · PDF fileii Created by XMLmind XSL-FO Converter. Tartalom Bevezetés

Irodalomjegyzék

371 Created by XMLmind XSL-FO Converter.

[FANTASZTIKUS PROGRAMOZÁS] Bátfai, Norbert és Bátfai, Erika. Fantasztikus programozás. Debreceni

Egyetem Egyetemi és Nemzeti Könyvtár http://javacska.lib.unideb.hu/konyv/bv-naploja-kezirat-I-

5_0_0.pdf . 2004.

[LEGO MINDSTORMS] LEGO.com MINDSTORMS NXT Home. http://mindstorms.lego.com/ .

[LEJOS JAVA] leJOS - Java for Lego Mindstorms. http://www.lejos.org http://lejos.sourceforge.net/ .

[LEGO és NI] LEGO MINDSTORMS NXT - Powered by NI LabVIEW.

http://www.ni.com/academic/mindstorms/ .

Tudományos közösségek és szórakoztató ismeretterjesztés

[KAPCSOLAT MOZI] Zemeckis, Robert. Contact. http://www.imdb.com/title/tt0118884/ . 1997.

[KAPCSOLAT REGÉNY] Sagan, Carl. Kapcsolat. Édesvíz. 1993.

[SETI HOME] SETI@home. http://setiathome.ssl.berkeley.edu .

[ASIMOV REGÉNY] Asimov, Isaac. Én, a robot. Szukits. 2004.

[ASIMOV MOZI] Proyas, Alex. Én, a robot. http://www.imdb.com/title/tt0343818/ . 2004.

A szokásos paradigmákon túl

[KVANTUM JÓGA] Goswami, Amit. Képzelt ablak. Édesvíz. 2005.

[PROGRAMOZOTT VÍZ] Emoto, Masaru. A víz rejtett bölcsessége. Édesvíz. 2005.

Általános

[WIKI] , . Wikipedia, the free encyclopedia. Wikipedia .