Qual é a diferença entre a.getClass () e A.class em Java?

101

Em Java, quais prós / contras existem em torno da escolha de usar a.getClass()ou A.class? Qualquer um pode ser usado sempre que um Class<?>for esperado, mas imagino que haveria desempenho ou outros benefícios sutis em usar ambos em circunstâncias diferentes (assim como há com Class.forName()e ClassLoader.loadClass().

IAmYourFaja
fonte

Respostas:

163

Eu não os compararia em termos de prós / contras, pois eles têm finalidades diferentes e raramente há uma "escolha" a ser feita entre os dois.

  • a.getClass()retorna o tipo de tempo de execução de a. Ou seja, se tiver, A a = new B();então a.getClass()retornará a Baula.

  • A.classavalia para a Aclasse estaticamente e é usado para outros fins geralmente relacionados à reflexão.

Em termos de desempenho, pode haver uma diferença mensurável, mas não vou dizer nada sobre isso porque no final é JVM e / ou dependente do compilador.


Esta postagem foi reescrita como um artigo aqui .

aioobe
fonte
2
Que tal A.class.getClass()?
user1870400
5
Isso lhe daria o Classobjeto da classe que representa o A.classobjeto que é novamente uma instância de java.lang.Class.
aioobe
Que tal A.getClass().class?
Shikhar Mainalee
@ShikharMainalee, isso realmente não faz sentido se Afor uma aula. Não há getClassmétodo estático nas classes.
aioobe
como isso se relaciona com a sugestão aqui de que eles também apontam para carregadores de classes diferentes. Isso também pode ser uma diferença significativa entre os dois?
Jim
32

Na verdade, eles são diferentes com relação a onde você pode usá-los. A.classfunciona em tempo de compilação, enquanto a.getClass()requer uma instância do tipo Ae funciona em tempo de execução.

Pode haver uma diferença de desempenho também. Enquanto A.classpode ser resolvido pelo compilador porque ele conhece o tipo real de A, a.getClass()é uma chamada de método virtual acontecendo em tempo de execução.

Para referência, um bytecode direcionado ao compilador normalmente emite as seguintes instruções para Integer.getClass():

aload_1
invokevirtual   #3; //Method java/lang/Object.getClass:()Ljava/lang/Class;

e o seguinte para Integer.class:

//const #3 = class  #16;    //  java/lang/Integer

ldc_w   #3; //class java/lang/Integer

O primeiro normalmente envolveria um despacho de método virtual e, portanto, presumivelmente levaria mais tempo para executar. No entanto, isso é no final dependente da JVM.

Tomasz Nurkiewicz
fonte
1
[1] tecnicamente, a Especificação da linguagem Java não menciona nenhum pool constante ...
aioobe
@aioobe: Acho que você está certo, é por isso que verifiquei o bytecode gerado pelo Sun JDK.
Tomasz Nurkiewicz
1
... que tecnicamente falando também não fornece uma resposta oficial, já que a Especificação da Linguagem Java nem mesmo menciona o bytecode quando se trata de semântica.
aioobe
@aioobe: Entendo. Nunca mencionei o JLS, apenas verifiquei empiricamente como funciona, pois não tinha certeza. O OP pergunta sobre o desempenho e examinar o bytecode pareceu uma boa ideia. Sinta-se à vontade para editar minha postagem ou remover declarações ambíguas
Tomasz Nurkiewicz
1
retroceda se não gostar ;-)
aioobe
8

dê uma olhada nos exemplos abaixo

a.getClass()!= A.class, ou seja, a não é uma instância de A, mas de uma subclasse anônima de A

a.getClass() requer uma instância do tipo A

Massimiliano Peluso
fonte
4

Use a.getClassquando você tiver uma instância de classe / tipo e quiser obter o tipo exato dela. while a.classé usado quando você tem typedisponível e deseja criar uma instância dele.
Também getClass()retorna o tipo de instância em tempo de execução enquanto .classé avaliado em tempo de compilação.
Considerando o desempenho de getClass()e .class, .classtem um desempenho melhor do que getClass() .
Exemplo:

