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

时间:2014-06-30 14:04:40

标签: java c++ java-native-interface

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

3 个答案:

答案 0 :(得分:1)

您可以将指向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;
    }
}

答案 1 :(得分:0)

绝对。

在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();
}

答案 2 :(得分:-1)

你可以在java中使用很长的时间来完成它,但我认为将指针放在一个预期在沙箱中运行的语言的实例变量中的某个本地内存地址并不是一个好主意。它的草率,它可能是一个利用向量,取决于你做什么。

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