转自:  http://www.cnblogs.com/canphp/archive/2012/11/13/2768937.html

  JNIEnv是一个与线程相关的变量,不同线程的JNIEnv彼此独立。JavaVM是虚拟机在JNI层的代表,在一个虚拟机进程中只有一个JavaVM,因此该进程的所有线程都可以使用这个JavaVM。当后台线程需要调用JNI native时,在native库中使用全局变量保存JavaVM尤为重要,这样使得后台线程能通过JavaVM获得JNIEnv。(这句话引用了《深入理解Android卷1》第二章的内容)

native程序中频繁使用JNIEnv*和JavaVM*。而C和C++代码使用JNIEnv*和JavaVM*这两个指针的做法是有区别的,网上大部分代码都使用C++,基本上找不到关于C和C++在这个问题上的详细叙述。

在C中:

使用JNIEnv* env要这样      (*env)->方法名(env,参数列表)

使用JavaVM* vm要这样       (*vm)->方法名(vm,参数列表)

在C++中:

使用JNIEnv* env要这样      env->方法名(参数列表)

使用JavaVM* vm要这样       vm->方法名(参数列表)

  上面这二者的区别是,在C中必须先对env和vm间接寻址(得到的内容仍然是一个指针),在调用方法时要将env或vm传入作为第一个参数。C++则直接利用env和vm指针调用其成员。那到底C中的(*env)和C++中的env是否有相同的数据类型呢?C中的(*vm) 和C++中的vm是否有相同的数据类型呢?

为了验证上面的猜测,我们可以查看JNIEnv和JavaVM的定义。他们位于头文件jni.h。我开发JNI用的是android-5平台,下面是 $NDK\platforms\android-5\arch-arm\usr\include\jni.h的部分代码

 struct _JNIEnv;
struct _JavaVM;
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv; //C++使用这个类型
typedef _JavaVM JavaVM; //C++使用这个类型
#else
typedef const struct JNINativeInterface* JNIEnv; //C使用这个类型
typedef const struct JNIInvokeInterface* JavaVM; //C使用这个类型 #endif
struct JNINativeInterface { /****省略了的代码****/ jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); /****省略了的代码****/ jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID); /****省略了的代码****/ }; struct _JNIEnv {
const struct JNINativeInterface* functions;
#if defined(__cplusplus)
/****省略了的代码****/
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig) {
return functions->GetMethodID(this, clazz, name, sig);
}
/****省略了的代码****/
jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) {
return functions->GetStaticObjectField(this, clazz, fieldID);
}
/****省略了的代码****/
#endif /*__cplusplus*/
}; struct JNIInvokeInterface {
/****省略了的代码****/
jint (*GetEnv)(JavaVM*, void**, jint);
jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);
}; struct _JavaVM {
const struct JNIInvokeInterface* functions;
#if defined(__cplusplus)
/****省略了的代码****/
jint GetEnv(void** env, jint version) {
return functions->GetEnv(this, env, version);
}
jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args) {
return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args);
}
#endif /*__cplusplus*/
};

假如我们用C编码,宏__cplusplus没有定义,那么从最上面的宏#if defined(__cplusplus)可推断

  JNIEnv    代表类型 const struct JNINativeInterface*

  JavaVM   代表类型 const struct JNIInvokeInterface*

那么JNIEnv* env实际上等价于声明 const struct JNINativeInterface**  env

  JavaVM* vm实际上等价于声明 const struct JNIInvokeInterface ** vm

因此要调用JNINativeInterface结构体内的函数指针就必须先对env间接寻址。

(*env)的类型是const struct JNINativeInterface*(指向JNINativeInterface结构体的指针),这时候可以用这个指针调用结构体的成员函数指针,(*env)-> GetMethodID(env, jclass, const char*, const char*)。同理可分析JavaVM* vm。

----------------------------------------------------------------------------------------------------------------------------------------------

假如我们用C++编码,宏__cplusplus有定义,那么从最上面的宏#if defined(__cplusplus)可推断

  JNIEnv    代表类型 struct _JNIEnv

  JavaVM   代表类型 struct _JavaVM

那么JNIEnv* env实际上等价于声明 struct _JNIEnv*  env

  JavaVM* vm实际上等价于声明 struct _JavaVM* vm

要调用_JNIEnv结构体内的函数指针这直接使用env而不需间接寻址, env-> GetMethodID(jclass, const char*, const char*)。同理可分析JavaVM* vm。

现在可以回答刚才的猜测了,C中的(*env)类型是const struct JNINativeInterface*,C++中的env类型是struct _JNIEnv*,因此他们的数据类型不相同(虽然都是指针,但指向不同的结构体类型)。

我们再看结构体_JNIEnv(C++的JNIEnv所代表的类型),这个结构体内有一个成员const struct JNINativeInterface* functions,再仔细看_JNIEnv内定义的函数。当调用_JNIEnv内定义的函数时,其实就是通过functions这个指针调用JNINativeInterface内的函数指针,因此_JNIEnv的成员方法是JNINativeInterface的同名成员函数指针的包装而已,归根结底无论在C还是C++中其实都使用了JNINativeInterface结构体。这时调用JNINativeInterface的函数指针的第一参数是this,在C++中this代表指向当前上下文对象的指针其类型是struct _JNIEnv*(即JNIEnv*)。同理可分析_JavaVM。

