乐趣区

关于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/

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

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

退出移动版