次のようにのは、例を見てみましょう:
パブリッククラスTestJNI { 静的{ System.loadLibraryを(「diaoyong」); //ロード時にプログラム、ライブラリが自動的にロードされlibdiaoyong.so } 公共のネイティブのボイド集合(int値); //ネイティブ関数を宣言。nativeキーワードを追加するには注意してください 公共ネイティブint型のget(); パブリック静的無効メイン(文字列[] args){ TestJNIテスト=新しいTestJNI()。 test.set(1)。 System.out.println(test.get())。 } }
javacのTestJNI.javaコマンドは、ファイルを生成しjava.class
次のようにjavahは-jni TestJNIコマンドは、TestJNI.hファイルを生成します。
/ *このファイルを編集しないでください - それは* /生成されたマシンであります 書式#include <jni.h中> / *クラスTestJNIのヘッダ* / #ifndefの_Included_TestJNI #define _Included_TestJNI #ifdefの__cplusplus extern "C" { #endifの / * *クラス:TestJNI *方法:セット *署名:(I)V * / JNIEXPORTボイドJNICALL Java_TestJNI_set (JNIEnvの* jオブジェクト、JINT)。 / * *クラス:TestJNI *方法:取得 *署名:()I * / JNIEXPORT JINT JNICALL Java_TestJNI_get (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。
jint是以JNI为中介使Java的int类型与本地的int沟通的一种类型。
Java | C/C++ | 字节数 |
boolean | jboolean | 1 |
byte | jbyte | 1 |
char | jchar | 2 |
short | jshort | 2 |
int | jint | 4 |
long | jlong | 8 |
float | jfloat | 4 |
double | jdouble | 8 |
对于数组型参数,
Java | C/C++ |
boolean[ ] | JbooleanArray |
byte[ ] | JbyteArray |
char[ ] | JcharArray |
short[ ] | JshortArray |
int[ ] | JintArray |
long[ ] | JlongArray |
float[ ] | JfloatArray |
double[ ] | JdoubleArray |
函数的名称是Java_+Java程序的package路径+函数名组成的。
Dynamic linkers resolve entries based on their names. A native method name is concatenated from the following components:
- the prefix Java_
- a mangled fully-qualified class name
- an underscore (“_”) separator
- a mangled method name
- for overloaded native methods, two underscores (“__”) followed by the mangled argument signature
对于本地方法参数来说
函数的名称是Java_+Java程序的package路径+函数名组成的。
第一个参数JNIEnv接口指针,指向一个个函数表,函数表中的每一个入口指向一个JNI函数。本地方法经常通过这些函数来访问JVM中的数据结构。下图演示了JNIEnv这个指针:
第二个参数根据本地方法是一个静态方法还是实例方法而有所不同。本地方法是一个静态方法时,第二个参数代表本地方法所在的类;本地方法是一个实例方法时,第二个参数代表本地方法所在的对象。如上例子当Java_TestJNI_get与Java_TestJNI_set是一个实例方法,因此jobject参数指向方法所在的对象。
继续编写对应的c语言的实现,如下:
#include <stdio.h> #include "TestJNI.h" int i=0; JNIEXPORT void JNICALL Java_TestJNI_set (JNIEnv * env, jobject obj, jint j) { i=j*888; } JNIEXPORT jint JNICALL Java_TestJNI_get (JNIEnv * env, jobject obj){ printf("ok!You have successfully passed the Java call c\n"); return i; }
gcc -Wall -fPIC -c TestJNI.c -I ./ -I /home/mazhi/workspace/jdk1.8.0_192/include/linux/ -I /home/mazhi/workspace/jdk1.8.0_192/include/ 命令生成TestJNI.o文件。
命令中-Wall:打开警告开关。-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
编译~/.bashrc文件,添加环境变量的配置export LD_LIBRARY_PATH=./ 使用source ~/.bashrc命令使配置生效
java TestJNI对文件进行运行即可。
参考文章:
https://jingyan.baidu.com/album/6c67b1d68e33bc2787bb1ee6.html?picindex=3