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

时间:2010-04-27 17:43:41

标签: java jvm

jvm如何知道对象是运行时实例的类。我知道我们可以使用getClass方法来获取类名,但getClass方法如何工作? 谢谢, 普利文。

4 个答案:

答案 0 :(得分:5)

答案是什么?魔术!

不,严重的是,它是实现定义的,并且JVM的实现不需要使用单个简单技术,例如将类作为引用存储在实例数据中的常量偏移量的字段中。它所需要做的就是确保getClass方法可以像记录的那样显着地工作。例如,对于escape analysis,JVM可以静态地在堆上分配实例,因为它知道实例不会超过堆栈帧。在这种情况下,它可能会选择将getClass()调用转换为Class实例的直接加载,而不是方法调用!类似地,因为getClass()在逻辑上是一个虚方法(我知道它是最终的,但它的返回值在任何给定类加载器的类的所有实例中都是常量,但对于每个不同的类是不同的,就好像它是返回的虚拟一个常数值),它可能会经历inline caching的类似优化。

答案 1 :(得分:2)

我不知道JVM的细节,但在大多数面向对象的语言+运行时系统(Delphi,C ++,.NET)中,隐藏字段被添加到对象实例数据中,指向对象实例的类型信息。

将对象实例直接映射到外部数据结构时必须小心,因为对象实例数据中的隐藏类型信息或虚方法表指针将与外部数据结构中的字段失去对齐。 / p>

通常可以通过查看对象实例的大小来查看此工件。 Sizeof()或等价物。没有声明字段的对象仍将具有大于零的内存占用。那就是类型信息魔法的来源。

答案 2 :(得分:0)

答案 3 :(得分: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