JNI 資料型態與傳送
資料型態對應
Java JNI 的資料,是位於JVM之內,而C/C++的資料則位於JVM之外。Java傳到C/C++,必需有相互對應的型態。
基本資料型態
Java的 8 個基本資料型態
byte, short, int, long, float, double, char, boolean
分別對應到 C/C++的
jbyte, jshort, jint, jlong, jfloat, jdouble, jchar, jboolean
陣列
Java的 byte[], short[]…分別對應到C/C++的jbyteArray, jshortArray…..
其他
另外還有Java的object, Class, String, Throwable對應到jobject, jclass, jstring, jthrowable
詳細列表如下
Java | C/C++ | 備註 |
byte | jbyte | |
short | jshort | |
int | jint | |
long | jlong | |
float | jfloat | |
double | jdouble | |
char | jchar | |
boolean | jboolean | |
byte[] | jbyteArray | |
short[] | jshortArray | |
int[] | jintArray | |
long[] | jlongArray | |
float[] | jfloatArray | |
double[] | jdoubleArray | |
char[] | jcharArray | |
boolean[] | jbooleanArray | |
Object[] | jobjectArray | |
all Object | jobject | |
Class | jclass | |
String | jstring | |
Throwable | jthrowable |
C/C++原本沒有 jbyte, jshort, ……這些型態的,怎麼會無端生出這些呢? 因為這些新型態在 jni.h標頭檔中重新被定義過了,所以一定要include
函數名稱對應
Java JNI
Java Jni中必需在companion object的init{}中先載入函數庫,然後再宣告外部函數名稱。外部函數的修飾子在Kotlin是 external, 在Java是使用native,如下所示
Kotlin版本:
public external fun setValue(value:String):Uint
Java版本:
public native void setValue(String value);
C/C++ JNI
如果是 .cpp檔,必需先在函數前加 extern “C”. .c檔則不用加
然後加入 JNIEXPORT void JNICALL Java_包名_類別名_函數名(JNIEnv *env, jobject jobj, 參數1,參數2, …….)
請注意,包名必需使用 “_” 分隔,而不是 “.”。另外前二個參數一定是 *env, jobj, 第三個參數開始,才是對應到Java的參數。如下所示
JNIEXPORT void JNICALL Java_com.asuscomm_mahaljsp_jnitest_PokemonJni_setValue(
JNIEnv *.env, jobject jobj, 參數1, 參數2, ....){
}
接收JVM參數
Java 是位於 JVM 的內部,其資料被 JVM保 護著,所以外部的 C/C++ 完全無法窺看,更別說接收了。所以JNI開發了 JNIEnvi 這個特殊類別當作二者的溝通橋樑,操作方式分三個部份,底下以String為範例
1. env->GetStringUTFChars()來取得Java傳來的參數,接收者必需是 const char *
2. 將char*的值進行運算
3. env->ReleaseStringUTFChars()釋放記憶
char buffer[100];
JNIEXPORT void JNICALL Java_com_asuscomm_mahaljsp_jnitest_PokemonJni_setValue(
JNIEnv *env, jobject jobj, jstring j_value){
const char *c_value=env->GetStringUTFChars(j_value, NULL);
strcpy(buffer, c_value);
env->ReleaseStringUTFChars(j_value, c_value);
}
GetStringUTFChars(j_value, NULL) : 接收傳入的值。第1 個參數為傳進來的值,第2個參數指定是否為copy傳入,請設為0 or NULL
ReleaseStringUTFChars(j_value, c_value) : 釋放記憶体。因為C/C++沒有垃圾回收機制,必需手動釋放。所以如果沒有這行,最後會造成 out of memory錯誤,讓app直接閃退
參數送回JVM
將字串傳回JVM,使用 NewStringUTF()創造新的字串符傳回,如下
JNIEXPORT jstring JNICALL Java_com_asuscomm_mahaljsp_jnitest_PokemonJni_getValue(JNIEnv *env, jobject jobj){
strcat(buffer, ", Thomas");
return env->NewStringUTF(buffer);
}
NewStringUTF()直接穿入JVM,所以回收機制由Java控制,C/C++不用管理回收問題。
std:string
“hello”.c_str()將會轉換std:string成char,並傳回指標
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_asuscomm_mahaljsp_ctest_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
