Java2 1.5: objectgeoriënteerd programmeren

  1. Inleiding
  2. Klassen en variabelen
  3. Methoden
  4. Constructors maken en overloaden, het sleutelwoord this
  5. Recursie
  6. Bereik van variabelen
  7. Garbage-collection
  8. Arrays en ArrayLists
  9. Oefeningen

Inleiding in het objectgeoriënteerd programmmeren

De programmeertaal Java kan je niet gebruiken als je de principes van het objectgeriënteerd programmeren niet onder de knie hebt.

Het is dan ook één van de allereerste doelstellingen in deze cursus om je daarmee vertrouwd te maken.

Objecten, klassen en methoden zijn al ter sprake gekomen in de vorige cursusonderdelen, misschien kwamen bepaalde begrippen nogal abstract over. Dit hoofdstuk heeft als bedoeling je volledig vertrouwd te maken met de principes van het objectgeoriënteerd programmeren.

Objectgeoriënteerd programmeren is in feite een techniek om als programmeur het verdeel en heers principe toe te passen. Het idee erachter is dat we kleine autonome stukken programmacode maken die we dan vanuit ander programmaonderdelen kunnen gebruiken. We moeten ons naderhand geen zorgen meer maken om de kleine programmaonderdelen.

Sleutelconcepten

Concept Beschrijving
Klasse Vormt de blauwdruk voor een object. Een klasse is een element waarvan je objecten afleidt, in de klasse staat aangegeven hoe het object er zal 'uitzien', wat je met het object kan doen. Klassen zijn de bouwplannen van Java.
Object Een object is een instantie van een klasse. Dit betekent dat een object aangemaakt werd aan de hand van de richtlijnen van een klasse.
Gegevensleden De variabelen die onderdeel zijn van een klasse. Je gebruikt ze om gegevens op te slaan die je voor het object of de klasse gebruikt.
Methode Een functionaliteit die in een klasse is ingebouwd.
Overerving Klassen kunnen de functionaliteit van een andere klasse gebruiken en overnemen. Dit principe wordt overerving genoemd.

Het is heel belangrijk in te zien dat zonder het gebruik van klassen programmeren in Java onmogelijk is. Wanneer je een toepassing maakt begin je eenvoudigweg met het maken van een klasse. Wanneer deze toepassing een applet is, dan ga je meteen de klasse java.applet.Applet gebruiken in je project...

Het is dan ook ten zeerste aan te raden niet te 'licht' om te springen met de voorbeelden in dit hoofdstuk van de cursus. De inhoud van de voorbeelden zal niet altijd 'spectaculair' zijn, maar er komen principes en technieken aan bod die voor het maken van nuttige toepassingen onontbeerlijk zijn.

Klassen en variabelen

Klassen declareren

Er zijn twee onderdelen bij de opbouw van een klasse: de klassendeclaratie en de klassendefinitie. De declaratie vertelt Java wat het dient te weten over de nieuwe klasse:

[toegang] class klassenaam [extends...] [implements...]
{
	//klassendefinitie komt hier
}
De feitelijke implementatie van de klasse wordt de klassendefinitie genoemd en vormt dus zoals uit het voorbeeld hierboven kan worden afgeleid het centrale deel van de klassendeclaratie.

De klassendefinitie zullen we nu stap voor stap leren kennen.

Klassevariabelen

Klassevariabelen worden ook wel eens eigenschappen of properties van klassen (klassevariabelen) of objecten (instantievariabelen) genoemd.

Instantievariabelen maken


public class Meubel {
    
    public String meubeltekst = "Ik ben een meubelstuk";
    
    public Meubel() {
    }
    
}

Hier maken we een klasse aan met de naam Meubel.

De klasse Meubel bevat een String-instantievariabele meubeltekst met de waarde "Ik ben en meubelstuk"

Deze klasse kan nu een blauwdruk vormen voor objecten in een andere klasse:

public class Winkel {
    
    public Winkel() {
    }
    
    public static void main(String[] args) {
        
        Meubel kast = new Meubel();
        
        System.out.println(kast.meubeltekst);
    
    }
    
}

