在Java中有兩類數據類型:primitive types,如,int, float, char;另一種爲reference types,如,類,實例,數組。
注意:數組,不管是對象數組還是基本類型數組,都作爲reference types存在,有專門的JNI方法取數組中每個元素。
1、void
java的void與JNI的void是一致的。
2、基本數據類型
3、對象類型
相比基本類型,對象類型的傳遞要複雜得多。不能對Jstring進行直接操作。
//如下使用方式是錯誤的,因爲jstring不同於C語言中的char *類型。
Java_com_conowen_test_testActivity_test(JNIEnv *env, jobject obj, jstring str)
{
/* ERROR: incorrect use of jstring as a char* pointer */
printf("%s", str);
...
}
注意:
typedef jint jsize;
3.1、GetStringUTFChars與ReleaseStringUTFChars函數簡單說明(跳到3.2有更方便的函數)
JNI支持Unicode/UTF-8字符編碼互轉。Unicode以16-bits值編碼;UTF-8是一種以字節爲單位變長格式的字符編碼,並與7-bitsASCII碼兼容。UTF-8字串與C字串一樣,以NULL('\0')做結束符, 當UTF-8包含非ASCII碼字符時,以'\0'做結束符的規則不變。7-bit ASCII字符的取值範圍在1-127之間,這些字符的值域與UTF-8中相同。當最高位被設置時,表示多字節編碼。
//調用GetStringUTFChars,把一個Unicode字串轉成UTF-8格式字串
Java_com_conowen_test_testActivity_test(JNIEnv *env, jobject obj, jstring str)
{
char buf[128];
const jbyte *cbyte;
cbyte= (*env)->GetStringUTFChars(env, str, NULL);
if (cbyte== NULL) {
return NULL;
}
printf("%s", cbyte);
(*env)->ReleaseStringUTFChars(env, str, cbyte);
scanf("%127s", buf);
return (*env)->NewStringUTF(env, buf);
//或者return (*env)->NewStringUTF(env, "hello world");
}
上述函數中,有isCopy參數,當該值爲JNI_TRUE,將返回str的一個拷貝;爲JNI_FALSE將直接指向str的內容。 注意:當isCopy爲JNI_FALSE,不要修改返回值,不然將改變java.lang.String的不可變語義。一般會把isCopy設爲NULL,不關心Java VM對返回的指針是否直接指向java.lang.String的內容。
注意:在調用GetStringChars之後,一定要調用ReleaseStringChars做釋放,(Unicode -> UTF-8轉換的原因)。不管在調用GetStringChars時爲isCopy賦值JNI_TRUE還是JNI_FALSE,因不同JavaVM實現的原因,ReleaseStringChars可能釋放內存,也可能釋放一個內存佔用標記。
3.2、GetStringRegion/GetStringUTFRegion函數簡單說明
因爲這兩個函數不涉及內存操作,所以較GetStringUTFChars使用要簡單。也不用進行釋放指針之類的操作,非常方便。(推薦使用)
Java_com_conowen_test_testActivity_test(JNIEnv *env, jobject obj, jstring str)
{
char outputbuf[128], inputbuf[128];
int len = (*env)->GetStringLength(env, str);
(*env)->GetStringUTFRegion(env, str, 0, len, outbuf);
printf("%s", outputbuf);
scanf("%s", inputbuf);
return (*env)->NewStringUTF(env, inbuf);
}
GetStringUTFRegion有兩個主要的參數,start 和 length, 這兩個參數以Unicode編碼計算. 該函數會做邊界檢查,所以可能拋出StringIndexOutOfBoundsException。
3.3、GetStringLength/GetStringUTFLength函數簡單說明
前者是Unicode編碼長度,後者返回的是是UTF編碼長度。
4、數組類型
JNI對每種數據類型的數組都有對應的函數。
4.1、常見錯誤操作:
/* 直接操作數組是錯誤的 */
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{
int i, sum = 0;
for (i = 0; i < 10; i++) {
sum += arr[i];
}
}
4.2、使用
void Get<Type>ArrayRegion(JNIEnv *env,<ArrayType> array, jsize start,jsize len, <NativeType> *buf);
進行操作
參數說明:
env: the JNIEnv interface pointer.
array: a reference to an array whose elements are to be copied.將要被拷貝的目標數組<ArrayType>
start: the starting index of the array elements to be copied.(數組的起始位置)
len: the number of elements to be copied.(拷貝元素的個數)buf:the destination buffer.存放結果的本地數組<NativeType>
返回值:void
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{
jint buf[10];
jint i, sum = 0;
(*env)->GetIntArrayRegion(env, arr, 0, 10, buf);
for (i = 0; i < 10; i++) {
sum += buf[i];
}
return sum;
}
JNI中數組的基類爲jarray,其他如jintArray都是繼承自jarray。
4.3、使用<NativeType> *Get<Type>ArrayElements(JNIEnv *env,<ArrayType> array, jboolean *isCopy);進行數組操作
參數說明:
env: the JNIEnv interface pointer.array: a reference to the primitive array whose elements are tobe accessed.(目標數組)
isCopy: a pointer to a jboolean indicating whether a function
返回值:返回指向Java數組的一個直接的指針
使用實例:
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{
jint *carr;
jint i, sum = 0;
carr = (*env)->GetIntArrayElements(env, arr, NULL);
if (carr == NULL) {
return 0; /* exception occurred */
}
for (i=0; i<10; i++) {
sum += carr[i];
}
(*env)->ReleaseIntArrayElements(env, arr, carr, 0);
return sum;
}
)
更多數組操作函數:
5、另外一些有用的宏定義(來自jni.h)
#define JNI_FALSE 0
#define JNI_TRUE 1
#define JNI_VERSION_1_1 0x00010001
#define JNI_VERSION_1_2 0x00010002
#define JNI_VERSION_1_4 0x00010004
#define JNI_VERSION_1_6 0x00010006
#define JNI_OK (0) /* no error */
#define JNI_ERR (-1) /* generic error */
#define JNI_EDETACHED (-2) /* thread detached from the VM */
#define JNI_EVERSION (-3) /* JNI version error */
#define JNI_COMMIT 1 /* copy content, do not free buffer */
#define JNI_ABORT 2 /* free buffer w/o copying back */