JNA (Java 本地访问)理论概述与入门
目录
JNA (Java 本地访问)概述
C 语言 与 Java
JNA 入门示例
msvcrt.dll 运行库
printf 打印方法
kernel32 动态链接库
GetLogicalDriveStringsA
GetSystemDirectoryA
本文参考网址:https://blog.csdn.net/gwd1154978352/article/details/55097376
本文基于 win10 的 64 位操作系统
JNA (Java 本地访问)概述
1、JNA 全称 Java Native Access (Java 本地访问),JNA 提供一组 Java 工具类用于在运行期间动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JNI代码。
2、开发人员只要在一个Java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。
3、JNA全称Java Native Access,是一个建立在经典的JNI(Java Native Interface-Java本地接口)技术之上的Java开源框架
4、Github托管地址:https://github.com/java-native-access/jna
5、JNA 开发包下载地址
https://maven.java.net/content/repositories/releases/net/java/dev/jna/jna/4.0.0/jna-4.0.0.jar
https://maven.java.net/content/repositories/releases/net/java/dev/jna/jna-platform/4.0.0/jna-platform-4.0.0.jar
6、官方入门示例:https://github.com/java-native-access/jna/blob/master/www/GettingStarted.md
6、通俗的说就是使用 JNA 可以更方便的调用 windows/Linux 系统底层的函数(方法)
C 语言 与 Java
1、Windows 底层主要使用 C++ 编写以及还有 C 语言加汇编语言,Linux 主要以 C 语言为主
2、dll 和 so 是 C 函数的集合和容器,这与 Java 中的接口概念吻合,所以 JNA 把 dll 文件和 so 文件看成一个个接口。在 JNA 中定义一个接口就是相当于了定义一个 DLL/SO 文件的描述文件,该接口代表了动态链接库中发布的所有函数。而且,对于程序不需要的函数,可以不在接口中声明。
3、JNA 定义的接口一般继承 com.sun.jna.Library 接口,如果dll文件中的函数是以stdcall方式输出函数,那么该接口就应该继承com.sun.jna.win32.StdCallLibrary接口。
4、JNA 难点在于学 Java 的人完全不知道电脑系统底层到底有哪些库?库叫什么名字?库中有哪些函数?函数是什么含义?等等
Java 类型 |
C 类型 |
原生表现 |
|
boolean |
int |
32位整数(可定制) |
|
byte |
char |
8位整数 |
|
char |
wchar_t |
平台依赖 |
|
short |
short |
16位整数 |
|
int |
int |
32位整数 |
|
long |
long long, __int64 |
64位整数 |
|
float |
float |
32位浮点数 |
|
double |
double |
64位浮点数 |
|
Buffer/Pointer |
pointer |
平台依赖(32或64位指针) |
|
<T>[] (基本类型的数组) |
pointer/array |
32或64位指针(参数/返回值) 邻接内存(结构体成员) |
|
String |
char* |
/0结束的数组 (native encoding or jna.encoding) |
|
WString |
wchar_t* |
/0结束的数组(unicode) |
|
String[] |
char** |
/0结束的数组的数组 |
|
WString[] |
wchar_t** |
/0结束的宽字符数组的数组 |
|
Structure |
struct*/struct |
指向结构体的指针(参数或返回值) (或者明确指定是结构体指针)结构体(结构体的成员) (或者明确指定是结构体) |
|
Union |
union |
等同于结构体 |
|
Structure[] |
struct[] |
结构体的数组,邻接内存 |
|
Callback |
<T> (*fp)() |
Java函数指针或原生函数指针 |
|
NativeMapped |
varies |
依赖于定义 |
|
NativeLong |
long |
平台依赖(32或64位整数) |
|
PointerType |
pointer |
和Pointer相同 |
JNA 入门示例
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;/** Simple example of JNA interface mapping and usage. */
public class HelloWorld {// This is the standard, stable way of mapping, which supports extensive// customization and mapping of Java to native types.public interface CLibrary extends Library {CLibrary INSTANCE = (CLibrary) Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);void printf(String format, Object... args);}public static void main(String[] args) {CLibrary.INSTANCE.printf("Hello, World\n");for (int i=0;i < args.length;i++) {CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]);}}
}
1、运行程序,没带参数时只打印出“Hello, World”,带了参数时,则会打印出所有的参数。
2、没有写一行 C 代码,就直接在 Java 中调用了系统动态链接库中的函数!
程序说明:
一:自定义接口
public interface CLibrary extends Library { .....
自定义一个接口,继承Library 或 StdCallLibrary。默认的是继承Library ,如果动态链接库里的函数是以stdcall方式输出的,那么就继承StdCallLibrary,比如众所周知的kernel32库
二:接口内部定义
Clibrary INSTANCE = (Clibrary) Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
接口内部需要一个公共静态常量:INSTANCE,通过这个常量,就可以获得这个接口的实例,从而使用接口的方法,也就是调用外部 dll/so 的函数
INSTANCE 常量通过 Native.loadLibrary() API函数获得,该函数有2个参数:
第一个参数是动态链接库dll/so的名称,但不带.dll或.so这样的后缀,这符合JNI的规范,因为带了后缀名就不可以跨操作系统平台了。搜索动态链接库路径的顺序是:先从当前类的当前文件夹找,如果没有找到,再在工程当前文件夹下面找win32/win64文件夹,找到后搜索对应的dll文件,如果找不到再到WINDOWS下面去搜索,再找不到就会抛异常了。比如上例中printf函数在Windows平台下所在的dll库名称是"msvcrt",而在其它平台如Linux下的so库名称是"c"。
第二个参数是自定义接口的Class类型。JNA通过这个Class类型,根据指定的.dll/.so文件,动态创建接口的实例。该实例由JNA通过反射自动生成。
void printf(String format, Object... args); 接口中只需要定义要用到的函数或者公共变量,不需要的可以不定义。注意参数和返回值类型,应该和系统链接库中的函数类型保持一致。
三:调用链接库函数
定义好接口后,就可以使用接口中的方法即相应dll/so中的函数了,通过接口中的实例即可进行调用
如:CLibrary.INSTANCE.printf("Hello, World\n"); 即可调用系统中的printf函数
msvcrt.dll 运行库
1、msvcrt.dll 是微软在windows操作系统中提供的C语言运行库执行文件(Microsoft Visual C Runtime Library)
2、msvcrt.dll 中提供了printf,malloc,strcpy 等 C语言库函数的具体运行实现
printf 打印方法
1、第一步自定义接口继承Library,接口名称建议与库名称一致,如 Msvcrt。如果dll库文件中的函数是以stdcall方式输出,那么自定义接口就应该继承com.sun.jna.win32.StdCallLibrary接口。
2、使用 Native 加载链接库,msvcrt的后缀名.dll不要写,想要使用msvcrt.dll库中哪些方法,就在自定义接口声明它即可
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
/*** Created by Administrator on 2018/6/27 0027.*/
public interface Msvcrt extends Library {Msvcrt INSTANCE = (Msvcrt) Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),Msvcrt.class);void printf(String format, Object... args);
}
3、第二步则是常见自定义接口的实例调用接口中的方法,也是msvcrt库中的函数
/*** 测试msvcrt.dll的printf方法*/
@Test
public void test1() {Msvcrt msvcrt = Msvcrt.INSTANCE;msvcrt.printf("Hello JNA");
}
kernel32 动态链接库
1、kernel32.dll 是Windows中非常重要的32位动态链接库文件,属于内核级文件。
2、kernel32.dll 控制着系统的内存管理、数据的输入输出操作和中断处理,当Windows启动时,kernel32.dll就驻留在内存中特定的写保护区域,使别的程序无法占用这个内存区域。
3、kernel32.dll库中有GetLogicalDriveStringsA、GetSystemDirectoryA等方法
GetLogicalDriveStringsA
1、获取本地系统的系统盘符
2、自定义接口,然后指明动态链接库名称,同时声明方法
import com.sun.jna.Library;
import com.sun.jna.Native;
/*** Created by Administrator on 2018/6/27 0027.*/
public interface Kernel32 extends Library {Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);/*** 【获取本地系统逻辑盘符】* @param length* @param buffer* @return*/int GetLogicalDriveStringsA(int length,byte[] buffer);
}
/*** 测试kernel32.dll的GetLogicalDriveStringsA方法* 【获取本地系统逻辑盘符】*/
@Test
public void test2() {Kernel32 kernel32 = Kernel32.INSTANCE;byte[] buffer2 = new byte[64];/*** GetLogicalDriveStringsA方法会把结果缓存到buffer2字节数组中* logicalDriveStringsSize:方法返回值其实是结果的大小*/int logicalDriveStringsSize = kernel32.GetLogicalDriveStringsA(buffer2.length / 2, buffer2);StringBuilder stringBuilder = new StringBuilder(logicalDriveStringsSize);for (byte bt : buffer2) {stringBuilder.append((char) bt);}String logicalDriveStrings = stringBuilder.toString().trim();System.out.println(logicalDriveStrings);
}
GetSystemDirectoryA
import com.sun.jna.Library;
import com.sun.jna.Native;
/*** Created by Administrator on 2018/6/27 0027.*/
public interface Kernel32 extends Library {Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);/*** 【获取本地系统逻辑盘符】* @param length* @param buffer* @return*/int GetLogicalDriveStringsA(int length,byte[] buffer);/*** 【获取系统目录】* @param buffer* @param size* @return*/int GetSystemDirectoryA(byte[] buffer,int size);
}
/*** 测试kernel32.dll的GetSystemDirectoryA方法* 【获取系统目录】*/
@Test
public void test3() {Kernel32 kernel32 = Kernel32.INSTANCE;byte[] buffer = new byte[50];/*** 同理此方法也是将结果缓存到了字节数组中,数组大小自己设置即可* 返回值systemDirectoryStrSize仍然是结果的长度大小*/int systemDirectoryStrSize = kernel32.GetSystemDirectoryA(buffer, 50);StringBuilder stringBuilder = new StringBuilder(systemDirectoryStrSize);for (byte bt : buffer) {stringBuilder.append((char) bt);}String systemDirectoryStr = stringBuilder.toString().trim();System.out.println(systemDirectoryStr);
}
JNA (Java 本地访问)理论概述与入门相关推荐
- java本地监听zk服务器节点【动态上下线】
[README] java本地访问 zk cluster, refer 2 https://blog.csdn.net/PacosonSWJTU/article/details/111404364 [ ...
- 视频编码零基础入门(1):视频编解码之理论概述
1.前言 即时通讯应用中的实时音视频技术,几乎是IM开发中的最后一道高墙.原因在于:实时音视频技术 = 音视频处理技术 + 网络传输技术 的横向技术应用集合体,而公共互联网不是为了实时通信设计的.有关 ...
- Java-Day11 面向对象遍程的入门 (类属性的默认值、构造方法、类的成员、static关键字、类的成员加载顺序、Java(权限)访问修饰符)
目录 1. 类的属性的默认值问题 2. 构造方法(Constructor) 3. 类的成员 3.1 类的成员之一:属性 3.2 UML类图 4. static关键字 5. 类的成员加载(运行)顺序 6 ...
- java私塾 设计模式 视频_[章节]Java Web开发理论部分视频教程 之 04 mvc设计模式详解视频教程 - 我的学习中心 - 私塾在线 - 只做精品视频课程服务...
第01节课:进行整体课程概览:复习事件机制:复习表现层的功能:复习表现层的开发 第02节课:Web应用的基础知识,包括:Internet.Http.IP.Port.MIME规范.Web客户端和服务端. ...
- 视频编解码之理论概述 和即时通信
前言 即时通讯应用中的实时音视频技术,几乎是IM开发中的最后一道高墙.原因在于:实时音视频技术 = 音视频处理技术 + 网络传输技术 的横向技术应用集合体,而公共互联网不是为了实时通信设计的.有关实时 ...
- 学习笔记:Java 并发编程①_基础知识入门
若文章内容或图片失效,请留言反馈. 部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 视频链接:https://www.bilibili.com/video/av81461839 视频下载: ...
- Linux负载均衡解决方案 -- LVS 理论概述
Lvs 理论概述 一.什么是 LVS ? 二.为什么需要 LVS ? 三.LVS 原理 1.LVS 体系结构 2.LVS 工作模式 3.LVS 调度算法 四.LVS 工作方式 1.LVS-DR 模式 ...
- Apache Thrift 官网学习 一 基本概述与入门
文章目录 一 基本概述与入门 1.1 官网知识 1.2 下载安装 1.3 基本数据结构 1.4 基本案例入门 1.4.1 编写thrift文件 1.4.2 新建springBoot项目 1.4.3 生 ...
- Java本地高性能缓存的几种实现方式
Java缓存技术可分为远端缓存和本地缓存,远端缓存常用的方案有著名的redis和memcache,而本地缓存的代表技术主要有HashMap,Guava Cache,Caffeine和Encahche. ...
- stylus vue 报错_【Vue】Re01 理论概念和入门上手
一.Vue概述 什么是渐进式?1.把Vue作应用的一部分嵌套项目中2.如果完全抛弃其他组件和框架,Vue又具有丰富的生态和库莱支持3.Core + Router + VueX 满足项目绝大多数的需求- ...
最新文章
- 【 iOS 应用开发 】 UIKit 控件 ( 代码生成控件 | UIView 属性方法 | Storyboard | Bundle | Property List | 动画 | 图片内存优化 )
- MyBatis -- 结果集映射
- libevent简介和使用【转】
- 组态王接入多比物联网云平台
- Ubuntu常用APT命令参数
- python打印文件中的前三行_linux利用grep查看打印匹配的下几行或前后几行的命令...
- 用SwipeBackLayout让activity具有滑动返回的效果
- mysql备份文件0kb_Oracle 数据文件大小为0kb或者文件丢失恢复
- 一图看懂云栖大会「云原生」发布
- Windows Phone 7 定义和使用字典资源(ResourceDictionary)
- D3.js学习(二)
- ADNI数据库数据集下载权限申请
- 计算机 取得高级权限,win10获取system权限,win7获取最高权限
- 如何修改wamp5的端口号,默认页。
- 特斯拉神器TeslaMate一键安装,终于来了
- unity python热更新_Unity热更新介绍和测试方法
- 2021-07-23 N卡显示器亮度设置
- 单休和双休有多大区别(月薪1万和8千如何选择)
- mysql master_log_file_change master 未指定master_log_file
- matlab负无穷大到正无穷大怎么打,matlab中怎么定义n从负无穷到正无?
热门文章
- hdoj 1071 The Area 求面积
- 为什么败者树的访问外存次数要比胜者树少_为什么说蒙地卡罗搜索树MCTS是AlphaZero的核心?[AlphaZero理论篇之三]...
- mac安装helm工具_适用于初学者的基本 kubectl 和 Helm 命令
- 拓端tecdat|R语言弹性网络Elastic Net正则化惩罚回归模型交叉验证可视化
- 拓端tecdat|R语言马尔可夫区制转移模型Markov regime switching
- 拓端tecdat|python对NOAA天气数据格式转换
- 拓端tecdat|数据告诉你:互联网哪个职位最有前途?
- java 字符串转换int_java IPV4字符串转int或long
- 3-8 堆栈模拟队列 (25 分)
- spring cloud学习笔记01