JNI教程-語法篇

一.概述

Hello Everyone焦辅,上一篇是教大家配置了開發(fā)環(huán)境梢莽,好多同學(xué)對(duì)里面的某些代碼可能還存在疑惑的,這篇文章就帶領(lǐng)代駕熟悉下JNI編程的一些語法知識(shí)盗忱。
在開篇之前我們看下状蜗,我們以上篇的例子來展開


image.png

image.png

通過javah生成的c++文件拟枚,可以看到一個(gè)很奇怪的方法瞧柔。這個(gè)就是我們今天的入門了薪夕。其中System.loadLibrary(“[庫名]”)桃纯,名字命名是有相應(yīng)的規(guī)則的酷誓,而這個(gè)庫名和CMakeList.txt文件中的庫名必須一致。Java虛擬機(jī)會(huì)找到這個(gè)類名并調(diào)用該函數(shù)态坦。

靜態(tài)注冊(cè)Native方法:

仔細(xì)看這個(gè)函數(shù)會(huì)發(fā)現(xiàn)方法名的組成為 Java_包名類名方法名盐数。其中JNIEXPORT和JNICALL是兩個(gè)宏定義,主要作用就是說明該函數(shù)為JNI函數(shù)伞梯,jstring是定義JNI定義的數(shù)據(jù)類型玫氢。在Java虛擬機(jī)加載的時(shí)候回連接對(duì)應(yīng)的Native方法,比如在例子中的 public native String getId(); 通過javah操作后會(huì)生成

JNIEXPORT jstring JNICALL Java_com_example_mylibrary_JNITest_getID();

動(dòng)態(tài)注冊(cè)Native方法:

JNI_ONLOAD函數(shù):該函數(shù)會(huì)有兩個(gè)參數(shù)谜诫,其中*jvm為Java虛擬機(jī)實(shí)例漾峡,JavaVM結(jié)構(gòu)體定義了以下函數(shù):

DestroyJavaVM
AttachCurrentThread
DetachCurrentThread
GetEnv

這里我們使用了GetEnv函數(shù)獲取JNIEnv變量,上面的JNI_ONLOAD函數(shù)有如下代碼:

JNIEnv *env;
if (jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

    return -1;
}

這里調(diào)用了GetEnv函數(shù)獲取JNIEnv結(jié)構(gòu)體指針喻旷,其實(shí)JNIEnv結(jié)構(gòu)體是指向一個(gè)函數(shù)表的生逸,該函數(shù)表指向了一個(gè)對(duì)應(yīng)的JNI函數(shù),我們通過調(diào)用這些JNI函數(shù)實(shí)現(xiàn)JNI編程且预。

獲取JAVA對(duì)象槽袄,完成動(dòng)態(tài)注冊(cè)

上面介紹 如何獲取JNIEnv結(jié)構(gòu)體指針,得到結(jié)構(gòu)體指針我們就可以調(diào)用JNIEnv中的RegisterNatives函數(shù)完成動(dòng)態(tài)注冊(cè)native方法:

jint RegisterNatives(jclass clazz, const JNINativeMethod* methods, jint nMethods)

第一個(gè)參數(shù)是Java層對(duì)應(yīng)包含native方法的對(duì)象锋谐,指的就是JNITest對(duì)象了遍尺,通過調(diào)用JNIEnv對(duì)應(yīng)的函數(shù)獲取class對(duì)象

jclass clz = env->FindClass("com/github/songnick/jni/AndroidJni");

第二個(gè)參數(shù)是JNINativeMethod結(jié)構(gòu)體指針,這里 JNINative結(jié)構(gòu)體是描述Java層Native方法的怀估,定義如下:

typedef struct {
    const char* name;//Java層native方法的名字
    const char* signature;//Java層native方法的描述符
    void*       fnPtr;//對(duì)應(yīng)JNI函數(shù)的指針
} JNINativeMethod;

