在我们 Java 开发中,有些时候会涉及到跨语言的调用,比如涉及到一些高效计算、图形渲染、加密和解密的时候会用到 C++ 编写的程序,大部分情况我们都是利用 JNI
来调用 C++ 的 dll 或者 so,其实随着技术发展,更简单和易用的 JNA
应用而生。
Java 调用 C++ 编写的。dll/.so 文件,可以使用传统的 JNI
调用。
dll/so
中公布的函数。Java Native
函数作为 dll/so 中函数的代理。经过 2 个繁琐的步骤才能在 Java 中调用本地代码。
因此,很少有 Java 程序员愿意编写调用 dll/.so 库中的原生函数的 Java 程序。这也使 Java 语言在客户端上乏善可陈。可以说 JNI 是 Java 的一大弱点!
如果你想具体了解 JNI 如何使用,可以参考这篇博客:https://blog.csdn.net/jiangwei0910410003/article/details/17465085
我相信你看了后,会有砸键盘的冲动。
其实正是因为 JNI
的复杂,所以有了更加简单易用的 JNA
。
其区别主要有:
首先推荐这个网站:https://www.eshayne.com/jnaex/index.html
上述网站可以找到 C 中结构 和 Java JNA 中类的对应关系,可以借助查阅这个文档,实现类型映射构建对应实体类。
废话不多说我们先来一个代码解解渴:
假如有一个 C 的接口如下所示:
int increase(int val)
{
return val + 1;
}
其编译后的文件为 say.dll
或者 say.so
如果使用 JNA 需要先引入 pom.
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.5.1</version>
</dependency>
然后构建一个接口:
import com.sun.jna.Library;
import com.sun.jna.Native;
/**
* 测试JNA调用C的接口
*
* @author LiuChunfu
* @date 2018/5/27
*/
public interface SayLibrary extends Library {
/////////// 如下为接口 //////////
/**
* 根据C提供的接口构造的接口
*
* @param val
* @return
*/
int increase(int val);
/////////// 如下为调用入口 ///////////
/**
* 需要将C编译的dll 或者so 文件放入Java运行目录。
*/
SayLibrary LIBRARY = (SayLibrary) Native.loadLibrary("say", SayLibrary.class);
}
在使用的时候可以如下使用:
public static void main(String[] args) {
// 通过接口的入口 LIBRARY进行调用
int result = SayLibrary.LIBRARY.increase(1);
System.out.println(result);
}
需要说明的是:
src/main/resources
理论上就可以成功调用了。System.getProperty("java.library.path");
输出的路径中选择任一路径来进行放置。关于 dll 或者 so 文件存放路径可以参考:https://blog.csdn.net/daylight_1/article/details/70199452
/////////// 如下为调用入口 ///////////
/**
* 需要将C编译的dll 或者so 文件放入Java运行目录。
*/
SayLibrary LIBRARY = (SayLibrary) Native.loadLibrary("say", SayLibrary.class);
LIBRARY
进行相应方法的调用。其实 JNA 最难的一点是构建形参,特别是有指针、结构体等等包裹的时候,如果可能建议和 C 接口编写人沟通下,确定下,形参尽量简单。