In de klasse Winkel kunnen we nu objecten aanmaken van het type Meubel. Dit doen we op dezelfde manier als we vroeger met bvb. arrays en Strings hebben gewerkt.

We noemen meubeltekst een instantie-variabele daar we voor elk object van het type Meubel dat we straks aanmaken de waarde voor deze variabele apart kunnen instellen. M.a.w. elke instantie van de klasse Meubel zal over zijn eigen variabele meubeltekst beschikken.

public class Winkel {
    
    public Winkel() {
    }
    
    public static void main(String[] args) {
        
        Meubel kast = new Meubel();
        
        Meubel stoel = new Meubel();
        stoel.meubeltekst = "Ik ben een stoel !";
        
        System.out.println(kast.meubeltekst);
        System.out.println(stoel.meubeltekst);
        System.out.println(kast.meubeltekst);
    }
}
Maak voor het uitvoeren van deze voorbeelde gebruik van een goede editor, of gebruik kladblok voor het ingeven van de code. Sla je bestanden op onder de naam: naamklasse.java.

Compileren doe je vanaf de prompt met: javac naamklasse.java

Uitvoeren van consoleapplicaties doe je met de opdracht java naamklasse

Zorg ervoor dat de bestanden in eenzelfde map terechtkomen (of pas de CLASSPATH-variabele aan).

Zorg ervoor dat je eerst de benodigde klassen compileert voor je het hoofdprogramma compileert, dus eerst Meubel.java en dan Winkel.java compileren. Het enige programma dat je kan uitvoeren is dan Winkel. De toepassing Winkel gebruikt dan de klasse Meubel (achter de schermen).

Toegang tot variabelen instellen

Je merkt dat de instanties van de klasse Meubel (kast en stoel) de variabele meubeltekst binnen de klasse Meubel kunnen aanpassen.

De variabele meubeltekst is gedefiniëerd als public, daardoor is deze variabele toegankelijk van overal binnen het programma.

Mogelijke waarden voor de toegang tot een variabele zijn:

Toegang Beschrijving
public toegankelijk van overal in het programma
private enkel toegankelijk vanuit de klasse zelf
protected toegankelijk binnen de klasse, binnen klassen van hetzelfde pakket en voor klassen afgeleid van die klasse
Verander je dus de toegang tot meubeltekst in private, dan krijg je en foutmelding te zien bij het uitvoeren van Winkel. De instantievariabele meubeltekst is nu niet meer toegankelijk van buiten de klasse Meubel, en dus bijgevolg kunnen we vanuit de klasse Winkel deze variabele niet meer benaderen.

Klassevariabelen maken

In de toepassing Winkel hebben we een variabele meubeltekst gedefiniëerd. Deze variabele is een instantievariabele, elke instantie (object) dat afgeleid is van de klasse Winkel beschikt over zijn eigen variabele meubeltekst.

Wanneer je in een klasse waarden wenst vast te leggen die voor elke instantie hetzelfde zijn, maak je gebruik van klassevariabelen: deze variabelen zijn voor alle instanties van de klasse gelijk.

Klassevariabelen declareer je met het sleutelwoord static

Voorbeeld:

Toon volledige code... Toon nieuwe code...

public class Meubel {
    
    public static String meubeltekst = "Ik ben een meubelstuk";
    
    public Meubel() {
    }
    
}
Wanneer je Winkel.class uitvoert zal je meken dat meubeltekst nu is gewijzigd voor alle Meubel-objecten.

Klassevariabelen instellen

Wanneer je een of andere berekening wenst uit te voeren om statische variabelen te initialiseren, dan kan dat in een codeblok voorzien van het woord static.
public class Meubel {
    
    public static String meubeltekst = "Ik ben een meubelstuk";
    private static String slogan = ", de beste kwaliteit van het land";
    
    static {
        meubeltekst = meubeltekst.concat(slogan);
    }
	
	
    public Meubel() {
    }
    
}



public class Winkel {
    
    public Winkel() {
    }
    
