O que significa a natureza genérica da classe? O que é T?
Class
, só há um objecto. Então, porquê o parâmetro T
? O que está a especificar? E por que é necessário (se é)?
4 answers
O parâmetro do tipo <T>
foi adicionado a java.lang.Class
para permitir um idioma específico.1 - utilização de Class
objectos como fábricas de objectos seguros do tipo. Essencialmente, a adição de <T>
permite-lhe instanciar classes de uma forma segura de tipo, como esta:
T instance = myClass.newInstance();
O parâmetro do tipo <T>
representa a própria classe, permitindo-lhe evitar efeitos desagradáveis do tipo de apagamento, armazenando Class<T>
numa classe genérica ou passando-a como parâmetro para um método genérico. Note que T
por si só não seria suficiente para completar esta tarefa2: o tipo de T
é apagado, por isso torna-se java.lang.Object
debaixo do capô.
Aqui está um exemplo clássico onde {[[2]} parâmetro da classe se torna importante. No exemplo abaixo, o compilador Java é capaz de garantir a segurança do tipo, permitindo que você produza uma coleção digitada de uma string SQL e uma instância de Class<T>
. Note-se que a classe é utilizada como uma fábrica , e que a sua segurança de tipo pode ser verificada na compilação tempo:
public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
Collection<T> result = new ArrayList<T>();
/* run sql query using jdbc */
for ( /* iterate over jdbc results */ ) {
T item = c.newInstance();
/* use reflection and set all of item’s fields from sql results */
result.add(item);
}
return result;
}
Desde que Java apaga o parâmetro do tipo, tornando-o um java.lang.Object
ou uma classe especificada como o genérico limite superior , é importante ter acesso ao objecto Class<T>
dentro do método select
. Uma vez que newInstance
devolve um objecto do tipo <T>
, o compilador pode efectuar a verificação do tipo, eliminando um molde.
1
2 isto é diferente de implementações de genéricos sem apagamento de tipo, como um em. NET.
3Java Generics tutorial by Oracle.
A resposta de dasblinkenlight já demonstrou uma das principais utilizações deste parâmetro. Há mais um aspecto que considero relevante: usando esse parâmetro, você pode restringir o tipo de classe que deseja passar em um determinado local. Por isso, por exemplo
Class<? extends Number> cls
Significa que cls
pode ser qualquer classe que implemente a interface Number
. Isso pode ajudar a capturar certos erros no tempo de compilação, e torna os requisitos de argumento de classe mais explícitos.
// Java ≥5 with generics // Java <5 style without generics
Class<? extends Foo> c; Class c;
Foo t1 = c.newInstance(); Foo t1 = (Foo)c.newInstance();
Object obj; Object obj;
Foo t2 = c.cast(obj); Foo t2 = (Foo)c.cast(obj);
Como podes ver, não ter T
como argumento exigiria uma série de moldes explícitos, pois os métodos correspondentes teriam de retornar Object
em vez de T
. Se Foo
em si é um argumento de tipo genérico, então todos os moldes seriam desligados, resultando em uma sequência de avisos de compilador. Você pode suprimi - los, mas a questão central permanece: o compilador não pode verificar a validade destes moldes a menos que você use corretamente o tipo argumento.
Em Java há um único metaclass: {[[0]}. Suas instâncias (somente uma por tipo existe) são usados para representar classes e interfaces, portanto, o T
em Class<T>
refere-se a tipo da classe ou interface que a instância atual do Class
representa.
O uso de genéricos no tipo de classe é de topo definir o tipo de classe. Se eu tiver 'classe obj' o meu objeto obj pode ter apenas filhos de Charsequência. Este é um argumento opcional. Sou muitas vezes posto um "an"? para evitar avisos da IDE do Eclipse se eu não precisar de um tipo específico de classe.