Java Generics beheersen: Sortering vereenvoudigen & Typeveiligheid verbeteren
Het zou fijn zijn als we een enkele sorteermethode kunnen schrijven die de elementen in een Integer-array, een String-array, of een array van elk type dat ordering ondersteunt, kan sorteren.
Java Generics (generieke methodes en generieke klassen) stellen programmeurs in staat om, met een enkele methode-declaratie, een set gerelateerde methodes te specificeren, of met een enkele klasse-declaratie, een set gerelateerde typen, respectievelijk.
Generics bieden ook compile-time type safety (compileertijd typeveiligheid), waarmee programmeurs ongeldige typen tijdens compilatie kunnen opvangen.
Met het Java Generics-concept kunnen we een generieke methode schrijven voor het sorteren van een array van objecten, en deze generieke methode aanroepen met Integer-arrays, Double-arrays, String-arrays, enz., om de array-elementen te sorteren.
Generieke Methodes (Generic Methods)
Je kunt een enkele generieke methode-declaratie schrijven die aangeroepen kan worden met argumenten van verschillende typen. Op basis van de typen van de argumenten die aan de generieke methode worden doorgegeven, behandelt de compiler elke methode-aanroep op de juiste manier.
Regels voor het definiëren van Generic Methods:
- Alle generieke methode-declaraties hebben een type-parametersectie begrensd door hoekhaakjes (
<en>) die voorafgaat aan het returntype van de methode (< E >in het volgende voorbeeld). - Elke type-parametersectie bevat één of meer typeparameters gescheiden door komma's. Een typeparameter, ook wel typevariabele genoemd, is een identifier die een generieke typenaam specificert.
- De typeparameters kunnen gebruikt worden om het returntype te declareren en fungeren als placeholders voor de typen van de argumenten die aan de generieke methode worden doorgegeven, bekend als actual type arguments.
- De body van een generieke methode wordt gedeclareerd als die van elke andere methode. Let op: typeparameters kunnen alleen referentietypen vertegenwoordigen, geen primitieve typen (zoals int, double, char).
Voorbeeld: Generieke printArray methode
public class GenericMethodTest {
// generieke methode printArray
public static <E> void printArray(E[] inputArray) {
// Display array elementen
for (E element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println();
}
public static void main(String args[]) {
// Maak arrays van Integer, Double en Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println("Array integerArray bevat:");
printArray(intArray); // geef een Integer array door
System.out.println("\nArray doubleArray bevat:");
printArray(doubleArray); // geef een Double array door
System.out.println("\nArray characterArray bevat:");
printArray(charArray); // geef een Character array door
}
}
Resultaat:
Array integerArray bevat: 1 2 3 4 5 Array doubleArray bevat: 1.1 2.2 3.3 4.4 Array characterArray bevat: H E L L O
Bounded Type Parameters (Beperkte Typeparameters)
Er kunnen momenten zijn waarop je de typen die aan een typeparameter doorgegeven mogen worden, wilt beperken. Bijvoorbeeld, een methode die op getallen werkt, wil misschien alleen instanties van Number of zijn subclasses accepteren. Dit is waar bounded type parameters voor zijn.
Om een bounded type parameter te declareren, geef je de naam van de typeparameter, gevolgd door het extends-sleutelwoord, gevolgd door de upper bound.
Voorbeeld: Maximum van drie Comparable objecten
public class MaximumTest {
// Bepaalt het grootste van drie Comparable objecten
public static <T extends Comparable<T>> T maximum(T x, T y, T z) {
T max = x; // neem aan dat x initieel het grootste is
if (y.compareTo(max) > 0) {
max = y; // y is tot nu toe het grootste
}
if (z.compareTo(max) > 0) {
max = z; // z is nu het grootste
}
return max; // retourneert het grootste object
}
public static void main(String args[]) {
System.out.printf("Max van %d, %d en %d is %d\n\n", 3, 4, 5, maximum(3, 4, 5));
System.out.printf("Max van %.1f, %.1f en %.1f is %.1f\n\n", 6.6, 8.8, 7.7, maximum(6.6, 8.8, 7.7));
System.out.printf("Max van %s, %s en %s is %s\n", "peer", "appel", "sinaasappel", maximum("peer", "appel", "sinaasappel"));
}
}
Resultaat:
Max van 3, 4 en 5 is 5 Max van 6.6, 8.8 en 7.7 is 8.8 Max van peer, appel en sinaasappel is peer
Let op: In dit voorbeeld wordt extends in een algemene zin gebruikt om te betekenen "extends" (voor klassen) of "implements" (voor interfaces).
Generieke Klasses (Generic Classes)
Een generieke klassedeclaratie ziet eruit als een niet-generieke klassedeclaratie, behalve dat de klassenaam wordt gevolgd door een type-parametersectie.
Net als bij generieke methodes kan de type-parametersectie van een generieke klasse één of meer typeparameters hebben, gescheiden door komma's. Deze klassen worden geparametriseerde klassen of geparametriseerde typen genoemd omdat ze één of meer parameters accepteren.
Voorbeeld: Box klasse
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("Hello World"));
System.out.printf("Integer Value :%d\n\n", integerBox.get());
System.out.printf("String Value :%s\n", stringBox.get());
}
}
Resultaat:
Integer Value :10 String Value :Hello World
Java
- Java primitieve datatypes: complete gids met voorbeelden
- Java-operators beheersen: typen, syntax en praktische voorbeelden
- Java-commentaar: typen, gebruik en best practices
- Java Enhanced For-lus beheersen: syntax, voorbeelden en best practices
- Java Strings beheersen: aanmaken, methodes en best practices
- Java interfaces meesteren: concepten, implementatie en best practices
- Java Try-with-resources meesteren: automatische resource management uitgelegd
- Java Annotaties uitgelegd: typen, plaatsing en praktische voorbeelden
- Java Assertions: een praktische gids voor bugdetectie en codebetrouwbaarheid
- Java Type Casting: Van widening tot narrowing en verder
- Java Generics: Herbruikbare, type-veilige code bouwen