Использование нестатических объектов в jni в java

0

Я пытаюсь изучить 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());
    }
}

Так что я пытаюсь сделать, чтобы каждый тестовый объект сохранял значение в 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, у него есть измененияd к тому, к чему я установил test2. Как это исправить. Я попробовал сопоставление каждого задания с значением int, но это тоже не сработало.

Теги:
jni
native-code

1 ответ

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

Я переименовал собственные методы, чтобы ввести параметр address без изменения API.

  • 0
    я не уверен, что понимаю, что вы имеете в виду
  • 0
    @Popgalop Я добавил модификации вашего кода в мой ответ для уточнения. Надеюсь, это поможет.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню