java - 如何使 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
上面发布的),然后稍后使用这个缓存的值一切正常并按预期工作(即没有崩溃)。
解决方案
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
实际上,上述内容可以正常工作,因为first
和second
将是对Class<Short>
.
推荐阅读
- regex - 如何使用捕获组和交替组合 Notepad++ 的多个 RegEx 命令?
- javascript - 接受一个数字并返回另一个数字的函数,反之亦然
- ruby-on-rails - 使用 Selenium 和 Headless Chrome 进行 Rails 系统测试的 Gitlab CI 配置
- vb.net - Datagridivew 列标题日期格式反转
- javascript - 如何使用 Ancestry gem 在 Rails 中使用类别/子类别填充下拉列表(2 或更多深度级别)
- reactjs - 无法进行 API 调用 React Native
- java - 如何从 JAX-RS 中的 ClientResponseFilter 访问响应?
- coq - 在产品类型上定义递归函数
- python - 通过 for 循环从列表中删除不需要的字符
- typescript - 如何创建访问它正在创建的类类型的静态成员的通用工厂方法