1. fejezet

Elõttünk egy számítógép: hogy jön mindez a Jávához? Processzor, memória és a maradék: mindezeket programok vezérlik. Programszöveg nekünk és program a számítógépnek: a fordítóprogramok. Egy érdekes megoldás a Jávában: a virtuális gép. Elsõ Jáva programunk.

Ahhoz, hogy elolvashasd ezt a szöveget, számítógépet kell használnod és a lecke munkafüzet jellege miatt is szükséged lesz rá. Bizonyára a gép használata már meglehetõsen ismert, különben nem vágtál volna bele egy programozási tanfolyamba. Mindazonáltal tisztázzuk, alapvetõen milyen vadállat megszelídítésére vállalkoztunk. A számítógép feladata adatok feldolgozása. Bármit meg tud velük csinálni, összeadja, kivonja, mozgatja a memóriájában és a hozzá csatolt eszközök között. Minthogy ezt jóval gyorsabban csinálja, mint egy ember, nem lehet úgy irányítani, mint egy markológépet; mire megkapja a következõ emberi parancsot, azalatt elrepül sok millió mûvelet végrehajtási lehetõsége. Ezen okból a számítógépnek az elvégzendõ mûveletsorozatot elõre mondják meg, ez a program. A számítógép memóriája számok tárolására szolgál, így a programot magát is számsorozat formájában tárolják. Neumann János nagy felismerése volt, hogy a program és az adat alapvetõen ugyanolyan típusú információ és ezért ugyanabban a memóriában tárolható. Az alábbi képen egy Neumann-típusú számítógép blokkvázlata látható.

Neumann számítógép

1. ábra: Neumann-számítógép blokkvázlata

A legfontosabb komponens a CPU, a Central Processing Unit, röviden a processzor. Ez a számítógép központi vezérlõegysége, ez hajtja végre a memóriában elhelyezett programot. Az egy áramköri lapkán, chip-en (ezek azok a kis fekete lapos dobozok a számítógép áramköri lapján) megvalósított processzort mikroprocesszornak nevezzük. Minthogy manapság szinte mindegyik elterjedt processzor ilyen, a két elnevezést ma már felcserélhetõen használják.

A memóriában helyezkednek el azok az adatok, amikkel a processzor mûveleteket tud végezni illetve a programja, amit végrehajt. A memória, mint már írtam, számsorozatok formájában tárolja a programot. Egy szám, mint programutasítás jelentését a processzor tervezésekor döntik el. A processzor által támogatott összes utasítás számokhoz rendelése a gépi kód. A pusztán számokkal leírt, a processzor számára közvetlenül értelmezhetõ programot gépi kódúnak nevezzük. A gépi kód jelentése processzortípusonként változik, ez az egyik oka annak, hogy egyik típusú gépre írt program nem megy a másik típusú gépen.

Nagyon sokféle memória létezik, de ebben a pillanatban két csoportba osztjuk õket: felejtõ és nem felejtõ memóriákra. A felejtõ memória tartalma kitörlõdik, amikor a gépet kikapcsoljuk, ezt RAM-nak (Random Access Memory) is nevezik. A felejtésért cserébe a RAM írható és olvasható is, mégpedig mindkét mûveletet elég gyorsan meg lehet vele csinálni. A másik fajta memória nem felejti el a tartalmát, amikor a gépet kikapcsolják, ennek egyik alaptípusát ROM-nak (Read Only Memory) nevezik. Amint a neve is mondja, a ROM-ot csak olvasni lehet, a tartalmát a gyártás során állítják be. Ezen felül vannak még köztes típusok, pl. a Flash memóriák, amik nem felejtõk és írhatók is, viszont relatíve lassú õket írni.

A számítógépnek nem sok haszna van, ha csak a memóriájában levõ adatokat rendezgeti teljes elszigeteltségben, valahogy bele kell juttatni adatokat majd kinyerni belõle. Erre szolgálnak a perifériák vagyis a be-kiviteli egységek. Periféria pl. a billentyûzet, vagy a képernyõ, amin ezt olvasod, a merevlemez, az egér, a hálózati csatoló, stb. Nagyon bonyolult perifériák vannak, legtöbbjük (pl. a merevlemezed vagy a billentyûzeted) maga is egy kis specializált számítógép.

