Hoofdstuk 1: Klassen en Objecten
Inleiding
Objectgeoriënteerd maakt het mogelijk om grootschalige projecten op te bouwen en te onderhouden voorzien van Grafische gebruikersinterfaces
- In de cursus "Computers en programmeren" heb je veel problemen kunnen oplossen via programmeertechnieken zoals keuzes (
if-else
,switch
), lussen (while
,do-while
,for
), methodes en arrays. Echter, enkel deze technieken zijn niet genoeg om grafische gebruikersinterfaces te gaan maken of om grote programma's en sofwareprojecten op te bouwen. - Veronderstel dat we een grafische gebruikersinterface willen ontwerpen, hoe zou je die opbouwen?
Definiëren van klassen voor objecten
- Objectgeoriënteerd programmeren (OOP) omvat het gebruik van objecten om programma's te maken. Een object stelt een entiteit voor die een realiteit kan gedefinieerd worden. Bijvoorbeeld, een student, een bureau, een cirkel, een knop of zelfs een lening kan je zien als objecten.
Een object wordt opgebouwd uit 3 elementen : een unieke identiteit, een toestand een een gedrag.
- De toestand van een object wordt voorgesteld door gegevensvelden of variabelen waarin waardes kunnen toegekend worden. De toestand wordt ook wel de eigenschappen of attributen genoemd. Bijvoorbeeld. En object cirkel heeft een veld
straal
omdat dit een eigenschap is die de cirkel definieert. Een rechthoek heeft als gegevensveldenhoogte
enbreedte
. - Het gedrag van een object wordt gedefinieerd door methodes die het object kan uitvoeren. Dit wordt ook wel acties genoemd. Als een methode uitgevoerd wordt, dan wordt er gevraagd aan het object om een actie uit te voeren. Bijvoorbeeld, een cirkel object kan methodes uitvoeren om de oppervlakte of de optrek te meten. We definieren dan methodes
berekenOppervlakte
ofberekenOmtrek
voor cirkel objecten. Een cirkle object kan de methodeberekenOppervlakte
uitvoeren, dat dan het resultaat van die berekening teruggeeft. Een cirkel object kan ook een methode hebben die eigenschappen van die cirkel kunnen veranderen. Bijvoorbeeld, de methodesetStraal(getal)
kan de straal veranderen naar een nieuwe waardegetal
.
- De toestand van een object wordt voorgesteld door gegevensvelden of variabelen waarin waardes kunnen toegekend worden. De toestand wordt ook wel de eigenschappen of attributen genoemd. Bijvoorbeeld. En object cirkel heeft een veld
Objecten van eenzelfde type worden gedefinieerd in een gemeenschappelijke klasse. Een klasse is een sjabloon, een bouwplan of een contract dat de gegevensvelden en methodes van objecten beschrijft.
- Een object is dan een instantie van die klasse. Er kunnen meerdere objecten gemaakt worden van een klasse. Bijvoorbeeld, kan je meerdere huizen bouwen met eenzelfde bouwplan.
Java gebruikt variabelen om gegevensvelden te definiëren en methodes om het gedrag te definieren. Daarenboven, heeft Java speciale methodes die de objecten maken, zogenaamde constructor. Een constructor zijn speciaal ontworpen voor objecten te initializeren, zoals de initializatie van gegevensvelden.
Een voorbeeld van een klasse wordt hieronder weergegeven:
- De voorgaande klasse is anders dan de vorige programma's die we in de vorige cursus gemaakt hebben. Het bevat geen
main
methode, en het kan daarom niet uitgevoerd worden. De klasse is enkel een definitie voor cirkelobjecten.
Voorbeeld: Definiëren van Klassen en maken van objecten
Klassen zijn definities voor objecten en objecten worden gemaakt vanuit een klasse
- Het onderstaand programma zal 3 cirkelobjecten maken met straal
1
,25
en125
en zal de straal en de omtrek tonen op het scherm. Daarna wordt de tweede cirkel veranderd en wordt opnieuw de straal getoond en de omtrek berekend.
- Het bovenstaand programma bevat twee klassen. De eerste klasse
TestCirkel
is de main klasse. Het doel van die klasse is om de tweede klasseCirkel
te testen. Wanneer we het programma zal starten, dan zal Java demain
-methode aanroepen. - Je kan twee klassen in één java-bestand plaatsen, maar slechts één klasse kan een
public class
zijn. Bovendien moet de naam van depublic class
dezelfde zijn als de naam van het java-bestand. Dus bovenstaand programma kan je in een java-bestand plaatsen met de naamTestCirkel.java
en niet inCirkel.java
. De compilatie van TestCirkel.java zal resulteren in twee bestandenTestCirkel.class
enCirkel.class
. - Het getuigt van een goede praktijk om het programma met de
main
-methode en de klasse (bv. Cirkel) te scheiden in twee verschillende betanden:TestCirkel.java
enCirkel.java
.
Maken van objecten door het gebruik van constructoren
Een constructor wordt aangeroepen wanneer een object moet gemaakt worden door middel van de
new
operator
- Constructoren zijn speciale methodes. Ze hebben 3 eigneschappen:
- Een constructor moet exact dezelfde naam hebben als de klasse zelf (rekening houdend met de hoofdletters)
- Een constructor heeft geen retourtype - zelfs niet
void
- Constructoren worden aangeroepen met de
new
operator wanneer een object moet gemaakt worden. Constructoren spelen dus een grote rol in het initializeren van objecten en de gegevensvelden van die objecten.
- De naam van de constructor is exact hetzelfde als de naam van de klasse. Zoals andere methodes kunnen constructoren overladen worden, dus kunnen we meerdere constructoren definiëren met verschillende signaturen. Op deze manier kunnen we objecten maken met verschillende beginwaarden voor de gegevensvelden.
- Constructoren worden gebruikt om objecten te maken. Om een object te maken vanuit een klasse, moeten we
new
operator gebruiken als volgt:
new KlasseNaam(argumenten);
- Bijvoorbeeld,
new Cirkel()
maakt een object van de klasseCirkel
door de eerste constructor in bovenstaande codevoorbeeld aan te roepen.new Cirkel(25)
gebruikt de tweede constructor. - Een klasse voorziet normaal gezien een constructor zonder argumenten (bv.
Cirkel()
). Een dergelijke constructor wordt ook wel de no-arg of no-argumentconstructor genoemd. - Een klasse kan gedefinieerd worden zonder constructoren. In dat geval wordt een no-argument constructor met een lege body impliciet aangemaakt. Deze constructor noemen we de default constructor en wordt enkel maar voorzien als en slechts als er geen andere constructor expliciet gedefinieerd is.
Objecten aanspreken via referentievariabelen
De gegegevensvelden en methodes van een object kunnen aangeroepen worden door de punt (.) operator via de referentievariabele
Referentievariabelen en referentie types
- Nieuwe objecten worden in het geheugen aangemaakt en kunnen we aanspreken via een referentievariabele. Die referentievariabele bevat een verwijzing naar het object. Dergelijke variabelen worden gedeclareerd als volgt:
KlasseNaam objectReferentieVariabele;
- Een klasse is in essentie een type die door de programmeur kan bepaald worden. Een klasse is een referentie type, dat betekent dat een variabele van die klasse type kan wijzen naar een object van die klasse. De volgende uitdrukking bepaalt een variabele
mijnCirkel
van het typeCirkel
.
Cirkel mijnCirkel;
- De variabele
mijnCirkel
kan verwijzen naar eenCirkel
object. De volgende uitdrukking maken we eenCirkel
object en kennen we de verwijzing naar dit object toe aanmijnCirkel
.
mijnCirkel = new Cirkel();
We kunnen ook één uitdrukking gebruiken om
- een referentievariabele te declareren,
- een object te maken door de constructor aan te roepen en
- een verwijzing naar het gemaakte object toe te kennen aan de referentievariabelen
In het algemeen wordt dit:
KlasseNaam objectReferentieVariabele = new KlasseNaam();
- Bijvoorbeeld met het de klasse
Cirkel
wordt dit:
Cirkel mijnCirkel = new Cirkel();
- Opmerking: Een referentievariabele van een object bevat eigenlijk een verwijzing naar het object. Strikt genomen is de referentievariabele en het object zelf totaal verschillend, meer meestal wordt dit verschil genegeerd. Hierdoor gaan we voor de eenvoud zeggen dat
mijnCirkel
een object is van de klasseCirkel
. Eerder dan steeds te vermelden datmijnCirkel
een referentie/verwijzing is naar het objectCirkel
, wat zeer omslachtig is. - Opmerking: Arrays worden beschouwd als objecten in Java. Arrays moeten dus gemaakt worden door middel van de
new
operator.
Gegevensvelden en methodes van een object aanspreken
In OOP, kunnen we gegevensvelden van objecten aanspreken (opvragen of veranderen) of methodes van objecten aanroepen. Wanneer een object gemaakt is, kunnen we de gegevensvelden en methodes aanspreken met de punt operator (.). In het Engels ook wel object member access operator genoemd.
objectReferentieVariabele.gegevensVeld
verwijst naar een gegevensveld in het objectobjectReferentieVariabele.methode(argumenten)
roept de methode aan die in de klasse van het object beschreven staat
Bijvoorbeeld,
mijnCirkel.straal
verwijst naar de straal van het objectmijnCirkel
enmijnCirkel.berekenOppervlakte
roept de methodeberekenOppervlakte
aan op het objectmijnCirkel
. Methodes worden aangeroepen als bewerkingen op het object.Opgelet: Herinner je dat je methodes van de
Math
klasse kan aanroepen doorMath.methodeNaam(argumenten)
(bv.Math.pow(3,2.5)
). Kan je de methodeberekenOppervlakte()
enberekenOmtrek()
ook op die manier aanroepen (dus alsCirkel.berekenOppervlakte()
ofCirkel.berekenOmtrek()
)? Het antwoord is nee. Alle methodes in de klasseMath
zijn zogenaamde statische methodes. Dit zijn methodes die je kunt aanroepen zonder dat je een object moet maken. Voor een machtsverheffing (Math.pow
) of het genereren van een willekeurig getal (Math.random()
), heb je geen object nodig. Maar voor het berekenen van een oppervlakte of omtrek hebben we de straal nodig die gedefinieerd is in de gegevensvelden van het objectmijnCirkel
. Dus voor instanties moeten we de naamvan het object gebruiken om die methodes te kunnen aanroepen. Dus,mijnCirkel.berekenOppervlakte()
enmijnCirkel.berekenOmtrek()
.
Gegevensvelden die verwijzingen bevatten en de waarde null
- De gegevensvelden van objecten kunnen ook andere objecten zijn. De types van deze gegevensvelden worden dan referentietypes genoemd. Bijvoorbeeld, een klasse
Student
bevat een gegevensveldnaam
dat een object is van de klasseString
.String
is een vooraf gedefinieerd klasse in Java.
- Als een gegevensveld een object bevat van een klasse (en dus een referentietype bevat), dan heeft het gegevensveld de waarde
null
bij de initializatie.null
is een literal voor een verwijzing naar een object als die verwijzing nog niet toegekend is. - Bij het maken van objecten kent Java initiële waarden toe voor de gegevensvelden:
null
voor een object van een andere klasse,0
voor een type dat een getal bevat (int
,double
),false
voorboolean
en\u0000
voor het typechar
.
Referentietypes versus Primitieve types
- Voor elke variabele in een programma wordt een geheugenlocatie aangemaakt. Wanneer je een variabele declareert, dan zeg je aan de compiler welk type de variabele heeft en dus hoeveel geheugen er moet vrij gehouden worden om waardes op die locatie te bewaren. Een variabele dat gedeclareerd is als een primitief type, dan bevat deze ook een waarde van het primitieve type.

