赞
踩
Java Native Interface (JNI)头文件路径:java/jdk/include/jni.h
Java Native Interface头文件是Java开发工具包(Java Development Kit,JDK)中的一部分。JNI允许Java代码与其他编程语言(如C或C++)进行交互,通过使用JNI.h头文件,开发者可以访问和使用底层的本地功能和库。
JNIEnv 概念 : 是一个线程相关的结构体, 该结构体代表了 Java 在本线程的运行环境 ;
即在每个线程中都有一个 JNIEnv 指针, 每个JNIEnv 都是线程专有的, 其它线程不能使用本线程中的 JNIEnv。 在同一个线程中, 多次调用 JNI层方法, 传入的 JNIEnv 是相同的;
JNIEnv 结构 : 由上面的代码可以得出, JNIEnv 是一个指针, 指向一个线程相关的结构, 线程相关结构指向 JNI 函数指针 数组, 这个数组中存放了大量的 JNI 函数指针, 这些指针指向了具体的 JNI 函数;
JNIEnv 与 JavaVM : 注意区分这两个概念;
JavaVM : JavaVM 是 Java虚拟机在 JNI 层的代表, 一个JVM中只有一个JavaVM实例,这个实例是线程共享的;
JNIEnv : JavaVM 在线程中的代表, 每个线程都有一个, JNI 中可能有很多个 JNIEnv;
在 C 语言 和 C++ 中 , JNIEnv 代表着不同的含义 ;
#if defined(__cplusplus) //声明 C++ 环境下的 JNIEnv 类型 ;
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM; //将 _JNIEnv 结构体类型声明为 JNIEnv 类型
#else //声明 C 语言环境下的 JNIEnv 类型 ;
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM; //将 JNINativeInterface 结构体指针 类型 声明为 JNIEnv 类型
#endif
C 语言中的 JNIEnv * env 实际上是 JNINativeInterface** 类型。调用其中的方法指针时 , 先解引用得到其一维指针 , 然后调用对应的函数指针: (* env)->函数指针 。
C++ 中专门定义了 JNIEnv 结构体类型,JNIEnv结构体的函数直接封装调用了 JNINativeInterface 结构体中的函数指针 , 只需要调用 JNIEnv 结构体中的方法即可。 C++ 中的 JNIEnv * env , 可以将其当做一个对象使用直接调用其中的方法: env->方法名称;
总结 : JNI 中定义的函数指针 , 实际都定义在 JNINativeInterface 结构体中 ;
JNIEnv 的创建和释放
JNIEnv 创建 和 释放 : 定义在 JavaVM结构体中
调用 (AttachCurrentThread)(JavaVM, JNIEnv*, void) 方法, 创建 JNIEnv结构体;
调用 (DetachCurrentThread)(JavaVM)方法, 释放本线程中的 JNIEnv;
/* jni_md.h contains the machine-dependent typedefs for jbyte, jint and jlong */ typedef long jint; typedef __int64 jlong; typedef signed char jbyte; #ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H typedef unsigned char jboolean; typedef unsigned short jchar; typedef short jshort; typedef float jfloat; typedef double jdouble; typedef jint jsize; #ifdef __cplusplus class _jobject {}; class _jclass : public _jobject {}; class _jthrowable : public _jobject {}; class _jstring : public _jobject {}; class _jarray : public _jobject {}; class _jbooleanArray : public _jarray {}; class _jbyteArray : public _jarray {}; class _jcharArray : public _jarray {}; class _jshortArray : public _jarray {}; class _jintArray : public _jarray {}; class _jlongArray : public _jarray {}; class _jfloatArray : public _jarray {}; class _jdoubleArray : public _jarray {}; class _jobjectArray : public _jarray {}; typedef _jobject *jobject; typedef _jclass *jclass; typedef _jthrowable *jthrowable; typedef _jstring *jstring; typedef _jarray *jarray; typedef _jbooleanArray *jbooleanArray; typedef _jbyteArray *jbyteArray; typedef _jcharArray *jcharArray; typedef _jshortArray *jshortArray; typedef _jintArray *jintArray; typedef _jlongArray *jlongArray; typedef _jfloatArray *jfloatArray; typedef _jdoubleArray *jdoubleArray; typedef _jobjectArray *jobjectArray; #else struct _jobject; typedef struct _jobject *jobject;//代表了Java中包含native方法的类的一个实例 typedef jobject jclass; //jclass代表的是一个类对象 typedef jobject jthrowable; typedef jobject jstring; typedef jobject jarray; typedef jarray jbooleanArray; typedef jarray jbyteArray; typedef jarray jcharArray; typedef jarray jshortArray; typedef jarray jintArray; typedef jarray jlongArray; typedef jarray jfloatArray; typedef jarray jdoubleArray; typedef jarray jobjectArray; #endif
typedef union jvalue {
jboolean z;
jbyte b;
jchar c;
jshort s;
jint i;
jlong j;
jfloat f;
jdouble d;
jobject l;
} jvalue;
//Object对象 L开头,包名/类名,”;”结尾,$标识嵌套类
//数组 [内部类型 如果是普通类型的数组不需要加“;”后缀,如果是Object类型的数组则需要添加”;”
struct _jfieldID;
typedef struct _jfieldID *jfieldID;
struct _jmethodID;
typedef struct _jmethodID *jmethodID;
JNINativeInterface_结构体类型中定义了 229 个函数指针 , 用于处理 Java 层 与 Native 层的数据交互信息
struct JNINativeInterface_ { void *reserved0; void *reserved1; void *reserved2; void *reserved3; jint (JNICALL *GetVersion)(JNIEnv *env); jclass (JNICALL *DefineClass) (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len); jclass (JNICALL *FindClass) (JNIEnv *env, const char *name); jmethodID (JNICALL *FromReflectedMethod) (JNIEnv *env, jobject method); jfieldID (JNICALL *FromReflectedField) (JNIEnv *env, jobject field); jobject (JNICALL *ToReflectedMethod) (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic); jclass (JNICALL *GetSuperclass) (JNIEnv *env, jclass sub); jboolean (JNICALL *IsAssignableFrom) (JNIEnv *env, jclass sub, jclass sup); jobject (JNICALL *ToReflectedField) (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic); ...... };
_JNIEnv 结构体中封装了一个 JNINativeInterface 结构体类型指针 , _JNIEnv 结构体中也封装了 229 个 方法 , 每个方法都调用 对应的 JNINativeInterface functions 中的函数指针 ;*
struct JNIEnv_ { const struct JNINativeInterface_ *functions; #ifdef __cplusplus jint GetVersion() { return functions->GetVersion(this); } jclass DefineClass(const char *name, jobject loader, const jbyte *buf, jsize len) { return functions->DefineClass(this, name, loader, buf, len); } jclass FindClass(const char *name) { return functions->FindClass(this, name); } jmethodID FromReflectedMethod(jobject method) { return functions->FromReflectedMethod(this,method); } jfieldID FromReflectedField(jobject field) { return functions->FromReflectedField(this,field); } jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) { return functions->ToReflectedMethod(this, cls, methodID, isStatic); } jclass GetSuperclass(jclass sub) { return functions->GetSuperclass(this, sub); } jboolean IsAssignableFrom(jclass sub, jclass sup) { return functions->IsAssignableFrom(this, sub, sup); } ...... }
以下以 JNINativeInterface 结构体中函数为例,在C++中去除第一个参数即可。
jclass (JNICALL *GetObjectClass) (JNIEnv *env, jobject obj);
获取对象所属的类,object对隐式this参数对象的引用
jclass (JNICALL *FindClass) (JNIEnv *env, const char *name);
以字符串形式来指定类名
jclass (JNICALL *GetSuperClass)(JNIEnv *env,jclass obj)
通过jclass可以获取其父类的jclass实例。
jfieldID (JNICALL *GetFieldID) (JNIEnv *env, jclass clazz, const char *name, const char *sig);
返回类中一个域的标识符
jfieldID (JNICALL *GetStaticFieldID) (JNIEnv *env, jclass clazz, const char *name, const char *sig);
返回类中一个静态域的标识符
void (JNICALL *SetDoubleField) (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val);
设置域的值
jdouble (JNICALL *GetDoubleField) (JNIEnv *env, jobject obj, jfieldID fieldID);
返回域的double值
jint (JNICALL *GetStaticIntField) (JNIEnv *env, jclass clazz, jfieldID fieldID);
返回域的double值
JVM提供了一种方式允许程序员在加载动态链接库文件的时候做一些自定义操作。
所以这两个函数就是一个本地库最重要的两个管理生命周期的函数。
//依旧定义在JNI头文件:java/jdk/include/jni.h
/* Defined by native libraries. */
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved);
JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM *vm, void *reserved);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。