Java 通过 JNA 调用 C++ DLL:关键流程总结

java_native_access 项目 JNA 调用流程

1. 项目结论

这个项目演示了 Java 通过 JNA 调用 C++ 动态库中的两个排序函数。完整调用链是:

text 复制代码
App.main
  -> JnaDll 接口中的 JNA 动态代理
  -> JNA 自带的 jnidispatch.dll
  -> Windows 加载 libcpp_native_sort_int_arr.dll
  -> 查找并调用 bubble_sort / selection_sort
  -> C++ 原地修改整数数组
  -> 修改结果回写到 Java int[]
  -> App 打印排序结果

它和传统 JNI 示例的主要区别是:项目不需要生成 JNI 头文件,也不需要编写 Java_包名_类名_方法名 形式的桥接函数。Java 只需声明一个与原生函数匹配的 JNA 接口,JNA 在运行时完成动态库加载、符号查找、参数转换和函数调用。

项目包含两个相互独立的构建根:

  • cpp_native:使用 CMake 和 MinGW 构建 C++ DLL。
  • java_call_cpp:使用 Maven 编译 Java、引入 JNA,并生成可执行 fat JAR。

2. 关键文件与职责

文件 职责
cpp_native/src/sort_int_arr.h 声明 bubble_sortselection_sort,用 extern "C" 保持 C 符号名。
cpp_native/src/sort_int_arr.cpp 实现两个原地排序函数。
cpp_native/CMakeLists.txt 创建 cpp_native_sort_int_arr 共享库目标。
cpp_native/CMakePresets.json 配置 MinGW、Debug 构建目录和构建预设。
java_call_cpp/src/main/java/com/JnaDll.java 定义 Java 与原生函数之间的 JNA 映射,并加载 DLL。
java_call_cpp/src/main/java/com/App.java Java 入口;创建数组、调用两个原生排序函数并打印结果。
java_call_cpp/pom.xml 引入 JNA、设置 com.App 入口、复制 DLL,并生成 fat JAR。

3. 构建与产物流转

3.1 C++ 动态库

CMakeLists.txt 使用 add_library(... SHARED ...) 创建共享库目标:

text 复制代码
cpp_native_sort_int_arr

MinGW 构建后的主要产物是:

text 复制代码
cpp_native/build/mingw/libcpp_native_sort_int_arr.dll
cpp_native/build/mingw/libcpp_native_sort_int_arr.dll.a

其中 .dll 是运行时动态库,.dll.a 是供原生链接器使用的导入库;本项目的 JNA 调用只需要 .dll

头文件中的 extern "C" 阻止 C++ 名字改编,因此 DLL 中可以找到与 Java 方法同名的导出符号:

text 复制代码
bubble_sort
selection_sort

本次已经从现有 DLL 导出表中确认这两个符号。需要区分两个概念:

  • extern "C" 负责保持符号名,避免 C++ 名字改编。
  • __declspec(dllexport) 或链接器配置负责把符号导出到 DLL。

当前源码没有实际使用 __declspec(dllexport)CPP_NATIVE_EXPORTS 即便作为编译定义存在,也没有被头文件消费。因此当前构建依赖 MinGW 的导出行为,切换到 MSVC 时应补充有效的显式导出宏。

3.2 DLL 进入 Java 模块

CMake 构建结束后,需要先手动复制 DLL:

text 复制代码
cpp_native/build/mingw/libcpp_native_sort_int_arr.dll
  -> java_call_cpp/libcpp_native_sort_int_arr.dll

这是 CMake 与 Maven 两个构建根之间的桥接步骤,当前没有被 CMake 或 Maven 自动完成。

执行 mvn package 时,maven-resources-pluginprepare-package 阶段继续复制 DLL:

text 复制代码
java_call_cpp/libcpp_native_sort_int_arr.dll
  -> java_call_cpp/target/libcpp_native_sort_int_arr.dll

同时,maven-assembly-plugin 生成:

text 复制代码
java_call_cpp/target/java_call_cpp-1.0-SNAPSHOT-jar-with-dependencies.jar

fat JAR 内包含项目类、JNA Java 类以及 JNA 自带的各平台 jnidispatch 库,但项目自己的 libcpp_native_sort_int_arr.dll 没有嵌入 JAR,仍然是外部 sidecar 文件。

普通的 java_call_cpp-1.0-SNAPSHOT.jar 只包含项目代码,不包含 JNA 依赖,不能直接作为独立程序运行;完整运行应使用 jar-with-dependencies 产物。

4. Java 到 C++ 的运行时调用流程

