首页 > 解决方案 > 如何使 JNI FindClass 返回的地址始终返回相同的地址

问题描述

在我的 C 程序中,我有以下代码:

jclass class;
jmethodID method;


class = (*env)->FindClass(env, "java/lang/Short");
method = (*env)->GetMethodID(env, class, "<init>", "(S)V");
printf("First: class=%p * method=%p\n", class, method);


class = (*env)->FindClass(env, "java/lang/Short");
method = (*env)->GetMethodID(env, class, "<init>", "(S)V");
printf("Second: class=%p * method=%p\n", class, method);

当我编译程序(在 GCC 中)并运行它时,它会给出以下输出:

First: class=0x7f55ac089450 * method=0x7f55ac0d99b8

Second: class=0x7f55ac089458 * method=0x7f55ac0d99b8

可以看到,每次FindClass调用类的地址都不一样。我认为类的地址是静态的,并且在我们程序的生命周期内不会改变。事实上,当人们从 IBM 阅读这篇关于如何使用 JNI( https://developer.ibm.com/languages/java/articles/j-jni/#notc )优化 C 代码的著名文章时,他们说要缓存值返回FindClass(所以人们会期望它不会改变)。但是,如果您稍后在 JNI 函数调用中使用此缓存值,它将使您的 C 程序崩溃(因为它使用了错误的 Java 类地址)。

另一个奇怪的事情是,当缓存FindClass类返回的值时java/lang/Integer(而不是java/lang/Short上面发布的),然后稍后使用这个缓存的值一切正常并按预期工作(即没有崩溃)。

标签: javacjava-native-interface

解决方案


FindClass返回的是Java对象的本地引用。Class

在您的示例中,您获得了两个单独的引用 - 但它们都可能引用同一个对象。

考虑一下如果行为符合您的预期并且您对两个FindClass调用都获得了相同的引用会发生什么:

first = (*env)->FindClass(env, "java/lang/Short");
second = (*env)->FindClass(env, "java/lang/Short");
(*env)->DeleteLocalRef(env, first);
method = (*env)->GetMethodID(env, second, "<init>", "(S)V");  // OOPS! this reference may no longer be valid

实际上,上述内容可以正常工作,因为firstsecond将是对Class<Short>.


推荐阅读