Tudo o que sabemos é " Todas as instâncias de qualquer classe compartilham o mesmo objeto java.lang.Class desse tipo de classe "
por exemplo)
Student a = new Student();
Student b = new Student();
Então a.getClass() == b.getClass()
é verdade.
Agora assuma
Teacher t = new Teacher();
sem genéricos, o abaixo é possível.
Class studentClassRef = t.getClass();
Mas isso está errado agora ..?
por exemplo) public void printStudentClassInfo(Class studentClassRef) {}
pode ser chamado comTeacher.class
Isso pode ser evitado usando genéricos.
Class<Student> studentClassRef = t.getClass(); //Compilation error.
Agora, o que é T ?? T é parâmetros de tipo (também chamados de variáveis de tipo); delimitado por colchetes angulares (<>), segue o nome da classe.
T é apenas um símbolo, como um nome de variável (pode ser qualquer nome) declarado durante a gravação do arquivo de classe. Posteriormente, T será substituído por
um nome de classe válido durante a inicialização ( HashMap<String> map = new HashMap<String>();
)
por exemplo) class name<T1, T2, ..., Tn>
Então Class<T>
representa um objeto de classe de tipo de classe específico 'T
'.
Suponha que seus métodos de classe funcionem com parâmetros de tipo desconhecido, como abaixo
/**
* Generic version of the Car class.
* @param <T> the type of the value
*/
public class Car<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Aqui T pode ser usado como String
tipo como CarName
OR T pode ser usado como Integer
tipo como modelNumber ,
OR T pode ser usado como Object
tipo como instância de carro válida .
Agora, aqui está o POJO simples, que pode ser usado de maneira diferente em tempo de execução.
Coleções, por exemplo) List, Set, Hashmap são os melhores exemplos que funcionarão com objetos diferentes conforme a declaração de T, mas uma vez que declaramos T como String,
por exemplo) HashMap<String> map = new HashMap<String>();
Então, ele aceitará apenas objetos de instância da Classe String.
Métodos genéricos
Métodos genéricos são métodos que apresentam seus próprios parâmetros de tipo. Isso é semelhante a declarar um tipo genérico, mas o escopo do parâmetro type é limitado ao método em que é declarado. Métodos genéricos estáticos e não estáticos são permitidos, bem como construtores de classes genéricos.
A sintaxe de um método genérico inclui um parâmetro de tipo, entre colchetes angulares, e aparece antes do tipo de retorno do método. Para métodos genéricos, a seção de parâmetro type deve aparecer antes do tipo de retorno do método.
class Util {
// Generic static method
public static <K, V, Z, Y> boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
class Pair<K, V> {
private K key;
private V value;
}
Aqui <K, V, Z, Y>
está a declaração dos tipos usados nos argumentos do método que deveriam antes do tipo de retorno que está boolean
aqui.
No abaixo; declaração de tipo <T>
não é necessária no nível do método, pois já está declarada no nível da classe.
class MyClass<T> {
private T myMethod(T a){
return a;
}
}
Mas abaixo está errado, pois os parâmetros do tipo de classe K, V, Z e Y não podem ser usados em um contexto estático (método estático aqui).
class Util <K, V, Z, Y>{
// Generic static method
public static boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
OUTROS CENÁRIOS VÁLIDOS SÃO
class MyClass<T> {
//Type declaration <T> already done at class level
private T myMethod(T a){
return a;
}
//<T> is overriding the T declared at Class level;
//So There is no ClassCastException though a is not the type of T declared at MyClass<T>.
private <T> T myMethod1(Object a){
return (T) a;
}
//Runtime ClassCastException will be thrown if a is not the type T (MyClass<T>).
private T myMethod1(Object a){
return (T) a;
}
// No ClassCastException
// MyClass<String> obj= new MyClass<String>();
// obj.myMethod2(Integer.valueOf("1"));
// Since type T is redefined at this method level.
private <T> T myMethod2(T a){
return a;
}
// No ClassCastException for the below
// MyClass<String> o= new MyClass<String>();
// o.myMethod3(Integer.valueOf("1").getClass())
// Since <T> is undefined within this method;
// And MyClass<T> don't have impact here
private <T> T myMethod3(Class a){
return (T) a;
}
// ClassCastException for o.myMethod3(Integer.valueOf("1").getClass())
// Should be o.myMethod3(String.valueOf("1").getClass())
private T myMethod3(Class a){
return (T) a;
}
// Class<T> a :: a is Class object of type T
//<T> is overriding of class level type declaration;
private <T> Class<T> myMethod4(Class<T> a){
return a;
}
}
E, finalmente, o método estático sempre precisa de <T>
declaração explícita ; Não deriva do nível de classe Class<T>
. Isso ocorre porque o nível de classe T está vinculado à instância.
Leia também Restrições sobre genéricos
Curingas e Subtipagem
argumento de tipo para um método genérico
Na documentação Java:
[...] Surpreendentemente, a classe Class foi gerada. Os literais de classe agora funcionam como tokens de tipo, fornecendo informações sobre os tipos de tempo de execução e tempo de compilação. Isso permite um estilo de fábricas estáticas exemplificadas pelo método getAnnotation na nova interface AnnotatedElement:
Este é um método genérico. Ele infere o valor do parâmetro de tipo T do argumento e retorna uma instância apropriada de T, conforme ilustrado pelo seguinte trecho:
Antes dos genéricos, você teria que transmitir o resultado ao autor. Além disso, você não teria como fazer com que o compilador verifique se o parâmetro real representa uma subclasse de Anotação. [...]
Bem, eu nunca tive que usar esse tipo de coisa. Qualquer um?
fonte
Class<? extends X>
notação que imaginei, poderia limitá-la apenas aos tipos de 'serviço'. Exceto que não havia um tipo comum de 'serviço', então eu só poderia fazê-loClass<?>
. Alas.Eu achei
class<T>
útil quando crio pesquisas de registro de serviço. Por exemplofonte
Como outras respostas apontam, há muitas e boas razões pelas quais isso
class
foi tornado genérico. No entanto, há muitas vezes que você não tem como saber o tipo genérico para usarClass<T>
. Nesses casos, você pode simplesmente ignorar os avisos do eclipse amarelo ou pode usarClass<?>
... É assim que eu faço;)fonte
@SuppressWarnings("unchecked")
vem para o resgate! (Apenas tenha cuidado para sempre aplicá-lo ao menor escopo possível, pois isso oculta problemas em potencial no seu código.)Seguindo a resposta de @Kire Haglin, um outro exemplo de métodos genéricos pode ser visto na documentação para descomposição de JAXB :
Isso permite
unmarshal
retornar um documento de um tipo arbitrário de árvore de conteúdo JAXB.fonte
Você costuma usar curingas com
Class
. Por exemploClass<? extends JComponent>
,, permitiria especificar que a classe é uma subclasse deJComponent
. Se você recuperou aClass
instância deClass.forName
, poderá usarClass.asSubclass
a conversão antes de tentar, por exemplo, construir uma instância.fonte
Em java
<T>
significa classe genérica. Uma classe genérica é uma classe que pode funcionar em qualquer tipo de dados ou, em outras palavras, podemos dizer que é independente do tipo de dados.Onde T significa tipo. Agora, quando você cria uma instância dessa classe Shape, precisará informar ao compilador qual tipo de dados ele estará trabalhando.
Exemplo:
Inteiro é um tipo e String também é um tipo.
<T>
especificamente significa tipo genérico. De acordo com o Java Docs - Um tipo genérico é uma classe ou interface genérica parametrizada sobre os tipos.fonte
Apenas para dar outro exemplo, a versão genérica de Class (
Class<T>
) permite escrever funções genéricas, como a abaixo.fonte
É confuso no começo. Mas ajuda nas situações abaixo:
fonte
Action a = new Action()
?Action
Em uma interface,SomeAction
estamos tentando obter uma instância do. Temos apenas o nome deSomeAction
disponível em tempo de execução.Basta usar a classe de carne bovina:
fonte