Como usar a classe em Java?

Há uma boa discussão sobre os Genéricos e o que eles realmente fazem nos bastidores sobre a esta pergunta, então todos nós sabemos que Vector<int[]> é um vetor de matrizes de número inteiro, e HashTable<String, Person> é uma tabela de cujas chaves são cadeias de caracteres e os valores Persons. No entanto, o que me entorpece é o uso de Class<>.

A classe java Class também deve ter um nome de modelo, (ou assim estou sendo dito pelo sublinhado amarelo no eclipse). Não entendo o que devo pôr lá. Ponto do objeto Class é quando você não tem a informação completa sobre um objeto, para reflexão e tal. Porque é que me faz especificar qual a classe que o objecto Class irá possuir? Eu claramente não sei, ou eu não estaria usando o objeto Class, eu usaria o específico.

Author: Community, 2009-01-20

10 answers

Usar a versão generificada da classe permite-lhe, entre outras coisas, escrever coisas como

Class<? extends Collection> someCollectionClass = someMethod();

E então você pode ter certeza de que o objeto de classe que você recebe se estende Collection, e uma instância desta classe será (pelo menos) uma coleção.

 110
Author: Yuval, 2014-10-20 10:31:25

Tudo o que sabemos é que "Todas as instâncias de uma qualquer classe compartilham o mesmo java.idioma.Objecto da classe desse tipo de classe"

E. g)

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

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

Agora assume

Teacher t = new Teacher();

Sem genéricos, o abaixo é possível.

Class studentClassRef = t.getClass();
Mas isto agora está errado ..?

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

Isto pode ser evitado usando genéricos.

Class<Student> studentClassRef = t.getClass(); //Compilation error.
O que é isto ?? T é o tipo de parâmetros (também chamado variáveis do tipo); delimitadas por parêntesis angulares ( ), segue o nome da classe.
T é apenas um símbolo, como um nome variável (pode ser qualquer nome) declarado durante a escrita do arquivo de classe. Mais tarde, o T será substituído por
nome de classe válido durante a inicialização (HashMap<String> map = new HashMap<String>();)

E. g) class name<T1, T2, ..., Tn>

Assim Class<T> representa um objecto de classe de tipo específico de classe ' T'.

Assume que os teus métodos de classe têm de funcionar com parâmetros de tipo desconhecidos como: abaixo de

/**
 * 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 não pode ser usado como String tipo como CarName

Ou T podem ser utilizados como Integer tipo número de modelos,

Ou T pode ser usado como Object tipo como instância válida para automóveis .

Agora aqui o acima é o POJO simples que pode ser usado de forma diferente no tempo de execução.
Colecções P. ex.) lista, Conjunto, Hashmap são os melhores exemplos que irão funcionar com diferentes objectos de acordo com a declaração de T, mas quando declararmos T como texto
e. g) HashMap<String> map = new HashMap<String>(); Então só aceitará objectos de instância de classe String.

Métodos Genéricos

Os métodos genéricos são métodos que introduzem os seus próprios parâmetros de tipo. Isto é semelhante a declarar um tipo genérico, mas o escopo do parâmetro do tipo é limitado ao método onde ele é declarado. São permitidos métodos genéricos estáticos e não estáticos, bem como construtores genéricos de classes.

A sintaxe para um método genérico inclui um parâmetro de tipo, dentro do ângulo entre parênteses, e aparece antes do tipo de retorno do método. Para os métodos genéricos, a secção do parâmetro do tipo 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 utilizados nos argumentos do método que deve antes do tipo de retorno que é boolean aqui.

Em baixo; a declaração do tipo <T> não é necessária ao nível do método, uma vez que já é declarada ao nível da classe.

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

Mas abaixo está errado como parâmetros de tipo de classe K, V, Z e Y não podem ser usados num 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, por fim, o método estático necessita sempre de uma declaração explícita <T>; Não derivará do nível de classe Class<T>. Isto é por causa do nível de classe T é vinculado com instância.

Também deve ler-se restrições aos genéricos

 136
Author: Kanagavelu Sugumar, 2016-09-15 14:18:59

Da documentação Java:

[...] Mais surpreendentemente, a classe foi generificada. Os literais de classe agora funcionam como tokens de tipo, fornecendo informações de tempo de execução e tempo de compilação. Isto permite um estilo de fábricas estáticas exemplificadas pelo método de obtenção de anotações na nova interface de anotação:

<T extends Annotation> T getAnnotation(Class<T> annotationType); 

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

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

Antes dos genéricos, você teria que lançar o resultado para o autor. Além disso, você não teria tido nenhuma maneira de fazer a verificação do compilador que o parâmetro atual representava uma subclasse de anotação. [...]

Nunca tive de usar este tipo de coisas. Alguém?
 30
Author: raupach, 2011-11-03 23:26:09

Eu achei class<T> útil quando crio pesquisas no registo de serviços. Por exemplo

<T> T getService(Class<T> serviceClass)
{
    ...
}
 8
Author: Kire Haglin, 2009-01-20 21:52:48
Como outras respostas apontam, há muitas e boas razões pelas quais este class foi tornado Genérico. No entanto, há muitas vezes que você não tem nenhuma maneira de saber o tipo genérico a usar com Class<T>. Nestes casos, você pode simplesmente ignorar os avisos de eclipse amarelo ou você pode usar Class<?> ... É assim que eu faço;)
 5
Author: bruno conde, 2009-01-20 17:53:39

Seguindo a resposta de @Kire Haglin, um outro exemplo de métodos genéricos pode ser visto na documentação para a unmarshalling JAXB:

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

Isto permite que unmarshal devolva um documento de um tipo arbitrário de árvore de conteúdo JAXB.

 3
Author: Stew, 2012-11-07 16:29:53

Deseja frequentemente utilizar caracteres especiais com {[[0]}. Por exemplo, Class<? extends JComponent>, permitir-lhe-ia especificar que a classe é alguma subclasse de JComponent. Se você recuperou a instância Class de Class.forName, então você pode usar Class.asSubclass para fazer o elenco antes de tentar, digamos, construir uma instância.

 2
Author: Tom Hawtin - tackline, 2009-01-20 17:47:13

Só para dar outro exemplo, a versão genérica da classe (Class<T>) permite que se escreva funções genéricas como a abaixo.

public static <T extends Enum<T>>Optional<T> optionalFromString(
        @NotNull Class<T> clazz,
        String name
) {
    return Optional<T> 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();
                }
            });
}
 0
Author: zeronone, 2017-04-10 08:13:15
É confuso no início. Mas ajuda nas situações abaixo:
class SomeAction implements Action {
}

// Later in the code.
Class<Action> actionClass = Class.forName("SomeAction"); 
Action action = actionClass.newInstance();
// Notice you get an Action instance, there was no need to cast.
 -2
Author: fastcodejava, 2010-02-02 12:25:39

Usa apenas a classe de carne de bovino:

public <T> T beefmarshal( Class<beef> beefClass, InputBeef inputBeef )
     throws JAXBException {
     String packageName = docClass.getPackage().getBeef();
     JAXBContext beef = JAXBContext.newInstance( packageName );
     Unmarshaller u = beef.createBeef();
     JAXBElement<T> doc = (JAXBElement<T>)u.beefmarshal( inputBeef );
     return doc.getBeef();
}
 -5
Author: yaa, 2013-07-29 19:17:22