【JNA探索之路系列】之一:JNA开篇

来源:互联网 发布:淘宝账号怎样手机申诉 编辑:程序博客网 时间:2024/06/05 00:53

作者:郭嘉
邮箱:allenwells@163.com
博客:http://blog.csdn.net/allenwells
github:https://github.com/AllenWell

本篇文章是【JNA探索之路系列】的开篇文章,主要介绍JNA的相关功能。

首先给出相关资源:

这里写图片描述

JNA开源项目

JNA API

在讨论JNA之前,先讨论一下大家熟知的JNI工作流程,如下所示:

  1. 编写Java类代码
  2. 编译字节码
  3. 产生C/C++头文件
  4. 编写JNI代码
  5. 编译成链接库文件

可见编程步骤非常繁琐,而且JNI层代码的编写非常容易出问题,对于一个已经编写好的.dll/.so库,我们还需要用JNI代码为它封装一层,用Java规定的数据结构替代C语言的数据结构,然后才能成为Java可以用的.dll/.so库。

那么有办法不用编写JNI层代码就直接使用.dll/.so库库吗?

答案是肯定的,JNA(Java Native Access)就是提供这样一种功能的Java开源框架,它建立在JNI基础之上,简化了本地库的调用,使用很方便,基本上不用脱离Java编译环境。

一 JNA实现原理

JNA使用一个小型的JNI库插件程序来动态的调用本地代码,开发者使用Java接口描述本地库的功能和结构,自动的生成与本地函数的额映射,而不需要再手动的编写JNI代码去映射本地函数。

JNA的这种自动映射的功能也就意味着它会带来些许性能损失,但是它同样也规避了JNI复杂的工作量和平台配置的开销。

二 JNA相关功能

JNA的相关功能如下所示:

  • 自动映射从Java到本机的功能,用简单的映射为所有原始数据类型
  • 它支持Java在大多数平台上运行
  • C和Java字符串之间自动转换,可定制的编码/解码
  • 结构和联合参数/返回值,参考和值
  • 函数指针(从本地代码的Java回调)为结构参数和/或成员
  • 自动生成的Java代理的本地函数指针
  • 通过引用(指针到型)参数
  • Java数组和NiO缓冲参数(基本类型和指针)作为指针到缓冲区
  • 嵌套结构和数组
  • 宽(wchar_t的为主)的字符串
  • 原生支持长(32位或64位的如适用)
  • 演示应用程序/例子
  • 支持在1.4或更高版本的JVM,包括JavaME的(早期的虚拟机可能使用存根NIO支持)
  • 可定制的编组/解组(参数和返回值转换)
  • 从Java方法的本地函数名,调用自定义映射定制模拟C预处理器的宏功能
  • 支持Windows自动ASCII / UNICODE函数映射
  • 支持可变长度
  • 类型安全的本地指针
  • VM故障保护(可选)
  • 优化的直接映射高性能应用。
  • 早期和后期绑定COM支持。
  • COM/类型库的Java代码生成

三 JNA使用流程

JNA的使用过程如下所示:

  1. 编写JNA实现代码
  2. 编译成字节码
  3. 使用已有的链接库文件

举例

package com.sun.jna.examples;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 {    /* 定义一个接口继承Library,如果动态链接库里的函数是一stdcall方式输出的,则继承StdCallLibrary */    public interface CLibrary extends Library {        /* 定义一个公共静态常量INSTANCE,通过这个常量可以调用外部dll/do库里的函数 */        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]);        }    }}

本篇文章就讲到这里的,后续的文章会详细的探讨JNA的API和相关技术点。

0 0
原创粉丝点击