目錄
第一章 介紹
第二章 設計機制
第三章 JNI類型和數據結構
第四章 JNI函數(1)
第四章 JNI函數(2)
第四章 JNI函數(3)
第四章 JNI函數(4)
第五章 Invocation API
第四章 JNI函數
4.10 訪問靜態域
GetStaticFieldID
jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
返回類的靜態域的fieldID,這個靜態域通過字段名和簽名來指定。GetStatic<type>Field
和 SetStatic<type>Field
一系列訪問函數通過該方法獲得的fieldID來獲取靜態域。
此函數可能引起未初始化(initialized)的類初始化。
參數:
-
env
:JNI接口指針 -
clazz
:java class object -
name
:靜態域的名稱 -
sig
:靜態域的簽名
返回值:
返回fieldID,無法指定的靜態域沒有找到則返回 NULL
拋出異常:
-
NoSuchFieldError
:如果指定的靜態域沒有被找到 -
ExceptionInInitializerError
:如果類在初始化的過程中出現異常。
使用實例:
imagePath_ID = env->GetStaticFieldID(clazz, "imagePath", "Ljava/lang/String;");
CHECK_EXCEPTION;
symbolPath_ID = env->GetStaticFieldID(clazz, "symbolPath", "Ljava/lang/String;");
CHECK_EXCEPTION;
以上代碼來至: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);
一系列函數用于獲取不同類型的靜態域。
參數:
-
env
:JNI接口指針 -
class
:java class對象 -
fieldId
: 靜態域的fieldId.
返回值:
返回靜態域的值。
使用實例:
jfieldID fieldID = env->GetStaticFieldID(wfClass, fieldName, signature);
return env->GetStaticObjectField(wfClass, fieldID);
以上代碼來至: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);
一系列設置不同類型靜態域的函數。
參數:
-
env
:JNI接口指針 -
class
:java class對象 -
fieldId
: 靜態域的fieldId. -
value
:靜態域的新值
返回值:
無
使用實例:
env->SetStaticBooleanField(wFlagsClassID, d3dEnabledID, d3dEnabled);
以上代碼來至:OpenJDK/jdk/src/windows/native/sun/java2d/windows/WIndowsFlags.cpp
?
?
4.11 調用靜態方法
GetStaticMethodID
jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
返回類的靜態方法的methodID,靜態方法按方法名和簽名來指定。
該方法可能引發未初始化的方法被初始化。
參數:
-
env
:JNI接口指針 -
class
:java class對象。 -
name
:靜態方法名(MUTF-8編碼字符串) -
sig
:靜態方法簽名(MUTF-8編碼字符串)
返回值:
返回靜態方法的methodID,或操作失敗返回 NULL
拋出異常:
-
NoSucMethodError
:如果指定的方法沒有被找到 -
ExceptionInInitializerError
: 如果在初始化類的過程中出現異常 -
OutOfMemoryError
; 如果系統內存不足時。
使用實例:
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);
以上代碼來至: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);
一系列調用不同類型的靜態方法的函數。
參數:
-
env
:JNI接口指針 -
clazz
: Java class對象 -
methodId
: 靜態方法methodID
返回值:
返回Java靜態方法返回的結果。
?
?
4.12 操作字符串
NewString
jstring NewString(JNIEnv *env, const jchar *unicodeChars, jsize len);
使用unicode字符串數組來構造一個 java.lang.String
對象。
參數:
-
env
:JNI接口指針 -
unicodeChars
:指向unicode字符串的指針 -
len
: unicode字符串的長度
返回值:
返回一個Java String對象,當字符串無法被構造時返回 NULL
拋出異常:
-
OutOfMemoryError
如果系統內存不足時。
使用實例:
jchar *strp = new jchar[len];
env->GetCharArrayRegion(str, off, len, strp);
jstring jstr = env->NewString(strp, len);
以上代碼來至:OpenJDK/jdk/src/windows/native/sun/windows/awt_Font.cpp
?
GetStringLength
jsize GetStringLength(JNIEnv *env, jstring string);
返回Java String的長度(unicode字符串數組的長度)
參數:
-
env
:JNI接口指針 -
string
:需要獲取長度的字符串
返回值:
Java String的長度
使用實例:
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;
以上代碼來至:OpenJDK/jdk/src/windows/native/sun/windows/awt_Window.cpp
?
GetStringChars
const jchar * GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);
返回Java String對象的unicode字符串數組的指針。這個指針一直在調用 ReleaseStringchars()
方法前都有效。
參數:
-
env
:JNI接口指針 -
string
:目標Java String對象 -
isCopy
:NULL或JNI_TRUE表示返回一份copy,JNI_FALSE表示不copy,直接返回指向Java String的原始地址
返回值:
返回unicode 字符串的指針。操作失敗而返回 NULL
使用實例:
// 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
以上代碼來至:OpenJDK/jdk/src/windows/native/sun/securty/mscapi/security.cpp
個人理解部分:
- 默認 isCopy 參數傳 NULL 即可以了,默認返回拷貝值,但如果要求返回Java String對象的原始地址,則一定不要修改它的值,否則破壞了Java String不可修改的原則。
- 先要記住jchar的定義
typedef unsigned short jchar;
- 然后了解wchat_t 寬字節, 在C語言里面的定義
typedef unsigned short wchar_t;
在C++里面則是內置類型。 - 然后要明白 unicode(UTF-16) 和 UTF-8 的區別。UTF-16永遠是雙字節,而UTF-8在英文是單字節,中文等才用雙字節。
- 在Java里面的字符串都是使用 unicode 雙字節的。GetStringChars方法返回的都是雙字節,類似C語言里面的 wchat_t 類型。
- UTF-8字符串以’\0’結尾,而Unicode字符串不是。
?
ReleaseStringChars
void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);
通知虛擬機本地代碼不再需要訪問 chars ,chars參數是一個指針,指向用 string
參數調用 GetStringChars()
方法返回的unicode字符串。
參數:
-
env
:JNI接口指針 -
string
:一個java字符串對象 -
chars
:指向unicode字符串的指針
返回值:
無
使用實例:
// 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);
以上代碼來至:OpenJDK/jdk/src/windows/native/sun/securty/mscapi/security.cpp
?
NewStringUTF
jstring NewStringUTF(JNIEnv *env, const char *bytes);
根據一個MUTF-8編碼的字符串數組(an array of characters in modified UTF-8 encodin)來構建一個 java.lang.String
對象。
參數:
-
env
:JNI接口指針 -
bytes
:指向MUTF-8編碼字符串的指針。
返回值:
返回一個Java String對象,或失敗時返回 NULL
拋出異常:
-
OutOfMemoryError
如果系統內存不足時。
使用實例:
jstring threadName = env->NewStringUTF("Serviceability Agent Command Thread");
以上代碼來至:OpenJDK/hotspot/agent/src/share/native/jvmdi/sa.cpp
?
GetStringUTFLength
jsize GetStringUTFLength(JNIEnv *env, jstring string);
返回代表字符串的MUTF-8編碼字符串數組長度(the length in bytes of the modified UTF-8 representation of a string)
參數:
-
env
:JNI接口指針 -
string
:Java String對象
返回值:
返回字符串的MUTF-8編碼字符串數組的長度。
使用實例:
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;
}
以上代碼來至:OpenJDK/hotspot/src/share/vm/prims/pref.cpp
?
GetStringUTFChars
const char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);
返回一個指針,指向代表字符串MUTF-8編碼的字節數組(an array of bytes representin the string in modified UTF-8 encoding)。這個數組的指針一個在調用 ReleaseStrinUTFChars()
前有效。
參數:
-
env
:JNI接口指針 -
string
:目標Java String對象 -
isCopy
:NULL或JNI_TRUE表示返回一份copy,JNI_FALSE表示不copy,直接返回指向Java String的原始地址
返回值:
返回指向MUTF-8字符串的指針,或失敗返回 NULL
使用實例:
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);
以上代碼來至:OpenJDK/jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp
?
ReleaseStringUTFChars
void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf);
通知Java虛擬機本地代碼不需要訪問 utf
了。這個 utf
是使用 string
調用 GetStringUTFChars
返回的指針。
參數:
-
env
:JNI接口指針 -
string
:Java String對象 -
utf
:指向MUTF-8字符串的指針
返回值:
無
使用實例:
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);
以上代碼來至:OpenJDK/jdk/src/windows/native/sun/windows/awt_Window.cpp
?
GetStringRegion
void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
從 start
偏移量開始拷貝len
個unicode字符到指定的 buf
緩存中。
參數:
-
env
:JNI接口指針 -
str
: 目標Java String對象 -
start
: 偏移量 -
len
:拷貝的長度 -
buf
: 拷貝到的目標緩存buffer
返回值:
無
拋出異常:
-
StringIndexOutOfBoundsException
當指針越界時
使用實例:
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';
以上代碼來至:OpenJDK/jdk/src/windows/native/sun/windows/awt_Window.cpp
個人理解部分:
GetStringRegion函數不需要VM來分配內存,而直接將Java字符串拷貝到C++字符串數組中,因此不需要釋放函數,也不會造成 OutOfMemoryError
?
GetStringUTFRegion
void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, char *buf);
從 start
偏移量開始拷貝len
個unicode字符,將其轉換成MUTF-8編碼,放置到指定的 buf
緩存中。
參數:
-
env
:JNI接口指針 -
str
: 目標Java String對象 -
start
: 偏移量 -
len
:拷貝的長度 -
buf
: 拷貝到的目標緩存buffer
返回值:
無
拋出異常:
-
StringIndexOutOfBoundsException
當指針越界時
使用實例:
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;
}
以上代碼來至:OpenJDK/hotspot/src/share/vm/prims/pref.cpp
個人理解部分:
GetStringUTFRegion函數不需要VM來分配內存,而直接將Java字符串拷貝到C++字符串數組中,因此不需要釋放函數,也不會造成 OutOfMemoryError
?
GetStringCritical
const jchar * GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy);
和GetStringChars函數類似,如果可能,Java虛擬機會返回內部指向字符串元素的指針,否則返回一個復制值。但不管怎樣,GetStringCritical
和 ReleaseStringCritical
這些函數的使用必須非常小心,在這兩個函數之間,本地代碼必須不能調用任何可能阻塞當前線程的JNI函數。
參數:
-
env
:JNI接口指針 -
jstring
: 目標Java字符串對象 -
isCopy
:是否復制值。
返回值:
虛擬機內部指向字符串元素的指針。
使用實例:
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之間是一個關鍵區。
* 在這關鍵區之中,絕對不能呼叫JNI的其他函數和會造成當前線程中斷或是會讓當前線程等待的任何本地代碼,
* 否則將造成關鍵區代碼執行區間垃圾回收器停止運作,任何觸發垃圾回收器的線程也會暫停。
* 其他觸發垃圾回收器的線程不能前進直到當前線程結束而激活垃圾回收器。
*/
c_str = (*env)->GetStringCritical(env,j_str,NULL); // 返回源字符串指針的可能性
if (c_str == NULL) // 驗證是否因為字符串拷貝內存溢出而返回NULL
{
return NULL;
}
while(*c_str)
{
*pBuff++ = *c_str++;
}
(*env)->ReleaseStringCritical(env,j_str,c_str);
return (*env)->NewStringUTF(env,buff);
}
以下為個人理解部分:
因為僅從文檔說明,這兩個函數較為難以理解,所以這里摘抄一段網上的說明文字:
Get/ReleaseStringChars和Get/ReleaseStringUTFChars這對函數返回的源字符串會后分配內存,如果有一個字符串內容相當大,有1M左右,而且只需要讀取里面的內容打印出來,用這兩對函數就有些不太合適了。此時用Get/ReleaseStringCritical可直接返回源字符串的指針應該是一個比較合適的方式。不過這對函數有一個很大的限制,在這兩個函數之間的本地代碼不能調用任何會讓線程阻塞或等待JVM中其它線程的本地函數或JNI函數。因為通過GetStringCritical得到的是一個指向JVM內部字符串的直接指針,獲取這個直接指針后會導致暫停GC線程,當GC被暫停后,如果其它線程觸發GC繼續運行的話,都會導致阻塞調用者。所以在Get/ReleaseStringCritical這對函數中間的任何本地代碼都不可以執行導致阻塞的調用或為新對象在JVM中分配內存,否則,JVM有可能死鎖。另外一定要記住檢查是否因為內存溢出而導致它的返回值為NULL,因為JVM在執行GetStringCritical這個函數時,仍有發生數據復制的可能性,尤其是當JVM內部存儲的數組不連續時,為了返回一個指向連續內存空間的指針,JVM必須復制所有數據。
?
ReleaseStringCritical
void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray);
釋放由 GetStringCritical
函數調用獲得的字符串指針。
參數:
-
env
:JNI接口指針 -
string
:字符串對象 -
carray
: 獲取到的字符串指針。
返回值:
無
?
4.13 操作數組
GetArrayLength
jsize GetArrayLength(JNIEnv *env, jarray array);
返回數組(array)的元素個數。
參數:
-
env
:JNI接口指針 -
array
:目標Java數組對象
返回值:
返回數組的長度
使用實例:
int length = env->GetArrayLength(andMask);
jbyte *andMaskPtr = new jbyte[length];
env->GetByteArrayRegion(andMask, 0, length, andMaskPtr);
以上代碼來至:awt_Cursor.cpp (openjdk\jdk\src\windows\native\sun\windows)
?
NewObjectArray
jobjectArray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement);
構造一個新的 elementClass
類型的數組,并設置其初始值。
參數:
-
env
:JNI接口指針 -
length
:數組長度 -
elementClass
:數組元素的class -
initialElement
:初始化數組元素
返回值:
返回一個Java數組對象,如果數組不能被構造則返回 NULL
。
拋出異常:
-
OutOfMemoryError
:如果系統內存不足時。
使用實例:
clauseReading = env->NewObjectArray(cClause, JNU_ClassString(env), NULL);
for (int i =0; i < cClause; i++) {
env->SetObjectArrayElement(clauseReading, i, rgClauseReading[i]);
}
以上代碼來至:awt_Component.cpp (openjdk\jdk\src\windows\native\sun\windows)
?
GetObjectArrayElement
jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index);
返回數組的index處的元素對象。
參數:
-
env
:JNI接口指針 -
array
:Java數組 -
index
:數組下標
返回值:
返回一個Java對象。
拋出異常:
-
ArrayIndexOutOfBoundsException
: 如果index數組越界時。
使用實例:
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();
}
以上代碼來至:awt_Choice.cpp (openjdk\jdk\src\windows\native\sun\windows)
?
SetObjectArrayElement
void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value);
設置數組的某個值。
參數:
-
env
:JNI接口指針 -
array
:一個Java數組 -
index
:數組下標 -
value
:設置的新值
返回值:
無
拋出異常:*
-
ArrayIndexOutOfBoundsException
,如果index
數組越界時。 -
ArrayStoreException
,如果value
類型錯誤時。
使用實例:
clauseReading = env->NewObjectArray(cClause, JNU_ClassString(env), NULL);
for (int i =0; i < cClause; i++) {
env->SetObjectArrayElement(clauseReading, i, rgClauseReading[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);
一組函數用于構造各種不同基本類型的數組對象。
參數:
-
env
:JNI接口指針 -
length
:數組長度
返回值:
返回Java數組,數組無法被構造則返回 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);
一組函數用于獲取各種不同基本類型數組的元素。
返回的結構在調用相應的 Release<Type>ArrayElements()
之前一直有效。因為返回的可能是一個復制值,因此對于返回值的修改不一定會對原始數組產生影響,直到調用了相應的 Release<Type>ArrayElements()
才可能影響到原始數組。
參數:
-
env
:JNI接口指針 -
array
:目標數組 -
isCopy
:NULL
或JNI_FALSE
不COPY,JNI_TRUE
返回COPY值。
返回值:
返回數組某個元素的指針。或失敗返回 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);
一組函數通知虛擬機本地代碼不再需要訪問數組中的元素。這些元素是使用 Get<type>ArrayElements
函數來獲取的,如果需要,這個函數會把修改后的內容復制到原始的數組中。使用最后一個參數 mode 來控制:
-
mode = 0
, 將內容復制回原始數組,并釋放elems
(通常情況下都傳入0即可) -
mode = JNI_COMMIT
,將內容復制回原始數組,但不釋放elems
-
mode = JNI_ABORT
,不將內容復制回原始數組,并釋放elems
參數:
-
env
:JNI接口指針
返回值:
無
?
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);
一組函數用來復制基本類型數據的一部分值到buffer。
參數:
-
env
:JNI接口指針 -
array
:java數組 -
start
:起始的下標 -
len
:需要復制的元素個數 -
buf
:目標buffer
返回值:
無
拋出異常:
-
ArrayIndexOutOfBoundsException
:如果數組越界時。
使用實例:
(*env)->GetBooleanArrayRegion(env, jArray, 0, *ckpLength, jpTemp);
if ((*env)->ExceptionCheck(env)) {
free(jpTemp);
return;
}
以上代碼來至:
?
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復制回基本類型數組的函數。
參數:
-
env
:JNI接口指針 -
array
:java數組 -
start
:起始的下標 -
len
:需要復制的元素個數 -
buf
:數據源buffer
返回值:
無
拋出異常:
-
ArrayIndexOutOfBoundsException
:如果數組越界時。
?
GetPrimitiveArrayCritical
void * GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy);
和 Get<type>ArrayElements
函數類似,但如果可能的話,Java虛擬機會返回一個基本類型數組的原始指針,否則返回一個copy值得指針。
GetPrimitiveArrayCritical
和 ReleasePrimitiveArrayCritical
這些函數的使用必須非常小心,在這兩個函數之間,本地代碼必須不能調用任何可能阻塞當前線程以等待其他Java線程的JNI函數,或任何系統調用。(例如,當前線程不能 read
一個另一個Java線程正在寫入的流。)
參數:
-
env
:JNI接口指針 -
array
:目標數組 -
isCopy
:JNI_TRUE
復制值,JNI_FALSE
不復制。
返回值:
無
?
ReleasePrimitiveArrayCritical
void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode);
釋放由 GetPrimitiveArrayCritical
函數獲取的數組原始指針。
參數:
-
env
:JNI接口指針 -
array
:目標數組 -
carray
: 之前獲取的原始數組指針 -
mode
:0
或JNI_COMMIT
或JNI_ABORT
返回值:
無
使用實例:
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 注冊本地方法
RegisterNatives
jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods);
給clazz注冊一個本地方法。
JNINativeMethod定義為:
typedef struct {
char *name;
char *signature;
void *fnPtr;
} JNINativeMethod;
這些本地函數必須至少有2個參數,且前2個參數必須依次是:JNIEnv *env
,jobject objectOrClass
例如:
jstring nativeFunc(JNIEnv* env, jobject thiz)
{
return env->NewStrinUTF("Hello world from native method!");
}
參數:
-
env
:JNI接口指針 -
clazz
:指定的java class對象 -
methods
:原生方法列表 -
nMethods
: 原生方法列表數量
返回值:
成功返回0, 失敗返回負數
拋出異常:
-
NoSuchMethodError
: 如果指定的方法沒有找到,或者方法不是native。
使用實例:
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)
{
//注冊本地方法.Load 目標類
clazz = (*env)->FindClass(env,classPathName);
if (clazz == NULL)
{
LOGE("Native registration unable to find class '%s'", classPathName);
return JNI_ERR;
}
//注冊本地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;
}
以上代碼來至:http://blog.chinaunix.net/uid-26009923-id-3410141.html
?
UnregisterNatives
jint UnregisterNatives(JNIEnv *env, jclass clazz);
注銷一個類的所有本地方法,這個類會回到之前被鏈接或注冊本地方法之前的狀態。
這個函數不應該在一般的本地代碼中使用。
參數:
-
env
:JNI接口指針 -
clazz
:java class對象
返回值:
成功返回0, 失敗返回負數。
使用實例:
jclass jClass = env->FindClass(JNI_AN_MainActivity);
env->UnregisterNatives(jClass);
env->DeleteLocalRef(jClass);
?