android jni 调用java_Android JNI开发系列(九)JNI调用Java的静态方法实例方法
JNI調(diào)用Java的靜態(tài)方法&實(shí)例方法
package org.professor.jni.bean;
import android.util.Log;
/**
* Created by peng on 2018/10/11.
*/
public class Person {
/*C/CPP 調(diào)用Java 靜態(tài)方法 */
public native void callJavaStaticMethod();
/*C/C++ 調(diào)用Java 實(shí)例方法 */
public native void callJavaInstanceMethod();
public static void setPersonInfo(String name, int age) { Log.i("PERSON", "name= " + name + "\\t age=" + age); }
public void setPersonMoney(float money) { Log.i("PERSON", "money= " + money);
}
}
上面寫(xiě)了一個(gè)Java Bean類(lèi),里面定義了兩個(gè)Native方法,分別用來(lái)調(diào)用,該類(lèi)的靜態(tài)方法和實(shí)例方法,實(shí)現(xiàn)在本地native方法里
JNI調(diào)用靜態(tài)方法
# include
# include
# include
//extern "C" // C 編譯器編譯我的代碼
JNIEXPORT void JNICALL Java_org_professor_jni_bean_Person_callJavaStaticMethod(JNIEnv *env, jobject instance) {
//1.獲取類(lèi)類(lèi)型的Class對(duì)象
jclass personClass = (*env)->FindClass(env, "org/professor/jni/Person");
if (NULL == personClass) {
__android_log_print(ANDROID_LOG_ERROR, "PERSON", "NOT FIND CLASS");
return;
}
//2.獲取方法ID 方法簽名:(String:Ljava/lang/String ;int:I) 方法簽名可以通過(guò)javap -s命令生成
jmethodID pJmethodID = (*env)->GetStaticMethodID(env, personClass, "setPersonInfo",
"(Ljava/lang/String;I)V");
if (NULL == pJmethodID) {
__android_log_print(ANDROID_LOG_ERROR, "PERSON", "NOT FIND STATIC METHOD");
return;
}
jstring str = (*env)->NewStringUTF(env, "Yimi");
//3.調(diào)用方法
(*env)->CallStaticVoidMethod(env, personClass, pJmethodID, str, 18);
// 刪除局部變量引用表,JVM內(nèi)部由于引用表,
// 記錄全局和局部的變量,當(dāng)超過(guò)引用表數(shù)量,導(dǎo)致內(nèi)存溢出
// 造成崩潰
(*env)->DeleteLocalRef(env, personClass);
(*env)->DeleteLocalRef(env, str);
}
注意:
JVM 針對(duì)所有數(shù)據(jù)類(lèi)型的返回值都定義了相關(guān)的函數(shù)。上面callStaticMethod 方法的返回類(lèi)型為 void,所以調(diào)用 CallStaticVoidMethod。根據(jù)返回值類(lèi)型不同,JNI 提供了一系列不同返回值的函數(shù),如:CallStaticIntMethod、CallStaticFloatMethod、CallStaticShortMethod、CallStaticObjectMethod等,分別表示調(diào)用返回值為 int、float、short、Object 類(lèi)型的函數(shù),引用類(lèi)型統(tǒng)一調(diào)用CallStaticObjectMethod 函數(shù)。另外,每種返回值類(lèi)型的函數(shù)都提供了接收3種實(shí)參類(lèi)型的實(shí)現(xiàn):CallStaticXXXMethod(env, clazz, methodID, ...),CallStaticXXXMethodV(env, clazz, methodID, va_list args),CallStaticXXXMethodA(env, clazz, methodID, const jvalue args),分別表示:接收可變參數(shù)列表、接收 va_list 作為實(shí)參和接收const jvalue為實(shí)參。下面是jni.h頭文件中CallStaticVoidMethod 的三種實(shí)參的函數(shù)原型: void (JNICALL *CallStaticVoidMethod) (JNIEnv *env, jclass cls, jmethodID methodID, ...);
void (JNICALL *CallStaticVoidMethodV) (JNIEnv *env, jclass cls, jmethodID methodID, va_list args);
void (JNICALL *CallStaticVoidMethodA) (JNIEnv *env, jclass cls, jmethodID methodID, const jvalue * args);
雖然函數(shù)結(jié)束后,JVM 會(huì)自動(dòng)釋放所有局部引用變量所占的內(nèi)存空間。但還是手動(dòng)釋放一下比較安全,因?yàn)樵?JVM 中維護(hù)著一個(gè)引用表,用于存儲(chǔ)局部和全局引用變量,經(jīng)測(cè)試在 Android NDK 環(huán)境下,這個(gè)表的最大存儲(chǔ)空間是512 個(gè)引用,如果超過(guò)這個(gè)數(shù)就會(huì)造成引用表溢出,JVM 崩潰。在 PC 環(huán)境下測(cè)試,不管申請(qǐng)多少局部引用也不釋放都不會(huì)崩,我猜可能與 JVM 和 Android Dalvik 虛擬機(jī)實(shí)現(xiàn)方式不一樣的原因。所以有申請(qǐng)就及時(shí)釋放是一個(gè)好的習(xí)慣!(局部引用和全局引用在后面的文章中會(huì)詳細(xì)介紹)
JNI調(diào)用實(shí)例方法
JNIEXPORT void JNICALL Java_org_professor_jni_bean_Person_callJavaInstanceMethod(JNIEnv *env, jobject instance) {
//1.獲取類(lèi)類(lèi)型的Class對(duì)象
jclass personClass = (*env)->FindClass(env, "org/professor/jni/Person");
if (NULL == personClass) {
__android_log_print(ANDROID_LOG_ERROR, "PERSON", "NOT FIND CLASS");
return;
}
//2.獲取方法ID 方法簽名:(String:Ljava/lang/String ;int:I)
jmethodID pJmethodID = (*env)->GetMethodID(env, personClass, "setPersonMoney",
"(F)V");
if (NULL == pJmethodID) {
__android_log_print(ANDROID_LOG_ERROR, "PERSON", "NOT FIND INSTANCE METHOD");
return;
}
//3.獲取默認(rèn)的構(gòu)造方法ID (; = public org.professor.jni.bean.Person(); ),先獲取構(gòu)造函數(shù)的ID
jmethodID constructor = (*env)->GetMethodID(env, personClass, "", "()V");
if (NULL == constructor) {
__android_log_print(ANDROID_LOG_ERROR, "PERSON", "NOT FIND INSTANCE CONSTRUCTOR METHOD");
return;
}
//4.獲取默認(rèn)構(gòu)造函數(shù)對(duì)象
jobject object = (*env)->NewObject(env, personClass, constructor);
if (NULL == object) {
__android_log_print(ANDROID_LOG_ERROR, "PERSON", "NOT FIND OBJECT");
return;
}
//5.調(diào)用實(shí)例方法
(*env)->CallVoidMethod(env, object, pJmethodID, 30.0);
//6.刪除局部引用變量
(*env)->DeleteLocalRef(env, personClass);
(*env)->DeleteLocalRef(env, object);
}
擴(kuò)展方法簽名表
簽名
java類(lèi)型
V
void
Z
boolean
I
int
J
long
D
double
F
float
B
byte
C
char
S
short
[I
int[]
[F
float[]
[B
byte[]
[C
char[]
[S
short[]
[D
double[]
[J
long[]
[Z
boolean[]
L用/分割包的完整類(lèi)名; Ljava/lang/String;
Object
例如: void set(String str); 簽名:"(Ljava/lang/String;)V"
可以用javap -s "ClassFile" 命令查看方法簽名
總結(jié)
調(diào)用靜態(tài)方法使用 CallStaticXXXMethod/V/A 函數(shù),XXX 代表返回值的數(shù)據(jù)類(lèi)型。如:CallStaticIntMethod
調(diào)用實(shí)例方法使用 CallXXXMethod/V/A 函數(shù),XXX 代表返回的數(shù)據(jù)類(lèi)型,如:`CallIntMethod
獲取一個(gè)實(shí)例方法的 ID,使用 GetMethodID 函數(shù),傳入方法名稱(chēng)和方法簽名
獲以一個(gè)靜態(tài)方法的 ID,使用 GetStaticMethodID 函數(shù),傳入方法名稱(chēng)和方法簽名
獲取構(gòu)造方法 ID,方法名稱(chēng)使用""
獲取一個(gè)類(lèi)的 Class 實(shí)例,使用 FindClass 函數(shù),傳入類(lèi)描述符。JVM 會(huì)從 classpath 目錄下開(kāi)始搜索。
創(chuàng)建一個(gè)類(lèi)的實(shí)例,使用 NewObject 函數(shù),傳入 Class 引用和構(gòu)造方法 ID
刪除局部變量引用,使用 DeleteLocalRef, 傳入引用變量
方法簽名格式:(形參參數(shù)列表)返回值類(lèi)型。注意:形參參數(shù)列表之間不需要用空格或其它字符分隔
類(lèi)描述符格式:L 包名路徑/類(lèi)名;,包名之間用/分隔。如:Ljava/lang/String;
調(diào)用 GetMethodID 獲取方法 ID 和調(diào)用 FindClass 獲取 Class 實(shí)例后,要做異常判斷
總結(jié)
以上是生活随笔為你收集整理的android jni 调用java_Android JNI开发系列(九)JNI调用Java的静态方法实例方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 登录mysql报错2059_navica
- 下一篇: redis java驱动_Redis学习