Java Academy · Lektion

Övre begränsade wildcards

? extends T för producenter.

Lektion 1 av 413 steg

Övre begränsade wildcards är en gratis lektion i Java Academy på CoddyKit. Detta är lektion 1 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Java Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Java Academy innehåller totalt 4 lektioner.

Generics är invarianta

I Java är generics invarianta. En List<Integer> är inte en List<Number>, även om Integer är en Number.

Detta överraskar nybörjare, men gör typsystemet robust. Wildcards lättar säkert på denna begränsning.

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> ints = List.of(1, 2, 3);
        // List<Number> nums = ints; // would NOT compile
        System.out.println("List<Integer> is not List<Number>");
        System.out.println(ints);
    }
}

Det övre begränsade wildcardet

? extends T är ett övre begränsat wildcard. Det betyder ”någon okänd typ som är T eller en undertyp till T”.

List<? extends Number> kan hänvisa till en List<Integer>, en List<Double> eller en List<Number>.

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<? extends Number> a = List.of(1, 2, 3);
        List<? extends Number> b = List.of(1.5, 2.5);
        System.out.println(a.get(0));
        System.out.println(b.get(0));
    }
}

Läsa från en producent

Med ? extends Number kan du säkert läsa element som Number.

Oavsett vilken den faktiska elementtypen är garanteras den vara minst en Number, så läsningen är typsäker.

import java.util.List;

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

Det går inte att skriva till den

Här är haken: du kan inte lägga till element i en lista av typen ? extends Number (förutom null).

Kompilatorn känner inte till den exakta elementtypen. Det kan vara en List<Integer>, så det skulle vara osäkert att lägga till en Double.

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

public class Main {
    public static void main(String[] args) {
        List<? extends Number> list = new ArrayList<Integer>();
        // list.add(1);   // does NOT compile
        // list.add(1.5); // does NOT compile
        System.out.println("Cannot add to ? extends Number");
        System.out.println("size = " + list.size());
    }
}

Varför skrivning inte är tillåten

Föreställ dig att det vore tillåtet. Du skulle kunna skicka in en List<Integer> som List<? extends Number> och sedan lägga till en Double.

Kod som senare läser listan som List<Integer> skulle få ett ClassCastException. Kompilatorn förhindrar detta genom att förbjuda skrivning.

import java.util.List;

public class Main {
    public static void main(String[] args) {
        // Conceptual: this is why add is blocked
        System.out.println("Writing a Double into a List<Integer> would corrupt it");
        System.out.println("so ? extends bans all adds");
    }
}

Användningsfall för producent

Använd ? extends T när en metod bara producerar (läser ut) värden åt dig.

En metod som kopierar ut element från en källsamling är ett perfekt exempel.

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

public class Main {
    static List<Number> copyOut(List<? extends Number> source) {
        List<Number> dest = new ArrayList<>();
        for (Number n : source) dest.add(n);
        return dest;
    }
    public static void main(String[] args) {
        System.out.println(copyOut(List.of(1, 2, 3)));
    }
}

Begränsade typparametrar jämfört med wildcards

Blanda inte ihop <T extends Number> (en begränsad typparameter) med ? extends Number (ett wildcard).

  • Typparameter: namnger typen så att den kan användas i hela metoden.
  • Wildcard: en anonym, okänd subtyp som används när du inte behöver namnge den.
import java.util.List;

public class Main {
    static <T extends Number> T first(List<T> list) { return list.get(0); }
    public static void main(String[] args) {
        Integer i = first(List.of(10, 20));
        System.out.println(i);
    }
}

Flera begränsningar

En typparameter kan ha flera begränsningar med &, till exempel <T extends Number & Comparable<T>>.

Wildcards stöder bara en enda övre begränsning, så flera begränsningar kräver en namngiven typparameter.

import java.util.List;

public class Main {
    static <T extends Number & Comparable<T>> T max(List<T> list) {
        T best = list.get(0);
        for (T t : list) if (t.compareTo(best) > 0) best = t;
        return best;
    }
    public static void main(String[] args) {
        System.out.println(max(List.of(3, 9, 1, 7)));
    }
}

Wildcards med Collections.max

JDK använder övre begränsningar i stor utsträckning. Till exempel för att summera eller gå igenom en skrivskyddad samling.

Här hittar vi det största elementet i en lista som är typad som en producent.

import java.util.List;

public class Main {
    static double largest(List<? extends Number> nums) {
        double max = Double.NEGATIVE_INFINITY;
        for (Number n : nums) max = Math.max(max, n.doubleValue());
        return max;
    }
    public static void main(String[] args) {
        System.out.println(largest(List.of(4, 2, 9, 1)));
        System.out.println(largest(List.of(0.5, 9.9, 3.3)));
    }
}

Null är det enda skrivbara värdet

Det enda du kan lägga till i en samling av typen ? extends T är null, eftersom null kan tilldelas till alla referenstyper.

Detta är sällan användbart, men förklarar varför add inte är helt förbjudet, utan bara i praktiken inte kan användas.

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

public class Main {
    public static void main(String[] args) {
        List<? extends Number> list = new ArrayList<Number>();
        // Only null is assignable; demonstrated conceptually
        System.out.println("Only null could be added; we avoid that");
        System.out.println("size = " + list.size());
    }
}

Det går alltid att läsa ut som Object

Eftersom alla typer ärver från Object kan du alltid läsa element från valfri wildcard-lista som Object.

Med en övre begränsning på Number får du dessutom fördelen att läsa dem direkt som Number.

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<? extends Number> nums = List.of(1, 2.0, 3L);
        for (Object o : nums) System.out.println(o.getClass().getSimpleName());
    }
}

Snabbkontroll

Testa din förståelse av övre begränsningar.

Sammanfattning

Du har lärt dig wildcards med övre begränsning:

  • ? extends T betyder en okänd subtyp av T.
  • Du kan läsa element som T (en producent).
  • Du kan inte lägga till element som inte är null.
  • Generics är invarianta, och wildcards gör dem mer flexibla på ett säkert sätt.

Nästa steg är spegelbilden: wildcards med nedre begränsning.

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<? extends Number> nums = List.of(1, 2, 3);
        System.out.println("Upper bound recap: read " + nums.get(0));
    }
}
Gratis att börja

Lär dig Java med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
104
Lektioner
374

Vanliga frågor

Är lektionen ”Övre begränsade wildcards” gratis?

Ja – hela texten till ”Övre begränsade wildcards” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Java Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i Java Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Övre begränsade wildcards”?

? extends T för producenter. Ni övar på Java Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Java Academy?

Du behöver inga förkunskaper. Utbildningen i Java Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 1 av 4.

Hur lång tid tar lektionen ”Övre begränsade wildcards”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Java Academy-lektionen?

Ja. Varje Java Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Övre begränsade wildcards
  2. Undre begränsade wildcards
  3. PECS-principen
  4. Wildcards i API:er
← Tillbaka till Java Academy