jni使用深入分析

想要查看jni函数的具体说明,可以查看百度文库的 jni此常用函数
1.部分类型转换及常用函数说明
1) 本地方法对Java字符串的操作
const jchar *GetStringChars(jstring str, jboolean*isCopy)
将一个jstring对象,转换为(UTF-16)编码的宽字符串(jchar*)。
const char *GetStringUTFChars(jstring str,jboolean *isCopy)
将一个jstring对象,转换为(UTF-8)编码的字符串(char*)

第一个参数传入一个指向Java 中String对象的jstring引用。第二个参数传入的是一个jboolean的指针,其值可以为NULL、JNI_TRUE、JNI_FLASE。

如果为JNI_TRUE则表示开辟内存,然后把Java中的String拷贝到这个内存中,然后返回指向这个内存地址的指针。

如果为JNI_FALSE,则直接返回指向Java中String的内存指针。这时不要改变这个内存中的内容,这将破坏String在Java中始终是常量的规则。

如果是NULL,则表示不关心是否拷贝字符串。

使用这两个函数取得的字符,在不使用的时候,要分别对应的使用下面两个函数来释放内存。

RealeaseStringChars(jstring jstr, const jchar*str)

RealeaseStringUTFChars(jstring jstr, constchar* str)

第一个参数指定一个jstring变量,即要释放的本地字符串的资源

第二个参数就是要释放的本地字符串
2) 创建Java String对象

jstring NewString(const jchar *unicode, jsizelen) // 根据传入的宽字符串创建一个Java String对象

jstring NewStringUTF(const char *utf) // 根据传入的UTF-8字符串创建一个Java String对象

3) 返回Java String对象的字符串长度

jsize GetStringLength(jstring jstr) //返回一个java String对象的字符串长度

jsize GetStringUTFLength(jstring jstr) //返回一个java String对象经过UTF-8编码后的字符串长度

使用示例:
JNIEXPORT jstring JNICALL Java_com_wonder_Utils_getString(JNIEnv *env,jclass arg, jstring prompt) {
const char* str = (*env)->GetStringUTFChars(env, prompt, 0);
jstring res = (*env)->NewStringUTF(env, str);
(*env)->ReleaseStringUTFChars(env, prompt, str);
return res;
}

4)Java数组在本地代码中的处理
我们可以使用GetFieldID获取一个Java数组变量的ID,然后用GetObjectFiled取得该数组变量到本地方法,返回值为jobject,然后我们可以强制转换为jArray类型。

typedef jarray jbooleanArray;

typedef jarray jbyteArray;

typedef jarray jcharArray;

typedef jarray jshortArray;

typedef jarray jintArray;

typedef jarray jlongArray;

typedef jarray jfloatArray;

typedef jarray jdoubleArray;

typedef jarray jobjectArray;

jArray类型是JNI定义的一个对象类型,它并不是C/C++的数组,如int[]数组,double[]数组等等。所以我们要把jArray类型转换为C/C++中的数组来操作。

JNIEnv定义了一系列的方法来把一个jArray类型转换为C/C++数组或把C/C++数组转换为jArray。

jsize GetArrayLength(jarray array) // 获得数组的长度

jobjectArray NewObjectArray(jsize len, jclass clazz, jobjectinit) // 创建对象数组,指定其大小

jobject GetObjectArrayElement(jobjectArray array, jsizeindex) // 获得数组的指定元素

void SetObjectArrayElement(jobjectArray array, jsizeindex,jobject val) // 设置数组元素

jbooleanArrayNewBooleanArray(jsize len) // 创建Boolean数组,指定其大小

jbyteArrayNewByteArray(jsize len) //下面的都类似,创建对应类型的数组,并指定大小

jcharArrayNewCharArray(jsize len)

jshortArrayNewShortArray(jsize len)

jintArrayNewIntArray(jsize len)

jlongArrayNewLongArray(jsize len)

jfloatArrayNewFloatArray(jsize len)

jdoubleArrayNewDoubleArray(jsize len)

// 获得指定类型数组的元素

jboolean * GetBooleanArrayElements(jbooleanArray array,jboolean *isCopy)

jbyte * GetByteArrayElements(jbyteArray array, jboolean*isCopy)

