JNA实战笔记汇总(一)—— JNA简介及demo环境创建

article/2025/10/8 4:23:46

目录

1、简介

2、原理

3、配置环境,创建demo

3.1 搞清楚.dll/.so文件适用环境

3.2 创建一个普通的maven项目

3.2.1 将.dll/.so文件放在resources根路径下

3.2.2 pom.xml文件添加jna依赖

3.2.3 编写一个CLibrary接口,继承Library接口

3.2.4 编写一个测试类调用c++函数代码VixHz_InitSDK()

4、调用JNA过程遇到的问题及解决方法


1、简介

提到JNA 就不得不提一下JNI(Java Native Interface),有过不同语言间通信开发经历的一般都知道,它允许java和其他语言代码(尤其是C/C++)进行交互,只要遵守约定即可。首先看下JNI调用C/C++过程,注意写程序时自下而上,调用时自上而下:

可见步骤之多,调用.dll/.so共享库之痛苦的过程。

若已有编译好的.dll/.so文件—>需先用是C语言另外写一个.dll/.so共享库,使用SUN规定的数据结构代替C语言的数据结构,调用已有的dll/so中公布的函数—>java中载入这个库—>java编写Native函数作为链接库中函数的代理

问题是很少有java程序员愿意编写调用.dll/.so库中原生函数的java程序,这也使java在客户端上乏善可言,是JNI的一大弱点!

但是JNA不能完全替代JNI,JNI不仅可以实现java访问C,也可实现C调用java。

而JNA只能实现Java访问C函数,作为一个Java框架,自然不能实现C语言调用Java代码。此时,你还是需要使用JNI技术。

那什么是JNA呢?

JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架。

JNA框架就是为了解决上述JNI弱点而开发的,它提供一组java工具类用于在运行期间动态访问系统本地共享类库,java开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射,而不需要编写任何Native/JNI代码,大大降低了Java调用本体共享库的开发难度。

之所以说它是JNI的替代者,是因为JNA大大简化了调用本地方法的过程,使用很方便,基本上不需要脱离Java环境就可以完成。JNA调用C/C++的过程大致如下:

可以看到步骤减少了很多,最重要的是我们不需要重写我们的动态链接库文件,而是有直接调用的API,大大简化了我们的工作量。

2、原理

JNA使用一个小型的JNI库插桩程序来动态调用本地代码。开发者使用java接口描述目标本地库的功能和结构,这使得它很容易利用本机平台的功能,而不会产生多平台配置和生成JNI代码的高开销。这样的性能、准确性和易用性显然受到很大的重视。此外JNA包括一个已与许多本地函数映射的平台库,以及一组简化本地访问的共用接口。

注意:

JNA是建立在JNI技术基础之上的一个java类库,它提供了一个动态的C语言编写的转发器,可以自动实现java和C的数据类型映射,不需要再编写C动态链接库,可方便使用java直接访问动态链接库中的函数,JNA性能上有些微损失。

3、配置环境,创建demo

3.1 搞清楚.dll/.so文件适用环境

示例代码是根据不同的环境调用不同的动态链接库:

public class JnaUtil {public static Logger logger = Logger.getLogger(JnaUtil.class);static CLibrary INSTANCE;public static CLibrary LED_INSTANCE;static {// 获取jdk位数String bits = System.getProperty("sun.arch.data.model");// 获取os名称String ops = System.getProperty("os.name");logger.info("jdk bits=" + bits);logger.info("option sysetm=" + ops);if (ops.startsWith("win") || ops.startsWith("Win"))//windows{if ("32".equals(bits)) {logger.info("use CCR_SDKx32.dll");INSTANCE = (CLibrary) Native.loadLibrary("CCR_SDKx32.dll", CLibrary.class);}if ("64".equals(bits)) {logger.info("use CCR_SDKx64.dll and LEDControl_x64.dll");INSTANCE = (CLibrary) Native.loadLibrary("CCR_SDKx64.dll", CLibrary.class);LED_INSTANCE = Native.loadLibrary("LEDControl_x64.dll", CLibrary.class);}} else {if ("32".equals(bits)) {logger.info("use libCCR_SDKx64-x86_32.so");INSTANCE = (CLibrary) Native.loadLibrary("libCCR_SDKx64-x86_32.so", CLibrary.class);}if ("64".equals(bits)) {logger.info("use libCCR_SDKx64-x86_64.so and libLEDControl-x86_64.so");INSTANCE = (CLibrary) Native.loadLibrary("libCCR_SDKx64-x86_64.so", CLibrary.class);LED_INSTANCE = Native.loadLibrary("libLEDControl-x86_64.so", CLibrary.class);}}}
}

java环境的jdk位数要与.dll/.so位数相同,否则会报类似错误:

