Programmeren in Java/Generics

Programmeren in Java In ontwikkeling. Revisiedatum: onbekend

Inleiding Redelijk ontwikkeld. Revisiedatum: 22 augustus 2008

Installatie In ontwikkeling. Revisiedatum: 26 decemeber 2020

Hulpmiddelen Nog vrijwel niets. Revisiedatum: 26 decemeber 2020
  1. Introductie Goed ontwikkeld. Revisiedatum: 19 januari 2021
  2. Klassen Redelijk ontwikkeld. Revisiedatum: 22 januari 2021
  3. Package Goed ontwikkeld. Revisiedatum: 28 januari 2021
  4. Private en Public Goed ontwikkeld. Revisiedatum: 27 december 2020
  5. Getters en Setters Goed ontwikkeld. Revisiedatum: 19 januari 2021
  6. Static Goed ontwikkeld. Revisiedatum: 16 maart 2021
  7. Overerving In ontwikkeling. Revisiedatum: 20 januari 2007
  8. Protected Nog vrijwel niets. Revisiedatum: 22 januari 2021
  9. Abstract Nog vrijwel niets. Revisiedatum: 22 januari 2021
  10. Interfaces Nog vrijwel niets. Revisiedatum: 19 januari 2021
  11. Enums Goed ontwikkeld. Revisiedatum: 15 augustus 2020
  12. Generics Nog vrijwel niets. Revisiedatum: 19 januari 2021
  13. Boxing en Unboxing Goed ontwikkeld. Revisiedatum: 22 januari 2021
  14. Optional Nog vrijwel niets. Revisiedatum: 21 december 2020
  15. Functionele interfaces Nog vrijwel niets. Revisiedatum: 19 januari 2021
Appendices

Generics of genericiteit is een techniek om in een programmeertaal "generiek" te programmeren. Deze zin zegt eigenlijk niet veel over wat generics is. Het is makkelijker om het uit te leggen met een voorbeeld. Stel je wilt een klasse aanmaken die een array met instanties van een bepaald object bevat. Tijdens het ontwikkelen weet je echter nog niet wat voor objecten dit gaan zijn, maar je weet wel alvast dat het objecten is en geen primitieve waarden. Je kunt dan het volgende doen.

public class ArrayOfObject {
    private Object[] arrayOfObject;

    public ArrayOfObject(Object[] arrayOfObject){
        this.arrayOfObject = arrayOfObject;
    }

    public Object[] getArrayOfObject() {
        return arrayOfObject;
    }
    
    public Object get(int index){
        return arrayOfObject[index];
    }
    
    // Andere methodes
}

Je hebt dus een klasse gemaakt met een array van Objecten. Na verloop van tijd weet je welke klasse je wilt gebruiken met deze ArrayOfObject, namelijk Person. Dus pas je je klasse aan naar het volgende:

public class ArrayOfPerson {
    private Person[] arrayOfPerson;

    public ArrayOfPerson(Person[] arrayOfPerson){
        this.arrayOfPerson = arrayOfPerson;
    }

    public Person[] getArrayOfObject() {
        return arrayOfPerson;
    }

    public Person get(int index){
        return arrayOfPerson[index];
    }
    
    // Andere methodes
}

Alle verwijzingen naar Object zijn nu veranderd naar Person en het werkt. Maar nu wil je het ook gebruiken voor andere soorten klassen, bijvoorbeeld Animal, Car, maar ook meer abstracte zaken zoals File. Je kunt dan twee dingen doen. Je kunt terug gaan naar Object aangezien je met Object alle soorten klassen kunt gebruiken. Of je maakt deze ArrayOf-klasse voor elk type klasse.

Waarom je Object niet zou gebruiken:

  • Als je een Person-instantie in een Object steekt, moet je het terug casten naar een Person klasse wanneer je het eruit haalt.
  • Omdat het Object is kunnen er ook instanties van verschillende klassen worden bewaard, waardoor er misschien problemen komen.

Waar je geen ArrayOf-klasse zou schrijven voor iedere klasse:

  • Je schrijft dan eigenlijk dubbele code voor ieder type klasse
  • Als er een fout is in de code moet je dit doen voor alle versies van het "ArrayOf"-klasse.

