Az elterjedt nyelvekkel (C, C++, Delphi, stb.) ellentétben a Java már csak objektum alapokon működik: a legkisebb fordítási egység az osztály lett. Mivel az objektum orientált programozás (OOP) témaköre nem túl könnyű - sőt mondhatjuk igen összetett: nézzük meg, mit is jelent objektum orientált módszertan szerint programot írni.

 

2.1. Elmélet

Az objektum alapú programozás közelebb hozta egymáshoz a programnyelv és a való élet fogalmait, így OOP alapon egyszerűbb és átláthatóbb programok születhetnek, amelyek karbantartása is egyszerűbb lehet, ha a programban használt fogalmak megközelítőleg fedik a valóságot. A jól megírt OOP szemléletű program a valóságot próbálja modellezni, ehhez több fogalmat is tisztázni kell.

Az egyik legfontosabb fogalom maga az objektum, egy-egy objektum a való élet egy-egy részét modellezi a programunkban: egy objektum lehet például egy üveg, egy kis sör vagy egy pohár. Minden objektumnak van állapota, vannak lehetséges műveletei és képes más objektumokkal együttműködni. Ez azt jelenti, hogy egy üveg sört ki tudunk nyitni, ezzel a "zárt" és "teli" állapotát a "nyitás" művelettel "nyitott" és "teli" állapotba hozni. Ha fogunk egy üres poharat, amelybe beletöltjük a nyitott üveg tartalmát, akkor a "kitöltés" művelet eredménye egy "teli" pohár illetve egy "üres" és "nyitott" sörösüveg. Természetesen a sörrel teli poharat az "ivás" művelettel üzemszerű módon tudjuk használni... :)

Ha kerítünk egy újabb üveg sört, akkor az már egy új objektum, de észre kell vennünk a két üveg sör közötti hasonlóságot. Ha szólunk a csinos pincércsajnak, hogy még egy üveg sört szeretnénk, akkor szinte biztosak lehetünk benne, hogy nem egy üveg bambit fog hozni. Ehhez mindkettőnknek tisztában kell lennünk az üveg sör fogalom jelentésével: a való életben a feltűnő hasonlóságok mentén - jobban mondva a közös jellemzők alapján - osztályokba tudjuk sorolni az objektumokat, egy-egy szavunk a dolgok egy-egy osztályát írja le. Az osztály határozza meg, hogy egy objektum milyen állapotokat vehet fel, milyen műveleteket lehet végezni vele, és milyen kölcsönhatások képzelhetők el más objektumokkal kapcsolatban. Az osztály neve egyedi kell legyen abban a környezetben, ahol hivatkozunk rá, ám fel kell készülnünk arra, hogy egy adott név másik környezetben mást jelent.

Mint mindent, a Java nyelv osztályait is példákon át ismerhetjük meg legjobban, ezért vegyük példának egy kocsma absztakcióját, hiszen oda mindenki naponta időnként eljár – tehát a továbbiakban egy kocsmát fogunk meglátogatni absztrahálni.

 

Nézzünk körül egy kocsmában, mit is látunk: alapvetően vannak dolgok. Ez egy igen magas absztrakciós szint, mivel teljesen elvonatkoztattunk attól, hogy a dolgok sörök, borok, zsíroskenyerek, üvegek, korsók, illetve poharak is lehetnek. Egy ilyen absztakció során az három dolgot kell megfigyelnünk a dolog osztályba sorolt dolgokról:

A számunkra lényeges azért van kiemelve, mivel ez az absztrakció lényege: csak azon tulajdonságokkal kell foglalkozunk, amelyek segítenek egymástól megkülönböztetni az osztályba sorolt különféle dolgokat, a többit figyelmen kívül kell hagynunk. Nézzünk újfent körül a kocsmában, és szedjük össze a dolgok közös-de-megkülönböztető jellemzőit. Az osztályt úgy célszerű elnevezznünk, hogy a neve a fogalmakat vagy a tárgyakat egy-két szóban jellemezze, és lehetőleg ne használjunk többes számot. Mivel a leírásnak minden egyes dologra illenie kell a kocsmában, ezért az osztály neve az lesz, hogy Dolog.

2.1.1. Az osztály

Soroljuk fel a kocsmában található összes kézzelfogható dolog lényeges és közös jellemzőjét. Mi az a tulajdonság, ami egyaránt jellemzi a sörösrekeszt, a sört, a zsíroskenyeret, a sörcsapot, a pultot és a kocsmárost? Hát... hm... ööö... izé.Az absztrakció nem is olyan egyszerű, nézzük pár ötletet:

