標籤:出錯 rto param find value 意義 cpp ons 參數
https://my.oschina.net/zhiweiofli/blog/114064
通過使用合適的JNI函數,你可以建立Java對象,get、set 靜態(static)和 執行個體(instance)的域,調用靜態(static)和執行個體(instance)函數。JNI通過ID識別域和方法,一個域或方法的ID是任何處理域和方法的函數的必須參數。
下表列出了用以得到靜態(static)和執行個體(instance)的域與方法的JNI函數。每個函數接受(作為參數)域或方法的類,它們的名稱,符號和它們對應返回的jfieldID或jmethodID。
| 函數 |
描述 |
| GetFieldID |
得到一個執行個體的域的ID |
| GetStaticFieldID |
得到一個靜態域的ID |
| GetMethodID |
得到一個執行個體的方法的ID |
| GetStaticMethodID |
得到一個靜態方法的ID |
構造一個Java對象的執行個體
jclass cls = (*env)->FindClass(env, "Lpackagename/classname;"); //建立一個class的引用jmethodID id = (*env)->GetMethodID(env, cls, "", "(D)V"); //注意這裡方法的名稱是"",它表示這是一個建構函式,而且構造參數是double型的jobject obj = (*env)->NewObjectA(env, cls, id, args); //獲得一執行個體,args是建構函式的參數,它是一個jvalue*類型。
首先是獲得一個Java類的class引用 (*env)->FindClass(env, "Lpackagename/classname;"); 請注意參數:Lpackagename/classname; ,L代表這是在描述一個物件類型,packagename/classname是該對象耳朵class路徑,請注意一定要以分號(;)結束!
然後是擷取函數的id,jmethodID id = env->GetMethodID(cls, "", "(D)V"); 第一個是剛剛獲得的class引用,第二個是方法的名稱,最後一個就是方法的簽名了
還是不懂?我曾經如此,請接著看...
難理解的函數簽名
JNINativeMethod的定義如下:
typedef struct { const char* name; const char* signature; void* fnPtr;} JNINativeMethod;
第一個變數name是Java中函數的名字。
第二個變數signature,用字串是描述了函數的參數和傳回值
第三個變數fnPtr是函數指標,指向C函數。
其中比較難以理解的是第二個參數,例如
"()V"
"(II)V"
"(Ljava/lang/String;Ljava/lang/String;)V"
實際上這些字元是與函數的參數類型一一對應的。
"()" 中的字元表示參數,後面的則代表傳回值。例如"()V" 就表示void Func();
"(II)V" 表示 void Func(int, int);
那其他情況呢?請查看下錶:
| 類型 |
符號 |
| boolean |
Z |
| byte |
B |
| char |
C |
| short |
S |
| int |
I |
| long |
L |
| float |
F |
| double |
D |
| void |
V |
| object對象 |
LClassName; L類名; |
| Arrays |
[array-type [數群組類型 |
| methods方法 |
(argument-types)return-type (參數類型)傳回型別 |
稍稍補充一下:
1、方法參數或者傳回值為java中的對象時,簽名中必須以“L”加上其路徑,不過此路徑必須以“/”分開,自訂的對象也使用本規則
比如說 java.lang.String為“java/lang/String”,com.nedu.jni.helloword.Student為"Lcom /nedu/jni/helloword/Student;"
2、方法參數或者傳回值為數群組類型時,請前加上[
例如[I表示 int[],[[[D表示 double[][][],即幾維數組就加幾個[
在本地方法中調用Java對象的方法1、擷取你需要訪問的Java對象的類:
jclass cls = (*env)->GetObjectClass(env, obj); // 使用GetObjectClass方法擷取obj對應的jclass。 jclass cls = (*env)->FindClass(“android/util/log”) // 直接搜尋類名,需要是static修飾的類。
2、擷取MethodID:
jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "(I)V"); //GetStaticMethodID(…),擷取靜態方法的ID使用GetMethdoID方法擷取你要使用的方法的MethdoID
其參數的意義:
env-->JNIEnv
cls-->第一步擷取的jclass
"callback"-->要調用的方法名
"(I)V"-->方法的Signature, 簽名同前面的JNI規則。
3、調用方法:
(*env)->CallVoidMethod(env, obj, mid, depth);// CallStaticIntMethod(….) , 調用靜態方法
使用CallVoidMethod方法調用方法。參數的意義:
env-->JNIEnv
obj-->通過本地方法穿過來的jobject
mid-->要調用的MethodID(即第二步獲得的MethodID)
depth-->方法需要的參數(對應方法的需求,添加相應的參數)
註:這裡使用的是CallVoidMethod方法調用,因為沒有傳回值,如果有傳回值的話使用對應的方法,在後面會提到。
CallVoidMethod CallStaticVoidMethodCallIntMethod CallStaticVoidMethodCallBooleanMethod CallStaticVoidMethodCallByteMethod CallStaticVoidMethod
現在稍稍明白文章開始構造Java對象那個執行個體了吧?讓我們繼續深入一下:
Jni操作Java的String對象
從java程式中傳過去的String對象在本地方法中對應的是jstring類型,jstring類型和c中的char*不同,所以如果你直接當做char*使用的話,就會出錯。因此在使用之前需要將jstring轉換成為c/c++中的char*,這裡使用JNIEnv提供的方法轉換。
const char *str = (*env)->GetStringUTFChars(env, jstr, 0);(*env)->ReleaseStringUTFChars(env, jstr, str);
這裡使用GetStringUTFChars方法將傳進來的prompt(jstring類型)轉換成為UTF-8的格式,就能夠在本地方法中使用了。
注意:在使用完你所轉換之後的對象之後,需要顯示調用ReleaseStringUTFChars方法,讓JVM釋放轉換成UTF-8的string的對象的空間,如果不顯示的調用的話,JVM中會一直儲存該對象,不會被記憶體回收行程回收,因此就會導致記憶體溢出。
下面是Jni訪問String對象的一些方法:
- GetStringUTFChars 將jstring轉換成為UTF-8格式的char*
- GetStringChars 將jstring轉換成為Unicode格式的char*
- ReleaseStringUTFChars 釋放指向UTF-8格式的char*的指標
- ReleaseStringChars 釋放指向Unicode格式的char*的指標
- NewStringUTF 建立一個UTF-8格式的String對象
- NewString 建立一個Unicode格式的String對象
- GetStringUTFLength 擷取UTF-8格式的char*的長度
- GetStringLength 擷取Unicode格式的char*的長度
下面提供兩個String對象和char*互轉的方法:
/* c/c++ string turn to java jstring */jstring charToJstring(JNIEnv* env, const char* pat){jclass strClass = (*env)->FindClass(env, "java/lang/String");jmethodID ctorID = (*env)->GetMethodID(env, strClass, "", "([BLjava/lang/String;)V");jbyteArray bytes = (*env)->NewByteArray(env, strlen(pat));(*env)->SetByteArrayRegion(env, bytes, 0, strlen(pat), (jbyte*)pat);jstring encoding = (*env)->NewStringUTF(env, "UTF-8");return (jstring)(*env)->NewObject(env, strClass, ctorID, bytes, encoding);}/* java jstring turn to c/c++ char* */char* jstringToChar(JNIEnv* env, jstring jstr){ char* pStr = NULL; jclass jstrObj = (*env)->FindClass(env, "java/lang/String"); jstring encode = (*env)->NewStringUTF(env, "utf-8"); jmethodID methodId = (*env)->GetMethodID(env, jstrObj, "getBytes", "(Ljava/lang/String;)[B"); jbyteArray byteArray = (jbyteArray)(*env)->CallObjectMethod(env, jstr, methodId, encode); jsize strLen = (*env)->GetArrayLength(env, byteArray); jbyte *jBuf = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE); if (jBuf > 0) { pStr = (char*)malloc(strLen + 1); if (!pStr) { return NULL; } memcpy(pStr, jBuf, strLen); pStr[strLen] = 0; } env->ReleaseByteArrayElements(byteArray, jBuf, 0); return pStr;}
本文轉自Zhiweiofli‘s Blog,轉載請註明出處,謝謝。
Android NDK開發之Jni調用Java對象