JNI技術(shù)規(guī)范 - 第四章 JNI函數(shù)(3)

目錄

第一章 介紹
第二章 設(shè)計(jì)機(jī)制
第三章 JNI類型和數(shù)據(jù)結(jié)構(gòu)
第四章 JNI函數(shù)(1)
第四章 JNI函數(shù)(2)
第四章 JNI函數(shù)(3)
第四章 JNI函數(shù)(4)
第五章 Invocation API

第四章 JNI函數(shù)

4.10 訪問(wèn)靜態(tài)域

GetStaticFieldID

jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);

返回類的靜態(tài)域的fieldID,這個(gè)靜態(tài)域通過(guò)字段名和簽名來(lái)指定。GetStatic<type>FieldSetStatic<type>Field 一系列訪問(wèn)函數(shù)通過(guò)該方法獲得的fieldID來(lái)獲取靜態(tài)域。

此函數(shù)可能引起未初始化(initialized)的類初始化窝撵。

參數(shù):

  • env :JNI接口指針
  • clazz :java class object
  • name:靜態(tài)域的名稱
  • sig :靜態(tài)域的簽名

返回值:

返回fieldID踪少,無(wú)法指定的靜態(tài)域沒(méi)有找到則返回 NULL

拋出異常:

  • NoSuchFieldError :如果指定的靜態(tài)域沒(méi)有被找到
  • ExceptionInInitializerError:如果類在初始化的過(guò)程中出現(xiàn)異常豁遭。

使用實(shí)例:

  imagePath_ID = env->GetStaticFieldID(clazz, "imagePath", "Ljava/lang/String;");
  CHECK_EXCEPTION;

  symbolPath_ID = env->GetStaticFieldID(clazz, "symbolPath", "Ljava/lang/String;");
  CHECK_EXCEPTION;

以上代碼來(lái)至:OpenJDK/hotspot/agent/src/os.win32/windbg/sawindbg.cpp

?

GetStatic<type>Field

jobject GetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID);
jboolean GetStaticBooleanField(JNIEnv *env, jclass clazz, jfieldID fieldID);
jbyte GetStaticByteField(JNIEnv *env, jclass clazz, jfieldID fieldID);
jchar GetStaticCharField(JNIEnv *env, jclass clazz, jfieldID fieldID);
jshort GetStaticShortField(JNIEnv *env, jclass clazz, jfieldID fieldID);
jint GetStaticIntField(JNIEnv *env, jclass clazz, jfieldID fieldID);
jlong GetStaticLongField(JNIEnv *env, jclass clazz, jfieldID fieldID);
jfloat GetStaticFloatField(JNIEnv *env, jclass clazz, jfieldID fieldID);
jdouble GetStaticDoubleField(JNIEnv *env, jclass clazz, jfieldID fieldID);

一系列函數(shù)用于獲取不同類型的靜態(tài)域难捌。

參數(shù):

  • env :JNI接口指針
  • class:java class對(duì)象
  • fieldId: 靜態(tài)域的fieldId.

返回值:

返回靜態(tài)域的值。

使用實(shí)例:

jfieldID fieldID = env->GetStaticFieldID(wfClass, fieldName, signature);
return env->GetStaticObjectField(wfClass, fieldID);

以上代碼來(lái)至:OpenJDK/jdk/src/windows/native/sun/java2d/windows/WindowsFlags.cpp

?

SetStatic<type>Field

void SetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value);
void SetStaticBooleanField(JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value);
void SetStaticByteField(JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value);
void SetStaticCharField(JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value);
void SetStaticShortField(JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value);
void SetStaticIntField(JNIEnv *env, jclass clazz, jfieldID fieldID, jint value);
void SetStaticLongField(JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value);
void SetStaticFloatField(JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value);
void SetStaticDoubleField(JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value);

一系列設(shè)置不同類型靜態(tài)域的函數(shù)跨晴。

參數(shù):

  • env :JNI接口指針
  • class:java class對(duì)象
  • fieldId: 靜態(tài)域的fieldId.
  • value:靜態(tài)域的新值

返回值:

無(wú)

使用實(shí)例:

env->SetStaticBooleanField(wFlagsClassID, d3dEnabledID, d3dEnabled);

以上代碼來(lái)至:OpenJDK/jdk/src/windows/native/sun/java2d/windows/WIndowsFlags.cpp

?

?

4.11 調(diào)用靜態(tài)方法

GetStaticMethodID

jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);

返回類的靜態(tài)方法的methodID欧聘,靜態(tài)方法按方法名和簽名來(lái)指定。

該方法可能引發(fā)未初始化的方法被初始化端盆。

參數(shù):

  • env :JNI接口指針
  • class:java class對(duì)象怀骤。
  • name:靜態(tài)方法名(MUTF-8編碼字符串)
  • sig:靜態(tài)方法簽名(MUTF-8編碼字符串)

返回值:

返回靜態(tài)方法的methodID费封,或操作失敗返回 NULL

拋出異常:

  • NoSucMethodError :如果指定的方法沒(méi)有被找到
  • ExceptionInInitializerError: 如果在初始化類的過(guò)程中出現(xiàn)異常
  • OutOfMemoryError ; 如果系統(tǒng)內(nèi)存不足時(shí)晒喷。