 java.lang.UnsatisfiedLinkError: %1 不是有效的 Win32 应用程序。

3.2 创建一个普通的maven项目

3.2.1 将.dll/.so文件放在resources根路径下

(若放在子包中,也是可以加载库文件的,不放心可在Native.loadLibrary()中制定下库文件路径)

3.2.2 pom.xml文件添加jna依赖

建议jna包的版本不要太老旧:

<dependency><groupId>net.java.dev.jna</groupId><artifactId>jna</artifactId><version>4.5.1</version>
</dependency>

3.2.3 编写一个CLibrary接口,继承Library接口

public interface CLibrary extends Library {CLibrary INSTANCE = Native.loadLibrary("iNetSDK.dll", CLibrary.class);/*** 初始化SDK 注意:调用SDK其他接口前必须先调用此接口!** @return TRUE表示成功,FALSE表示失败*/boolean VixHz_InitSDK();
}

3.2.3.1 在上面的代码中,我们定义了一个接口,继承自Library 或StdCallLibrary,默认的是继承Library ,
如果动态链接库里的函数是以stdcall方式输出的,那么就继承StdCallLibrary,比如众所周知的kernel32库。

接口中使用的函数必须与链接库中的函数原型保持一致。

3.2.3.2 接口内部定义

接口内部需要一个公共静态常量:INSTANCE,通过这个常量,就可以获得这个接口的实例,从而使用接口的方法,也就是调用外部dll/so的函数。
该常量通过Native.loadLibrary()这个API函数获得,该函数有2个参数:

  • 第一个参数是动态链接库dll/so的名称,但不带.dll或.so这样的后缀(此处加了后缀,不同系统和环境已经适用了不同的库文件),这符合JNI的规范,因为带了后缀名就不可以跨操作系统平台了。搜索动态链接库路径的顺序是:当前类当前文件夹,找不到——再在工程当前文件夹下面找win32/win64文件夹,找到后搜索对应的dll文件,找不到——到WINDOWS下面去搜索,再找不到——抛异常。

