JNI(Java Native Interface, Java本地接口)编程指南

编程环境

操作系统: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即可。
详细实现过程及代码解释见下一节。
JNI(Java Native Interface, Java本地接口)编程指南_第1张图片

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文件
在这里插入图片描述JNI(Java Native Interface, Java本地接口)编程指南_第2张图片

“javac -h ./ Hello.java” 用以生成Hello.h文件,其中./表示生成在当前路径下
在这里插入图片描述JNI(Java Native Interface, Java本地接口)编程指南_第3张图片
2)根据Hello.h中的函数声明提示,编写函数实体
hello.h文件内容如下所示:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* 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

关注到其中

JNI(Java Native Interface, Java本地接口)编程指南_第4张图片
在这里插入图片描述
这就是我们需要用到的函数声明头部,接下来编写函数实体如下:

#include "Hello.h"//包含javac -h生成的头文件
#include 
 
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

JNI(Java Native Interface, Java本地接口)编程指南_第5张图片
4)运行Hello.class文件
JNI(Java Native Interface, Java本地接口)编程指南_第6张图片

三、相关文章

完整工程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

你可能感兴趣的:(JAVA,CUDA,C,Dev,C++)