Változók, avagy dobozok minden esetre
Ismerkedjünk meg a változókkal. A változóknak alapvetően két típusát különböztetjük meg: primitív és referencia. A referencia típusú változók nem egy egyszerű értére mutatnak, hanem egy összetettebb adatszerkezetre, maga a változó csak egy hivatkozás az adatszerkezet memóriabeli címére. Most a primitív változókat fogjuk tárgyalni.
A programunkban szinte mindig előfordul az, hogy valamilyen adatot tárolni szeretnénk. Az elméleti bevezetés cikkben foglalkoztunk azzal, hogy a Java egy objektum orientált programozási nyelv. Az objektumok pedig rájuk jellemző tulajdonságokból és az ezeket kezelő (beállító, lekérdező, módosító) metódusokból állnak. Ezeket a tulajdonságokat mi rendeljük hozzá az objektumokhoz, hiszen mi döntjük el, miket kívánunk használni. Minden tulajdonságot alapvetően három fontos elem határoz meg. A tulajdonság típusa, neve és értéke. A változó a háttérben valójában egy memóriaterület, ami valamilyen értéket tárol. Felsorolásképp nézzünk meg pár fontos megállapítást a változókkal kapcsolatban:
- A változók neve egyedi kell hogy legyen (adott blokkon belül), csak betűvel kezdődhet, de utána bármennyi és bármilyen karakter állhat.
- A változók értéke alapvetően nem fix, ezt módosíthatjuk, erre utal a változó név. (léteznek fix változók is, melyek értékét csak egyszer adhatjuk meg.)
- Minden változó egy időpontban egyetlen értéket tárolhat. Ha új értéket adunk neki, az előző érték törlődik.
A változó neve a programunkon belül minden esetben a benne tárolt értéket jelenti. Ahol a változó nevét a programba illesztjük, ott az abban tárolt értéket fogja felhasználni. Említettem, hogy a változó típussal, névvel és értékkel rendelkezik. Ebből a típusról nem volt még szó. A típus azt határozza meg, hogy milyen jellegű értéket tárolhatunk az adott változóban. A primitív változók alapvetően négyféle típusúak lehetnek, egy-egy konkrét példával:
- egész szám: 32
- valós szám: 1.125
- karakter: c
- logikai érték: true
Ezek az alaptípusok, de az egész és valós számok váltózói a bennük tárolt szám nagyságától függően még tovább bonthatók. Az egész számok egész értékeket tárolnak tizedesjegyek nélkül. A valós számok tizedesjegyekkel rendelkező számokat jelentenek. A karakter típusú változó valamilyen billentyűzeten lévő begépelhető karaktert tárolhat (betűk, számok, írásjelek, speciális karakterek, szóköz, stb), valamint speciális, önmagában be nem gépelhető vezérlő karaktereket tartalmazhat. A logikai érték pedig egy kétállású kapcsoló, mely igaz vagy hamis értékeket tárolhat, pontosabban ezek angol nyelvű megfelelőjét (true, false).
A változó tehát egy típussal, névvel és a típus által meghatározott értékkel rendelkező adatelem. Nézzünk a változók használatára egy példát. Vegyünk egy autó objektumot és pár ahhoz tartozó tulajdonságot. Legyen az autónak sebességfokozata, pillanatnyi sebessége, színkódja, és egy jelző, ami a színkódot bővíti ki, hogy metálfényű-e vagy sem. Ebben a példakódban mind a négy alaptípus megtalálható.
public class Auto { public static void main( String[] args ) { int fokozat; double sebesseg; char szinkod; boolean metal; System.out.println("Ez egy virtualis auto."); fokozat = 4; sebesseg = 48.6; szinkod = 'R'; metal = true; System.out.println( "Az auto sebessegfokozata: " + fokozat ); System.out.println( "Az auto pillanatnyi sebessege: " + sebesseg ); System.out.println( "Az auto szinkodja: " + szinkod ); System.out.println( "Az auto metalszinu: " + metal ); } }
A változók használatával kapcsolatban két nagyon fontos fogalmat kell tisztázni:
- deklarálás
- inicializálás
A deklarálás a változó típusának és nevének megadását jelenti. Ennek általános formája:
típus változónév;
Az inicializálás a változónak történő kezdőérték adás. Általános formája:
változónév = kezdőérték;
Ez a két lépés akár össze is vonható, ekkor a következőt írjuk:
típus változónév = kezdőérték;
A változók tekintetében fontos ügyelni arra, hogy addig ne használjuk – nem is nagyon tudjuk – a változót, amíg nem rendelkezik kezdőértékkel, ami akár nulla vagy típustól függően speciális null (üres) érték is lehet. Használatnak minősül az is, ha a változó értékét ki szeretnénk íratni a képernyőre. A változó értékét természetesen többször is meg lehet változtatni, ilyenkor az előző érték, mint már említettem, törlődik. Ez az értékadás formailag ugyanolyan, mint az inicializálás. A különbség a kettő között csak annyi, hogy az inicializálás a legelső értékadás.
Ahogy már említettem, a változó nevét használva a benne tárolt értéket kaphatjuk meg. Amikor például ki szeretnénk írni, hogy milyen értéket tárol, akkor a következőt tesszük:
"Az auto sebessegfokozata: " + fokozat
Az idézőjelek közötti szövegrészt String-nek nevezzük. Ez egy karakterekből álló karakterlánc (szövegnek is nevezik, bár nem csak betűket tartalmazhat). A String egy referencia változótípus, később fogjuk tárgyalni, most elég annyit tudni róla, hogy amit idézőjelek közé teszünk, az String típusú lesz. Azért fontos ez, mert jellemzően szövegeket írunk ki a képernyőre. Látjuk azt azonban, hogy a szöveghez “hozzáadjuk” a változót. A Java nyelvben a műveletek többségét (csakúgy, mint matematikában) balról jobbra értékeljük ki. Ekkor az történik, hogy a megadott szöveghez hozzáfűzi a változó értékét. De nem csak ennyi történik, hanem egy nagyon fontos dolog is!
Az összeadás, mint művelet itt összefűzést jelent, vagyis a változó tartalmát odailleszti a szöveg végére. De a szöveg és a példában említett fokozat nevű változó nem egyforma típusú. Az összefűzés során a számérték szöveg típusúvá alakul egy automatikus konverziót (típusváltást) követően. Ezért lehet így kiíratni a változók értékét.
Még a primitív változóknál is léteznek adott típuson belül különféle “méretű” tárolók. Attól függetlenül, hogy egy változó mondjuk egész számokat tartalmazhat, meg lehet adni a méretét is. A mérete alatt azt értjük, hogy a számítógép hány bájton tárolja a szám értékét, ezáltal meghatározza azt az intervallumot, amekkora értéket a változó felvehet. Egész típuson belül a következő állnak rendelkezésünkre:
Típus | Leírás | Tárolás | Intervallum |
---|---|---|---|
byte | bájt méretű egész | 8 bit | [-128;127] |
short | rövid egész | 16 bit | [-32768;32767] |
int | egész | 32 bit | [-2147483648;2147483647] |
long | hosszú egész | 64 bit | [-9223372036854775808;9223372036854775807] |
Az egész típusokhoz hasonlóan lebegőpontos számokat tartalmazó változóból is többféle, szám szerint kettő van.
Típus | Leírás | Tárolás |
---|---|---|
float | egyszeres pontosságú lebegőpontos | 32 bit |
double | kétszeres pontosságú lebegőpontos | 64 bit |
Mivel azonos típusból többféle méret létezik, már a kezdőérték megadásakor problémák lehetnek. Vegyük ezt a példát:
int szam = 10;
Ezzel semmi gond nincs, ugyanis az int típusba ez a méretű szám elfér. A byte és short típusoknál is hasonlóan lehet megadni kezdőértéket, arra kell csak ügyelni, hogy megfelelő méretű számot tároljunk csak benne. Az utolsóval már gond lenne, mert a tárolni kívánt érték már nincs benne a változónak megfelelő intervallumban.
- byte b = 10;
- byte b = -40;
- byte b = 120;
- byte b = 130;
A short típussal is hasonló a helyzet, ott például már nem lehetne egy 35000 értéket tárolni, mert nem fér el ebben a típusú változóban.
Mi a helyzet a long típussal? Egy érdekes hibába futhatunk bele egy ilyen sorral
long szam = 3000000000;
Tegyük fel, egy 3 milliárdos kezdőértéket akarunk adni. Fura, hiszen a változóban sokkal nagyobb méretű szám is beleférne. Ez a 3 milliárd melyik változónak az intervallumából log ki? Az int típuséból. Arról van szó, hogy ha csak egy számot leírunk mindenféle sallang nélkül, azt a Java int típusú értékként kezeli. A kisebb számoknál akkor hogyan oldja meg, hogy egy byte változóba belerakhatja a nagyobb méretű int típusú értéket? Konverzióval, vagyis a byte változóban már az átalakított, megfelelő méretű értéket helyezi el. Igen ám, de maradva az előző hibánál itt a gond az, hogy ekkora méretű int szám nem is létezik, ezért el sem fogadja így leírva. Ekkor külön jeleznünk kell a számérték végén a szám típusát a következőképp:
long szam = 3000000000L;
A leírt fix értékeket (nem csak ezeket, általában a leírt fix értékeket) literálnak nevezzük. Ez a long típus literálja. Középiskolában ekkora számokkal nem dolgozunk, de jó ha tudsz erről. Érdekes módon a Java a 10L helyett a 10l literált is elfogadja, holott alaphelyzetben a kis és nagybetűk között különbséget tesz.
A változók, mint adott méretű tárolók természetesen csak a nekik megfelelő méretű számokat képesek tárolni. A nagyobb méretű tárolókba elhelyezhetjük egy kisebb méretű változó értékét, de fordítva ez nem fordulhat elő, mert már fordítási hibával figyelmeztet a rendszer:
int i = 10; short s = i;
Összefoglalva tehát az egész számokat:
- négyféle méretű típusa létezik
- nagyobb méretű típusba be lehet tenni a kisebbet, fordítva nem
- a számokkal megadott literál int típusú, ha long típust szeretnél akkor 10L
A lebegőpontos számok esetén is hasonló a helyzet. Itt a jelzés nélküli literál alaphelyzetben double típust jelent: 10.0 Ha azonban mindenképpen float típust szeretnénk, akkor a 10F vagy 10f literál használatos. Itt is fordítási hibát ad, ha a nagyobb méretet a kisebb méretűben szeretnénk elhelyezni:
double d = 10.0; float f = d;
Tizedesvessző helyett tizedes pontot használunk, valamit nem kötelező ezt sem megadni ebben az esetben:
double d = 10D; float f = 10F;
Itt látszólag egész számot adunk kezdőértéknek, de a 10D literál miatt ez a 10.0 lesz valójában, vagy float típusnál hasonlóan csak kisebb méretben. Float típus értékmegadásánál viszont a literálnál kötelező ezt a formát használni, mivel az F elhagyásakor a számot alapból double méretűként kezelné a rendszer, ami viszont a float-ba nem fér bele. Ez a példa ezt a hibás használatot mutatja meg a jó megoldással együtt:
float f = 10.3; // hibás! float f = 10.3F; // helyes
Szia, nagyon jó a magyarázat és alapos az anyag. Viszont ez az állítás szerintem fordítva igaz: “•nagyobb méretű típust be lehet tenni a kisebbe, fordítva nem”
Köszönöm az észrevételt, javítottam. Ha találsz még másikat, kérem jelezd!