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();
    }
}

Java onlyoffiice保存回调 jni java回调c+_Java

① 静态代码块,可以引入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 $

Java onlyoffiice保存回调 jni java回调c+_jvm_02

在完成工具建立后,我们对程序进行build Project ,然后我们在类HelloCpp上点击鼠标右键External ToolsGenerateHeader生成头文件,就可以在jni目录就生成`HelloCpp.h的文件了

Java onlyoffiice保存回调 jni java回调c+_jvm_03

步骤三:CLion软件设置
一、新建项目

在CLion同样新建项目,命名为hello,Language standard随意选择,Library type选择shared

Java onlyoffiice保存回调 jni java回调c+_java_04


在Settings–Build, Execution, Deployment–CMake中将Build directory修改为build/debug,同样添加Release并进行类似的设置。

Java onlyoffiice保存回调 jni java回调c+_c++_05


Java onlyoffiice保存回调 jni java回调c+_java_06

二、拷贝.h文件

在项目下建立一个文件夹jni,将HelloCpp.h拷贝到jni文件夹下(也可以将java项目下的jni文件夹直接复制到这个项目下)

Java onlyoffiice保存回调 jni java回调c+_CL_07

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安装目录中

Java onlyoffiice保存回调 jni java回调c+_c++_08


(也可以只将jni.h、jni_md.h等文件复制过来,此处只是为了方便,视个人情况而定)

四、配置CMakeLists.txt

Java onlyoffiice保存回调 jni java回调c+_c++_09

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)

Java onlyoffiice保存回调 jni java回调c+_jvm_10


此时,Clion的工作已经完成。

步骤四:编译与运行

复制上面生成的libhello.dll文件到IntelliJ IDEA下的lib目录(前面新建的一个文件夹)

在编辑运行配置,选择右上角的Modify optionsAdd VM options,添加-Djava.library.path=$ProjectFileDir$/lib

Java onlyoffiice保存回调 jni java回调c+_c++_11


最后运行Java项目,会打印Hello JNI。基本上利用Java调用C++基本操作已经全部完成。

Java onlyoffiice保存回调 jni java回调c+_c++_12


后面更新native接口进需要重新生成头文件,并将jni目录复制到CLion中。

如果只是更新native的实现,需要将动态库从CLion项目中复制到IntelliJ IDEA中。

考资料:

一、 枫竹梦 使用IntelliJ IDEA和CLion开发JNI环境搭建 原文链接:

二、 KITE Java调用C++的步骤和一些自己的见解(详细款式)