Methoden van subklassen

Overerven van methoden

Subklassen erven alle methoden over van hun superklasse, zowel instance-methoden als klassenmethoden, afhangend van hun toegangsniveau (enkel public en protected methoden zijn toegankelijk vanuit de subklasse uit een ander pakket).

We gaan een Square-object maken en gebruik maken van getArea() en getPerimeter() om de oppervlakte en omtrek van het vierkant af te drukken.

public class SquareApp{
    public static void main(String[] args){
        Square sq = new Square();
        System.out.println(sq.getArea());
        System.out.println(sq.getPerimeter());
    }
}

Opdracht: Overgeërfde methoden gebruiken

  • Druk in het hoofdprogramma de oppervlakte en omtrek van het vierkant af
  • Vraag de eigenschappen van het vierkant op door middel van methoden en druk de gegevens op het scherm af
  • Stel ook de positie van het vierkant in met de methode setPosition()

Toevoegen van methoden

Verder kunnen we ook methoden aan de klasse Square toevoegen. Zo kunnen we bijvoorbeeld een methode toevoegen die de zijde van een vierkant teruggeeft en een methode die de zijde instelt.

public class Square extends Rectangle {
    
    ...

    public int getSide() {
        return side;
    }

    public void setSide(int side) {

        setWidth(side);
        setHeight(side);
    }

    ...

}

We zorgen ervoor dat de hoogte en breedte ingesteld worden op dezelfde waarde. We gebruiken hiervoor de bestaande methoden in plaats van deze waarden rechtstreeks toe te kennen. Zo maken we automatisch gebruik van de controle op negatieve waarden.

Opdracht: Een methode toevoegen

  • Voeg de methoden toe om de zijde in te stellen en op te vragen
  • Gebruik deze methoden in het hoofdprogramma
  • Druk de afmetingen van het vierkant af
  • Geef een negatieve waarde voor de zijde op en evalueer het resultaat
Methoden toevoegen

Vervangen van methoden (override)

De klasse Rectangle heeft methoden om de hoogte en de breedte van een rechthoek afzonderlijk in te stellen. Voor een vierkant moeten we er steeds voor zorgen dat de hoogte gelijk is aan de breedte. Wanneer we deze overgeërfde methoden zomaar zouden gebruiken, zouden we dus een onecht vierkant kunnen maken door de hoogte en breedte anders in te stellen.

We gaan daarom deze methoden vervangen door een nieuwe implementatie:

public class Square extends Rectangle {
    
    ...

    @Override
    public void setWidth(int width) {
        setSide(width);
    }

    @Override
    public void setHeight(int height) {
        setSide(height);
    }

    ...
    
}

We roepen hierbij gewoon de methode voor het instellen van de zijde op waardoor zowel hoogte als breedte op dezelfde waarde worden ingesteld.

Om een oneindige lus te mijden moeten we ook er voor zorgen dat de methode setSide() de methoden setHeight() en setWidth() van de superklasse Rectangle oproept, en niet de vervangen methoden van de klasse Square. Ook al hebben setHeight() en setWidth() vervangen, en daarom ook verborgen, zijn de oorspronkelijke methoden echter wel nog toegankelijk via het keyword super.

public class Square extends Rectangle {
    
    ...

    public int getSide() {
        return side;
    }

    public void setSide(int side) {
        super.setWidth(side);
        super.setHeight(side);
    }

    @Override
    public void setWidth(int width) {
        setSide(width);
    }

    @Override
    public void setHeight(int height) {
        setSide(height);
    }
}

De Override annotatie

Methoden die vervangen worden, zoals onze setWidth() en setHeight(), moeten exact dezelfde naam en exact hetzelfde aantal en type van parameters hebben. Als het return-type een object is, dan hoeft het sinds Java 5 niet hetzelfde te zijn als die van de superklasse (voor primitieve waarden moet het return-type wel exact hetzelfde zijn).

Indien de ‘signatuur‘ – de naam, het aantal parameters, de types van de parameters, en de volgorde van de parameters – van de methode verschilt met die van de superklasse, vervangt deze niet de methode van de superklasse en wordt er gewoon een nieuwe methode toegevoegd (wat hoogst waarschijnlijk niet de bedoeling is). Een veel voorkomende fout is daarom ook dat bij het vervangen van een methode de signatuur niet precies overeenkomt met de signatuur van de te vervangen methode.

Om dergelijke problemen te vermijden, kan men de annotatie @Override toevoegen voor de te vervangen methoden. Op die manier gaat de compiler controleren of deze methode inderdaad een methode binnen de superklasse gaat vervangen, of dat er door tikfouten gewoon een nieuwe methode gedefinieerd wordt.

Annotaties zijn nieuw sins Java 5 en ze bieden de mogelijkheid om meta-informatie toe te voegen die gebruikt kan worden door allerlei tools of runtime-omgevingen.

Scope

Subklassen kunnen het toegangsniveau van methoden enkel vergroten, niet verkleinen. Het is niet mogelijk de methode setHeight() te vervangen en te definiëren als private. Methoden die in de superklasse als protected gedefinieerd zijn kunnen in de subklasse als public gedefinieerd worden. Private methoden worden impliciet wel overgeërfd maar zijn niet toegankelijk vanuit de subklasse en kunnen dus eigenlijk niet vervangen worden. Het is wel mogelijk een methode te definiëren met dezelfde signatuur, maar eigenlijk wordt hier dan een nieuwe methode toegevoegd

Opdracht: Methoden vervangen

  • Vervang in de klasse Square de implementatie van de methoden setHeight() en setWidth()
  • Test deze methoden uit zonder de methode setSide() aan te passen
  • Pas ook de methode setSide() aan