    public static void main(String[] args) {
        
        Meubel kast = new Meubel();
        
        Meubel stoel = new Meubel();
        
        System.out.println(kast.meubeltekst);
        System.out.println(stoel.meubeltekst);
        
        stoel.meubeltekst = "Ik ben een stoel !";
        
        System.out.println(kast.meubeltekst);
        System.out.println(stoel.meubeltekst);

        
    
    }
    
}

Methoden

Methodes aanmaken, toegankelijkheid van methoden

Een methode is een codeblok waaraan de controle kan worden doorgegeven, de cod binnen dit blok wordt nu uitgevoerd.

In feite stellen methoden je in staat iets te doen met je klassen en objecten.

We hebben in voorgaande voorbeelden steeds gebruik gemaakt van een methode : System.out.println(). Deze methode zorgt er bij een console-applicatie voor dat tekst op het scherm wordt getoond.

Nu gaan we zelf methodes aanmaken binnen onze eigen klassen:

public class Meubel {
    
    private static String meubeltekst = "Ik ben een meubelstuk";
    
    public Meubel() {
    }
    
    public void toonTekst(){
        System.out.println(meubeltekst);
    }
}

public class Winkel {
    
    public Winkel() {
    }
    
    public static void main(String[] args) {
        
        Meubel kast = new Meubel();
        Meubel stoel = new Meubel();
        
        kast.toonTekst();
        stoel.toonTekst();
        
    }
}

De klassevariabele (static) meubeltekst werd als private gedeclareerd, we hebben dus geen toegang meer tot deze variabele vanuit code buiten de klasse Meubel.

In de klasse Meubel werd een methode toegevoegd met de naam toonTekst. Deze methode werd gedeclareerd als public, dit betekent dat de methode toonTekst wel toegankelijk is vanuit een andere klasse. Vanuit de klasse Winkel kunnen we deze methode toepassen op onze Meubel-objecten kast en stoel.

Toegang tot methodes:

Toegang Beschrijving
public Toegankelijk vanuit elke plaats in het programma
private Enkel toegankelijk vanuit de klasse waarin de methode is gedeclareerd
protected Toegankelijk voor de huidige klasse, voor andere klassen in hetzelfde pakket en klassen die afgeleid zijn van de huidige klasse.

Het gebruik van methoden schermt de variabelen van de klasse Meubel af. We zijn nu verplicht om de methode toonTekst te gebruiken om meubeltekst op het scherm te brengen. Deze werkwijze heeft als grote voordeel dat je nu binnen je methodes kan werken met controles. Deze techniek wordt wel eens data-encapsulation genoemd.

Parameters aan methoden doorgeven

Doordat de variabele meubeltekst private is gedeclareerd, kunnen we de inhoud ervan niet meer rechtstreeks wijzigen buiten de klasse Meubel. Om toch toegang te hebben tot deze private variabele vanuit de klasse Winkel maken we in de klasse Meubel een publieke methode zetTekst aan.

Deze methode ontvangt een parameter, het is de bedoeling dat we bij het uitvoeren van de methode de meubeltekst kunnnen instellen op een zelf gekozen zin.

Toon volledige code... Toon nieuwe code...

public class Meubel {
    
    ...
    
    public void zetTekst(String nieuwemeubeltekst){
        meubeltekst = nieuwemeubeltekst;
    }
}


public class Winkel {
    
    ...
        
        kast.zetTekst("Onze meubels zijn niet te overtreffen!");
    ...
        
    }
}
We zorgen er nu ook voor dat voor elke instantie van de klasse Meubel een prijs kan worden bewaard. De prijs slaan we op in de private objectvariabele prijs, het type van deze variabele is double. De publieke methoden toonPrijs en zetPrijs kunnen we gebruiken om de prijs van een meubel te tonen en in te stellen. De methode zetPrijs heeft een argument van het type double: de in te stellen prijs voor het meubel.

Toon volledige code... Toon nieuwe code...

public class Meubel {
    
    ...
    
    public void zetTekst(String nieuwemeubeltekst){
        meubeltekst = nieuwemeubeltekst;
    }
    
