中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Java中JNI的使用(上)

2018-10-08    來源:importnew

容器云強(qiáng)勢上線!快速搭建集群,上萬Linux鏡像隨意使用

JNI 全稱是 Java Native Interface。是在 Java?和 Native 層(包括但不限于C/C++)相互調(diào)用的接口規(guī)范。

JNI 在 Java?1.1中正式推出,在 Java?1.2版本中加入了 JNI_OnLoad、JNI_OnUnload 方法,這兩個(gè)方法還是很有用的,后面再說。

JNI基礎(chǔ)篇

Java 通過 JNI 調(diào)用本地方法的過程大致是:

  1. 寫一個(gè) Java 類,在其中聲明對應(yīng)要調(diào)用的 native 方法,用?native?關(guān)鍵字修飾。 比如?private static native int native_newInstance();
  2. 通過?javah?命令生成 Java?類對應(yīng)的 C/C++ 頭文件。javah -encoding utf-8 -cp src com.young.soundtouch.SoundTouch;
  3. 在 C/C++ 中實(shí)現(xiàn)頭文件中聲明的函數(shù);
  4. 編譯 C/C++ 代碼為動態(tài)庫(Windows中的dll、Linux/Android 中的 so、MAC OSX 中的 dylib);
  5. 在 Java?代碼中加載動態(tài)庫,即可像調(diào)用 Java?方法一樣,調(diào)用到 native 函數(shù)。

其中第3步在 Java 1.2 中增加了?JNI_OnLoad?方法之后有另一種實(shí)現(xiàn)方式(后面說)。

javah 生成的頭文件大致是這樣的:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_young_soundtouch_SoundTouch */

