Java调用C++知识分享

Java调用C++知识分享

Java调用C/C++代码,最原始的方式是使用JNI(Java Native Interface),但是使用JNI技术非常痛苦,因为你需要对照要调用的C/C++函数写一个“接口”,使用SUN规定的数据结构替代C/C++语言的数据结构,调用已有的 dll/so中公布的函数。然后再在Java中载入这个“接口”,调用dll/so库中的函数。面对如此繁琐的过程的,因此诞生出了建立在经典的JNI的基础之上的一个框架–JNA( Java Native Access)。
本文主要是通过举例的方式,从代码中来到代码中去的方法,讲述JNA的使用。本文中的方法在Windows平台下以及在Centos的Linux平台下都加以验证过。因此我也才放开胆子去写。٩(๑❛ᴗ❛๑)۶。
分享开始!

下边通过一个简单的例子,让你对JNA方式完成Java调用C++有一个简单清晰的认识。

第一步:首先在pom文件中加入JNA的依赖

    <dependency>
      <groupId>com.sun.jna</groupId>
      <artifactId>jna</artifactId>
      <version>3.0.9</version>
    </dependency>

第二步:编写Java方法(注意看注释的部分就行了0.0)

/**
 * Created by zhonghao.han on 9/12/2018.
 */
public class JnaTest {
  //继承Library,用于加载库文件
  public interface Clibrary extends Library{
    //windows下加载helloworld.dll链接库,Linux下加载libhelloworldLinux.so(Linux下会自动寻找lib开头的库)
    Clibrary INSTANTCE = (Clibrary) Native.loadLibrary((Platform.isWindows() ? "helloworld" : "helloworldLinux"), Clibrary.class);

    //此方法为链接库中的方法
    void test();
  }

  public static void main(String[] args) {
    //调用
    Clibrary.INSTANTCE.test();
  }
}

第三步:编写需要调用的C方法helloworld.c(C和C++都可以,都测试过0.0 这里是随手复制的一个C代码)

#include<stdio.h>
void test(){
printf("hello JNA!\n");
}
需要注意的是Native.loadLibrary第 一个参数是动态链接库dll/so的名称,但不带.dll或.so这样的后缀,这符合JNI的规范,因为带了后缀名就不可以跨操作系统平台了。

第四步:将C代码编译成dll(在Windos平台下C/C++一般都是编译成.dll,在Linux下一般是编译成.so).具体的编译这里就不再细说哈哈Alt text

上例用的是Windows的平台做的演示,Linux平台的一样。

注意:库文件的位置需要放置到项目的根路径下,否则Java调用库的时候会找不到这个库文件而报如下的错误

Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'helloworld': Native library (win32-x86-64/helloworld.dll) not found in resource path 
([file:/C:/hzh/SoftWares/jdk/jre/lib/charsets.jar, file:/C:/hzh/SoftWares/jdk/jre/lib/deploy.jar, file:/C:/hzh/SoftWares/jdk/jre/lib/ext/access-bridge-64.jar, file:/C:/hzh/SoftWares/jdk/jre/lib/ext/cldrdata.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/ext/dnsns.jar, file:/C:/hzh/SoftWares/jdk/jre/lib/ext/jaccess.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/ext/jfxrt.jar, file:/C:/hzh/SoftWares/jdk/jre/lib/ext/localedata.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/ext/nashorn.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/ext/sunec.jar, file:/C:/hzh/SoftWares/jdk/jre/lib/ext/sunjce_provider.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/ext/sunmscapi.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/ext/sunpkcs11.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/ext/zipfs.jar, file:/C:/hzh/SoftWares/jdk/jre/lib/javaws.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/jce.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/jfr.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/jfxswt.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/jsse.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/management-agent.jar, 
file:/C:/hzh/SoftWares/jdk/jre/lib/plugin.jar, file:/C:/hzh/SoftWares/jdk/jre/lib/resources.jar, file:/C:/hzh/SoftWares/jdk/jre/lib/rt.jar, 
file:/C:/hzh/codes/JNADemo/target/classes/, 
file:/C:/hzh/SoftWares/Intellij/IntelliJ%20IDEA%202016.3.2/jre/jre/bin/hzh/maven/repository/net/java/dev/jna/jna/4.1.0/jna-4.1.0.jar, 
file:/C:/hzh/SoftWares/Intellij/IntelliJ%20IDEA%202016.3.2/lib/idea_rt.jar])
	at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:271)
	at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:398)
	at com.sun.jna.Library$Handler.<init>(Library.java:147)
	at com.sun.jna.Native.loadLibrary(Native.java:412)
	at com.sun.jna.Native.loadLibrary(Native.java:391)
	at com.zhonghao.JnaTest$Clibrary.<clinit>(JnaTest.java:16)
	at com.zhonghao.JnaTest.main(JnaTest.java:25)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
为什么是项目根目录呢?

Java代码搜索动态链接库路径的顺序是:先从当前类的当前文件夹找,如果没有找到再在工程当前文件夹下面找对应的dll文件,如果找不到再到WINDOWS下面去搜索,再找不到就会抛异常了。
即:

1)项目的根路径

2)操作系统的全局路径、

3)path指定的路径。(这种尝试了未遂)

至此JNA的简单实例就结束了。

我目前只找到这一种指定库文件位置的方法,其他的方式也试了,但是未遂。方法肯定是有的,但是需要再花点时间去尝试。同样在Linux环境下,路径也是一个问题。

在Linux环境下,我尝试了指定路径等做法,未遂!然后按照windows下把库文件放到项目根目录下也不行,找不到库,报上边相同的错误。于是我将库文件放到上边错误中提到的一个路径/Desktop/JNADemo/target/classes/下,于是就可以找到库并正常调用C/C++的方法了。目前Linux下就只发现这一种。即把库文件.so放到项目编译生成的/target/ 下。

看到这里,估计大佬们已经耐不住想要深入了解JNA了,甚至想摩拳擦掌看看有没有复杂点的例子

不要着急,下边将献上一些复杂点的C++方法接口,你先思考拿到这样的方法接口,在Java中该怎么调用?比如这个C++方法接口中需要结构体这样的参数,需要指针、函数指针这样的参数,这些在Java中该如何声明?

大餐上菜之前先说说JNA的编程过程
JNA的编程过程

在Java中加载库的接口中你需要声明要调用的函数,如test方法就是C/C++代码中的方法(文章底部附上本篇实例的完整代码,那时你可以看到全局,现在只放出局部代码)

public interface Clibrary extends Library{
    //加载libhello.dll链接库
    Clibrary INSTANTCE = (Clibrary) Native.loadLibrary((Platform.isWindows() ? "helloworld" : "helloworldLinux"
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fighting_Boss_Hao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值