JNI —— 使用Java调用C程序

现在有个需求,就是使用Java调用linux或者windows的系统API,或者需要C语言才能实现的本地方法,这时候就JNI就出场了。

下面看一个完整的例子:

准备工作:windows下安装mingw-64编译器 使用gcc命令编译

一、创建Java类文件

Main.java

public class Main {
    // 静态初始化代码块,保证虚拟机在第一次使用该类时就会装载库
    static{
        System.loadLibrary("MyNativeLib");
    }

    // native 关键字表示本地方法,提醒编译器该方法将在外部定义(注:不能包含_)
    public static native void sayHello();

    // 主函数调用本地方法
    public static void main(String[] args) {
        sayHello();
    }
}

二、生成.h头文件

> javac Main.java
> javah -classpath . -jni Main

使用上述命令生成的 Main.h 文件内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Main */

#ifndef _Included_Main
#define _Included_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Main
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_Main_sayHello
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

三、创建C实现文件

创建Main.c文件,实现头文件中的函数。

#include <stdio.h>
#include "Main.h"

JNIEXPORT void JNICALL Java_Main_sayHello(JNIEnv *env, jobject c1) {
	printf("Hello Native !!\n");
}

四、编译生成动态链接库

使用gcc的-I参数(大写i)指定需要需找头文件的目录。

或者,将JDK目录下的 include/jni.h 和 include/win32/jni_md.h 拷贝到当前工程的目录下来。

然后执行命令(在这之前需要将Main.h中的#include <jni.h>改成 #include "jni.h",先在当前目录搜素头文件,再到系统目录搜索)

> gcc -fPIC -shared -o MyNativeLib.dll Main.c

至此目录中已生成 MyNativeLib.dll 动态链接库文件,其他的C语言文件可以删除。

扫描二维码关注公众号,回复: 10867164 查看本文章

五、测试运行

> java Main

运行结果为:

常见问题:

  • java.lang.UnsatisfiedLinkError: 类名.函数名()V

此时动态库已经加载,检查.h文件和.c文件函数实现名字是否一致,且命名不能带有下划线_。

c文件中的函数名是有规则的 Java_Main_sayHello ,Java_类名_函数名。

  • no MyNativeLib in java.library.path at java.lang.ClassLoader.loadLibrary(Unknown Source)

如果是dll库都没有加载成功,看对应dll是否成功生成,编译命令是否正确和项目位置等。

  • 在linux环境编译和上述相同,动态库文件扩展名为.so

参考:

发布了19 篇原创文章 · 获赞 9 · 访问量 2996

猜你喜欢

转载自blog.csdn.net/Necrolic/article/details/105542898
今日推荐