ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# Java本地方法调用 ## 引子 ~~~ Class.forName("com.msql.jdbc.Driver"); ~~~ 我们在加载`mysql`的`jdbc`驱动时,会主动加载对应的驱动类,然后使用`DriverManager`来获取连接操作数据库。 跟进`forName`的实现会发现是调用的`native`方法来实现的,也就是`JNI(java native interface)`Java本地接口。 ~~~ /** Called after security check for system loader access checks have been made. */ private static native Class<?> forName0(String name, boolean initialize, ClassLoader loader, Class<?> caller) throws ClassNotFoundException; ~~~ 其中有native关键字修饰的,则是Java定义的本地接口,使用C或者C++共享库DLL(操作系统不同后缀不同)实现。 ![](https://img.kancloud.cn/ca/0d/ca0d1187fd0fae28dc3e7dd26dd4459e_348x230.png) 如下是Java和C的类型对应图。 ![](https://img.kancloud.cn/af/04/af040d690013f2150f8e2cfab960be84_1590x692.png) ## 简单案例入门 ### 步骤 1. 编写Java类,定义本地方法 ~~~ public class NativeTest { /** * 加法 */ public static native int add(int a,int b); static { // 加载动态库 System.loadLibrary("c_dll"); } public static void main(String[] args) { // 调用本地方法 int sum = add(2,3); System.out.println(sum); } } ~~~ 2. 编译Java类,并生成c的头文件 ``` javah -classpath /Users/mango/git/java-study/demo-case/target/classes -d ./cdll org.mango.demo._case.native2.NativeTest ``` 得到头文件`org_mango_demo__case_native2_NativeTest.h` ~~~ /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class org_mango_demo__case_native2_NativeTest */ #ifndef _Included_org_mango_demo__case_native2_NativeTest #define _Included_org_mango_demo__case_native2_NativeTest #ifdef __cplusplus extern "C" { #endif /* * Class: org_mango_demo__case_native2_NativeTest * Method: add * Signature: (II)I */ JNIEXPORT jint JNICALL Java_org_mango_demo__1case_native2_NativeTest_add (JNIEnv *, jclass, jint, jint); #ifdef __cplusplus } #endif #endif ~~~ 3. 编写C语言实现本地方法 使用C的IDE工具CLion创建C语言的共享库工厂c-dll。 ![](https://img.kancloud.cn/df/8d/df8dec0805d4d6b5b927aca0e9bf5b1e_1600x1244.png) 创建.c源文件,引入头文件。 ![](https://img.kancloud.cn/fd/65/fd651110b7b9a2b30769974feb718481_2110x768.png) 其中需要将`jni.h`和`jni.md.h`也`copy`到同级目录,这2个文件在jdk里,如下图: ![](https://img.kancloud.cn/f2/23/f223d72b8f20f3474f72cd36ac8c2003_1556x1056.png) C语言实现add方法如下: ~~~ #include "org_mango_demo__case_native2_NativeTest.h" JNIEXPORT jint JNICALL Java_org_mango_demo__1case_native2_NativeTest_add (JNIEnv *env, jclass c, jint a, jint b){ printf("call native from c method\n"); printf("a=%d\nb=%d\n",a,b); return a+b; } ~~~ 4. 编译C语言程序得到共享库DLL文件 点击菜单build工程得到共享库文件 ![](https://img.kancloud.cn/14/6a/146a45a0308c3b947164a1eeae70d998_504x482.png) 在Mac上得到的是`libc_dll.dylib`的文件 ![](https://img.kancloud.cn/0f/24/0f24c08cf991de7797169dabfec46c0c_1610x478.png) 5. 链接加载DLL文件,在Java程序内调用本地方法 将动态库文件copy到java工程的resources下(classpath) ![](https://img.kancloud.cn/4b/cf/4bcf067c2ebf87cdc9e42cf42a4db07e_654x480.png) 代码里显示加载: ~~~ static { System.loadLibrary("c_dll"); } ~~~ 运行Java程序后,报错: ``` Exception in thread "main" java.lang.UnsatisfiedLinkError: no c_dll in java.library.path at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867) at java.lang.Runtime.loadLibrary0(Runtime.java:870) at java.lang.System.loadLibrary(System.java:1122) at org.mango.demo._case.native2.NativeTest.<clinit>(NativeTest.java:14) ``` 说明未配置动态库,如下图配置一下即可: ![](https://img.kancloud.cn/55/99/55992ce60d6931269ffb123ed118e020_2416x1230.png) 再次运行成功: ![](https://img.kancloud.cn/1a/d3/1ad3b5f88271a9157fcb3ec3dd5bdd87_2304x1336.png)