Java中调用native函数传递的参数是Java数据类型,到了JNI层需进行数据类型转换,基本数据类型是在前面加个j,如int——>jint,应用数据类型除了基本数据类型的数据、Class、String和Throwable外,其余所有Java对象的数据类型在JNI中都用jobject表示。

//Java层com.xxx.yyy包MyJni.java中的jnitest有三个参数

jnitest(String path, String name, MyJni mj);

//JNI层对应的函数的后三个参数与jnitest的参数对应

com_xxx_yyy_MyJni_jnitest(JNIEnv *env, jobject thiz, jstring path, jstring name, jobject mj);

若对象类型都用就object表示,就好比是native层的void* 类型一样。第二个参数就object代表Java层的实例对象,如果Java层是static函数,则这个参数将是jclass,表示在调用哪个Java Class的静态函数。

JNIEnv介绍

JNIEnv是一个与线程相关的代表JNI环境的结构体,内部结构如图:

从上图可知JNIEnv提供了一些JNI系统函数:

调用Java的函数

操作jobejct对象等很多事情

每个线程都有一个JNIEnv,由于线程相关,所以一个线程不能使用另一个线程的JNIEnv结构体。JNIEnv是native函数转换成JNI层函数后有虚拟机传进来的,但当后台线程收到一个网络消息,且需有native层函数主动回调Java层函数时,JNIEnv如何传递?

这就要用到JavaVM,它是虚拟机在JNI层的代表,如下:

//全进程只有一个JavaVM对象,可保存且在任何地方都可使用

jint JNI_OnLoad(JavaVM* vm, void* reserved);

而JavaVM 和 JNIEnv的关系如下:

调用JavaVM的AttachCurrentThread函数,就可得到这个线程的JNIEnv结构体,即可在后台回调Java函数。

在后台线程退出前,需调用JavaVM的DetachCurrentThread函数释放对应的资源。

通过JNIEnv操作jobject

Java引用类型除了少数几个外,其余在JNI层都会用jobject来表示对象的数据类型,操作jobject的本质是操作Java对象的成员变量和成员函数。

jfieldID 和 jmethodID 介绍

JNI规则中用jfieldID 和 jmethodID表示Java类的成员变量和成员函数,可通过JNIEnv的函数得到:

jfieldID GetFieldID(jclass clazz, const char *name, const char *sig);

jmethodID GetMethodID(jclass clazz, const char *name, const char *sig);

其中,jclass表示Java类,name表示成员函数或成员变量的名字,sig为这个函数和变量的签名信息。使用方法如下:

MyJni(JNIEnv *env, jobject mj)......

