Principais habilidades e conceitos abordados
Vantagens dos tipos genéricos
- Reutilização de código de maneira segura e confiável.
- Eliminação de coerções manuais e redução de erros de discrepância de tipos.
Criação de classes, métodos, construtores e interfaces genéricas
- Uso de tipos parametrizados .
- Definição de classes e métodos que funcionam com múltiplos tipos de dados.
Parâmetros de tipo limitado
- Restrição do tipo genérico com extends para herança ou implementação de interfaces.
Uso de curingas e curingas limitados
- Flexibilidade no trabalho com tipos desconhecidos (?).
- Curingas com limites superior (? extends) e inferior (? super).
Tipos brutos
- Uso de classes genéricas sem especificar o tipo, com advertências de segurança.
Inferência de tipos com o operador losango (<>)
- Redução de redundância na definição de tipos ao criar objetos genéricos.
Entendimento da técnica de erasure
- Como o compilador traduz genéricos para código baseado em Object.
Restrições e ambiguidades dos genéricos
- Limitações, como a não utilização de tipos primitivos diretamente.
- Questões relacionadas à compatibilidade e herança.
Exemplos de código
Classe genérica básica
// Classe genérica com tipo parametrizado T
class Caixa<T> {
private T valor;
public void adicionar(T valor) {
this.valor = valor;
}
public T obter() {
return valor;
}
}
// Uso da classe genérica
Caixa<String> caixaTexto = new Caixa<>();
caixaTexto.adicionar("Olá, Genéricos!");
System.out.println(caixaTexto.obter());
Método genérico
// Método genérico que troca dois elementos em um array
public static <T> void trocar(T[] array, int i, int j) {
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
// Uso do método genérico
Integer[] numeros = {1, 2, 3, 4};
trocar(numeros, 1, 3);
System.out.println(Arrays.toString(numeros)); // Saída: [1, 4, 3, 2]
Curinga limitado
// Soma elementos de uma lista de números (ou subclasses de Number)
public static double somaLista(List<? extends Number> lista) {
double soma = 0.0;
for (Number numero : lista) {
soma += numero.doubleValue();
}
return soma;
}
// Uso do curinga limitado
List<Integer> inteiros = Arrays.asList(1, 2, 3);
System.out.println(somaLista(inteiros)); // Saída: 6.0
Inferência de tipo com losango
// Inferência de tipo ao criar um ArrayList genérico
List<String> lista = new ArrayList<>();
lista.add("Java");
lista.add("Genéricos");
System.out.println(lista);
Interface genérica
// Interface genérica
interface Pilha<T> {
void push(T item);
T pop();
}
// Implementação da interface genérica
class PilhaArray<T> implements Pilha<T> {
private List<T> itens = new ArrayList<>();
public void push(T item) {
itens.add(item);
}
public T pop() {
return itens.isEmpty() ? null : itens.remove(itens.size() - 1);
}
}
Construtor genérico
class Par<T, U> {
private T primeiro;
private U segundo;
// Construtor genérico
public <V> Par(V valor, T primeiro, U segundo) {
System.out.println("Valor adicional: " + valor);
this.primeiro = primeiro;
this.segundo = segundo;
}
}
Pontos importantes sobre os genéricos em Java
- Segurança de tipos: Reduz riscos ao evitar erros de tempo de execução com conversões inadequadas.
- Tipos primitivos: Não podem ser usados diretamente nos genéricos, mas podem ser utilizados com wrappers (e.g., Integer para int).
- Limitação com erasure: Durante a compilação, o tipo genérico é substituído por Object ou o limite especificado (e.g., extends).
- Curingas poderosos: Permitem flexibilidade ao trabalhar com tipos desconhecidos, mantendo a segurança de tipos.
Esses conceitos tornam os genéricos uma ferramenta essencial para criar código reutilizável, eficiente e seguro em Java.
--
Top comments (0)