異常:程式在執行期間沒有按照正常的程式邏輯執行,在執行過程當中出現了某種錯誤,導致程式崩潰。
作用: 1、保證Java程式碼可以執行
2、補救措施保證C程式碼繼續執行
由於JNI自己丟擲的異常,在Java層無法被捕捉,只能在C層清空。而使用者通過ThrowNew丟擲的異常,可以在Java層捕捉。
public class MyException {
public native void exeception();
private String name = "xiaoming";
public static void main(String[] args) {
MyException m = new MyException();
try {
m.exeception();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("nihao");
}
//載入動態庫
static {
System.loadLibrary("ConsoleApplication1");
}
}
複製程式碼
native方法實現
JNIEXPORT void JNICALL Java_com_lwj_test_MyException_exeception
(JNIEnv *env, jobject jobj){
jclass cls = (*env)->GetObjectClass(env, jobj);
jfieldID fid = (*env)->GetFieldID(env, cls, "myname", "Ljava/lang/String;");
//檢測是否發生Java異常
jthrowable exception = (*env)->ExceptionOccurred(env);
if (exception != NULL){
//讓Java程式碼可以繼續執行
//清空異常資訊
(*env)->ExceptionClear(env);
//補救措施
fid = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
}
//獲取屬性的值
jstring jstr = (*env)->GetObjectField(env, jobj, fid);
char *str = (*env)->GetStringUTFChars(env, jstr, NULL);
//對比屬性值是否合法
if (_stricmp(str, "xiaoming2") != 0){
//認為丟擲異常,給Java層處理
jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
(*env)->ThrowNew(env, newExcCls, "key's value is invalid!");
}
}
複製程式碼
關於更加詳細的異常處理,大家可以參考這篇文章:《JNI/NDK開發指南(十一)——JNI異常處理》
快取策略
區域性變數使用static jfieldID key_id
Java類:
public class MyException {
public native void cached();
private String name = "xiaoming";
public static void main(String[] args) {
MyException m = new MyException();
for(int i = 0;i< 10;i++) {
m.cached();
}
}
//載入動態庫
static {
System.loadLibrary("ConsoleApplication1");
}
}
複製程式碼
native實現
JNIEXPORT void JNICALL Java_com_lwj_test_MyException_cached
(JNIEnv *env, jobject jobj){
jclass cls = (*env)->GetObjectClass(env, jobj);
//獲取jfieldID只獲取一次
//區域性靜態變數
static jfieldID key_id = NULL;
if (key_id == NULL){
key_id = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
printf("--------GetFieldID-------\n");
}
}
複製程式碼
從結果中看出只獲取一次。
2、全域性變數
//初始化全域性變數,動態庫載入完成之後,立刻快取起來
jfieldID key_fid;
jmethodID random_mid;
JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_initIds(JNIEnv *env, jclass jcls){
key_fid = (*env)->GetFieldID(env, jcls, "key", "Ljava/lang/String;");
random_mid = (*env)->GetMethodID(env, jcls, "genRandomInt", "(I)I");
}
複製程式碼