{

//先找到com.xxx.yyy.MyJni类在JNI层中对应的jclass实例。

jclass myJniInterface = env->FindClass("com.xxx.yyy.MyJni");

//取出MyJni类中函数jnitest的jMethodID。

mMyJniMethodID = env->GetMethodID(myJniInterface, "jnitest", "(Ljava/lang/String;JJ)V");

//取出MyJni类中函数jnitest1的jMethodID。

mJniTestMethodID = env->GetMethodID(myJniInterface, "jnitest1",

"(Ljava/lang/String;Ljava/lang/String;)V");

如果每次操作jobject前都去查询jmethodID或jfieldID,将会影响程序的运行效率,故在初始化时可取出ID并保存起来供后续使用。

使用jfieldID 和 jmethodID

实例代码如下:

virtual bool myjni(const char* path, long long lastModified, long long fileSize)

{

jstring pathstr;

if ((pathStr = mEnv->NewStringUTF(path)) == NULL)

return;

/*

调用JNIEnv的CallVoidMethod函数,注意CallVoidMethod的参数:

第一个是MyJni的jobject对象,

第二个是函数myjni的jmethodID,后面是Java中myjni的参数

*/

mEnv->CallVoidMethod(mClient, mMyJniMethodID, pathStr, lastModified, fileSize);

mEnv->DeleteLocalRef(pathStr);

return (!mEnv->ExceptionCheck());

通过JNIEnv输出CallVoidMethod,再把jobject、jMethodID和对应的参数传进去,JNI层就能调用Java对象的函数。

实际上JNIEnv输出一系列类似CallVoidMethod的函数,形式如下:

NativeType CallMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)

其中type对应Java函数的返回值类型,例如CallIntMethod、CallVoidMethod等。

上面是针对非static函数,如果调用Java的static函数,则用JNIEnv输出的CallStatic< Type>Method系列函数。

通过jfieldID操作jobject的成员变量,如下:

//获得filedID可调用GetField系列函数获取jobject对应的成员变量值

nativeType GetField(JNIEnv *env, jobject obj, jfieldID fieldID)

//或调用SetField系列函数设置jobject对应的成员变量值

void SetField(JNIEnv *env, jobject obj, jfield fieldID, NativeType value)

JNI类型签名介绍

static JNINativeMethod gMethods[] = {

......

{

"processFile"

"(Ljava/lang/String;Ljava/lang/String;Landroid/media/MyJni;)V",

(void*)com_xxx_yyy_MyJni

},

......

}

代码中字符串”(Ljava/lang/String;Ljava/lang/String;Landroid/media/MyJni;)V”是Java中对应函数的签名信息,有参数类型和返回值类型共同组成。Java支持函数重载,可定义同名但不同参数的函数,进根据函数名无法找到具体函数,故JNI技术中将参数类型和返回值类型作为函数的签名信息。

JNI规范定义的函数签名信息格式:

(参数1类型标示参数2类型标示...参数n类型标示)返回值类型标示

“(Ljava/lang/String;Ljava/lang/String;Landroid/media/MyJni;)V”,其中括号内是参数类型的标识,最右边是返回值类型的标识,void类型对应的标识是V。当参数的类型是引用类型时,其格式是“L包名;”,其中包名中的“.”换成“/”。Ljava/lang/String表示是一个Java的String类型。

内构函数java_Android JNI参数传递相关推荐

  1. Python函数细节:多数量参数、强制参数传递、返回多值、匿名/内联函数

    1. 可接受任意数量参数的函数 接受任意数量的位置参数,使用参数*来解决 # rest是由所有其他位置参数组成的元组 def avg(first, *rest):return ( first + su ...

  2. python3 内置函数

    """ # 内置函数之---abs():绝对值 # a = 10086 a = 'hello' try:print(abs(a))with open('666.p', ' ...

  3. Python基础11-函数式编程与内置函数

    目录 函数即变量 lambda关键字定义匿名函数 高阶函数 内置函数map 内置函数filter 内置函数reduce 内置函数看文档 函数即变量 书接上回,Python里面,函数就是变量,可以被当成 ...

  4. python常用的内置函数

    内置函数,就是Python提供的, 可以直接拿来直接用的函数. 一.数字相关 01 数据类型 bool() 描述:测试一个对象是True, 还是False.bool 是 int 的子类. 语法:cla ...

  5. day4 匿名函数、装饰器、生成器、迭代器、内置函数、 json 与 pickle 模块

    文章目录 1.列表生成式 2.匿名函数 3.装饰器 4.生成器 5.迭代器 6.内置函数 7.json & pickle 序列化与反序列化 1.列表生成式 可通过特定语句便捷生成列表 list ...

  6. c语言函数参数类型检查,内联函数在编译时是否做参数类型检查?

    先说宏和函数的区别: 1. 宏做的是简单的字符串替换(注意是字符串的替换,不是其他类型参数的替换),而函数的参数的传递,参数是有数据类型的,可以是各种各样的类型. 2. 宏的参数替换是不经计算而直接处 ...

  7. 列举5个python内置函数_Python5个内建高阶函数的使用

    描述 本文结合各种实际的例子详细讲解了Python5个内建高阶函数的使用,能够帮助理解Python的数据结构和提高数据处理的效率,这5个函数分别是: map reduce filter sorted/ ...

  8. 深浅拷贝、函数、内置函数、文件处理、三元运算、递归

    深浅拷贝 import copy copy.copy() #浅拷贝 copy.deepcopy() #深拷贝 num = 110 copynum = num #赋值 一.数字和字符串 对于 数字 和 ...

  9. python常用内置函数总结-Python 常用内置函数

    Python 常用内置函数如下: 1. abs()函数返回数字的绝对值. print( abs(-45) )# 返回45print("abs(0.2):",abs(0.2))#返回 ...

最新文章

  1. 对称加密----AES和DES加密、解密
  2. python视频下载-Python实现视频下载功能
  3. jquery判断页面滚动条(scroll)是上滚还是下滚,且是否滚动到头部或者底部
  4. C#中教你一步步实现一个电话本窗体程序
  5. 大棚骨架搭建好 科学施肥增收增产
  6. rssi室内定位算法原理_室内定位方案常用的4种定位算法
  7. php正则表达式 包含特殊字符,php正则表达式的特殊字符含义
  8. mac文件丢失,苹果电脑有没有好用的恢复软件?
  9. 清华紫光输入法linux,紫光拼音输入法
  10. FLASH闪存编程原理与步骤
  11. 如何更改Excel2016中折线图的连接点颜色和样式?
  12. 8脚语音芯片指的是什么?有什么特点?以及如何区分和选型
  13. 给深度学习新手做项目的10个建议
  14. 100 Most Brilliant Tech Hacks You Need To Know Right Now
  15. 知乎热榜“人脸安全”,这些博主怎么看
  16. 跟着老猫来搞GO-基础进阶
  17. docker 批量垃圾清理
  18. 2021年挖矿电脑配置推荐
  19. Qt_OpenCV_VS2013配置方法
  20. 量化投资实战教程(1)—基于backtrader的简单买入卖出策略

热门文章

  1. html怎么在字体中加波浪线,CSS3实现文字波浪线效果
  2. linux隐藏apache信息,Linux下如何隐藏Apache版本号信息
  3. CSS3 线性渐变背景的过渡效果
  4. UE4 HTC VIVE - 番外篇 - 局域网联机(一)
  5. 深入浅出FSUIPC的作用以及使用方法
  6. 简单的UTF8编码生成
  7. 设计模式C++实现 ——状态模式
  8. C++设计模式之三 单例模式
  9. centos 6 安装mysql,CentOS6.5安装MySQL教程(完整教程)
  10. SharePoint List item数量超过5000的解决办法