jchar * GetCharArrayElements(jcharArray array, jboolean*isCopy)

jshort * GetShortArrayElements(jshortArray array, jboolean*isCopy)

jint * GetIntArrayElements(jintArray array, jboolean*isCopy)

jlong * GetLongArrayElements(jlongArray array, jboolean*isCopy)

jfloat * GetFloatArrayElements(jfloatArray array,jboolean *isCopy)

jdouble * GetDoubleArrayElements(jdoubleArray array,jboolean *isCopy)

// 释放指定数组

void ReleaseBooleanArrayElements(jbooleanArrayarray,jboolean *elems,jint mode)

void ReleaseByteArrayElements(jbyteArray array,jbyte*elems,jint mode)

void ReleaseCharArrayElements(jcharArray array,jchar*elems,jint mode)

void ReleaseShortArrayElements(jshortArray array,jshort*elems,jint mode)

void ReleaseIntArrayElements(jintArray array,jint*elems,jint mode)

void ReleaseLongArrayElements(jlongArray array,jlong*elems,jint mode)

void ReleaseFloatArrayElements(jfloatArray array,jfloat*elems,jint mode)

void ReleaseDoubleArrayElements(jdoubleArrayarray,jdouble *elems,jint mode)

void * GetPrimitiveArrayCritical(jarray array, jboolean*isCopy)

void ReleasePrimitiveArrayCritical(jarray array, void*carray, jint mode)

void GetBooleanArrayRegion(jbooleanArray array,jsizestart, jsize len, jboolean *buf)

void GetByteArrayRegion(jbyteArray array,jsize start,jsize len, jbyte *buf)

void GetCharArrayRegion(jcharArray array,jsize start,jsize len, jchar *buf)

void GetShortArrayRegion(jshortArray array,jsize start,jsize len, jshort *buf)

void GetIntArrayRegion(jintArray array,jsize start,jsize len, jint *buf)

void GetLongArrayRegion(jlongArray array,jsize start,jsize len, jlong *buf)

void GetFloatArrayRegion(jfloatArray array,jsize start,jsize len, jfloat *buf)

void GetDoubleArrayRegion(jdoubleArray array,jsizestart, jsize len, jdouble *buf)

void SetBooleanArrayRegion(jbooleanArray array, jsizestart, jsize len,const jboolean *buf)

void SetByteArrayRegion(jbyteArray array, jsize start,jsize len,const jbyte *buf)

void SetCharArrayRegion(jcharArray array, jsize start,jsize len,const jchar *buf)

void SetShortArrayRegion(jshortArray array, jsizestart, jsize len,const jshort *buf)

void SetIntArrayRegion(jintArray array, jsize start,jsize len,const jint *buf)

void SetLongArrayRegion(jlongArray array, jsize start,jsize len,const jlong *buf)

void SetFloatArrayRegion(jfloatArray array, jsizestart, jsize len,const jfloat *buf)

void SetDoubleArrayRegion(jdoubleArray array, jsizestart, jsize len,const jdouble *buf)

上面是JNIEnv提供给本地代码调用的数组操作函数,大致可以分为下面几类:

1) 获取数组的长度

jsize GetArrayLength(jarray array);

2) 对象类型数组的操作

jobjectArray NewObjectArray(jsize len, jclassclazz,jobject init) // 创建

jobject GetObjectArrayElement(jobjectArray array, jsizeindex) // 获得元素

void SetObjectArrayElement(jobjectArray array, jsizeindex,jobject val) // 设置元素

JNI没有提供直接把Java的对象类型数组(Object[ ])直接转到C++中的jobject[ ]数组的函数。而是直接通过Get/SetObjectArrayElement这样的函数来对Java的Object[ ]数组进行操作

3) 对基本数据类型数组的操作

基本数据类型数组的操作方法比较多,大致可以分为如下几类:

GetArrayElements/RealeaseArrayElements;

GetArrayElements(Array arr, jboolean*isCopied);

这类函数可以把Java基本类型的数组转换到C/C++中的数组。有两种处理方式,一是拷贝一份传回本地代码,另一种是把指向Java数组的指针直接传回到本地代码,处理完本地化的数组后,通过RealeaseArrayElements来释放数组。处理方式由Get方法的第二个参数isCopied来决定。

