JNI接口

JNI是Java Native Interface的英文缩写,类似一种标准,提供了很多的API,使Java可以和C/C++进行通信。而JNI接口正是Java层世界与C/C++语言世界之间的桥梁。

探究:为什么使用JNI呢?

1.使用现有的开源库,现在很多优秀的开源库都是用C/C++编写的。

2.代码的保护,Android APK的Java代码容易被反编译,而C/C++更难 反编译。

3.便于移植,用C/C++写的库可以方便在其他嵌入式平台使用。

一:通过JNI接口实现Java层与Native层相互调用

现在来看下面这一张图,通过这张图完美的展示JNI接口的规则。

首先看到这张图片左边部分是熟悉的Java层开发,中间部分是要用到JNI接口来调用相关的C/C++函数。那么C/C++是怎么调用Java代码的呢?这就要用到反射,在JNI接口中提供了很多函数供我们进行调用。

JNI接口

二:JNI接口

JNI接口是谷歌开发人员为了方便Java层与C/C++层进行通信而对外提供的接口,对应的接口描述文档在“jni.h”头文件中。

这一排就是JNI接口中的数据类型,数据类型就是在基本数据类型前加了一个字母j而已,记忆起来比较简单。如下图所示。

JNI接口

紧接着是对象、数组等类型,如下图所示。

JNI接口

接下来介绍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接口函数和它们的用途,如下表所示。

JNI接口

猜你喜欢

转载自blog.51cto.com/15002917/2585492
JNI