"libcpp_native_sort_int_arr.dll" "jnidispatch.dll" "JNA 动态代理" "JnaDll" "App.main" "libcpp_native_sort_int_arr.dll" "jnidispatch.dll" "JNA 动态代理" "JnaDll" "App.main" #mermaid-svg-FlYrX8jr4ofJ0nWQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FlYrX8jr4ofJ0nWQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .error-icon{fill:#552222;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .marker.cross{stroke:#333333;}#mermaid-svg-FlYrX8jr4ofJ0nWQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FlYrX8jr4ofJ0nWQ p{margin:0;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-FlYrX8jr4ofJ0nWQ text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-FlYrX8jr4ofJ0nWQ .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-FlYrX8jr4ofJ0nWQ #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .sequenceNumber{fill:white;}#mermaid-svg-FlYrX8jr4ofJ0nWQ #sequencenumber{fill:#333;}#mermaid-svg-FlYrX8jr4ofJ0nWQ #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .messageText{fill:#333;stroke:none;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .labelText,#mermaid-svg-FlYrX8jr4ofJ0nWQ .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .loopText,#mermaid-svg-FlYrX8jr4ofJ0nWQ .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-FlYrX8jr4ofJ0nWQ .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .noteText,#mermaid-svg-FlYrX8jr4ofJ0nWQ .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .actorPopupMenu{position:absolute;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-FlYrX8jr4ofJ0nWQ .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-FlYrX8jr4ofJ0nWQ .actor-man circle,#mermaid-svg-FlYrX8jr4ofJ0nWQ line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-FlYrX8jr4ofJ0nWQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 首次读取 JnaDll.jnaDll Native.load(DLL 名称, JnaDll.class) 从 JAR 解压并加载 JNA 原生桥 LoadLibrary 返回 JnaDll 动态代理 bubble_sort(arr, arr.length) 代理拦截 Java 方法调用 查找 bubble_sort 并传入 int*、int 原地执行冒泡排序 void 返回 修改结果反映到原 int\[\] selection_sort(arr, arr.length) 按同样方式调用 selection_sort 修改结果反映到原 int\[\]

4.1 初始化 JNA 接口

JnaDll 继承 com.sun.jna.Library

java 复制代码
public interface JnaDll extends Library {
    JnaDll jnaDll =
        (JnaDll) Native.load("libcpp_native_sort_int_arr.dll", JnaDll.class);
}

接口字段隐式为 public static final。当 App 第一次读取 JnaDll.jnaDll 时,JVM 初始化该接口并执行 Native.load(...)

Native.load(...) 创建 Library.Handler,由它加载 DLL,然后通过 Proxy.newProxyInstance(...) 返回一个实现 JnaDll 的运行时动态代理。第一次调用某个接口方法时,代理按 Java 方法名取得对应的原生 Function 并执行。

4.2 加载 JNA 自身的原生桥

JNA 的 Java 代码不能直接执行任意 DLL 函数。第一次初始化 com.sun.jna.Native 时,JNA 会从依赖 JAR 中找到与当前系统和 CPU 架构匹配的 jnidispatch.dll,将它解压到临时目录并加载。

这个 DLL 是 JNA 自己的底层桥接层,不是本项目编写的 DLL。它负责把 Java 侧的动态调用转换为操作系统原生函数调用。

4.3 加载项目 DLL

JNA 随后按 JnaDll.java 中的名称查找:

text 复制代码
libcpp_native_sort_int_arr.dll

当前代码传入的是相对文件名,因此运行时必须满足下列条件之一:

  • 当前工作目录中存在该 DLL;
  • 通过 -Djna.library.path=目录 指定 DLL 搜索目录;
  • DLL 位于操作系统可搜索的路径中。

项目将 DLL 复制到 target 后,可以先进入 target 再启动 JAR,也可以显式把 target 设置为 jna.library.path。仅仅让 DLL 与 JAR 位于同一目录,并不等于 JNA 会自动按 JAR 所在目录查找;进程工作目录和显式搜索路径才是关键。

4.4 Java 与 C/C++ 签名映射

Java 接口:

java 复制代码
void bubble_sort(int[] values, int length);
void selection_sort(int[] values, int length);

C/C++ 声明:

cpp 复制代码
void bubble_sort(int* values, int length);
void selection_sort(int* values, int length);

映射关系如下:

Java/JNA C/C++ 说明
void void 原生函数没有返回值。
int int 在当前 Windows/MinGW ABI 中,两侧都是 32 位有符号整数。
int[] int* JNA 让原生函数访问数组元素;调用完成后,修改反映到原 Java 数组。
Java 方法名 DLL 导出符号名 未配置 FunctionMapper 时,JNA 按同名符号查找。
Library 默认调用约定 C 默认调用约定 与当前 MinGW 导出函数匹配。

