我的样本.h文件如下:
class Test
{
public:
void SelectValues(long long values[])
};
我使用SWIG并从.i文件下面创建了JNI接口
%module MyLib
%include "carrays.i"
%array_functions(long long, long_long_array )
%{
#include "Test.h"
%}
/* Let's just grab the original header file here */
%include <windows.i> /*This line is used for calling conventions*/
% include "Test.h"
当我创建Java方法时,它创建如下:
public void SelectValues(SWIGTYPE_p_long_long includeKeys)
同样对于JNI文件,它将参数作为jlongArray
,但仅采用简单的jlong
。由于这个问题,我无法创建像long[]={1L,2L}
这样的长数组,并将其传递给Java方法以上,以调用适当的JNI方法。
我希望SWIG以这样的方式生成接口,我可以将上面提到的数组传递给我的C ++方法。
我已阅读this question,但它无法帮助我了解如何将数组从Java传递到C ++。
答案 0 :(得分:2)
你在这里使用array_functions
所做的是正确和可用的,但它专注于直接包装C ++代码,并且它不会使用底层Java数组。您可以使用以下内容:
SWIGTYPE_p_long_long array = MyLib.new_long_long_array(100); // new array with 100 elements.
for (int i = 0; i < 100; ++i) {
long_long_array_setitem(array, i, i);
}
new Test().SelectValues(array);
其中array只是一个“真正的”C ++内存块的代理,您可以在Java端读取/写入并传递给包装函数。
我猜你的问题是你有兴趣让这种感觉在Java方面更“自然”。 SWIG还提供array_class
,它类似地包装数组,但是作为一个适当的对象而不是静态函数的集合。例如,如果您将接口文件更改为使用array_class(long long, LongLongArray)
而不是array_functions
,则可以执行以下操作:
LongLongArray array = new LongLongArray(100);
for (int i = 0; i < 100; ++i) {
array.setitem(i,i);
}
new Test().SelectValues(array.cast());
如果您愿意,实际上您可以使SWIG做多于一些类型图的操作。你的示例类在SelectValues
中的长度并不长,所以我假设你终止了数组,尽管你可以通过一些简单的改变来传递长度。
(为方便起见,我%inline
你的班级减少了文件的数量,并添加了一个虚拟的文件实现用于测试)
%module MyLib
%{
#include <iostream>
%}
%typemap(jtype) long long values[] "long[]"
%typemap(jstype) long long values[] "long[]"
%typemap(javain) long long values[] "$javainput"
%typemap(jni) long long values[] "jlongArray"
%typemap(in) long long values[] {
jboolean isCopy;
$1 = JCALL2(GetLongArrayElements, jenv, $input, &isCopy);
}
%inline %{
class Test
{
public:
void SelectValues(long long values[]) {
while (*values) {
std::cout << *values++ << "\n";
}
}
};
%}
这里我们说代理类SWIG都生成,它生成的JNI类将使用long[]
,即Java数组。我们不需要在Java代理到Java JNI转换中执行任何操作,因此javain
类型映射只是直接传递。在JNI的C ++端是jlongArray
,我们也在另一个typemap中指定了它。
然后我们需要一个in
类型映射来安排从Clong端的jlongArray到long long[]
的转换 - 对此有一个JNI调用,我们不关心它是副本还是实际的内存来自我们最终使用的JVM。 (您可能会关心是否要修改结果并将其显示在Java内部)例如
我测试了这个:
public class run {
public static void main(String[] argv) {
System.loadLibrary("mylib");
long arr[] = {100,99,1,0}; // Terminate with 0!
new Test().SelectValues(arr);
}
}
完全按照你的意愿行事。