关于java:java高级用法之JNA中的Function

简介

在JNA中,为了和native的function进行映射,咱们能够有两种mapping形式,第一种是interface mapping,第二种是direct mapping。尽管两种形式不同,然而在具体的办法映射中,咱们都须要在JAVA中定义一个和native办法进行映射的办法。

而这个JAVA中的映射在JNA中就是一个function。通过或者function对象,咱们能够实现一些十分弱小的性能,一起看看吧。

function的定义

先来看下JNA中Function的定义:

public class Function extends Pointer

能够看到Function实际上是一个Pointer,指向的是native function的指针。

那么怎么失去一个Function的实例呢?

咱们晓得JNA的流程是先进行Library的映射,而后再对Library中的Function进行映射。所以很天然的咱们应该能够从Library中失去Function。

咱们看一下依据Library name失去function实例的办法定义:

public static Function getFunction(String libraryName, String functionName, int callFlags, String encoding) {
        return NativeLibrary.getInstance(libraryName).getFunction(functionName, callFlags, encoding);
    }

这个办法能够承受4个参数,后面两个参数大家应该很相熟了,第三个参数是callFlags,示意的是函数调用的flags,Function定义了三个callFlags:

    public static final int C_CONVENTION = 0;

    public static final int ALT_CONVENTION = 0x3F;

    public static final int THROW_LAST_ERROR = 0x40;

其中C_CONVENTION示意的是C语言类型的办法调用。

ALT_CONVENTION示意的其余的调用形式。

THROW_LAST_ERROR示意如果native函数的返回值是非零值的时候,将会抛出一个LastErrorException。

最初一个参数是encoding,示意的是字符串的编码方式,实际上指的是 Java unicode和native (const char*) strings 的转换形式。

除了依据Library name获取Function之外,JNA还提供了依据Pointer来获取Function的办法。

    public static Function getFunction(Pointer p, int callFlags, String encoding) {
        return new Function(p, callFlags, encoding);
    }

这里的Pointer指的是一个执行native办法的指针,因为Function自身就是继承自Pointer。所以跟Pointer来创立Function的实质就是在Pointer的根底上增加了一些Function特有的属性。

有了Function的定义,更为重要的是如何通过Function来调用对应的办法。跟反射很相似,Function中也有一个invoke办法,通过调用invoke,咱们就能够执行对应的Function的性能。

Function中的invoke办法有两种,一种是通用的返回对象Object,一种是带有返回值的invoke办法,比方invokeString,invokePointer,invokeInt等。

Function的理论利用

Function的理论应用和JAVA中的反射有点相似,其工作流程是首先取得要加载的NativeLibrary,而后从该NativeLibrary中找到要调用的Function,最初invoke该Function的某些办法。

C语言中的printf应该是大家最相熟的native办法了。咱们看一下如何应用Function来调用这个办法吧:

        NativeLibrary lib = NativeLibrary.getInstance(Platform.C_LIBRARY_NAME);
        Function f = lib.getFunction("printf");
        try {
            f.invoke(getClass(), new Object[] { getName() });
            fail("Invalid return types should throw an exception");
        } catch(IllegalArgumentException e) {
            // expected
        }

能够看到调用的流程十分简洁。如果是用interface Mapping或者direct Mapping的模式,咱们还须要自定义一个interface或者class,并且在其中定义一个相应的java办法映射。然而如果应用Function的话,这些都不须要了。咱们间接能够从NativeLibrary中拿到对应的函数,并最终调用其中的办法。

C语言中的printf的原型如下:

# include <stdio.h>
int printf(const char *format, ...);

printf带有返回值的,如果要输入这个返回值,则能够调用Function中的invokeInt命令。咱们再来看一个有返回值的调用例子:

NativeLibrary lib = NativeLibrary.getInstance(Platform.C_LIBRARY_NAME);
        Function f = lib.getFunction("printf");
        Object[] args = new Object[Function.MAX_NARGS+1];
        // Make sure we don't break 'printf'
        args[0] = getName();
        try {
            f.invokeInt(args);
            fail("Arguments should be limited to " + Function.MAX_NARGS);
        } catch(UnsupportedOperationException e) {
            // expected
        }

总结

应用Function能够缩小手写Mapping的工作,在某些状况下是十分好用的,然而Function的invoke反对TypeMapper,并不反对FunctionMapper,所以在应用中还是有一些限度。

大家能够在应用过程中酌情思考。

本文已收录于 http://www.flydean.com/07-jna-function/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」,懂技术,更懂你!

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理