编程环境
操作系统:Windows 10 版本1809
Java:“11.0.2” 2019-01-15 LTS
GCC:5.1.0 (tdm64-1)
代码编辑器:Sublime Text 3
命令行工具:Git bash
字符编码:UTF-8
一、认识JNI
JNI,全程为Java Native Interface(Java本地接口),是Java语言的本地编程接口,用以对接其他编程语言,如C语言,CUDA C等。在java程序中,我们可以通过JNI实现一些用java语言不便实现的功能,如下:
1)标准的java类库没有提供你的应用程序所需要的功能,通常这些功能是平台相关的(只能由其他语言编写)。
2)你希望使用一些已经有的类库或者应用程序,而他们并非用java语言编写的。
3)程序的某些部分对速度要求比较苛刻,你选择用汇编或者c语言来实现并在java语言中调用他们。
4)为了应用的安全性,会将一些复杂的逻辑和算法通过本地代码(C或C++)来实现,本地代码比字节码难以破解。
二、JNI编程模型
1.实现步骤:
1)在Java类中声明一个native方法,该方法的方法实体将会在.c文件中实现;
2)运行javac得到Java类的字节码文件.class,也即下图中的操作1;
3)运行javac -h 得到一个native方法需要的.h头文件,也即下图中的操作2;
4)编写该native方法的实体在.c文件中,并通过.h头文件和.c源文件生成.dll动态编译库;
5)将动态编译库加载到java.library.path中,运行JVM即可。
详细实现过程及代码解释见下一节。
2. 详细实现
1)编写.java文件,并编译生成相应文件
public class Hello
{
static
{
System.load(System.getProperty("user.dir")+"//sayHello.dll");//用于添加sayhello.dll
}
public static native void sayHello();
public static native int Add(int a, int b);
@SuppressWarnings("static-access")
public static void main(String[] args)
{
new Hello().sayHello();//调用C语言中的sayHello()方法
System.out.println(new Hello().Add(2,3));//调用C语言中的sayHello()方法);
}
}
接下来需要通过命令行输入:
“javac Hello.java” 用以生成 Hello.class文件
“javac -h ./ Hello.java” 用以生成Hello.h文件,其中./表示生成在当前路径下
2)根据Hello.h中的函数声明提示,编写函数实体
hello.h文件内容如下所示:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Hello */
#ifndef _Included_Hello
#define _Included_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Hello
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Hello_sayHello
(JNIEnv *, jclass);
/*
* Class: Hello
* Method: Add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_Hello_Add
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
关注到其中
这就是我们需要用到的函数声明头部,接下来编写函数实体如下:
#include "Hello.h"//包含javac -h生成的头文件
#include <stdio.h>
JNIEXPORT void JNICALL Java_Hello_sayHello(JNIEnv *env, jclass jc)
{
printf("Hello,JNI");
}
JNIEXPORT jint JNICALL Java_Hello_Add(JNIEnv *env, jclass jc, jint a, jint b)
{
return a+b;
}
3)生成动态编译库文件
通过以下指令,生成sayHello.dll文件(这里源文件与函数同名,不建议这么做):
gcc -m64 -Wl,--add-stdcall-alias -I"C:\Program Files\Java\jdk-11.0.2\include" -I"C:\Program Files\Java\jdk-11.0.2\include\win32" -shared -o sayHello.dll sayHello.c
4)运行Hello.class文件
三、相关文章
完整工程Github:
https://github.com/ZhangPHinNEU/Demo_JNI
JNI介绍:
https://www.cnblogs.com/zh1164/p/6283831.html
Java.library.path(这部分在代码中未具体实现,后续再继续学习):
https://fahdshariff.blogspot.com/2011/08/changing-java-library-path-at-runtime.html
https://blog.csdn.net/u013517229/article/details/79530140
https://www.cnblogs.com/ylz8401/p/9605498.html
https://blog.csdn.net/cruise_h/article/details/41575481
https://www.cnblogs.com/minteliu/p/5829061.html
静态编译与动态编译:
https://blog.csdn.net/andrewniu/article/details/76443348
https://www.cnblogs.com/king-lps/p/7757919.html
JNI与CUDA :
https://blog.csdn.net/lllzzh123321/article/details/53520815
http://blog.sina.com.cn/s/blog_e05bc2770102y29r.html