Maradjunk annyiban, hogy a dolgoknak egyelőre csak neve van, ez kezdetnek egyszerű és jó. Az osztályokat legjobban és legtömörebben UML osztálydiagrammon lehet leírni, amint az a jobb oldali ábrán is egy ilyen látszik. Az UML ábra tetején láthatjuk az osztály nevét, amelyet egyszerűen úgy hívjuk, hogy Dolog. Az Attributes jelzi a tulajdonságokat, amelyek jellemzik az osztályt, jelen esetben egyetlen egy String típusú és név megnevezésű tulajdonságunk van csak - ahogy ezt már szövegesen le is írtuk. Az osztállyal tudunk műveleteket végezni, jelen esetben semmi különös műveletünk nincs, van egy konstruktor, illetve egy getter (lekérdező) és egy setter (beállító) metódus a névhez. Az attribútumok és a műveletek előtt látható private és public szó jelzi, hogy az adott jellemző vagy művelet elérhető-e az osztályon kívülről - értelemszerűen a public jelenti a publikus elérhetőséget, a private pedig a privát használatot - de ezekről később ejtünk több szót.

A Dolog osztály célja, hogy alapot adjon további osztályok definiálásához, ugyanis az objektum orientált programozás (és gondolkodás!) lényege az, hogy egyes osztályokból leszármaztatunk újabb osztályokat, amely esetben a leszármaztatott osztály specializáltabb lesz, mint az az osztály, amelyből leszármaztattuk (figyelem: nem szülő és gyermek osztály a nevük, célszerűbb az ős és a leszármazott szó használata). Az UML ábrán az osztály neve dőlt betűvel van szedve, amely azt jelenti, hogy ez az osztály absztrakt osztály lesz, így ezt nem lehet példányosítani, csak azokat az osztályokat, amelyeket ebből származtatunk le. A leszármaztatásról egy későbbi fejezetben lesz szó, egyelőre tegyük félre ezt a fogalmat.

2.1.1.1. A Java osztályok

Tekinsük meg az UML ábra osztályleírását Java nyelven is:

package hu.javakocsma;  
  
public abstract class Dolog  
{  
}

Haladjunk végig a fenti osztályon:

Az osztály törzse kapcsos zárójelek közé kerül, ha az osztály üres, akkor is ki kell tennünk a nyitó és záró kapcsos zárójelet.

2.1.1.2. Tulajdonságok

Haladjunk tovább, én egészítsük ki ezt az UML ábrán látott tulajdonságokkal:

package hu.javakocsma;  
  
public abstract class Dolog  
{  
  private String név;  
}

A tulajdonságokat általában az UML leírás szerint soroljuk fel, egy tulajdonságot egy sorba - az UML tulajdonságot a Java programban már változónak jobban mondva példányváltozónak hívjuk, és az osztályba foglalását deklarációnak:

2.1.1.3. Műveletek

Lássuk az UML ábra utolsó harmadát, a műveleteket is:

package hu.javakocsma;  
  
public abstract class Dolog  
{  
  
  private String név;  
  
  public Dolog()  
  {  
  }  
  
  public String getNév()  
  {  
    return this.név;  
  }  
  
  public void setNév(String név)  
  {  
    this.név = név;  
  }  
}

Mint látható, az osztályban már az UML ábra műveletei is fel vannak sorolva, Java nyelvben konstruktor és metódusnéven hivatkozunk a továbbiakban ezekre a műveletekre.

Konstruktorok

Emeljük ki a konstruktort, hogy megvizsgálhassuk közelebbről is:

public Dolog()  
{  
}

A konstruktor legfőbb ismérve, hogy a neve azonos az osztály nevével és a név után szorosan a metódusokra is jellemző kerek zárójelet találjuk meg, a zárójelek között pedig paramétereket - a jelenlegi példában nincs ilyen paraméter - a paraméter nélküli konstruktort alapértelmezett konstruktornaknevezzük. A konstruktor neve előtt lehetnek módosítók:

Hasonlóan a osztályhoz - a konstruktornak is van törzse, amelyet kapcsos zárójelek zárnak közre. Ha a törzs üres, akkor is ki kell tennünk a nyitó és a záró kapcsos zárójelet.

A konstruktor feladata, hogy elkészítse az osztály egy új példányát. Egy osztálynak több példánya is lehet, a példányokat a példányváltozók különböztetik meg egymástól. Ha két példánynak azonos értékek vannak a példányváltozóikban - például két azonos nevű dolog, akkor a két példány ugyan egyenlő egymással, de mégis két külön példánynak számítanak.