public class PerfomanceClass {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        long time=System.nanoTime();
        Class class1="String".getClass();
        class1="String".getClass();
        class1="String".getClass();
        class1="String".getClass();

        System.out.println("time (getClass()) :"+(System.nanoTime()-time)+" ns");     


        long time2=System.nanoTime();
        Class class2=String.class;
        class2=String.class;
        class2=String.class;
        class2=String.class;

        System.out.println("time (.class):"+(System.nanoTime()-time2)+" ns");
    }

}

Resultado :

time (getClass()) : 79410 ns
time (.class)     : 8032 ns
Rohan
fonte
1

Há uma diferença que gostaria de acrescentar. Digamos que você tenha uma classe um construtor conforme mostrado abaixo com uma superclasse que recebe um objeto Class. Você deseja que sempre que um objeto de subclasse for criado, o objeto de classe da subClasse seja passado para a superclasse. O código abaixo não será compilado, pois você não pode chamar um método de instância em um construtor. Nesse caso, se você substituir myObject.getClass()por MyClass.class. Ele funcionará perfeitamente.

Class MyClass
{
    private MyClass myObject = new MyClass();
    public MyClass()
    {
        super(myObject.getClass()); //error line compile time error
    }
}
prashant
fonte
2
Ter instância da mesma classe que variáveis ​​de instância da mesma classe ... Você ficará sem espaço de heap porque está criando objetos recursivamente.
Aniket Thakur de
1

Curiosamente, as diferenças de desempenho mencionadas no exemplo acima parecem estar relacionadas a outros motivos. Usando 3 classes diferentes, em média, o desempenho será quase o mesmo:

import java.util.LinkedHashMap;
public class PerfomanceClass {

public static void main(String[] args) {

    long time = System.nanoTime();
    Class class1 = "String".getClass();
    Class class11 = "Integer".getClass();
    Class class111 = "LinkedHashMap".getClass();

    System.out.println("time (getClass()) :" + (System.nanoTime() - time) + " ns");

    long time2 = System.nanoTime();
    Class class2 = String.class;
    Class class22 = Integer.class;
    Class class222 = LinkedHashMap.class;

    System.out.println("time (.class):" + (System.nanoTime() - time2) + " ns");
} }

A saída será algo como:

time (getClass()) :23506 ns 
time (.class):23838 ns

E mudar a ordem das chamadas também resultará em getClass()ser mais rápido.

import java.util.LinkedHashMap;

public class PerfomanceClass {

public static void main(String[] args) {
    long time2 = System.nanoTime();
    Class class2 = LinkedHashMap.class;

    System.out.println("time (.class):" + (System.nanoTime() - time2) + " ns");

    long time = System.nanoTime();
    Class class1 = "LinkedHashMap".getClass();

    System.out.println("time (getClass()) :" + (System.nanoTime() - time) + " ns");
}}

Resultado:

time (.class):33108 ns
time (getClass()) :6622 ns
user4287932
fonte
“Usando 3 classes diferentes”. Mas na seção getClass () você não está usando 3 classes diferentes. Todos são String e, portanto, getClass retornará java.lang.String para todas as instâncias.
Kilian de
1

p.getClass(), onde pé uma instância de um objeto, retorna a classe de tempo de execução desse objeto p. pnão pode ser um tipo que causará um erro em tempo de compilação, deve ser uma instância de um objeto.

// B extends A
A a = new B();
System.out.println(a.getClass());
//output: class B

p.classé uma expressão. O .classé chamado de sintaxe de classe. pé um tipo. Pode ser o nome de uma classe, interface ou array e até mesmo um tipo primitivo. a.getClass() == B.class.

Se um tipo estiver disponível e houver uma instância, é possível usar o getClassmétodo para obter o nome do tipo. Caso contrário, use a .classsintaxe

triplestone
fonte