1. JNIEnv 是什么
JNIEnv 即 Java Native Interface Environment,Java 本地编程接口环境。JNIEnv 内部界说了许多函数用于简化咱们的 JNI 编程。
JNI 把 Java 中的一切目标或许目标数组当作一个 C 指针传递到本地办法中,这个指针指向 JVM 中的内部数据结构(目标用jobject来表明,而目标数组用jobjectArray或许具体是基本类型数组),而内部的数据结构在内存中的存储办法是不可见的。只能从 JNIEnv 指针指向的函数表中选择适宜的 JNI 函数来操作JVM 中的数据结构。
在 C 语言中,JNIEnv 是一个指向 JNINativeInterface_ 结构体的指针:
#ifdef __cplusplus
typedef JNIEnv_ JNIEnv;
#else
typedef const struct JNINativeInterface_ *JNIEnv; // C 语言
#endif
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);
jstring (JNICALL *NewStringUTF)
(JNIEnv *env, const char *utf);
//省掉其他函数指针
//......
}
JNINativeInterface_ 结构体中界说了非常多的函数指针,这些函数用于简化咱们的 JNI 编程。C 语言中,JNIEnv 中函数的运用办法如下:
//JNIEnv * env
// env 的实际类型是 JNINativeInterface_**
(*env)->NewStringUTF(env,"Hello from JNI !");
在 C++ 代码中,JNIEnv 是一个 JNIEnv_ 结构体:
#ifdef __cplusplus
typedef JNIEnv_ JNIEnv;
#else
typedef const struct JNINativeInterface_ *JNIEnv;
#endif
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);
}
//省掉其他函数
//......
}
JNIEnv_ 结构体中相同界说了非常多的成员函数,这些函数用于简化咱们的 JNI 编程。C++ 语言中,JNIEnv 中函数的运用办法如下:
//JNIEnv * env
// env 的实际类型是 JNIEnv_*
env->NewstringUTF ( "Hello from JNI ! ");
2. 怎么获取到 JNIEnv
对于单线程的状况,咱们能够直接经过 JNI 办法传入的参数获取到 JNIEnv
// 第一个参数就是 JNIEnv
JNIEXPORT jstring JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject obj)
{
return (*env)->NewStringUTF(env,"Hello from JNI !");
}
对于多线程的状况,首先咱们要知道,JNIEnv 是一个线程效果域的变量,不能跨线程传递,不同线程的 JNIEnv 互相独立。那怎么在不同的线程中获取到 JNIEnv 呢:
//界说全局变量
//JavaVM 是一个结构体,用于描述 Java 虚拟机,后面会讲
JavaVM* gJavaVM;
JNIEXPORT jstring JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject obj)
{
//线程不允许共用env环境变量,可是JavaVM指针是整个jvm共用的,所以能够经过下面的办法保存JavaVM指针,在线程中运用
env->GetJavaVM(&gJavaVM);
return (*env)->NewStringUTF(env,"Hello from JNI !");
}
//假定这是一个东西函数,或许被多个线程调用
void util_xxx()
{
JNIEnv *env;
//从全局的JavaVM中获取到环境变量
gJavaVM->AttachCurrentThread(&env,NULL);
//就能够运用 JNIEnv 了
//最后需要做清理操作
gJavaVM->DetachCurrentThread();
}
3. JNIEnv 内部函数分类
JNIEnv 中界说的函数能够分为以下几类:
函数名 | 功用 |
---|---|
FindClass | 用于获取类 |
GetObjectClass | 经过目标获取这个类 |
NewGlobalRef | 创立 obj 参数所引用目标的新全局引用 |
NewObject | 结构新 Java 目标 |
NewString | 利用 Unicode 字符数组结构新的 java.lang.String 目标 |
NewStringUTF | 利用 UTF-8 字符数组结构新的 java.lang.String 目标 |
New<Type>Array | 创立类型为Type的数组目标 |
Get<Type>Field | 获取类型为Type的字段 |
Set<Type>Field | 设置类型为Type的字段的值 |
GetStatic<Type>Field | 获取类型为Type的static的字段 |
SetStatic<Type>Field | 设置类型为Type的static的字段的值 |
Call<Type>Method | 调用回来类型为Type的办法 |
CallStatic<Type>Method | 调用回来值类型为Type的static办法 |
相关的函数不止上面的这些,这些函数的介绍和运用办法,咱们能够在开发过程中参阅官方文档 docs.oracle.com/en/java/jav…
参阅资料
- JNI/NDK入门指南之JavaVM和JNIEnv
- Java Native Interface Specification Contents
关于
我叫阿豪,2015 年本科毕业于国防科技大学指挥自动化专业,毕业后,从事信息化配备的研发工作。首要研究方向为 Android Framework 与 Linux Kernel,2023年春节后开始做 Android Framework 相关的技术共享。
假如你对 Framework 感兴趣或许正在学习 Framework,能够参阅我总结的Android Framework 学习路线指南,也可重视我的微信大众号,我会在大众号上继续共享我的经历,协助正在学习的你少走一些弯路。学习过程中假如你有疑问或许你的经历想要共享给我们能够增加我的微信,我拉你进技术交流群。