A számítógép egységeit egy adatút köti össze, ezt rendszerbusznak nevezzük. Bármely két (vagy több) egység képes itt kommunikálni oly módon, hogy az adatszolgáltató egység ráteszi az adatát a buszra, a fogadó(k) pedig leolvassa (leolvassák). Általában a CPU irányítja ezt a tevékenységet, de ez nem törvényszerû, intelligens perifériák maguk is képesek adatokat a memóriába írni. Modern számítógépekben nem egy busz van, hanem több is, de a programozó számára általában csak az öreg Neumann-architektúra látszik.

Amikor a gépet bekapcsolod, a processzor azonnal vad tevékenységbe fog és ezt nem is hagyja abba kikapcsolásig. A vad tevékenység azt jelenti, hogy egy megadott helyen elkezdi végrehajtani a memóriában tárolt programot. Jó, ha ott valami értelmes program van (ne feledd: minden memóriatartalom végrehajtható, hiszen minden program csak egy számsor), erre jó a ROM. Ide általában valami olyan programot tesznek, ami végeredményben lehetõvé teszi a felhasználónak, hogy kommunikáljon a géppel, begépelje a parancsait és elolvashassa a választ. Azért írom, hogy "végeredményben", mert a modern nagy számítógépekben ez egy elég bonyolult folyamat végeredménye, mivel az alapprogram is igen nagy. A ROM-ban elhelyezett programocska nem csinál mást, mint valami perifériáról feltölti azt a megalomániás valamit, ami manapság egy modern operációs rendszer (Operating System, OS). Az operációs rendszer egy programcsomaggyûjtemény, ami tartalmazza mindazt, ami egy program és a felhasználó számára szükséges a gép használatához. Egy program olyan alapfunkciókat igényelhet az operációs rendszertõl, mint egy fájl megnyitása, törlése, írása, olvasása, írás a képernyõre, olvasás a billentyûzetrõl, kommunikáció más gépekkel a hálózaton keresztül, stb. A felhasználó számára lehetõvé teszi programok indítását, leállítását, bejelentkezést, kijelentkezést, stb. Vannak funkciók, amelyeknél igen nehezen eldönthetõ, az operációs rendszerhez tartoznak-e, pl. a grafikus felület kezelése. Egy biztos: a dolog, amivel a géped több percig szórakozik bekapcsolása után, az operációs rendszer elindítása.

Az összes többi, kevésbé általános program az operációs rendszer irányítása alatt és annak szolgáltatásait felhasználva fut, ezeket alkalmazásoknak hívjuk. Mi is ilyen alkalmazásokat fogunk írni. Az alkalmazások gépi kódban töltõdnek be és értelmezõdnek. Roppant kellemetlen lenne azonban direkt gépi kódban programot írni és még kellemetlenebb karbantartani, tehát javítani, bõvíteni. Gondold meg: fejben kell tartani minden utasításhoz tartozó kódot és megérteni pedig a számokból kell a programot. Ugyancsak nem elõnyös, hogy a gépi kódú utasítások nagyon alacsony szintûek, egy betû képernyõre írása több száz sor is lehet. Dacára tehát annak, hogy a programunk mindig (még a Jávában is) a processzor saját nyelvén, tehát gépi kódban fut le, szinte sohase ebben írják, hanem valamilyen, ember számára jobban emészthetõ formában.

A legegyszerûbb ilyen forma az a kódolás, amikor a gépi kód minden egyes utasításának egy szöveges utasítást feleltetnek meg, ez a nyelv az assembly. Az assembly-ben könnyebbség, hogy nem kell számokra emlékezni, de továbbra is adott az utasítások egyszerûsége, assembly-ben nagyon munkaigényes programot írni. Az assembly programot a processzor természetesen nem képes végrehajtani (hiszen az csak ember számára olvasható (olvasható?) szöveg), elõbb kell egy program, az assembler, ami gépi kódú programot csinál belõle. Amióta a PC-k olyan nagyok lettek, mint régen egy miniszámítógép, az assembly használata visszaszorult, de mindenhol használják, ahol az erõforrások (processzor, memória) szûkösek vagy a feladat olyan gépet próbáló, hogy minden teljesítményt ki kell belõle facsarni.

