JNI.h jtypes和关系

时间:2018-01-14 07:24:10

标签: types jvm java-native-interface

我在这里看到jni.h的代码:  http://xdprof.sourceforge.net/doxygen/jni_8h-source.html

我想知道这是什么:

class _jobject {};
00053 class _jclass : public _jobject {};
00054 class _jthrowable : public _jobject {};
00055 class _jstring : public _jobject {};
00056 class _jarray : public _jobject {};
00057 class _jbooleanArray : public _jarray {};
00058 class _jbyteArray : public _jarray {};
00059 class _jcharArray : public _jarray {};
00060 class _jshortArray : public _jarray {};
00061 class _jintArray : public _jarray {};
00062 class _jlongArray : public _jarray {};
00063 class _jfloatArray : public _jarray {};
00064 class _jdoubleArray : public _jarray {};
00065 class _jobjectArray : public _jarray {};

_jobject空类和Object类之间的关系是什么 - " Object.h/Object.cpp" (在JVM内部)以及为什么这些类是空的?

3 个答案:

答案 0 :(得分:2)

仅需要这些类来维护相应JNI类型之间的层次结构:

jobject <- jarray <- jintArray etc.

因此可以使用jarray,例如,在接受jobject的函数中。

课程内容无关紧要。 JNI类型对于应用程序来说是不透明的。 JNI类型和Java类之间没有直接关系。这种关系隐藏在JVM代码中,即如果某些JNI函数需要jstring参数,JVM会明确将该参数视为java.lang.String实例的句柄。例如。来自HotSpot sources

JNI_QUICK_ENTRY(jsize, jni_GetStringLength(JNIEnv *env, jstring string))
  ...
  oop s = JNIHandles::resolve_non_null(string);
  if (java_lang_String::value(s) != NULL) {       <-- explicitly cast a handle
    ret = java_lang_String::length(s);
  }

此类操作的类型安全性可能会也可能不会在运行时强制执行,具体取决于JVM的实现。例如。如果您传递一些精心设计的jstring参数,HotSpot可能会崩溃,该参数实际上不是java.lang.String对象的句柄。

修改

jstring是指向Java String实例的指针(注意双重间接)。 JVM不访问class _jstring的值,而是将其视为指向实际实例的指针(参见上面的示例)。

  java.lang.String             JNIHandleBlock                    jstring string
  ------------------           -----------------------           -----------------
 |  0: (header)     |<---\    | oop[0]                |     /---| class _jclass * |
 |  8: (class ptr)  |     \---| oop[1]  <------------------/     -----------------
 | 12: char[] value |         | ...                   |
 | 16: int hash     |         | oop[31]               |
 | 24: (padding)    |         |                       |
  ------------------          | int _top              |
                              | JNIHandleBlock* _next |
                              | ...                   |
                               -----------------------

使用jstring时,HotSpot JVM首先解析oop(普通对象指针)的句柄:

    oop s = JNIHandles::resolve_non_null(string);
    // This is effectively the same as
    //     oop s = *(oop*)string;

然后,为了读取oop的字段,JVM使用原始指针算法(假设它知道字段value从java.lang.String实例的开头有偏移量12):

    java_lang_String::value(s)
    // Effectively the same as
    //     s->obj_field(12)
    // which is expanded to something like
    //     *(oop*)((intptr_t)s + 12)

其他JVM实现可能会以不同方式处理class _jstring。我们的想法是使JNI类型不透明,以便不同的JVM可以以自己的方式实现JNI句柄,而无需重新编译使用这些句柄的代码。这就是为什么类的内容无关紧要 - 这只是声明,而不是类型的实际定义

答案 1 :(得分:0)

这在不同的运行时实现中可能会有所不同,但我将使用Android的旧Dalvik运行时作为示例。

jobject,定义为_jobject*,是间接引用。指针的位不是用作普通指针,而是用于编码引用类型(本地,全局,弱全局)和引用表索引(source)。

因此,当您将jobject传递给某个JNI函数时,例如NewGlobalRefjobject将传递给确定引用类型的dvmDecodeIndirectRef,并从相应的参考表中返回相应的Object*

答案 2 :(得分:0)

JNI不是C ++接口,它是纯C接口。幸运的是,JNI有一个C ++包装器,可以在C ++编译器提供帮助时减少样板代码,并避免(某些)错误,C ++类型系统可以减少歧义。

在您发布的C ++引擎盖下,所有JNI对象都使用由JNI函数解释的黑盒句柄(您可以将它们称为对象引用)。在Dalvik JVM上,其中一些句柄只是指向JVM内部表的指针,但这是一个只能与某些调试相关的实现细节。

这个实现细节在切换到其他JVM时引起了很大的麻烦,包括现代Android ART,因为使用指针,我们有时可以使用与本地引用混合的全局引用等等。