JNA即Java Native Access(Java本地访问),是一个开源的Java框架,起初由SUN公司主导开发,目前托管在Github上。JNA是基于JNI之上开发的框架,它为Java程序提供了更简便的方法访问本地库。通过JNA,Java代码可以像调用普通的Java函数一样,调用本地库中的函数,基本上无需编写中间代码。让我们来试一下这个神奇的框架。还是同上一篇一样,我们用Java程序来调用第一篇中”libhello.so”里的hello()方法。

  • 从网上下载JNA包
    Github项目主页在https://github.com/java-native-access/jna,上面可以下载到最近的jna.jar包,当前版本是4.1.0。对于源代码感兴趣的朋友们,也可以从上面克隆源代码下来慢慢研究。

  • 编写Java测试程序”TestJna.java”

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;

public class TestJna {

    public interface LibHello extends Library {
        LibHello INSTANCE = (LibHello) Native.loadLibrary("hello", LibHello.class);
        void hello(String name);
    }

    public static void main(String[] args) {
        LibHello.INSTANCE.hello("JNA");
    }
}

上面的代码创建了一个内部接口LibHello,其中Native.loadLibrary("hello", LibHello.class);用来加载本地库”libhello.so”。接口中同时声明了”libhello.so”中的公有函数hello()。这里的函数名,参数类型和个数须同本地库保持一致。如果本地库中还有其他的公有函数,你也可以依此声明。之后对所有”libhello.so”中公有的函数,你都可以用LibHello.INSTANCE对象来调用。是不是很简单?我们来运行下。

  • 编译测试程序
    这里需引入jna.jar,本例中jar包存放在当前目录下,”libhello.so”也在当前目录下。

    $ javac -classpath ./jna-4.1.0.jar TestJna.java
    
  • 运行测试程序

    $ java -classpath .:./jna-4.1.0.jar TestJna
    

屏幕上显示出

Hello JNA!

祝贺你,又一次成功了!

比较JNI的实现方法,JNA不但免去编写Java代理类和C/C++动态链接库来包装”libhello.so”,它还帮我们做了函数参数类型的自动转换(还记得上一篇GetStringUTFChars()的方法吗?)。JNA提供了Java基础类型同C/C++类型的自动转换。可以参见下表:

C/C++类型 长度 Java类型 Windows平台类型
char 8-bit integer byte BYTE, TCHAR
short 16-bit integer short WORD
wchar_t 16 / 32-bit character char TCHAR
int 32-bit integer int DWORD
int boolean value boolean BOOL
long 32 / 64-bit integer NativeLong LONG
long long 64-bit integer long __int64
float 32-bit FP float
double 64-bit FP double
char* C string String LPTCSTR
void* pointer Pointer LPVOID, HANDLE, LPXXX

既然JNA那么简单,为什么还有人用JNI呢?其实JNI相对于JNA最大的优势就是性能,毕竟是JDK原生的。如果你的项目对性能有很高的要求,还是建议使用JNI。如果性能不是问题时,使用JNA就方便许多了。

本例代码可以从这里下载