javah.exe 是 Java 开发工具包(JDK)中的一个工具,用于生成 JNI(Java Native Interface)头文件。JNI 是 Java 提供的一种机制,允许 Java 代码调用本地(C/C++)代码,以便与系统级功能进行交互。
使用 javah.exe 工具可以根据 Java 类中的 native 方法生成对应的 C/C++ 头文件,这样就可以在本地代码中实现这些 native 方法。
javah [options] <classes>
-o <file> 输出文件 (只能使用 -d 或 -o 之一)
-d <dir> 输出目录,指定生成的头文件的输出目录。
-v -verbose 启用详细输出
-h --help -? 输出此消息
-version 输出版本信息
-jni 生成 JNI 样式的标头文件 (默认值)
-force 始终写入输出文件,强制覆盖已存在的头文件。
-classpath <path> 指定 javah 工具查找类文件的路径。
-cp <path> 从中加载类的路径
-bootclasspath <path> 从中加载引导类的路径
<classes> 是使用其全限定名称指定的,例如:java.lang.Object
假设您有一个名为 HelloWorld 的 Java 类,其中包含一个 native 方法 nativeMethod,您希望生成 JNI 头文件以实现该方法的本地实现。步骤如下:
(1)编写 Java 类 HelloWorld.java:
package com.hxstrive.javah; /** * @author HuangXin * @since 1.0.0 2024/2/28 13:59 */ public class HelloWorld { public native void nativeMethod(); public static void main(String[] args) { HelloWorld hello = new HelloWorld(); hello.nativeMethod(); } }
(2)编译 Java 类:
E:\demo\src\main\java>javac ./com/hxstrive/javah/HelloWorld.java
(3)使用 javah 命令生成 JNI 头文件:
E:\demo\src\main\java>javah -jni com.hxstrive.javah.HelloWorld
执行上述命令后,将生成一个名为 HelloWorld.h 的头文件,其中包含了 nativeMethod 方法的声明。您可以在本地代码中实现该方法。如下图:
com_hxstrive_javah_HelloWorld.h 文件内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_hxstrive_javah_HelloWorld */ #ifndef _Included_com_hxstrive_javah_HelloWorld #define _Included_com_hxstrive_javah_HelloWorld #ifdef __cplusplus extern "C" { #endif /* * Class: com_hxstrive_javah_HelloWorld * Method: nativeMethod * Signature: ()V */ JNIEXPORT void JNICALL Java_com_hxstrive_javah_HelloWorld_nativeMethod (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
(4)编写本地代码 HelloWorld.c 来实现 native 方法:
#include <stdio.h> #include <jni.h> #include "com_hxstrive_javah_HelloWorld.h" JNIEXPORT void JNICALL Java_com_hxstrive_javah_HelloWorld_nativeMethod(JNIEnv *_env, jobject _obj) { // 在这里实现 nativeMethod 的本地代码 printf("Hello from JNI C code!\n"); }
(5)编译本地 C 代码(注意,需要提前安装 MinGW):
E:\demo\src\main\java>gcc -shared -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" HelloWorld.c -o HelloWorld.dll
其中:
-I"%JAVA_HOME%\include" 和 -I"%JAVA_HOME%\include\win32" 分别指定了 JDK 的头文件路径。
-shared 参数表示生成共享库文件。
在编译成功后,将生成一个名为 HelloWorld.dll 动态链接库文件。
(6)将共享库加载到 Java 程序中,并调用 nativeMethod 方法。修改一下 HelloWorld.java 程序,如下:
package com.hxstrive.javah; public class HelloWorld { public native void nativeMethod(); static { // 加载共享库 HelloWorld.dll System.loadLibrary("HelloWorld"); } public static void main(String[] args) { HelloWorld hello = new HelloWorld(); hello.nativeMethod(); } }
注意:运行程序前需要将 HelloWorld.dll 共享库放到 %JAVA_HOME%\bin 目录,而且还要将共享库和 JDK 版本保持一致,要么全是 32位,要么全是 64位。否则将会得到如下错误信息:
java.lang.UnsatisfiedLinkError: C:\Program Files\Java\jdk1.8.0_171\bin\HelloWorld.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform at java.lang.ClassLoader$NativeLibrary.load(Native Method) at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941) at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1857) at java.lang.Runtime.loadLibrary0(Runtime.java:870) at java.lang.System.loadLibrary(System.java:1122) at com.hxstrive.javah.HelloWorld.<clinit>(HelloWorld.java:12) Exception in thread "main"