本文介绍了JNI的基本用法以及如何将.a静态库二次封装成.so动态库供JNI调用等内容。
什么是JNI?
JNI全称为Java Native Interface,是Java提供的一套和不同平台native交互(或者说调用native)的接口。意味着你可以通过JNI在Windows平台上调用.DLL或者在Linux(Centos/Ubuntu/Android)平台上调用.so,至于.DLL和.so是什么此处不再赘述,读者可自行查阅有关资料。
如何使用?
这里以Ubuntu为例,介绍如何使用JNI调用.a静态库(将.a静态库封装成为.so库供JNI调用)
①新建一个Java文件JT.java
并声明native方法call
:
import java.lang.String;
import java.lang.System;
public class JT{
public native void call(); // native方法
public static void main(String[] args) { //Java入口
System.out.println("java in...");
new JT().call();
System.out.println("java out..");
}
static {
System.loadLibrary("demo"); //加载libdemo.so
}
}
②生成头文件
命令行切换到JT.java
所在目录,依次执行以下命令:
javac JT.java
上述命令用于生成JT.java
的字节码文件
javah JT
上述命令用于生成JNI头文件,这里生成的头文件为JT.h
③实现头文件中声明的方法
这里首先要对头文件进行完善,头文件中声明的方法只有参数类型,没有参数名称,这里需要手动补全(这里作者补全了env
和obj
,如果还有其它参数,同理补全)
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JT */
#ifndef _Included_JT
#define _Included_JT
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: JT
* Method: call
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_JT_call
(JNIEnv * env, jobject obj);
#ifdef __cplusplus
}
#endif
#endif
然后需要模拟一个静态库,这里为welcome
库,它包含一个welcome.h
(方法声明)和一个welcome.c
(方法实现),具体代码如下:
welcome.h
#ifndef _WELCOME_H
#define _WELCOME_H
void welcome();
#endif
welcome.c
#include<stdio.h>
#include"welcome.h"
void welcome()
{
printf("welcome, this is static library\n");
}
然后编译生成welcome.a
静态库:
gcc -Wall -O2 -fPIC -I./ -c -o welcome.o welcome.c
ar crv libwelcome.a welcome.o
有了静态库之后,开始编写demo.c
,实现JNI方法并调用welcome.a
静态库中的welcome
方法:
#include<stdio.h>
#include"JT.h"
#include"welcome.h"
/*
* Class: JT
* Method: call
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_JT_call
(JNIEnv * env, jobject obj) {
printf("hello, demo!\n");
welcome(); //welcome.a
}
然后编译demo.c
生成demo.o
gcc -Wall -O2 -fPIC -I /opt/jdk1.8.0_321/include/ -I /opt/jdk1.8.0_321/include/linux/ -I./ -c -o demo.o demo.c
再将demo.o
和welcome.a
封装成为libdemo.so
gcc -shared demo.o -L. -lwelcome -o libdemo.so
④通过Java调用
java -Djava.library.path=./ JT
这里需要通过-Djava.library.path
参数指定了共享库的路径,否则默认会报错,找不到共享库libdemo.so
,再来看看输出:
java in...
hello, demo!
welcome, this is static library
java out..
目录及文件结构如下:
.
├── demo.c
├── demo.o
├── jni.h
├── JT.class
├── JT.h
├── JT.java
├── libdemo.so
├── libwelcome.a
├── welcome.c
├── welcome.h
└── welcome.o
参考文档
1.Oracle JNI文档,此文档介绍了Oracle JNI的一些规范、动态库和静态库的区别及注意事项和高级特性。
2.JNA调用.a静态库,此blog介绍了如何通过JNA调用so动态库,以及如何将.a静态库封装成为.so动态库供JNA调用。