JNI 包装器从 C++ 读取列表并返回到 JAVA

kal*_*ala 1 c++ java java-native-interface stl

我有一个要求,我需要使用 JNI 将一些值从 C++ 传递到 JAVA。根据要求,c++ 代码的输入是一条带有点列表的线,我必须读取每个点的 x 和 y 坐标并返回到 java 代码。我已将列表声明为 std::list> listofpoints; 并读取 x 和 y 坐标为

for(size_t j = 0; j < track->geometry.points.size(); ++j)
{

 PointZ &p = track->geometry.points[j]             listofpoints.push_back(std::pair<double, double>(p.vertex.position.x,p.vertex.position.y)); 
Run Code Online (Sandbox Code Playgroud)

这个 geometry.points 是读取每个点,获取 x 和 y 坐标。现在我将此 listofpoints 返回给 JNI 方法。在这里我必须编写代码,以便它读取 x 和 y 坐标并将其发送到 JAVA 方法。我正在寻找一种迭代列表并获取值的方法,但是,我发现很难从 JNI 返回到 JAVA,因为 JNI 仅返回 jobjectarray。如何将此列表转换为 JNI 中的数组并发送到 JAVA 方法。我对 JNI 和 JAVA 也很陌生。

Jor*_*nee 6

您可以将 转换std::list<std::pair<double, double>>为 Java List<Pair<Double, Double>>

下面是一个例子:

Java方法:

public static native List<Pair<Double, Double>> getList();
Run Code Online (Sandbox Code Playgroud)

C++部分:

std::list<std::pair<double, double>> myList{ // example input
    {1, 2},
    {3, 4}
};

JNIEXPORT jobject JNICALL Java_Main_getList(JNIEnv *env, jclass cls) {
    // First, get all the methods we need:
    jclass arrayListClass = env->FindClass("java/util/ArrayList");    
    jmethodID arrayListConstructor = env->GetMethodID(arrayListClass, "<init>", "()V");
    jmethodID addMethod = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");

    jclass pairClass = env->FindClass("javafx/util/Pair");
    jmethodID pairConstructor = env->GetMethodID(pairClass, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");        

    // This is needed to go from double to Double (boxed)
    jclass doubleClass = env->FindClass("java/lang/Double");    
    jmethodID doubleValueOf = env->GetStaticMethodID(doubleClass, "valueOf", "(D)Ljava/lang/Double;");

    // The list we're going to return:
    jobject list = env->NewObject(arrayListClass, arrayListConstructor);

    for(auto& coord : myList) {
        // Convert each C++ double to a java.lang.Double:
        jobject x = env->CallStaticObjectMethod(doubleClass, doubleValueOf, coord.first);
        jobject y = env->CallStaticObjectMethod(doubleClass, doubleValueOf, coord.second);

        // Create a new pair object
        jobject pair = env->NewObject(pairClass, pairConstructor, x, y);
        // Add it to the list
        env->CallBooleanMethod(list, addMethod, pair);
    }

    return list;
}
Run Code Online (Sandbox Code Playgroud)

也就是说,std::vector在 C++ 端使用 a 可能更容易。将 的组件展平std::pair为 a double[],并将其传递回 java:

public static native double[] getList();
Run Code Online (Sandbox Code Playgroud)

C++:

std::vector<std::pair<double, double>> myList{ // Now an std::vector
    {1, 2},
    {3, 4}
};

JNIEXPORT jdoubleArray JNICALL Java_Main_getList(JNIEnv *env, jclass cls) {
    size_t length = myList.size() * 2;
    double input[length];

    // Flatten pairs
    for(int i = 0, j = 0; i < length; i += 2, j++) {    
        input[i] = myList[j].first;
        input[i + 1] = myList[j].second;
    }

    // Copy into Java double[]
    jdoubleArray array = env->NewDoubleArray(length);        
    env->SetDoubleArrayRegion(array, 0, length, ((jdouble*) &input));

    return array;
}
Run Code Online (Sandbox Code Playgroud)

然后在 Java 方面,您将做一些进一步的翻译。例如:

public List<Pair<Double, Double>> getTranslated() {
    List<Pair<Double, Double>> ret = new ArrayList<>();

    double[] list = getList(); // Calling our native method
    for(int i = 0; i < list.length; i += 2) {
        ret.add(new Pair<>(list[i], list[i + 1]));
    }

    return ret;
}
Run Code Online (Sandbox Code Playgroud)