Java 如何在JNI中识别方法?

Java 如何在JNI中识别方法?,java,c,java-native-interface,Java,C,Java Native Interface,在开发过程中,由于错误,我错过了在函数中添加参数。但本机jni调用中的相同函数具有参数。但它仍然在从java调用精确的方法 Java类Demo.Java package jniexamples.rmi; class Demo { private native void jBoolean(); public static void main(String[] args) { new Demo().jBoolean(); } static {

在开发过程中,由于错误,我错过了在函数中添加参数。但本机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;
}
#包括
#包括
JNIEXPORT void JNICALL
Java_jnieExamples_rmi_Demo_jBoolean(JNIEnv*env,jobject-ob,jint-dtype)
{
printf(“第一次演示%d”,数据类型);
返回;
}
结果:第一次演示-1579007728


即使方法签名不同,我也很困惑,它是如何调用jni方法的?

C函数仅在链接和运行时通过名称进行标识,因此Java将调用该函数,但不提供任何参数

如果在调用C函数时提供的参数太少,则会调用未定义的行为,这意味着可能会发生任何事情。(在您的例子中,您得到了一个看似随机的值。)


javah生成的头文件将具有具有正确签名的函数声明。如果包含生成的头,编译器可以将头中的签名与
.c
文件中的签名进行比较,如果两者不同,则编译时将发出错误。

非常简短的场景将在下一步中显示。当您从java调用
jBoolean()
时,JVM注意到这个方法是本机的,并试图找到它的实现。在您的例子中,JVM通过用类和包名修饰
jBoolean
来构造本机函数的名称。结果是字符串
Java\u jniexamples\u rmi\u Demo\u jBoolean
。然后,它尝试使用
dlsym()
在进程的地址空间中查找具有此名称的函数。因此,在尝试调用本机模块之前,使用此函数加载本机模块是至关重要的。然后,如果可以-
dlsym()
返回指向函数的指针,但请注意,此指针没有关于实际函数签名的信息,JVM仅使用java中声明的一个签名推断出本机签名。然后JVM根据推断出的签名调用本机函数


结果-推断签名和实际签名之间的差异导致未定义的行为,这可能导致非常奇怪的事情,而不仅仅是随机参数值。因此,将
javah
生成的头包含到本机实现中是一种很好的做法。如果您的一个实现的签名与header中声明的签名不同,则此header会导致编译中断,并出现错误。

看起来您只是在为缺少的参数获取未定义的值。该方法由其名称标识。您需要确保签名匹配.IIRR,您应该包括由javah生成的.h头文件,以确保您具有正确的函数原型。如果我有两个方法,并且具有相同的名称但参数不同,那么没有头将是有问题的。@Nilesh没有其他正确的方法可以做到这一点。JVM和
javah
分享了Java本机方法签名如何映射到C的确切知识。
javah
将生成正确的头文件,由您来确保.C文件与之一致。谢谢,我是Jni和C的新手。但在这种情况下,头文件将如何帮助?@Nilesh生成的头文件将具有具有正确签名的函数声明。如果包含生成的头,编译器可以将头中的签名与.c文件中的签名进行比较,如果它们不同,则编译时将发出错误。感谢Serhio,我清楚了JVM如何将java函数映射到本机函数,以及如何使用头文件