9. fejezet

Adatok tömegesen: tömbök a Jávában. Tömbtípusok. A Jáva tömbök is csak objektumok. Objektumok és tömbök tömbje.

Emlékszel lottós példánkra az 5. fejezetben, ott öt változóban tároltuk a lottószámokat. Talán már akkor megfordult a fejedben, hogy esetleg van egy elegánsabb módszer egymáshoz tartozó azonos típusú adatok tárolására. Ha a fiókosszekrénynél maradunk, mód van valami olyasmire, mint egy katalógusszekrény, ahol bizonyos kulcs (általában kezdõbetû) alapján érhetjük el az elemeket. A katalógusszekrénynek megfelelõ eleme a Jávának is van, de mi egy egyszerûbb adattípussal kezdjük, ahol az elemeket egy számmal, az indexszel lehet kiválasztani. Ezt az adattípust szinte minden számítógépes nyelv ismeri, tömbnek hívják.

Legegyszerûbb egy példával kezdeni. Nézzük a következõ sort:

int a[] = new int[20];

Különösebb magyarázat nélkül (majd jön az is!) egyelõre fogadjuk el, hogy ez a sor egy 20-elemû tömböt kreál, amelyben minden tömbelem egy int. Az tömbelemeket egy egész típusú indexszel választjuk ki: a tömb elsõ eleme a[0], a második az a[1], az utolsó az a[19] (minthogy 0-ról kezdtük a számlálást!) A tömbelemeket ugyanúgy kezelhetjük, mintha normális változók lennének, értéket adhatunk nekik:

a[0] = 42;

vagy pedig felhasználhatjuk az értékeit kifejezésekben:

a[2] = a[0] + a[1];

Természetesen az indexnek nem kell konstansnak lennie, tetszõleges egész kifejezés megteszi. Példának okáért a következõ programrészlettel tölthetjük fel az egész tömböt 42-vel.

for( int i = 0 ; i < 20 ; ++i )
  a[i] = 42;

Ilyen egyszerû ez a felszínen! Most vizsgáljuk meg a tömböt létrehozó sort, mert érdekességek találhatók ottan. Az objektumoknál megszokott módon nézzük a tömbváltozót magát:

int a[];

Ez a változó egy int-ekbõl álló tömbre mutató referencia. Ugyanúgy, mint egy objektumreferencia (mint ahogy valójában objektumreferencia is) egy mutatón kívül nincs lefoglalt tárterület mögötte. A 20 egész értékünk nem itt van. A referencia akkor lesz használható, ha létrehozunk egy tömbobjektumot, amire a referencia mutathat. Ilyen objektumot gyárt az értékadás jobb oldalán álló kifejezés.

new int[20];

Ez a kifejezés 20 egész számot befogadni képes tömbnek foglal helyet és visszatérési értéke a tömbre mutató referencia. Ezt tesszük bele az "a" tömbreferenciára, minek eredményeképpen az "a" változón keresztül indexelni tudjuk a tömböt. Az "a" változó - hasonlóan bármilyen más objektumrefernciához - tehát attól kap értelmet, amire mutat. Írhatjuk késõbb, hogy

a = new int[40];

Ekkor a régi tömb, amire "a" imént mutatott eltûnik (vagy elérhetõ egy másik referencián keresztül, ha volt ilyen) és "a" egy vadi új, ezúttal 40 elemû tömböt tud elérni.

A tömbök tehát a Jávában teljesen úgy viselkednek, mint az objektumok. Ha van egy tömb típusú referenciánk, azzal "rámutathatunk" egy már létezõ tömbre, így két tömbreferencián keresztül érhetjük el ugyanazt a tömböt. Példa:

int a[] = new int[20];
int b[];
b = a;
a[0] = 1;
b[1] = 13;

A két értékadás a programrész végén ugyanannak a tömbnek a 0. és az 1. elemét manipulálja, minthogy a 3. sorban megtettük, hogy a "b" is ugyanarra a tömbre hivatkozzon.

A tömbök annyira objektumszerûek, hogy saját egyedváltozóik is vannak. Minden tömbobjektumnak van egy length egyedváltozója, ami megmondja a tömb méretét. Elõzõ példánkban

a.length

és

b.length

egyaránt 20-at ad vissza értékként (merthogy igazából ez ugyanaz a tömb).

A Jáva teljes típus- és indexhatárellenõrzéssel rendelkezik. Nem tehetjük meg azt, mint a C-ben, hogy a tömbindexet a tömb méreténél nagyobbra állítjuk és telepiszkítjuk a memóriát. Amikor egy tömbreferencián keresztül elérünk egy tömbobjektumot, a Jáva ellenõrzi a tömbobjektum tényleges méretét (dinamikusan foglaltuk, fordításidõben nem jöhet rá) és kilövi a programot, ha túlindexelni próbálja a tömböt.