使用實(shí)例:

if (AwtCursor::updateCursorID == NULL) {
    jclass cls = env->FindClass("sun/awt/windows/WGlobalCursorManager");
    AwtCursor::globalCursorManagerClass =(jclass)env->NewGlobalRef(cls);
    AwtCursor::updateCursorID =env->GetStaticMethodID(cls, "nativeUpdateCursor", 
                                                      "(Ljava/awt/Component;)V");
    DASSERT(AwtCursor::globalCursorManagerClass != NULL);
    DASSERT(AwtCursor::updateCursorID != NULL);
}

env->CallStaticVoidMethod(AwtCursor::globalCursorManagerClass,
                          AwtCursor::updateCursorID, jcomp);

以上代碼來(lái)至:OpenJDK/jdk/src/windows/native/sun/windows/awt_Cursor.cpp

?

CallStatic<type>Method(MethodA, MethodV)

NativeType CallStatic<type>Method(JNIEnv *env, jclass clazz, jmethodID methodID, ...);

NativeType CallStatic<type>MethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);

NativeType CallStatic<type>MethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

一系列調(diào)用不同類型的靜態(tài)方法的函數(shù)。

參數(shù):

  • env :JNI接口指針
  • clazz: Java class對(duì)象
  • methodId: 靜態(tài)方法methodID

返回值:

返回Java靜態(tài)方法返回的結(jié)果访敌。

?

?

4.12 操作字符串

NewString

jstring NewString(JNIEnv *env, const jchar *unicodeChars, jsize len);

使用unicode字符串?dāng)?shù)組來(lái)構(gòu)造一個(gè) java.lang.String 對(duì)象凉敲。

參數(shù):

  • env :JNI接口指針
  • unicodeChars :指向unicode字符串的指針
  • len : unicode字符串的長(zhǎng)度

返回值:

返回一個(gè)Java String對(duì)象,當(dāng)字符串無(wú)法被構(gòu)造時(shí)返回 NULL

拋出異常:

  • OutOfMemoryError 如果系統(tǒng)內(nèi)存不足時(shí)寺旺。

使用實(shí)例:

jchar *strp = new jchar[len];
env->GetCharArrayRegion(str, off, len, strp);
jstring jstr = env->NewString(strp, len);

以上代碼來(lái)至:OpenJDK/jdk/src/windows/native/sun/windows/awt_Font.cpp

?

GetStringLength

jsize GetStringLength(JNIEnv *env, jstring string);

返回Java String的長(zhǎng)度(unicode字符串?dāng)?shù)組的長(zhǎng)度)

參數(shù):

  • env :JNI接口指針
  • string:需要獲取長(zhǎng)度的字符串

返回值:

Java String的長(zhǎng)度

使用實(shí)例:

int length = env->GetStringLength(title);
TCHAR *buffer = new TCHAR[length + 1];
env->GetStringRegion(title, 0, length, reinterpret_cast<jchar*>(buffer));
buffer[length] = L'\0';
VERIFY(::SetWindowText(w->GetHWnd(), buffer));
delete[] buffer;

以上代碼來(lái)至:OpenJDK/jdk/src/windows/native/sun/windows/awt_Window.cpp

?

GetStringChars

const jchar * GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);

返回Java String對(duì)象的unicode字符串?dāng)?shù)組的指針爷抓。這個(gè)指針一直在調(diào)用 ReleaseStringchars() 方法前都有效。

參數(shù):

  • env :JNI接口指針
  • string:目標(biāo)Java String對(duì)象
  • isCopy :NULL或JNI_TRUE表示返回一份copy阻塑,JNI_FALSE表示不copy蓝撇,直接返回指向Java String的原始地址

返回值:

返回unicode 字符串的指針。操作失敗而返回 NULL

使用實(shí)例:

// Set the certificate's friendly name
int size = env->GetStringLength(jCertAliasName);
pszCertAliasName = new WCHAR[size + 1];

jCertAliasChars = env->GetStringChars(jCertAliasName, NULL);
memcpy(pszCertAliasName, jCertAliasChars, size * sizeof(WCHAR));
pszCertAliasName[size] = 0; // append the string terminator

以上代碼來(lái)至:OpenJDK/jdk/src/windows/native/sun/securty/mscapi/security.cpp

個(gè)人理解部分:

  1. 默認(rèn) isCopy 參數(shù)傳 NULL 即可以了陈莽,默認(rèn)返回拷貝值渤昌,但如果要求返回Java String對(duì)象的原始地址,則一定不要修改它的值走搁,否則破壞了Java String不可修改的原則独柑。
  2. 先要記住jchar的定義 typedef unsigned short jchar;
  3. 然后了解wchat_t 寬字節(jié), 在C語(yǔ)言里面的定義 typedef unsigned short wchar_t; 在C++里面則是內(nèi)置類型私植。
  4. 然后要明白 unicode(UTF-16) 和 UTF-8 的區(qū)別忌栅。UTF-16永遠(yuǎn)是雙字節(jié),而UTF-8在英文是單字節(jié)曲稼,中文等才用雙字節(jié)索绪。
  5. 在Java里面的字符串都是使用 unicode 雙字節(jié)的。GetStringChars方法返回的都是雙字節(jié)贫悄,類似C語(yǔ)言里面的 wchat_t 類型瑞驱。
  6. UTF-8字符串以’\0’結(jié)尾,而Unicode字符串不是窄坦。

