Curingas com limite superior
? extends T para produtores.
Curingas com limite superior é uma aula grátis de Java Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Java Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Java Academy inclui 4 aulas no total.
Os genéricos são invariantes
Em Java, os genéricos são invariantes. Uma List<Integer> não é uma List<Number>, embora Inteiro seja um Número.
Isso surpreende quem está começando, mas mantém o sistema de tipos seguro. Os curingas relaxam essa restrição com segurança.
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);
}
}O curinga com limite superior
? extends T é um curinga com limite superior. Isso significa algum tipo desconhecido que seja o tipo indicado ou um subtipo dele.
List<? extends Number> pode fazer referência a uma List<Integer>, a uma List<Double> ou a uma 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));
}
}Lendo de um produtor
Com ? extends Number, você pode ler elementos com segurança como Number.
Seja qual for o tipo real dos elementos, é garantido que ele é pelo menos um Número; portanto, a leitura é segura quanto aos tipos.
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)));
}
}Não é possível escrever nele
Aqui está o ponto importante: você não pode adicionar elementos a uma lista ? extends Number (exceto nulo).
O compilador não conhece o tipo exato do elemento. Ela poderia ser uma List<Integer>, portanto adicionar um Double seria inseguro.
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());
}
}Por que não é permitido escrever
Imagine se isso fosse permitido. Você poderia passar uma List<Integer> como List<? extends Number> e depois adicionar um Double.
Mais tarde, o código que lesse a lista como List<Integer> obteria uma ClassCastException. O compilador evita isso proibindo operações de escrita.
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 de uso de produtor
Use ? extends T quando um método apenas produz valores para você, ou seja, quando apenas os lê.
Um método que copia elementos de uma coleção de origem é um exemplo perfeito.
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)));
}
}Parâmetros de tipo limitados versus curingas
Não confunda <T extends Number> (um parâmetro de tipo limitado) com ? extends Number (um curinga).
- Parâmetro de tipo: dá nome ao tipo para que ele seja usado em todo o método.
- Curinga: um subtipo desconhecido e anônimo, usado quando não é necessário dar um nome a ele.
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);
}
}Vários limites
Um parâmetro de tipo pode ter vários limites usando &, como em <T extends Number & Comparable<T>>.
Os curingas aceitam apenas um único limite superior, portanto vários limites exigem um parâmetro de tipo nomeado.
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)));
}
}Curingas com Collections.max
O JDK usa limites superiores amplamente. Por exemplo, ao somar valores ou percorrer uma coleção somente para leitura.
Aqui encontramos o maior elemento de uma lista tipada como produtora.
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)));
}
}Nulo é o único valor gravável
A única coisa que você pode adicionar a uma coleção ? extends T é null, porque nulo pode ser atribuído a qualquer tipo de referência.
Isso raramente é útil, mas explica por que add não é completamente proibido, apenas na prática.
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());
}
}Ler como Object sempre funciona
Como todo tipo é um subtipo de Object, você sempre pode ler os elementos de qualquer lista com curinga como Object.
Com um limite superior de Number, você ainda pode lê-los diretamente como um tipo numérico.
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ção rápida
Teste sua compreensão dos limites superiores.
Recapitulação
Você aprendeu sobre curingas com limite superior:
? extends Tsignifica um subtipo desconhecido de T.- Você pode ler elementos como T (um produtor).
- Você não pode adicionar elementos que não sejam nulos.
- Os tipos genéricos são invariantes, e os curingas relaxam essa regra com segurança.
A seguir, a imagem espelhada: curingas com limite inferior.
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));
}
}Perguntas Frequentes
A aula “Curingas com limite superior” é grátis?
Sim — o texto completo de “Curingas com limite superior” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Java Academy, atualize para CoddyKit PRO. O curso de Java Academy inclui 4 aulas no total.
O que vou aprender em “Curingas com limite superior”?
? extends T para produtores. Você pratica Java Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Java Academy?
Nenhuma experiência prévia é necessária. Java Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.
Quanto tempo leva a aula “Curingas com limite superior”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Java Academy?
Sim. Cada aula de Java Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Curingas com limite superior
- Curingas com limite inferior
- O princípio PECS
- Curingas em APIs