Java Academy · Lektion

Wildcards in APIs

Flexible generische Methoden entwerfen

Lektion 4 von 413 Schritte

Wildcards in APIs ist eine kostenlose Java Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Java Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Java Academy-Kurs umfasst insgesamt 4 Lektionen.

Flexible Methoden entwerfen

Wildcards sind vor allem ein Werkzeug für API-Entwickler. Eine passend platzierte Wildcard ermöglicht es Aufrufern, mehr Typen ohne Casts zu übergeben.

Das Ziel: maximale Flexibilität für Aufrufer und vollständige Typsicherheit innerhalb der Methode.

import java.util.List;

public class Main {
    static double total(List<? extends Number> items) {
        double sum = 0;
        for (Number n : items) sum += n.doubleValue();
        return sum;
    }
    public static void main(String[] args) {
        System.out.println(total(List.of(1, 2, 3)));
        System.out.println(total(List.of(1.5, 2.5)));
    }
}

Unbeschränkte Wildcards

List<?> ist eine unbeschränkte Wildcard: eine Liste eines unbekannten Typs.

Verwenden Sie sie, wenn Ihre Methode den Elementtyp nicht benötigt, zum Beispiel beim Zählen der Elemente oder beim Prüfen, ob die Liste leer ist.

import java.util.List;

public class Main {
    static int size(List<?> any) {
        return any.size();
    }
    public static void main(String[] args) {
        System.out.println(size(List.of("a", "b")));
        System.out.println(size(List.of(1, 2, 3)));
    }
}

List<?> im Vergleich zu List<Object>

Diese beiden Typen sind unterschiedlich. List<Object> akzeptiert nur eine Liste, die als Object deklariert wurde. List<?> akzeptiert eine Liste jedes beliebigen Typs.

Sie können eine List<String> an einen List<?>-Parameter übergeben, aber nicht an einen List<Object>-Parameter.

import java.util.List;

public class Main {
    static void printAll(List<?> list) {
        for (Object o : list) System.out.println(o);
    }
    public static void main(String[] args) {
        List<String> names = List.of("Ada", "Linus");
        printAll(names); // works; List<Object> would reject this
    }
}

Wann ein Type-Parameter verständlicher ist

Wenn Sie sich mehr als einmal auf den Elementtyp beziehen müssen, ist ein benannter Type-Parameter verständlicher als eine Wildcard.

Vergleichen Sie void swap(List<?> l, int i, int j) (benötigt eine private Hilfsmethode) mit einer übersichtlichen generischen Variante.

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

public class Main {
    static <T> void swap(List<T> list, int i, int j) {
        T tmp = list.get(i);
        list.set(i, list.get(j));
        list.set(j, tmp);
    }
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(List.of("a", "b", "c"));
        swap(list, 0, 2);
        System.out.println(list);
    }
}

Der Trick mit der Wildcard-Erfassung

Wenn eine öffentliche API List<?> verwenden muss, können Sie die Aufgabe an eine private generische Hilfsmethode delegieren, um die Wildcard zu erfassen.

Die Hilfsmethode benennt den Typ T, sodass sie wieder in die Liste schreiben kann.

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

public class Main {
    public static void reverse(List<?> list) { reverseHelper(list); }
    private static <T> void reverseHelper(List<T> list) {
        for (int i = 0, j = list.size() - 1; i < j; i++, j--) {
            T tmp = list.get(i);
            list.set(i, list.get(j));
            list.set(j, tmp);
        }
    }
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4));
        reverse(list);
        System.out.println(list);
    }
}

Produzenten-Parameter in einer echten API

Für ein addAll, das aus jeder kompatiblen Quelle liest, verwenden Sie eine obere Schranke für die Quelle.

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class Main {
    static <T> void addAll(List<T> target, Collection<? extends T> source) {
        for (T t : source) target.add(t);
    }
    public static void main(String[] args) {
        List<Number> nums = new ArrayList<>();
        addAll(nums, List.of(1, 2, 3));
        System.out.println(nums);
    }
}

Konsumenten-Parameter in einer echten API

Eine Senken-API, die Ergebnisse schreibt, verwendet eine untere Schranke für das Ziel, sodass Aufrufer allgemeinere Container bereitstellen können.

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

public class Main {
    static <T> void repeat(T value, int times, List<? super T> sink) {
        for (int i = 0; i < times; i++) sink.add(value);
    }
    public static void main(String[] args) {
        List<Object> out = new ArrayList<>();
        repeat("hi", 3, out);
        System.out.println(out);
    }
}

