1、JNI介绍
JNI是Java Native Interface的英文缩写,意为Java本地接口。为了方便Java调用c、c++等本地代码所封装的一层接口。Java的优点是跨平台,但是作为优点的同时,其在本地交互的时候编程就有了缺点,Java的跨平台特性导致其本地交互的能力不够强大,一些和操作系统相关的特性Java无法完成(Java编写底层的应用较难实现),于是Java提供了JNI专门用于和本地代码交互(C/C++开发任何和系统相关的程序和类库),这样就增强了Java语言的本地交互能力。
2、Java通过JNI调用C代码
先学习一个最简单的例子HelloWorld!
最简单的Java通过JNI调用C代码的步骤:
1、在Java类中声明一个native的方法
2、使用Javah命令生成包含native方法声明的C头文件
3、按照生成的C/C++头文件来写C源文件
4、将C源文件编译成动态连接库(dll/SO)
5、把dll/so文件加入PATH环境变量下
6、Java类中加载so或dll,然后调用声明的native方法。
第一步:在Java类中声明一个native的方法
Java代码:TestJni.java
package com.hutest;
public class TestJni {
public native String sayHello(String text); //调用C接口
public static void main(String[] args){
System.loadLibrary("TestJni");
TestJni tj=new TestJni();
String result=tj.sayHello("Hello World!");
System.out.println(result);
}
}
第二步,使用Javah命令生成包含native方法声明的C头文件
1、 编译TestJni .java文件
javac com/hutest/TestJni.java
2、生成TestJni .h文件(com_hutest_TestJni.h)
javah com.hutest.TestJni
生成的头文件:com_hutest_TestJni.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_hutest_TestJni */
#ifndef _Included_com_hutest_TestJni
#define _Included_com_hutest_TestJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_hutest_TestJni
* Method: sayHello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_hutest_TestJni_sayHello
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
第三步,按照生成的C头文件来写C源文件
C代码:TestJni.c
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "com_hutest_TestJni.h"
#include "string.h"
JNIEXPORT jstring JNICALL Java_com_hutest_TestJni_sayHello
(JNIEnv *env, jobject obj, jstring string){
return string;
}
第4步,将C源文件编译成动态连接库(dll/SO)
这里是在linux环境下,所以是编译成.so文件
#编译
$gcc -I /home/cg/java_all/java64/jdk1.8.0_221/include -I /home/cg/java_all/java64/jdk1.8.0_221/include/linux TestJni.c -fPIC -shared -o libTestJni.so
$gcc -I /home/cg/java_all/java64/jdk1.8.0_221/include -I /home/cg/java_all/java64/jdk1.8.0_221/include/linux TestJni.c -fPIC -shared -o libTestJni.so
第五步,把dll/so文件的目录加入PATH环境变量下
export LD_LIBRARY_PATH=/opt/jnitest:$ LD_LIBRARY_PATH
第六步,Java类中加载so或dll,然后调用声明的native方法。
Linux环境下加载so,运行结果如下:
[root@loaclhost jnitest]# java com.hutest.TestJni
Hello World!
备注:其中的一些疑问和回答。
jni的步骤是先写.java文件定义Nactive方法,然后javac生成class,然后javah生成对应c的头文件,再通过生成的c头文件里定义的函数名写具体实现,然后编译成dll或so
问:如果是两个人写,那么定义好方法和规范,然后Java开发写好.java的Nactive方法,生成class给和生成c头文件给C开发?
答:对,先把nactive定义好了把java文件提供一份
后续新增可以不用提供,复制已经生成好的,改下最后的函数名和参数就行了
大概了解了,看来想真的弄懂得自己弄个小的demo才行。
编译和执行
参考:https://www.jb51.net/article/92121.htm
https://www.jb51.net/article/92121.htm
https://blog.csdn.net/weixin_33246767/article/details/114254282
https://www.runoob.com/w3cnote/jni-getting-started-tutorials.html