我在这里看到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内部)以及为什么这些类是空的?
答案 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函数时,例如NewGlobalRef
,jobject
将传递给确定引用类型的dvmDecodeIndirectRef
,并从相应的参考表中返回相应的Object*
。
答案 2 :(得分:0)
JNI不是C ++接口,它是纯C接口。幸运的是,JNI有一个C ++包装器,可以在C ++编译器提供帮助时减少样板代码,并避免(某些)错误,C ++类型系统可以减少歧义。
在您发布的C ++引擎盖下,所有JNI对象都使用由JNI函数解释的黑盒句柄(您可以将它们称为对象引用)。在Dalvik JVM上,其中一些句柄只是指向JVM内部表的指针,但这是一个只能与某些调试相关的实现细节。
这个实现细节在切换到其他JVM时引起了很大的麻烦,包括现代Android ART,因为使用指针,我们有时可以使用与本地引用混合的全局引用等等。