JNA 底层可以固定 Java 数组,也可以使用临时本机缓冲区;这个细节由 JVM/JNA 原生桥决定。对本项目而言,已经通过实际运行确认 C++ 的修改会反映到原来的 int[]

4.5 执行排序并回写数组

Apparr.length 作为第二个参数传给 C++。C++ 直接通过 int* 原地交换数组元素,函数返回后,App 可以从原来的 Java 数组中看到新顺序,所以不需要接收返回值。

当前 C++ 函数不检查空指针或长度上界。现有调用始终传入非空数组和 arr.length,是安全的;新增调用方也必须保证 0 <= length <= values.length。原生函数不能保存本次调用获得的 int*,该指针只在这次 JNA 调用期间有效。

5. 完整构建与运行命令

以下命令按 Windows Git Bash / MSYS2 Bash 格式编写。

bash 复制代码
set -euo pipefail

cd /c/source/learning_cpp_vscode/java_native_access/cpp_native

# 普通 Git Bash 未配置 MinGW 时,先补充工具链路径。
export PATH="/c/msys64/ucrt64/bin:$PATH"

# 配置并构建 C++ DLL。
cmake --preset mingw
cmake --build --preset mingwbuild

# 把最新 DLL 交给 Java 模块。
test -f build/mingw/libcpp_native_sort_int_arr.dll
cp build/mingw/libcpp_native_sort_int_arr.dll \
   ../java_call_cpp/libcpp_native_sort_int_arr.dll

# 编译 Java、复制 DLL,并生成 fat JAR。
cd ../java_call_cpp
mvn clean package

# 显式指定 Maven target 为 JNA 的 DLL 搜索目录。
test -f target/libcpp_native_sort_int_arr.dll
java -Djna.library.path=target \
     -jar target/java_call_cpp-1.0-SNAPSHOT-jar-with-dependencies.jar

预期输出:

text 复制代码
Hello World!
[-1, 1, 2, 5, 6, 8, 9]
[-1, 1, 2, 5, 6, 8, 9]

也可以进入 target 后运行:

bash 复制代码
cd /c/source/learning_cpp_vscode/java_native_access/java_call_cpp/target
java -Djna.library.path=. \
     -jar java_call_cpp-1.0-SNAPSHOT-jar-with-dependencies.jar

6. 调试 DLL 加载过程

JNA 支持输出动态库查找日志:

bash 复制代码
cd /c/source/learning_cpp_vscode/java_native_access/java_call_cpp
java -Djna.debug_load=true \
     -Djna.library.path=target \
     -jar target/java_call_cpp-1.0-SNAPSHOT-jar-with-dependencies.jar

关键日志应包含:

text 复制代码
Looking for library 'libcpp_native_sort_int_arr.dll'
Trying libcpp_native_sort_int_arr.dll
Found library 'libcpp_native_sort_int_arr.dll'

如果默认临时目录不可写,可显式设置 JNA 解压目录:

bash 复制代码
cd /c/source/learning_cpp_vscode/java_native_access/java_call_cpp
mkdir -p target/jna-tmp
java -Djna.tmpdir="$PWD/target/jna-tmp" \
     -Djna.debug_load=true \
     -Djna.library.path=target \
     -jar target/java_call_cpp-1.0-SNAPSHOT-jar-with-dependencies.jar

7. 常见失败点

现象 调用链中的失败位置 检查项
UnsatisfiedLinkError: Unable to load library JNA 加载项目 DLL 当前工作目录、jna.library.path、DLL 是否已复制、DLL 的间接依赖是否齐全。
Failed to create temporary file ... jnidispatch.dll JNA 初始化自身原生桥 临时目录权限;必要时设置 -Djna.tmpdir
找不到 bubble_sortselection_sort JNA 查找导出函数 extern "C"、实际导出表、方法名拼写、调用约定。
NoClassDefFoundError: com/sun/jna/Library JVM 加载 Java 依赖 误运行了普通 JAR;改用 jar-with-dependencies
DLL 架构不匹配错误 Windows 加载 DLL JVM、JNA 与 DLL 的 x86/x64 架构必须一致。
Java 数组结果错误或进程崩溃 参数封送或 C++ 数组访问 Java/C 类型是否匹配,length 是否越界,是否传入空数组。
修改 C++ 后仍运行旧逻辑 CMake 与 Maven 之间的手动桥接 重新构建 DLL,并再次复制到 java_call_cpp 后再打包。

可用 MinGW 工具确认导出符号:

