JVM在运行时如何知道对象的类

5

jvm在运行时如何知道一个对象是哪个类的实例。我知道我们可以使用getClass方法来获取类名,但是getClass方法是如何工作的呢? 谢谢, Praveen。

4个回答

5
答案是什么?那就是魔法!不过,严肃地说,这取决于实现方式,JVM的实现不需要使用单一简单的技术,例如在实例数据中将类存储为字段的引用。它只需要确保getClass方法按照文档说明正常工作即可。例如,通过逃逸分析,JVM可以在堆上静态分配一个实例,因为它知道该实例不会超出堆栈帧的生命周期。在这种情况下,它可能选择将getClass()调用转换为直接加载Class实例,而不是方法调用!同样,由于getClass()在逻辑上是一个虚拟方法(我知道它是final的,但它的返回值在来自任何给定类加载器的所有类的所有实例之间都是恒定的,但对于每个不同的类则不同,就像返回常量值的虚拟方法一样),因此它可能经历类似于内联缓存的优化。

2
我不知道JVM的具体情况,但在大多数面向对象的语言和运行时系统(Delphi、C++、.NET)中,会在对象实例数据中添加一个隐藏字段,该字段指向对象实例的类型信息。
当将对象实例直接映射到外部数据结构时,必须小心处理此问题,因为对象实例数据中的隐藏类型信息或虚方法表指针会使外部数据结构中的字段偏移。
您通常可以通过查看对象实例的大小来看到这个现象。使用Sizeof()函数或等效函数。即使没有声明字段的对象也将具有大于零的内存占用空间。这就是类型信息的魔力所在。

0

1
类文件格式是用于定义类的序列化格式。它与JVM如何通过getClass()方法将任何给定对象实例与Class对象实例连接并没有真正关系。 - Barry Kelly
它确实解释了当JVM创建一个对象时做了什么。其中一部分是使类元信息可用。 - Romain Hippeau
实际上并不会。JVM规范只定义了看起来会发生什么事情。例如,它通过栈机器的术语来定义代码的含义;但在运行时,并不需要存在任何具有相同逻辑插槽和相同逻辑值推送和弹出的实际堆栈机器。相反,JVM可以选择即时编译所有内容,而不解释。但这个问题涉及到JVM如何在运行时知道,当栈可能不存在时。唯一的答案是完全取决于JVM,只要它能像记录中描述的那样工作即可。 - Barry Kelly

0

正如之前的答案所建议的那样,实现并没有具体说明。

为了了解实现可能的样子,我研究了最近 Hotspot JVM 的运行时部分。 在 Hotspot 中,每个对象都以标记字(用于 GC 和其他用途)和 klass 指针开头。 如果您调用 getClass,则会调用 Object.c 中的本机实现:

JNIEXPORT jclass JNICALL
Java_java_lang_Object_getClass(JNIEnv *env, jobject this)
{
    if (this == NULL) {
        JNU_ThrowNullPointerException(env, NULL);
        return 0;
    } else {
        return (*env)->GetObjectClass(env, this);
    }
}

GetObjectClass是JNI API的一部分。(http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html) JNI GetObjectClass的内部实现实际上只是解析对象指针,从类指针中读取klass,并返回该类的Java表示形式:

JNI_ENTRY(jclass, jni_GetObjectClass(JNIEnv *env, jobject obj))
  JNIWrapper("GetObjectClass");

  HOTSPOT_JNI_GETOBJECTCLASS_ENTRY(env, obj);

  Klass* k = JNIHandles::resolve_non_null(obj)->klass();
  jclass ret =
    (jclass) JNIHandles::make_local(env, k->java_mirror());

  HOTSPOT_JNI_GETOBJECTCLASS_RETURN(ret);
  return ret;
JNI_END

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