说明
java如果需要调用c 或者 c++写的库(windwos下为dll的文件,linux下为so的文件),需要用到jna或者jni技术。
调用方式
一.jni(Java Native Interface)
1.说明
- jni是Java SDK中的一部分,提供一种Java字节码调用C/C++的解决方案,JNI描述的是一种技术。
- jni使用比较麻烦,使用jni的前提是动态库内部需要按java的方式把每个API封装一次。
- jni的调用效率要比jna高得多,如果一个操作涉及到java虚拟机与外部动态库的频繁调用,且对程序执行效率有要求的话,建议使用jni。
2.使用
//完整类样例:
public class Mp3DecoderJni {
//类加载时加载库
static {
System.loadLibrary("mp3decoder");
}
//库中对应的方法
public native void addMp3Frame(byte[] val,int length);
//库里面回调这个方法,里面写具体逻辑,前提是库里面有调这个方法
public int onDecodeCall(byte[] data , int length , int samplingrate){
return 0;
}
}
3.语法
- 其中System.loadLibrary的第一个参数为动态库的路径,相对/绝对,.so/.dll后缀可加可不加,建议不加,跨平台就不用改缀名了。
- System.loadLibrary加载的动态库是需要含有jni语法层的。
二.jna(Java Native Access)
1.说明
- jna使用需要引入第三方库。
- jna是jni的更高封装,jna使用方便些,不需要动态库内部按按java的方式把每个API封装一次。
- jna基于jni技术开发,主要在上层作了类型自动转换的封装,无需jni那样的繁杂的接口层开发。
2.引入
maven
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.3.1</version>
</dependency>
3.使用
//完整类样例1:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class HelloWorld {
public interface CLibrary extends Library {
CLibrary INSTANCE = Native.load((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
void printf(String format, Object... args);
}
public static void main(String[] args) {
CLibrary.INSTANCE.printf("Hello, World\n");
}
}
//完整类样例2:
//CLibrary.java
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public interface CLibrary extends Library {
CLibrary INSTANCE = Native.load((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
void printf(String format, Object... args);
}
//Test.java
public class Test {
public static void main(String[] args) {
CLibrary.INSTANCE.printf("Hello, World\n");
}
}
//通过此demo可以看出调用时CLibrary的INSTANCE,并不需要声明是public static的。
//printf是msvcrt.dll库提供的方法。
4.语法
- 使用jna,需要创建一个接口继承Library,然后在创建一个 Native.load创建一个自己的实例。然后在接口编码库中对应的方法和入参即可,并不需要跟jni一样加native标识符。
- 其中Native.load的第一个参数为动态库的路径,相对/绝对,.so/.dll后缀可加可不加,建议不加,跨平台就不用改缀名了。
- 其中"msvcrt"在项目中相对路径是没对应dll,为什么还是可以执行?因为msvcrt为windwos自带的dll,这样写也是可以正常使用的,我们可以直接在C:\Windows\System32找到msvcrt.dll文件。
- demo中的msvcrt,msvcrt.dll是微软在windows操作系统中提供的C语言运行库执行文件(Microsoft Visual C Runtime Library),其中提供了printf,malloc,strcpy等C语言库函数的具体运行实现,并且为使用C/C++(Vc)编译的程序提供了初始化(如获取命令行参数)以及退出等功能;demo中的c,c.so应该是linux中自带的类似msvcrt的库。
5.回调
回调用来实现c调用java的函数。
//完整类样例1:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.*;
public interface JnaTest extends Library{
JnaTest INSTANCE = Native.load("main",JnaTest.class);
//1.与动态库中对应的方法
int test_callback(addCallback f);
//2.创建一个接口继承Callback/StdCallCallback
public interface myCallback extends Callback{
public int callback(int x,int y);
}
//3.实现2中的接口
public static class addCallback implements myCallback{
@Override
public int callback(int x,int y){
return x + y; //返回值根据实际业务传入相关的值
}
}
//4.调用1中对应方法传入3中回调方法
public static void main(String[] args) {
JnaTest.INSTANCE.test_callback(new JnaTest.addCallback());
}
}
参考:
JNA回调 Java C语言