您在此处对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);
其中数组只是“真实”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 中没有长度,所以我假设您是 0 终止数组,尽管您可以通过一些简单的更改同样很好地传递长度。
(为方便起见,我%inlined 你的班级以减少文件数量并添加了一个虚拟实现以进行测试)
%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 Proxy 到 Java JNI 的转换中做任何事情,所以 javain 类型映射只是直接通过。在 JNI 的 C++ 端,它是 jlongArray,我们还在另一个类型图中指定了它。
然后我们需要一个 in 类型映射来安排在 C++ 端从 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);
}
}
正如你所愿。