第三個(gè)參數(shù)為注冊(cè)native方法的數(shù)量狮鸭,一般會(huì)動(dòng)態(tài)注冊(cè)多個(gè)native方法合搅,首先會(huì)定義一個(gè)JNINativeMethod數(shù)組,然后將該指針作為RegisterNative函數(shù)的參數(shù)傳入

JNINativeMethod nativeMethod[] = {{"dynamicLog", "()V", (void*)nativeDynamicLog}};

最后調(diào)用RegisterNative函數(shù)完成動(dòng)態(tài)注冊(cè):

env->RegisterNatives(clz, nativeMethod, sizeof(nativeMethod)/sizeof(nativeMethod[0]));

JNIEnv結(jié)構(gòu)體

JNIEnv結(jié)構(gòu)體指向一個(gè)函數(shù)表歧蕉,該函數(shù)表指向一系列的JNI函數(shù)灾部,我們通過調(diào)用這些JNI函數(shù)可以與Java層進(jìn)行交互,以下是常用的函數(shù):

..........
jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)
jboolean GetBooleanField(jobject obj, jfieldID fieldID)
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
CallVoidMethod(jobject obj, jmethodID methodID, ...)
CallBooleanMethod(jobject obj, jmethodID methodID, ...)
..........

  • GetFieldID函數(shù)是獲取Java對(duì)象中某個(gè)變量的ID
  • GetBooleanField()函數(shù)是根據(jù)變量的ID獲取數(shù)據(jù)類型為Boolean
  • GetMethodID函數(shù)獲取Java對(duì)象中對(duì)應(yīng)的方法ID
  • CallVoidMethod根據(jù)methodID調(diào)用對(duì)應(yīng)對(duì)象中的方法惯退,并且該方法的返回值Void類型
  • CallBooleanMethod根據(jù)methodID調(diào)用對(duì)應(yīng)對(duì)象中的方法赌髓,并且該方法的返回值Boolean類型

JNI數(shù)據(jù)類型

JNI的本質(zhì)是銜接Java和C++/C 相互通信的,因?yàn)镴ava的對(duì)象是不被C++識(shí)別的催跪,同樣的C++的指針也不被Java識(shí)別锁蠕,所以JNI需要自定義一些自己的數(shù)據(jù)類型來使雙方的通信保持順暢。

1.原始數(shù)據(jù)類型Java Type Native Typ Description
JavaType Native Description
boolean jboolean unsigned 8 bits
byte jbyte signed 8 bits
char jchar unsigned 16 bits
short jshort signed 16 bits
int jint signed 32 bits
long jlong signed 64 bits
float jfloat 32 bits
double jdouble 64 bits
void void N/A
2.引用類型

前面我們?cè)讷@取AndroidJni對(duì)象的使用通過定義jclass引用懊蒸,然后調(diào)用FindClass函數(shù)獲取了該對(duì)象荣倾,所以JNI也定義了一些引用類型以便JNI層調(diào)用,具體的引用類型如下:

jobject (all Java objects)
|
|-- jclass (java.lang.Class objects)
|-- jstring (java.lang.String objects)
|-- jarray (array)
| |--jobjectArray (object arrays)
| |--jbooleanArray (boolean arrays)
| |--jbyteArray (byte arrays)
| |--jcharArray (char arrays)
| |--jshortArray (short arrays)
| |--jintArray (int arrays)
| |--jlongArray (long arrays)
| |--jfloatArray (float arrays)
| |--jdoubleArray (double arrays)
|
|--jthrowable

3.方法和變量的ID
?當(dāng)需要調(diào)用Java中的某個(gè)方法的時(shí)候我們首先要獲取它的ID骑丸,根據(jù)ID調(diào)用JNI函數(shù)獲取該方法舌仍,變量的獲取過程也是同樣的過程,這些ID的結(jié)構(gòu)體定義如下:

struct _jfieldID;              /* opaque structure */ 
typedef struct _jfieldID *jfieldID;   /* field IDs */ 

struct _jmethodID;              /* opaque structure */ 
typedef struct _jmethodID *jmethodID; /* method IDs */
描述符