    public void toonPrijs(){
        System.out.println(prijs);
    }
    
    public void zetPrijs(double nieuweprijs){
        prijs = nieuweprijs;
    }
}


public class Winkel {
    
    ...
        
        kast.zetPrijs(200.99);
        stoel.zetPrijs(50);
        
        kast.toonTekst();
        kast.toonPrijs();
        stoel.toonPrijs();
    }
}

Klassenmethoden maken

Daar de variabele meubeltekst een klassevariabele is (elk object heeft voor deze variabele dezelfde waarde) is het opportuun om de methode zetTekst en de methode toonTekst te definiëren als klassenmethoden. Dit kan je met het sleutelwoord static. Een klassenmethode kan je aanspreken zonder eerst een object van de klasse aan te maken:

Toon volledige code... Toon nieuwe code...


public class Meubel {
    
    ...
    
    public static void toonTekst(){
        System.out.println(meubeltekst);
    }
    
    public static void zetTekst(String nieuwemeubeltekst){
        meubeltekst = nieuwemeubeltekst;
    }
    
    ...
}

public class Winkel {
    
    ...
        
        Meubel.zetTekst("Onze meubels zijn niet te overtreffen");
        
        ...
        
        Meubel.toonTekst();
        kast.toonTekst();
        ...
    }
}
Het is belangrijk hierbij op te merken dat je klassenmethoden nog steeds vanuit een instantie (object) kan benaderen. In het bovenstaande voorbeeld roepen we de methode toonTekst aan met de naam van de klasse Meubel en de instantie kast.

Waarden terugleveren aan methoden

Je kan bij het aanroepen van een methode ook een waarde laten terugkeren door die methode. Hier zie je de methode berekenKortingsprijs. Deze methode ontvangt een int waarde en keert een double terug. De meegegeven integerwaarde wordt gebruikt als het kortingspercentege. De terugkeerwaarde wordt in de methode voorafgegaan door het sleutelwoord return.

Toon volledige code... Toon nieuwe code...

public class Meubel {
    
    ...
    
    public double berekenKortingsprijs( int korting){
        return prijs - prijs * korting / 100;
    }
}

public class Winkel {
    
    ...
        
        System.out.println(kast.berekenKortingsprijs(20));
        System.out.println(stoel.berekenKortingsprijs(50));
    }
}

In het volgende onderdeel maak je kennis met speciale methoden genaamd constructors. Het is belangrijk hierbij op te merken dat gewone methoden net zoals contructors kunnen overloaded worden.

Constructors maken en overloaden

Constructors

Constructors zijn codeblokken die worden uitgevoerd bij het aanmaken van een instantie (object) van een klasse. Je kan zelf constructors voor een klasse aanmaken op een eenvoudige manier: je voegt gewoon een methode toe aan de klasse met dezelfde naam als de klasse, zonder teruglevertype.

In het voorbeeld hieronder maken we twee constructors voor de klasse Meubel. We hebben twee methoden met de naam Meubel gedefiniëerd, deze hebben telkens andere parameters die worden ontvangen. Aan de hand van de opgegeven parameters weet Java welke constructor moet worden toegepast.

Het maken van meerdere constructors noemen we constructor-overloading. Ook gewone methodes kunnen overloaded worden. Je definiëert twee keer een methode met eenzelfde naam maar verschillende parameters (verschil qua type en/of qua aantal).

Toon volledige code... Toon nieuwe code...

public class Meubel {
    
    ...
    public Meubel() {
            prijs = 0;
    }
    
     
    public Meubel(int nieuweprijs) {
            prijs = nieuweprijs;
    }
    
    ...
}


public class Winkel {
    
    public Winkel() {
    }
    
    public static void main(String[] args) {
        
        Meubel kast = new Meubel();
        Meubel stoel = new Meubel(50);
        
        Meubel.zetTekst("Onze meubels zijn niet te overtreffen");
        
        kast.zetPrijs(200.99);

        kast.toonPrijs();
        stoel.toonPrijs();
    }
}
Bij het maken van een Meubel-object kan je kiezen of je een prijs meegeeft of niet. Geef je geen prijs op, dan wordt deze ingesteld op 0.