- Wanneer je één variabele toekent aan een andere variabele, dan bevat die andere variabele dezelfde waarde. Als je de waarde van een referentievariable aan een andere referentievariabele dan wordt de referentie toegekend aan die andere variabele.

- Merk op: als we in bovenstaande figuur
c1 = c2
, dan wijstc1
naar het object waarnaarc2
verwijst. Het object naar waartoec1
oorspronkelijke verwees is niet meer bruikbaar en het is daarom aanzien als afval of garbage. Garbage neemt plaats in het geheugen die we niet meer kunnen gebruiken. Java voorziet daarom een mechanisme om geheugen dat niet meer gebruikt wordt terug vrij te geven. Dit is gekend als garbage collection.
Statische variabelen, Constanten en Methodes
een statische variabele wordt gedeeld door alle objecten van een klasse. Een statische methode heeft geen toegang tot de gegevensvelden of methodes van een klasse.
- Beschouw de klasse
Cirkel
. Een object van die klasse heeft een gegevensveldstraal
en is ook gekend als een intantievariabele. Een instantievariabele is gebonden aan een specifieke instantie van die klasse en de inhoud van de instantievariabele kan niet gedeeld worden met ander objecten. Bijvoorbeeld: beschouw het volgend stuk code
- De
straal
incirkel1
is volledig onafhankelijk van destraal
incirkel2
en wordt opgeslaan op een verschillende geheugenlocatie. Wanneer de waarde vanstraal
in het objectcirkel1
verandert, dan wordt de waarde vanstraal
in het objectcirkel2
niet meeverandert. Indien je informatie wil delen over alle objecten in een bepaalde kasse, dan kan je statische variabelen gebruiken (ook wel klassevariabelen genoemd). Statische variabelen slaan waardes op voor variabelen in een gemeenschappelijk stuk geheugen. Daarom als je de waarde van een statische variabele verandert in een object van een klasse (bv.
cirkel1
) dan verandert die waarde ook in andere objecten (bv.cirkel2
). Statische methodes zijn methodes die kunnen aangeroepen worden zonder dat je een object van de klasse moet aanmaken.Stel dat we de klasse Cirkel willen aanpassen zodat we het aantal gemaakte objecten willen bijhouden. We kunnen dit doen met een statische variabele
aantalObjecten
. Wanneer een eerste object gemaakt wordt dan wordtaantalObjecten
gelijk aan 1. Bij een volgend object, wordt dit 2.
Toegangsniveaus van gegevensvariabelen en methodes
Toegangsniveaus worden gebruikt om de toegang van een klasse, zijn gegevensvariabelen en zijn methodes te beperken
- Je kan het toegangsniveau
public
gebruiken om aan te duiden dat een gegevensveld of methode kan worden opgevraagd of uitgevoerd door een andere klasse. Als er geen toegangsniveau wordt meegegeven dan zijn automatisch de gegevensvariabelen en methodespublic
. - Naast
public
, voorziet Java ook nogprivate
enprotected
.protected
wordt gebruikt bij overerving en zal besproken worden in Hoofdstuk 3. - Het toegangsniveau
private
maakt methodes en gegevensvariabelen enkel toegankelijk binnen de eigen klasse. - Onderstaand voorbeeld illustreert het gebruik van
private
,public
en default toegangsniveau's.
Bestand: C1.java
Bestand: C2.java
- Een object heeft toegang tot private gegevensvariabelen en methodes als ze gedefinieerd zijn in dezelfde klasse. Bv:
Bestand: C.java
Encapsulatie van gegevensvelden
Het is goed om gegevensvariabelen
private
te declareren, zodat de klasse gemakkelijk te onderhouden is
- In ons voorbeeld van de klasse
Cirkel
konden we toegang krijgen tot de veldenstraal
enaantalObjecten
op een heel directe manier viac1.straal
enc1.aantalObjecten
. Dit is geen goede manier van werken, omdat:- gegevens kunnen aangepast worden, zodat ze verkeerde informatie kunnen bevatten.
- de klasse heel moeilijk te onderhouden wordt en kwetsbaar wordt voor fouten. Veronderstel dat je de klasse
Cirkel
wil aanpassen zodat je wil verzekeren dat het gegevensveldstraal
een niet-negatief getal bevat. Dan moet je niet alleen de klasseCirkel
aanpassen maar ook de programma's die gebruik maken van de klasseCirkel
en die de straal direct aanpassen (bv.c1.straal = -5
).
- Om dergelijke fouten te voorkomen, moeten we de gegevensvelden allemaal voorzien van
private
. Dit staat in Object Georiënteerd programmeren bekend als encapsulatie. - Een
private
gegevensvariabele kan niet opgevraagd worden door een object buiten de klasse. Toch moet het mogelijk zijn om waarden van die gegevensvariabelen te gebruiken in andere klasses. Om toegang te verkrijgen tot de waarde van een private gegevensveld, maken we gebruik van een getter methode. Een getter methode is ook wel gekend als een accessor wordt in het algemeen als volgt gedefinieerd:
public retourtype getGegevensVariabele()
- Om de waarde van een
private
gegevensvariabele te veranderen, gebruiken we een setter methode. Een setter methode is ook welk gekend als een mutator en wordt als volgt gedefinieerd:
public void setGegevensVariabele(dataType nieuweWaarde)
- Bijvoorbeeld voor de gegegevensvariabele
straal
van de klasseCirkel
wordt dit
Cirkel.java
TestCirkel.java
Objecten als argumenten meegeven aan methodes
Een object meegeven als argument bij een methode is hetzelfde als het meegeven van de referentie van het objectReferentieVariabele
- Het is mogelijk om objecten mee te geven met methodes, maar men er rekening mee houden dat je in feite de referentie of verwijzing doorgeeft aan de methode. Bijvoorbeeld:
Arrays van objecten
Een array kan ook objecten bevatten als ook waarden van primitieve types
- Het is mogelijk om arrays van objecten te definiëren. Bv. het volgend stukje code maakt een array van 10 Cirkel objecten.
- Dit maakt enkel de array, bij elk element van de array moeten nog de objecten van Cirkel gemaakt worden:
- De array bevat in feite referenties naar de objecten. Dus arrays van objecten zijn in feite 2 types van referenties.
cirkelArray
is een referentie naar een array object en een element vancirkelArray
(bv.cirkelArray[0]
) is een referentie naar eenCirkel
object.
De this
referentie
Het sleutelwoord
this
verwijst naar het object zelf. Het kan gebruikt worden in een constructor om een andere constructor aan te roepen.
- Het sleutelwoord
this
is de naam van een referentie dat wijst naar het object waarin het sleutelwoord gebruikt wordt. Het sleutelwoord kan ook gebruikt woorden om te verwijzen naar gegevensvariabelen en methodes van het object.
is equivalent met
- Het is een goede manier om gegevenvariabelen als parameternaam te gebruiken in een setter methode of een constructor. Hierdoor wordt de code leesbaarder en vermijden we het onnodig gebruik veel namen. Bv. de
setStraal
methode kan als volgt geïmplementeerd worden:
- In de toekenning
this.straal = straal
wordt viathis
in het linkerlid gerefereerd naar de gegevensvariabele, terwijl de straal in het rechterlid verwijst naar het argument van de methodesetStraal
. - Een variabele die
static
gedeclareerd is kunnen we niet refereren viathis
en moeten we de naam van klasse gebruiken: bv.KlasseNaam.staticVariabele
.
- We kunnen this ook gebruiken om een constructor aan te roepen. Het sleutelwoord
this
wordt gebruikt om een andere constructor aan te roepen binnen dezelfde klasse. De onderstaande code, toont een constructer zonder argumenten (no-argument constructor) om een cirkle met maken met straal gelijk aan1.0
.
- Let op! Java vereist dat een constructor aanroep via
this
voor alle andere uitdrukkingen staat binnen de constructor.