我正在尝试学习jni,我想知道如何使它成为一个java对象在jni c ++层中可以有一些与之关联的值。目前我有这个java代码。
public class Test
{
static
{
Runtime.getRuntime().loadLibrary("JNITests");
}
public native void setValue(int value);
public native int getValue();
public static void main(String[] args)
{
Test test1 = new Test();
test1.setValue(34);
Test test2 = new Test();
test2.setValue(23);
System.out.println(test1.getValue());
}
}
所以我想要做的是使用这个c ++代码,让每个Test对象使用setValue在jni中存储一个值并获取getValue。
#include <jni.h>
#include "Test.h"
int value;
JNIEXPORT void JNICALL Java_Test_setValue(JNIEnv *, jobject, jint newValue)
{
value = newValue;
}
JNIEXPORT jint JNICALL Java_Test_getValue(JNIEnv *, jobject)
{
return value;
}
然而,问题是当我在test2上使用setValue然后我打印test1的值时它已经改变为我将test2设置为。我该如何解决。我尝试将每个jobject映射到一个int值,但这也不起作用。
答案 0 :(得分:2)
可能的解决方案可能是在本机代码中使用动态分配的结构。要使其工作,您必须分配(例如,在构造函数中)一些保存结构的内存。该结构的地址被传递回Java部分并存储在Java对象中。然后,对于getValue
和setValue
,添加一个参数来保存已分配结构的内存地址,然后可以使用该参数存储该值。在销毁对象时,必须手动释放内存。
使用您的代码,原生部分可能如下所示:
#include <cstdlib>
#include <jni.h>
#include "Test.h"
struct data {
int value;
};
JNIEXPORT void JNICALL Java_Test_setValue0(JNIEnv *, jobject, jlong address, jint newValue)
{
struct data *ptr = (struct data *)address;
ptr->value = newValue;
}
JNIEXPORT jint JNICALL Java_Test_getValue0(JNIEnv *, jobject, jlong address)
{
struct data *ptr = (struct data *)address;
return ptr->value;
}
JNIEXPORT jlong JNICALL Java_Test_construct0(JNIEnv *, jobject) {
struct data *ptr = (struct data *)malloc(sizeof(*ptr));
return (jlong)ptr;
}
JNIEXPORT void JNICALL Java_Test_destruct0(JNIEnv *, jobject, jlong address) {
struct data *ptr = (struct data *)address;
free(ptr);
}
然后Java部分看起来像:
public class Test
{
static
{
Runtime.getRuntime().loadLibrary("JNITests");
}
private long address;
private native long construct0();
private native void destruct0(long address);
private native void setValue0(long address, int value);
private native int getValue0(long address);
public Test() {
this.address = this.construct0();
}
@Override
public void finalize() {
this.destruct0(this.address);
super.finalize();
}
public void setValue(int value) {
this.setValue0(this.address, value);
}
public int getValue() {
return this.getValue0(this.address);
}
public static void main(String[] args)
{
Test test1 = new Test();
test1.setValue(34);
Test test2 = new Test();
test2.setValue(23);
System.out.println(test1.getValue());
}
}
我重命名了本机方法,以便在不更改API的情况下引入address
参数。