Het sleutelwoord this

Bekijk volgende codefragment: dit stuk code werd gebruikt als constructor voor de klasse Meubel.
...
public Meubel(int nieuweprijs) {
            prijs = nieuweprijs;
    }
...
Wanneer je waarden aan een constructor doorgeeft hoef je niet steeds een andere naam voor die waarde te verzinnen (nieuweprijs i.p.v. prijs.

Je kan met dezelfde naam als de variabele werken wanneer je in de constructor (of een andere methoden) gebruik maakt van het sleutelwoord this.

...
public Meubel(int prijs) {
            this.prijs = prijs;
    }
...
This vormt een referentie aan het huidige object.

Recursie

Recursie is een term die gebruikt wordt voor methodes die zichzelf aanroepen, soms kan dit heel interessant zijn. Bekijk volgende klasse Reken waarbij geen gebruik werd gemaakt van een recursieve methode voor het berekenen van de faculteit van een getal:
//    NIET RECURSIEF !

public class Reken {
  
    public static int berekenFaculteit(int getal) {
        int fac = 1;
        for(;getal>1;getal--){
            fac = fac * getal;
        }
        return fac;
    }
       
    public static void main(String[] args) {
        System.out.println(Reken.berekenFaculteit(6));
    }  
}
We kunnen dit probleem op volgende manier recursief oplossen:
public class Reken2 {
   
    public static int berekenFaculteit(int getal) {
        if(getal == 1) {
            return getal;
        } else {
            return getal * berekenFaculteit(getal-1);
        }
    }
    
    public static void main(String[] args) {
        System.out.println(Reken2.berekenFaculteit(5));
    }
}

Bereik van variabelen

Variabelen hebben in Java een bepaalde levensduur. Dit betekent dat variabelen die je declareert vroeg of laat weer worden vernietigd.

Java definiëert drie hoofdbereiken: klasse-niveau, methode-niveau en codeblok-niveau.

Voorbeeld:

public class Bereik {
    int waarde;                       //waarde: zichtbaar in de volledige klasse
    
    public Bereik(int nieuwewaarde) { // nieuwewaarde: enkel binnen deze methode
        waarde = nieuwewaarde;
    }
    
    public void verhoog(){
        int vergelijk = 10;           //vergelijk: enkel binnen deze methode
        if(waarde<vergelijk){
            int verhoog = 20;         //verhoog: enkel in dit if-blok
            waarde += verhoog;
        }
    }
    
    public static void main(String[] args) {
        Bereik bereik1 = new Bereik(5);
        bereik1.verhoog();
        System.out.println(bereik1.waarde);
    } 
}

Garbage-collection

Principe

In Java zal je voor het opruimen van objecten die je hebt gemaakt met de opdracht new kunnen rekenen op een ingebouwd proces dat garbage-collection heet. Java gaat dus zelf gereserveerd geheugen opruimen waar niet langer referenties naar bestaan. Om deze garbage-collection van uw object toe te staan kan je de referentie naar dat object instellen op null. Pas op, je weet nu nog niet zeker wanneer het object zal worden opgeruimd.

Toon volledige code... Toon nieuwe code...

...

public class Winkel {
    
    ...
        
        kast = null;
        stoel = null;
        
    }
}

De finalize-methode

Wanneer een object door de garbage-collector wordt opgehaald, gaat de garbage-collector een methode van het object met de naam finalize aanroepen, als die bestaat.

Waarden en objecten doorgeven aan methoden

Wanneer je primitieve datatypes zoals int, long, boolean, ... doorgeeft aan een methode gebeurt dat byValue: enkel de waarde van de variabele wordt meegegven, de variabele zelf wordt binnen de scope van de methode niet aangepast.

Geef je objecten (dus ook arrays) door aan een methode, dan worden die gegevens byReference meegegeven, de methode werkt met het object in kwestie, het object komt er dus gemanipuleerd uit.

