JNI总管:JNIEnv

2.3 JNI总管:JNIEnv

在Log系统的实例中,JNI层实现方法和注册方法中都使用了JNIEnv这个指针,通过它调用JNI函数,访问Java虚拟机,进而操作Java对象。JNIEnv是JNI编程中最重要的概念,本节将详细介绍它。首先看JNIEnv的体系结构,如图2-2所示。

在图2-2中可以看到,JNIEnv首先指向一个线程相关的结构,该结构又指向一个指针数组,在这个指针数组中的每个元素最终指向一个JNI函数。所以可以通过JNIEnv去调用JNI函数。

打开jni.h文件看看这部分内容是如何设计的。由于不同平台上有不同的jni.h文件,只需要取一个加以分析,这里打开libnativehelper/include/nativehelper/jni.h。

在jni.h中,为了兼容C和C++两种代码,使用宏__cplusplus加以区分。

首先看JNIEnv在文件中是如何定义的:

 
 
  1. struct _JNIEnv;  
  2. struct _JavaVM;  
  3. typedef const struct JNINativeInterface* C_JNIEnv;  
  4. #if defined(__cplusplus)   //C++  
  5. typedef _JNIEnv JNIEnv;   //C++中JNIEnv的类型  
  6. typedef _JavaVM JavaVM;  
  7. #else  
  8. typedef const struct JNINativeInterface* JNIEnv; //C中JNIEnv的类型  
  9. typedef const struct JNIInvokeInterface* JavaVM;  
  10. #endif 

这里仅仅是用typedef关键字做了类型定义。那么_JNIEnv和JNINativeInterface又是什么类型呢?_JNIEnv结构体的源码如下:

 
 
  1. struct _JNIEnv {  
  2.    const struct JNINativeInterface* functions;  
  3. #if defined(__cplusplus)  
  4. jclass FindClass(const char* name)  
  5. { return functions->FindClass(this, name); }  
  6.   ……  
  7. jint ThrowNew(jclass clazz, const char* message)  
  8. { return functions->ThrowNew(this, clazz, message); }  
  9.   …… 

以上是对 const struct JNINativeInterface*类型的包装,并间接调用了const struct  JNINativeInterface* 上定义的方法。继续分析JNINativeInterface 的定义,代码如下:

 
 
  1. struct JNINativeInterface {  
  2.   ……  
  3.   jclass      (*FindClass)(JNIEnv*, const char*);  
  4.   jint        (*ThrowNew)(JNIEnv *, jclass, const char *);  
  5.   …… 

这里才真正涉及JNI函数的调用。当然,这里也只是个接口,具体的实现要参考虚拟机实现。

最终可以得到如下结论:

C++中:JNIEnv就是struct _JNIEnv。 JNIEnv* env等价于struct _JNIEnv*env,在调用JNI函数的时候,只需要env-> FindClass(JNIEnv*, const char*),就会间接调用JNINativeInterface结构体里定义的函数指针,而无需首先对env解引用。

C中:JNIEnv就是const struct JNINativeInterface*。JNIEnv* env实际等价于const struct JNINativeInterface**? env,因此要得到JNINativeInterface结构体内的函数指针就必须先对env解引用得到(*env),即const struct JNINativeInterface*,这个指针才是真正指向JNINativeInterface结构体的指针,然后再通过它调用具体的JNI函数。因此需要这样调用:(*env)-> FindClass(JNIEnv*, const char*)。

注意 JNIEnv只在当前线程中有效。本地方法不能将JNIEnv从一个线程传递到另一个线程中。相同的 Java 线程中对本地方法多次调用时,传递给该本地方法的JNIEnv是相同的。但是,一个本地方法可被不同的 Java 线程所调用,因此可以接受不同的 JNIEnv。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值