?

ReleaseStringChars

void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);

通知虛擬機(jī)本地代碼不再需要訪問(wèn) chars 钱烟,chars參數(shù)是一個(gè)指針,指向用 string 參數(shù)調(diào)用 GetStringChars() 方法返回的unicode字符串嫡丙。

參數(shù):

  • env :JNI接口指針
  • string:一個(gè)java字符串對(duì)象
  • chars:指向unicode字符串的指針

返回值:

無(wú)

使用實(shí)例:

// jstring jCertAliasName

// Set the certificate's friendly name
int size = env->GetStringLength(jCertAliasName);
pszCertAliasName = new WCHAR[size + 1];

jCertAliasChars = env->GetStringChars(jCertAliasName, NULL);
memcpy(pszCertAliasName, jCertAliasChars, size * sizeof(WCHAR));
pszCertAliasName[size] = 0; // append the string terminator

CRYPT_DATA_BLOB friendlyName = {
  sizeof(WCHAR) * (size + 1),
  (BYTE *) pszCertAliasName
};

env->ReleaseStringChars(jCertAliasName, jCertAliasChars);

以上代碼來(lái)至:OpenJDK/jdk/src/windows/native/sun/securty/mscapi/security.cpp

?

NewStringUTF

jstring NewStringUTF(JNIEnv *env, const char *bytes);

根據(jù)一個(gè)MUTF-8編碼的字符串?dāng)?shù)組(an array of characters in modified UTF-8 encodin)來(lái)構(gòu)建一個(gè) java.lang.String對(duì)象拴袭。

參數(shù):

  • env :JNI接口指針
  • bytes:指向MUTF-8編碼字符串的指針。

返回值:

返回一個(gè)Java String對(duì)象曙博,或失敗時(shí)返回 NULL

拋出異常:

  • OutOfMemoryError 如果系統(tǒng)內(nèi)存不足時(shí)拥刻。

使用實(shí)例:

jstring threadName = env->NewStringUTF("Serviceability Agent Command Thread");

以上代碼來(lái)至:OpenJDK/hotspot/agent/src/share/native/jvmdi/sa.cpp

?

GetStringUTFLength

jsize GetStringUTFLength(JNIEnv *env, jstring string);

返回代表字符串的MUTF-8編碼字符串?dāng)?shù)組長(zhǎng)度(the length in bytes of the modified UTF-8 representation of a string)

參數(shù):

  • env :JNI接口指針
  • string:Java String對(duì)象

返回值:

返回字符串的MUTF-8編碼字符串?dāng)?shù)組的長(zhǎng)度。

使用實(shí)例:

static char* jstr_to_utf(JNIEnv *env, jstring str, TRAPS) {

  char* utfstr = NULL;

  if (str == NULL) {
    THROW_0(vmSymbols::java_lang_NullPointerException());
    //throw_new(env,"NullPointerException");
  }

  int len = env->GetStringUTFLength(str);
  int unicode_len = env->GetStringLength(str);

  utfstr = NEW_RESOURCE_ARRAY(char, len + 1);

  env->GetStringUTFRegion(str, 0, unicode_len, utfstr);

  return utfstr;
}

以上代碼來(lái)至:OpenJDK/hotspot/src/share/vm/prims/pref.cpp

?

GetStringUTFChars

const char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);

返回一個(gè)指針父泳,指向代表字符串MUTF-8編碼的字節(jié)數(shù)組(an array of bytes representin the string in modified UTF-8 encoding)般哼。這個(gè)數(shù)組的指針一個(gè)在調(diào)用 ReleaseStrinUTFChars()前有效吴汪。

參數(shù):

  • env :JNI接口指針
  • string:目標(biāo)Java String對(duì)象
  • isCopy :NULL或JNI_TRUE表示返回一份copy,JNI_FALSE表示不copy蒸眠,直接返回指向Java String的原始地址

返回值:

返回指向MUTF-8字符串的指針漾橙,或失敗返回 NULL

使用實(shí)例:

const char* prop  = env->GetStringUTFChars(pProp, JNI_FALSE);
const char* value = env->GetStringUTFChars(pValue, JNI_FALSE);
jboolean   retval = uPtr->set_option(prop, value);
env->ReleaseStringUTFChars(pProp,  prop);
env->ReleaseStringUTFChars(pValue, value);

以上代碼來(lái)至:OpenJDK/jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp

?

ReleaseStringUTFChars

void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf);

通知Java虛擬機(jī)本地代碼不需要訪問(wèn) utf 了。這個(gè) utf 是使用 string 調(diào)用 GetStringUTFChars 返回的指針楞卡。

參數(shù):

  • env :JNI接口指針
  • string:Java String對(duì)象
  • utf:指向MUTF-8字符串的指針

返回值:

無(wú)

