
Java 可以通过 JNI(Java Native Interface)与本地代码进行交互。JNI 使 Java 程序能够调用和被调用本地应用程序和库。JNI 提供了一种机制,通过它可以在运行时动态地调用本地方法,而无需重新编译整个应用程序。使用 JNI 的主要步骤包括:声明本地方法、生成头文件、实现本地方法以及加载本地库。接下来,将详细介绍这些步骤。
一、声明本地方法
在 Java 中声明本地方法需要使用 native 关键字。以下是一个简单的例子:
public class MyClass {
// 声明本地方法
public native void myNativeMethod();
static {
// 加载本地库
System.loadLibrary("MyNativeLib");
}
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.myNativeMethod();
}
}
在这个例子中,我们声明了一个名为 myNativeMethod 的本地方法。System.loadLibrary 方法用于加载包含本地方法实现的本地库。
二、生成头文件
接下来,需要使用 javah 工具生成包含本地方法声明的头文件。假设上面的 Java 类文件名为 MyClass.java,可以使用以下命令生成头文件:
javac MyClass.java
javah -jni MyClass
这将生成一个名为 MyClass.h 的头文件,其中包含 myNativeMethod 的声明。
三、实现本地方法
接下来,需要在 C 或 C++ 中实现这些本地方法。以下是一个示例的 C 代码实现:
#include <jni.h>
#include "MyClass.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_MyClass_myNativeMethod(JNIEnv *env, jobject obj) {
printf("Hello from native code!n");
}
在这个例子中,我们实现了 Java_MyClass_myNativeMethod 函数,该函数将打印一条消息到控制台。
四、编译本地代码
接下来,需要编译本地代码以生成共享库。在 Linux 上,可以使用以下命令:
gcc -shared -o libMyNativeLib.so -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux MyClass.c
在 Windows 上,可以使用类似的命令,但文件扩展名将是 .dll。
gcc -shared -o MyNativeLib.dll -I"%JAVA_HOME%include" -I"%JAVA_HOME%includewin32" MyClass.c
五、加载和调用本地方法
回到我们的 Java 代码,当 System.loadLibrary("MyNativeLib") 被调用时,Java 虚拟机将加载我们编译的本地库。然后,当 myNativeMethod 被调用时,控制权将转移到我们在 C 代码中实现的 Java_MyClass_myNativeMethod 函数。
六、JNI 的高级用法
1、传递复杂数据类型
JNI 不仅可以传递基本数据类型,还可以传递对象和数组。以下是一个示例,展示了如何传递和处理 Java 字符串:
Java 代码
public class MyClass {
public native String reverseString(String input);
static {
System.loadLibrary("MyNativeLib");
}
public static void main(String[] args) {
MyClass obj = new MyClass();
String reversed = obj.reverseString("Hello");
System.out.println(reversed);
}
}
C 代码
#include <jni.h>
#include "MyClass.h"
#include <string.h>
JNIEXPORT jstring JNICALL Java_MyClass_reverseString(JNIEnv *env, jobject obj, jstring input) {
const char *inCStr = (*env)->GetStringUTFChars(env, input, NULL);
if (NULL == inCStr) return NULL;
size_t len = strlen(inCStr);
char outCStr[len + 1];
for (size_t i = 0; i < len; i++) {
outCStr[i] = inCStr[len - i - 1];
}
outCStr[len] = '