Я пытаюсь выучить 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());
}
}
Итак, я пытаюсь сделать так, чтобы каждый объект Test сохранял значение в jni с помощью setValue и получал getValue, используя этот код c ++.
#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;
}
Однако проблема в том, что когда я использую setValue для test2, а затем печатаю значение test1, оно меняется на то, что я установил для test2. Как это исправить. Я попытался сопоставить каждый рабочий объект со значением int, но это тоже не сработало.
Возможным решением может быть использование динамически распределенной структуры в собственном коде. Чтобы это работало, вы должны выделить (например, в конструкторе) некоторую память, которая содержит структуру. Адрес этой структуры передается обратно в часть 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());
}
}
Я переименовал родные методы, чтобы представить address
параметр без изменения API.
Других решений пока нет …