Home Generics em Java
Post
Cancelar

Generics em Java

Baseado nos cursos da Softblue

Introdução

  • O Generics foi introduzido a partir do Java 5

  • Similar aos templates em C++

  • Permitem a parametrização de tipos de dados

Sem generics:

1
2
3
4
5
List strings = new ArrayList();
strings.add("abc");
strings.add("def"); 
strings.add(new Integer(1));
String s = (String) strings.get(0);

Com generics:

1
2
3
4
5
List<String> strings = new ArrayList<String>();
strings.add("abc");
strings.add("def"); 
strings.add(new Integer(1)); //Não compila porque o objeto não é uma String
String s = strings.get(0);

Definindo uma classe com generics

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Gerenciador {
	
	private Object obj; //O uso de Object possibilita que qualquer objeto seja utilizado
	
	public void setObjeto(Object obj) {
		this.obj = obj;
	}

	public Object getObjeto() {
		return obj;
	}
}

Casa c = new Casa();
Gerenciador g = new Gerenciador();

g.setObjeto(c);
c = (Casa) g.getObjeto();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Gerenciador<T> {
	
	private T obj; //Agora o tipo do dado é parametrizável

	public void setObjeto(T obj) {
		this.obj = obj;
	}

	public T getObjeto() {
		return obj;
	}
}

Casa c = new Casa();
Gerenciador<Casa> g = new Gerenciador<Casa>();

g.setObjeto(c); //Apenas uma instância de Casa pode ser fornecida
c = g.getObjeto(); //O casting não é necessário

Generics e as subclasses

  • Suponha que existem as classes

– Animal

– Cachorro (estende de Animal)

  • O código abaixo funciona normalmente
1
2
3
4
Cachorro[] cachorros = new Cachorro[2];
cachorros[0] = new Cachorro();
cachorros[1] = new Cachorro();
Animal[] animais = cachorros; //É possível atribuir um array de Cachorro a um array de Animal devido à herança

O mesmo código usando generics:

1
2
3
4
List<Cachorro> cachorros = new ArrayList<Cachorro>();
cachorros.add(new Cachorro());
cachorros.add(new Cachorro());
List<Animal> animais = cachorros; //Não é possível atribuir, mesmo sendo uma lista da subclasse
  • Em generics, a atribuição só pode ser feita se o tipo parametrizado é o mesmo

Wildcard

  • Utilizado para deixar em aberto o tipo parametrizado

  • Representado por “?”

1
2
3
4
5
public void imprimir(Collection<?> c) { //A coleção pode ser de qualquer tipo
	for(Object o : c) {
		System.out.println(o);
	}
}

Wildcard e o extends

  • Quando é necessário deixar o tipo do dado em aberto mas garantir que este tipo deve estender de determinada classe, é possível usar o extends
1
2
3
4
5
public void imprimir(Collection<? extends Animal> c) { //A coleção pode ser de qualquer tipo que seja uma subclasse de Animal ou a própria classe Animal
	for(Animal a : c) {
		a.andar();
	}
}
  • Quando a restrição deve ser feita a classes que implementam uma interface, o extends também é usado
1
2
3
public void imprimir(Collection<? extends Comparable> c) { //Comparable é uma interface, mas o extends é usado mesmo assim
	//...
}

Quando o extends é usado, não é possível adicionar elementos

Wildcard e o super

  • Quando é necessário deixar o tipo do dado em aberto mas garantir que este tipo deve ter uma determinada superclasse, é possível usar o super
1
2
3
public void imprimir(Collection<? super Cachorro> c) { //A coleção pode ser de qualquer tipo que seja uma superclasse de Cachorro ou a própria classe Cachorro
	//...
}

Quando o super é usado, a coleção pode receber novos elementos

Definindo métodos com generics

  • Além do tipo parametrizado poder ser definido a nível de classe, ele também pode ser definido a nível de método
1
2
3
4
5
6
7
8
private <T> List<T> criarLista(T e) { //T é o tipo parametrizado
	List<T> l = new ArrayList<T>();
	l.add(e);
	return l;
}

List<String> l1 = criarLista("a");
List<Integer> l2 = criarLista(2); //A lista é criada e retornada com o tipo do parâmetro
Esta postagem está licenciada sob CC BY 4.0 pelo autor.