1.類描述符
前面為了獲取Java的JNITest對(duì)象通危,是通過調(diào)用FindClass()函數(shù)獲取的铸豁,該函數(shù)參數(shù)只有一個(gè)字符串參數(shù),字符串如下:
>com/example/mylibrary/JNITest

這個(gè)就是我們JNI定義了對(duì)類的描述符菊碟,規(guī)則也很簡(jiǎn)單节芥,包名+類名,并用“/”替換“.”
2.方法描述符
前面我們動(dòng)態(tài)注冊(cè)native方法的時(shí)候結(jié)構(gòu)體JNINativeMethod中含有方法描述符逆害,就是確定native方法的參數(shù)和返回值头镊,

Method Descriptor Java Language Type
"()Ljava/lang/String;" String f();
"(ILjava/lang/Class;)J" long f(int i, Class c);
"([B)V" String f(byte[] bytes);

上面的栗子我們看到方法的返回類型和方法參數(shù)有引用類型以及boolean、int等基本數(shù)據(jù)類型魄幕,對(duì)于這些類型的描述符在下個(gè)部分介紹拧晕。這里數(shù)組的描述符以"["和對(duì)應(yīng)的類型描述符來表述。對(duì)于二維數(shù)組以及三維數(shù)組則以"[["和"[[["表示:

Descriptor Java Langauage Type
"[[I" int[][]
"[[[D" double[][][]

3.數(shù)據(jù)類型描述符
?前面我們說了方法的描述符梅垄,那么針對(duì)boolean、int等數(shù)據(jù)類型描述符是怎樣的呢输玷,JNI對(duì)基本數(shù)據(jù)類型的描述符定義如下:

Descriptor Java Langauage Type
Z boolean
B byte
C char
S short
I int
J long
F float
D double

Field Desciptor Java Language Type
Z boolean
B byte
C char
S short
I int
J long
F floa
D double

Descriptor Java Langauage Type
Z boolean
B byte
C char
S short
I int
J long
F float
D double

對(duì)于引用類型描述符是以"L"開頭";"結(jié)尾队丝,示例如下所示:

Field Desciptor Java Language Type
"Ljava/lang/String;" String
"[Ljava/lang/Object;"

今天的學(xué)習(xí)就到這里了,該篇文章只是介紹了下基本的語法知識(shí)以及jni通信的基本方法欲鹏。后續(xù)我們接著進(jìn)行~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末机久,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子赔嚎,更是在濱河造成了極大的恐慌膘盖,老刑警劉巖胧弛,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異侠畔,居然都是意外死亡结缚,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門软棺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來红竭,“玉大人,你說我怎么就攤上這事喘落∫鹣埽” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵瘦棋,是天一觀的道長(zhǎng)稀火。 經(jīng)常有香客問我,道長(zhǎng)赌朋,這世上最難降的妖魔是什么凰狞? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮箕慧,結(jié)果婚禮上服球,老公的妹妹穿的比我還像新娘。我一直安慰自己颠焦,他們只是感情好斩熊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著伐庭,像睡著了一般粉渠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上圾另,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天霸株,我揣著相機(jī)與錄音,去河邊找鬼集乔。 笑死去件,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扰路。 我是一名探鬼主播尤溜,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼汗唱!你這毒婦竟也來了宫莱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤哩罪,失蹤者是張志新(化名)和其女友劉穎授霸,沒想到半個(gè)月后巡验,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碘耳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年显设,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藏畅。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡敷硅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出愉阎,到底是詐尸還是另有隱情绞蹦,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布榜旦,位于F島的核電站幽七,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏溅呢。R本人自食惡果不足惜澡屡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望咐旧。 院中可真熱鬧驶鹉,春花似錦、人聲如沸铣墨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伊约。三九已至姚淆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間屡律,已是汗流浹背腌逢。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留超埋,地道東北人搏讶。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像霍殴,于是被迫代替她去往敵國和親窍蓝。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容