Java中的a.getClass()和A.class有什么区别?


101

在Java中,围绕使用a.getClass()或选择存在哪些利弊A.class?可以在Class<?>预期的任何地方使用这两种方法,但是我想在不同的情况下使用这两种方法都会有性能或其他微妙的好处(就像with Class.forName()和and一样ClassLoader.loadClass()。)

Answers:


163

我不会在优点/缺点方面进行比较,因为它们具有不同的目的,并且很少在两者之间做出选择。

  • a.getClass()返回运行时类型a。也就是说,如果你有A a = new B();那么a.getClass()将返回B类。

  • A.class静态地对A类求值,并用于通常与反射相关的其他目的。

在性能方面,可能会有可测量的差异,但是我不会在此赘述,因为最终它取决于JVM和/或编译器。


这篇文章在这里已被重写为文章。


2
怎么A.class.getClass()
user1870400

5
这将为您提供Class代表该A.class对象的类的对象,该对象又是的一个实例java.lang.Class
aioobe

怎么A.getClass().class
Shikhar Mainalee

@ShikharMainalee,如果A是一堂课,那真的没有意义。getClass类上没有静态方法。
aioobe '19

请问这个涉及到的建议在这里,他们还指出,不同的类加载器。两者之间是否也可能有重大区别?
吉姆(Jim)

32

实际上,它们在哪里可以使用方面有所不同。A.class在编译时工作,而a.getClass()需要一个类型的实例,A并在运行时工作。

性能可能也会有所不同。虽然A.class可以由编译器解决,因为它知道的实际类型A,这a.getClass()是在运行时发生的虚拟方法调用。

作为参考,针对字节码的编译器通常针对以下问题发出以下指令Integer.getClass()

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

以及以下内容Integer.class

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

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

前者通常会涉及虚拟方法的分派,因此大概需要更长的时间才能执行。最终这取决于JVM。


1
[1]从技术上讲Java语言规范根本没有提到任何常量池...
aioobe 2012年

@aioobe:我想你是对的,这就是为什么我检查了Sun JDK生成的字节码的原因。
Tomasz Nurkiewicz 2012年

1
...从技术上讲也没有提供权威性的答案,因为Java语言规范在语义方面甚至都没有提到字节码。
aioobe 2012年

@aioobe:我明白你的意思。我从未提到过JLS,只是不确定地凭经验检查了它的工作原理。OP询问性能,检查字节码似乎是个好主意。随时编辑我的帖子或删除模棱两可的陈述
Tomasz Nurkiewicz 2012年

1
如果您不喜欢它
回滚

8

看下面的例子

a.getClass()!= A.class,即a不是A的实例,而是A的匿名子类

a.getClass() 需要类型A的实例


4

使用a.getClass时,你有类/类型的实例,你想获得它的确切类型。while a.classtype可用并要创建实例时使用。在编译时求值时,
getClass()返回实例的运行时类型.class
考虑到性能getClass().class.class具有比更好的性能 getClass()
范例:

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

}

输出:

time (getClass()) : 79410 ns
time (.class)     : 8032 ns

1

我想补充一个区别。假设您有一个具有以下构造函数的类,如下所示,该类带有一个带有Class对象的超类。您希望无论何时创建子类对象,都应将子类的类对象传递给超类。由于无法在构造函数中调用实例方法,因此以下代码无法编译。在这种情况下,如果您替换myObject.getClass()MyClass.class。它将完美运行。

Class MyClass
{
    private MyClass myObject = new MyClass();
    public MyClass()
    {
        super(myObject.getClass()); //error line compile time error
    }
}

2
具有相同类的实例和相同类的实例变量。...在递归创建对象时,将用完堆空间。
Aniket Thakur 2013年

1

有趣的是,上面示例中提到的性能差异似乎与其他原因有关。使用3个不同的类,平均而言,性能几乎相同:

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

输出将类似于:

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

切换呼叫顺序甚至getClass()会更快。

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

输出:

time (.class):33108 ns
time (getClass()) :6622 ns

“使用3个不同的类”。但是在getClass()部分中,您没有使用3个不同的类。这些都是String,因此getClass将为所有实例返回java.lang.String。
基利安

1

p.getClass(),其中p是对象的实例,返回此对象的运行时类pp不能是会导致编译时错误的类型,它应该是对象的实例。

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

p.class是一个表达。在.class被称为类语法。p是一种。它可以是类,接口或数组的名称,甚至可以是原始类型的名称。 a.getClass() == B.class

如果类型可用并且有实例,则可以使用getClassmethod获取类型的名称。否则,请使用.class语法

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.