如何使用SWIG实现C++ std::map到Java Map的类型转换
实现步骤
你不需要手动编写自定义typemap,SWIG官方提供的std_map.i标准库文件已经内置了C++ std::map<K,V> 到Java端java.util.Map<K,V>的完整转换逻辑,包括JNI层类型转换、内存管理、遍历逻辑都已经实现。你当前的配置只需要修正两个问题即可实现自动转换:
- 移除全局作用域下错误放置的
#include <string>,所有原生C头文件引用必须放在%{ ... %}块内,这部分代码会被SWIG原样输出到生成的C包装代码中,放在全局作用域会被SWIG当成接口解析导致报错。 - 在解析你自己的业务头文件之前,用
%template宏显式实例化你用到的具体map类型。SWIG是静态生成包装代码的,仅引入std_map.i不会自动支持所有任意类型参数的map,必须明确告诉SWIG需要为std::map<std::string, std::string>生成对应包装代码。
修正后的完整SWIG接口文件
%module test // 引入SWIG标准库对基础类型的封装支持 %include <std_string.i> %include <std_map.i> %include <windows.i> // 如果业务中没有使用宽字符串、不需要SWIG默认指针类型映射,可以删掉下面两行 // %include <std_wstring.i> // %include <typemaps.i> // 原生C++代码引入块,内容会直接输出到生成的JNI C++文件中 %{ #include <string> #include "File.h" %} // 关键:显式实例化string-string类型的map模板 // 括号内的StringStringMap是生成的Java端包装类名,可以自定义,符合Java类命名规范即可 %template(StringStringMap) std::map<std::string, std::string>; // 最后引入需要包装的业务头文件 %include "File.h"
调用说明
用上述接口文件编译生成JNI动态库和Java代码后,Java端调用逻辑和普通Java方法完全一致:
public class Demo { public static void main(String[] args) { System.loadLibrary("test"); // 加载编译生成的JNI库 A a = new A(); Map<String, String> result = a.GetMap(); // 直接返回Java标准Map类型,无需手动转换 // 可以直接使用Map的所有常规方法:get、put、遍历等 for (Map.Entry<String, String> entry : result.entrySet()) { System.out.println(entry.getKey() + ":" + entry.getValue()); } } }
注意事项
%template声明必须放在%include "File.h"之前,否则SWIG解析到GetMap()的返回值时,还没有识别到对应map类型的实例化,会把返回值包装成不透明的SWIG指针对象,无法自动转换为Java Map。- 如果后续需要使用其他键值类型的map,只需要新增对应
%template声明即可,比如要支持std::map<int, std::string>,就加一行%template(IntStringMap) std::map<int, std::string>;。 - 不要手动重写这个类型的typemap,SWIG自带的实现已经处理了跨语言内存释放、类型校验等边界情况,手写很容易出现内存泄漏、类型转换异常问题。
内容的提问来源于stack exchange,提问作者TestUser
相关产品推荐
相关产品推荐

