JNI
阅读数:76 评论数:0
跳转到新版页面分类
python/Java
正文
Java Native Interface是Java语言的本地编程接口,我们可以通过JNI实现一些用java语言不便实现的功能。
JNI开发流程主要分为以下6步:
1、写一个Java类,在其中声明对应要调用的native方法,用native关键字修饰。比如:private static native int native_newInstance();
2、通过javah命令生成java类对应的C/C++头文件。javah -encoding utf-8 -cp src com.young.soundtouch.SourchTouch、
javah生成的头文件大致是这样的:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_young_soundtouch_SoundTouch */
#ifndef _Included_com_young_soundtouch_SoundTouch
#define _Included_com_young_soundtouch_SoundTouch
#ifdef __cplusplus
extern "C" {
#endif
#undef com_young_soundtouch_SoundTouch_SETTING_USE_AA_FILTER
#define com_young_soundtouch_SoundTouch_SETTING_USE_AA_FILTER 0L
/*
* Class: com_young_soundtouch_SoundTouch
* Method: native_getDefaultSampleElementSize
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_young_soundtouch_SoundTouch_native_1getDefaultSampleElementSize
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
(1)包含了jni.h头文件(一般位于$JAVA_HOME/jdk-version/include),这是JNI中所有的类型、函数、宏等定义的地方。
(2)在类中声明的常量(static final)类型会在头文件中以宏的形式出现。
(3)JNIEXPORT是函数的导出方式。
(4)JNICALL函数的调用方式也就是汇编级别参数的传入方式。
(5)超长的函数名,格式:Java_类全名_native方法名,其中会把名中的点替换成下划线,同时为了避免冲突把下划线替换成_1。
(6)方法的参数,上面的这个方法在JAVA的声明中实际上是没有参数的,其中的JNIENV顾明思义是JNI环境,和具体的线程绑定。而第二个参数jclass其实是java中的Class,因为上面是一个static方法,因此第二个参数是jclass。如果是一个实例方法则对应第二个参数是jobject,相当于java中的this。
3、在C/C++中实现头文件中声明的函数。
4、编译C/C++代码为动态库。
5、在java代码中加载动态库,即可像调用Java方法一样,调用到native函数。
类型转换
javah生成的头文件里面使用的类型都是jni.h定义的,目的是做到平台无关。
1、基本对应关系
jni 类型 | JAVA类型 | 对应本地类型 | 类型签名 |
---|---|---|---|
jboolean | boolean | uint8_t | Z |
jbyte | byte | char | B |
jcahr | char | uint16_t | C |
jshort | short | int16_t | S |
jint | int | int32_t | I |
jlong | long | int64_t | J |
jfloat | float | float | F |
jdouble | double | double | D |
void | void | void | V |
2、引用类型对应关系
java类型 | JNI 类型 | java类型 | JNI 类型 |
---|---|---|---|
所有的实例引用 | jobject | java.lang.Class | jclass |
java.lang.String | jstring | Ocject[] | jobjectArray |
java.lang.Throwable | jthrowable | 基本类型[] | jxxxArray |
除了上面定义的String、Class、Throwable,其他的类都是以jobject的形式出现的。
JNI中操作jobject
在JNI使用类似于反射的方式来进行field和method的操作:
jfieldID GetFieldID(jclass clazz, const char *name, const char *sig);
jfieldID GetStaticFieldID(jclass clazz, const char *name, const char *sig);
jmethodID GetMethodID(jclass clazz, const char *name, const char *sig);
jmethodID GetStaticMethodID(jclass clazz, const char *name, const char *sig) ;
jclass FindClass(const char *name)需要注意的是name参数,它是一个类包名的全称,但是需要把包中的点替换成斜杠。
1、成员变量
get
(1)<type> Get<type> Field(jobject,jfieldID);
(2)<type> GetStatic<type> Filed(jobject,jfieldID);
set
(1)void Set<type> Field(jobject obj,jfieldID fieldID,<type>val);
(2)void SetStatic<type>Field(jclass clazz,jfieldID fieldID,<type> value);
2、参数传递
(1)Call<type> Method(jobject obj,jmethodID methodID,...)
可变长参数。
(2)Call<type> MethodV(jobject obj,jmethodID methodID,va_list args)
(3)Call<type> MethodA(jobject obj,jmethodID mthodID,const jvalue *args)
jvalue是JNI中各个数据类型的union。
3、调用实例方法
(1)<type> Call<type> Method(jobject obj,jmethodId methodId,...)
(2)<type> Call<type> MethodV(jobject obj,jmethodId methodId,va_list args);
(3)Call<type>MethodA(jobject obj,jmethodID methodID, const jvalue * args)
4、调用静态方法
(1)<type> CallStatic<type> Method(jobject obj,jmethodId methodId,...)
(2)<type> CallStatic<type> MethodV(jobject obj,jmethodId methodId,va_list args);
(3)CallStatic<type>MethodA(jobject obj,jmethodID methodID, const jvalue * args)
5、调用父类方法
(1)<type> CallNonvirtual<type> Method(JNIEnv *env,jobject obj,jclass clazz,jmethodId methodId,...)
(2)<type> CallNonvirtual<type> MethodV(JNIEnv *env,jobject obj,jclass clazz,jmethodId methodId,va_list args);
(3)CallNonvirtual<type>MethodA(JNIEnv *env,jobject obj,jclass clazz,jmethodID methodID, const jvalue * args)
6、数组的操作
(1)获取数组长度 jsize GetArrayLength(jarray array)
(2)创建新数组 ArrayType New<PrimitiveType>Array(jsize length);
(3)通过JNI数组获取一个C/C++数组:<type> * Get<type>ArrayElements(jshortArray array,jboolean *isCopy)
(4)指定原数组的范围取一个C/C++数组(该方法只针对于原始数组,不包括Object数组):void Get<PrimitiveType>ArrayRegion(JNIEnv *env,ArrayTypeArray,jsize start,jsize len,NativeType *buf)
(5)设置数组元素:void Set<type>ArrayRegion(jshortArray array,jsize start,jsize len,const <type> *buf)。如果是Object数组需要使用: void setObjectArrayElement(JNIEnv *env,jobjectArray array,jsize index,jobject value);
(6)使用完之后,释放数组: void Release<type> ArraysElements(jshortArray array,jshort *elems,jint mode)