I have a JNI class with methods init()
work()
, and cleanup()
. On the C++ side I create an instance of a C++ class Foo
during init()
, then call some methods on it during work()
, and finally delete it inside cleanup()
. Right now I store instance of Foo
as a global singleton on the C++ so that I can retrieve it from the different JNI calls. What I would really like to do is store a pointer to the Foo
instance inside the jobject
instance that gets passed to each JNI call, so that I can avoid having a global singleton and also so that I can support multiple instances of Foo
. Is something like this possible?

- 6,040
- 8
- 41
- 80
-
2Possible http://stackoverflow.com/questions/337268/what-is-the-correct-way-to-store-a-native-pointer-inside-a-java-object(duplicate) – mkaes Jun 30 '14 at 14:12
3 Answers
You can store a pointer to your C++ object as a Java class member. For example, in Java:
class Foo
{
public long ptr = 0;
public native void init();
public native void work();
public native void cleanup();
}
And in 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;
}
}

- 18,506
- 3
- 48
- 56
-
Is this better than the `reinterpret_cast
` proposed in Da Ha Song's answer? And why? – JonasVautherin Mar 04 '20 at 21:05
Absolutely.
Create a Foo instance in JNI. Simply return the pointer (points to the instance created) as a jlong type. So you can use it as a handler later. Here is an example:
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();
}

- 398
- 5
- 11
You can do it with a long in java, however I would argue that its not a very good idea to put a pointer to some native memory address in an instance variable of a language that is expected to be operating in a sandbox. Its sloppy and it could be a exploit vector depending on what your doing.
I am guessing you are running into this problem because your native code is very close to your JNI code. If you structure your JNI layer as translation between your native code and Java, you may find it easier to work with.

- 4,316
- 4
- 28
- 47