[英]How method Identified in JNI?
在開發過程中,由於錯誤,我錯過了在函數中添加參數的機會。 但是本地jni調用中的相同函數具有參數。 但是它仍然從Java調用精確方法。
Java類Demo.java 。
package jniexamples.rmi;
class Demo {
private native void jBoolean();
public static void main(String[] args) {
new Demo().jBoolean();
}
static {
System.load("jnidemo.so");
}
}
Demo.c
#include <jni.h>
#include <stdio.h>
JNIEXPORT void JNICALL
Java_jniexamples_rmi_Demo_jBoolean(JNIEnv *env, jobject ob,jint dtype)
{
printf("first demo %d" , dtype);
return;
}
結果:第一次演示-1579007728
即使方法簽名不同,我也很困惑,它如何調用jni方法?
C函數僅在鏈接期間和運行時通過名稱標識,因此Java將調用該函數,但不提供任何參數。
如果在調用C函數時提供的參數太少,則會調用未定義的行為,這意味着可能發生任何事情。 (在您的情況下,您獲得了看似隨機的值。)
用javah生成的頭文件,它將具有正確簽名的函數聲明。 如果包含生成的標頭,則編譯器可以將標頭中的簽名與.c
文件中的簽名進行比較,如果它們不同,則在編譯時會發出錯誤。
非常簡短的場景將以另一種方式出現。 從Java調用jBoolean()
時,JVM會注意到此方法是本地方法,並嘗試查找其實現。 在您的情況下,JVM通過用類和包名稱修飾jBoolean
構造本機函數的名稱。 結果是字符串Java_jniexamples_rmi_Demo_jBoolean
。 然后,它嘗試使用dlsym()
在進程的地址空間中找到具有該名稱的函數。 因此,在嘗試調用此功能之前,使用此功能加載本機模塊至關重要。 然后,如果可以的話dlsym()
返回該函數的指針,但是請注意,該指針沒有有關實際函數簽名的信息,並且JVM僅使用Java中聲明的一個來推斷本機簽名。 然后,JVM根據推斷出的簽名調用您的本機函數。
結果-推斷的簽名與實際簽名之間的差異會導致未定義的行為,這可能會導致非常奇怪的事情,不僅會導致隨機參數值。 因此,這是一個好習慣-將javah
生成的標頭包含在本機實現中。 如果您的實現之一具有與標頭中聲明的簽名不同的簽名,則此類標頭會使編譯出錯並出錯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.