使用實(shí)例:

    jstring value = (jstring)env->CallObjectMethod(type, windowTypeNameMID);
    if (value == NULL) {
        env->DeleteLocalRef(type);
        return;
    }

    const char* valueNative = env->GetStringUTFChars(value, 0);
    if (valueNative == NULL) {
        env->DeleteLocalRef(value);
        env->DeleteLocalRef(type);
        return;
    }

    // ...

    env->ReleaseStringUTFChars(value, valueNative);
    env->DeleteLocalRef(value);
    env->DeleteLocalRef(type);

以上代碼來(lái)至:OpenJDK/jdk/src/windows/native/sun/windows/awt_Window.cpp

?

GetStringRegion

void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);

start 偏移量開(kāi)始拷貝len 個(gè)unicode字符到指定的 buf 緩存中霜运。

參數(shù):

  • env :JNI接口指針
  • str: 目標(biāo)Java String對(duì)象
  • start : 偏移量
  • len:拷貝的長(zhǎng)度
  • buf : 拷貝到的目標(biāo)緩存buffer

返回值:

無(wú)

拋出異常:

  • StringIndexOutOfBoundsException 當(dāng)指針越界時(shí)

使用實(shí)例:

size_t length = env->GetStringLength(javaWarningString) + 1;
warningString = new WCHAR[length];
env->GetStringRegion(javaWarningString, 0,
                     static_cast<jsize>(length - 1), reinterpret_cast<jchar*>(warningString));
warningString[length-1] = L'\0';

以上代碼來(lái)至:OpenJDK/jdk/src/windows/native/sun/windows/awt_Window.cpp

個(gè)人理解部分:

GetStringRegion函數(shù)不需要VM來(lái)分配內(nèi)存,而直接將Java字符串拷貝到C++字符串?dāng)?shù)組中蒋腮,因此不需要釋放函數(shù)淘捡,也不會(huì)造成 OutOfMemoryError

?

GetStringUTFRegion

void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, char *buf);

start 偏移量開(kāi)始拷貝len 個(gè)unicode字符,將其轉(zhuǎn)換成MUTF-8編碼池摧,放置到指定的 buf 緩存中焦除。

參數(shù):

  • env :JNI接口指針
  • str: 目標(biāo)Java String對(duì)象
  • start : 偏移量
  • len:拷貝的長(zhǎng)度
  • buf : 拷貝到的目標(biāo)緩存buffer

返回值:

無(wú)

拋出異常:

  • StringIndexOutOfBoundsException 當(dāng)指針越界時(shí)

使用實(shí)例:

static char* jstr_to_utf(JNIEnv *env, jstring str, TRAPS) {

  char* utfstr = NULL;

  if (str == NULL) {
    THROW_0(vmSymbols::java_lang_NullPointerException());
    //throw_new(env,"NullPointerException");
  }

  int len = env->GetStringUTFLength(str);
  int unicode_len = env->GetStringLength(str);

  utfstr = NEW_RESOURCE_ARRAY(char, len + 1);

  env->GetStringUTFRegion(str, 0, unicode_len, utfstr);

  return utfstr;
}

以上代碼來(lái)至:OpenJDK/hotspot/src/share/vm/prims/pref.cpp

個(gè)人理解部分:

GetStringUTFRegion函數(shù)不需要VM來(lái)分配內(nèi)存,而直接將Java字符串拷貝到C++字符串?dāng)?shù)組中作彤,因此不需要釋放函數(shù)膘魄,也不會(huì)造成 OutOfMemoryError

?

GetStringCritical

const jchar * GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy);

和GetStringChars函數(shù)類似,如果可能竭讳,Java虛擬機(jī)會(huì)返回內(nèi)部指向字符串元素的指針瓣距,否則返回一個(gè)復(fù)制值。但不管怎樣代咸,GetStringCriticalReleaseStringCritical 這些函數(shù)的使用必須非常小心蹈丸,在這兩個(gè)函數(shù)之間,本地代碼必須不能調(diào)用任何可能阻塞當(dāng)前線程的JNI函數(shù)呐芥。

參數(shù):

  • env :JNI接口指針
  • jstring : 目標(biāo)Java字符串對(duì)象
  • isCopy :是否復(fù)制值逻杖。

返回值:

虛擬機(jī)內(nèi)部指向字符串元素的指針。

使用實(shí)例:

JNIEXPORT jstring JNICALL Java_com_study_jnilearn_Sample_sayHello
  (JNIEnv *env, jclass cls, jstring j_str)
{
    const jchar* c_str= NULL;
    char buff[128] = hello ;
    char* pBuff = buff + 6;
    /*
     * 在GetStringCritical/RealeaseStringCritical之間是一個(gè)關(guān)鍵區(qū)思瘟。
     * 在這關(guān)鍵區(qū)之中,絕對(duì)不能呼叫JNI的其他函數(shù)和會(huì)造成當(dāng)前線程中斷或是會(huì)讓當(dāng)前線程等待的任何本地代碼荸百,
     * 否則將造成關(guān)鍵區(qū)代碼執(zhí)行區(qū)間垃圾回收器停止運(yùn)作,任何觸發(fā)垃圾回收器的線程也會(huì)暫停滨攻。
     * 其他觸發(fā)垃圾回收器的線程不能前進(jìn)直到當(dāng)前線程結(jié)束而激活垃圾回收器够话。
     */
    c_str = (*env)->GetStringCritical(env,j_str,NULL);   // 返回源字符串指針的可能性
    if (c_str == NULL)  // 驗(yàn)證是否因?yàn)樽址截悆?nèi)存溢出而返回NULL
    {
        return NULL;
    }
    while(*c_str) 
    {
        *pBuff++ = *c_str++;
    }
    (*env)->ReleaseStringCritical(env,j_str,c_str);
    return (*env)->NewStringUTF(env,buff);
}