Wildcards mit verschachtelten Generics

Verschachtelte Generics benötigen häufig Wildcards. Eine Methode, die eine Liste beliebiger Listen akzeptiert, verwendet List<? extends List<?>>.

import java.util.List;

public class Main {
    static int countAll(List<? extends List<?>> lists) {
        int total = 0;
        for (List<?> inner : lists) total += inner.size();
        return total;
    }
    public static void main(String[] args) {
        System.out.println(countAll(List.of(List.of(1, 2), List.of("a", "b", "c"))));
    }
}

Übermäßige Generics vermeiden

Nicht jede Methode benötigt Wildcards. Wenn Aufrufer immer nur einen einzigen Typ übergeben, ist ein einfacher Parameter verständlicher.

Fügen Sie Wildcards hinzu, wenn Sie feststellen, dass echte Aufrufer durch Invarianz eingeschränkt werden, nicht vorsorglich.

import java.util.List;

public class Main {
    // Simple and clear; no wildcard needed for this internal use
    static String joinStrings(List<String> parts) {
        return String.join(", ", parts);
    }
    public static void main(String[] args) {
        System.out.println(joinStrings(List.of("a", "b", "c")));
    }
}

Die Absicht von Wildcards dokumentieren

Eine Wildcard signalisiert eine Absicht. ? extends T sagt den Lesern: „Ich lese daraus nur“. ? super T bedeutet: „Ich schreibe nur hinein“.

Die richtige Wildcard zu wählen, ist eine Form von selbstdokumentierendem Code, der den Vertrag gleichzeitig erzwingt.

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

public class Main {
    // src: read-only producer; dest: write-only consumer
    static <T> void transfer(List<? extends T> src, List<? super T> dest) {
        for (T t : src) dest.add(t);
    }
    public static void main(String[] args) {
        List<Number> dest = new ArrayList<>();
        transfer(List.of(1, 2), dest);
        System.out.println(dest);
    }
}

Eine generische Stack-API

Blochs berühmtes Stack-Beispiel: pushAll konsumiert aus einem Produzenten (extends), popAll produziert in einen Konsumenten (super).

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.ArrayList;
import java.util.List;

public class Main {
    static class Stack<E> {
        private final Deque<E> items = new ArrayDeque<>();
        void pushAll(Collection<? extends E> src) { for (E e : src) items.push(e); }
        void popAll(Collection<? super E> dst) { while (!items.isEmpty()) dst.add(items.pop()); }
    }
    public static void main(String[] args) {
        Stack<Integer> s = new Stack<>();
        s.pushAll(List.of(1, 2, 3));
        List<Number> out = new ArrayList<>();
        s.popAll(out);
        System.out.println(out);
    }
}

Kurzer Test

Testen Sie Ihr Gespür für API-Entwürfe.

Zusammenfassung

Sie haben gelernt, APIs mit Wildcards zu entwerfen:

  • List<?> für schreibgeschützte Methoden, die vom Typ unabhängig sind.
  • Wenden Sie PECS bei Parametern an, um Flexibilität zu erreichen.
  • Verwenden Sie den privaten Trick der Wildcard-Erfassung, wenn Sie durch eine Wildcard schreiben müssen.
  • Vermeiden Sie Wildcards in Rückgabetypen und übermäßig viele Generics.

Sie haben den Kurs zu Wildcards und PECS abgeschlossen.

public class Main {
    public static void main(String[] args) {
        System.out.println("Wildcards in APIs course complete");
    }
}
Kostenlos starten

Lerne Java mit einem KI-Tutor — kostenlos

Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.

Kurse
104
Lektionen
374

Häufig gestellte Fragen

Ist die Lektion „Wildcards in APIs“ kostenlos?

Ja — der vollständige Text von „Wildcards in APIs“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Java Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Java Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Wildcards in APIs“?

Flexible generische Methoden entwerfen Du übst Java Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Java Academy zu starten?

Keine Vorkenntnisse erforderlich. Java Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.

Wie lange dauert die Lektion „Wildcards in APIs“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Java Academy-Lektion Code schreiben und ausführen?

Ja. Jede Java Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Wildcards mit oberer Schranke
  2. Wildcards mit unterer Schranke
  3. Das PECS-Prinzip
  4. Wildcards in APIs
← Zurück zu Java Academy