Dit is waar generics van pas kunnen komen. Het is een vorm van abstractie waarbij je éénmaal een klasse kunt schrijven die gebruikt maakt van één of meerdere generics die instaan voor een typeklasse. De bedoeling is dat deze klasse, de generische klasse genoemd, dan werkt ongeacht welke klasse uiteindelijk in de plaats van een generic zouden komen.

Om een generische klasse aan te maken moet er worden gebruik gemaakt van een type parameter, die instaat voor de klasse die we later gaan gebruiken. Een type parameter vermelden we achter de naam van de klasse tussen punthaakjes (<>).

public class ArrayOf<T> {
    
}

Hier gebruiken we dus T als type parameter. Nu kunnen we verder bouwen en de klasse uitbreiden. Je kunt nu namelijk de type parameter gebruiken voor het volgende:

  • Voor het datatype te bepalen van een property (eigenschap) van een klasse.
  • Als datatype voor een argument bij zowel een constructor van de klasse als bij een gewone methode.
  • Het datatype van de retourwaarde (return) van een methode.

Als datatype kun je het dus bijvoorbeeld als volgt gebruiken:

private T t1; // Een property met als datatype T
private T[] ts; // Een array van T-objecten

Dit kunnen we toepassen in de ArrayOf-klasse.

public class ArrayOf<T> {
    private T[] ts;

}

Je kunt dus ook de type parameter gebruiken als datatype (naast andere datatypes) voor parameters bij constructors en methodes.

public constructor(T t){
    //code
}
public constructor(T[] t, int nietGerelateerdeInt){
    //code
}

public methodeA(T t){
    //code
}

public methodeB(T[] t){
    //code
}

In de ArrayOf klasse wordt het dan ongeveer zo.

public class ArrayOf<T> {
    private T[] ts;

    public ArrayOf(T[] ts){
        this.ts  = ts;
    }
}

Als laatste nog de type parameter voor de return type, die je onder ander zo kunt gebruiken.

public T getT(int index) {
    //code
}

public T[] getTs() {
    //code
}

Wat uiteindelijk voor de ArrayOf-klasse het volgende geeft.

public class ArrayOf<T> {
    private T[] ts;

    public ArrayOf(T[] ts){
        this.ts  = ts;
    }

    public T[] getArrayOf() {
        return ts;
    }
    
    public T get(int index){
        return ts[index];
    }

    // Andere methodes
}

Een generische klasse gebruiken

bewerken

Een generische klasse aanmaken doe je net zoals een gewone klasse met het sleutelwoord new. Je moet dan ook een klasse meegeven als type parameter. Bijvoorbeeld als volgt:

public class Main {

    public static void main(String[] args) {
        ArrayOf<Person> persons = new ArrayOf<Person>(new Person[10]);
    }

    public static class ArrayOf<T> {
        private T[] ts;

        public ArrayOf(T[] ts) {
            this.ts = ts;
        }

        public T[] getArrayOf() {
            return ts;
        }

        public T get(int index) {
            return ts[index];
        }

        // Andere methodes
    }

    public class Person {
        // Lege klasse bedoeld als voorbeeld.
    }
}

Je kunt vervolgens andere klassen in de plaats van Person gebruiken.

ArrayOf<String> strings = new ArrayOf<String>(new String[10]);
ArrayOf<Integer> integers = new ArrayOf<Integer>(new Integer[10]);
ArrayOf<ElkeAndereKlasseZolangHetBestaat> elkeAndereKlasseZolangHetBestaats = new ArrayOf<ElkeAndereKlasseZolangHetBestaat>(new ElkeAndereKlasseZolangHetBestaat[10]);

Meerdere type parameters

bewerken

Naamgeving voor type parameters

bewerken

Je kunt in principe elke letter gebruiken als type parameter, maar er is wel een conventie die sterk wordt aangeraden om te gebruiken.

  • T – Type (Het eerste type parameter dat je gebruikt)
  • S, U, V, etc. – (Een tweede, derde, vierde, etc. type parameter)
  • E – Element (wordt gebruikt bij Collections)
  • K – Key (Sleutel, wordt gebruikt bij Dictionaries)
  • V – Value (Waarde, wordt net zoals by Key gebruikt bij Dictionaries)
  • N – Number (een nummer)
Informatie afkomstig van https://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.