Jni相關(guān)基礎(chǔ)1-解釋以及常見配置或語法

md文件相關(guān)操作語法參考
java之jvm的javap命令
獲取class字節(jié)碼相關(guān)、類信息、方法簽名(javap s xxx.class)

本文包括內(nèi)容

配置或小知識點

在AndroidStudio中需要打印C中的日志:

android{
  defaultConfig {
    //新版中其實默認已經(jīng)支持了。只需要使用android/log.h即可打印日志
    ndk {
        ldLibs = "log" //此配置是指添加ndk的日志支持.實際使用:liblog.so
    }
  }
}

JNI相關(guān)知識點解釋

示例方法:

//實現(xiàn)Java_com_test01_Test_firstTest方法
JNIEXPORT void JNICALL Java_com_test01_Test_firstTest(JNIEnv *, jobject){
   Console::WriteLine(L"第一個Jni小程序");
}

1、jni方法的各個部分所代表的的含義

JNIEXPORT void JNICALL Java_com_test01_Test_firstTest (JNIEnv * env, jobject obj);
  • JNIEXPORT :在Jni編程中所有本地語言實現(xiàn)Jni接口的方法前面都有一個"JNIEXPORT",這個可以看做是Jni的一個標志,至今為止沒發(fā)現(xiàn)它有什么特殊的用處。
  • void :這個學(xué)過編程的人都知道,當然是方法的返回值了。
  • JNICALL :這個可以理解為Jni 和Call兩個部分,和起來的意思就是 Jni調(diào)用XXX(后面的XXX就是JAVA的方法名)。
  • Java_com_test01_Test_firstTest:這個就是被上一步中被調(diào)用的部分,也就是Java中的native 方法名,這里起名字的方式比較特別,是:包名+類名+方法名。
  • JNIEnv * env:這個env可以看做是Jni接口本身的一個對象,在上一篇中提到的jni.h頭文件中存在著大量被封裝好的函數(shù),這些函數(shù)也是Jni編程中經(jīng)常被使用到的,要想調(diào)用這些函數(shù)就需要使用JNIEnv這個對象。例如:env->GetObjectClass()。(詳情請查看jni.h)
  • jobject obj:剛才在Test類的main方法中有這樣一段代碼:
    Test t=new Test();
    t.firstTest();
    這個jobject需要兩種情況分析。上段代碼中firstTest方法是一個非靜態(tài)方法,在Java中要想調(diào)用它必須先實例化對象,然后再用對象調(diào)用它,那這個時候jobject就可以看做Java類的一個實例化對象,也就是obj就是t。如果firstTest是一個靜態(tài)方法,那么在Java中,它不是屬于一個對象的,而是屬于一個類的,Java中用Test.firstTest()這樣的方式來調(diào)用,這個時候jobject就可以看做是java類的本身,也就是obj就是Test.class。

1、本地方法注冊

本地代碼的注冊方式有兩種:

  1. 在執(zhí)行本地方法前,在Java代碼里使用語句System.loadLibrary("foo")加載本地方法所有的鏈接庫;
  2. 在本地方法的實現(xiàn)里,需要用到其他鏈接庫里的本地方法時,第一種方法就不適用了,比如,在本地方法里聲明另一個本地方法void JNICALL g_impl(JNIEnv *env, jobject self);但它的實現(xiàn)是在另一個鏈接庫里實現(xiàn)的,則需要使用下面的代碼來作為這個方法的實現(xiàn):
//這里某一個本地方法里的代碼,省略了其他部分代碼
 JNINativeMethod nm;
 nm.name = "g";//需要使用的其他鏈接庫里的本地方法的名字
/* 方法的描述,如返回值,參數(shù)等 */
 nm.signature = "()V";
 nm.fnPtr = g_impl;//在這里的本地方法的聲明的名字
//注冊g_impl方法
 (*env)->RegisterNatives(env, cls, &nm, 1);

方法g_imlp的聲明并不需要遵循JNI的命名規(guī)范,因為這只是調(diào)用時的方法指針,并不需要展開代碼(調(diào)用這個方法時,實際調(diào)用的是另一個鏈接庫里名為g的JNI方法),所有不需要使用JNIEXPORT,但需要遵循JNI的調(diào)用規(guī)范。

多線程之間ENV環(huán)境變量的約束:

在本地方法里寫有關(guān)多線程的代碼時,需要知道下面幾個約束:

(注:JVM可以跨線程共享)

  1. 一個JNIEnv指針只在與它關(guān)聯(lián)的線程里有效,也就是說,在線程間傳遞JNIEnv指針和在多線程環(huán)境里通過緩存來使用它是不允許和不安全的。JVM在同一個線程里多次調(diào)用同一個本地方法時傳遞的是同一個JNIEnv指針,但在不同的線程里調(diào)用同一個本地方法時傳遞的是不同的JNIEnv指針。
  2. 本地引用只在創(chuàng)建它的線程里有效,也就是說你不能在線程間傳遞本地引用。因為在多線程的環(huán)境里可能會使用到相同的引用,因此我們需要將本地引用轉(zhuǎn)型為全局引用
    在任意線程中獲取env環(huán)境對象:
JavaVM *jvm; /* already set */
f(){
    JNIEnv *env;
    //建立當前線程的連接。將環(huán)境變量變量關(guān)聯(lián)到當前線程,也就是獲取到當前線程
    (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
    ... /* use env */

    //使用完成之后一定要調(diào)用此方法釋放jvm和當前線程的連接
    javaVM->DetachCurrentThread();
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容