Java Academy · Lezione

Wildcard con limite superiore

? extends T per i produttori

Lezione 1 di 413 passaggi

Wildcard con limite superiore è una lezione Java Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Java Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Java Academy include 4 lezioni in totale.

I generics sono invarianti

In Java, i generics sono invarianti. Una List<Integer> non è una List<Number>, anche se Integer è un Number.

Questo sorprende chi è alle prime armi, ma mantiene coerente il sistema dei tipi. I wildcard attenuano questa restrizione in modo sicuro.

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);
    }
}

Il wildcard con limite superiore

? extends T è un wildcard con limite superiore. Significa "un tipo sconosciuto qualsiasi che sia T o un sottotipo di T".

List<? extends Number> può riferirsi a una List<Integer>, a una List<Double> o a una 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));
    }
}

Lettura da un produttore

Con ? extends Number può leggere in sicurezza gli elementi come Number.

Qualunque sia il tipo effettivo degli elementi, è garantito che sia Number o un suo sottotipo, quindi la lettura è sicura dal punto di vista dei tipi.

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)));
    }
}

Non è possibile scrivere al suo interno

Ecco il punto: non è possibile aggiungere elementi a una lista ? extends Number (tranne null).

Il compilatore non conosce il tipo esatto degli elementi. Potrebbe trattarsi di una List<Integer>, quindi aggiungere un Double non sarebbe sicuro.

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());
    }
}

Perché la scrittura è vietata

Immagini che fosse consentito. Si potrebbe passare una List<Integer> come List<? extends Number> e poi aggiungere un Double.

Il codice eseguito successivamente, leggendo la lista come List<Integer>, riceverebbe una ClassCastException. Il compilatore lo impedisce vietando le operazioni di scrittura.

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");
    }
}

Caso d'uso del produttore

Utilizzi ? extends T quando un metodo si limita a produrre valori per Lei, cioè a leggerli.

Un metodo che copia elementi da una raccolta sorgente è un esempio perfetto.

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)));
    }
}

Parametri di tipo con limite e wildcard

Non confonda <T extends Number> (un parametro di tipo con limite) con ? extends Number (una wildcard).

  • Parametro di tipo: assegna un nome al tipo da usare in tutto il metodo.
  • Wildcard: un sottotipo anonimo e sconosciuto, usato quando non è necessario assegnargli un nome.
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);
    }
}

Limiti multipli

Un parametro di tipo può avere più limiti usando &, ad esempio <T extends Number & Comparable<T>>.

Le wildcard supportano un solo limite superiore, quindi per usare più limiti è necessario un parametro di tipo con nome.

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)));
    }
}

Wildcard con Collections.max

Il JDK usa ampiamente i limiti superiori, ad esempio per sommare o analizzare una raccolta in sola lettura.

Qui troviamo l'elemento più grande di una lista tipizzata come produttore.

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 è l'unico valore scrivibile

L'unico elemento che può aggiungere a una raccolta ? extends T è null, perché null è assegnabile a qualsiasi tipo di riferimento.

È raramente utile, ma spiega perché l'operazione add non sia completamente vietata, bensì lo sia di fatto.

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());
    }
}

La lettura come Object funziona sempre

Poiché ogni tipo estende Object, è sempre possibile leggere gli elementi di qualsiasi lista con wildcard come Object.

Con un limite superiore pari a Number, si ottiene inoltre il vantaggio di poterli leggere direttamente come 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());
    }
}

Verifica rapida

Verifichi la Sua comprensione dei limiti superiori.

Riepilogo

Ha imparato a usare le wildcard con limite superiore:

  • ? extends T indica un sottotipo sconosciuto di T.
  • È possibile leggere gli elementi come T (un produttore).
  • Non è possibile aggiungere elementi diversi da null.
  • I generics sono invarianti e le wildcard rilassano questa regola in modo sicuro.

Ora vediamo l'immagine speculare: le wildcard con limite inferiore.

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 per iniziare

Impara Java con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
104
Lezioni
374

Domande Frequenti

La lezione «Wildcard con limite superiore» è gratuita?

Sì — il testo completo di «Wildcard con limite superiore» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Java Academy, passa a CoddyKit PRO. Il corso Java Academy include 4 lezioni in totale.

Cosa imparerò in «Wildcard con limite superiore»?

? extends T per i produttori Eserciti Java Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Java Academy?

Non è richiesta alcuna esperienza precedente. Java Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.

Quanto tempo richiede la lezione «Wildcard con limite superiore»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Java Academy?

Sì. Ogni lezione Java Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Wildcard con limite superiore
  2. Wildcard con limite inferiore
  3. Il principio PECS
  4. Wildcard nelle API
← Torna a Java Academy