JNA

JNA (Java Native Access)框架是一个开源的java框架,是sum公司主导开发,简历在一个经典的JNI基础之上的一个框架。强大易用,其中JNA是对JNI(Java Native Interface)的封装

比较

JNI允许java代码和其他语言(尤其C/C++)写的代码进行交互,只要遵守调用规则即可。先来看看调用C/C++的过程,主义写程序时自下而上,调用时自下而上

可见步骤非常的多,很麻烦,使用JNI调用.dll/.so共享库都能体会到这个痛苦的过程。如果已有一个编译好的.dll/.so文件,如果使用JNI技术调用,我们首先需要使用C语言另外写一个.dll/.so共享库,使用SUN规定的数据结构替代C语言的数据结构,调用已有的 dll/so中公布的函 数。然后再在Java中载入这个库dll/so,最后编写Java native函数作为链接库中函数的代理。经过这些繁琐的步骤才能在Java中调用 本地代码。因此,很少有Java程序员愿意编写调用dll/.so库中原生函数的java程序。这也使Java语言在客户端上乏善可陈,可以说JNI是 Java的一大弱点!

JNA

JNA框架解决了既需要编写java代码,又编写C语言的代码方法及很多数据类型的转换问题,它提供一组java工具类用于在运行期间动态访问系统本地共享类库而不需要编写任何native、JNI代码。开发人员只需要在一个java接口中描述native libary的函数结构,JNA将自动实现java接口到native function 的映射,大大降低了java调用本体共享库的开发难度

过程如下

原理

JNA使用一种小型的JNI库茶庄程序来动态调用本地代码。开发者使用Java接口描述目标本地库的功能结构,这使得它很容易利用本机平台的功能,而不会产生多平台配置和生成JNI代码的高开销。

这样的性能,准确性和易用性显然受到很大重视

此外JNA包括一个已于多本地函数映射的平台库,以及一组简化本地访问的公用接口

注意:

JNA是建立在JNI技术基础智商的一个java类库,可以方便的使用java直接访问动态链接库中的函数

原来使用JNI必须手工用C写一个动态链接库,在C语言中映射Java的数据类型

JNA中,它提供了一个动态的C语言编写的转发器,可以自动实现Java和C的数据类型映射,不需要再编写C动态链接库

也许这意味着,JNA技术相比使用JNI技术调用动态链接库,稍微会有一些性能损失。但总体影响不大,因为JNA也避免了JNI的一些平台配置的开销

回调函数

在windows中,程序员想让系统DLL调用自己编写的一个方法,于是利用DLL当中回调函数(CALLBACK)的接口编写程序,使它调用,这个就称为回调,在调用接口时,需要阉割的按照定义的参数和方法调用,并且需要处理函数的异步,否则就会导致程序崩溃

所谓回调,就是客户程序C调用服务程序S中的某个方法a,然后S又在某个时候反过来调用C中的某个方法b,对于C来说,这个b便叫做回调函数。

一般说来,C不会自己调用b,C提供b的目的就是让S来调用它,而且是C不得不提供。由于S并不知道C提供的b叫甚名谁,所以S会约定b的接口规范(函数原型),然后由C提前通过S的一个函数r告诉S自己将要使用b函数,这个过程称为回调函数的注册,r称为注册函数。

下面举个通俗的例子:

某天,我打电话向你请教问题,当然是个难题,你一时想不出解决方法,我又不能拿着电话在那里傻等,于是我们约定:等你想出办法后打手机通知我,这样,我就挂掉电话办其它事情去了。过了XX分钟,我的手机响了,你兴高采烈的说问题已经搞定,应该如此这般处理。故事到此结束。

这个例子说明了“异步+回调”的编程模式。其中,你后来打手机告诉我结果便是一个“回调”过程;我的手机号码必须在以前告诉你,这便是注册回调函数;我的手机号码应该有效并且手机能够接收到你的呼叫,这是回调函数必须符合接口规范

package S;
 
public class C {
    //回调函数
    void add(int i) {
        System.out.println(i);
    }
    public static void main(String[] args) throws InterruptedException {
        S s = new S();
        s.start();
        Thread.sleep(10);
        //注册回调函数
        s.set(new C());
    }
}
class S extends Thread{
    private C c;
    //注册回调函数
    void set(C c) { 
        this.c =c;
    }
    public void run() {
        for(int i =0;i<5;i++) {
            if(c != null) {
                //回调函数
                c.add(i);
            }
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
Last modification:January 5, 2023
如果觉得我的文章对你有用,请随意赞赏