首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java JNI 調用 C++ 原生庫完整流程:從 .java 到 .dll/.so 落地

     編輯:Java 相關知識

Java Native Interface (JNI) 讓 Java 呼叫 C/C++ 實作的高效能或平台相關功能。本文以 HelloWorld 為例,完整示範:Java 宣告 native 方法 → javac 編譯 → javah 生成 .h → C++ 實作 → 編譯動態庫 → Java 載入執行。

1. Java 類別宣告 native 方法

public class HelloWorld {
    public native void displayHelloWorld(); // 無實作體

    static {
        System.loadLibrary("hello"); // 載入 hello.dll (Windows) 或 libhello.so (Linux)
    }

    public static void main(String[] args) {
        new HelloWorld().displayHelloWorld();
    }
}

2. 編譯產生 .class

javac HelloWorld.java

3. 生成 JNI 頭文件

javah -jni HelloWorld
// 產生 HelloWorld.h,包含 JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv*, jobject);

4. C++ 實作 (HelloWorldImpl.cpp)

#include 
#include 
#include "HelloWorld.h"

JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj) {
    printf("Hello from C++!\n");
}

5. 編譯動態庫

Windows (MSVC):

cl -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -LD HelloWorldImpl.cpp -Fehello.dll

Linux/macOS (GCC):

gcc -shared -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" \
    HelloWorldImpl.cpp -o libhello.so

6. 執行

java -Djava.library.path=. HelloWorld
// 輸出: Hello from C++!

關鍵避坑指南

  • 函數簽名必須完全一致:Java_包名_類名_方法名,包名用底線分隔,若類在包內需包含包路徑。
  • 資料類型映射:jint↔int、jstring 需用 GetStringUTFChars/ReleaseStringUTFChars、jobjectArray 對應 Java 陣列。
  • 異常傳遞:C++ 端用 ThrowNew(env, clazz, msg) 拋出 Java 異常。
  • 執行緒安全:JNIEnv 非執行緒安全,若在 Native 執行緒回呼 Java,需用 AttachCurrentThread。
  • 效能考量:JNI 呼叫開銷大,避免頻繁跨界;大量數據傳輸用 GetPrimitiveArrayCritical 或 Direct Buffer。
  • 替代方案:JNA (Java Native Access) 免寫 C++ Glue Code,適合簡單庫調用;GraalVM Native Image 可將 Java 編譯為原生執行檔,減少 JNI 需求。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved