4

我有 JNI 级别的代码。它可以抛出异常。代码是:

#include "JavaGlueClass.h"
#include <stdio.h>         
#include <windows.h>
#include <string.h>

jint throwNoClassDefError(JNIEnv *env, const char *message)
{
    jclass exClass;
    char *className = (char *) "java/lang/NoClassDefFoundError" ;

    exClass = env->FindClass(className);

    if ( exClass != NULL ) {
        return env->ThrowNew(exClass, message);
    }

    //free the local ref 
    env->DeleteLocalRef(exClass);

}

void throwGetFieldIDException(JNIEnv *env)
{
    const char *className = "GetFieldIDException";
    jclass exClass = env->FindClass(className);
    if (exClass == NULL) {
        throwNoClassDefError(env, className);
    } else {
        env->ThrowNew(exClass, "GetFieldIDException message");
    }
    env->DeleteLocalRef(exClass);
    printf("printprint");
}




JNIEXPORT jobject JNICALL Java_JavaGlueClass_test(JNIEnv *env, jobject obj) 
{
    jmethodID constructor;
    jobject object;
    jclass clazz;
    jfieldID fid;
    jstring stringField;

    clazz = env->FindClass("Information"); 
    if (clazz == 0) {
        printf("error while finding class");
        throwNoClassDefError(env, "no such class");
    } else {                
        //create object throuht constructor
        constructor = env->GetMethodID(clazz, "<init>", "()V");  
        object = env->NewObject(clazz, constructor);    

        // set private value1 field 
        stringField = env->NewStringUTF("str1");
        //fid = env->GetFieldID(clazz,"value1","Ljava/lang/String;");
        fid = NULL;
        if (fid == NULL) {
            throwGetFieldIDException(env, "error with value1 field.");
            //return NULL;
        }

        env->SetObjectField(object, fid, stringField);

        //set private value2 field
        fid = env->GetFieldID(clazz,"value2","I");
        if (fid == NULL) {
            throwGetFieldIDException(env, "error with value1 field.");
            //return NULL;
        }
        env->SetIntField(object, fid, 1); 

        // set private value3 field 
        stringField = env->NewStringUTF("str2");
        fid = env->GetFieldID(clazz,"value3","Ljava/lang/String;");
        if (fid == NULL) {
            throwGetFieldIDException(env, "error with value1 field.");
            //return NULL;
        }
        env->SetObjectField(object, fid, stringField);

        //set private value4 field
        fid = env->GetFieldID(clazz,"value4","I");
        if (fid == NULL) {
            throwGetFieldIDException(env, "error with value1 field.");
            //return NULL;
        }
        env->SetIntField(object, fid, 2); 

        printf("end of cpp function");              
        return object;
    }

}

Java_JavaGlueClass_test 函数创建自定义信息类的对象。每次我设置类字段时,都会检查“fid”是否为空。我阅读了有关 JNI 异常的信息,这些异常是待处理的异常。我发现将抛出的第一个异常将代码流移动到 Java 级别(而不是 JNI 级别)。但是 JNI 级别的异常之后的其余代码呢?据我了解,它将被执行。是否有可能在第一个异常之后引发第二个、第三个等异常?为了不执行 JNI 级别的其余代码,我是否应该在抛出异常后返回 NULL 或其他内容?

4

1 回答 1

6

JNI 规范

通过 JNI 引发的未决异常(例如,通过调用 ThrowNew)不会立即中断本机方法的执行。这与 Java 编程语言中异常的行为方式不同。当 Java 编程语言中抛出异常时,虚拟机会自动将控制流转移到最近的与异常类型匹配的封闭 try/catch 语句。然后虚拟机清除挂起的异常并执行异常处理程序。相反,JNI 程序员必须在异常发生后显式地实现控制流。

于 2012-12-12T17:51:31.007 回答