JNI中的列表嵌套列表需要进行传递、返回和转换为向量列表

27

我需要从Java中传递参数

List< List<MyPoint> > points;

通过jni转换到C ++并转换为

std::vector< std::vector<MyPoint> >

处理这些向量并返回

List< List<MyPoint> >
  1. 如何正确传递和返回列表的列表?
  2. 如何将对象的列表的列表转换为对象的向量的向量及其反向操作?

3
你试过使用Swig吗,特别是Swig与STL? 它会为你生成必要的JNI粘合代码。 - G. Martinek
不,使用Swig解决这个问题是不可接受的——只能使用标准工具。 - George
@WdF:为什么这是不可接受的?你至少可以尝试一下Swig并查看它生成的Java/JNI代码类型。Swig自动完成的所有操作也可以使用手写代码完成。 - In silico
Swig不是裸JNI - 它是附加工具。最初,使用最少量的第三方工具。 - George
4个回答

19

我使用标准工具解决了这个问题。

  1. 在Java中创建对象(O)容器(C)
  2. 将对象(O)数组从Java代码传递到本地部分
  3. 在C++代码中从数组创建向量
  4. 计算新的向量
  5. 构建容器(C)的数组并插入对象(O)
  6. 返回容器(C)的数组

代码实现:

在Java部分:

1 - 从点列表创建数组

在C++部分:

2 - 构建输入向量

std::vector<CurvePoint> src_line;

jclass java_points_cls = env->FindClass("myPointClass");
jmethodID java_mid = env->GetMethodID(java_points_cls, "<init>", "(II)V");    
jfieldID fidX = env->GetFieldID(java_points_cls, "x", "I");
jfieldID fidY = env->GetFieldID(java_points_cls, "y", "I");

int srcCount = env->GetArrayLength(srcLines);

for (int i=0; i < srcCount; i++) 
{
    jobject cur_pnt =  env->GetObjectArrayElement(srcLines, i); 

    LinePoint src_point;        

    src_point.x = env->GetIntField(cur_pnt, fidX); 
    src_point.y = env->GetIntField(cur_pnt, fidY);    

    src_line.push_back(src_point);
}

3 - 计算 lines

4 - 构建输出数组

jclass java_line_cls = env->FindClass("myLinesClass");

jmethodID java_line_add = env->GetMethodID(java_line_cls, "addPoint", "(II)V");  
jmethodID java_line_init = env->GetMethodID(java_line_cls, "<init>", "()V");

jobjectArray resLines = (jobjectArray) env->NewObjectArray(lines.size(),     java_line_cls, 0); 

for(int i = 0; i < lines.size(); ++i)
{
    jobject cur_line =  env->NewObject(java_line_cls, java_line_init);
    for(int j = 0; j < lines[i].size(); ++j)
        env->CallVoidMethod(cur_line, java_line_add, 
                                lines[i][j].x,
                                lines[i][j].y);
    env->SetObjectArrayElement(resLines, i, cur_line);
}

return resLines;

Java部分

5 - 从返回的数组创建行列表


2
好的,那这个比JavaCPP更好在哪里? - Samuel Audet
2
必须仅使用标准工具。这是项目的要求。在另一种情况下,可以使用JavaCpp或SWIG。我认为JavaCpp是更好的选择。 - George
啊,我明白了……虽然使用SWIG或JavaCPP的输出作为参考可能仍然有用,我想 :) - Samuel Audet
嘿@George, 我有同样的情况,我必须从我的JNI Vector <Vector <Point>> points返回到Java类。 我该怎么做? - DcodeChef
@DcodeChef,请看第(4)步。我在Java部分中有一个名为“myLinesClass”的类。我创建了该类的实例数组。而且,这个类包含点的数组。我使用该类的“addPoint”方法将点推入其中。因此,在类的实例中我们有vector<Point>,在实例数组中我们有vector<vector<Point>>。 - George
显示剩余2条评论

6
JNIEXPORT jobjectArray JNICALL Java_ProcessInformation_getAllProcessPid  (JNIEnv*env,jobject obj) {

    vector<string>vec;

    vec.push_back("Ranjan.B.M");

    vec.push_back("Mithun.V");

    vec.push_back("Preetham.S.N");

    vec.push_back("Karthik.S.G");

    cout<<vec[0];

    cout<<vec[0];

    jclass clazz = (env)->FindClass("java/lang/String");

    jobjectArray objarray = (env)->NewObjectArray(vec.size() ,clazz ,0);

    for(int i = 0; i < vec.size(); i++) {

        string s = vec[i]; 

         cout<<vec[i]<<endl;

         jstring js = (env)->NewStringUTF(s.c_str());

        (env)->SetObjectArrayElement(objarray , i , js);

    }

    return objarray;    

}

2
根据JNI的参考资料,我了解到JNI只能处理一维的原始类型或对象数组。
因为在Java方面,必须将列表转换为数组。然后,在本地部分传递数组和元素数量。这里会处理所需的向量并返回两个数组作为结果(包含所有轮廓点的数组和每个轮廓点数的数组),以及轮廓数。结果数组在Java方面被收集到一个列表中。
虽然问题没有完全解决,因为JNI无法为本地部分中的现有项目分配内存。因此需要部分提取数据,在Java方面为它们分配内存,并填充本地部分。
可能的解决方法是使用绑定器,如SWIG或JavaCpp。

+1 for JavaCPP :) 顺便说一句,在 JNI 中,所有在 Java 中可以做的事情都可以做到,只是很麻烦和效率低下。 - Samuel Audet
1
@SamuelAudet,JavaCPP做得很好 - 我通常使用SWIG,但JavaCPP看起来真的很不错。我必须深入研究一下 :) 谢谢! - G. Martinek

1

您也可以使用此项目。它将允许通过JNI像本地一样使用Java类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接