bash 复制代码
cd /c/source/learning_cpp_vscode/java_native_access/cpp_native
nm -g --defined-only build/mingw/libcpp_native_sort_int_arr.dll \
  | grep -E 'bubble_sort|selection_sort'

8. 当前实现边界

  • 当前实现面向 Windows,Java 代码硬编码了 .dll 文件名。
  • jna-platform 已在 POM 中声明,但这两个函数调用只使用了核心 jna 依赖。
  • java_call_cpp/README.MD 中的手动下载 JNA JAR 说明不参与当前 Maven 构建;实际依赖来自 POM。
  • fat JAR 包含 JNA 自身的 jnidispatch.dll,但不包含项目的 C++ DLL。
  • cpp_native/REAEME.MD 仍描述旧的 JNI hello.dll 示例,不能作为当前 JNA 构建链的准确说明。
  • CMakePresets.json 的显示名仍写着 GCC 9.2.0,但本次实际解析到的是 g++ 16.1.0;显示名只是标签。
  • Maven 当前没有测试源码;mvn clean package 会执行测试阶段,但结果是 No tests to run

9. 本次验证结果

验证日期:2026-07-29。

  • cmake --preset mingw:配置成功。
  • cmake --build --preset mingwbuild --verbose:目标 cpp_native_sort_int_arr 构建成功。
  • DLL 导出表:确认存在 bubble_sortselection_sort,DLL 为 x86-64。
  • mvn clean package:构建成功,生成普通 JAR、fat JAR 和 target 下的 DLL。
  • fat JAR 内容:确认包含 com.Appcom.JnaDll、JNA 类和 Windows jnidispatch.dll;确认未嵌入项目 DLL。
  • Java 端到端运行:两个原生排序调用均得到 [-1, 1, 2, 5, 6, 8, 9]
  • 验证环境:Java 21.0.2、Maven 3.9.6、CMake 3.26.3、MinGW g++ 16.1.0,均为 64 位 Windows 环境。

完整代码

1.cpp端,工程名cpp_native

1.CMakeLists.txt

cpp 复制代码
cmake_minimum_required(VERSION 3.14)
project(cpp_native_sort_int_arr LANGUAGES CXX)

set(CUR_TARGET_NAME ${PROJECT_NAME})

# 创建动态库目标
add_library(${CUR_TARGET_NAME} SHARED
    src/sort_int_arr.cpp
)

2.CMakePresets.json

json 复制代码
{
    "version": 6,
    "configurePresets": [
        {
            "name": "mingw",
            "displayName": "GCC 9.2.0 mingw32",
            "description": "Using compilers: gcc, g++",
            "generator": "MinGW Makefiles",
            "binaryDir": "${sourceDir}/build/${presetName}",
            "cacheVariables": {
                "CMAKE_C_COMPILER": "gcc",
                "CMAKE_CXX_COMPILER": "g++",
                "CMAKE_MAKE_PROGRAM": "mingw32-make",
                "CMAKE_BUILD_TYPE": "Debug",
                "CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
            }
        }
    ],
    "buildPresets": [
        {
            "name": "mingwbuild",
            "displayName": "Build with MinGW",
            "description": "Build the project using the mingw configure preset.",
            "configurePreset": "mingw"
        }
    ]
}

3.src\sort_int_arr.h

cpp 复制代码
#ifndef SORT_INT_ARR_H
#define SORT_INT_ARR_H

#ifdef __cplusplus
extern "C" {
#endif

// 冒泡排序:重复交换相邻逆序元素,原地排序。
void bubble_sort(int* values, int length);

// 选择排序:每轮选择未排序区间的最小值,原地排序。
void selection_sort(int* values, int length);

#ifdef __cplusplus
}
#endif

#endif

4.src\sort_int_arr.cpp

cpp 复制代码
#include "sort_int_arr.h"

void bubble_sort(int* values, int length) {
    for (int i = 0; i < length - 1; ++i) {
        for (int j = 0; j < length - 1 - i; ++j) {
            if (values[j] > values[j + 1]) {
                int temp = values[j];
                values[j] = values[j + 1];
                values[j + 1] = temp;
            }
        }
    }
}

void selection_sort(int* values, int length) {
    for (int i = 0; i < length - 1; ++i) {
        int min_index = i;
        for (int j = i + 1; j < length; ++j) {
            if (values[j] < values[min_index]) {
                min_index = j;
            }
        }
        if (min_index != i) {
            int temp = values[i];
            values[i] = values[min_index];
            values[min_index] = temp;
        }
    }
}

2.java端,工程名java_call_cpp

