Java 中创建一个对应的 Native 类,声明一个接受该结构体指针作为参数的本地方法:
```java
public class DiskInfoJava {
private native void getDiskInfo(DiskInfo diskInfo);
static {
System.loadLibrary("diskinfo"); // 加载本地库
}
public void processDiskInfo() {
// 创建一个 DiskInfo 实例
DiskInfo disk = new DiskInfo();
// 调用本地方法
getDiskInfo(disk);
// 在这里可以处理返回的 disk 信息
}
}
```
在 C++ 中,我们需要实现这个 `getDiskInfo` 方法。我们需要定义与 Java 对应的数据类型,并且创建一个转换函数,将 Java 的对象转换为 C++ 的结构体:
```c++
#include <jni.h>
#include "DiskInfoJava.h" // 包含自动生成的头文件
// 定义 C++ 的 DiskInfo 结构体
struct DiskInfo {
char name[256];
int serial;
};
// 转换函数,将 Java 的 DiskInfo 对象转换为 C++ 的 DiskInfo 结构体
DiskInfo convertFromJava(JNIEnv* env, jobject diskInfoObj) {
// 获取 DiskInfo 的字段 ID
jfieldID nameFieldID = env->GetFieldID(env->GetObjectClass(diskInfoObj), "name", "Ljava/lang/String;");
jfieldID serialFieldID = env->GetFieldID(env->GetObjectClass(diskInfoObj), "serial", "I");
// 获取字段值
jstring nameStr = (jstring) env->GetObjectField(diskInfoObj, nameFieldID);
int serial = env->GetIntField(diskInfoObj, serialFieldID);
// 将 Java 字符串转换为 C 字符数组
const char* nameChars = env->GetStringUTFChars(nameStr, NULL);
strcpy(diskInfo.name, nameChars);
env->ReleaseStringUTFChars(nameStr, nameChars);
// 设置序列号
diskInfo.serial = serial;
return diskInfo;
}
JNIEXPORT void JNICALL Java_DiskInfoJava_getDiskInfo(JNIEnv* env, jobject thisObj, jobject diskInfoObj) {
// 转换 Java 对象为 C++ 结构体
DiskInfo disk = convertFromJava(env, diskInfoObj);
// 在这里处理 C++ 的 DiskInfo 结构体
// ...
// 不需要做什么处理,因为 C++ 结构体不会改变 Java 对象
// 如果需要更新 Java 对象,可以反向转换并设置字段
}
```
在上面的示例中,我们展示了如何在 JNI 中处理 Java 对象与 C++ 结构体之间的转换。需要注意的是,Java 中的对象在传递给 C++ 时,需要通过 JNI 提供的 API 来获取其字段值。此外,由于 Java 和 C++ 数据类型的差异,例如 Java 的字符串是 `jstring` 类型,而 C++ 中是 `char*`,所以需要进行适当的转换。
当 C++ 处理完数据后,如果需要更新 Java 对象的状态,还需要将 C++ 结构体的信息反向转换回 Java 对象的字段。这个过程可能涉及到内存管理,如创建新的 Java 对象或释放临时分配的内存。
总结一下,JNI 参数传递的关键点包括:
1. **类型映射**:Java 和 C++ 的数据类型不同,需要使用 JNI 提供的类型映射,如 `jint`、`jstring` 等。
2. **字段访问**:使用 JNI 的 `GetFieldID` 和 `GetObjectField`、`GetIntField` 等方法获取 Java 对象的字段值。
3. **对象转换**:根据需要创建 C++ 结构体,并从 Java 对象中提取数据填充结构体;反之,如果需要更新 Java 对象,也需要将 C++ 结构体的数据转换回 Java 对象。
4. **内存管理**:注意内存的分配和释放,避免内存泄漏,尤其是在处理字符串和自定义对象时。
虽然 JNI 提供了强大的功能,但它的使用会增加代码的复杂性和维护难度,同时降低了程序的可移植性。因此,除非必要,否则应尽量避免使用 JNI。在实际开发中,可以考虑使用其他技术,如 GraalVM 的 Substrate VM 或者 AOT 编译,来提高 Java 代码的性能,减少对本地代码的依赖。