版权声明:本文为博主原创文章,未经博主允许不得转载。
本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。
一、JNI 访问数组
1.访问基本类型数组
C:
JNIEXPORT jbyteArray JNICALL Java_com_xiaoyue_JNIString_testArray
(JNIEnv *env, jobject jobj, jintArray intArray) {
int compare(jint * a, jint *b);
//jintArray -> jint *
jint *elemts = (*env)->GetIntArrayElements(env, intArray, NULL);
if (elemts == NULL)
{
return;
}
//数组长度
int len = (*env)->GetArrayLength(env, intArray);
qsort(elemts, len, sizeof(jint), compare);
//释放可能的内存
//将JNI 修改的数据重新写回原来的内存
(*env)->ReleaseIntArrayElements(env, intArray, elemts, JNI_COMMIT);
}
int compare(jint * a, jint *b) {
return *a - *b;
}
这是传入一个 int 数组,进行快速排序,并返回。
jint *elemts = (*env)->GetIntArrayElements(env, intArray, NULL);
GetIntArrayElements 是对 jintArray 进行数组转换,转换为 C 语言中的 int 数组。获取其他类型数据数组方法类似。
int len = (*env)->GetArrayLength(env, intArray);
GetArrayLength 获取数组长度。
(*env)->ReleaseIntArrayElements(env, intArray, elemts, JNI_COMMIT);
ReleaseIntArrayElements 会释放缓存区(如果有的话),同时将 JNI 修改的数据重新写回原来的内存。
这边的快速排序采用的是 C 自带的 qsort 函数进行快速排序。
2.访问引用数据类型的数组
C:
JNIEXPORT jobjectArray JNICALL Java_com_xiaoyue_JNIString_testArray
(JNIEnv *env, jobject jobj, jobjectArray result) {
int i;
int size = (*env)->GetArrayLength(env, result);
jclass jclz = (*env)->FindClass(env, "java/lang/String");
if (jclz == NULL) {
return NULL;
}
// 赋值
for (i = 0; i < size; i++) {
//C 字符串
char * c_str = (char *)malloc(256);
memset(c_str, 0, 256);
//将 int 转换成为 char
sprintf(c_str, "C: %d\n", i);
//C ->jstring
jstring str = (*env)->NewStringUTF(env, c_str);
if (str == NULL) {
return NULL;
}
//将jstring 赋值给数组
(*env)->SetObjectArrayElement(env, result, i, str);
free(c_str);
c_str = NULL;
}
//返回jobjectArray
return result;
}
这是对传进来的字符串数组进行修改。
(*env)->SetObjectArrayElement(env, result, i, str);
SetObjectArrayElement 对数组具体摸个位置的值进行修改。
二、异常
java:
public class JNIMain {
public native void exception();
static{
System.loadLibrary("FirstApplication");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
JNIMain jniMain = new JNIMain();
jniMain.exception();
System.out.println("jni exception");
}
}
C:
JNIEXPORT void JNICALL Java_com_xiaoyue_JNIMain_exception
(JNIEnv *env, jobject jobj) {
jclass cls = (*env)->GetObjectClass(env, jobj);
jfieldID fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");
printf("exception\n");
}
结果:
在 C 中获取属性 key,由于没有这个属性,报错。但是报错后, C 后面的代码可以继续执行,而 java 后面的代码不能继续。即使手动给 java 加上 try、catch 也是无法捕捉到异常。
这时候需要 C 语言创建一个异常并抛出来,同时在 java 层进行 try、catch 处理。
java:
public class JNIMain {
public native void exception();
static{
System.loadLibrary("FirstApplication");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
JNIMain jniMain = new JNIMain();
try {
jniMain.exception();
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.toString());
}
System.out.println("jni exception");
}
}
C :
JNIEXPORT void JNICALL Java_com_xiaoyue_JNIMain_exception
(JNIEnv *env, jobject jobj) {
jclass cls = (*env)->GetObjectClass(env, jobj);
jfieldID fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");
//检查是否发生异常
jthrowable ex = (*env)->ExceptionOccurred(env);
// 判断异常是否发生
if (ex != NULL) {
jclass newExc;
//清空 JNI 产生的异生
(*env)->ExceptionClear(env);
//IllegalArgumentException
newExc = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
if (newExc == NULL)
{
printf("exception\n");
return;
}
(*env)->ThrowNew(env, newExc, "Throw exception from JNI: GetFieldID faild ");
}
}
结果:
这样,java 代码可以继续往下执行。可以在 C 语言中对异常处理进行封装成一个工具类进行使用。