A fenti trükköt, miszerint a programot valamilyen ember által könnyebben érthetõ formában írjuk, amit aztán egy másik program segítségével etetünk meg a számítógéppel, széles körben használják és nem csak olyan egyszerû nyelvekkel, mint az assembly. Ha az általunk írt förmedvényt (avagy zseniális programot) amúgy is el kell olvasnia egy másik programnak, hogy a géppel megetesse, akkor nem kell a gépi utasítások alacsony szintjéhez kötõdnünk, kényelmesebb nyelveket is létrehozhatunk ízlésünk szerint. Így jöttek létre a számítógépes nyelvek tucatjai, a LISP, a FORTRAN, a C, a BASIC, a Pascal, a C++ és a Jáva, hogy a többiekrõl ne is beszéljünk. Ezek a nyelvek elsõ pillantásra nagyon különböznek, de igazából csak néhány alapkoncepció variálására épülnek. Ahogy az egyik kalapács lehet jó és a másik rossz, úgy vannak jó és rossz nyelvek is. Sõt, ahogy az egyik kalapács jó lehet kõtörésre, a másik cipészkedésre, feladathoz is érdemes nyelvet választani. Az eddig legsikeresebbnek bizonyult programozási nyelv a C ill. az objektumorientált bõvítése a C++, ezt a két nyelvet a rendszerprogramozástól csillagászati programok készítéséig mindenre fel lehet használni. A Jáva nem ennyire sokoldalú, azonban felhasználói alkalmazások, különösen hálózati alkalmazások jóval gyorsabban és kevesebb hibalehetõséggel rakhatók benne össze, ezért ebben az alkalmazási szegmensben gyorsan terjed.

Mint megállapítottuk, minden programnál, ami nem gépi kódban íródott, kell egy másik program, ami a gép szájába rágja, mit is akartunk mondani. Pontosan, mintha a munkásunk csak eszperantóul beszélne, mi pedig netán csak magyarul tudnánk kommunikálni, kell valaki, aki lefordítja neki. Mint az emberi fordításoknál, itt is sokféle felállás lehetséges. Például leírhatjuk az instrukcióinkat, azt egy tolmács lefordíthatja eszperantóra és odaadhatja a munkásnak, aki ezek után elvégzi a feladatot. Világos, hogy a munkásnak ez jó, hiszen amikor dolgozik, már nem kell a fordítással törõdnie, ugyanakkor az instrukciók korrekt lefordítása munkaigényes feladat és meg se változtathatjuk õket menet közben. A fenti példához teljesen hasonló módon és ugyanazokkal az elõnyökkel-hátrányokkal mûködnek a compiler-ek vagy magyarul a fordítóprogramok. Ezek a programok megeszik az általunk írt programot és közvetlenül végrehajtható gépi kódot generálnak belõle. A legfõbb elõny a gépi kódra fordított program gyors futási sebessége és a jó minõségû fordítás, hiszen a fordítóprogramnak egy csomó ideje van gondolkodni a legjobb variáción. Példának okáért a C, C++ és a FORTRAN nyelvek leggyakoribb implementációi fordítóprogramot alkalmaznak.

Másik lehetõség, hogy szinkrontolmácsot alkalmazunk és miközben mi elõadjuk a mondókánkat, õ menetközben fordítja le eszperantóra. Hátrány persze, hogy a fordítás ideje hozzáadódik a munkavégzés idejéhez, hiszen amíg a munkás a tolmácsot hallgatja, nem dolgozik. Bizonnyal a fordítás se a legpontosabb. Ugyanakkor kimarad az elõzetes fárasztó külön fordítási menet és menetközben is megváltoztathatjuk az instrukciókat. A fenti séma az interpreter-ek vagyis az értelmezõprogramok megoldása. Itt a programunkat az értelmezõprogram futásidõben fordítja le. Elõnye a rendkívül gyors fejlesztési idõ (nincsenek lassú fordítási menetek) és elvileg lehet olyan programot is írni, ami újraírja önmagát. Hátrány a végrehajtási sebesség. A LISP és a BASIC legtöbbször értelmezõprogramos megvalósításban szokott rendelkezésre állni.

