¿Cuál es la diferencia entre a.getClass () y A.class en Java?

101

En Java, ¿qué ventajas y desventajas existen en torno a la elección de utilizar a.getClass()o A.class? Cualquiera de los dos se puede usar donde Class<?>se espere a, pero imagino que habría rendimiento u otros beneficios sutiles al usar ambos en diferentes circunstancias (al igual que con Class.forName()y ClassLoader.loadClass().

IAmYourFaja
fuente

Respuestas:

163

No los compararía en términos de pros / contras, ya que tienen diferentes propósitos y rara vez hay una "elección" entre los dos.

  • a.getClass()devuelve el tipo de tiempo de ejecución de a. Es decir, si tienes A a = new B();entonces a.getClass()te devolverá la Bclase.

  • A.classevalúa la Aclase de forma estática y se utiliza para otros fines relacionados con la reflexión.

En términos de rendimiento, puede haber una diferencia medible, pero no diré nada al respecto porque al final depende de JVM y / o del compilador.


Esta publicación ha sido reescrita como un artículo aquí .

aioobe
fuente
2
¿Qué tal A.class.getClass()?
user1870400
5
Eso le daría el Classobjeto de la clase que representa el A.classobjeto que es nuevamente una instancia de java.lang.Class.
aioobe
¿Qué tal A.getClass().class?
Shikhar Mainalee
@ShikharMainalee, eso no tiene sentido si Aes una clase. No hay un getClassmétodo estático en las clases.
aioobe
¿Cómo se relaciona esto con la sugerencia aquí de que también apuntan a diferentes cargadores de clases? ¿Esto también podría ser una diferencia significativa entre los dos?
Jim
32

En realidad, son diferentes con respecto a dónde puede usarlos. A.classfunciona en tiempo de compilación, mientras que a.getClass()requiere una instancia de tipo Ay funciona en tiempo de ejecución.

También puede haber una diferencia de rendimiento. Si bien A.classel compilador puede resolverlo porque conoce el tipo real de A, a.getClass()hay una llamada a un método virtual en tiempo de ejecución.

Como referencia, un código de bytes de destino del compilador normalmente emite las siguientes instrucciones para Integer.getClass():

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

y lo siguiente para Integer.class:

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

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

El primero normalmente implicaría un envío de método virtual y, por lo tanto, presumiblemente tardaría más en ejecutarse. Sin embargo, al final eso depende de la JVM.

Tomasz Nurkiewicz
fuente
1
[1] técnicamente, la especificación del lenguaje Java no menciona ningún grupo constante en absoluto ...
aioobe
@aioobe: Supongo que tienes razón, por eso verifiqué el código de bytes generado por Sun JDK.
Tomasz Nurkiewicz
1
... que técnicamente hablando tampoco proporciona una respuesta autorizada, ya que la Especificación del lenguaje Java ni siquiera menciona el código de bytes cuando se trata de semántica.
aioobe
@aioobe: Entiendo tu punto. Nunca mencioné JLS, solo verifiqué empíricamente cómo funciona, ya que no estaba seguro. El OP pregunta sobre el rendimiento y examinar el código de bytes parecía una buena idea. Siéntase libre de editar mi publicación o eliminar declaraciones ambiguas
Tomasz Nurkiewicz
1
retrocede si no te gusta ;-)
aioobe
8

echa un vistazo a los ejemplos a continuación

a.getClass()!= A.class, es decir, a no es una instancia de A sino de una subclase anónima de A

a.getClass() requiere una instancia de tipo A

Massimiliano Peluso
fuente
4

Úselo a.getClasscuando tenga una instancia de clase / tipo y desee obtener el tipo exacto. while a.classse usa cuando tienes typedisponible y quieres crear una instancia de él.
También getClass()devuelve el tipo de instancia en tiempo de ejecución mientras .classse evalúa en tiempo de compilación.
Teniendo en cuenta el rendimiento de getClass()y .class, .classtiene un mejor rendimiento que getClass() .
Ejemplo:

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");
    }

}

Salida:

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

Hay una diferencia que me gustaría agregar. Digamos que tiene un constructor de clase a como se muestra a continuación con una superclase que toma un objeto Class. Desea que siempre que se cree un objeto de subclase, el objeto de clase de subclase se pase a la superclase. El siguiente código no se compilará ya que no puede llamar a un método de instancia en un constructor. En ese caso, si reemplaza myObject.getClass()con MyClass.class. Funcionará perfectamente.

Class MyClass
{
    private MyClass myObject = new MyClass();
    public MyClass()
    {
        super(myObject.getClass()); //error line compile time error
    }
}
prashant
fuente
2
Tener una instancia de la misma clase que las variables de instancia de la misma clase ... Se quedará sin espacio de pila ya que está creando objetos de forma recursiva.
Aniket Thakur
1

Curiosamente, las diferencias de rendimiento mencionadas en el ejemplo anterior parecen estar relacionadas con otras razones. Usando 3 clases diferentes, en promedio, el rendimiento será casi el mismo:

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");
} }

La salida será algo como:

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

Y cambiar el orden de las llamadas incluso resultará en getClass()ser más 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");
}}

Salida:

time (.class):33108 ns
time (getClass()) :6622 ns
user4287932
fuente
"Usando 3 clases diferentes". Pero en la sección getClass () no está usando 3 clases diferentes. Todos estos son String y, por lo tanto, getClass devolverá java.lang.String para todas las instancias.
Kilian
1

p.getClass(), donde pes una instancia de un objeto, devuelve la clase de tiempo de ejecución de este objeto p. pno puede ser un tipo que cause un error en tiempo de compilación, debe ser una instancia de un objeto.

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

p.classes una expresion. Se .classllama sintaxis de clase. pes un tipo. Puede ser el nombre de una clase, interfaz o matriz e incluso un tipo primitivo. a.getClass() == B.class.

Si un tipo está disponible y hay una instancia, entonces es posible usar el getClassmétodo para obtener el nombre del tipo. De lo contrario, use la .classsintaxis

triplestone
fuente