本文已使用 Google Cloud Translation API 自动翻译。
某些文档最好以原文阅读。
Java 本机接口 (JNI) 是一个强大的工具,它允许 Java 代码与用其他语言编写的本机代码进行互操作。在本文中,我们将仔细研究 JNI 的工作原理以及如何使用它来提高 Java 应用程序的性能。
Java 本机接口是一组标准,定义了 Java 代码如何与用其他语言编写的本机代码进行交互。 JNI 是平台无关的,这意味着它可以用来编写在任何操作系统上运行的代码。
JNI 定义了一组规则来管理 Java 代码和本机代码如何交互。当 Java 应用程序调用本地方法时,JNI 层将方法调用翻译成本地语言。然后执行本机代码,并将结果返回给 Java 应用程序。
使用 JNI 有几个好处,包括:
使用 JNI 也有一些缺点,包括:
当利大于弊时,应该使用 JNI。 JNI 最常用于提高 Java 应用程序的性能或访问 Java 平台中不可用的本机库。
让我们看一个如何使用 JNI 来提高 Java 应用程序性能的示例。我们将从计算两个整数之和的简单 Java 方法开始:
public static int sum(int a, int b) {
return a + b;
}
我们可以通过使用 JNI 调用在本地代码中执行计算的本地方法来提高此方法的性能。首先,我们需要用C写native方法:
int sum(int a, int b) {
return a + b;
}
接下来,我们需要编写一个调用本地方法的 Java 包装器方法:
public static native int sum(int a, int b);
最后,我们需要将 C 代码和 Java 代码编译成一个共享库。在 Linux 上,我们可以使用以下命令执行此操作:
gcc -shared -fPIC -o libsum.so sum.c
然后我们可以使用以下代码将共享库加载到我们的 Java 应用程序中:
System.loadLibrary("sum");
我们现在可以从 Java 代码中调用 sum() 方法,计算将在本机代码中执行。这可以提高我们应用程序的性能,因为本机代码通常比 Java 代码更快。
JNI 还可用于访问 Java 平台中不可用的本机库。例如,Java 平台不提供用于访问 Win32 API 的本机库。但是,我们可以使用 JNI 从我们的 Java 代码中调用 Win32 API。
首先,我们需要为每个要调用的 Win32 API 函数编写一个 Java 包装器方法:
public static native int MessageBox(int hWnd, String lpText, String lpCaption, int uType);
接下来,我们需要编写一个包含 Win32 API 和 JNI 头文件的 C++ 文件:
#include <windows.h>
#include <jni.h>
然后我们可以编写 Java 包装器方法的实现:
JNIEXPORT jint JNICALL Java_MessageBox_1MessageBox(JNIEnv *env, jclass cls, jint hWnd, jstring lpText, jstring lpCaption, jint uType)
{
return MessageBox(hWnd, (LPCTSTR)lpText, (LPCTSTR)lpCaption, uType);
}
最后,我们需要将我们的 C++ 代码编译成一个共享库。在 Windows 上,我们可以使用以下命令执行此操作:
cl /LD MessageBox.cpp
然后我们可以使用以下代码将共享库加载到我们的 Java 应用程序中:
System.loadLibrary("MessageBox");
我们现在可以从我们的 Java 代码调用 MessageBox() 函数,Win32 API 将被调用。这允许我们从 Java 代码访问 Win32 API,即使 Java 平台没有为 Win32 API 提供本机库。
JNI 也可用于从本机代码调用 Java 方法。当我们需要从没有 JNI 接口的本机库调用 Java 方法时,这会很有用。
首先,我们需要为要调用的 Java 方法编写一个 Java 包装器方法:
public static native void print(String msg);
接下来,我们需要编写一个包含 JNI 头文件的 C++ 文件:
#include <jni.h>
然后我们可以编写 Java 包装器方法的实现:
JNIEXPORT void JNICALL Java_print_1print(JNIEnv *env, jclass cls, jstring msg)
{
// Get the printStream field from the java.lang.System class
jclass systemClass = env->FindClass("java/lang/System");
jfieldID printStreamField = env->GetStaticFieldID(systemClass, "out", "Ljava/io/PrintStream;");
// Get the PrintStream object from the printStream field
jobject printStream = env->GetStaticObjectField(systemClass, printStreamField);
// Get the println() method from the PrintStream class
jclass printStreamClass = env->GetObjectClass(printStream);
jmethodID printlnMethod = env->GetMethodID(printStreamClass, "println", "(Ljava/lang/String;)V");
// Call the println() method
env->CallVoidMethod(printStream, printlnMethod, msg);
}
最后,我们需要将我们的 C++ 代码编译成一个共享库。在 Windows 上,我们可以使用以下命令执行此操作:
cl /LD print.cpp
然后我们可以使用以下代码将共享库加载到我们的 Java 应用程序中:
System.loadLibrary("print");
我们现在可以从 C++ 代码调用 print() 方法,Java println() 方法将被调用。这允许我们从没有 JNI 接口的本机库调用 Java 方法。
JNI 是一个强大的工具,它允许 Java 代码与用其他语言编写的本机代码进行互操作。 JNI 可用于提高 Java 应用程序的性能或访问 Java 平台中不可用的本机库。但是,JNI 也为 Java 应用程序增加了一层额外的复杂性,并且不能跨平台移植。