如何将Java接口作为参数传入C++的std::function类型函数?
解决方案
要将Java的ByteArrayProvider接口实例传入C的sign函数,你需要在JNI层完成类型适配,把Java接口的调用逻辑包装成C的std::function<Data(Data)>类型,具体步骤如下:
1. 保存Java接口实例的全局引用
在JNI代码中,先为ByteArrayProvider实例创建全局引用,避免局部引用被Java垃圾回收机制回收:
// 假设你已通过JNI拿到ByteArrayProvider的局部引用jobj jobject globalProvider = env->NewGlobalRef(jobj);
2. 实现C++适配函数
编写一个适配函数,负责完成C++与Java之间的数据类型转换,并调用Java接口的provide方法:
Data javaProviderAdapter(Data inputData) { // 获取当前线程的JNIEnv,多线程环境下需先调用AttachCurrentThread JNIEnv* env = ...; jclass providerClazz = env->GetObjectClass(globalProvider); // 获取ByteArrayProvider接口中provide方法的ID jmethodID provideMethod = env->GetMethodID(providerClazz, "provide", "([B)[B)"); // 将C++的std::vector<byte>转换为JNI的jbyteArray jbyteArray inputJArray = env->NewByteArray(inputData.size()); env->SetByteArrayRegion(inputJArray, 0, inputData.size(), reinterpret_cast<const jbyte*>(inputData.data())); // 调用Java接口的provide方法 jbyteArray resultJArray = static_cast<jbyteArray>(env->CallObjectMethod(globalProvider, provideMethod, inputJArray)); // 将JNI的jbyteArray转换为C++的std::vector<byte> jsize resultLength = env->GetArrayLength(resultJArray); Data resultData(resultLength); env->GetByteArrayRegion(resultJArray, 0, resultLength, reinterpret_cast<jbyte*>(resultData.data())); // 释放JNI局部引用,避免内存泄漏 env->DeleteLocalRef(inputJArray); env->DeleteLocalRef(resultJArray); env->DeleteLocalRef(providerClazz); return resultData; }
3. 包装为std::function并传入sign函数
把适配函数包装成std::function<Data(Data)>类型,直接传入sign函数即可:
std::function<Data(Data)> signer = javaProviderAdapter; sign(signer);
关键注意事项
- 多线程处理:如果
sign函数在非JNI初始化线程中调用,需要先调用AttachCurrentThread获取JNIEnv,使用完毕后调用DetachCurrentThread。 - 资源回收:不再使用
ByteArrayProvider实例时,记得调用env->DeleteGlobalRef(globalProvider)释放全局引用。 - 异常检查:可以添加
env->ExceptionCheck()检查Java层是否抛出异常,防止异常扩散导致C++程序崩溃。
内容的提问来源于stack exchange,提问作者DDk9499
相关产品推荐
相关产品推荐

