Java调用本地代码(三)—— JNA实现
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就方便许多了。
本例代码可以从这里下载