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)

 




相关推荐

实现Java代码调用本地C/C++ dll/so有两种方式: 1、JNI(Java Native Interface) 如果有一个现有的.dll/.so文件,使用JNI技术调用,我们首先需要使用C语言