在JNI(Java Native Interface)中,如果要想使用一个别人提供好的.so文件(动态链接库),必须要知道知道源文件的 函数名,返回值类型,和传入参数的类型,
那么在Java文件中调用这些本地函数时,必须对Native方法进行声明,而且声明的文件必须确保Java中的类和方法签名与C/C++源文件中定义的完全一致。这包括包名、类名、方法名和参数类型。如果不匹配,Java虚拟机(JVM)将无法找到并调用正确的本地方法,导致程序抛出UnsatisfiedLinkError
。
也就是说整个工程的包名必须要和.so生成之前的源文件的包名保持一致
把函数声明完之后就可以新建实例进行调用函数进行使用了。
原理解释
JNI是一种机制,允许Java代码和其他语言(如C和C++)编写的代码进行交互。当Java代码调用一个本地方法时,JVM需要通过JNI找到对应的C/C++函数并调用它。这个过程涉及到几个关键步骤:
-
命名约定:
- JNI使用特定的命名约定来生成C/C++中函数的名称。这个名称由Java的包名、类名和方法名组合而成,它们通过下划线(_)连接,并且全部转换为小写。例如,如果Java中有如下方法:
java
那么JNI生成的C/C++函数名将是package com.example; public class MyClass { public native void myMethod(); }
Java_com_example_MyClass_myMethod
。
- JNI使用特定的命名约定来生成C/C++中函数的名称。这个名称由Java的包名、类名和方法名组合而成,它们通过下划线(_)连接,并且全部转换为小写。例如,如果Java中有如下方法:
-
加载库:
- 在Java代码中,使用
System.loadLibrary("libraryName")
来加载.so文件。这里的libraryName
是不带lib
前缀和.so
后缀的库名。
- 在Java代码中,使用
-
查找和调用函数:
- JVM使用JNI生成的函数名来查找.so文件中对应的C/C++函数。如果Java中的类或方法名与C/C++中的不匹配,JVM将无法找到正确的函数,导致调用失败。
-
数据类型映射:
- JNI还负责在Java和C/C++之间进行数据类型映射。例如,Java中的
int
对应C/C++中的jint
,String
对应jstring
等。
- JNI还负责在Java和C/C++之间进行数据类型映射。例如,Java中的
为什么需要匹配
-
唯一性:JNI生成的函数名是唯一的,它依赖于Java的包名、类名和方法名。这种唯一性确保了JVM可以准确地找到并调用正确的本地方法。
-
安全性:通过确保Java和C/C++之间的签名完全匹配,JNI可以防止类型不匹配和潜在的安全问题。
-
兼容性:这种机制确保了不同语言编写的代码可以无缝集成,同时保持代码的清晰和可维护性。
因此,为了成功调用.so文件中的本地方法,Java工程中的包名、类名和方法名必须与C/C++源文件中的定义完全一致。这是JNI工作方式的基本要求,也是确保Java和本地代码正确交互的关键。