  • 第二个参数是本接口的Class类型。JNA通过这个Class类型,根据指定的.dll/.so文件,动态创建接口的实例。该实例由JNA通过反射自动生成。

3.2.4 编写一个测试类调用c++函数代码VixHz_InitSDK()

@RunWith(SpringRunner.class)
@SpringBootTest
public class DeviceSdkApplicationTests {/*** 初始化SDK*/@Testpublic void testVixHz_InitSDK() {boolean initSDKResult = CLibrary.INSTANCE.VixHz_InitSDK();System.out.println("initSDKResult = " + initSDKResult);}
}

运行结果,类型简单的JNA调用成功:

4、调用JNA过程遇到的问题及解决方法

4.1 调用JNA报的错java.lang.Error: Invalid memory access:很大可能是JNA调c++接口类型映射的问题;

类型复杂涉及到指针和结构体,接下来总结下JNA实战笔记汇总(二)——JNA和C / C ++的数据类型映射


http://chatgpt.dhexx.cn/article/wsbteNMq.shtml

相关文章

ROW(行)与COLUMN(列)

数列数&#xff0c;COLUMNS&#xff08;A:B&#xff09;2&#xff0c;即A到B一共两列。

column函数HTML5,column函数 excel中column函数的使用方法

column函数是一种查询的工具,我相信许多人都不会使用到这一个函数,因此在实际工程当中并不是十分的常见,然而这一款韩束如果能够掌握,对我们的工作也是非常有帮助的,接下来我们就一起来好好的了解一下这个函数究竟该如何使用。 column函数——column函数的使用方法 1.colu…

Duplicate column name ‘xxx_column‘

错误场景: 使用MyBatisPlus分页查询的情况下列名重复(注:select查询不报错, 映射正常) 例如 → select id, name, name from user 解决方法: 列名重复&#xff0c;删除重复的列名, 保证留一个就可以了 错误原因: 根据错误定位到PaginationInterceptor的queryTotal方法 最终…

mysql插入报错:colum xxx cannot be null

测试同学催促我赶紧解决上面的问题&#xff0c;首先看了下数据库这个字段确实是必填的&#xff0c;默认是当前时间 可是看了下代码发现mybatis的sql语句插入的时候包含了这个operate_time字段 那么讲道理必需给实体对象的operateTime字段赋值才行&#xff0c;可线上代码明明没有…

Vue template中函数获取el-table-colum中的属性值

方案如下&#xff1a; <el-table-column prop"id" label"操作"><template slot-scope"scope"><istyle"margin: 0 10px; cursor: pointer"click"clickItemInfo(scope.$index, scope.row,scope.column,scope.row.i…

hbase架构原理之region、memstore、hfile、hlog、columm-family、colum、cell

**鄙人的新书《elasticsearch7完全开发指南》&#xff0c;欢迎订阅&#xff01;** ----- https://wenku.baidu.com/view/8ff2ce94591b6bd97f192279168884868762b8e7 **《kibana权威指南》** ---- https://wenku.baidu.com/view/24cfee1ce43a580216fc700abb68a98270feac21 Hbas…

Row Column

Row Column 参考&#xff1a; Row classFlutter Layout Cheat SheetFlutter — Row/Column Cheat Sheet mainAxisAlignment和crossAxisAlignment 属性mainAxisAlignment和crossAxisAlignment mainAxisAlignment - 表示的是主轴的对齐方式crossAxisAlignment - 表示的是次轴…

Mybatis中resultMap的Colum和property属性

1&#xff1a; resultMap标签 当我们的数据库字段与实体类的属性不一致时&#xff0c;就需要使用该标签进行一一映射。 2&#xff1a;使用情况 2.1 简单查询 <resultMap id"这个resultMap的id" type"对应实体类的全限定类名"><id column"…

CSS3多列布局columns相关属性

tip&#xff1a;有问题或者需要大厂内推的我脉脉哦&#xff1a;丛培森 ٩( ‘ω’ )و CSS3中增加了可以实现多列布局的属性 在此之前的实现很麻烦可能需要各种定位 现在我们只需要一个属性就可以实现 多列布局类似于我们的报纸布局 这样可以方便读者观看 #多列数量与多列宽度#…

mysql5.7以上报错:Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated colum

这里写目录标题 一、前言二、解决方法临时解决&#xff1a;永久解决&#xff1a; 一、前言 在写sql时报错信息&#xff1a; 1055 - Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘pms.ru.role_id’ which is not functionall…

Vue+EleMentUI实现el-table-colum表格select下拉框可编辑

说明&#xff1a; 在进行采购入库的过程中&#xff0c;有必要对表格中的一行进行快速编辑保存&#xff0c;节省时间&#xff0c;提高工作效率&#xff01;&#xff0c;而不是每次编辑都要弹窗才可编辑 源码&#xff1a;https://gitee.com/charlinchenlin/store-pos 效果图&am…

Flutter学习(三)Row,Colum布局

主题 本文将介绍&#xff0c;flutter中的row&#xff0c;colum的用法。通俗来说&#xff0c;就是横向布局和纵向布局的用法。 开发环境 win10 androidstudio2022.1.1 jdk11 fluttersdk-flutter_windows_3.7.8 源码 文末将会附上完整开源demo地址 开发过程 首先&#xff…

column多列布局

CSS3 新增多列布局适合排版很长的文字内容&#xff0c;让其多列显示。使开发者能够轻松实现报纸版式的布局。 colum的相关属性&#xff1a; 属性说明column-count属性值是一个数字&#xff0c;规定元素被分为几列column-width列宽column-gap列与列的间隔宽度column-rule列的间…

为什么函数f(x)=x²不是满射

看到许多同学在问这个问题&#xff0c;一时也不知道该问谁&#xff0c;今天就去刨根问底了一下。 大致弄清缘由了&#xff0c;很可能是有同学看到有一本书《高等数学第7版上册》&#xff08;同济大学数学系 编&#xff09;&#xff0c;其中的第一章 函数与极限 第2页 例1提到&…

e^x导数证明

证明当x→0时,e^x-1与x是等价无穷小 https://www.zybang.com/question/1888f36ace3f205309482870c58e8a64.html

关于优化公式的小白理解

1、为什么要将e(x)写成e(xdx)的形式&#xff1f; 2、J(x)是什么对什么的导数&#xff1f; 理解 1、形式上来说&#xff0c;e(x)和e(xdx)并没有任何区别&#xff0c;以为dx本身就是小量&#xff0c;只要xdx还在作用域&#xff1f;内&#xff0c;函数的意思就是一样的。 更土一点…

x 的平方根(牛顿迭代法)

x 的平方根 实现 int sqrt(int x) 函数。 计算并返回 x 的平方根&#xff0c;其中 x 是非负整数。 由于返回类型是整数&#xff0c;结果只保留整数的部分&#xff0c;小数部分将被舍去。也就是说向下取整. 示例 1: 输入: 4 输出: 2 示例 2: 输入: 8 输出: 2 说明: 8 的平方根…

025 导数的四则求导法则之u+v、uv、u/v求导

025 导数的四则求导法则之uv及uv u/v求导

幂函数导数公式的推导

1 幂函数的定义域 【引理】 设幂函数 f ( x ) x α ( α ∈ R ) f(x)x^\alpha(\alpha\in R) f(x)xα(α∈R) 的定义域为 D α D_\alpha Dα​&#xff0c;则 &#xff08;1&#xff09;当 α 0 \alpha 0 α0&#xff0c; D α { x ∣ x ≠ 0 } D_\alpha\{x|x\neq 0\} Dα…

深度学习代码学习笔记(一)——阶跃函数与激活函数的python代码实现

今天正式开始学习深度学习&#xff0c;看的书是《深度学习入门——基于python的理论与实现》。 感知机使用阶跃函数作为激活函数&#xff0c;而神经网络使用 sigmoid 函数作为激活函数。 下面分别来用代码实现并绘制阶跃函数和激活函数的图形。 一、阶跃函数 阶跃函数以阈值…