Tegyük fel, hogy eszperantó anyanyelvû alkalmazottunk mellett van olyan is, aki csak belgául tud. Akár a fordítóprogramos, akár az értelmezõprogramos megoldást választjuk, mindenképpen meg kell duplázni a fordítók számát. Pontosan ugyanez a probléma akkor is, ha szempont az, hogy minnél többfajta gépen menjen a programunk. Mindegyikben más processzor lenne, ami más gépi kódot ért, más fordító fog kelleni. Áthidaló megoldásként kitalálhatjuk, hogy soknyelvû alkalmazottainkkal piktogrammokkal fogunk kommunikálni. Tolmácsunk az instrukciókat piktogrammnyelvre fordítja, amit kitûnõ munkásaink sokkal gyorsabban fognak fel, mintha magyarul mondanánk nekik, habár nem olyan gyorsan, mintha az anyanyelvükön volna leírva. Ezzel a némileg idióta hasonlattal el is jutottunk a közbülsõ kódot alkalmazó nyelvekhez, mint amilyen a Jáva.

A Jáva nyelv nagy ígérete, és korlátai mellett az elterjedésének legnagyobb segítõje, hogy a nyelv egy saját kis világot hoz létre a hordozó processzoron és operációs rendszerben, amelyben minden Jáva program mindenhol lefuthat. Olyan ez, mint amikor világutazásunk közben mindegy, hol térünk be egy McDonald's-ba, Kínában vagy Nicaraguában, mindenhol ugyanazt kapjuk. A Jáva programok a Jáva virtuális processzor gépi kódjára fordítódnak és a Jáva virtuális operációs rendszer szolgáltatásait veszik igénybe. Ezt persze egy konkrét gépen ill. operációs rendszeren a Jáva futtatókörnyezet, a Jáva Virtuális Gép (Java Virtual Machine, JVM) kell fogadja és megoldania a Jáva gépi nyelv (a Jáva bájtkód) futtatását valamint a Jáva operációs rendszer szolgáltatásainak (a Jáva osztálykönyvtárnak) igénybevételét. Ez idõbe kerül, így Jáva programok sohase lehetnek olyan gyorsak, mint pl. a C-ben írtak. A sebesség azonban másodlagos lehet olyan elõnyök mellett, hogy pl. a Jáva programot gond nélkül lehet PC-n fejleszteni, majd változtatás nélkül telepíteni valami esztelen méretû számítógépre. Maga a Jáva futtatórendszer az operációs rendszer számára egy egyszerû alkalmazás, habár történtek már kísérletek az operációs rendszerrel való integrálására. A miáltalunk használt változat egyszerû alkalmazásként fut.

Az alábbi ábrán ez a koncepció látható. Meg kell jegyezni, hogy a JVM és a Jáva osztálykönyvtár implementációja természetesen szintén függ az operációs rendszertõl és a processzortól, de a rajta futó Jáva bájtkód már ugyanaz.

JVM

2. ábra. A Jáva program, a JVM, az operációs rendszer és a processzor kapcsolata

Ennyi csigázás után talán csapjunk is a lovak közé. Két dologra lesz szükségünk: egy installált Jáva futtatórendszerre (Java SDK) és egy szövegszerkesztõre. A szövegszerkesztõnek tudnia kell egyszerû szöveges fájlokat kezelnie, ilyen pl. a népszerû Notepad Windows rendszerekben. Számos oknál fogva a Word vagy hozzá hasonló komoly szövegszerkesztõ nem praktikus, habár használható. Érdemes szerezni egy programozóknak szánt szövegszerkesztõt (én Windows-on a GWD szövegszerkesztõt használom), az ilyenek el vannak látva minden csingilingivel, például színezik a forrásszöveget, ami javítja az áttekinthetõségét. Ha azonban nem akarsz ilyen kalandokba belemenni, jó az öreg Notepad.

Kell még a Java SDK. Lehet. hogy a gépeden már meg is van, tesztelésképpen add ki a java ill. a javac parancsokat a parancsértelmezõ ablakában (Command prompt). Ha ezek végrehajtódnak (képernyõnyi segítõ szöveget írva ki), más már nem is kell. Ha nem, fordulj

Kitérõ: a Java SDK installálása

fejezetünkhöz. Most pedig lássuk elsõ programunkat:

public class Elso {
  public void prog( String args[] ) {
    System.out.println( "Hello, ez az elso Java programunk!" );
  }

  public static void main( String args[] ) {
    Elso e = new Elso();
    e.prog( args );
  }
}