以上代碼來(lái)至:http://www.2cto.com/kf/201412/364156.html

以下為個(gè)人理解部分:

因?yàn)閮H從文檔說(shuō)明,這兩個(gè)函數(shù)較為難以理解光绕,所以這里摘抄一段網(wǎng)上的說(shuō)明文字:

Get/ReleaseStringChars和Get/ReleaseStringUTFChars這對(duì)函數(shù)返回的源字符串會(huì)后分配內(nèi)存女嘲,如果有一個(gè)字符串內(nèi)容相當(dāng)大,有1M左右诞帐,而且只需要讀取里面的內(nèi)容打印出來(lái)欣尼,用這兩對(duì)函數(shù)就有些不太合適了。此時(shí)用Get/ReleaseStringCritical可直接返回源字符串的指針應(yīng)該是一個(gè)比較合適的方式停蕉。不過(guò)這對(duì)函數(shù)有一個(gè)很大的限制愕鼓,在這兩個(gè)函數(shù)之間的本地代碼不能調(diào)用任何會(huì)讓線程阻塞或等待JVM中其它線程的本地函數(shù)或JNI函數(shù)钙态。因?yàn)橥ㄟ^(guò)GetStringCritical得到的是一個(gè)指向JVM內(nèi)部字符串的直接指針,獲取這個(gè)直接指針后會(huì)導(dǎo)致暫停GC線程菇晃,當(dāng)GC被暫停后册倒,如果其它線程觸發(fā)GC繼續(xù)運(yùn)行的話,都會(huì)導(dǎo)致阻塞調(diào)用者磺送。所以在Get/ReleaseStringCritical這對(duì)函數(shù)中間的任何本地代碼都不可以執(zhí)行導(dǎo)致阻塞的調(diào)用或?yàn)樾聦?duì)象在JVM中分配內(nèi)存驻子,否則,JVM有可能死鎖册着。另外一定要記住檢查是否因?yàn)閮?nèi)存溢出而導(dǎo)致它的返回值為NULL拴孤,因?yàn)镴VM在執(zhí)行GetStringCritical這個(gè)函數(shù)時(shí)脾歧,仍有發(fā)生數(shù)據(jù)復(fù)制的可能性甲捏,尤其是當(dāng)JVM內(nèi)部存儲(chǔ)的數(shù)組不連續(xù)時(shí),為了返回一個(gè)指向連續(xù)內(nèi)存空間的指針鞭执,JVM必須復(fù)制所有數(shù)據(jù)司顿。

來(lái)源:http://www.2cto.com/kf/201412/364156.html

?

ReleaseStringCritical

void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray);

釋放由 GetStringCritical 函數(shù)調(diào)用獲得的字符串指針。

參數(shù):

  • env :JNI接口指針
  • string:字符串對(duì)象
  • carray: 獲取到的字符串指針兄纺。

返回值:

無(wú)

?

4.13 操作數(shù)組

GetArrayLength

jsize GetArrayLength(JNIEnv *env, jarray array);

返回?cái)?shù)組(array)的元素個(gè)數(shù)大溜。

參數(shù):

  • env :JNI接口指針
  • array:目標(biāo)Java數(shù)組對(duì)象

返回值:

返回?cái)?shù)組的長(zhǎng)度

使用實(shí)例:

    int length = env->GetArrayLength(andMask);
    jbyte *andMaskPtr = new jbyte[length];
    env->GetByteArrayRegion(andMask, 0, length, andMaskPtr);

以上代碼來(lái)至:awt_Cursor.cpp (openjdk\jdk\src\windows\native\sun\windows)

?

NewObjectArray

jobjectArray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement);

構(gòu)造一個(gè)新的 elementClass 類型的數(shù)組,并設(shè)置其初始值估脆。

參數(shù):

  • env :JNI接口指針
  • length:數(shù)組長(zhǎng)度
  • elementClass :數(shù)組元素的class
  • initialElement:初始化數(shù)組元素

返回值:

返回一個(gè)Java數(shù)組對(duì)象钦奋,如果數(shù)組不能被構(gòu)造則返回 NULL

拋出異常:

  • OutOfMemoryError :如果系統(tǒng)內(nèi)存不足時(shí)疙赠。

使用實(shí)例:

clauseReading = env->NewObjectArray(cClause, JNU_ClassString(env), NULL);
for (int i  =0; i < cClause; i++) {
  env->SetObjectArrayElement(clauseReading, i, rgClauseReading[i]);
}

以上代碼來(lái)至:awt_Component.cpp (openjdk\jdk\src\windows\native\sun\windows)

?

GetObjectArrayElement

jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index);

返回?cái)?shù)組的index處的元素對(duì)象付材。

參數(shù):

  • env :JNI接口指針
  • array:Java數(shù)組
  • index:數(shù)組下標(biāo)

返回值:

返回一個(gè)Java對(duì)象。

