Java如何利用JNI调用C++(简略介绍及步骤)
文章目录
- Java如何利用JNI调用C++(简略介绍及步骤)
- 一、原理介绍
- 二、详细步骤
- 步骤一:编写Java类
- 步骤二:生成.h文件
- 步骤三:CLion软件设置
- 一、新建项目
- 二、拷贝.h文件
- 三、复制include文件夹
- 四、配置CMakeLists.txt
- 五、方法(函数)程序实现
- 六、编译library.cpp
- 步骤四:编译与运行
使用软件:
Java IDE:Jetbrain Intellij IDEA 2022.2
C++ IDE: Jetbrain CLion 2022.2.3
一、原理介绍
1、JNI是Java Native Interface的缩写,通过使用Java本地接口书写程序,可以确保代码在不同的平台上方便移植。 从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他编程语言,只要调用约定受支持就可以了。值得一提的是,JNI只是Java对外的一份说明书,告诉外界如何与Java交流,并不能用JNI去约束Java去遵守其他语言的规范。
2、要清楚Java如何从C++那里获取到需要的方法(函数),首先C++需要知道所编写Java程序对应JNI规范,然后在自己程序中遵循这个规范(JNI),才能跟随Java来实现自身的方法(函数)。
3、Java和C++毕竟是两个世界的人(虽然Java是用C++语言写的底层),尽管JNI是所有语言都知道的规范,但是C++还是无法知道Java需要它自己做什么。所以Java若想要C++帮忙,首先将自身的方法(也就是我们都知道的.java文件)交给Java虚拟机(Java Virtual Machine,JVM),JVM生成一份.class文件,这是一份二进制文件,也就是Java的机器语言,可以让其他所有的程序语言都可以获取到Java的程序内容,但还是没有办法直接读取。所以想要C++能读懂Java的意思,我们需要将Java生成一份C++能看懂的文件(也就是.h后缀文件),C++拿到这份文件后,就可以理解到了Java的意思,当作规范来使用,就能实现Java的意图了。
4、C++在自己世界里实现了Java所需要的方法(函数)之后,由于是.cpp,这时Java又看不懂了,C++没办法写出.class文件。这时候就需要一个神器来帮忙了,就是动态链接库(Dynamic Link Library,DLL),DLL想办法将C++实现的方法(函数)存到了文件(.dll)中,Java本身的变量环境中就有这个文件,所以导出的.dll文件放到Java本身环境中,Java就能够使用DLL,也就使用了C++的方法。
二、详细步骤
本次操作是根据网上资料各种参考而得,但由于实践的时候出现多次错误,所以内容也与其他帖子略有不同,对程序的名字也有改动,将在文章最后给出参考资料及原文链接,感谢互联网上每一位无私分享的作者! 如有侵权,请私信或留言,我立即删除相关内容!
步骤一:编写Java类
首先建立一个Java接口,附带一个native类型的接口,接口命名为sayHello(如下方代码所示),其中native是JNI标准的关键字,表示此方法是由外部其他语言实现的,此处只能起一个声明作用。自定义sayHello的方法,用来供C++语言实现。
public class HelloCpp {
static {
System.loadLibrary("libhello");
}
public native void sayHelloCpp();
public static void main(String[] args) {
new HelloCpp().sayHelloCpp();
}
}
① 静态代码块,可以引入dll文件 ② 这里为声明,不是实现 也就是前面说的native是一个声明作用 ③native关键字是对外部实现接口的声明
- 新建目录
jni
,用于存储生成的头文件,也可以不建,待会快捷工具可以自动生成。 - 新建目录
lib
,用于存放C/C++编译的动态库文件。后续有大用!!
步骤二:生成.h文件
在此之前,我们可以添加一个快捷工具生成 .h 头文件,在Settings→Tools→External Tools中新建,Name和Description随意填写,但Name会在下面用到。重要的是下面三个:
· Program内容 $JDK $ /bin/javah
· Arguments内容 -classpath OutputPath -d ./jni $FileClass $
· Working directory内容 $ProjectFileDir $
在完成工具建立后,我们对程序进行build Project ,然后我们在类HelloCpp上点击鼠标右键External Tools
–GenerateHeader
生成头文件,就可以在jni目录就生成`HelloCpp.h的文件了
步骤三:CLion软件设置
一、新建项目
在CLion同样新建项目,命名为hello
,Language standard随意选择,Library type选择shared
在Settings–Build, Execution, Deployment–CMake中将Build directory修改为build/debug,同样添加Release并进行类似的设置。
二、拷贝.h文件
在项目下建立一个文件夹jni,将HelloCpp.h拷贝到jni文件夹下(也可以将java项目下的jni文件夹直接复制到这个项目下)
HelloCpp.h内容如图所示
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus}
#endif //此处兼容c语言
JNIEXPORT void JNICALL Java_HelloCpp_sayHelloCpp
(JNIEnv *, jobject);// 转换的Java接口函数
三、复制include文件夹
将Java目录下的include文件夹复制到了当前项目的文件夹下,include文件夹可以在java的安装目录中寻找,我的include文件夹在java安装目录中
(也可以只将jni.h、jni_md.h等文件复制过来,此处只是为了方便,视个人情况而定)
四、配置CMakeLists.txt
include_directories 为可以包含的文件路径,这样就可以只用写#include “jni.h”,而不是#include “include\jni.h”
五、方法(函数)程序实现
拷贝HelloCpp.h中 JNIEXPORT void JNICALL Java_HelloCpp_sayHelloCpp (JNIEnv *, jobject);也就是Java的接口函数到.cpp中
#include "HelloCpp.h"
#include "jni.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_HelloCpp_sayHelloCpp
(JNIEnv *, jobject){
printf("Hello JNI!\n");
} //本处实现为:输出Hello JNI!
六、编译library.cpp
Build Project 这个项目,即可生成相应的dll文件,由前面设置可知在build\debug 下即可找到libhello.dll (lib+hello)
此时,Clion的工作已经完成。
步骤四:编译与运行
复制上面生成的libhello.dll文件到IntelliJ IDEA下的lib目录(前面新建的一个文件夹)
在编辑运行配置,选择右上角的Modify options
–Add VM options
,添加-Djava.library.path=$ProjectFileDir$/lib
最后运行Java项目,会打印Hello JNI。基本上利用Java调用C++基本操作已经全部完成。
后面更新native接口进需要重新生成头文件,并将jni目录复制到CLion中。
如果只是更新native的实现,需要将动态库从CLion项目中复制到IntelliJ IDEA中。
参考资料:
一、 枫竹梦 使用IntelliJ IDEA和CLion开发JNI环境搭建 原文链接:
二、 KITE Java调用C++的步骤和一些自己的见解(详细款式)