在實(shí)際開(kāi)發(fā)中,JNI與java有很多場(chǎng)景需要傳遞數(shù)據(jù),有時(shí)是基本數(shù)據(jù)類型,而有時(shí)則是自定義類型。在遇到通過(guò)回調(diào)Java中函數(shù)進(jìn)行自定義類型傳遞時(shí),是不可以直接傳遞,需要進(jìn)行轉(zhuǎn)換,本篇將針對(duì)參數(shù)存在自定義類型和自定義類型數(shù)組兩種場(chǎng)景進(jìn)行舉例說(shuō)明。
基本數(shù)據(jù)類型參數(shù)數(shù)組
針對(duì)如下代碼片段說(shuō)明:
//基本數(shù)據(jù)類型參數(shù)數(shù)組的靜態(tài)函數(shù)
package com.test.jni;
//Java 函數(shù)
public class TestFunc{
public static void testFunc(float vals[]){
//...
}
}
//JNI函數(shù)回調(diào)片段
jclass clz = jenv->FindClass("com/test/jni/TestFunc");
jmethodID methodId = env->GetMethodID(clz,"TestFunc","([F)V");
float[] data = new float[]{1.f,2.f};
//!!錯(cuò)誤示例!!
env->CallStaticVoidMethod(clz,methodId,data);
//正確用例
jfloatArray array = env->NewFloatArray(2);
//參數(shù)1:待賦值數(shù)組;參數(shù)2:賦值起始位置;參數(shù)3:賦值長(zhǎng)度;參數(shù)4:數(shù)據(jù)源
env->SetFloatArrayRegion(array,0,3,data);
env->CallStaticVoidMethod(clz,methodId,array);
自定義結(jié)構(gòu)類型參數(shù)數(shù)組
針對(duì)如下代碼片段說(shuō)明:
//自定義類型
package com.test.jni;
public class MyObject{
private String name;
private int number;
//some getters and setters
...
public MyObject(String name, int number){
this.name = name;
this.number = number;
}
}
//自定義類型參數(shù)數(shù)組的靜態(tài)函數(shù)
package com.test.jni;
//Java 函數(shù)
public class TestFunc{
public static void testFunc(MyObject vals[]){
//...
}
}
//JNI函數(shù)回調(diào)片段
jclass clz = jenv->FindClass("com/test/jni/TestFunc");
jmethodID methodId = jenv->GetMethodID(clz,"TestFunc","([Lcom/test/jni/MyObject;)V");
MyObject myObjects = new MyObject[2];
for(int i = 0; i < myObjects.length; i++){
myObjects[i] = new MyObject("name_" + i, i);
}
//!!錯(cuò)誤示例!!
jenv->CallStaticVoidMethod(clz,methodId,myObjects);
//正確用例: 需要在JNI層創(chuàng)建類型數(shù)組
jclass jclzMyObject = jenv->FindClass("com/test/jni/MyObject");
jmethodID jmethodConstructID = jenv->GetMethodID(jclzMyObject, "<init>", "()V");
//進(jìn)行實(shí)例創(chuàng)建
jobjectArray array = jenv->NewObjectArray(myObjects.length, jclzMyObject,NULL);
for(int i = 0; i < 2; i++){
jobject jobjMyObj = jenv->NewObject(jclzMyObject, jmethodConstructID);
jfieldID nameField = jenv->GetFieldID(jclzMyObject, "name","Ljava/lang/String;");
jfieldID numberField = jenv->GetFieldID(jclzMyObject,, "number","I");
jenv->SetObjectField(jobjMyObj, nameField, myObjects[i].name);
jenv->SetIntField(jobjMyObj, numberField, myObjects[i].number);
jenv->SetObjectArrayElement(array, i, jobjMyObj);
jenv->DeleteLocalRef(jobjMyObj);
}
//調(diào)用類的靜態(tài)方法
jenv->CallStaticVoidMethod(clz,methodId,array);
通過(guò)在JNI層重新創(chuàng)建實(shí)例的數(shù)組,并將數(shù)組進(jìn)行賦值,此時(shí)可以通過(guò)該反射調(diào)用Java函數(shù)的方式將JNI層的數(shù)值傳遞到Java層進(jìn)行后續(xù)的計(jì)算處理。有以下需要注意的地方:
- 在JNI層創(chuàng)建實(shí)例對(duì)象時(shí),需要對(duì)Java層該類的構(gòu)造函數(shù)進(jìn)行有針對(duì)性的實(shí)現(xiàn);
- 在JNI層創(chuàng)建實(shí)例對(duì)象之后,尤其是還需要加入其數(shù)組數(shù)據(jù)結(jié)構(gòu)中,需要在最后進(jìn)行本地引用的釋放,否則在循環(huán)創(chuàng)建超過(guò)512個(gè)引用之后則會(huì)溢出;
- 針對(duì)非靜態(tài)方法,則需要類似地通過(guò)反射在JNI層創(chuàng)建類的實(shí)例,通過(guò)調(diào)用實(shí)例函數(shù)方式;
CSDN 同步發(fā)布 地址