Feladat

Írjuk át a már elkészített lottó programot úgy, hogy a véletlen számokat egy 5 elemû int típusú tömbbe helyezze el! ! Gyakorlásképpen használjunk statikus metódusokat és adattagokat! A megoldást itt találhatod.

Feladat

  1. Készítsünk programot, mely feltölt egy 100 elemû, véletlen számokból álló tömböt, majd az elemeket kilistázza a konzolra! Gyakorlásképpen használjunk statikus metódusokat és adattagokat! Az osztály neve legyen "Osszegzes"!
  2. Bõvítsük a programot úgy, hogy adjuk össze az így generált tömb elemeit, majd az összeget írjuk ki a konzolra!
  3. Válogassok le az eredeti tömbbõl a páros, illetve páratlan számokat egy "paros" illetve "paratlan" nevu tömbbe, listázzuk ki külön a páros, illetve páratlan számokat, illetve írjuk ki ezek arányát! A megoldás az Osszegzes.java programban található, az 2. illetve 3. részfeladat a zárójelek elhagyásával bõvíthetõ.

Eddig túlságosan az egész típusú tömbökre összpontosítottunk, pedig a tömb által tárolt értékhalmaz (a tömb alaptípusa) természetesen akármilyen Jáva típus lehet. Lehet természetesen objektumreferencia is és ez agy nagyszerû esélyt ad nekünk arra, hogy objektumokat nagy számban állítsunk elõ. Eddig ugye mindegyikhez kellett egy külön referenciaváltozó, de ha most egy tömböt csinálunk referenciákból, jó sok objektumot létrehozhatunk. Emlékszünk még Elso objektumunkra a 7. fejezetben? Most csinálhatunk belõle mondjuk százat olymódon, hogy létrehozunk egy Elso típusú referenciatömböt és minden tömbelembe belepakolunk egy új Elso egyed referenciáját. Valahogy így:

Elso et[] = new Elso[100];
for( int i = 0 ; i < 100 ; ++i )
    et[i] = new Elso();

Az eredmény száz Elso egyed amelyeket az "et" tömb megfelelõ indexszelésével érhetünk el. Például mondhatjuk:

et[42].prog( args );

Ekkor a 43. Elso egyed prog metódusát hívtuk meg args paraméterrel.

Feladat

Írd át népszerû Kõ-Papír-Olló programunkat a 7. fejezetbõl úgy, hogy 5 játékos játsszon! A Jatekos referenciákból csinálj egy tömböt és ciklusokkal oldd meg. amit az eredeti program külön változókkal csinált! Íme a megoldás. Vedd észre, hogy a megoldás rövidebb, mint az eredeti program, tömbökkel sokat lehet spórolni!

Mint mondtam, a tömb alaptípusa bármi lehet, tehát tömb is. A tömb alaptípusú tömböt többdimenziós tömbnek hívjuk és néha nagyon jól tudnak jönni. A példa kedvéért tekintsünk egy kétdimenziós tömböt.

double t[][] = new double[100][100];

Ebben 100x100 double elem van, minden double elem 8 bájtot foglal, tehát a tömb mérete 80 kilobájt meg egy pici. Ez már igazán hatékony eszköz. Címezni a többdimenziós tömböt is csak úgy kell, mint egy egydimenzióst:

t[42][45] = 3.14;

Feladat

Írjunk programot, ami kiszámolja a hõeloszlást vízzel teli csõben. Azt tudjuk, hogy csõ keresztmetszete négyzetes, az alsó oldala egyenletes 12 fokon, a teteje egyenletes 90 fokon van, az oldalfalai mellett pedig a hõmérséklet egyenletesen 12-rõl 90 fokra emelkedik. Oldjuk meg a feladatot olymódon, hogy a csõ keresztmetszetét bontsuk kis kockákra, mondjuk 100x100-ra. A legszélsõ kockákat (tehát a 0. és 99. sorban ill. a 0. és 99. oszlopban levõket) töltsük fel a fix hõmérsékletértékekkel, a többit meg tetszõleges értékkel, pl. 12 és 90 átlagával. Számoljuk újra minden nem fix hõmérsékletû kiskocka hõmérsékletét úgy, hogy az a négy szomszédjának az átlaga, írjuk vissza az átlagot a kiskockába és tartsuk számon, mekkora volt a legnagyobb változás az átlagszámítás elõtti és utáni értékekre vonatkoztatva. Ha egy menetben a legnagyobb hõmérsékletváltozás nem több, mint 0.01 fok, nyomtassuk ki a tömbben tárolt értékeket 4 soronként ill oszloponként. Íme a megoldás. Mit befolyásol az átlagoláson átesett kiskockák kezdõértéke?

Ellenõrzõ kérdések

Kovetkezo lecke Tartalomjegyzek