Mentsd el a fenti szöveget az Elso.java nevû fájlba. Fontos, hogy a fájl neve mindenképpen ez legyen! Jóval késõbb fogjuk kifejteni, miért , de a forrásban a "public class" mögött levõ névvel megegyezõnek kell legyen a forrásfájl neve .java kiterjesztéssel. Most mondd azt:

javac Elso.java

Ha minden jól ment, a parancs némi motozás után üzenet kiírása nélkül befejezi a futását. Ha most megnézed a könyvtárat, ahol a forrásszöveg volt, találsz egy Elso.class nevû fájlt. Ez a lefordított Jáva program, ebben van benne a programod Jáva bájtkódban. Most már csak egy Jáva virtuális gépet kell találnunk, ami le is futtatja. A java parancs pont ezt tudja.

java Elso

És megjelenik a következõ szöveg:

Hello, ez az elso Java programunk!

Hihetetlen, már mûködõképes programot írtunk! Igaz ugyan, hogy az egészbõl nem értünk semmit, de elsõ lépésnek nem rossz! A sok kékséggel most ne foglalkozzunk, egy sort azért elmagyarázok. A System.out.println arra jó, hogy amit a mögötte levõ zárójelek közé írtunk, kiírja a konzolra. Az idézõjelek fontosak: ez mondja meg a fordítóprogramnak, hogy amit mögötte lát, az nem programszöveg, nincs értelme a számítógép számára, csak egy, a gép számára értelmetlen, önkényes karaktersorozat, vagyis betûk, számok és szimbólumok sora. Errõl bõvebben majd egy késõbbi fejezetben! Végül az utasítást egy pontosvesszõ zárja, ez kötelezõ. Minden Jáva utasítás végén pontosvesszõ kell legyen.

Azt tanultuk a fejezet elején, hogy a számítógépnek a program elõre mondja meg, mit kell majd csinálnia. Ugyan a mi kis programunk elindításakor már így is jó sok mindent csinál (el se tudod képzelni, mennyi mindent!), mégis, demonstráljuk ezt a képességét most szuperprogramunk egy jelentõs bõvítésével: írassunk ki vele egy újabb sort.

public class Masodik {
  public void prog( String args[] ) {
    System.out.println( "Hello, ez az elso Java programunk!" );
    System.out.println( "Ez pedig egy masodik sor tole" );
  }

  public static void main( String args[] ) {
    Masodik e= new Masodik();
    e.prog( args );
  }
}

Másoljuk ki a szövegbõl a szövegszerkesztõbe, mentsük el, fordítsuk le és futtassuk. (Most utoljára súgok: Copy-Paste Notepad-be, elmenteni a Notepad-bõl Masodik.java néven, javac Masodik.java, java Masodik). A futtatási eredmény nem meglepõ:

Hello, ez az elso Java programunk!
Ez pedig egy masodik sor tole

Figyeljük meg, hogy a két szöveg egymás alá íródott ki. Ez a System.out.println tulajdonsága, ez minden, általa kiírt karaktersorozat után egy soremelést is kiír. A soremelés egy olyan speciális karakter, ami a következõ karakter kiírása pozícióját egy új sor elejére lépteti.

Feladat:

írasd ki a saját nevedet a számítógéppel!

Ezzel a lecke végére is értünk. Jókora utat jártunk be, a számítógép fogalmától eljutottunk egy mûködõképes Jáva programig. A következõ fejezetben bemutatjuk, miféle számításokat tudunk végeztetni szilíciumagyú barátunkkal.

Ellenõrzõ kérdések

  1. Mi a számítógépes program?
  2. Mi a processzor szerepe a számítógépben?
  3. Mi az operációs rendszer?
  4. Miért szükségesek fordítóprogramok?
  5. Miért elõnyös a McDonald's?
  6. Mi a különbség a gépi kód és a Jáva bájtkód között?
  7. Mi a Jáva virtuális gép?
  8. Milyen parancs indítja el a Jáva fordítóprogramot?
  9. Milyen parancs indítja el a Jáva virtuális gépet?
  10. Mi az a Jáva szerkezet, amivel a konzolra lehet írni?
  11. Mit jelent a karakter fogalma?
  12. Mi az a soremelés karakter?

Kovetkezo lecke Tartalomjegyzek