将自定义 Java 数据模型传递到我的本机代码

Passing Custom Java Data Models to my Native Code

我想我知道该怎么做,我只是想看看 SO 社区,看看我是否走在正确的轨道上,因为我没有从我的研究中看到关于这个特定主题的任何信息。

我有一些自定义 Java(数据模型)classes,我想在我的应用程序的本机 C++ 端访问它们。我意识到这两个环境是相当独立的,所以我很可能必须在 c++ 中创建一个 "copy" 我的数据模型,并在我的 nativeLib JNI 文件中初始化它们?

我假设我不能 "convert" java class 到 c++ class,因为编译器可能无法做到这样的转换。我将不得不通过 JNI 方法调用手动管理我需要的每个字段。

这是正确的,还是有我不知道的更好的方法?

我想一个例子可能是这样的:

Foo.java

public class Foo {
    boolean A;
    boolean B;
    boolean C;
}

原生-lib.cpp

extern "C" {

    std::unique_ptr<Foo> foo;

    JNIEXPORT void JNICALL
    Java_com_example_user_project_native_1Foo(JNIEnv *env, jobject instance, jbool jbooleanA, jbool jbooleanB, jbool jbooleanC) {

    Foo->setA(jbooleanA);
    Foo->setB(jbooleanB);
    Foo->setC(jbooleanC);
}

Foo.h

class Foo {
private:
    bool A;
    bool B;
    bool C;

public:
    // add setters & getters here, or any other needed functions
}

I'm assuming I can't just "convert" the java class to the c++ class, since the compiler probably won't be able to do such a conversion.

你的假设是对的。如果您寻求在本机和 Java 之间自动代理 classes,请查看 SWIG。它能够扫描头文件并构建包装器 (.cpp + .java) 代码,将本机 class 公开给 JVM。这不是您要问的确切内容,但可能非常接近。

在寻找我的问题的解决方案时,我发现了有关为什么转换不起作用的更多细节:

  1. ArrayList(来自 Java)在 JNI 框架中未被视为 jobjectArray。它被识别为 jObject。因此,如果您想转换 ArrayList 对象,则必须在 JNI

  2. 中创建一个新的 jobjectArray
  3. 您不能访问 ArrayList class 中的方法(如 get 或 set),因为参数的 class 是通用的。 JNI

  4. 中不允许泛型

由于这两个原因,ArrayList对象无法通过JNI转换发送。相反,我选择将我的 ArrayList 转换为 Java 端的对象数组 myClass[],然后将其发送。

下面是我为这个转换写的代码:

javaClass.java

void setFooArray(ArrayList<Foo> param) {
    Foo[] fooArray = new Foo[param.size()];

    for (int i = 0; i < param.size(); i++) {
        fooArray[i] = param.get(i);
    }

    native_setFooArray(fooArray, fooArray.length);
}

// ...

private native void native_setFooArray(Foo[] fooArray, int size);

原生-lib.cpp

JNIEXPORT void JNICALL
java_com_example_my_project_native_1setFooArray(JNIEnv *env, jobject instance, jobjectArray fooArray, jint arraySize) {

    std::vector<Foocpp> cfooArray;

    jfieldID fidA;
    jfieldID fidB;

    for (jint i = 0; i < arraySize; i++) {
        jobject jfoo = env->GetObjectArrayElement(fooArray, i);
        jclass cfoo = env->GetObjectClass(jfoo);

        fidA = env->getFieldID(cfoo, "A", "I");
        fidB = env->GetFieldID(cfoo, "B", "I");
        jint A = env->GetIntField(cfoo, fidA);
        jint B = env->GetIntField(cfoo, fidB);

        const Foocpp foo = Foocpp(A, B);
        cfooArray.push_back(foo);
    }

    class->setFooArray(cfooArray);

有用链接: