在JNI中,是否有比jlong​​更便携的方法来封装指针?

时间:2013-12-28 05:04:59

标签: java java-native-interface

我见过使用long / jlong来允许Java对象保留C ++指针的示例:

class Foo {
    private native long create();
}

struct Foo { };

JNIEXPORT jlong JNICALL Java_Foo_create
  (JNIEnv *, jobject)
{
    return (jlong) (new Foo);
}

这让我觉得有点紧张,因为它假设一个指针适合64位;这在OS / 400上是不真实的。

是否有更安全的解决方案,例如封装C ++指针的Java标准库类?

4 个答案:

答案 0 :(得分:5)

您可以使用哈希表来存储指针并将此哈希表的键返回给用户。像:

 std::unordered_map<long, Foo*> handles;
 long newHandle = 0
 ...
  JNIEXPORT jlong JNICALL Java_Foo_create
  (JNIEnv *, jobject)
   {
       Foo* ptr = new Foo;
       long handle = newHandle;
       handles.insert(std::pair<long, Foo*>(newHandle++, ptr));
       return handle;
   }

现在您可以使用句柄从hashmap获取指针:

JNIEXPORT void JNICALL Java_Foo_use
  (JNIEnv *, jobject, jlong handle) {
   auto iter = handles.find(handle);
   if (iter != handles.end()) {
       Foo* ptr = iter->second;
       // use Foo* here
   }
}

此方法还可以帮助您检查对象是否已被删除或删除仍然存在的所有Foo对象。 缺点是访问hashmap以获取指针会降低性能。此外,您可能应该使用多线程访问的句柄映射或使用线程安全的映射实现来保护。

或者,如果您需要为Java实现包装器,我建议考虑SWIG(Simplified Wrapper和Interface Generator)。

答案 1 :(得分:1)

为简洁而跳过错误检查:

JNIEXPORT jobject JNICALL Java_Foo_create(JNIEnv * env, jobject) {
  Foo* ptr = new Foo;
  return env->NewDirectByteBuffer(&ptr, sizeof(ptr));
}

/* private */ const Foo* from_jobject(JNIEnv * env, jobject java_foo) {
  return (reinterpret_cast<Foo**>(env->GetDirectBufferAddress(java_foo)))[0];
}

另见http://rkennke.wordpress.com/2007/07/30/efficient-jni-programming-iv-wrapping-native-data-objects/

答案 2 :(得分:0)

虽然jobject被定义为指针,但它有气味,因为它不是有效的JVM对象。 (如果你小心不把它当作JVM对象,我不知道是否会引起任何问题。)

您可以尝试jobject返回的NewDirectByteBuffer。它捕获指针并创建有效的JVM对象。

JNIEXPORT jobject JNICALL Java_Foo_create
  (JNIEnv *env, jobject)
{
    Foo *pFoo = new Foo();
    return env->NewDirectByteBuffer(pFoo, sizeof(Foo)); 
}

另外,请务必考虑终身管理以及IvanMushketyk的answer中提出的其他问题。并且,请查看JNA(通过JNAerator)和SWIG作为编写自己的JNI代码的替代方法。它们的输出可能不是可移植的,但它们的构建过程可能是。

答案 3 :(得分:0)

并不是真正的解决方案,但是编译时检查可以提供帮助:

export default connect(mapStateToProps, mapDispatchToProps)(TchExportButton)