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

所以我想做的是让每个测试对象使用setValue在jni中存储一个值并使用这个c++代码获取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 值,但这也不起作用。

4

1 回答 1

2

一种可能的解决方案可能是在本机代码中使用动态分配的结构。为此,您必须分配(例如,在构造函数中)一些保存该结构的内存。该结构的地址被传回 Java 部分并存储在 Java 对象中。然后,对于getValueand 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。

于 2013-10-06T14:22:05.730 回答