Jokers à borne supérieure
? extends T pour les producteurs
Jokers à borne supérieure est une leçon Java Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Java Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Java Academy comprend 4 leçons au total.
Les génériques sont invariants
En Java, les génériques sont invariants. Une List<Integer> n’est pas une List<Number>, même si un entier est un nombre.
Cela surprend les débutants, mais garantit la cohérence du système de types. Les jokers assouplissent cette restriction en toute sécurité.
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);
}
}Le joker à borne supérieure
? extends T est un joker à borne supérieure. Cela signifie « un type inconnu qui est T ou un sous-type de T ».
List<? extends Number> peut désigner une List<Integer>, une List<Double> ou une 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));
}
}Lire depuis un producteur
Avec ? extends Number, vous pouvez lire les éléments en tant que Number.
Quel que soit le type réel des éléments, il est garanti qu’il est au moins de type numérique ; la lecture est donc sûre du point de vue des types.
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)));
}
}Vous ne pouvez pas y écrire
Voici le piège : vous ne pouvez pas ajouter d’éléments à une liste ? extends Number (sauf null).
Le compilateur ne connaît pas le type exact des éléments. Il pourrait s’agir d’une List<Integer>, et ajouter un Double serait donc dangereux.
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());
}
}Pourquoi l’écriture est interdite
Imaginez que cela soit autorisé. Vous pourriez transmettre une List<Integer> comme List<? extends Number>, puis ajouter un Double.
Du code exécuté plus tard, qui lirait la liste comme une List<Integer>, obtiendrait une ClassCastException. Le compilateur empêche cela en interdisant les écritures.
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");
}
}Cas d’utilisation d’un producteur
Utilisez ? extends T lorsqu’une méthode ne fait que produire des valeurs (les lire) pour vous.
Une méthode qui copie des éléments depuis une collection source en est un exemple parfait.
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)));
}
}Paramètres de type bornés et caractères génériques
Ne confondez pas <T extends Number> (un paramètre de type borné) avec ? extends Number (un caractère générique).
- Paramètre de type : il nomme le type afin de pouvoir l’utiliser dans toute la méthode.
- Caractère générique : c’est un sous-type anonyme et inconnu, utilisé lorsqu’il n’est pas nécessaire de lui donner un nom.
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);
}
}Bornes multiples
Un paramètre de type peut avoir plusieurs bornes avec &, comme <T extends Number & Comparable<T>>.
Les caractères génériques n’acceptent qu’une seule borne supérieure ; plusieurs bornes nécessitent donc un paramètre de type nommé.
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)));
}
}Caractères génériques avec Collections.max
Le JDK utilise largement les bornes supérieures, par exemple pour additionner les éléments d’une collection en lecture seule ou y effectuer une recherche.
Ici, nous trouvons le plus grand élément d’une liste utilisée comme producteur.
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 est la seule valeur inscriptible
La seule chose que vous puissiez ajouter à une collection ? extends T est null, car null peut être affecté à n’importe quel type référence.
C’est rarement utile, mais cela explique pourquoi add n’est pas totalement interdit : il est seulement inutilisable en pratique.
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());
}
}Lire renvoie toujours un objet
Comme tout type étend Object, vous pouvez toujours lire les éléments de n’importe quelle liste utilisant un caractère générique comme Object.
Avec une borne supérieure de Number, vous bénéficiez en plus de la possibilité de les lire directement comme 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());
}
}Vérification rapide
Testez votre compréhension des bornes supérieures.
Récapitulatif
Vous avez appris les caractères génériques à borne supérieure :
? extends Tdésigne un sous-type inconnu de T.- Vous pouvez lire les éléments comme T (un producteur).
- Vous ne pouvez pas ajouter d’éléments non nuls.
- Les types génériques sont invariants, et les caractères génériques assouplissent cette règle en toute sécurité.
Ensuite, nous verrons l’image miroir : les caractères génériques à borne inférieure.
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));
}
}Questions Fréquemment Posées
La leçon « Jokers à borne supérieure » est-elle gratuite ?
Oui — le texte complet de « Jokers à borne supérieure » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Java Academy, passe à CoddyKit PRO. Le cours Java Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Jokers à borne supérieure » ?
? extends T pour les producteurs Tu pratiques Java Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Java Academy ?
Aucune expérience préalable n'est requise. Java Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.
Combien de temps prend la leçon « Jokers à borne supérieure » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Java Academy ?
Oui. Chaque leçon Java Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Jokers à borne supérieure
- Jokers à borne inférieure
- Principe PECS
- Jokers dans les API