NDK(13)JNIEnv和JavaVM的更多相关文章

  1. 【Android JNI】JNIEnv和JavaVM的区别

     JNI的实现可涉及两个关键类:JNIEnv和JavaVM. JavaVM:这个代表java的虚拟机.所有的工作都是从获取虚拟机的接口开始的.             第一种方式,在加载动态链接库的时 ...

  2. 第40篇-JNIEnv和JavaVM

    下面介绍2个与JNI机制相关的类型JNIEnv和JavaVM. 1.JNIEnv JNIEnv一般是是由虚拟机传入,而且与线程相关的变量,也就说线程A不能使用线程B的JNIEnv.而作为一个结构体,它 ...

  3. Jni 线程JNIEnv,JavaVM,JNI_OnLoad(GetEnv返回NULL?FindClass返回NULL?)

    此文章是关于NDK线程的第二篇理论知识笔记.主要有两个点,如下: 1.pthread_create(Too many arguements, expected 1) ?2.线程中如何获取JNIEnv? ...

  4. 第41篇-JNIEnv与JavaVM的初始化

    JavaVM和JNIEnv的初始化和JVM各模块的初始化都是在JNI_CreateJavaVM()函数中完成.这一篇将详细介绍JavaVM和JNIEnv的初始化过程. 1.初始化JavaVM Java ...

  5. NDK(5) Android JNI官方综合教程[JavaVM and JNIEnv,Threads ,jclass, jmethodID, and jfieldID,UTF-8 and UTF-16 Strings,Exceptions,Native Libraries等等]

    JNI Tips In this document JavaVM and JNIEnv Threads jclass, jmethodID, and jfieldID Local and Global ...

  6. NDK开发之javaVM

    1.关于JNIEnv和JavaVM JNIEnv是一个与线程相关的变量,不同线程的JNIEnv彼此独立.JavaVM是虚拟机在JNI层的代表,在一个虚拟机进程中只有一个JavaVM,因此该进程的所有线 ...

  7. 【Android 系统开发】Android JNI/NDK (三) 之 JNIEnv 解析

    jni.h文件 : 了解 JNI 需要配合 jni.h 文件, jni.h 是 Google NDK 中的一个文件, 位置是 $/Android-ndk-r9d/platforms/android-1 ...

  8. Android:JNI与NDK(一)

    友情提示:欢迎关注本人公众号,那里有更好的阅读体验以及第一时间获取最新文章 本篇目录 以下举例代码均来自:NDK示例代码 一.前言 安卓开发中很多场景需要用到NDK来开发,比如,音视频的渲染,图像的底 ...

  9. 继续研究NDK

    继续研究NDK 我在阿里云服务器上搭建了Android ndk的开发平台,并且借助这一平台研究了NDK的内部细节. NDK提供了Android本地编程的接口,让你可以开发高效的依赖库,提高程序的速度, ...

随机推荐

  1. google api , using a refresh token to get the access token

    router.get('/refresh',function(req,res){ oauth2Client.credentials = { refresh_token: '1/RqVyL7yLBxws ...

  2. 如何在64位的Windows中安裝PLSQLDEVELOPER 8

    先到 Oracle 官網下載Oracle Database 11g Release 2 Client (11.2.0.1.0) for Microsoft Windows (x64) ,接者依照以下步 ...

  3. 对cnblogs.com用户体验的评价

    一.对于cnblogs.com的用户体验我们先对以下问题进行回答: 1.你是什么样的用户, 有什么样的心理, 对cnblogs 的期望值是什么? 我们是正在学习软件工程课程的在校计算机专业大学生,在博 ...

  4. windows 2008 怎么对外开放端口

    服务器已经运行了程序,但是android客户端连接不上, 网上提示说用: start /min telnet 192.168.3.42 2121 查看,但是我的提示tenlet找不到命令,估计是端口的 ...

  5. [转载+原创]Emgu CV on C# (二) —— Emgu CV on 灰度化

    本文主要对彩色图片灰度化的方法及其实现过程进行总结,最终给出Emgu CV实现的代码. 一.灰度化原理及数学实现(转载自——<图像灰度化方法总结及其VC实现> 该篇文章使用opencv实现 ...

  6. spring mvc 学习笔记【1】---前言

    扎扎实实地掌握好技术 ----------------------------------------------------------------------------------------- ...

  7. 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

    // ConsoleApplication2.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include "stdafx.h ...

  8. 【POJ】【3710】Christmas Game

    博弈论 贾志豪论文上的题目……题解请看论文 Orz了一下Hzwer Source Code Problem: User: sdfzyhy Memory: 716K Time: 0MS Language ...

  9. 【转载】struct和typedef struct彻底明白了

    分三块来讲述: 1 首先://注意在C和C++里不同 在C中定义一个结构体类型要用typedef: typedef struct Student { int a; }Stu; 于是在声明变量的时候就可 ...

  10. Unity3D脚本中文系列教程(三)

    http://dong2008hong.blog.163.com/blog/static/4696882720140302323886/ Unity3D脚本中文系列教程(二) 示,属性不被序列化或显示 ...