在JNI jobject中存储一个c++对象实例,稍后检索

Store a c++ object instance inside JNI jobject and retrieve later

本文关键字:实例 对象 c++ 检索 一个 jobject JNI 存储      更新时间:2023-10-16

我有一个JNI类,方法是init()work()cleanup()。在c++方面,我在init()期间创建了一个c++类Foo的实例,然后在work()期间对其调用一些方法,最后在cleanup()中删除它。现在我将Foo的实例存储为c++上的全局单例,以便我可以从不同的JNI调用中检索它。我真正想做的是在传递给每个JNI调用的jobject实例中存储一个指向Foo实例的指针,这样我就可以避免拥有全局单例,也可以支持Foo的多个实例。这样的事情可能发生吗?

可以将指向c++对象的指针存储为Java类成员。例如,在Java中:

class Foo
{
    public long ptr = 0;
    public native void init();
    public native void work();
    public native void cleanup();
}

在c++中:

jfieldID getPtrFieldId(JNIEnv * env, jobject obj)
{
    static jfieldID ptrFieldId = 0;
    if (!ptrFieldId)
    {
        jclass c = env->GetObjectClass(obj);
        ptrFieldId = env->GetFieldID(c, "ptr", "J");
        env->DeleteLocalRef(c);
    }
    return ptrFieldId;
}
class Foo
{
    /* ... */
};
extern "C"
{
    void Java_Foo_init(JNIEnv * env, jobject obj)
    {
        env->SetLongField(obj, getPtrFieldId(env, obj), (jlong) new Foo);
    }
    void Java_Foo_work(JNIEnv * env, jobject obj)
    {
        Foo * foo = (Foo *) env->GetLongField(obj, getPtrFieldId(env, obj));
        foo->work();
    }
    void Java_Foo_cleanup(JNIEnv * env, jobject obj)
    {
        Foo * foo = (Foo *) env->GetLongField(obj, getPtrFieldId(env, obj));
        delete foo;
    }
}

当然。

在JNI中创建Foo实例。只需将指针(指向创建的实例)作为jlong类型返回即可。因此您可以稍后将其用作处理程序。下面是一个例子:

JNIEXPORT jlong JNICALL Java_com_example_init(JNIEnv *env, jobject thiz) {
   Foo* pFoo = new Foo();
   if (NULL == pFoo) {
       // error handling
   }
   pFoo->initialize();
   return reinterpret_cast<jlong>(pFoo);
}
JNIEXPORT void JNICALL Java_example_start(JNIEnv *env, jobject thiz,
jlong fooHandle) {
   Foo* pFoo = reinterpret_cast<Foo*>(fooHandle);
   pFoo->start();
}

您可以在java中使用long来完成此操作,但是我认为在预计在沙盒中操作的语言的实例变量中放置指向某些本机内存地址的指针并不是一个好主意。它很草率,可能是一个利用向量,这取决于你做什么。

我猜你正在遇到这个问题,因为你的本机代码非常接近你的JNI代码。如果您将JNI层构建为本机代码和Java之间的转换,您可能会发现使用它更容易。