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_SOURCEbash
代碼以下多線程
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的名字放在一個可執行的映像中,當映像運行的時候纔去鏈接函數
方法簽名的格式爲:(形參參數類型列表)返回值
。
形參參數列表中,引用類型以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目錄下 生成結果以下:/* 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
複製代碼
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
複製代碼