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

Java JNI 開發完整流程指南:從聲明到動態庫調用實戰

     編輯:Java 相關知識

JNI 核心價值與適用場景

JNI (Java Native Interface) 打破 Java 跨平台封閉性,實現 Java 與 C/C++ 代碼互調。典型場景:

  • 調用平台特定 API(硬件控制、系統級操作)
  • 復用成熟 C/C++ 庫(加密、圖像處理、視頻編解碼)
  • 性能熱點優化(數學運算、數據結構操作)
  • 與現有 Legacy 系統集成

完整開發 7 步驟

步驟 1:編寫 Java 類聲明 native 方法

package com.example.jni;

public class NativeCalculator {
    // 加載動態庫:Windows -> calculator.dll, Linux -> libcalculator.so
    static {
        System.loadLibrary("calculator");
    }
    
    // native 關鍵字聲明,無方法體
    public native int add(int a, int b);
    public native double sqrt(double x);
    
    public static void main(String[] args) {
        NativeCalculator calc = new NativeCalculator();
        System.out.println("5 + 3 = " + calc.add(5, 3));
        System.out.println("sqrt(16) = " + calc.sqrt(16));
    }
}

步驟 2:編譯生成 .class 文件

javac com/example/jni/NativeCalculator.java

步驟 3:生成 C/C++ 頭文件

# 進入 src 根目錄執行
javah -classpath . -jni com.example.jni.NativeCalculator

生成 com_example_jni_NativeCalculator.h:

/* DO NOT EDIT - machine generated */
#include 

#ifndef _Included_com_example_jni_NativeCalculator
#define _Included_com_example_jni_NativeCalculator
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jint JNICALL Java_com_example_jni_NativeCalculator_add
  (JNIEnv *, jobject, jint, jint);

JNIEXPORT jdouble JNICALL Java_com_example_jni_NativeCalculator_sqrt
  (JNIEnv *, jobject, jdouble);

#ifdef __cplusplus
}
#endif
#endif

步驟 4:實現 C/C++ 源文件

#include "com_example_jni_NativeCalculator.h"
#include 

JNIEXPORT jint JNICALL Java_com_example_jni_NativeCalculator_add
  (JNIEnv *env, jobject obj, jint a, jint b) {
    return a + b;
}

JNIEXPORT jdouble JNICALL Java_com_example_jni_NativeCalculator_sqrt
  (JNIEnv *env, jobject obj, jdouble x) {
    return sqrt(x);
}

關鍵點:

  • 函數命名規範:Java_包名_類名_方法名(點替換為下劃線)
  • JNIEnv*:JNI 環境指針,提供數組/字符串/對象操作 API
  • jobject:調用對象實例(非靜態方法),靜態方法為 jclass
  • 類型映射:jint→int、jdouble→double、jstring→String 等

步驟 5:編譯生成動態庫

Linux/macOS (GCC):

gcc -shared -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux \
    -o libcalculator.so com_example_jni_NativeCalculator.c

Windows (MSVC):

cl /I"%JAVA_HOME%\include" /I"%JAVA_HOME%\include\win32" /LD \
    com_example_jni_NativeCalculator.c /Fe:calculator.dll

步驟 6:配置庫路徑並運行

# Linux/macOS
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
java com.example.jni.NativeCalculator

# Windows
set PATH=.;%PATH%
java com.example.jni.NativeCalculator

步驟 7:驗證輸出

5 + 3 = 8
sqrt(16) = 4.0

進階主題:數組與字符串處理

// Java 聲明
public native int sumArray(int[] arr);
public native String reverseString(String str);

// C 實現
JNIEXPORT jint JNICALL Java_com_example_jni_NativeCalculator_sumArray
  (JNIEnv *env, jobject obj, jintArray arr) {
    jint *elements = (*env)->GetIntArrayElements(env, arr, NULL);
    jsize len = (*env)->GetArrayLength(env, arr);
    int sum = 0;
    for (int i = 0; i < len; i++) sum += elements[i];
    (*env)->ReleaseIntArrayElements(env, arr, elements, 0); // 釋放
    return sum;
}

JNIEXPORT jstring JNICALL Java_com_example_jni_NativeCalculator_reverseString
  (JNIEnv *env, jobject obj, jstring str) {
    const char *cstr = (*env)->GetStringUTFChars(env, str, NULL);
    // 反轉邏輯...
    (*env)->ReleaseStringUTFChars(env, str, cstr);
    return (*env)->NewStringUTF(env, reversed);
}

常見問題與最佳實踐

  1. UnsatisfiedLinkError:庫名不匹配、路徑錯誤、架構不匹配(32/64位)、依賴庫缺失
  2. 內存洩漏:Get*ArrayElements/GetStringUTFChars 必須配對 Release*
  3. 異常處理:C 代碼拋出異常需用 ThrowNew,不可直接拋 C++ 異常
  4. 線程安全:JNIEnv 線程私有,不可跨線程傳遞;需 AttachCurrentThread 附加線程
  5. 性能優化:緩存 jclass/jmethodID/jfieldID,避免重複查找
  6. 現代替代方案:JNA(無需編譯 C 代碼)、GraalVM Native Image、Panama API (JDK 19+)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved