摘要:的接口函數(shù)和指針代碼想要訪問(wèn)虛擬機(jī)需要調(diào)用方法,而獲取方法則通過(guò)。
JNI的接口函數(shù)和指針
native代碼想要訪問(wèn) java虛擬機(jī)需要調(diào)用JNI方法,而獲取JNI方法則通過(guò) JNI interface Pointer。它實(shí)際指向的就是一個(gè)都是指針的數(shù)組,每個(gè)指針指向的都是一個(gè)接口函數(shù)
這樣做的優(yōu)勢(shì):
JNI 命名和native code書(shū)寫(xiě)分開(kāi),避免硬編碼
JNI interface Pointer 只在當(dāng)前線程有效,即native 方法不能在線程之間傳遞(不同線程的指針可能不一編譯
樣),VM保證同一個(gè)線程中調(diào)用多次JNI interface Pointer是同一個(gè)
JAVA VM支持多線程,native 方法在編譯的時(shí)候需要加上對(duì)應(yīng)的參數(shù),如 gcc加上 -D_REENTRANT或者-D_POSIX_C_SOURCE
加載代碼如下
package pkg; class Cls { native double f(int i, String s); static { System.loadLibrary(“pkg_Cls”); //名字可以隨便定義 } }
對(duì)于不同的系統(tǒng),打包的后綴名會(huì)有不同,solaris系統(tǒng)一般是libpkg_Cls.so(使用的時(shí)候則是直接用的pkg_Cls)Win32的系統(tǒng)則是pkg_Cls.dll
連接如果當(dāng)前系統(tǒng)不支持動(dòng)態(tài)連接,所有的Native方法必須預(yù)先和VM建立連接,通過(guò)System.loadLibrary是無(wú)法自動(dòng)加載。如果要靜態(tài)連接可以使用 JNI的函數(shù) RegisterNatives
靜態(tài)連接需要把所有的library復(fù)制到可執(zhí)行的映像中;動(dòng)態(tài)連接是把共享的library的名字放在一個(gè)可執(zhí)行的映像中,當(dāng)映像運(yùn)行的時(shí)候才去連接Native方法名
生成規(guī)則:Java_ 作為前綴,類(lèi)的全路徑名,用 “_” 分隔每一個(gè)目錄名,再加上 方法名,如果是重載的方法,則會(huì)添加 “__”和
方法簽名,比如: 全路徑是:com.study.jnilearn.HelloWorld,生成的方法是 Java_com_study_jnilearn_HelloWorld_sayHello:
查找規(guī)則:VM查找native library里面的方法名,首先查找短的名字,即方法名沒(méi)有參數(shù)簽名;然后查找有參數(shù)簽名的方法;長(zhǎng)方法名只有在native方法重載了另一個(gè)native方法的時(shí)候需要
方法簽名方法簽名的格式為:(形參參數(shù)類(lèi)型列表)返回值。
形參參數(shù)列表中,引用類(lèi)型以L開(kāi)頭,后面緊跟類(lèi)的全路徑名(需將.全部替換成/),以分號(hào)結(jié)尾
比如:long f(int n,String s,int[] arr); 對(duì)應(yīng)的Native方法簽名是 (ILjava/lang/String;[I)J.Native的方法參數(shù)
各種類(lèi)型簽名對(duì)比
第一個(gè)參數(shù)是JNI Interface pointer(類(lèi)型是 JNIEnv),如果是靜態(tài)native方法,第二個(gè)參數(shù)則是對(duì)應(yīng)java class的引用,非靜態(tài)的native則對(duì)應(yīng)的是 對(duì)象的引用,其它的參數(shù)對(duì)應(yīng)的是java方法的參數(shù)
JNI的Hello world實(shí)現(xiàn)創(chuàng)建自己的Hello world文件,在其中使用Native方法
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"); } }
用javac編譯HelloWorld.java文件
用javah編譯產(chǎn)生頭文件 HelloWorld.h
命令為 javah -jni -d ./jni HelloWorld;-d:將生成的文件放到j(luò)ni目錄下
生成結(jié)果如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include/* 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
用C實(shí)現(xiàn)HelloWorld.h中的函數(shù)
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 "); return NULL; } printf("Java Str:%s ", c_str); sprintf(buff,"hello %s",c_str); (*env)->ReleaseStringUTFChars(env,j_str,c_str); return (*env)->NewStringUTF(env,buff); } #ifdef __cplusplus } #endif
編譯C的代碼生成native文件
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:表示生成動(dòng)態(tài)鏈接庫(kù) * -o:指定動(dòng)態(tài)鏈接庫(kù)編譯后生成的路徑以及文件名 * -framwork JavaVM -I:編譯JNI需要用到的JVM頭文件(jni.h)
執(zhí)行java程序,指定動(dòng)態(tài)鏈接庫(kù)
命令為 java -Djava.library.path=動(dòng)態(tài)鏈接的目錄 Helloworld
java Str:paxi hello paxi附錄
JNI 文檔
JNI hello world原博客地址
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/71593.html
摘要:它對(duì)應(yīng)的實(shí)現(xiàn)是在中,原始代碼為這里是省略的方法體轉(zhuǎn)換后這里是省略的方法體附錄簡(jiǎn)介 怎么看open jdk native的源碼 類(lèi)的命名與java類(lèi)的命名是一模一樣的 方法的命名為JNI的代碼風(fēng)格 一般關(guān)注下文件頭,如果是系統(tǒng)文件,比如 , 是搜不到源碼的,否則全局可以搜到對(duì)應(yīng)的命名 JVM_ENTRY等類(lèi)似這樣的字符是啥意思? JVM_ENTRY本身是一個(gè)宏定義,位于interfa...
閱讀 4913·2023-04-25 18:47
閱讀 2673·2021-11-19 11:33
閱讀 3445·2021-11-11 16:54
閱讀 3101·2021-10-26 09:50
閱讀 2540·2021-10-14 09:43
閱讀 665·2021-09-03 10:47
閱讀 671·2019-08-30 15:54
閱讀 1498·2019-08-30 15:44