拋出異常:

  • ArrayIndexOutOfBoundsException: 如果index數(shù)組越界時(shí)圃阳。

使用實(shí)例:

        jsize i;
        int itemCount = env->GetArrayLength(items);
        if (itemCount > 0) {
           c->SendMessage(WM_SETREDRAW, (WPARAM)FALSE, 0);
           for (i = 0; i < itemCount; i++)
           {
               jstring item = (jstring)env->GetObjectArrayElement(items, i);
               JNI_CHECK_NULL_GOTO(item, "null item", next_elem);
               c->SendMessage(CB_INSERTSTRING, index + i, JavaStringBuffer(env, item));
               env->DeleteLocalRef(item);
next_elem:
               ;
           }
           c->SendMessage(WM_SETREDRAW, (WPARAM)TRUE, 0);
           InvalidateRect(c->GetHWnd(), NULL, TRUE);
           c->ResetDropDownHeight();
           c->VerifyState();
        }

以上代碼來(lái)至:awt_Choice.cpp (openjdk\jdk\src\windows\native\sun\windows)

?

SetObjectArrayElement

void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value);

設(shè)置數(shù)組的某個(gè)值厌衔。

參數(shù):

  • env :JNI接口指針
  • array:一個(gè)Java數(shù)組
  • index:數(shù)組下標(biāo)
  • value:設(shè)置的新值

返回值:

無(wú)

拋出異常:*

  • ArrayIndexOutOfBoundsException ,如果 index 數(shù)組越界時(shí)捍岳。
  • ArrayStoreException 富寿,如果 value 類型錯(cuò)誤時(shí)。

使用實(shí)例:

clauseReading = env->NewObjectArray(cClause, JNU_ClassString(env), NULL);
for (int i  =0; i < cClause; i++) {
  env->SetObjectArrayElement(clauseReading, i, rgClauseReading[i]);
}

以上代碼來(lái)至:awt_Component.cpp (openjdk\jdk\src\windows\native\sun\windows)

?

New<PrimitiveType>Array

jbooleanArray NewBooleanArray(JNIEnv *env, jsize length);
jbyteArray NewByteArray(JNIEnv *env, jsize length);
jcharArray NewCharArray(JNIEnv *env, jsize length);
jshortArray NewShortArray(JNIEnv *env, jsize length);
jintArray NewIntArray(JNIEnv *env, jsize length);
jlongArray NewLongArray(JNIEnv *env, jsize length);
jfloatArray NewFloatArray(JNIEnv *env, jsize length);
jdoubleArray NewDoubleArray(JNIEnv *env, jsize length);

一組函數(shù)用于構(gòu)造各種不同基本類型的數(shù)組對(duì)象锣夹。

參數(shù):

  • env :JNI接口指針
  • length:數(shù)組長(zhǎng)度

返回值:

返回Java數(shù)組页徐,數(shù)組無(wú)法被構(gòu)造則返回 NULL

?

Get<PrimitiveType>ArrayElements

jboolean GetBooleanArrayElements(JNIEnv *env, jbooleanArray array, jboolean *isCopy);
jbyte GetByteArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy);
jchar GetCharArrayElements(JNIEnv *env, jcharArray array, jboolean *isCopy);
jshort GetShortArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy);
jint GetIntArrayElements(JNIEnv *env, jintArray array, jboolean *isCopy);
jlong GetLongArrayElements(JNIEnv *env, jlongArray array, jboolean *isCopy);
jfloat GetFloatArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy);
jdouble GetDoubleArrayElements(JNIEnv *env, jdoubleArray array, jboolean *isCopy);

一組函數(shù)用于獲取各種不同基本類型數(shù)組的元素银萍。

返回的結(jié)構(gòu)在調(diào)用相應(yīng)的 Release<Type>ArrayElements() 之前一直有效泞坦。因?yàn)榉祷氐目赡苁且粋€(gè)復(fù)制值,因此對(duì)于返回值的修改不一定會(huì)對(duì)原始數(shù)組產(chǎn)生影響砖顷,直到調(diào)用了相應(yīng)的 Release<Type>ArrayElements() 才可能影響到原始數(shù)組贰锁。

參數(shù):

  • env :JNI接口指針
  • array:目標(biāo)數(shù)組
  • isCopy: NULLJNI_FALSE 不COPY赃梧,JNI_TRUE 返回COPY值。

返回值:

返回?cái)?shù)組某個(gè)元素的指針豌熄∈卩郑或失敗返回 NULL

?

Release<PrimitiveType>ArrayElements

void ReleaseBooleanArrayElements(JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode);
void ReleaseByteArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode);
void ReleaseCharArrayElements(JNIEnv *env, jcharArray array, jchar *elems, jint mode);
void ReleaseShortArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode);
void ReleaseIntArrayElements(JNIEnv *env, jintArray array, jint *elems, jint mode);
void ReleaseLongArrayElements(JNIEnv *env, jlongArray array, jlong *elems, jint mode);
void ReleaseFloatArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode);
void ReleaseDoubleArrayElements(JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode);

