JNA
JNA是建立在JNI技术基础之上的一个Java类库,它使您可以方便地使用java直接访问c/c++动态链接库中的函数。 相对于JNI, JNA大大简化了调用本地方法的过程,使用很方便,基本上不需要脱离Java环境就可以完成。(但是JNA无法完全替代JNI, JNA只能实现Java访问C/C++函数,作为一个Java框架,自然不能实现C语言调用Java代码, 此时,你还是需要使用JNI技术。
Maven依赖
<dependencies>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.12.1</version>
</dependency>
</dependencies>
参数传递与处理
数据类型对应关系
官方文档: Overview (JNA API) (java-native-access.github.io)
C/C++ type | java type | description |
---|---|---|
char | byte | 8-bit |
wchar_t | char | 16/32-bit |
short | short | 16-bit |
int | int | 32-bit |
long/_int64 | long | 64-bit |
long long | long | 64-bit |
float | float | 32-bit |
double | double | 32-bit |
pointer(指针) | Pointer | |
pointer array(指针数组) | [ ] (数组) | |
char* | String | |
char** | String[] | |
void* | Pointer | |
void** | PointerByReference | |
int& | IntByReference | |
int* (指向单个) | IntByReference | |
struct | Structure | |
(*fp)() (函数指针) | Callback | 一般用于回调函数 |
代码实战
C/C++层实现动态库
头文件声明
#ifndef ADAPTER_LIBRARY_H
#define ADAPTER_LIBRARY_H
#ifndef EXPORT_DLL
#define EXPORT_DLL __declspec(dllexport) //导出dll声明
#endif
struct Point {
int x;
int y;
};
struct DataPtr {
int size;
int *arr;
char *str;
};
struct DataArray {
int intArr[3];
char charArr[3];
};
struct DataInf {
DataPtr *data;
};
extern "C" {
EXPORT_DLL void GetDataStr(Point points[], int n);
EXPORT_DLL void GetDataPtrStr(DataPtr &dataPtr);
EXPORT_DLL void GetDataArrayString(DataArray *dataArray);
EXPORT_DLL void GetDataInfStr(DataInf &dataInf);
}
extern "C" {
EXPORT_DLL void GetArrSum(int *arr, int n, int &ret);
// 将arr赋值, 返回
EXPORT_DLL void getArrBack(int *arr, int n);
EXPORT_DLL void PrintStrArr(char *str);
}
/**
* 回调函数
*/
typedef void (*ProcessCallback)(char *host, int port);
ProcessCallback processCallback;
typedef void (*MessageCallback)(char *);
MessageCallback messageCallback;
extern "C" {
EXPORT_DLL void registerCallBack(ProcessCallback callback1, MessageCallback callback2);
EXPORT_DLL void invokeProcessCallBack(char *host, int port, char *str);
}
#endif //ADAPTER_LIBRARY_H
具体实现
#include "library.h"
#include <string>
#include <iostream>
EXPORT_DLL void GetDataStr(Point points[], int n) {
std::string str = "{";
for (int i = 0; i < n; ++i) {
str += "[" + std::to_string(points[i].x) + "," + std::to_string(points[i].y) + "]";
}
str += "}";
std::cout << "points = " << str << std::endl;
}
EXPORT_DLL void GetDataPtrStr(DataPtr &dataPtr) {
int n = dataPtr.size;
std::string str;
for (int i = 0; i < n; ++i) {
str += std::to_string(dataPtr.arr[i]) + dataPtr.str[i] + "%";
}
std::cout << "str = " << str << std::endl;
}
EXPORT_DLL void GetDataArrayString(DataArray *dataArray) {
int n = sizeof(dataArray->charArr) / sizeof(char);
std::string str;
for (int i = 0; i < n; ++i) {
str += std::to_string(dataArray->intArr[i]) + dataArray->charArr[i] + "%";
}
std::cout << "str = " << str << std::endl;
}
EXPORT_DLL void GetDataInfStr(DataInf &dataInf) {
int n = dataInf.data->size;
std::string str;
for (int i = 0; i < n; ++i) {
str += std::to_string(dataInf.data->arr[i]) + dataInf.data->str[i] + "%";
}
std::cout << "str = " << str << std::endl;
}
EXPORT_DLL void GetArrSum(int *arr, int n, int &ret) {
for (int i = 0; i < n; ++i) {
ret += arr[i];
}
}
EXPORT_DLL void getArrBack(int *arr, int n) {
for (int i = 0; i < n; ++i) {
arr[i] = i;
}
std::cout << "get " << n << " data" << std::endl;
}
EXPORT_DLL void PrintStrArr(char *str) {
std::cout << str << std::endl;
}
EXPORT_DLL void registerCallBack(ProcessCallback callback1, MessageCallback callback2) {
processCallback = callback1;
messageCallback = callback2;
std::cout << "call back function register successfully" << std::endl;
}
EXPORT_DLL void invokeProcessCallBack(char *host, int port, char *str) {
std::cout << "connect successfully to:" << host << ":" << port << std::endl;
processCallback(host, port);
messageCallback(str);
}
之后编写CMakeLists.txt
cmake_minimum_required(VERSION 3.19)
project(adapter)
set(CMAKE_CXX_STANDARD 17)
add_library(adapter SHARED library.cpp)
java层调用
结构体定义
(同名与否无所谓)
Point
public class Point extends Structure {
public int x;
public int y;
public Point() {
}
public Point(int a, int b) {
this.x = a;
this.y = b;
}
public static class ByReference extends Point implements Structure.ByReference {
public ByReference(int a, int b) {
this.x = a;
this.y = b;
}
}
public static class ByValue extends Point implements Structure.ByValue {
public ByValue(int a, int b) {
this.x = a;
this.y = b;
}
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("x", "y");
}
}
DataArray
public class DataArray extends Structure {
public int[] intArr = new int[3];
public byte[] bytesArr = new byte[3];
public static class ByReference extends DataArray implements Structure.ByReference {
}
public static class ByValue extends DataArray implements Structure.ByValue {
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("intArr","bytesArr");
}
}
DataInf
public class DataInf extends Structure {
public DataPtr.ByReference dataPtr;
public static class ByReference extends DataInf implements Structure.ByReference {
}
public static class ByValue extends DataInf implements Structure.ByValue {
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("dataPtr");
}
}
DataPtr
import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
public class DataPtr extends Structure {
public int size;
public Pointer intArrPtr;
public Pointer byteArrPtr;
public static class ByReference extends DataPtr implements Structure.ByReference {
}
public static class ByValue extends DataPtr implements Structure.ByValue {
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("size","intArrPtr","byteArrPtr");
}
}
DLL导入与同名接口
public interface CLibrary extends Library {
CLibrary INSTANCE = Native.load("D:\\Files\\Code\\JNA\\adapter\\cmake-build-release\\libadapter.dll", CLibrary.class);
void GetDataStr(Point[] data, int n);
void GetDataArrayString(DataArray.ByReference data);
void GetDataPtrStr(DataPtr.ByReference data);
void GetDataInfStr(DataInf.ByReference data);
void GetArrSum(int[] arr, int len, IntByReference ret);
void getArrBack(int[] arr, int len);
void PrintStrArr(String str);
/**
* 回调函数
*/
void registerCallBack(Callback callback1,Callback callback2);
void invokeProcessCallBack(String host, int port,String str);
}
调用测试
public class Main {
public static void main(String[] args) {
test1();
}
static void test1() {
int n = 2;
Point[] points = (Point[]) new Point().toArray(n);
points[0].x = 1;
points[0].y = 2;
points[1].x = 3;
points[1].y = 4;
CLibrary.INSTANCE.GetDataStr(points, n);
}
static void test2() {
DataArray.ByReference data = new DataArray.ByReference();
data.intArr = new int[]{5, 6, 7};
data.bytesArr = new byte[]{'a', 'b', 'c'};
CLibrary.INSTANCE.GetDataArrayString(data);
}
static void test3() {
int size = 5;
int[] arr = {1, 2, 3, 4, 5};
byte[] bytes = {'a', 'b', 'c', 'd', 'e'};
DataPtr.ByReference data = new DataPtr.ByReference();
data.size = size;
data.intArrPtr = new Memory(size * Native.getNativeSize(int.class));
data.intArrPtr.write(0, arr, 0, size);
data.byteArrPtr = new Memory(size * Native.getNativeSize(byte.class));
data.byteArrPtr.write(0, bytes, 0, size);
CLibrary.INSTANCE.GetDataPtrStr(data);
}
static void test4() {
int size = 4;
int[] arr = {1, 3, 1, 4,};
byte[] bytes = {'l', 'o', 'v', 'e'};
DataPtr.ByReference dataPtr = new DataPtr.ByReference();
dataPtr.size = size;
dataPtr.intArrPtr = new Memory(size * Native.getNativeSize(int.class));
dataPtr.intArrPtr.write(0, arr, 0, size);
dataPtr.byteArrPtr = new Memory(size * Native.getNativeSize(byte.class));
dataPtr.byteArrPtr.write(0, bytes, 0, size);
DataInf.ByReference dataInf = new DataInf.ByReference();
dataInf.dataPtr = dataPtr;
CLibrary.INSTANCE.GetDataInfStr(dataInf);
Native.free(Pointer.nativeValue(dataPtr.intArrPtr));
Pointer.nativeValue(dataPtr.intArrPtr, 0);
Native.free(Pointer.nativeValue(dataPtr.byteArrPtr));
Pointer.nativeValue(dataPtr.byteArrPtr, 0);
}
static void test5() {
int[] arr = {1, 3, 1, 4, 5, 2, 0};
String str = "love you";
IntByReference ret = new IntByReference();
CLibrary.INSTANCE.GetArrSum(arr, arr.length, ret);
System.out.println("sum:" + ret.getValue());
CLibrary.INSTANCE.PrintStrArr(str);
}
static void test6() {
int[] arr = new int[5];
CLibrary.INSTANCE.getArrBack(arr, arr.length);
System.out.println(Arrays.toString(arr));
}
static void test7() {
interface ProcessFunc extends Callback {
void connect(String host, int port);
}
interface MessageFunc extends Callback {
void msgPass(String str);
}
ProcessFunc processFunc = (host, port) -> System.out.println("connect to server " + host + ":" + port);
MessageFunc messageFunc = (str) -> System.out.println(str + " pang");
CLibrary.INSTANCE.registerCallBack(processFunc, messageFunc);
CLibrary.INSTANCE.invokeProcessCallBack("127.0.0.1", 8888, "ping");
}
test7执行结果:
call back function register successfully
connect successfully to:127.0.0.1:8888
connect to server 127.0.0.1:8888
ping pang
重点总结
回调函数:
-
C/C++:
typedef void (*MessageCallback)(char *)
定义函数指针 -
java层: 继承接口JNA的Callback接口, 注册回调函数, 调用回调函数实体
typedef void (*ProcessCallback)(char *host, int port);
ProcessCallback processCallback; // 回调函数名为processCallback
Cpp层调用:
processCallback(host, port);
结构体数组
java中定义结构体数组: Point[] points = (Point[]) new Point().toArray(n);
Memory与free
当对象不再被任何对象引用时,GC会调用该对象的finalize()方法. Memory中finalize方法如下:
/** Properly dispose of native memory when this object is GC'd. */
@Override
protected void finalize() {
dispose();
}
/** Free the native memory and set peer to zero */
protected synchronized void dispose() {
try {
free(peer);
} finally {
peer = 0;
allocatedMemory.remove(this);
}
}
protected static void free(long p) {
// free(0) is a no-op, so avoid the overhead of the call
if (p != 0) {
Native.free(p);
}
}
new memory申请内存, 对象被GC(回收)会释放申请的内存, 前提是执行了GC, 为避免过多分配导致内存不足, 可手动释放内存, 方法为:
Pointer p = new Memory(1024 * 1024);
long ptr = Pointer.nativeValue(p);
Native.free(ptr); //手动释放内存
Pointer.nativeValue(p, 0); //peer置为0, 避免Memory对象被GC时重复执行Nativ.free()方法
标签:arr,int,void,ByReference,JNA,new,使用指南,public From: https://www.cnblogs.com/shmilyt/p/17060637.html