场景
公司有一个C++的SDK需要调用,本人是Java开发,所以使用JNA调用C++,在这里分享一些JNA的使用经验供大家参考
JNA介绍
JNA是JNI的封装升级,但是JNI的使用比较繁琐,有兴趣的可以自行了解
JNA官网地址:链接地址
如何使用JNA
- 集成JNA包
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>4.5.2</version>
</dependency>
- 创建接口并继承Library接口,加载C++动态连接库
package com.yxsd.cloud.transfer.library;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.PointerByReference;
public interface TestLibrary extends Library{
TestLibrary INSTANCE = Native.loadLibrary("test",TestLibrary.class);
int add(int a,int b);
}
Native.loadLibrary用来加载C++动态连接库
接口中的方法需要对应C++的方法(参数也需要对应)
- 调用接口执行方法
int add = TestLibrary.INSTANCE.add(1, 2);
整体来说使用JNA就是在接口中加载C++动态连接库并对应C++的方法,然后通过接口调用方法即可、
JNA的方法映射
基本数据类型
基本数据类型比较简单,可以参考下面的图片(图片来源于JNA官网)
指针映射
Java中是没有指针概念的,JNA中用Point映射C++指针,一般情况下一级指针用Point,二级指针用PointerByRefrence,不同的数据类型,指针映射的情况也不一样
通过C++的方法和Java中对应的方法来熟悉指针
C++中的方法:
void GetListTest(name, number, ier)
char** name;
int* number;
long* ier;
JNA方法映射
void GetListTest(PointerByReference name,IntByReference number,LongByReference ier);
C++中char**是二级指针,JNA中用PointerByReference映射
C++中int*是一级指针,JNA中用IntByReference,如果这个一级指针数据类型是long,则用PointerByReference对应
建议大家去了解一下C++的指针,这样方便大家理解JNA中的pointer,比如char**的数据类型就相当于Java的字符串数组
结构体映射
C++中的结构体类似于Java中的实体类,但在Jna中java实体类的每个属性都要与C++结构体的每一个字段对应
C++结构体
typedef struct _testStruct
{
char id[18];
char name[48];
int intValue;
float floatValue;
long longValue;
} testStruct_t;
Java实体类
public class TestStruct extends Structure{
public byte[] id = new byte[18];
public byte[] name = new byte[48];
public int intValue;
public float floatValue;
public NativeLong longValue;
@Override
protected List<String> getFieldOrder() {
// TODO Auto-generated method stub
return Arrays.asList(new String[] {
"id",
"name",
"intValue",
"floatValue",
"longValue"
});
}
public static class ByReference extends TestStruct implements Structure.ByReference {}
public static class ByValue extends TestStruct implements Structure.ByValue {}
}
char[12]在JNA中需要用Java的byte[12],并且长度也是需要对应的,否则数据会发生错乱。getFieldOrder方法中必须按照顺序写出每个属性名,否则此实体类也是错误的。Structure.ByReference表示结构体的指针,Structure.ByValue表示结构体的值。
JNA总结
JNA的封装很便于Java对C++进行调用了,但是仍然处理不了一些问题,比如,C++的类是在JNA中无法体现的。各位如果想熟练使用JNA的话,建议各位了解一下Java和C++的一些基础知识,毕竟两种编程语言的思想还是有所不同的。
以上的介绍只是对JNA的一些简单使用,更复杂的方法调用不再过多演示,万变不离其宗,原理是一样的,如有问题,欢迎留言讨论。