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_sort 和 selection_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-plugin 在 prepare-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 执行排序并回写数组
App 把 arr.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_sort 或 selection_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仍描述旧的 JNIhello.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_sort和selection_sort,DLL 为 x86-64。 mvn clean package:构建成功,生成普通 JAR、fat JAR 和target下的 DLL。- fat JAR 内容:确认包含
com.App、com.JnaDll、JNA 类和 Windowsjnidispatch.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