RealeaseArrayElements(Arrayarr,* array, jint mode)用这个函数可以选择将如何处理Java和C/C++本地数组:

其第三个参数mode可以取下面的值:

l 0:对Java的数组进行更新并释放C/C++的数组

l JNI_COMMIT:对Java的数组进行更新但是不释放C/C++的数组

l JNI_ABORT:对Java的数组不进行更新,释放C/C++的数组
例如1:

Test.java

public class Test {

     privateint [] arrays=new int[]{1,2,3,4,5};

     publicnative void show();

     static{

               System.loadLibrary("NativeTest");

     }

     publicstatic void main(String[] args) {

               newTest().show();

     }

}

本地方法:

void native_test_show(JNIEnv * env, jobject obj)

{

     jfieldIDid_arrsys=env->GetFieldID(env->GetObjectClass(obj),"arrays","[I");

     jintArrayarr=(jintArray)(env->GetObjectField(obj, id_arrsys));

     jint*int_arr=env->GetIntArrayElements(arr,NULL);

     jsizelen=env->GetArrayLength(arr);

     for(inti=0; i<len; i++)

     {

               cout<<int_arr[i]<<endl;

     }

     env->ReleaseIntArrayElements(arr,int_arr,JNI_ABORT);

}
例如2
JNIEXPORT jbyteArray JNICALL Java_com_wonder_Utils_getbyte(JNIEnv *env,
jclass arg, jbyteArray byteArr) {
int len = (*env)->GetArrayLength(env, byteArr);
jbyte* jarr = (*env)->GetByteArrayElements(env, byteArr, JNI_FALSE);
jbyteArray jarrRV = (*env)->NewByteArray(env, len);
(*env)->SetByteArrayRegion(env, jarrRV, 0, len, jarr);
return jarrRV;
}

JNIEXPORT jintArray JNICALL Java_com_wonder_Utils_getIntArray(JNIEnv *env,
jclass arg, jintArray intArr) {
jsize len = (*env)->GetArrayLength(env, intArr);
jint* carr = (*env)->GetIntArrayElements(env, intArr, JNI_FALSE);
int i;
for (i = 0; i < len; i++) {
*(carr + i) += 10;
}
return intArr;
}
5.对象和结构体的传递
示例:
typedef struct Info {
int id;
char name[100];
} Info_t;

package com.wonder;

public class Info {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return “Info [id=” + id + “, name=” + name + “]”;
}
}

C代码:
Java对象传递到c中
JNIEXPORT void JNICALL Java_com_wonder_Utils_sendObj(JNIEnv *env, jclass arg, jobject obj){
jclass cls_objClass = (*env)->GetObjectClass(env,obj);
jmethodID methodId = (*env)->GetMethodID(env,cls_objClass, “getName”,”()Ljava/lang/String;”);
jstring js_name = (jstring)(*env)->CallObjectMethod(env,obj,methodId,NULL);
}
将C中的结构体传递给Java对象
JNIEXPORT jint JNICALL Java_com_wonder_Utils_getInfo(JNIEnv *env, jclass arg,
jobject jobj) {
Info_t* bar = malloc(sizeof(Info_t));
jclass clazz;
jfieldID fid;
//init the bar data of C
strcpy(bar->name,”Info”);
bar->id = strlen(bar->name);

 // mapping bar of C to foo
clazz = (*env)->GetObjectClass(env, jobj);
if(clazz==0){
    return (-1);
}
fid = (*env)->GetFieldID(env, clazz, "id", "I");
(*env)->SetIntField(env,jobj,fid,bar->id);
fid = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;");
jstring name = (*env)->NewStringUTF(env, bar->name);
(*env)->SetObjectField(env,jobj,fid,name);
free(bar);
return 0;

}
使用方式
Info info = new Info();
info.setId(1);
info.setName(“aaa”);
Utils.sendObj(info);
Info info2 = new Info();
Utils.getInfo(info2);
详细的参考jni讲解
jni的数据结构解释参考jni数据结构解释
数据类型转化数据类型转化
jni函数解析jni函数大全
jni操作复杂对象

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值