Bestudeer aandachtig volgend voorbeeld, voer het zeker uit en bekijk het resultaat, probeer de werking te begrijpen.

public class Doorgeef {
    public int getalwaarde;
    
    public static int verdubbel(int waarde){
        return waarde *= 2;
    }
    
    public void verdubbelgetalwaarde(Doorgeef B){
        B.getalwaarde *= 2;
    }
    
    public void verdubbelaar(int a[]){
        for(int teller=0;teller<a.length;teller++){
            a[teller] *= 2;
        }
    }
    
    public static void main(String[] args) {
        int getal = 50;
        
        System.out.println(getal);
        System.out.println(Doorgeef.verdubbel(getal));
        System.out.println(getal);
        
        
        System.out.println("\n");
        
        Doorgeef test = new Doorgeef();
        test.getalwaarde = 60;
        System.out.println(test.getalwaarde);
        test.verdubbelgetalwaarde(test);
        System.out.println(test.getalwaarde);
        
        System.out.println("");
         
        int mijnarray[] = {1,2,3,4,5,6};
        Doorgeef test2 = new Doorgeef();
        //arrayinhoud voor verdubbelaar
        for(int teller=0;teller<mijnarray.length;teller++){
            System.out.println("mijnarray[" +teller +"] = " +mijnarray[teller]);
        }
        
        //verdubbelaar uitvoeren
        test2.verdubbelaar(mijnarray);
        System.out.println("");
        
        //arrayinhoud na verdubbelaar
        for(int teller=0;teller<mijnarray.length;teller++){
            System.out.println("mijnarray[" +teller +"] = " +mijnarray[teller]);
        }
    }
}

Arrays, ArrayList : sorteren en doorzoeken

Arrays doorzoeken en sorteren

De klasse Arrays uit het pallet java.util bevat in Java tal van bijzonder interessante methodes voor het doorzoeken en sorteren van Array-objecten.

Het is dan ook af te raden zelf sorteeralgoritmes te schrijven die deze functionaliteiten afhandelen.

import java.util.*;
public class arraysklasse {
    
    public static void print(int[] a){
        for(int teller=0;teller<a.length;teller++){
            System.out.println("element " +teller +" = " +a[teller]);
        }
    }
    public static void main(String[] args) {
        int[] getallen = {8,150,23,46,5,89,75,23};
        print(getallen);
        Arrays.sort(getallen);
        print(getallen);  
    }
}
Meer over de klasse Arrays bij Sun.

Collecties: ArrayList

In het pakket java.util vinden we de klasse ArrayList. Het is niet de bedoeling hier reeds alle theorie omtrent collecties op te voeren, maar ik wil je toch reeds kennis laten maken met een deze heel interessante klasse.

Voor ons, als beginnende Java-programmeur is het gewoon interessant te weten dat deze klasse een heel krachtige aanvulling vormt op Arrays. Een ArrayList moet je niet meer voordimensioneren en je kan er gegevens aan toevoegen, verwijderen, wijzigen met behulp van voorgedefiniëerde methoden.

import java.util.*;
public class arrlist {
  
    public static void main(String[] args) {
        ArrayList alist = new ArrayList();
        alist.add("Brugge");
        alist.add("Gent");
        alist.add("Oostkamp");
        alist.add("Aartrijke");
        
        System.out.println(alist);
        System.out.println(alist.contains("Oostkamp"));
        
        alist.remove(2);
        
        System.out.println(alist);
        System.out.println(alist.contains("Oostkamp"));
        
        Collections.sort(alist);
        System.out.println(alist); 
    }   
}

Meer info over de klasse ArrayList bij Sun

Meer info over de klasse Collections (sorteren, zoeken, ...) bij Sun

In het pakket java.util bevinden zich nog tal van andere heel interessant klassen (hashtable, Linkedlist, Calendar,...) zeker eens bekijken !

Meer tutorials:
leer ook: html | xhtml | css | asp | asp.net | c# | ado.net | linq | ajax | java | javascript
Valid HTML 4.01! Valid CSS! © - Cursusweb