一組函數(shù)通知虛擬機(jī)本地代碼不再需要訪問(wèn)數(shù)組中的元素锣险。這些元素是使用 Get<type>ArrayElements函數(shù)來(lái)獲取的蹄皱,如果需要,這個(gè)函數(shù)會(huì)把修改后的內(nèi)容復(fù)制到原始的數(shù)組中芯肤。使用最后一個(gè)參數(shù) mode 來(lái)控制:

  • mode = 0 , 將內(nèi)容復(fù)制回原始數(shù)組巷折,并釋放 elems (通常情況下都傳入0即可)
  • mode = JNI_COMMIT ,將內(nèi)容復(fù)制回原始數(shù)組崖咨,但不釋放 elems
  • mode = JNI_ABORT 锻拘,不將內(nèi)容復(fù)制回原始數(shù)組,并釋放 elems

參數(shù):

  • env :JNI接口指針

返回值:

無(wú)

?

Get<PrimitiveType>ArrayRegion

void GetBooleanArrayRegion(JNIEnv *env, jbooleanArray array, jsize start, jsize len,  jboolean *buf);
void GetByteArrayRegion(JNIEnv *env, jbyteArray array, jsize start, jsize len,  jbyte *buf);
void GetCharArrayRegion(JNIEnv *env, jcharArray array, jsize start, jsize len,  jchar *buf);
void GetShortArrayRegion(JNIEnv *env, jshortArray array, jsize start, jsize len,  jshort *buf);
void GetIntArrayRegion(JNIEnv *env, jintArray array, jsize start, jsize len,  jint *buf);
void GetLongArrayRegion(JNIEnv *env, jlongArray array, jsize start, jsize len,  jlong  *buf);
void GetFloatArrayRegion(JNIEnv *env, jfloatArray array, jsize start, jsize len,  jfloat *buf);
void GetDoubleArrayRegion(JNIEnv *env, jdoubleArray array, jsize start, jsize len,  jdouble *buf);

一組函數(shù)用來(lái)復(fù)制基本類型數(shù)據(jù)的一部分值到buffer击蹲。

參數(shù):

  • env :JNI接口指針
  • array:java數(shù)組
  • start :起始的下標(biāo)
  • len:需要復(fù)制的元素個(gè)數(shù)
  • buf:目標(biāo)buffer

返回值:

無(wú)

拋出異常:

  • ArrayIndexOutOfBoundsException :如果數(shù)組越界時(shí)署拟。

使用實(shí)例:

    (*env)->GetBooleanArrayRegion(env, jArray, 0, *ckpLength, jpTemp);
    if ((*env)->ExceptionCheck(env)) {
        free(jpTemp);
        return;
    }

以上代碼來(lái)至:

?

Set<PrimitiveType>ArrayRegion

void SetBooleanArrayRegion(JNIEnv *env, jbooleanArray array, jsize start, jsize len, const jboolean *buf);
void SetByteArrayRegion(JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf);
void SetCharArrayRegion(JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf);
void SetShortArrayRegion(JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf);
void SetIntArrayRegion(JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf);
void SetLongArrayRegion(JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong  *buf);
void SetFloatArrayRegion(JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf);
void SetDoubleArrayRegion(JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf);

一組從buffer復(fù)制回基本類型數(shù)組的函數(shù)。

參數(shù):

  • env :JNI接口指針
  • array:java數(shù)組
  • start :起始的下標(biāo)
  • len:需要復(fù)制的元素個(gè)數(shù)
  • buf:數(shù)據(jù)源buffer

返回值:

無(wú)

拋出異常:

  • ArrayIndexOutOfBoundsException :如果數(shù)組越界時(shí)歌豺。

?

GetPrimitiveArrayCritical

void * GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy);

Get<type>ArrayElements 函數(shù)類似推穷,但如果可能的話,Java虛擬機(jī)會(huì)返回一個(gè)基本類型數(shù)組的原始指針类咧,否則返回一個(gè)copy值得指針馒铃。

GetPrimitiveArrayCriticalReleasePrimitiveArrayCritical 這些函數(shù)的使用必須非常小心,在這兩個(gè)函數(shù)之間痕惋,本地代碼必須不能調(diào)用任何可能阻塞當(dāng)前線程以等待其他Java線程的JNI函數(shù)区宇,或任何系統(tǒng)調(diào)用。(例如血巍,當(dāng)前線程不能 read一個(gè)另一個(gè)Java線程正在寫入的流萧锉。)

參數(shù):

  • env :JNI接口指針
  • array:目標(biāo)數(shù)組
  • isCopyJNI_TRUE復(fù)制值,JNI_FALSE不復(fù)制述寡。

返回值:

無(wú)

?

ReleasePrimitiveArrayCritical

void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode);

釋放由 GetPrimitiveArrayCritical函數(shù)獲取的數(shù)組原始指針柿隙。

參數(shù):

  • env :JNI接口指針
  • array:目標(biāo)數(shù)組
  • carray: 之前獲取的原始數(shù)組指針
  • mode0JNI_COMMITJNI_ABORT

返回值:

無(wú)

