在開發(fā)過程中鲁纠,java調(diào)用jni的native方法時(shí)除了使用基本數(shù)據(jù)類型作為參數(shù)傳遞妖枚,還會(huì)使用數(shù)組和引用類型參數(shù)魄衅。本節(jié)就會(huì)講解jni層與java層傳遞數(shù)組類型和引用類型參數(shù)峭竣。
本節(jié)后續(xù)代碼都是使用之前章節(jié)使用的代碼工程,java代碼編譯的.h文件和生成.dll動(dòng)態(tài)庫也不在此闡述了徐绑,具體代碼和流程請(qǐng)見JNI編程一http://www.reibang.com/p/486331fe30ec
JNI處理java傳遞過來的數(shù)組類型
舉個(gè)例子邪驮,假如在java代碼中有一個(gè)int型的數(shù)組,我們要在jni層里對(duì)這個(gè)數(shù)組按照從小到大的順序排序傲茄。
JniMain.java中的代碼
public class JniMain {
//----------------------jni訪問數(shù)組-----------------------
public native void giveArray(int[] arr);
//---------------------------------------------
static{
System.loadLibrary("JNI_Demo1");
}
public static void main(String[] args) {
JniMain jm = new JniMain();
//給jni傳遞數(shù)組
int[] arr = {3,40,6,17,5};
jm.giveArray(arr);
for(int i=0;i<5;i++) {
System.out.println(arr[i]);
}
}
上面代碼定義了一個(gè)整形數(shù)組毅访,然后調(diào)用jni層的native方法進(jìn)行排序沮榜,然后打印輸出。
jni_impl.c中的代碼
#include "stdafx.h"
#include "JniMain.h"
#include <string.h>
#include <Windows.h>
#include <stdlib.h>
//聲明函數(shù)
int compare(int * a, int * b);
//訪問基本數(shù)據(jù)類型
JNIEXPORT void JNICALL Java_JniMain_giveArray
(JNIEnv * env, jobject jobj, jintArray arr){
boolean iscp;
//jintArray -> jint *
jint * elements = (*env)->GetIntArrayElements(env,arr,&iscp);
if (elements == NULL)
{
return;
}
//數(shù)組長(zhǎng)度
int len = (*env)->GetArrayLength(env,arr)
qsort(elements, len, sizeof(jint), compare);
if (iscp == JNI_TRUE){
//釋放內(nèi)存喻粹,并將JNI修改的數(shù)據(jù)重新寫回到原來的內(nèi)存
(*env)->ReleaseIntArrayElements(env, arr, elements, JNI_COMMIT);
}
}
int compare(int * a,int * b){
return *a - *b;
}
上面的代碼是將java層的整形數(shù)組在JNI對(duì)應(yīng)的jintArray類型arr轉(zhuǎn)換成的指向jint類型的指針數(shù)組蟆融,然后對(duì)這個(gè)指針數(shù)組elements使用快速排序方法進(jìn)行重小到大排序,再把elements重新賦值給arr守呜。
打印結(jié)果如下
JNI層與java層引用類型的傳遞
代碼示例有以下內(nèi)容
1.jni層向java層傳遞一個(gè)String類型的數(shù)組型酥。
2.jni層創(chuàng)建一個(gè)局部引用,是用完之后立即刪除查乒。
3.jni層創(chuàng)建一個(gè)全局引用弥喉,是用完之后立即刪除。
4.jni層創(chuàng)建一個(gè)弱全局引用玛迄,在gc時(shí)就會(huì)自動(dòng)回收由境。
Jni_Main.java
public class JniMain {
static{
System.loadLibrary("JNI_Demo1");
}
//---------------------訪問引用類型-------------------
public native String[] initStringArray(int size);
//局部引用
public native void localRef();
public native void createGlobalRef();
public native String getGlobalRef();
public native void delGlobalRef();
public native String createWeakRef();
//------------------------------------------------
public static void main(String[] args) {
//調(diào)用非靜態(tài)native方法
JniMain jm = new JniMain();
jm.localRef();
jm.createGlobalRef();
System.out.println(jm.getGlobalRef());
jm.delGlobalRef();
}
}
jni_impl.c
#include "stdafx.h"
#include "JniMain.h"
#include <string.h>
#include <Windows.h>
#include <stdlib.h>
/*
* Class: JniMain
* Method: initStringArray
* Signature: (I)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL Java_JniMain_initStringArray
(JNIEnv * env, jobject jobj, jint size){
//創(chuàng)建jobjectArray
jobjectArray result;
jclass jclz = (*env)->FindClass(env, "java/lang/String");
if (jclz == NULL)
{
return NULL;
}
result = (*env)->NewObjectArray(env,size,jclz,jobj);
if (result==NULL)
{
return NULL;
}
for (int i = 0; i < size;i++){
//c 字符串
char * c_str = (char *)malloc(sizeof(char)* 256);
memset(c_str, 0, sizeof(char)* 256);
//將int 轉(zhuǎn)換成為char
sprintf(c_str, "hello num:%d\n", i);
//char數(shù)組 -> jstring
jstring str = (*env)->NewStringUTF(env, c_str);
if (str == NULL)
{
return NULL;
}
//將jstring賦值給數(shù)組
(*env)->SetObjectArrayElement(env,result,i,str);
free(c_str);
c_str = NULL;
(*env)->DeleteGlobalRef(env, str);
}
return result;
}
//JNI 引用
//局部引用
JNIEXPORT void JNICALL Java_JniMain_localRef
(JNIEnv *env, jobject jobj){
int i = 0;
for ( i = 0; i < 5; i++)
{
jclass cls = (*env)->FindClass(env, "java/util/Date");
jmethodID mid = (*env)->GetMethodID(env, cls, "<init>", "()V");
//創(chuàng)建一個(gè)局部Date類型的引用
jobject obj = (*env)->NewObject(env,cls,mid);
//使用這個(gè)引用
//釋放引用
(*env)->DeleteLocalRef(env,cls);
(*env)->DeleteLocalRef(env, obj);
}
}
//全局引用
//NewGlobalRef 是創(chuàng)建全局引用的唯一方法
jstring global_str;
JNIEXPORT void JNICALL Java_JniMain_createGlobalRef
(JNIEnv * env, jobject jobj){
jobject obj = (*env)->NewStringUTF(env, "JNI is interstring");
global_str = (*env)->NewGlobalRef(env,obj);
}
JNIEXPORT jstring JNICALL Java_JniMain_getGlobalRef
(JNIEnv * env, jobject jobj){
return global_str;
}
JNIEXPORT void JNICALL Java_JniMain_delGlobalRef
(JNIEnv * env, jobject jobj){
(*env)->DeleteGlobalRef(env, global_str);
}
//弱全局引用
//它不會(huì)阻止gc
jclass g_weak_cls;
JNIEXPORT jstring JNICALL Java_JniMain_createWeakRef
(JNIEnv *env, jobject jobj){
jclass cls_string = (*env)->FindClass(env,"java/lang/String");
g_weak_cls = (*env)->NewWeakGlobalRef(env, cls_string);
return g_weak_cls;
}
JNI中的異常處理
Jni_Main.java
public class JniMain {
static{
System.loadLibrary("JNI_Demo1");
}
public native void exception();
public static void main(String[] args) {
JniMain jm = new JniMain();
//異常處理
try {
jm.exception();
}catch(Exception e) {
System.out.println(e.toString());
}
}
}
jni_impl.c
#include "stdafx.h"
#include "JniMain.h"
#include <string.h>
#include <Windows.h>
#include <stdlib.h>
//JNI異常處理
JNIEXPORT void JNICALL Java_JniMain_exception
(JNIEnv * env, jobject jobj){
jclass cls = (*env)->GetObjectClass(env, jobj);
jfieldID cls = (*env)->GetFieldID(env, cls, "mykey", "Ljava/lang/String;");
//檢查是否發(fā)送異常
jthrowable ex = (*env)->ExceptionOccurred(env);
if (ex != NULL)
{
//清空之前產(chǎn)生的異常
(*env)->ExceptionClear(env);
jclass newExc;
newExc = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
if (newExc == NULL)
{
printf("exception\n");
return;
}
(*env)->ThrowNew(env, newExc, "Throw exception from JNI: GetFieldID faild");
}
}