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

Java JNI 入門實戰(下):類型映射、字串陣列操作、方法與欄位存取

     編輯:Java 程式設計入門

3. Java 與原生類型映射表

JNI 定義完整類型對應,確保 Java 與 C/C++ 數據無損傳遞:

Java 類型JNI 類型位寬/簽名
booleanjboolean8 位,無符號
bytejbyte8 位
charjchar16 位,無符號
shortjshort16 位
intjint32 位
longjlong64 位
floatjfloat32 位
doublejdouble64 位
voidvoidN/A

基本類型直接值傳遞,無需轉換。jboolean 在 C 中常用 unsigned char 實現。

4. 物件引用類型體系

所有 Java 物件引用統一對應 jobject(相當於 java.lang.Object)。JNI 提供子類型區分常用類別:

  • jclass、jstring、jarray、jobjectArray、jthrowable
  • 基本類型陣列:jbooleanArray、jbyteArray、jcharArray、jshortArray、jintArray、jlongArray、jfloatArray、jdoubleArray

5. 字串操作完整指南

jstring ≠ C char*,必須透過 JNIEnv 方法轉換:

核心 API

功能UTF-8 版本Unicode 版本
轉換為 C 字串GetStringUTFCharsGetStringChars
釋放 C 字串ReleaseStringUTFCharsReleaseStringChars
建立 Java 字串NewStringUTFNewString
獲取長度GetStringUTFLengthGetStringLength

範例:提示用戶輸入

JNIEXPORT jstring JNICALL Java_Prompt_getLine
  (JNIEnv *env, jobject obj, jstring prompt) {
    char buf[128];
    const char *str = (*env)->GetStringUTFChars(env, prompt, 0);
    printf("%s", str);
    (*env)->ReleaseStringUTFChars(env, prompt, str); // 必須釋放,否則記憶體洩漏
    fgets(buf, 128, stdin);
    return (*env)->NewStringUTF(env, buf);
}

鐵律: 每個 Get* 必配對 Release*,否則 JVM 無法回收臨時字串緩衝區,導致記憶體洩漏。

6. 陣列操作完整指南

基本類型陣列

JNIEXPORT jint JNICALL Java_IntArray_sumArray
  (JNIEnv *env, jobject obj, jintArray arr) {
    jsize len = (*env)->GetArrayLength(env, arr);      // 獲取長度
    jint *body = (*env)->GetIntArrayElements(env, arr, 0); // 獲取元素指針
    jint sum = 0;
    for (int i = 0; i < len; i++) sum += body[i];
    (*env)->ReleaseIntArrayElements(env, arr, body, 0); // 釋放,模式 0 表示複製回 Java 陣列
    return sum;
}

獲取/釋放元素指針對應表

陣列類型Get 函數Release 函數
boolean[]GetBooleanArrayElementsReleaseBooleanArrayElements
byte[]GetByteArrayElementsReleaseByteArrayElements
char[]GetCharArrayElementsReleaseCharArrayElements
short[]GetShortArrayElementsReleaseShortArrayElements
int[]GetIntArrayElementsReleaseIntArrayElements
long[]GetLongArrayElementsReleaseLongArrayElements
float[]GetFloatArrayElementsReleaseFloatArrayElements
double[]GetDoubleArrayElementsReleaseDoubleArrayElements

物件陣列(Object[])

無法一次性獲取所有元素,需逐個存取:

  • GetObjectArrayElement(env, arr, index) → 返回 jobject
  • SetObjectArrayElement(env, arr, index, val) → 更新元素

7. 調用 Java 方法

三步驟流程

  1. 獲取類別引用: jclass cls = (*env)->GetObjectClass(env, obj);
  2. 獲取方法 ID: jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "(I)V");
  3. 調用方法: (*env)->CallVoidMethod(env, obj, mid, depth);

方法簽名規則

格式:(參數類型簽名)返回類型簽名

Java 類型簽名字符
booleanZ
byteB
charC
shortS
intI
longJ
floatF
doubleD
類別 Lpkg/Cls;Lpkg/Cls;
陣列 [type[I 等

範例:void callback(int depth) → (I)V;String toString() → ()Ljava/lang/String;

獲取簽名神器:javap -s -p ClassName

調用函數家族

返回類型一般調用可變參數陣列參數
voidCallVoidMethodCallVoidMethodVCallVoidMethodA
booleanCallBooleanMethodCallBooleanMethodVCallBooleanMethodA
intCallIntMethodCallIntMethodVCallIntMethodA
... 其他基本類型同理
物件CallObjectMethodCallObjectMethodVCallObjectMethodA

靜態方法調用

將 GetMethodID → GetStaticMethodID,Call*Method → CallStatic*Method。

8. 存取 Java 欄位

與方法調用類比,將 Method 替換為 Field:

  • GetFieldID / GetStaticFieldID
  • GetIntField、SetIntField 等類型專用 Get/Set
  • GetObjectField / SetObjectField 處理引用類型

總結

JNI 核心在於:類型映射精確、資源獲取與釋放配對、簽名正確、引用管理規範。掌握字串、陣列、方法、欄位四大操作族群,即可應對絕大多數 Java-C/C++ 互操作場景。建議搭配 javah(JDK 8 前)或 javac -h(JDK 8+)自動生成頭文件,減少手寫錯誤。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved