Menu
Coddy logo textTech

Wildcards (?, extends, super)

Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy. Lektion 57 von 87.

Gebundene Typparameter beschränken Generics auf bestimmte Typen, aber was ist, wenn du mit vorhandenen generischen Typen arbeitest und den genauen Typparameter nicht kennst oder er dir egal ist? Hier kommen Wildcards ins Spiel.

Der unbegrenzte Wildcard-Typ ? stellt einen unbekannten Typ dar. Er ist nützlich, wenn du jeden parametrisierten Typ akzeptieren möchtest:

public static void printList(List<?> list) {
    for (Object item : list) {
        System.out.println(item);
    }
}

printList(new ArrayList<String>());   // Funktioniert
printList(new ArrayList<Integer>());  // Funktioniert

Der Wildcard mit oberer Schranke ? extends Type akzeptiert den angegebenen Typ oder eine seiner Unterklassen. Verwende ihn, wenn du aus einer generischen Struktur lesen musst:

public static double sumNumbers(List<? extends Number> numbers) {
    double sum = 0;
    for (Number n : numbers) {
        sum += n.doubleValue();
    }
    return sum;
}

sumNumbers(Arrays.asList(1, 2, 3));        // Liste von Integer
sumNumbers(Arrays.asList(1.5, 2.5));       // Liste von Double

Der untere begrenzte Wildcard ? super Type akzeptiert den angegebenen Typ oder eine seiner Oberklassen. Verwende ihn, wenn du in eine generische Struktur schreiben musst:

public static void addIntegers(List<? super Integer> list) {
    list.add(1);
    list.add(2);
}

List<Number> numbers = new ArrayList<>();
addIntegers(numbers);  // Funktioniert - Number ist ein Supertyp von Integer

Eine hilfreiche Richtlinie: Verwende extends, wenn du nur liest (Produzent), und verwende super, wenn du nur schreibst (Konsument). Dies ist als PECS-Prinzip bekannt: Producer Extends, Consumer Super.

challenge icon

Aufgabe

Einfach

Lass uns ein Zoo-Fütterungssystem erstellen, das alle drei Arten von Wildcards demonstriert! Du wirst eine Hierarchie von Tieren und Futter erstellen und anschließend Hilfsmethoden schreiben, die unbeschränkte, nach oben beschränkte und nach unten beschränkte Wildcards verwenden, um verschiedene Fütterungsszenarien zu verarbeiten.

Du wirst deinen Code auf vier Dateien verteilen:

  • Food.java: Erstelle eine einfache Klassenhierarchie für Futter. Beginne mit einer Basisklasse Food, die ein privates Feld name (String), einen Konstruktor zu dessen Initialisierung und eine getName()-Methode besitzt. Erstelle anschließend zwei Unterklassen in derselben Datei: Meat erweitert Food (der Konstruktor ruft super(name) auf) und Vegetable erweitert Food (nach demselben Muster).
  • Animal.java: Erstelle eine Basisklasse Animal mit einem privaten Feld species (String), einem Konstruktor und einer getSpecies()-Methode. Erstelle zwei Unterklassen: Carnivore und Herbivore, die jeweils Animal erweitern und den Konstruktor der übergeordneten Klasse aufrufen.
  • ZooFeeder.java: Hier kommen Wildcards zur Geltung! Erstelle eine Hilfsklasse mit drei statischen Methoden:

    printInventory(List<?> items) – Verwendet eine unbeschränkte Wildcard, um eine beliebige Liste auszugeben. Durchlaufe die Liste und gib jedes Element mithilfe von toString() jeweils in einer eigenen Zeile aus.

    calculateTotalFood(List<? extends Food> foods) – Verwendet eine nach oben beschränkte Wildcard, um aus einer Liste eines beliebigen Food-Typs zu lesen. Gib die Anzahl der Elemente als int zurück. Dies demonstriert das Lesen aus einem Produzenten.

    addMeatToStock(List<? super Meat> stock, String meatName) – Verwendet eine nach unten beschränkte Wildcard, um in eine Liste zu schreiben, die Meat aufnehmen kann. Erstelle ein neues Meat-Objekt mit dem angegebenen Namen und füge es dem Bestand hinzu. Dies demonstriert das Schreiben in einen Konsumenten.

  • Main.java: Führe dein Zoo-Fütterungssystem zusammen! Du erhältst zwei Eingaben: einen Fleischnamen (String) und einen Gemüsenamen (String).

    Erstelle zunächst eine ArrayList<Food> und füge ein Meat-Objekt mit dem Fleischnamen sowie ein Vegetable-Objekt mit dem Gemüsenamen hinzu. Gib Food inventory: aus und rufe anschließend printInventory mit dieser Liste auf.

    Gib danach eine leere Zeile aus und anschließend Total food items: [count], wobei du calculateTotalFood auf deine Futterliste anwendest.

    Erstelle schließlich eine neue ArrayList<Food> mit dem Namen meatStock. Gib eine leere Zeile und anschließend Adding to meat stock... aus. Rufe addMeatToStock mit dieser Liste und der Zeichenkette "Beef" auf. Gib danach Meat stock after adding: aus und rufe printInventory für den Fleischbestand auf.

Du erhältst zwei Eingaben in dieser Reihenfolge: einen Fleischnamen und einen Gemüsenamen.

Überschreibe toString() in deiner Food-Klasse so, dass der Name des Futters zurückgegeben wird und die Ausgabe korrekt funktioniert. Beachte, wie jeder Wildcard-Typ einem anderen Zweck dient: ? für maximale Flexibilität, wenn du lediglich als Object lesen musst, ? extends beim Lesen spezifischer Typen und ? super beim Schreiben in eine Collection!

Probier es selbst

import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String meatName = scanner.nextLine();
        String vegetableName = scanner.nextLine();
        
        // TODO: Erstelle eine ArrayList&lt;Food&gt; und füge Meat- und Vegetable-Objekte hinzu
        
        // TODO: Print "Food inventory:" then call printInventory
        
        // TODO: Print blank line, then "Total food items: [count]" using calculateTotalFood
        
        // TODO: Erstelle neue ArrayList&lt;Food&gt; namens meatStock
        
        // TODO: Print blank line, then "Adding to meat stock..."
        
        // TODO: Rufe addMeatToStock mit meatStock und "Beef" auf
        
        // TODO: Print "Meat stock after adding:" then call printInventory on meatStock
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Java-Compiler