日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android jni 调用java_Android JNI开发系列(九)JNI调用Java的静态方法实例方法

發布時間:2024/4/19 Android 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android jni 调用java_Android JNI开发系列(九)JNI调用Java的静态方法实例方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

JNI調用Java的靜態方法&實例方法

package org.professor.jni.bean;

import android.util.Log;

/**

* Created by peng on 2018/10/11.

*/

public class Person {

/*C/CPP 調用Java 靜態方法 */

public native void callJavaStaticMethod();

/*C/C++ 調用Java 實例方法 */

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);

}

}

上面寫了一個Java Bean類,里面定義了兩個Native方法,分別用來調用,該類的靜態方法和實例方法,實現在本地native方法里

JNI調用靜態方法

# include

# include

# include

//extern "C" // C 編譯器編譯我的代碼

JNIEXPORT void JNICALL Java_org_professor_jni_bean_Person_callJavaStaticMethod(JNIEnv *env, jobject instance) {

//1.獲取類類型的Class對象

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) 方法簽名可以通過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.調用方法

(*env)->CallStaticVoidMethod(env, personClass, pJmethodID, str, 18);

// 刪除局部變量引用表,JVM內部由于引用表,

// 記錄全局和局部的變量,當超過引用表數量,導致內存溢出

// 造成崩潰

(*env)->DeleteLocalRef(env, personClass);

(*env)->DeleteLocalRef(env, str);

}

注意:

JVM 針對所有數據類型的返回值都定義了相關的函數。上面callStaticMethod 方法的返回類型為 void,所以調用 CallStaticVoidMethod。根據返回值類型不同,JNI 提供了一系列不同返回值的函數,如:CallStaticIntMethod、CallStaticFloatMethod、CallStaticShortMethod、CallStaticObjectMethod等,分別表示調用返回值為 int、float、short、Object 類型的函數,引用類型統一調用CallStaticObjectMethod 函數。另外,每種返回值類型的函數都提供了接收3種實參類型的實現:CallStaticXXXMethod(env, clazz, methodID, ...),CallStaticXXXMethodV(env, clazz, methodID, va_list args),CallStaticXXXMethodA(env, clazz, methodID, const jvalue args),分別表示:接收可變參數列表、接收 va_list 作為實參和接收const jvalue為實參。下面是jni.h頭文件中CallStaticVoidMethod 的三種實參的函數原型: 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);

雖然函數結束后,JVM 會自動釋放所有局部引用變量所占的內存空間。但還是手動釋放一下比較安全,因為在 JVM 中維護著一個引用表,用于存儲局部和全局引用變量,經測試在 Android NDK 環境下,這個表的最大存儲空間是512 個引用,如果超過這個數就會造成引用表溢出,JVM 崩潰。在 PC 環境下測試,不管申請多少局部引用也不釋放都不會崩,我猜可能與 JVM 和 Android Dalvik 虛擬機實現方式不一樣的原因。所以有申請就及時釋放是一個好的習慣!(局部引用和全局引用在后面的文章中會詳細介紹)

JNI調用實例方法

JNIEXPORT void JNICALL Java_org_professor_jni_bean_Person_callJavaInstanceMethod(JNIEnv *env, jobject instance) {

//1.獲取類類型的Class對象

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.獲取默認的構造方法ID (; = public org.professor.jni.bean.Person(); ),先獲取構造函數的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.獲取默認構造函數對象

jobject object = (*env)->NewObject(env, personClass, constructor);

if (NULL == object) {

__android_log_print(ANDROID_LOG_ERROR, "PERSON", "NOT FIND OBJECT");

return;

}

//5.調用實例方法

(*env)->CallVoidMethod(env, object, pJmethodID, 30.0);

//6.刪除局部引用變量

(*env)->DeleteLocalRef(env, personClass);

(*env)->DeleteLocalRef(env, object);

}

擴展方法簽名表

簽名

java類型

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用/分割包的完整類名; Ljava/lang/String;

Object

例如: void set(String str); 簽名:"(Ljava/lang/String;)V"

可以用javap -s "ClassFile" 命令查看方法簽名

總結

調用靜態方法使用 CallStaticXXXMethod/V/A 函數,XXX 代表返回值的數據類型。如:CallStaticIntMethod

調用實例方法使用 CallXXXMethod/V/A 函數,XXX 代表返回的數據類型,如:`CallIntMethod

獲取一個實例方法的 ID,使用 GetMethodID 函數,傳入方法名稱和方法簽名

獲以一個靜態方法的 ID,使用 GetStaticMethodID 函數,傳入方法名稱和方法簽名

獲取構造方法 ID,方法名稱使用""

獲取一個類的 Class 實例,使用 FindClass 函數,傳入類描述符。JVM 會從 classpath 目錄下開始搜索。

創建一個類的實例,使用 NewObject 函數,傳入 Class 引用和構造方法 ID

刪除局部變量引用,使用 DeleteLocalRef, 傳入引用變量

方法簽名格式:(形參參數列表)返回值類型。注意:形參參數列表之間不需要用空格或其它字符分隔

類描述符格式:L 包名路徑/類名;,包名之間用/分隔。如:Ljava/lang/String;

調用 GetMethodID 獲取方法 ID 和調用 FindClass 獲取 Class 實例后,要做異常判斷

總結

以上是生活随笔為你收集整理的android jni 调用java_Android JNI开发系列(九)JNI调用Java的静态方法实例方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。