Csinálj egy új Java projektet, kocsma-oop névvel! Adj hozzá egy Innivalo nevű osztályt:
public class Innivalo {
double felszolgaltMeret=5; // dl
double alkoholTartalomSzazalek=4; // %
}
No ez eddig semmi nehézség, csak az innivaló tulajdonságai. Most fél liter 4 százalékos sört állítottam be, persze tudjuk, hogy nem minden innivaló ilyen... de kezdetnek ez jó lesz.
Aztán, adj hozzá egy Ember osztályt!
public class Ember {
double fogyasztottAlkohol=0;
double alkoholTures=1;
void igyal(Innivalo innivalo) {
fogyasztottAlkohol+=innivalo.felszolgaltMeret*innivalo.alkoholTartalomSzazalek/100;
}
}
No itt is csak az ember tulajdonsága van, itt is egyelőre 1 deci az alkoholtűrés. De az Ember képes műveletet is végezni: meginni egy innivalót. Erre szolgál az igyál metódus, aminek a paramétere nem int, nem double, nem string, hanem egy Innivalo típusú objektum.
Az innivalo objektum egy nagy "doboz", ami tartalmazza hogy épp mennyi a felszolgálási mérete és az alkohol százaléka egy innivalónak, és azt jól ki tudjuk olvasni belőle, és így kiszámolni, hogy mennnyi alkoholt fogyasztottnuk el amikor megittunk egy sört.
A kocsma osztályt is hozd létre. Ez az, ahol minden történik, és ebben lesz a main függvény, ami a programunk eleje.
public class Kocsma {
public static void main(String[] args) {
Ember jack=new Ember();
Ember jane=new Ember();
Innivalo sor=new Innivalo();
jack.igyal(sor);
}
}
No, mi is történik itt?
Először is, létrehozunk két Ember példányt. Isteni érzés, ugye? Szóval, jack és jane is Ember. Egy Ember objektum példányt a new operátorral (műveleti jellel) lehet létrehozni.
Ez egy sima értékadást, nézd csak meg, olyan, mint amikor egy int változónak adunk értéket:
int ennyiPizzatKerek=42;
Ember jack=new Ember();
No de, miért nem elég, hogy
Ember jack=42; // ez itt teljesen értelmetlen
A probléma az, hogy jack egy Ember, nem pedig egy szám. Eleve is legalább két változója van, most csináltuk, akkor az egyetlen számot hogyan is adhatnánk neki értékül?
A konvenció azt jelenti, megállapodás, és arra jó, hogy rendet tart a szokások között. A Javaban nagyon sok ilyen konvenció van, így a világ többmillió Java feljesztője egyformán jó minőségben tud programozni. Tegyünk mi is így, és tartsuk be ezeket:
Emlékszel, hogy a Javaban majdnem minden objektum. Kevés kivétel a primitív adattípusok, azaz azok az egyszerű dolgok, amik csak egyetlenegy értéket tárolnak.
Primitív az:
Egy objektum viszont egyszerre bármennyi értéket tárolhat, az Ember objektumunk két dolgot tárol most: az elfogyasztott alkohol mennyiségét, és az alkohol tűrést.
Objektum az:
Ahhoz hogy egy objektum belsejébe kezdőértéket adjunk, valami ilyesmit fogunk használni hamarosan:
De a Java nyelvhez is vannak objektumok, amik hasonítanak a primitív típusokhoz:
Na várjunk. Két oldallal ezelőtt még String a="Hello" volt, most akkor mi van? Meg miért is van Double meg double külön?
A helyzet az, hogy jó lenne, ha egy objektum-orientált nyelvben minden objektum lenne. Sajnos azonban az objektumok kissé több memóriát igényelnek és picit lassabb velük bánni, mint a primitív adattípusokkal.
A 90-es években, amikor a Java megjelent, a gépek nem voltak túl gyorsak, és sok régivágású igazi programozó úgy gondolta, hogy "a Java vacak, mert lassú, bezzeg C-ben az int milyen gyors". Hát így kerültek bele a Javaba a primitív adattípusok, hogy pont olyan gyors legyen, mint a C.
Viszont az objektum-típusok (Integer, Double) tudják mindazt a rengeteg sok jót, amit egy OOP nyelvtől el lehet várni. Szóval, mindkettő itt van, és mindkettő használható.
Ráadásul, hogy könnyebb legyen használni az objektum-típusokat, ezért a Java nyelvben van egy érdekes autoboxing nevű könnyítés. Ezzel az Integer, Double, Boolean, String típusokat olyan könnyen tudjuk használni, mintha primitív típusok lennének:
Integer a=new Integer(22); // létrehozzuk az ojjektumot ahogy kell
Integer a=22; // autoboxing, így könnyebb
String a=new String("Hello"); // létrehozzuk az ojjektumot ahogy kell
String a="Hello"; // autoboxing, így könnyebb
Természetesen ez működik visszafelé is, aminek a neve auto-unboxing. Ez akkor praktikus, ha számolni szeretnénk valamivel. Számolni csak számokkal lehet, objektumokkal nem (mit is jelenthet az, hogy jack*sör-jane?)
Integer a=22; // autoboxing, így könnyebb
Integer b=33; // autoboxing, így könnyebb
Integer c=new Integer(a.intValue()+b.intValue()); // Jajj de ronda
Integer c=a+b; // auto-unboxing előszedi a és b értékét, amit össze lehet adni
// és autoboxing becsomagolja az eredményt Integerbe
String hello="Hello"; // autoboxing
String vilag="Vilag"; // autoboxing
String eredmeny=hello+vilag; // ez is hasonló mint az unboxing,
// összefűzi a két String objektum tartalmát
Alapvetően a primitív típusok a jó választás, kivéve akkor, ha az adat értéke lehet nem-definiált. Ez mit is jelent? Egy int értéke mindenképpen egy szám, nem lehet benne "semmi", hanem egy számnak kell lennie benne. Ha mondjuk ez azt tárolja, hogy hány fok van, akkor az értéke lehet 22.
No de mi van akkor, ha San Francisco időjárásáról van szó, és épp nem tudjuk, hogy hány fok van? Nem tehetjük bele, hogy 0, mert nem nulla fok van. A primitív típussal nem tudjuk ezt a "nem tudjuk" értéket kifejezni.
A null egy speciális érték, ami azt jelenti, hogy "nem megadott, nem ismert, nem tudjuk, nincs". Például:
Integer homersekletIdehaza=new Integer(22); // 22 fok van, létrehoztunk egy Integer objektumot
Integer homersekletIdehaza=22; // 22 fok van, autoboxing
Integer homersekletSanFrancisco=null; // nem tudjuk, mennyi fok van
No ennyi háttér okosság után vissza a kocsmába! Itt tartottunk:
public class Kocsma {
public static void main(String[] args) {
Ember jack=new Ember();
Ember jane=new Ember();
Innivalo sor=new Innivalo();
jack.igyal(sor);
}
}
Mi a lényeg? Nekem ez tetszik:
jack.igyal(sor);
emlékszel, hogy az előző oldalon még ilyen ronda volt:
jack+=5*0.04;
A jack.igyal(sor) az egészen olvasható. Bárki kitalálja, mire való.
No lássuk, mi lesz, ha ellenőrizni kell, mennyit ivott Jack. Ezt vajon ki csinálja?
Szóval elő az Ember osztállyal, és ott ahol ledöntünk egy italt, rögtön nézzük is meg, hogy megártott-e!
public class Ember {
double fogyasztottAlkohol=0;
double alkoholTures=1;
void igyal(Innivalo innivalo) {
fogyasztottAlkohol+=innivalo.felszolgaltMeret*innivalo.alkoholTartalomSzazalek/100;
if (fogyasztottAlkohol>alkoholTures) {
System.out.println("Jajj, ez sok volt!");
System.exit(0);
}
}
}
Tettem bele egy if-et, és ha a fogyasztás után már túl sok az alkoholunk, akkor kiírjuk a képernyőre. A System.exit(0) kilép a programból - egyelőre így csináljuk meg, de valahogyan meg kell állni, hiszen többet már nem ihatunk.
Na lássuk valóságban! Nekem úgy tűnik, hogy Jack a 6. sör után dől ki:
public class Kocsma {
public static void main(String[] args) {
Ember jack=new Ember();
Ember jane=new Ember();
jack.igyal(new Innivalo());
jack.igyal(new Innivalo());
jack.igyal(new Innivalo());
jack.igyal(new Innivalo());
jack.igyal(new Innivalo());
jack.igyal(new Innivalo());
}
}
A valóságban egy sört csak egyszer lehet meginni, ezért úgy csináltam, hogy jack.igyal mindig egy új sör példányt fog inni, ezért a new Innivalo() ami új példányt csinál minden iváshoz.
Feladat: Játssz vele kicsit! Neked mennyi sört tud Jack meginni?