6

假设我有以下 Java 代码:

public class Test {
  public static int foo() {
    throw new RuntimeException();
  }
}

它以通常的方式加载本机库。本机库注册并缓存 JVM 或其他任何东西,然后稍后执行此函数:

JNIEnv* sEnv; // initialised somewhere properly
void throwMeARiver() {
  jclass c = sEnv->FindClass("Test");
  jmethodID m = sEnv->GetStaticMethodID(c, "foo", "()I");
  jint i = sEnv->CallStaticIntMethod(c, m);
  printf("Got %d\n", (int)i);
}

显然 sEnv->CheckException() 现在将返回 JNI_TRUE,但是本机函数会打印出什么?在 Java 中,抛出异常会使 JVM 停止执行它所在的方法,直到找到合适的处理程序,所以 foo() 的返回值是未定义的。那么我也是未定义的吗?

我找不到任何规格或任何其他说明,所以大概我 /is/ 未定义。在这种情况下,与大多数 JNI 函数不同,CallStaticIntMethod 没有“正常”范围。

我现在正在尝试这个,但我主要是问这个,看看某处是否有强制行为。

4

2 回答 2

2

虽然变量 i 将被定义,但它的值是未确定的。在这种情况下,该值很可能为 0,但前提是 JVM 在其实现中初始化了该值。否则,它将等于内存中存在的任何数据。

由本机函数的实现者来正确检查CallXXXMethod()via env->CheckException()env->ExceptionOccurred()env->ExceptionDescribe(). 最后,调用env->ClearException()以删除异常。

于 2013-10-01T18:24:17.460 回答
-1

不,JNI CheckException() 不等同于 Java try ... catch,因此您的 newRuntimeException()将进一步传播并且可能根本不会被捕获。

感谢@EJP纠正我:实际上,来自 Java 的任何Throwable都会被 C/C++ 调用者拦截。根据我在 Android 上的测试,返回的值是发生在某个不可预测的内存位置(堆栈?)中的任何内容。

有关 JNI 和异常的更多讨论,请参阅如何捕获 JNI/Java 异常

于 2013-10-01T17:54:09.870 回答