【隐私计算篇】Java(JDK17)通过JNI实现调用C++动态链接库(.so)

在最近的工作中,需要通过Java调用C++的动态链接库(.so文件)。为此,我使用了Java的JNI(Java Native Interface)技术。我整理了一个简单的示例,供大家参考。

JNI 是Java提供的一种机制,允许Java代码与本地应用程序或库进行交互,尤其是那些用C或C++编写的库。这在需要与底层系统进行高效交互或调用现有的本地库时非常有用。

步骤1:创建工具静态库 (libcalc.a)

首先,我们编写一个简单的 cpp 文件(calc.cpp),这个文件包含一个执行加法运算的函数,然后将其编译成静态库。

calc.h

cpp 复制代码
// calc.h
#ifndef CALC_H
#define CALC_H

class Calculator {
public:
    int add(int a, int b);
};

#endif // CALC_H

calc.cpp

cpp 复制代码
// calc.cpp
#include "calc.h"

int Calculator::add(int a, int b) {
    return a + b;
}

将这个文件编译成静态库:

bash 复制代码
g++ -c calc.cpp -o calc.o 
ar rcs libcalc.a calc.o

这将生成一个名为 libcalc.a 的静态库文件。

步骤2:编写 Java 代码调用动态库

接下来,使用 Java 17 编写一个类,加载动态库并调用本地方法。

CalcJNI.java

java 复制代码
public class CalcJNI {static {
        System.loadLibrary("jni_add");
    }
    // 声明本地方法
    public native int add(int a, int b);
    
    public static void main(String[] args) {
    CalcJNI calc = new CalcJNI();
    int result = calc.add(5, 3);
    System.out.println("Result of 5 + 3 = " + result);
    }
}

步骤3:生成 JNI 头文件

从 JDK 10 开始,javah 已被弃用,我们可以直接使用 javac-h 选项生成 JNI 头文件。

执行生成 JNI 头文件(CalcJNI.h)命令。

java 复制代码
javac -h . CalcJNI.java

这会在当前目录生成 CalcJNI.h 文件,供我们在 C++ 代码中使用。

步骤4:创建桥接动态库 (libjni_add.so)

接下来,我们编写一个动态库,动态库会链接到上面创建的静态库,并通过 JNI 暴露给 Java 使用。

jni_add.cpp

cpp 复制代码
#include <jni.h>
#include "CalcJNI.h"  // 由 javah 生成的 JNI 头文件
#include "calc.h"     // 包含静态库头文件

JNIEXPORT jint JNICALL Java_CalcJNI_add(JNIEnv *env, jobject obj, jint a, jint b) {
    Calculator calc;
    return calc.add(a, b);
}

编译这个文件并生成动态库

cpp 复制代码
g++ -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -c jni_add.cpp -o jni_add.o
g++ -shared -o libjni_add.so jni_add.o -L. -lcalc

上面的命令生成一个名为 libjni_add.so 的动态库文件。

步骤5:运行 Java 程序

最后,运行 Java 程序:

cpp 复制代码
java CalcJNI

如果一切顺利,输出应该是:

cpp 复制代码
Result of 5 + 3 = 8

小结

本次我们使用 C++ 实现了工具静态库和桥接动态库,并通过JNI与Java进行了集成。我们还使用了 JDK 17,并展示了如何使用 javac 生成 JNI 头文件。

这套流程不仅支持更复杂的 C++ 功能,还能更好地与现代 Java 版本兼容。


改进代码组织结构

CMake管理代码组织结构

cpp 复制代码
project/
│
├── CMakeLists.txt
│
├── calc/            # 步骤1的静态库代码
│   ├── CMakeLists.txt
│   ├── calc.h
│   └── calc.cpp
│
├── calc_jni/        # 步骤4的动态库及JNI封装代码
│   ├── CMakeLists.txt
│   ├── calc_jni_wrapper.h
│   ├── calc_jni_wrapper.cpp
│   ├── jni_add.cpp
│   └── calc_jni.h   # 步骤3生成的头文件
│
└── calc_project/    # 步骤2的Java代码
    ├── CMakeLists.txt
    ├── CalcJNI.java
    ├── CalcTool.java
    └── Demo.java

# 需要事先定义CalcJNI接口,并通过javac生成calc_jni.h 头文件。

外层的CMakeLists.txt

cpp 复制代码
cmake_minimum_required(VERSION 3.10)
project(CalcProject)

# 添加子目录
add_subdirectory(calc)
add_subdirectory(calc_jni)
add_subdirectory(calc_project)

新建一个build.sh

cpp 复制代码
rm -rf build
javac -h ./calc_jni ./calc_project/CalcJNI.java
mkdir build
cd build
cmake ..
cmake --build .

cd calc_project
java -Djava.library.path=../calc_jni -cp calc_project.jar Demo

🔥🔥🔥代码资源下载: https://download.csdn.net/download/Jackie_vip/89654764

相关推荐
今儿敲了吗几秒前
Python——函数基础
开发语言·笔记·python
CHANG_THE_WORLD6 分钟前
深入理解递归:从函数调用到调用栈的完整执行过程
java·开发语言·算法
xexpertS8 分钟前
CI/CD 熔断机制:如何通过编排级熔断器提升开发者效率
java·linux·运维
kels889932 分钟前
单连接动态增减订阅:股票行情API后端降负载实战方案
开发语言·笔记·python·信息可视化·金融
一拳一个呆瓜1 小时前
【STL】iostream 编程:使用提取运算符
c++·stl
zy happy1 小时前
VMware虚拟机添加新的硬盘
java·linux·jvm·docker
a4493153621 小时前
MacBook USB-C不充电故障诊断:从PD握手到主板供电链路
c语言·开发语言·macos·电脑
德福危险1 小时前
从目录枚举到bash破壳漏洞、从流量抓包到组权限提权:靶机练习之symfonos3
开发语言·bash
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题 第192题】【08_Kafka篇】第8题:死信队列是什么?延时队列是什么?
java·kafka·消息队列·死信队列·延时队列
meng半颗糖1 小时前
3.Java流程控制语句
java·开发语言·intellij-idea