Java 中的 getClass 如何工作

How does getClass in Java work

这是 JavaDoc 所说的:

public final Class <?> getClass()

Returns the runtime class of this Object. The returned Class object is the object that is locked by static synchronized methods of the represented class.
The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called. For example, no cast is required in this code fragment:

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

Returns:
The Class object that represents the runtime class of this object.

现在,我知道它是一个本地方法,所以它是在依赖于平台的代码中实现的。但是这个方法的return类型呢

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. Return 此方法的类型
  2. 未调用 toString 方法。关于此主题的类似 post 是: Java. getClass() returns a class, how come I can get a string too?
  3. 否则会导致编译时错误的注释代码。

每个对象的数据都包含对 class java.lang.Class 对象的引用,这是由方法 getClass 返回的。还有一个 java.lang.Class 对象描述 java.lang.Class。

将 Class 对象视为 "blueprint" 描述某个 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

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

此时,我们需要区分一个type和一个instance的类型。让我们用一个例子来解释它。

    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`
        }   
    }

类型

上面代码中的引用'typeInformation'属于Class类型,暂且搁置泛型。此信息通常驻留在非堆内存部分。针对每个 type jvm 负载存储以下信息:

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

实例

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

Return 类型的 getClass() 是通用的 Class 类型。与 java 中可用的许多其他 type - 字符串、整数等一样,Class 也是一种表示相关类型信息的类型。

toString() 方法在 Dog class 的 instance 上关联和调用,而不是 Dog 类型本身。

//Class<Dog> dd = new Dog(); Compile time error

这是由于将右侧的表达式结果分配给左侧的表达式结果时发生类型不匹配,这不是同一类型。 Class dd 指的是 Class 类型的引用。 Dog 是完全不同的类型,可以将新的 Dog() 分配给 'Dog' 类型的引用。

This link will help you understand the design aspects of java runtime environment

我已经回答了你的问题 3,

这会产生编译时错误,因为

原因 1:对于 Class 实例,您只能分配代表狗 class 的 class 对象,但不能分配狗 class直接反对。

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

原因 2:class Class 是最后一个 class 但不是狗 class 的超级 class。你回到java中的动态方法调度的概念,在那里你只能将subclass对象分配给superclass变量。