native代码想要访问 java虚拟机须要调用JNI方法,而获取JNI方法则经过 JNI interface Pointer。它实际指向的就是一个都是指针的数组,每一个指针指向的都是一个接口函数html
这样作的优点:java
JNI interface Pointer 只在当前线程有效,即native 方法不能在线程之间传递(不一样线程的指针可能不一
样),VM保证同一个线程中调用屡次JNI interface Pointer是同一个
JAVA VM支持多线程,native 方法在编译的时候须要加上对应的参数,如 gcc加上 -D_REENTRANT或者-D_POSIX_C_SOURCE数组
代码以下多线程
package pkg; class Cls { native double f(int i, String s); static { System.loadLibrary(“pkg_Cls”); //名字能够随便定义 } }
对于不一样的系统,打包的后缀名会有不一样,solaris系统通常是libpkg_Cls.so(使用的时候则是直接用的pkg_Cls)Win32的系统则是pkg_Cls.dlloracle
若是当前系统不支持动态链接,全部的Native方法必须预先和VM创建链接,经过System.loadLibrary是没法自动加载。若是要静态链接可使用 JNI的函数 RegisterNativeside
静态链接须要把全部的library复制到可执行的映像中;动态链接是把共享的library的名字放在一个可执行的映像中,当映像运行的时候才去链接
方法签名,好比: 全路径是:com.study.jnilearn.HelloWorld,生成的方法是 Java_com_study_jnilearn_HelloWorld_sayHello:函数
方法签名的格式为:(形参参数类型列表)返回值
。
形参参数列表中,引用类型以L开头,后面紧跟类的全路径名(需将.所有替换成/),以分号结尾ui
好比:long f(int n,String s,int[] arr); 对应的Native方法签名是 (ILjava/lang/String;[I)J.
各类类型签名对比
![]()
第一个参数是JNI Interface pointer(类型是 JNIEnv),若是是静态native方法,第二个参数则是对应java class的引用,非静态的native则对应的是 对象的引用,其它的参数对应的是java方法的参数编码
public class HelloWorld { public static native String sayHello(String name); public static void main(String[] args) { String text = sayHello("paxi"); System.out.println(text); } static{ System.loadLibrary("HelloWorld"); } }
命令为 javah -jni -d ./jni HelloWorld
;-d:将生成的文件放到jni目录下
生成结果以下:spa
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class HelloWorld */ #ifndef _Included_HelloWorld #define _Included_HelloWorld #ifdef __cplusplus extern "C" { #endif /* * Class: HelloWorld * Method: sayHello * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_HelloWorld_sayHello (JNIEnv *, jclass, jstring); #ifdef __cplusplus } #endif #endif
HelloWorld.c: #include "HelloWorld.h" #ifdef __cplusplus extern "C" { #endif /* * Class: HelloWorld * Method: sayHello * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_HelloWorld_sayHello (JNIEnv *env, jclass cls, jstring j_str){ const char *c_str = NULL; char buff[128] = {0}; c_str = (*env)->GetStringUTFChars(env,j_str,NULL); if (c_str == NULL) { printf("out of memory\n"); return NULL; } printf("Java Str:%s\n", c_str); sprintf(buff,"hello %s",c_str); (*env)->ReleaseStringUTFChars(env,j_str,c_str); return (*env)->NewStringUTF(env,buff); } #ifdef __cplusplus } #endif
mac下命令为
gcc -dynamiclib -o extensions/libHelloWorld.jnilib jni/HelloWorld.c -framework JavaVM -I/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/include/darwin * -dynamiclib:表示生成动态连接库 * -o:指定动态连接库编译后生成的路径以及文件名 * -framwork JavaVM -I:编译JNI须要用到的JVM头文件(jni.h)
命令为 java -Djava.library.path=动态连接的目录 Helloworld
java Str:paxi hello paxi