1.pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>java_call_cpp</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>java_call_cpp</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>

  <dependencies>
    <!-- JNA (Java Native Access) -->
    <dependency>
      <groupId>net.java.dev.jna</groupId>
      <artifactId>jna</artifactId>
      <version>5.19.1</version>
    </dependency>

    <dependency>
      <groupId>net.java.dev.jna</groupId>
      <artifactId>jna-platform</artifactId>
      <version>5.19.1</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <!-- 设置 JAR 的 Main-Class -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.0.2</version>
        <configuration>
          <archive>
            <manifest>
              <mainClass>com.App</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>

      <!-- 打包时将 DLL 复制到 target 目录,与 JAR 同级 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>3.0.2</version>
        <executions>
          <execution>
            <id>copy-native-dll</id>
            <phase>prepare-package</phase>
            <goals>
              <goal>copy-resources</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}</outputDirectory>
              <resources>
                <resource>
                  <directory>${project.basedir}</directory>
                  <includes>
                    <include>libcpp_native_sort_int_arr.dll</include>
                  </includes>
                </resource>
              </resources>
            </configuration>
          </execution>
        </executions>
      </plugin>

      <!-- 打包 fat JAR:将项目代码 + 所有依赖合并为一个可执行 JAR -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.6.0</version>
        <configuration>
          <archive>
            <manifest>
              <mainClass>com.App</mainClass>
            </manifest>
          </archive>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

2.src\main\java\com\JnaDll.java

java 复制代码
package com;
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface JnaDll extends Library {
    // 实例化dll
    JnaDll jnaDll = (JnaDll)Native.load("cpp_native_sort_int_arr", JnaDll.class);

    // 声明dll导出的函数
    // 冒泡排序:重复交换相邻逆序元素,返回排序后的副本。
    void bubble_sort(int[] values, int length);

    // 选择排序:每轮选择未排序区间的最小值,返回排序后的副本。
    void selection_sort(int[] values, int length);
}

3.src\main\java\com\App.java

java 复制代码
package com;

import java.util.Arrays;

public class App {
    public static void main(String[] args) {
        System.out.println("Hello World!");

        {
            int[] arr = { 2, 5, 1, -1, 9, 8, 6 };
            JnaDll.jnaDll.bubble_sort(arr, arr.length);
            System.out.println(Arrays.toString(arr));
        }
        {
            int[] arr = { 2, 5, 1, -1, 9, 8, 6 };
            JnaDll.jnaDll.selection_sort(arr, arr.length);
            System.out.println(Arrays.toString(arr));
        }
    }
}

3.编译和调用方式

1.编译cpp端cpp_native

bash 复制代码
cmake --preset mingw
cmake --build --preset mingwbuild

编译后可以看到如下输出,libcpp_native_sort_int_arr.dll已被生成

txt 复制代码
[ 50%] Building CXX object CMakeFiles/cpp_native_sort_int_arr.dir/src/sort_int_arr.cpp.obj
[100%] Linking CXX shared library libcpp_native_sort_int_arr.dll
[100%] Built target cpp_native_sort_int_arr

2.将libcpp_native_sort_int_arr.dll复制到java工程的根目录

bash 复制代码
cp cpp_native/build/mingw/libcpp_native_sort_int_arr.dll java_call_cpp/

3.编译java工程

bash 复制代码
mvn package

4.运行java工程,调用dll

bash 复制代码
java -jar ./target/java_call_cpp-1.0-SNAPSHOT-jar-with-dependencies.jar
相关推荐
风中芦苇啊15 小时前
Java EasyExcel 导入通用工具类:自定义注解映射字段 + 反射机制
java·开发语言
家有娇妻张兔兔15 小时前
Java 对接 PLC 主流型号最合适的方案:Apache PLC4X 实战指南
java·开发语言·plc·modbus·数据缓存·西门子s7·apache plc4x
摇滚侠16 小时前
Codebuddy 官网 Codebuddy IntelliJ IDEA 插件 阅读笔记 2
java·笔记·intellij-idea
gugucoding16 小时前
24. 【Java】枚举:更安全的常量
java·开发语言
一只旭宝16 小时前
C++手写shared_ptr共享智能指针|原子引用计数、强弱引用控制块、赋值重载底层深度剖析
开发语言·c++·面试
Kyrie_kk17 小时前
Java--BigInteger 超大整数计算
java·算法
z落落17 小时前
T-SQL 事务(Transaction)
java·数据库·sql
库克克18 小时前
【C++】智能指针
java·开发语言·c++
lemon_sjdk18 小时前
Spring WebFlux 响应式编程深度解析:从架构选型到核心抽象
java·spring·架构