当前位置:网站首页 > Java基础 > 正文

java调用dll动态库代码(java如何调用dll库)



大家好,我是不会java的java废材生。某一天突然接到个小需求,要求用c++写一个函数并用java来调用,而且特地强调不允许通过网络请求的方式调用(当然作者比较废也不会写c++的服务接口),这就需要本地调用ddl动态链接库来实现了。作者以前没有做过类似是场景,不过java有性能瓶颈,所以一些偏复杂的功能可能就是用其他性能较好的语言来实现的(比如c、c++等)再在java里面调用那些实现好的功能,以下是作者做的案例并踩的一些坑,希望能帮助到大家。

我们在实现类似上面需求之前,要大致了解一下什么是ddl。

ddl是一种文件的类型,在Windows开启文件后缀名展示的话能看到它是应用程序扩展文件,标准点叫动态链接库文件(Dynamic Link Library)。在Linux上,动态链接库的文件后缀为.so(有兴趣的朋友可以自行搜索)。

dll文件是实现资源共享的一种方式,本质就是编译好的机器指令文件,直接打开就会看到一些乱码;动态是指只有在程序运行时才会去调用某个ddl,因此ddl性能开销就会小很多(静态链接的性能开销会大不少,具体有兴趣也可以百度)。

在生成dll之前,需要注意设置好编译环境,clion工具只提供了cmake项目构建工具。编译器的话一般选择用MinGW,MinGW要和jdk位数一样,64位的jdk对应64位的MinGW,MinGW下载链接。

设置->构建、执行、部署->工具链,按照下图配置好确定即可。

1.png

选择c++库,按下图勾选即可

2.png

其实选择可执行文件那个也是可以的,但我们简单打印个helloworld不需要执行测试。项目创建成功后会默认生成一个library.cpp文件和library.h文件。

1.代码编写

使用 __declspec(dllexport)标识符

新建一个cpp文件,直接在函数前面加上这个标识符就可以,该关键字可以将该函数标识为要导出的函数,如下面void hello()函数

 

注意事项:这种方式导出函数得到ddl之后,导出的函数名会改变,在编译链接的时候,c++会按照自己的规则篡改函数名称。

解决方式:在定义导出函数时加上extern"C"限定符

可以这样

 

也可以这样将多个要导出了函数放一个块里

 

完整代码附图如下

3.png

2.配置CMakeList.txt文件

在编写完上面代码之后就可以去生成dll文件了。

找到项目根目录下的CMakeList.txt配置文件(创建项目的话会默认生成),加入如下内容

 

因为创建的是c++库项目,所以配置里有add_library,如果是创建的是c++可执行文件的项目就要自己手动加入。

dlltest就是生成的dll文件名称,mytest.cpp就要导出为dll的代码源文件

配置好之后如下图

4.png

3.构建项目生成dll文件

点击最上方那栏构建->构建项目

项目构建成功之后会在cmake-build-debug目录下生成dll文件,不过默认加上了lib的前缀。

5.png

将这个dll文件复制到程序可以访问到的地方就可以调用那个void hello()函数了,如果访问不到会报错文件找不到。

注意:这一种方式少一些流程,但依然存在问题,只能解决c和c++之间调用函数命名的问题,生成了dll给java调用的时候就会报错java.lang.UnsatisfiedLinkError,想用java调用就用方式二吧。

了解java调用dll常见的三种方法

java调用dll常用有三种方法,分别是用jni、jna和jnative。

jni是jdk自带的,性能最好(推荐),其他两种是基于jni的封装。

本文使用jni的方法来调用。

了解java中native关键字

它用于声明一个方法是由本地代码实现的,也就是说这个方法的实现并不是用 java 编写的,而是使用其他语言(比如 c/c++)编写的,并通过jni调用。

如果希望在 java 中调用dll中的函数,并且不希望函数名被改变,你可以使用 native 关键字声明一个本地方法,并在本地代码中实现这个方法。

1.在java中创建一个类声明native方法

 

2.生成native方法对应的c++头文件

该头文件的作用是定义c++能够识别的java中方法对应的c++函数。

生成头文件需要用到命令,不同版本jdk所需命令不一样。

jdk1.8版本

javah命令,在MylibTest.java所在的目录下执行命令。

1.8版本以上

方式一

这个地方有坑,网上查的时候说是java8之后的版本用javac -h命令(但没补充,作者一执行就报错),这个命令是没问题但是如上面命令一样直接执行就会出问题。

我们能看到下面执行报错说无源文件。

6.png

那怎么解决能,指定一个输出源目录就可以了

-h 指定头文件的输出目录,.代表当前目录,test则是在当前目录下生成一个test目录

执行之后就会在MylibTest.java所在目录生成一个test目录

执行成功

7.png

生成test目录

8.png

test目录下会有一个头文件。

方式二

在与方式一同样的目录位置执行如下命令,encoding指定编码为uft8

 

作者jdk17这两种命令都用过了,实测没问题。

3.将生成的头文件引入c++项目

之前创建好了c++项目这里就不再创建了。

将生成的头文件复制粘贴到项目跟目录,生成的头文件里面用到了jni.h和jni_md.h头文件(jni.h和jni_md.h头文件在jdk目录下的include目录里面,找一找很快就能找到),也一并复制粘贴过来。

9.png

生成的头文件类容如下

 

4.在当前目录新建一个cpp文件并实现函数

新建的cpp需要引入生成的头文件和jni.h头文件,并实现生成头文件里面的函数

 

5.配置CMakeList.txt

在里面的add_library添加cpp和引用到生成的那个头文件(同前面的一样)

 

6.构建生成dll

原理同方式一提到的一样。

7.将生成的dll直接粘贴到jdk的bin目录下

bin目录是java在加载库时最优先访问的目录。

8.编写java测试类

 

9.运行测试

可以看到测试成功

10.png

在第一次弄的时候,踩了不少坑,弄了一个下午没弄出来(可能是作者比较菜的原因)。作者没有因此而放弃,查了诸多文章之后给实现出来了,总的来说多试试、多看看文章、多看看书,总会有收获的。

到此这篇java调用dll动态库代码(java如何调用dll库)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • jvm内存结构面试题(javajvm内存结构)2025-02-14 18:00:10
  • java练习网站(java做题网站)2025-02-14 18:00:10
  • Java字符串转数组(java字符串转数组注解)2025-02-14 18:00:10
  • java自学app(Java自学视频)2025-02-14 18:00:10
  • java内存模型jmm(Java内存模型怎么理解)2025-02-14 18:00:10
  • java内存模型jmm(Java内存模型包含什么)2025-02-14 18:00:10
  • java面试题基础部分(java面试题基础题)2025-02-14 18:00:10
  • java爬虫与python爬虫的区别(java爬虫和python爬虫区别)2025-02-14 18:00:10
  • java的网站(java相关网站包括)2025-02-14 18:00:10
  • Java字符串转时间(java字符串转成时间)2025-02-14 18:00:10
  • 全屏图片