Ha egy osztályban nincs konstruktor, akkor azt úgy kell vennünk, mintha a fentebb említett minimális konstruktor lenne benne - ez azt jelenti, hogy a Dolog osztályból a jelenlegi konstruktort el is hagyhatnánk, nem történne érdemi változás a program működésében. Természetesen egy osztályban lehet több konstruktor is - de erre visszatérünk a későbbiekben.

Metódusok

Egy metódus sok dologban hasonlít a konstruktorhoz, azonban a metódus neve előtt szerepeltetni kell egy típust, amely típusú értéket a metódus visszaad. Egy metódusra úgy is gondolhatunk, mint egy matematikai függvényre, például az y = sin(x) esetén a színusz függvény az x érték színuszát adja értékül az y változónak. Nézzük meg egy átlagos metódust közelebbről:

public String getNév()  
{  
  return this.név;  
}

A metódus feje távolról hasonlít a példányváltozók deklarálásához, attól "csak"a kerek zárójelek és a metódus törzsét jelentő kapcsos zárójelek különböztetik meg:

A metódus törzsét a kapcsos zárójelek között találjuk meg - a példában ez üres, ide kerülnek a Java nyelvű utasítások, amelyek lépésről-lépésre elvégzik a kért műveletet:

return this.név;

Jelen esetben a getNév (publikus) metódus visszaadja a privát elérésű névpéldányváltozó által hordozott értéket. Nézzük meg a következő metódust is:

public void setNév(String név)  
{  
  this.név = név;  
}

Ennek a metódusnak már van egy paramétere, amely String típusú és neve egyszerűen név. A metódus törzse egy értékadás, ahol a paraméterben kapott értéket adjuk át a példányváltozónak.

Bean pattern

A két metódus közül az első a getter, a második a setter; a kettő publikus metódus és a privát példányváltozó együtt valósítják meg a bean pattern nevű fogalmat, amely a Java egyik alapfogalma. Java nyelven bizonyos osztályokat úgy nevezünk, hogy bean (mint kávébab). Egy ilyen bean olyan osztály, amelynek van egy alapértelmezett konstruktora és példányai állapotát csak olyan példányváltozók határozzák meg, amelyekhez egy getter és egy setter metódus tartozik az alábbi módon:

private String név;  

public String getNév()  
{  
  return this.név;  
}  
  
public void setNév(String név)  
{  
  this.név = név;  
}

Nézzük részletesen:

Vonjuk le a következtetést: a Dolog osztályunk egy Java bean.

2.2. Gyakorlat

Hozzunk létre (a már megismert módon) egy új projektet Kocsma néven, a művelet végén a projekt nézetben az alábbit kell látnunk:

Ügyeljünk arra, hogy a projekt neve nagy betűvel kezdődjön, és ne tartalmazzon szóközt. Az elméleti részben hivatkozott hu.javakocsma csomagot kell először létrehoznunk, ehhez jobb egérgombbal kattintani kell a Source Packages feliraton, majd a menüből a bal egérgomb segítségével ki kell választanunk a New, illetve a felbukkanó újabb menüből a Java Package... menüpontot:

A dialógus ablakban a csomag nevét kell csak megadnunk, majd a Finish gombon kell kattintsunk:

Ezek után az új csomagnak meg kell jelennie a projekt nézetben:

Az újonnan létrehozott csomagon jobb egérgombbal kattintva létre kell hoznunk egy új osztályt:

Nevezzük el az új osztályt Dolog néven, és ellenőrizzük, hogy a hu.javakocsma csomagban található:

A projekt nézetben ezek után látnunk kell az új osztályt az új csomag alatt:

A NetBeans szerkesztő panelben pedig megjelenik egy új fülön a Dologosztály tartalma, ezt írjuk át arra, amit az elméleti részben láttunk:

Ezek után nincs más hátra, minthogy az F11gomb megnyomásával a projektet futtatható állapotba hozzuk:

init:  

deps-jar:  
compile:  
Building jar: /home/work/JavaSuli/Kocsma/dist/Kocsma.jar  
Not copying the libraries.  
To run this application from the command line without Ant, try:  
java -jar "/home/work/JavaSuli/Kocsma/dist/Kocsma.jar"  
jar:  
BUILD SUCCESSFUL (total time: 0 seconds)

Nos, létrehoztuk az első saját osztályt NetBeans alatt, veregessük meg a vállunkat - jó munkát végeztünk... (smile)