Como usar o Class em Java?

Há uma boa discussão sobre Generics e o que eles realmente fazem nos bastidores nesta questão , então todos nós sabemos que Vector é um vetor de matrizes inteiras, e HashTable é uma tabela de cujas chaves são cadeias de caracteres e valores. No entanto, o que me incomoda é o uso da Class .

A class de Class java também deve ter um nome de modelo, (ou assim estou sendo informado pelo sublinhado amarelo no eclipse). Eu não entendo o que devo colocar lá. O ponto principal do object Class é quando você não tem as informações sobre um object, para refletir e tal. Por que isso me faz especificar qual class o object Class manterá? Eu claramente não sei, ou eu não estaria usando o object Class , eu usaria o específico.

Usando a versão generificada da class Class permite que você, entre outras coisas, escreva coisas como

 Class someCollectionClass = someMethod(); 

e então você pode ter certeza de que o object de class que você recebe estende a Collection , e uma instância dessa class será (pelo menos) uma coleção.

Tudo o que sabemos é ” Todas as instâncias de qualquer class compartilham o mesmo object java.lang.Class desse tipo de class

por exemplo)

 Student a = new Student(); Student b = new Student(); 

Então a.getClass() == b.getClass() é verdadeiro.

Agora suponha

 Teacher t = new Teacher(); 

sem genéricos o abaixo é possível.

 Class studentClassRef = t.getClass(); 

Mas isso está errado agora ..?

eg) public void printStudentClassInfo(Class studentClassRef) {} pode ser chamado com Teacher.class

Isso pode ser evitado usando genéricos.

 Class studentClassRef = t.getClass(); //Compilation error. 

Agora o que é T? T é tipo de parâmetros (também chamados de variables ​​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 class. Mais tarde, esse T será substituído por
nome de Classe válido durante a boot ( HashMap map = new HashMap(); )

eg) class name

Portanto, Class representa um object de class de tipo de class específico ‘ T ‘.

Suponha que seus methods de class tenham que trabalhar com parâmetros de tipo desconhecido, como abaixo

 /** * Generic version of the Car class. * @param  the type of the value */ public class Car { // 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 tipo String como CarName

OR T pode ser usado como tipo Integer como modelNumber ,

OR T pode ser usado como tipo de Object como instância de carro válida .

Agora aqui o acima é o POJO simples que pode ser usado de forma diferente em tempo de execução.
Coleções, por exemplo, List, Set, Hashmap são os melhores exemplos que irão trabalhar com objects diferentes, conforme a declaração de T, mas uma vez que declaramos T como String
eg) HashMap map = new HashMap(); Em seguida, ele aceitará apenas objects de instância da class String.

Métodos genéricos

Métodos genéricos são methods que introduzem seus próprios parâmetros de tipo. Isso é semelhante a declarar um tipo genérico, mas o escopo do parâmetro de tipo é limitado ao método em que ele é declarado. Métodos genéricos estáticos e não-estáticos são permitidos, assim como construtores de class genéricos.