使用實(shí)例:

  jint len = (*env)->GetArrayLength(env, arr1);
  jbyte *a1 = (*env)->GetPrimitiveArrayCritical(env, arr1, 0);
  jbyte *a2 = (*env)->GetPrimitiveArrayCritical(env, arr2, 0);
  /* We need to check in case the VM tried to make a copy. */
  if (a1 == NULL || a2 == NULL) {
    ... /* out of memory exception thrown */
  }
  memcpy(a1, a2, len);
  (*env)->ReleasePrimitiveArrayCritical(env, arr2, a2, 0);
  (*env)->ReleasePrimitiveArrayCritical(env, arr1, a1, 0);

?

?

4.14 注冊(cè)本地方法

RegisterNatives

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

給clazz注冊(cè)一個(gè)本地方法。

JNINativeMethod定義為:

typedef struct {
  char *name;
  char *signature;
  void *fnPtr;
} JNINativeMethod;

這些本地函數(shù)必須至少有2個(gè)參數(shù)鲫凶,且前2個(gè)參數(shù)必須依次是:JNIEnv *env 禀崖,jobject objectOrClass

例如:

jstring nativeFunc(JNIEnv* env, jobject thiz)
{
    return env->NewStrinUTF("Hello world from native method!");    
}

參數(shù):

  • env :JNI接口指針
  • clazz:指定的java class對(duì)象
  • methods:原生方法列表
  • nMethods: 原生方法列表數(shù)量

返回值:

成功返回0, 失敗返回負(fù)數(shù)

拋出異常:

  • NoSuchMethodError: 如果指定的方法沒(méi)有找到螟炫,或者方法不是native波附。

使用實(shí)例:

jstring native_stringFromJNI( JNIEnv* env, jobject thiz )
{
    return (*env)->NewStringUTF(env, "Hello from JNI !");
}
static const char *classPathName = "com/example/hellojni/HelloJni";

static JNINativeMethod methods[] = {
        {"stringFromJNI", "()Ljava/lang/String;", (void*)native_stringFromJNI},
};

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    //注冊(cè)本地方法.Load 目標(biāo)類
    clazz = (*env)->FindClass(env,classPathName);
    if (clazz == NULL)
    {
        LOGE("Native registration unable to find class '%s'", classPathName);
        return JNI_ERR;
    }
    //注冊(cè)本地native方法
    if((*env)->RegisterNatives(env, clazz, methods, NELEM(methods)) < 0)
    {
        LOGE("ERROR: MediaPlayer native registration failed\n");
           return JNI_ERR;
    }
    return JNI_VERSION_1_6; 
}

以上代碼來(lái)至:http://blog.chinaunix.net/uid-26009923-id-3410141.html

?

UnregisterNatives

jint UnregisterNatives(JNIEnv *env, jclass clazz);

注銷一個(gè)類的所有本地方法,這個(gè)類會(huì)回到之前被鏈接或注冊(cè)本地方法之前的狀態(tài)。

這個(gè)函數(shù)不應(yīng)該在一般的本地代碼中使用掸屡。

參數(shù):

  • env :JNI接口指針
  • clazz:java class對(duì)象

返回值:

成功返回0封寞, 失敗返回負(fù)數(shù)。

使用實(shí)例:

jclass jClass = env->FindClass(JNI_AN_MainActivity);
env->UnregisterNatives(jClass);
env->DeleteLocalRef(jClass);

以上代碼來(lái)至:https://github.com/Hackerofshi/DemoJNI-master/blob/01d974076bb157f6257a81ee52e70db4b96e8802/app/src/main/jni/jni_lib.cpp

?

第四章 JNI函數(shù)(4)
?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末仅财,一起剝皮案震驚了整個(gè)濱河市狈究,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盏求,老刑警劉巖抖锥,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異碎罚,居然都是意外死亡磅废,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門荆烈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拯勉,“玉大人,你說(shuō)我怎么就攤上這事耙考∶蘸埃” “怎么了潭兽?”我有些...
    開(kāi)封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵倦始,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我山卦,道長(zhǎng)鞋邑,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任账蓉,我火速辦了婚禮枚碗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘铸本。我一直安慰自己肮雨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布箱玷。 她就那樣靜靜地躺著怨规,像睡著了一般。 火紅的嫁衣襯著肌膚如雪锡足。 梳的紋絲不亂的頭發(fā)上波丰,一...
    開(kāi)封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音舶得,去河邊找鬼掰烟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的纫骑。 我是一名探鬼主播蝎亚,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼先馆!你這毒婦竟也來(lái)了颖对?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤磨隘,失蹤者是張志新(化名)和其女友劉穎缤底,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體番捂,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡个唧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了设预。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片徙歼。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鳖枕,靈堂內(nèi)的尸體忽然破棺而出魄梯,到底是詐尸還是另有隱情,我是刑警寧澤宾符,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布酿秸,位于F島的核電站,受9級(jí)特大地震影響魏烫,放射性物質(zhì)發(fā)生泄漏辣苏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一哄褒、第九天 我趴在偏房一處隱蔽的房頂上張望稀蟋。 院中可真熱鬧,春花似錦呐赡、人聲如沸退客。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)萌狂。三九已至,卻和暖如春管闷,著一層夾襖步出監(jiān)牢的瞬間粥脚,已是汗流浹背班套。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工卷拘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留同廉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓浆熔,卻偏偏與公主長(zhǎng)得像咖楣,于是被迫代替她去往敵國(guó)和親亿驾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子黄娘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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