Java中的getClass方法是如何工作的?

15

这是JavaDoc的内容:

public final Class <?> getClass()

返回此 Object 的运行时类。返回的 Class 对象是由所代表类的 static synchronized 方法锁定的对象。
实际结果类型为 Class<? extends |X|>,其中 |X| 是调用 getClass 的表达式的静态类型的擦除。例如,在此代码片段中不需要进行强制转换:

Number n = 0;
Class<? extends Number> c = n.getClass();

返回值:
表示此对象的运行时类的Class对象。

现在,我明白它是一个本地方法,因此它是在平台相关的代码中实现的。但是这个方法的返回类型是什么呢?

public final Class<?> getClass()

此外,请考虑以下代码:

class Dog
{
    @Override
    public String toString()
    {
        return "cat";
    }
}

public class Main
{
    public static void main(String[] args)
    {
        Dog d= new Dog();
        //Class<Dog> dd = new Dog();  Compile time error
        System.out.println(d.getClass());
    }
}

输出:

 

class Dog

因此,我的疑问在于:

  1. 这种方法的返回类型是什么
  2. toString方法没有被调用。有一个类似主题的帖子: Java. getClass()返回一个类,为什么我也可以得到一个字符串?
  3. 被注释的代码会导致编译时错误。

在Java中,Class是一种真正有效的Object类型。可以查看关于Class的Java文档。注释代码会出错,因为Class<Dog>应该设置为一个Class对象,而new Dog()返回一个Dog对象。 - CollinD
1
这不是一个本地方法。正如文档所说,类型为“Class”的对象仅表示一个类。每个Object都有一个引用指向表示其类的Class,而getClass()只是一个普通的getter。 - Kevin Krumwiede
@KevinKrumwiede,请看这里:https://dev59.com/loTba4cB1Zd3GeqP9rGU 现在我很困惑它是否是本地的? - Number945
1
这是java.lang.Object类定义中的源代码:public final native Class<?> getClass();。由于对象的表示是实现的问题,访问此实现定义的数据结构的代码最好是“native”的。必须在不需要本地化和必须本地化之间有一个限制。(另请参见:巴伯的悖论) - laune
@laune 啊...谢谢你澄清这个问题。 - Kevin Krumwiede
3个回答

9

每个对象的数据都包含对java.lang.Class类对象的引用,该引用可通过方法getClass返回。还有一个描述java.lang.Class的java.lang.Class对象。

将Class对象视为描述创建对象所需的某个类的“蓝图”。可以想象,蓝图也需要自己的蓝图(否则工程师如何知道如何制作蓝图)。

这些语句试图说明这一点。

Integer integer = 1;
Class<?> clazzInteger = integer.getClass();
System.out.println( "class of integer=" + clazzInteger );
Class<?> clazzClazzInteger = clazzInteger.getClass();
System.out.println( "class of class Integer's class=" + clazzClazzInteger );
String string = "x";
Class<?> clazzString = string.getClass();
System.out.println( "class of string=" + clazzString );
Class<?> clazzClazzString = clazzString.getClass();
System.out.println( "class of class String's class=" + clazzClazzString );

输出:

class of integer=class java.lang.Integer
class of class Integer's class=class java.lang.Class
class of string=class java.lang.String
class of class String's class=class java.lang.Class

一个类有一个名称,就像由蓝图描述的任何东西都有一个名称,这与蓝图本身不要混淆。如果一个类对象出现在某个上下文中,它的toString()方法会被隐式调用,这将返回类的名称。如果您想打印出一个类的所有细节(类似于打印蓝图本身),您必须编写大量的代码 - 只需查看java.lang.Class的javadoc:有很多信息可以检索(适合蓝图)。

1
在这一点上,我们需要区分一个类型和该类型的实例。让我们用一个例子来解释它。
    public class A {
        public static void main(String[] args) {
            Class<A> typeInformation = A.class; //Type information associated with type `A`
            A instanceOfA = new A();  //actual instance of type `A`
        }   
    }

类型

上述代码中的'reference typeInformation'是Class类型,暂时不考虑泛型。这些信息通常存储在非堆内存部分。以下信息存储在每个type jvm加载时:

  • 类型的完全限定名称
  • 类型的直接超类的完全限定名称(除非该类型是接口或类java.lang.Object,两者都没有超类)
  • 类型是类还是接口
  • 类型的修饰符(一些子集包括`public, abstract, final)
  • 任何直接超级接口的完全限定名称的有序列表

实例

instaneOfA是指向堆内存中地址的类型为A的实际实例的引用。

getClass()的返回类型是通用的Class类型。与Java中提供的许多其他type - String、Integer等一样,Class也是表示关联类型信息的类型。

toString()方法是与Dog类的一个实例相关联并调用的,而不是与Dog类型本身相关联和调用的。

//Class<Dog> dd = new Dog(); 编译时错误

这是由于在将右侧表达式的结果分配给左侧的Left Hand Side时发生了类型不匹配,两者类型不同。 Class dd是Class类型的引用。 Dog是完全不同的类型,并且new Dog()可以分配给类型为'Dog'的引用。

此链接将帮助您了解Java运行时环境的设计方面


0

我对你的第三个问题有一个答案:

这会导致编译时错误,因为

原因1:对于一个类实例,你只能分配代表Dog类的类对象,但不能直接分配Dog类对象。

例如:Class dd=Dog.class或Class dd=Class.forName("Dog"); 是正确的语法。

原因2:类Class是一个final类,但不是Dog类的超类。你需要回到Java中动态方法调度的概念,只能将子类对象分配给超类变量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接