- 1 JNI是什么
- 2 如何在JAVA中调用C/C++方法(通过JNI调用的demo)
- java中声明一个本地native方法
- 生成JNI头文件
- Java native方法转换成C的规则与语法说明
- C实现的native方法本地实现以及.o .dll库的生成
- 查看hello.dll库中的函数
- 运行一下HelloJNI
- JNI在DDS移植android平台的作用
1 JNI是什么
总结几点重要的如下:
- JNI是用来实现java代码和本地native方法(比如一些C C++实现的代码)之间交互的一种框架,同时也是java标准里面的一部分,是Java平台定义的规范接口;
private native void native_init();
private native void native_sub(int domainID);
点击这些native方法进行跳转,可以看到native方法的实现是C++代码所完成,即native方法的实现;
- 为了更好的与操作系统级别以及硬件级别交互,并且为了完成某些计算密集型的任务,很多本地代码都是通过C、C++来实现的,这要比纯java代码高效一些。然后java代码JNI与这些底层代码进行交互;
- java代码通过JNI来调用本地方法(本地方法就是关键字为native的java方法,并且不能有方法体), 所以JNI也是一个桥梁;也可以说通过JNI可以将C/C++代码集成在Java中;
- 使用native关键字将某方法声明为本地实例方法,这就很明显地告诉JVM:这个方法实现在另外一个语言中(C/C++),请去那里寻找他的实现
2 如何在JAVA中调用C/C++方法(通过JNI调用的demo)
整体的调用逻辑就在这张图上面
1、创建一个java源码,并且里面声明一个native关键字修饰的本地方法,该方法没有方法体;
2、通过javah工具,或者javac -h 产生JNI的.h头文件,过程中会同时产生.class文件。产生JNI头文件所需要的官方jni.h和jni_md.h都在JDK11 的安装包里面;
3、然后实现一个.c文件,这个.c文件就是真正要干的事情,而且JNI头文件和.c之间是有一定的对应关系的。
4、然后将.c文件通过gcc生成win下的共享库.dll
5、运行java。通过javac产生.class字节码文件,然后通过java XXX的命令运行起来。这时候java虚拟机会去通过System.loadLibrary调用共享库,找到native方法的C实现的代码,执行里面的流程
注意:javah到.h这一步,可能通过javac -h . XXX.java替代
🐵下面通过例子来描述:
java中声明一个本地native方法
java当中有个很重要的点,一个源文件中可以有多个类,但是只有一个public类。而且源文件的名称必须与public类的名称相同;
package org.example;
public class HelloJNI {
static {
System.loadLibrary("hello");
}
private native void sayHello();
public static void main(String[] args) {
new HelloJNI().sayHello();
}
}
生成JNI头文件
在终端javac -h . D:\IDC\Android\testJNI\src\main\java\org\example\HelloJNI.java
告诉 javac 编译器生成一个 C/C++ 头文件(JNI 头文件),以便与本地代码(如 C 或 C++)交互。javac XX.java是产生java的中间文件
请注意这里我写的java文件的绝对路径,后面会解释,接着往后走
1、 javac:Java 编译器,用于编译 Java 源文件。
2、-h .:-h 选项告诉 javac 生成一个 JNI 头文件,. 表示将头文件放置在当前目录下。
3、HelloJNI.java:指定要编译的 Java 源文件。
生成头文件可以通过javac -h <dir> XX.java
,也可以通过javah -d
的方式,javac -h
和 javah
都可以用于生成 JNI 头文件,但 javac -h
更倾向于在编译 Java 源文件的过程中生成头文件,而 javah
是一个独立的工具,主要用于生成头文件
如下图所示,生成了头文件org_example_HelloJNI.h
Java native方法转换成C的规则与语法说明
上面的生成函数中,可以看到JNI中生成的C函数是:Java_org_example_HelloJNI_sayHello (JNIEnv *, jobject);
- JNIEnv *:指向JNI运行环境的指针,可通过这个指针访问JNI函数
- jobject:java中的this对象
- extern “C” : 告诉编译器,这是C函数;
所以其规则是:Java_{package_and_classname}_{function_name}(JNI arguments),Java_包名_类名_native方法名
C实现的native方法本地实现以及.o .dll库的生成
HelloJNI.c代码如下,打印一行字符即可。
#include <jni.h>
#include <stdio.h>
//#include "HelloJNI.h"
// Implementation of native method sayHello() of HelloJNI class
JNIEXPORT void JNICALL Java_org_example_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {
printf("Hello World!\n");
return;
}
通过JDK编译HelloJNI.c文件产生.o 文件
gcc -c -I "D:\JDK11\include" -I "D:\JDK11\include\win32" HelloJNI.c
其中jni.h文件分别在JAVA_HOME下的include和include\win32下面
然后通过JDK编译HelloJNI.c文件产生.dll文件
注意不要在终端里面操作,powershell会认为某些参数不对
直接在黑窗口操作就不会报错
如下图所示
三种文件分别是:.C是源文件;.o是中间文件,还没有被链接成可执行文件或者库文件;.dll是win下的动态链接库;
查看hello.dll库中的函数
如果是在linux上面的话使用:nm hello.dll | grep say
如果是在win环境编的,在黑窗口中用:objdump -t hello.dll | findstr /R /C:"say"
运行一下HelloJNI
打印的hello,world
请注意,如果我们想要通过JDK编译java产生.class文件后运行的话,必须后面跟着绝对路径,这里报错了好久,先这么记下。
JNI在DDS移植android平台的作用
持续更新…
【参考文献】
JNI基础知识总结
Java——本地方法(JNI)详解
Java Native Interface(JNI)从零开始详细教程