A syntax 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 methods genéricos, a seção de parâmetro de tipo deve aparecer antes do tipo de retorno do método.

  class Util { // Generic static method public static  boolean compare(Pair p1, Pair p2) { return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue()); } } class Pair { private K key; private V value; } 

Aqui é a declaração dos tipos usados ​​nos argumentos do método que devem ser antes do tipo de retorno que é boolean aqui.

No abaixo; declaração de tipo não é necessária no nível do método, uma vez que já está declarada no nível da class.

 class MyClass { private T myMethod(T a){ return a; } } 

Mas abaixo está errado como os parâmetros de tipo de nível de class K, V, Z e Y não podem ser usados ​​em um contexto estático (método estático aqui).

 class Util { // Generic static method public static boolean compare(Pair p1, Pair p2) { return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue()); } } 

OUTROS CENÁRIOS VALIDOS SÃO

 class MyClass { //Type declaration  already done at class level private T myMethod(T a){ return a; } // is overriding the T declared at Class level; //So There is no ClassCastException though a is not the type of T declared at MyClass. private  T myMethod1(Object a){ return (T) a; } //Runtime ClassCastException will be thrown if a is not the type T (MyClass). private T myMethod1(Object a){ return (T) a; } // No ClassCastException // MyClass obj= new MyClass(); // obj.myMethod2(Integer.valueOf("1")); // Since type T is redefined at this method level. private  T myMethod2(T a){ return a; } // No ClassCastException for the below // MyClass o= new MyClass(); // o.myMethod3(Integer.valueOf("1").getClass()) // Since  is undefined within this method; // And MyClass don't have impact here private  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 a :: a is Class object of type T // is overriding of class level type declaration; private  Class myMethod4(Class a){ return a; } } 

E, finalmente, o método estático sempre precisa de uma declaração explícita ; Não derivará do nível de class Class . Isso ocorre porque o nível de class T está vinculado à instância.

Leia também Restrições sobre genéricos

Da documentação do Java:

[…] Mais surpreendentemente, a class Class foi generalizada. Os literais de class agora funcionam como tokens de tipo, fornecendo informações do tipo em tempo de execução e em tempo de compilation. Isso permite um estilo de fábricas estáticas exemplificadas pelo método getAnnotation na nova interface AnnotatedElement:

  T getAnnotation(Class annotationType); 

Este é um método genérico. Ele infere o valor de seu parâmetro de tipo T de seu argumento e retorna uma instância apropriada de T, conforme ilustrado pelo seguinte trecho:

 Author a = Othello.class.getAnnotation(Author.class); 

Antes dos genéricos, você teria que converter o resultado para Autor. Além disso, você não teria como fazer o compilador verificar se o parâmetro real representava uma subclass de Anotação. […]

Bem, eu nunca tive que usar esse tipo de coisa. Alguém?

Eu encontrei class útil quando eu criar pesquisas de registro de serviço. Por exemplo

  T getService(Class serviceClass) { ... } 

Como outras respostas apontam, existem muitas e boas razões pelas quais essa class foi genérica. No entanto, há muitas vezes que você não tem como saber o tipo genérico para usar com Class . Nestes casos, você pode simplesmente ignorar os avisos do eclipse amarelo ou usar a Class … É assim que eu faço;)

Seguindo a resposta do @Kire Haglin, um outro exemplo de methods genéricos pode ser visto na documentação do JAXB unmarhallhalling :

 public  T unmarshal( Class docClass, InputStream inputStream ) throws JAXBException { String packageName = docClass.getPackage().getName(); JAXBContext jc = JAXBContext.newInstance( packageName ); Unmarshaller u = jc.createUnmarshaller(); JAXBElement doc = (JAXBElement)u.unmarshal( inputStream ); return doc.getValue(); } 

Isso permite que unmarshal retorne um documento de um tipo arbitrário de tree de conteúdo JAXB.

Você geralmente deseja usar curingas com a Class . Por exemplo, Class Class , permite especificar que a class é uma subclass de JComponent . Se você recuperou a instância de Class de Class.forName , poderá usar Class.asSubclass para fazer o cast antes de tentar, digamos, construir uma instância.

Apenas para lançar outro exemplo, a versão genérica de Class ( Class ) permite escrever funções genéricas, como a abaixo.

 public static >Optional optionalFromString( @NotNull Class clazz, String name ) { return Optional opt = Optional.ofNullable(name) .map(String::trim) .filter(StringUtils::isNotBlank) .map(String::toUpperCase) .flatMap(n -> { try { return Optional.of(Enum.valueOf(clazz, n)); } catch (Exception e) { return Optional.empty(); } }); } 

É confuso no começo. Mas ajuda nas situações abaixo:

 class SomeAction implements Action { } // Later in the code. Class actionClass = Class.forName("SomeAction"); Action action = actionClass.newInstance(); // Notice you get an Action instance, there was no need to cast. 

Basta usar a class de carne:

 public  T beefmarshal( Class beefClass, InputBeef inputBeef ) throws JAXBException { String packageName = docClass.getPackage().getBeef(); JAXBContext beef = JAXBContext.newInstance( packageName ); Unmarshaller u = beef.createBeef(); JAXBElement doc = (JAXBElement)u.beefmarshal( inputBeef ); return doc.getBeef(); }