Java03.qxd
3/20/2011
9:46 AM
Page 49
3 Primitívek és hivatkozások
Ismerd meg a változóidat!
A változóknak két fajtája létezik: a primitívek (alaptípusok) és a hivatkozások. Eddig két helyen használtál változókat: az objektum állapotának leírására (példányváltozók) és helyi változókként (tagfüggvényen belül bevezetett változók). Késõbb majd argumentumokként (a hívó kód által a meghívott tagfüggvénynek átadott értékekként) és visszaadott típusként (a tagfüggvény hívójának visszaküldött értékekként) is alkalmazni fogod õket. Láttál már egyszerû alaptípusba tartozóként (pprimitívként) bevezetett egész értékû (int típusú) változókat, és összetettebb változókat, például karakterláncokat és tömböket is. Az élet azonban többrõl kell, hogy szóljon az egészeknél, karakterláncoknál és tömböknél. Mi van akkor, ha van egy PetOwner (Gazdi) objektumod egy Dog (Kutya) példányváltozóval? Vagy egy Car (Autó) objektumod egy Engine-nel (Motor)? Ebben a fejezetben lerántjuk a leplet a Java típusairól, és megnézzük, mi az, amit változóként bevezethetsz, mi az, amit egy változóba beletehetsz, és mi az, amit a változókkal csinálhatsz. Ezenkívül végre látni fogod, milyen az élet valójában a szemétgyûjtõ kupacban.
ez egy új fejezet
Java03.qxd
3/20/2011
9:46 AM
Page 50
változó bevezetése
Változó bevezetése
. usokra p í t a l e y odafigy etsz eg A Java áfot nem teh ir Egy Zs tozóba. ál Nyúl v
A Java odafigyel a típusokra. Nem engedi, hogy olyan bizarr és veszélyes dolgokat mûvelj, mint hogy egy Rabbit (Nyúl) változóba egy Giraffe (Zsiráf) hivatkozást gyömöszölsz – mi történik például, ha valaki arra próbálja utasítani a „zsiráfot”, hogy ugorjon (hop())? A Java azt sem hagyja, hogy egy egész típusú változóba lebegõpontos számot tegyél, hacsak be nem vallod a fordítónak, hogy tisztában vagy vele, hogy így pontosságot veszíthetsz (mindent, ami a tizedesvesszõ után áll). A fordítóprogram a legtöbb problémát képes kiszúrni:
Ne várd, hogy ezt lefordítsa. Szerencsére nem sikerülhet. Ahhoz, hogy a típusbiztonság érvényesüljön, minden változót a típusával együtt kell bevezetned. Egész változóról van szó? Egy Kutyáról? Egyetlen karakterrõl? A változóknak két fajtája létezik: primitívek (alaptípusok) és objektumhivatkozások. A primitívek alaptípusú értékeket (vagyis egyszerû bitmintákat) tárolnak – egészeket, logikai értékeket, lebegõpontos számokat –, míg az objektumhivatkozások (minõ meglepetés) objektumokra mutató hivatkozásokat (nahát!). Elõször a primitíveket vizsgáljuk meg, majd tisztázzuk, mit is jelent az, hogy objektumhivatkozás. A változó fajtájától függetlenül azonban két szabályt mindig be kell tartanod, amikor bevezetsz egy változót:
Minden változónak meg kell adnod a típusát. A típus mellett a változóknak névre is szükségük van, mert a kódban a nevükkel hivatkozhatsz rájuk. Nyúl változó
Minden változónak adnod kell egy nevet.
típus
név
Megjegyzés: Ha egy olyan utasítást látsz, aminek a jelentése „X típusú objektum”, a típust az osztály szinonimájának tekintheted. (A késõbbi fejezetekben ezen az állításon finomítunk egy kicsit.) 3. fejezet
Java03.qxd
3/20/2011
9:46 AM
Page 51
primitívek és hivatkozások
„Egy dupla tejeskávét kérek – nem is, legyen inkább egy int” A Java-változókra gondolhatsz úgy, mintha csészék, bögrék vagy korsók lennének: kávéscsészék; teásbögrék; söröskorsók sok-sok habzó nedûvel; pattogatott kukoricával töltött vödrök, amilyeneket a moziban adnak; csészék gömbölyû, szexi füllel; vagy fémperemû csészék, amelyekrõl tudod, hogy soha, de soha nem szabad betenni õket a mikróba. A változó csupán egy csésze. Egy tároló, ami tárol valamit. A csészékhez hasonlóan a változóknak is van mérete és típusa. Ebben a fejezetben elõször azokat a változókat (csészéket) tekintjük át, amelyek primitíveket tárolnak, egy kicsit késõbb pedig azokat, amelyek objektumokra mutató hivatkozásokat. Végig a csészehasonlatnál maradunk – bármilyen bárgyúnak tûnik is ebben a pillanatban a párhuzam, sokat segít majd, amikor jobban belebonyolódunk a tárgyalásba (ami hamarosan bekövetkezik). A primitívek olyanok, mint a kávézókban található csészék. Ha jártál már Starbucks kávézóban, akkor tudod, mirõl beszélünk: azokról a különféle méretû csészékrõl, amelyek mindegyikéhez társul egy „név”: kis rövid hosszú grande „rövid”, „hosszú”, „Szeretnék egy ’grande” mochát, csökkentett koffeintartalmút, extra tejszínhabbal”. A csészéket esetleg ki is teszik a pultra, hogy segítsenek a rendelésben:
long
A Javában a primitívek (alaptípusok) különbözõ méretûek, és ezeknek a méreteknek is van neve. Amikor bevezetsz egy változót a Javában, meg kell adnod a konkrét típusát. Az itt látható négy tároló a Java négy egész alaptípusát int short byte ábrázolja:
Minden csésze egy értéket tárol, csak éppen a Java-primitívek esetében nem azt mondod a fordítónak, hogy „Egy francia pörkölésû hosszút kérek”, hanem azt, hogy „Egy int változót legyen szíves, benne a 90-es számmal”. És van még egy aprócska különbség: a Javában nevet is kell adnod a csészéknek. A teljes rendelés tehát így hangzik: „Egy int változót legyen szíves, benne a 2486-os számmal, és a változó neve legyen height”. Minden primitív változó rögzített számú bitet tárol (ez a csésze mérete). A Java hat primitív számtípusának a méretét itt láthatod:
Alaptípusok Típus
Bitmélység
Értéktartomány
boolean és char boolean (JVM-függõ) true vagy false char 16 bit 0-tól 65535-ig
számtípusok (mindegyik elõjeles) egész byte
8 bit
short
16 bit
int
32 bit
long
64 bit
-128-tól 127-ig -32768-tól 32767-ig -2147483648-tól 2147483647-ig -hatalmastól +hatalmasig
lebegõpontos float 32 bit double 64 bit
változó változó
Primitívek bevezetése értékadással: int x; x = 234; byte b = 89; boolean isFun = true; double d = 3456.98; char c='f'; int z = x; boolean isPunkRock; isPunkRock = false; boolean powerOn; powerOn = isFun; long big = 3456789; float f = 32.5f;
knél ki t. Ezt a float értéke Figyeld meg az ’f’-e ntos po õ Java minden lebeg kell tenned, mert a m ne ak úként kezel, hacs értéket double típus ’f’-ként adod meg. most itt vagy
Java03.qxd
3/20/2011
9:46 AM
Page 52
primitív értékadás
Nem szeretnéd, ha kicsordulna…
Hegyezd ki a ceruzád!
Ügyelj rá, hogy az érték beleférjen a változóba.
Egy kis csészébe nem tehetsz nagy értéket. Na jó, tehetsz, de akkor túlcsordul a tetején. A fordítóprogram ezt megpróbálja megelõzni, ha látja a kódodból, hogy valami nem fog beleférni a kért tárolóba (változóba/csészébe). Egy int-nyi dolgot nem tölthetsz például egy byte méretû tárolóba:
// nem fog sikerülni!!
Miért nem sikerül? Végtére is, az x értéke 24, a 24 pedig határozottan elég kicsi ahhoz, hogy beleférjen egy byte-ba. Te is tudod, mi is tudjuk, de a fordítót csak az érdekli, hogy valami nagyot próbálsz beletenni egy kicsi tárolóba, és ezért fennáll a lehetõsége a túlcsordulásnak. Nem várhatod el a fordítótól, hogy ismerje az x értékét, még ha konkrétan látod is az értéket a kódban. Egy változóhoz többféleképpen is hozzárendelhetsz egy értéket: • beírsz egy konkrét („literális”) értéket az egyenlõségjel után (x=12, isGood = true stb.) • egy változó értékét rendeled hozzá egy másik változóhoz (x = y) • egy kifejezés segítségével kombinálod a kettõt (x = y + 43) Az alábbi példákban a literális értékeket félkövér, dõlt betûkkel jelöltük: egy size nevû, int típusú változót vezet be, és a 32 értéket rendeli hozzá egy initial (kezdõbetû) nevû, char típusú változót vezet be, és a ’j’ értéket rendeli hozzá egy d nevû, double típusú változót vezet be, és a 456,709 értékkel egy isCrazy nevû, boolean típusú változót vezet be (értékadás nélkül) a true értéket rendeli a korábban bevezetett isCrazy változóhoz egy y nevû, int típusú változót vezet be, és az x jelenlegi értékének, valamint a 456 értéknek az összeadásából származó értéket rendeli hozzá
3. fejezet
A fordítóprogram nem engedi, hogy egy nagy csészében levõ értéket egy kis csészébe önts. De mi a helyzet, ha fordítva próbálod – egy kicsit töltesz át egy nagyba? Semmi gond. Annak alapján, amit a primitív változók méretérõl és típusáról megtanultál, próbáld kitalálni, hogy az alábbi értékadások közül melyik érvényes, és melyik nem az. Még nem ejtettünk szót minden szabályról, ezért itt-ott a józan eszedre kell támaszkodnod. Tipp: a fordító mindig a biztonságot részesíti elõnyben. Az alábbi felsorolásban karikázd be azokat az utasítássorokat, amelyek egy adott tagfüggvényen belül érvényesek lennének:
Java03.qxd
3/20/2011
9:46 AM
Page 53
primitívek és hivatkozások
El a kezekkel attól a kulcsszótól! Azt már tudod, hogy a változóidnak meg kell adnod a nevét és a típusát. Már ismered az alaptípusokat (primitíveket). De mit használhatsz névként? Nos, a szabályok egyszerûek. Egy osztályt, tagfüggvényt vagy változót az alábbi szabályok szerint nevezhetsz el (a szabályok valójában egy kicsit rugalmasabbak, de így biztonságosabb):
Ragaszd fel!
A névnek betûvel, aláhúzásjellel (_) vagy dollárjellel ($) kell kezdõdnie. A nevek nem kezdõdhetnek számmal.
A
ptípus nyolc ala
golt Némi an t: e k meg õ
Az elsõ karakter után számokat is írhatsz; azok csak a név elején tiltottak. Feltéve, hogy betartod a fenti két szabályt, tetszõleges nevet választhatsz, de a Java foglalt (fenntartott) szavait nem használhatod.
Megfürdetni a macskát
szálak wait() notify()
a követk
ezõ:
kában udás birto
így jegye
zheted
ritert, y memo g e is k a agadn lhatsz m De kitalá n megragadjon: Vigyázat! A medvék ba hogy job gyomra nem bírja a nagy
Vannak úgynevezett kulcsszavak (és egyebek), amelyeket a fordítóprogram felismer. Ha össze szeretnéd zavarni a fordítót (nem jó ötlet), próbáld ki, hogy névként egy foglalt szót adsz meg. Már találkoztál néhány foglalt szóval, amikor a saját vá ltozóneve megírtad az elsõ osztályodat: idbe e A primitív típusok nevei ugyancsak a fenntartott szavak közé tartoznak:
ték A Java ér szerinti s á átad t alkalmaz
termetû szõrös kutyákat
Nem számít, mit hallottál: ne – ismétlem, ne – hagyd, hogy még egy n zek közül nagy szõrös kutyát egyiket se használd megegyek!
És még sok foglalt szó van, amivel eddig nem találkoztál. Ha nem is kell tudnod, mit jelentenek, azzal tisztában kell lenned, hogy te nem használhatod õket. Semmilyen körülmények között ne próbáld most megjegyezni ezeket a szavakat, mert ahhoz, hogy helyet csinálj nekik a fejedben, egy csomó mindent ki kell dobálnod (például hogy hová parkoltál a kocsiddal). Ne aggódj, mire a könyv végére érsz, a legtöbbet megtanulod majd.
Ez a táblázat foglalt.
A Java kulcsszavai és foglalt szavai (fontossági sorrend nélkül). Ha ezeket a szavakat használod, a fordítóprogram nagyon, nagyon dühös lesz. most itt vagy
Java03.qxd
3/20/2011
9:46 AM
Page 54
objektumhivatkozások
A Kutya objektumod vezérlése Már tudod, hogyan kell bevezetni egy primitív változót, és hogyan kell értéket adni neki. De mi a helyzet a nem primitív típusú változókkal? Más szavakkal, mi van az objektumokkal? Valójában nincs olyan, hogy objektum típusú változó. Csak objektumhivatkozás típusú változók léteznek. Az objektumhivatkozás típusú változók olyan biteket tárolnak, ame lyek egy objektum elérésének módját határozzák meg.
erre gondolj így
A változó nem magát az objektumot tárolja, hanem egy mutatót vagy címet. A Javában ugyanakkor nem tudjuk, hogy mi van egy hivatkozás típusú változón belül. Csak azt tudjuk, hogy bármi is le gyen, egy és csak egy objektumot jelképez. A JVM viszont tudja, hogyan érje el az objektumot a hivatkozás segítségével.
Egy objektumot nem gyömöszölhetsz bele egy változóba. Gyakran így gondolunk rá, és olyasmiket mondunk, hogy „Átadtam a String-et a System.out.println() tagfüggvénynek”, vagy „A tagfüggvény egy Kutyát ad vissza”, vagy „Egy új Foo objektumot tettem a myFoo nevû változóba” – de valójában nem ez történik. Nincsenek hatalmas bõvíthetõ csészék, amelyek tetszõleges objektum méretére képesek nõni. Az objektumok egyetlen helyen laknak – a szemétgyûjtõ kupacban. (Errõl bõvebben beszélünk a fejezet késõbbi részében.) A primitív változók olyan bitekkel vannak tele, amelyek a változó tényleges értékét ábrázolják, az objektumhivatkozás típusú változók azonban az objektum elérésének módját tárolják. A hivatkozó változók esetében a pont mûveletet (.) használhatod arra, hogy azt mondd, „fogd a pont elõtti dolgot, hogy megszerezd nekem a pont utánit”: Ez azt jelenti, hogy „fogd a myDog változó által hivatkozott objektumot, és hívd meg a segítségével a bark() tagfüggvényt”. Amikor a pont mûveletet használod egy objektumhivatkozáson, az olyan, mintha megnyomnál egy gombot az objektum távirányítóján. 3. fejezet
Cs óvá l U gat Ját szi Esz k ik Vis sza hoz
KU TYA A Dog (Kutya) hivatkozó változót tekintsd a Kutya távirányítójának, amivel ráveheted az „objektumot”, hogy különbözõ dolgokat csináljon (tagfüggvényeket hívjon meg).
Java03.qxd
3/20/2011
9:47 AM
Page 55
primitívek és hivatkozások
Az objektumok bevezetésének, létrehozásának és értékkel való ellátásának 3 lépése
hivatkozás (a bitmélység nem számít)
Az objektumhivatkozások is csak változóértékek. Olyasmi, amit beletölthetsz egy csészébe – csak éppen az érték ezúttal egy távirányító.
Primitív típusú változó primitív érték A változóba a 7-et ábrázoló bitek (00000111) kerülnek.
Hivatkozó változó
Dog objektum
A változóba a Dog objektum elérésének módját ábrázoló bitek Dog kerülnek. Maga a Dog objektum nem kerül a változóba!
hivatkozásérték
A primitív változók esetében a változó értéke… az érték (5, -26.7, 'a'). A hivatkozó változók 4esetében a változó értéke… az adott objektum elérésének módját ábrázoló bitek. Nem kell tudnod, hogyan valósítja meg a JVM az objektumhivatkozásokat. Persze egy mutatóval, ami egy mutatóra mutat stb. – de még ha tudod is, a biteket semmi másra nem használhatod, csak egy objektum elérésére. Azzal nem foglalkozunk, hogy hány 1-es és 0 van egy hivatkozás típusú változóban. Ez a JVM-tõl és a hold fázisától függ.
Hivatkozó változó bevezetése Ez arra utasítja a JVM-et, hogy foglaljon helyet egy hivatkozás típusú változónak, és adja neki a myDog nevet. A hivatkozás örökre Dog típusú lesz. Más szavakkal, egy olyan távirányító, amelyen egy kutya (Dog) – és nem egy macska (Cat), gomb (Button) vagy csatoló (Socket) – vezérlésére szolgáló gombok vannak.
Dog
Objektum létrehozása Ez arra utasítja a JVM-et, hogy foglaljon helyet egy új Dog objektum számára a kupacban (errõl késõbb bõvebben is beszélünk, különösen a 9. fejezetben).
Dog objektum
Az objektum és a hivatkozás összekapcsolása Ez az utasítás az új Dog-ot a myDog nevû hivatkozó változóhoz rendeli. Más szavakkal, beprogramozza a távirányítót.
Dog objektum
Dog most itt vagy
Java03.qxd
3/20/2011
9:47 AM
Page 56
objektumhivatkozások Nincsenek
hülye kérdések K: Milyen nagy egy hivatkozó változó?
Java – lehull a lepel Heti interjúalanyunk: Hivatkozás
Agyhullám: Elmondaná, milyen egy objektumhivatkozás élete? Hivatkozás: Ó, nincs benne semmi érdekes. Én csak egy távirányító vagyok, amit nem vagy jóban valakivel a JVM be lehet programozni, hogy különbözõ objektumokat vezéreljen. fejlesztõcsapatából, nem ismerheAgyhullám: A különbözõ objektumokat úgy érti, hogy miközben Ön fut? Például ted a hivatkozások ábrázolási képes egy Kutyára hivatkozni, aztán öt perccel késõbb egy Autóra? módját. Valahol biztos mutatók Hivatkozás: Természetesen nem. Ha bevezettek, akkor már nincs mit tenni. bújnak meg mögöttük, de nem Ha kutya-távirányító vagyok, akkor soha nem leszek képes semmi másra mutatférhetsz hozzájuk. Nincs is rá ni (húha, elszóltam magam; nem mondhatom, hogy mutatni), úgy értem, hivatszükséged. (Na jó, ha ragaszkozni, mint egy Kutyára. kodsz hozzá, képzeld azt, hogy Agyhullám: Ez azt jelenti, hogy csak egy Kutyára hivtkozhat? 64 bites értékekrõl van szó.) MeHivatkozás: Nem. Hivatkozhatok egy bizonyos Kutyára, aztán öt perc múlva egy mámóriafoglalási ügyekben a Nagy sik Kutyára. Amíg Kutyáról van szó, addig át lehet irányítani egy másikra (ahogy Kérdés az, hogy hány objektumot a távirányítót is át lehet programozni egy másik TV-re). Hacsak…á, hagyjuk. (és nem objektumhivatkozást) Agyhullám: Nem, nem, ez érdekes. Mit akart mondani? hozol létre, és azok (az objektuHivatkozás: Nem hiszem, hogy érdemes ebbe belebonyolódni, de azért elmonmok) milyen nagyok. dom röviden. Ha final jelzõt kapok, akkor semmi másra nem lehet beprogramozni, csak arra a bizonyos Kutyára. Más szavakkal, semmilyen más objektuK: Ez azt jelenti, hogy minden objek- mot nem lehet hozzám rendelni. tumhivatkozás azonos méretû, függet- Agyhullám: Igaza van, ebbe most tényleg ne menjünk bele. Szóval, hacsak nem véglenül attól, hogy ténylegesen mekko- leges (final) Ön, akkor hivatkozhat egy Kutyára, aztán késõbb egy másikra. Azt is rák azok az objektumok, amelyekre hi- megteheti, hogy semmire nem hivatkozik? Be lehet programozni a „semmire”? vatkoznak? Hivatkozás: Igen, de errõl nem szeretnék beszélni. A gyhullám: Miért? V: Aha. Egy adott JVM esetében minden hivatkozásnak egyforma Hivatkozás: Mert ez azt jelenti, hogy egy null vagyok, ami nagyon kínos nekem. Agyhullám: Úgy érti, azért, mert akkor nincs értéke? a mérete, függetlenül a hivatkoHivatkozás: Ó, nem. A null is egy érték. Attól még távirányító maradok, de zott objektumoktól, de mivel olyan, mintha venne egy új, univerzális távirányítót, miközben nincs is tévéje. minden JVM másképp ábrázolhatja a hivatkozásokat, a hivatko- Nem irányíthatok semmit. Egész nap nyomkodhatják a gombjaimat, semmi érdezások kisebbek vagy nagyobbak kes nem történik. Ettõl olyan…feleslegesnek érzem magam. Elpazarolt biteknek. Persze nem túl sok bitnek, de akkor is. És ez még nem a legrosszabb. Ha én valehetnek az egyik JVM-en, mint egy másikon. gyok az egyetlen hivatkozás egy bizonyos objektumra, és valaki null-ra állít („kiprogramoz”), akkor az azt jelenti, hogy többé senki nem érheti el azt az objektumot, amelyre hivatkoztam. K: A hivatkozó változókon is lehet Agyhullám: És ez szörnyû, mert…? matematikai mûveleteket végezni, Hivatkozás: Még kérdeznie kell? Felépítettem egy kapcsolatot ezzel az objektumpéldául növelni õket? Tudjátok, ilyen mal, bizalmas viszonyba kerültem vele, és erre valaki hirtelen elvágja a köztünk C-dolgokat… levõ köteléket. Ráadásul soha többé nem láthatom az objektumot, mert kijelölõV: Nem. Ismételd velünk: „A Java dik [Megjegyzés a gyártásvezetõnek: tragikus zene bevág] szemétgyûjtésre. [Zonem C.” kogás] Azt hiszi, a programozók valaha is gondolnak erre? [Szipogás] Miért? Miért nem lehetek primitív? Utálok hivatkozás lenni! A felelõsség, a tönkretett kapcsolatok…
V: Azt nem tudhatod. Hacsak
3. fejezet