Java通過(guò)JNI調(diào)用C++動(dòng)態(tài)庫(kù)的完整流程詳解
介紹使用 JNI 調(diào)用 C++ 編寫的動(dòng)態(tài)鏈接庫(kù)的全過(guò)程。
示例環(huán)境
| 項(xiàng)目 | 說(shuō)明 |
|---|---|
| JDK | 8 |
| C++ 編譯器 | Visual Studio 2019 |
| Java 開(kāi)發(fā)工具 | IntelliJ IDEA 2021.3 |
| 操作系統(tǒng) | Windows 10 |
Java 項(xiàng)目結(jié)構(gòu)概覽

編寫 Java 類
在 org.jni.nativejni 包下創(chuàng)建類 HelloWorldJni.java:
package org.jni.nativejni;
public class HelloWorldJni {
static {
// 加載 C++ 編譯生成的 DLL
System.load("E:/vsproject/HelloWorld/x64/Release/HelloWorld.dll");
}
// native 方法聲明
public native String sayHello(String str1, String str2);
public native int add(int a, int b);
public static void main(String[] args) {
HelloWorldJni hw = new HelloWorldJni();
System.out.println("拼接字符串:" + hw.sayHello("Hello", "World"));
System.out.println("相加:" + hw.add(52, 23));
}
}
生成 JNI 頭文件
方法一:使用 javac -h(推薦方式,支持 JDK8+)
在項(xiàng)目根目錄下執(zhí)行命令:
javac -h src/main/jni src/main/java/org/jni/nativejni/HelloWorldJni.java
說(shuō)明:
- -h 參數(shù)用于指定生成頭文件的目錄。
- 這個(gè)命令會(huì)編譯 .java 文件然后生成 .class 文件,同時(shí)生成 JNI 頭文件。
注意:這個(gè)命令會(huì)在源碼目錄中生成 .class 文件,建議在 target/classes 中操作,避免污染源碼。
方法二:使用 javah(僅適用于 JDK8)
先使用 Maven 編譯項(xiàng)目:
mvn clean install
然后執(zhí)行:
javah -classpath target/classes -d src/main/jni org.jni.nativejni.HelloWorldJni
說(shuō)明:
- -classpath 指定 .class 文件的根路徑。
- -d 指定 JNI 頭文件的輸出目錄。
實(shí)現(xiàn) JNI 層與調(diào)用 DLL 方法
使用 Visual Studio 編譯生成 DLL
1.創(chuàng)建一個(gè)新的 C++ DLL 項(xiàng)目,項(xiàng)目名稱為 HelloWorld。
2.添加源文件:
- HelloWorld.cpp:實(shí)現(xiàn) DLL 的原始功能邏輯。
- HelloWorldJNI.cpp:實(shí)現(xiàn) JNI 橋接代碼。
3.配置項(xiàng)目屬性:
C/C++ → 常規(guī) → 附加包含目錄中添加:
- JDK 的 include 目錄
- JDK 的 include/win32 目錄
C++ 頭文件:HelloWorld.h
#ifndef HELLO_WORLD_H #define HELLO_WORLD_H // 導(dǎo)出 HelloWorld 函數(shù) extern "C" __declspec(dllexport) const char* HelloWorld(const char* str1, const char* str2); // 導(dǎo)出 Add 函數(shù) extern "C" __declspec(dllexport) int Add(int a, int b); #endif // HELLO_WORLD_H#pragma once
C++ 實(shí)現(xiàn):HelloWorld.cpp
// HelloWorld.cpp
#include "pch.h" // 如果 VS 生成了預(yù)編譯頭文件
#include "HelloWorld.h" // 引入頭文件
#include <iostream>
#include <string>
extern "C" __declspec(dllexport) const char* HelloWorld(const char* str1, const char* str2) {
static std::string result; // 使用靜態(tài)變量存儲(chǔ)返回值,確保返回的指針有效
result = std::string(str1) + "," + std::string(str2);
return result.c_str(); // 返回拼接后的 C 字符串
}
// 一個(gè)簡(jiǎn)單的加法函數(shù)
extern "C" __declspec(dllexport) int Add(int a, int b) {
return a + b;
}JNI 頭文件:org_jni_nativejni_HelloWorldJni.h
由 javac -h 或 javah 自動(dòng)生成,內(nèi)容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_jni_nativejni_HelloWorldJni */
#ifndef _Included_org_jni_nativejni_HelloWorldJni
#define _Included_org_jni_nativejni_HelloWorldJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_jni_nativejni_HelloWorldJni
* Method: sayHello
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_org_jni_nativejni_HelloWorldJni_sayHello
(JNIEnv *, jobject, jstring, jstring);
/*
* Class: org_jni_nativejni_HelloWorldJni
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_org_jni_nativejni_HelloWorldJni_add
(JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
JNI 實(shí)現(xiàn):HelloWorldJNI.cpp
#include "pch.h" // 如果 VS 生成了預(yù)編譯頭文件
#include "org_jni_nativejni_HelloWorldJni.h" // 引入自動(dòng)生成的 JNI 頭文件
#include "HelloWorld.h" // 引入自定義的頭文件,調(diào)用已有的 DLL 接口
JNIEXPORT jstring JNICALL Java_org_jni_nativejni_HelloWorldJni_sayHello
(JNIEnv* env, jobject, jstring jStr1, jstring jStr2) {
// 將 Java 字符串轉(zhuǎn)換為 C 字符串
const char* str1 = env->GetStringUTFChars(jStr1, nullptr);
const char* str2 = env->GetStringUTFChars(jStr2, nullptr);
// 調(diào)用 C++ 動(dòng)態(tài)庫(kù)函數(shù)
const char* result = HelloWorld(str1, str2);
// 釋放 Java 字符串的本地內(nèi)存
env->ReleaseStringUTFChars(jStr1, str1);
env->ReleaseStringUTFChars(jStr2, str2);
// 將 C 字符串轉(zhuǎn)換為 Java 字符串并返回
return env->NewStringUTF(result);
}
JNIEXPORT jint JNICALL Java_org_jni_nativejni_HelloWorldJni_add
(JNIEnv*, jobject, jint a, jint b) {
return Add(a, b); // 調(diào)用原始的 Add 函數(shù)
}
提示:這里為了演示方便,JNI 橋接代碼和業(yè)務(wù)邏輯放在同一個(gè)項(xiàng)目中。實(shí)際開(kāi)發(fā)時(shí)橋接層要單獨(dú)封裝,便于維護(hù)與復(fù)用。
Java 調(diào)用 DLL 測(cè)試
將編譯生成的 HelloWorld.dll 放到系統(tǒng)環(huán)境變量中,這里這個(gè)庫(kù)沒(méi)什么其他依賴,都是系統(tǒng) c 盤中有的,所以直接指到它生成的目錄就可以使用了。
運(yùn)行 Java 主類的輸出結(jié)果:
拼接字符串:Hello,World
相加:75
總結(jié)
梳理一下 Java 調(diào)用 C++ DLL 的完整流程。主要包括:
- 編寫 Java 類并聲明 native 方法
- 使用 javac -h 或 javah 生成 JNI 頭文件
- 實(shí)現(xiàn) JNI 橋接層,調(diào)用 DLL 中的 C++ 方法
- 使用 Visual Studio 生成 DLL 文件
- Java 運(yùn)行時(shí)加載并調(diào)用本地方法,或者封裝成接口給別人使用。
到此這篇關(guān)于Java通過(guò)JNI調(diào)用C++動(dòng)態(tài)庫(kù)的完整流程詳解的文章就介紹到這了,更多相關(guān)Java JNI調(diào)用C++動(dòng)態(tài)庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 安卓應(yīng)用開(kāi)發(fā)通過(guò)java調(diào)用c++ jni的圖文使用方法
- c++ mk文件出錯(cuò)Jni調(diào)用產(chǎn)生java.lang.UnsatisfiedLinkError錯(cuò)誤解決方法
- Android JNI c/c++調(diào)用java的實(shí)例
- JNI實(shí)現(xiàn)最簡(jiǎn)單的JAVA調(diào)用C/C++代碼
- Java通過(guò)調(diào)用C/C++實(shí)現(xiàn)的DLL動(dòng)態(tài)庫(kù)——JNI的方法
- JNI實(shí)現(xiàn)Java調(diào)用C/C++代碼詳細(xì)代碼示例
相關(guān)文章
mybatis實(shí)現(xiàn)批量插入并返回主鍵(xml和注解兩種方法)
這篇文章主要介紹了mybatis實(shí)現(xiàn)批量插入并返回主鍵(xml和注解兩種方法),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Java如何Mock FileInputStream問(wèn)題
這篇文章主要介紹了Java如何Mock FileInputStream問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
Springboot項(xiàng)目javax.validation使用方法詳解
這篇文章主要介紹了Springboot項(xiàng)目javax.validation使用方法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
java正則表達(dá)式匹配網(wǎng)頁(yè)所有網(wǎng)址和鏈接文字的示例
這篇文章主要介紹了java正則表達(dá)式匹配網(wǎng)頁(yè)所有網(wǎng)址和鏈接文字java正則表達(dá)式匹配,需要的朋友可以參考下2014-03-03
Java8實(shí)戰(zhàn)之Stream的延遲計(jì)算
JDK中Stream的中間函數(shù)如 filter(Predicate super T>)是惰性求值的,filter并非對(duì)流中所有元素調(diào)用傳遞給它的Predicate,下面這篇文章主要給大家介紹了關(guān)于Java8實(shí)戰(zhàn)之Stream延遲計(jì)算的相關(guān)資料,需要的朋友可以參考下2021-09-09
Java實(shí)現(xiàn)在線編輯預(yù)覽office文檔詳解
PageOffice是一款在線的office編輯軟件,幫助Web應(yīng)用系統(tǒng)或Web網(wǎng)站實(shí)現(xiàn)用戶在線編輯Word、Excel、PowerPoint文檔,下面我們就來(lái)看看如何使用Java實(shí)現(xiàn)在線預(yù)覽office吧2024-01-01

