1

应用场景

通过JNI, 实现Java调用C++代码

环境

JDK: jdk-17.0.9
mingw-w64: x86_64-13.2.0-release-posix-seh-ucrt-rt_v11-rev1
操作系统: windows11

实现步骤

1. 声明native方法

NativeCommand.java

/**
 * # 生成头文件
 * javac -encoding UTF-8 -h . NativeCommand.java
 *  -jni表示生成c++头文件, 从Java 10开始,-jni 选项已经不再需要了,因为现在 javac -h 默认就会生成C++的头文件。
 *
 */
public class NativeCommand {

    /**
     * 发送命令给Cpp
     * @param command 命令
     * @param args 参数
     * @return 响应
     */
    public native String send(String command, String... args);

}

上面定义了方法public native send(xxx)

2. 生成.h头文件

执行命令即可(如果是JDK8, 需要使用javah命令, 相关用法请自行差查阅)
javac -encoding UTF-8 -h . NativeCommand.java

jdk17已经将javah合并到javac中了, 使用javac -h替代javah命令
执行完成后当前目录会生成NativeCommand.h文件

3. 编写C++代码

NativeCommand.cpp

#include "NativeCommand.h"
#include <iostream>
 
JNIEXPORT jstring JNICALL Java_NativeCommand_send
  (JNIEnv *env, jobject obj, jstring cmd, jobjectArray args) {
    std::cout<<"Cpp copy, Over"<<std::endl;
    // std::string hello = "Hello from C++";
    return env->NewStringUTF("Over");
}

4. 编译dll

g++ -Wall -g -I"boot/include" -I"boot/include/win32" -I"boot/include/win32/bridge" -fPIC NativeCommand.cpp -shared -o nativecmd.dll
将输出nativecmd.dll
其中boot/目录是jdk17的安装目录, 需要改成自己的

5. 加载dll

NativeMain.java

public class NativeMain {
    static {
        // 加载dll
        // 启动参数指定dll目录: -Djava.library.path=D:/WorkspaceVsCode/adswarhead

        // 打印 java.library.path
        // String javaLibraryPath = System.getProperty("java.library.path");
        // System.out.println(javaLibraryPath);

        // 这里不要加.dll后缀
        System.loadLibrary("nativecmd");
    }

    public static void main(String[] args) {
        new NativeCommand().send("xxx", args);
    }
}

执行NativeMain, 切记指定java.library.path参数, 指向dll文件所在的目录, 如果在IDEA中执行, 可以参考截图:
image.png

输出结果:
image.png

错误情况

1. UnsatisfiedLinkError

异常堆栈:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no nativecmd.dll in java.library.path: D:/WorkspaceVsCode/adswarhead
    at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2429)
    at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:818)
    at java.base/java.lang.System.loadLibrary(System.java:1989)
    at NativeMain.<clinit>(NativeMain.java:9)

原因: 加载dll失败
解决办法: 检查-Djava.library.path参数, 要设置成dll所在的目录, 示例: -Djava.library.path=D:/WorkspaceVsCode/adswarhead

资料

C++启动JVM并调用Java main方法


YYGP
25 声望11 粉丝

写BUG