JNI 的学习(一)对于 JNIEnv 的一些认识
Java 通过 JNI 机制调用 c/c++ 写的 native 程序。c/c++ 开发的 native 程序需要遵循一定的 JNI 规范,下面的例子就是一个 JNI 函数声明:
1 JNIEXPORT jstring JNICALL Java_com_clay_example_JNITest_getJNIString
2 (JNIEnv* env, jobject obj)
JVM 负责从Java Stack 转入 C/C++ Native Stack。当 Java 进入 JNI 调用,除了函数本身的参数(arg0),会多出两个参数:JNIEnv 指针和 jobject 指针。而我们在Java端定义这个方法的时候,是没有参数的,如下:
1 public native String printHello();
JNIEnv 指针是 JVM 创建的,用于 Native的 c/c++ 方法操纵 Java 执行栈中的数据,比如 Java Class, Java Method 等。
首先,JNI 对于JNIEnv 的使用, 提供了两种语法: c 语法以及 c++ 语法,如下:
c 语法:
1 jsize len = (*env)->GetArrayLength(env,array);
c++ 语法:
1 jsize len =env->GetArrayLength(array);
1 struct _JNIEnv;
2 struct _JavaVM;
3 typedef const struct JNINativeInterface* C_JNIEnv;
4
5 #if defined(__cplusplus)
6 typedef _JNIEnv JNIEnv; //从这里可以看出 C++ 中对 JNIEnv 的使用就是对结构体的使用
7 typedef _JavaVM JavaVM;
8 #else
9 typedef const struct JNINativeInterface* JNIEnv; //从这里可以看出 C 中队 JNIEnv 的使用就是对结构体指针的使用
10 typedef const struct JNIInvokeInterface* JavaVM;
11 #endif
在 C 中,我们可以看到 JNIEnv 的类型就是 JNINativeInterface* ,是一个指针类型,那么在 C++中呢,_JNIEnv 是什么样的呢?
1 /*
2 * C++ object wrapper. c++对象包装器。
3 *
4 * This is usually overlaid on a C struct whose first element is a
5 * JNINativeInterface*. We rely somewhat on compiler behavior. 这通常覆盖在第一个元素是 JNINativeInterface* 的 C 结构上。我们多少依赖于编译器的行为。
6 */
7 struct _JNIEnv {
8 /* do not rename this; it does not seem to be entirely opaque */
9 const struct JNINativeInterface* functions;
10
11 #if defined(__cplusplus)
12
13 jint GetVersion()
14 { return functions->GetVersion(this); }
而对于 C++ 来说, _JNIEnv 是一个结构体,里面包含了 JNINativeInterface* 的结构。
所以从这里也可以看到,对于 C 和 C++ 来说,它们引用 JNIEnv 中的方法是有一点不一样的。 总的来说,JNIEnv,不管是 C,还是 C++,其实关键都是 JNINativeInterface 的这个结构。
我们可以简单看一下 JNINativeInterface 结构的定义,如下:(删减的~~~)
1 /*
2 * Table of interface function pointers.
3 */
4 struct JNINativeInterface {
5 void* reserved0;
6 void* reserved1;
7 void* reserved2;
8 void* reserved3;
9
10 jint (*GetVersion)(JNIEnv *);
11
12 jclass (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,
13 jsize);
14 jclass (*FindClass)(JNIEnv*, const char*);
15
16 jmethodID (*FromReflectedMethod)(JNIEnv*, jobject);
17 jfieldID (*FromReflectedField)(JNIEnv*, jobject);
18 /* spec doesn't show jboolean parameter */
19 jobject (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean);
20
21 ......
22
23 jboolean (*ExceptionCheck)(JNIEnv*);
24
25 jobject (*NewDirectByteBuffer)(JNIEnv*, void*, jlong);
26 void* (*GetDirectBufferAddress)(JNIEnv*, jobject);
27 jlong (*GetDirectBufferCapacity)(JNIEnv*, jobject);
28
29 /* added in JNI 1.6 */
30 jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject);
31 };