ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
有两种方式可以检测JNI代码中是否有错误发生。 1. 大多数JNI函数使用一个不同的返回值(比如NULL)来标识有错误发生。这个错误返回值也暗示着在当前线程有一个异常。 以下代码展示了如何使用NULL对比返回值的方式检查GetFieldID是否发生错误。这个示例包括两部分:一个类Window定义了一些属性(handle, length以及width)以及一个Native方法用于缓存这些属性的ID。尽管这些属性在Window类中是存在的,我们仍然需要检查从GetFieldID函数返回的可能的错误,因为虚拟机可能不能为属性ID分配足够的内存空间。 ~~~ public class Window{ static { initIDs(); } long handle; int length; int width; static native void initIDs(); } ~~~ ~~~ /* * Class: Window * Method: initIDs * Signature: ()V */ jfieldID FID_Window_handle; jfieldID FID_Window_length; jfieldID FID_Window_width; JNIEXPORT void JNICALL Java_Window_initIDs (JNIEnv * env, jclass classWindow){ FID_Window_handle = (*env)->GetFieldID(env, classWindow, "handle", "J"); if(!FID_Window_handle){ return; /* error occured ! */ } FID_Window_length = (*env)->GetFieldID(env, classWindow, "length", "I"); if(!FID_Window_length){ return; /* error occured ! */ } FID_Window_width= (*env)->GetFieldID(env, classWindow, "width", "I"); if(!FID_Window_width){ return; /* error occured ! */ } /* no check necessary; we are about to return anyway */ } ~~~ 2. 当使用一个返回值不能标识其内部是否有错误发生的JNI函数时,Native代码必须依赖异常检查来检查是否有错误发生。检查当前函数是否有异常发生的JNI函数是ExceptionOccurred.(ExceptionCheck 在Java 2 SDK relaease 1.2)也被加进来了。例如,JNI函数CallIntMethod不能将错误场景都编码到返回值中,像-1或者NULL这样的通常的错误场景返回值此时并不能作为判断是否有错误产生的依据了,因为它们可能是被调用函数的合法返回值。想一下,有一个Fraction(小数)类,它的floor方法返回小数值的整数部分,另一个JNI函数调用了它。 ~~~ public class Fraction { // details such as constructors omitted int over, under; public int floor() { return Math.floor((double)over/under); } } ~~~ ~~~ /* Native code that calls Fraction.floor. Assume method ID MID_Fraction_floor has been initialized elsewhere. */ void f(JNIEnv *env, jobject fraction) { jint floor = (*env)->CallIntMethod(env,fraction, MID_Fraction_floor); /* important: check if an exception was raised */ if((*env)->ExceptionCheck(env)) { return; } /*...use floor */ } ~~~ 当JNI函数返回了一个明确的错误码,Native代码仍然可以使用像ExceptionCheck这样的函数检查是否有异常发生。不过显然,通过返回值检查异常往往会更高效。如果一个JNI函数返回了它的错误代码,在当前线程如果紧接着调用的ExceptionCheck,其返回值将保证返回JNI_TRUE.