Wildcards i API'er
Design fleksible generiske metoder
Wildcards i API'er er en gratis Java Academy-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Java Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Java Academy-kurset indeholder 4 lektioner i alt.
Design af fleksible metoder
Jokertegn er primært et værktøj til API-designere. Et velplaceret jokertegn lader kaldende kode sende flere typer uden typekonverteringer.
Målet er maksimal fleksibilitet for kaldende kode og fuld typesikkerhed internt.
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)));
}
}Ubundne jokertegn
List<?> er et ubundet jokertegn: en liste med en ukendt type.
Brug det, når din metode er ligeglad med elementtypen, f.eks. når den tæller elementer eller kontrollerer, om listen er tom.
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<?> kontra List<Object>
De er forskellige. List<Object> accepterer kun en liste, der er erklæret som Object. List<?> accepterer en liste af enhver type.
Du kan sende en List<String> til en parameter af typen List<?>, men ikke til en af typen List<Object>.
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
}
}Hvornår en typeparameter er tydeligere
Hvis du har brug for at referere til elementtypen mere end én gang, er en navngiven typeparameter tydeligere end et jokertegn.
Sammenlign void swap(List<?> l, int i, int j) (som kræver en privat hjælpermetode) med en enkel generisk version.
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);
}
}Tricket med hjælpermetoden til at indfange jokertegnet
Hvis en offentlig API skal bruge List<?>, kan du delegere til en privat generisk hjælpermetode for at indfange jokertegnet.
Hjælpermetoden navngiver typen T, så den kan skrive tilbage i listen.
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);
}
}Producentparametre i en praktisk API
Hvis du designer en addAll, der henter fra en vilkårlig kompatibel kilde, skal kilden have en øvre grænse.
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);
}
}Forbrugerparametre i en praktisk API
En API for en modtager, der skriver resultater, bruger en nedre grænse på destinationen, så kaldende kode kan levere bredere beholdere.
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);
}
}Jokertegn med indlejrede generiske typer
Indlejrede generiske typer har ofte brug for jokertegn. En metode, der accepterer en liste af enhver slags liste, bruger 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"))));
}
}Undgå overdreven generalisering
Ikke alle metoder har brug for jokertegn. Hvis kaldende kode kun sender én type, er en almindelig parameter tydeligere.
Tilføj jokertegn, når du ser, at den faktiske kaldende kode bliver blokeret af invarians, ikke på forhånd.
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")));
}
}Dokumentation af jokertegnets hensigt
Et jokertegn signalerer en hensigt. ? extends T fortæller læseren "Jeg læser kun fra dette". ? super T siger "Jeg skriver kun til dette".
Valget af det rigtige jokertegn er en form for selvbeskrivende kode, der også håndhæver kontrakten.
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);
}
}En generisk stak-API
Blochs berømte stakeksempel: pushAll forbruger fra en producent (extends), mens popAll producerer til en forbruger (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);
}
}Hurtigt tjek
Afprøv din fornemmelse for API-design.
Opsamling
Du har lært at designe API'er med jokertegn:
List<?>til skrivebeskyttede metoder, der er uafhængige af typen.- Anvend PECS på parametre for at opnå fleksibilitet.
- Brug det private hjælpertrick til at indfange jokertegnet, når du skal skrive gennem et jokertegn.
- Undgå jokertegn i returtyper, og overgenerér ikke.
Du har gennemført kurset om jokertegn og PECS.
public class Main {
public static void main(String[] args) {
System.out.println("Wildcards in APIs course complete");
}
}Lær Java med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 104
- Lektioner
- 374
Ofte stillede spørgsmål
Er lektionen “Wildcards i API'er” gratis?
Ja — hele teksten til “Wildcards i API'er” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Java Academy-kurset, skal du opgradere til CoddyKit PRO. Java Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Wildcards i API'er”?
Design fleksible generiske metoder Du øver dig i Java Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Java Academy?
Der kræves ingen tidligere erfaring. Java Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.
Hvor lang tid tager lektionen “Wildcards i API'er”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Java Academy-lektion?
Ja. Alle Java Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Upper bounded wildcards
- Lower bounded wildcards
- PECS-princippet
- Wildcards i API'er