什么是泛型?
Source: Dev.to
Generics 是在 Java 5 中引入的一项功能,允许创建能够处理不同数据类型的类、接口和方法。它们消除了显式类型转换(cast)的需求,并帮助在编译时检测错误。
在 Java 5 之前,集合把所有元素都当作 Object 处理。这会导致两个问题:
- 过度强制转换: 每次从列表中取出元素都需要进行
(String)强制转换。 - 不安全性: 没有任何机制阻止向本应只包含
String的列表中插入Integer,从而在运行时产生错误。
// Código antigo
List lista = new ArrayList(); // Lista "crua" (Raw Type)
lista.add("Olá");
lista.add(10); // O compilador deixa passar!
// O erro só acontece aqui, quando o programa está rodando:
String texto = (String) lista.get(1); // ClassCastException!
// Código novo com Generics
List lista = new ArrayList<>();
lista.add("Olá");
// lista.add(10); // O compilador nem deixa compilar. Erro na hora!
String texto = lista.get(0); // Sem necessidade de cast manual.
类型变量
Generics 允许类和方法在多种类型的对象上操作,确保编译时安全(compile‑time safety)。约定上,我们使用大写字母来表示这些泛型类型:
T: Type(类型)E: Element(元素,常用于集合)K,V: Key, Value(键、值,常用于映射)
泛型类
泛型类使用 类型参数 T,它充当实际类型的占位符。
// define que esta classe aceita um parâmetro de tipo
public class Caixa<T> {
private T conteudo;
public void guardar(T conteudo) {
this.conteudo = conteudo;
}
public T abrir() {
return conteudo;
}
}
public class AulaGenerics {
public static void main(String[] args) {
// Caixa que só aceita Strings
Caixa<String> caixaDeTexto = new Caixa<>();
caixaDeTexto.guardar("Segredo");
// caixaDeTexto.guardar(123); // Erro de compilação!
// Caixa que só aceita Inteiros
Caixa<Integer> caixaDeNumeros = new Caixa<>();
caixaDeNumeros.guardar(100);
}
}
T 在创建对象时会被 String、Integer 或其他类型替代。
通配符
Os wildcards (?) 代表在泛型中未知的类型,并且对于创建接受不同集合类型的方法非常有用。
?– 任意类型。? extends T(upper bounded) – 接受T或任何 子类型 的T。用法: 当只想 读取 数据时。? super T(lower bounded) – 接受T或任何 父类型 的T。用法: 当想 写入 数据时。
实际示例
import java.util.*;
public class Wildcards {
// Aceita lista de Number OU QUALQUER SUBTIPO (Integer, Double...)
// Só consigo LER com segurança (sei que tudo ali é Number)
public static double somarLista(List lista) {
double soma = 0;
for (Number n : lista) { // Posso ler como Number
soma += n.doubleValue();
}
// lista.add(10); // ERRO! Não posso adicionar nada (não sei se é lista de Double ou Integer)
return soma;
}
public static void main(String[] args) {
List inteiros = new ArrayList<>();
inteiros.add(1);
inteiros.add(2);
List doubles = new ArrayList<>();
doubles.add(1.5);
doubles.add(2.5);
// O método aceita ambos!
System.out.println(somarLista(inteiros));
System.out.println(somarLista(doubles));
}
}
Type Erasure
泛型仅供 编译器 使用。编译后,Java 会 擦除(type erasure)所有泛型信息,并用 Object(或上限)替代,同时自动插入强制类型转换。在运行时,List 与 List 是同一个类(List)。此策略是为了保持与早期 Java 版本的兼容性。