#ifndef _Included_com_young_soundtouch_SoundTouch
#define _Included_com_young_soundtouch_SoundTouch
#ifdef __cplusplus
extern "C" {
#endif
#undef com_young_soundtouch_SoundTouch_SETTING_USE_AA_FILTER
#define com_young_soundtouch_SoundTouch_SETTING_USE_AA_FILTER 0L
	/*
	* Class:     com_young_soundtouch_SoundTouch
	* Method:    native_getDefaultSampleElementSize
	* Signature: ()I
	*/
	JNIEXPORT jint JNICALL Java_com_young_soundtouch_SoundTouch_native_1getDefaultSampleElementSize
		(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif

文件開頭就是普通的頭文件,但是可以發(fā)現(xiàn):

  1. 包含了 jni.h 頭文件(一般位于 $JAVA_HOME/jd{jdk-version}/include 文目錄內(nèi))。這是 JNI 中所有的類型、函數(shù)、宏等定義的地方。所以C/C++世界的JNI是由他制定的游戲規(guī)則。
  2. 在類中生命的常量(static final)類型會在頭文件中以宏的形式出現(xiàn),這一點(diǎn)還是很方便的。
  3. 函數(shù)的注釋還是比較全的,包括了:
    • 對應(yīng)的 class
    • 對應(yīng)的 Java 方法名
    • 對應(yīng)?Java?方法的簽名
  4. 方法的聲明顯得有點(diǎn)奇怪,由以下及部分組成:
    • JNIEXPORT這是函數(shù)的導(dǎo)出方式;
    • jint 返回值類型(jint 由 jni.h 定義,對應(yīng) int,下面具體再說吧);
    • JNICALL 函數(shù)的調(diào)用方式也就是匯編級別參數(shù)的傳入方式;
    • Java_com_young_soundtouch_SoundTouch_native_1getDefaultSampleElementSize —— 超級長的函數(shù)名!!格式是 Java_ + 類全名 + _ + JAVA 中聲明的native方法名。其中會把包名中的點(diǎn)(.)替換成下劃線(_),同時(shí)為了避免沖突把下劃線替換成_1;
    • 方法的參數(shù),上面的這個(gè)方法在 Java 的聲明中實(shí)際上是沒有參數(shù)的,其中的 JNIENV 顧名思義是 JNI 環(huán)境,和具體的線程綁定。而第二個(gè)參數(shù) jclass 其實(shí)是 Java 中的 Class。因?yàn)樯厦媸且粋(gè) static 方法,因此第二個(gè)參數(shù)是 jclass。如果是一個(gè)實(shí)例方法則對應(yīng)第二個(gè)參數(shù)是 jobject,相當(dāng)于 Java中的 this。

下面在 C/C++ 中實(shí)現(xiàn)這個(gè)方法就行啦。但是在動手前現(xiàn)大致了解以下 jni.h 制定的游戲規(guī)則。

類型轉(zhuǎn)換

javah 生成的頭文件里面使用的類型都是 jni.h 定義的,目的是做到平臺無關(guān),比如保證在所有平臺上 jint 都是32位的有符號整型。

基本對應(yīng)關(guān)系如下:

引用類型對應(yīng)關(guān)系:

通過表格發(fā)現(xiàn),除了上面定義的?String、Class、Throwable,其他的類(除了數(shù)組)都是以?jobject?的形式出現(xiàn)的!事實(shí)上 jstring、 jclass 也都是 object 的子類。所以這里還是和 Java 層一樣,一切皆 jobject。(當(dāng)然,如果 jni 在 C 語言中編譯的話是沒有繼承的概念的,此時(shí) jstring、jclass 等其實(shí)就是 jobject!用了 typedef 轉(zhuǎn)換而已。。

接下來是?JNIEnv *?這個(gè)指針,它提供了 JNI 中的一系列操作的接口函數(shù)。

JNI 中操作 jobject

其實(shí)也就是在native層操作 Java 層的實(shí)例。 要操作一個(gè)實(shí)例無疑是:

  1. 獲取/設(shè)置 (即 get/set )成員變量(field)的值;
  2. 調(diào)用成員方法(method)。

所以問題來了:(挖掘機(jī)技術(shù)哪家強(qiáng)?! o(*≧▽≦)ツ┏━┓ )

怎么得到 field 和 method?

通過使用?jfieldID 和 jmethodID: 在 JNI 中使用類似于放射的方式來進(jìn)行 field 和 method 的操作。JNI 中使用j fieldID 和 jmethodID 來表示成員變量和成員方法,獲取方式是:

jfieldID GetFieldID(jclass clazz, const char *name, const char *sig);
jfieldID GetStaticFieldID(jclass clazz, const char *name, const char *sig);
jmethodID GetMethodID(jclass clazz, const char *name, const char *sig);
jmethodID GetStaticMethodID(jclass clazz, const char *name, const char *sig) ;

其中最后一個(gè)參數(shù)是簽名。?獲取jclass的方法除了實(shí)用上面靜態(tài)方法的第二個(gè)參數(shù)外,還可以手動獲取。?jclass FindClass(const char *name)?需要注意的是name參數(shù),他是一個(gè)類包括包名的全稱,但是需要把包名中的點(diǎn).替換成斜杠/。(好吧,事實(shí)上我不是太明白為啥要這么做。)

有了 jfieldID 和 jmethodID 就知道狗蛋住哪了,現(xiàn)在去狗蛋家找他玩 ?(^?^*)

1. get:

  • <type> Get<type>Field(jobject , jfieldID);?即可獲得對應(yīng)的field,其中field的類型是type,可以是上面類型所敘述的任何一種
  • <type> GetStatic<type>Field(jobject , jfieldID);?同1,唯一的區(qū)別是用來獲取靜態(tài)成員。
2. set:
  • void Set<type>Field(jobject obj, jfieldID fieldID, <type> val)
  • void SetStatic<type>Field(jclass clazz, jfieldID fieldID, <type> value);

成員方法:

調(diào)用方法自然要把方法的參數(shù)傳遞進(jìn)去,JNI中實(shí)現(xiàn)了三種參數(shù)的傳遞方式:

  1. Call<type>Method(jobject obj, jmethod jmethodID, ...)?其中?...?是 C 中的可變長參數(shù),類似于?printf?那樣,可以傳遞不定長個(gè)參數(shù)。于是你可以把 Java 方法需要的參數(shù)在這里面?zhèn)鬟f進(jìn)去。
  2. Call<type>MethodV(jobject obj, jmethodID methodID, va_list args)?其中的?va_list?也是 C 中可變長參數(shù)相關(guān)的內(nèi)容(我不了解,不敢瞎說,偷懶粘一下Oracle的文檔)“Programmers place all arguments to the method in an args argument of type va_list that immediately follows the methodID argument. The CallMethodV routine accepts the arguments, and, in turn, passes them to the Java method that the programmer wishes to invoke.”
  3. Call<type>MethodA(jobject obj, jmethodID methodID, const jvalue * args)?哎!這個(gè)我知道可以說兩句 LOL ~~這里的?jvalue?通過查代碼發(fā)現(xiàn)就是 JNI 中各個(gè)數(shù)據(jù)類型的 union,所以可以使用任何類型復(fù)制!所以參數(shù)的傳入方式是通過一個(gè) jvalue 的數(shù)組,數(shù)組內(nèi)的元素可以是任何 jni 類型。

然后問題又來了:(挖掘機(jī)技術(shù)到底哪家強(qiáng)?!o(*≧▽≦)ツ┏━┓) 如果傳進(jìn)來的參數(shù)和java聲明的參數(shù)的不一致會怎么樣。床环戏椒ê灻┻@里文檔中沒用明確解釋,但是說道: > Exceptions raised during the execution of the Java method.

typedef union jvalue {
    jboolean z;
    jbyte    b;
    jchar    c;
    jshort   s;
    jint     i;
    jlong    j;
    jfloat   f;
    jdouble  d;
    jobject  l;
} jvalue;

1. 調(diào)用實(shí)例方法(instance method):

  • <type> Call<type>Method(jobject obj, jmethodID methodID, ...);?調(diào)用一個(gè)具有<type>類型返回值的方法。
  • <type> Call<type>MethodV(jobject obj, jmethodID methodID, va_list args);
  • Call<type>MethodA(jobject obj, jmethodID methodID, const jvalue * args)

2. 調(diào)用靜態(tài)方法(static method):

  • <type> CallStatic<type>Method(jobject obj, jmethodID methodID, ...);
  • <type> CallStatic<type>MethodV(jobject obj, jmethodID methodID, va_list args);
  • CallStatic<type>MethodA(jobject obj, jmethodID methodID, const jvalue * args)
3. 調(diào)用父類方法(super.method),這個(gè)就有點(diǎn)不一樣了。多了一個(gè) jclass 參數(shù),jclass 可以使 obj 的父類,也可以是 obj 自己的class,但是 methodID 必須是從 jclass 獲取到的,這樣就可以調(diào)用到父類的方法。
  • <type> CallNonvirtual<type>Method(jobject obj, jclass clazz, jmethodID methodID, ...)
  • <type> CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args);
  • <type> CallNonvirtual<type>MethodA(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue *args);

標(biāo)簽: linux 代碼

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:Java中JNI的使用(下)

下一篇:Java中如何模擬真正的同時(shí)并發(fā)請求?