JNI是Java Native Interface的英文缩写,相似一种标准,提供了不少的API,使Java能够和C/C++进行通讯。而JNI接口正是Java层世界与C/C++语言世界之间的桥梁。java
探究:为何使用JNI呢?api
1.使用现有的开源库,如今不少优秀的开源库都是用C/C++编写的。数组
2.代码的保护,Android APK的Java代码容易被反编译,而C/C++更难 反编译。ide
3.便于移植,用C/C++写的库能够方便在其余嵌入式平台使用。函数
一:经过JNI接口实现Java层与Native层相互调用编码
如今来看下面这一张图,经过这张图完美的展现JNI接口的规则。 code
首先看到这张图片左边部分是熟悉的Java层开发,中间部分是要用到JNI接口来调用相关的C/C++函数。那么C/C++是怎么调用Java代码的呢?这就要用到反射,在JNI接口中提供了不少函数供咱们进行调用。对象
二:JNI接口blog
JNI接口是谷歌开发人员为了方便Java层与C/C++层进行通讯而对外提供的接口,对应的接口描述文档在“jni.h”头文件中。接口
这一排就是JNI接口中的数据类型,数据类型就是在基本数据类型前加了一个字母j而已,记忆起来比较简单。以下图所示。
紧接着是对象、数组等类型,以下图所示。
接下来介绍JNI函数,包含的有如下几种类型,其中Call开头的函数字面意思就是调用,这里指的是经过反射调用Java层方法;Get开头的函数字面意思就是获取,这里指的是经过反射获取Java层字段的值;Set开头的函数字面意思就是设置,这里指的是经过反射修改Java层字段的值;New开头的就是建立其余类型的函数。
jclass (FindClass)(JNIEnv, const char*);
jmethodID (GetMethodID)(JNIEnv, jclass, const char, const char);
jobject (CallObjectMethod)(JNIEnv,jobject,jmethodID, ...);
jfieldID (GetFieldID)(JNIEnv, jclass, const char, const char);
jobject (GetObjectField)(JNIEnv, jobject, jfieldID);
void (SetObjectField)(JNIEnv, jobject, jfieldID, jobject);
jmethodID(GetStaticMethodID)(JNIEnv,jclass,const char,constchar);
jobject (CallStaticObjectMethod)(JNIEnv,jclass, jmethodID, ...);
jfieldID (GetStaticFieldID)(JNIEnv,jclass,const char,const char);
jobject (GetStaticObjectField)(JNIEnv, jclass, jfieldID);
void (SetStaticObjectField)(JNIEnv, jclass, jfieldID, jobject);
jstring (NewStringUTF)(JNIEnv, const char*);
接下来对上面的JNI接口函数进行了解。
(1)调用Java层普通方法
Jobject:返回值,这里返回的是jobject 。
(*CallObjectMethod):这里调用的是普通方法。
(JNIEnv*,jobject,jmethodID, ...):参数列表信息。
第一参数是JNIEnv*,是本地调用接口,里面提供大量的JNI接口函数供调用。第二个参数是jobject对象。 第三个参数是方法ID,该参数能够经过GetMethodID函数获取。“...”表示的是调用方法的参数列表信息。
探究:什么是Get MethodID?
使用GetMethodID函数获取Java层的方法ID,原形以下:
jmethodID:返回值,这里返回的是Java层方法ID。
(*GetMethodID):获取普通方法ID。
(JNIEnv, jclass, const char, const char*):参数列表信息。
该函数的第二个参数是jclass,能够经过FindClass函数获取。第三个参数是Java层的方法名称,第四参数是Java层方法的签名信息。
探究:什么是FindClass?
FindClass函数经过反射获取Java类,原形以下:
Jclass:返回值,这里返回的是java类。
(*FindClass):反射获取Java类。
(JNIEnv, const char):参数列表信息。
(2)获取Java层实例字段的值
Jobject:返回值,这里返回的是jobject 。 (*GetObjectField):获取Java层实例字段的值。
(JNIEnv*, jobject, jfieldID):参数列表信息。第三参数是实例字段ID,该参数能够经过GetFieldID函数获取,原形以下:
jfieldID:返回值,这里返回的是实例字段ID。 (*GetFieldID):获取实例字段ID。 (JNIEnv*, jclass, const char*, const char*):参数信息。该函数的第三个参数是实例字段名称,第四个参数是实例字段的签名信息。
(3)设置Java层实例字段的值
Void:返回值为void。
(*SetObjectField):设置Java层实例字段的值。
(JNIEnv*, jobject, jfieldID, jobject):参数信息。第四个参 数为Java层实例字段要设置的值。
(4)调用Java层静态方法
Jobject:返回值,这里返回的是jobject 。
(*CallStaticObjectMethod):这里调用的是静态方法。
(JNIEnv,jclass, jmethodID, ...):参数列表信息。第一参数是JNIEnv,是本地调用接口,里面提供大量的JNI接口函数供咱们调用。第二个参数是jclass。第三个参数是静态方法ID,该参数能够经过GetStatic MethodID函数获取。后面“...”表示的是调用方法的参数列表信息。
探究:什么是GetStaticMethodID?
使用GetStaticMethodID函数获取Java层的静态方法ID,原形以下:
jmethodID :返回值,这里返回的是Java层方法ID。
(*GetStaticMethodID):获取静态方法ID。
(JNIEnv, jclass, const char, const char*):参数列表信息。
该函数的第二个参数是jclass,能够经过FindClass函数获取。第三个参数是Java层的方法名称,第四参数是Java层方法的签名信息。
(5)获取Java层静态字段的值
Jobject:返回值,这里返回的是jobject 。 (*GetStaticObjectField):获取Java层静态字段的值。 (JNIEnv*, jclass, jfieldID): 参数列表信息。第三参数是静态字段ID,该参数能够经过GetStaticFieldID函数获取,原形以下: jfieldID: 返回值,这里返回的是实例字段ID。 (*GetStaticFieldID): 获取静态字段ID。 (JNIEnv*, jclass, const char*, const char*): 参数信息。该函数的第三个参数是静态字段名称,第四个参数是静态字段的签名信息。
(6)设置Java层静态字段的值
void : 返回值为void。
(*SetStaticObjectField): 设置Java层静态字段的值。
(JNIEnv*, jclass, jfieldID, jobject):参数信息。第四个参数为Java层静态字段要设置的值。
(7)New开头的函数就是建立,借助new开头的函数api建立相应的基本类型、数组、对象,原形:
Jstring:返回值为jstring。
(*NewStringUTF) :建立utf-8编码的字符串。
(JNIEnv*, const char*):参数列表信息。第二个就是参数是char*类型的值,在这里能够输入想要建立的字符串。
小结:
JNI接口是实现Java层与C/C++层相互调用,以及经常使用的JNI接口函数和它们的用途,以下表所示。