android jni 中jnienv,android JNI中JNIEnv類型和jobject類型的解釋
JNIEXPORT void JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv *env, jobject obj)
{
cout<
}
對(duì)於這個(gè)方法參數(shù)中的JNIEnv* env參數(shù)的解釋:
JNIEnv類型實(shí)際上代表了Java環(huán)境,通過這個(gè)JNIEnv* 指針,就可以對(duì)Java端的代碼進(jìn)行操作。例如,創(chuàng)建Java類中的對(duì)象,調(diào)用Java對(duì)象的方法,獲取Java對(duì)象中的屬性等等。JNIEnv的指針會(huì)被JNI傳入到本地方法的實(shí)現(xiàn)函數(shù)中來對(duì)Java端的代碼進(jìn)行操作。
JNIEnv類中有很多函數(shù)可以用:
NewObject:創(chuàng)建Java類中的對(duì)象
NewString:創(chuàng)建Java類中的String對(duì)象
NewArray:創(chuàng)建類型為Type的數(shù)組對(duì)象
GetField:獲取類型為Type的字段
SetField:設(shè)置類型為Type的字段的值
GetStaticField:獲取類型為Type的static的字段
SetStaticField:設(shè)置類型為Type的static的字段的值
CallMethod:調(diào)用返回類型為Type的方法
CallStaticMethod:調(diào)用返回值類型為Type的static方法
等許多的函數(shù),具體的可以查看jni.h文件中的函數(shù)名稱。
參數(shù):jobject obj的解釋:
如果native方法不是static的話,這個(gè)obj就代表這個(gè)native方法的類實(shí)例
如果native方法是static的話,這個(gè)obj就代表這個(gè)native方法的類的class對(duì)象實(shí)例(static方法不需要類實(shí)例的,所以就代表這個(gè)類的class對(duì)象)
下面來看一下Java和C++中的基本類型的映射關(guān)系:
為了能夠在C/C++中使用Java類,jni.h頭文件中專門定義了jclass類型來表示Java中的Class類
JNIEnv類中有如下幾個(gè)簡(jiǎn)單的函數(shù)可以取得jclass:
jclass FindClass(const char* clsName):通過類的名稱(類的全名,這時(shí)候包名不是用.號(hào),而是用/來區(qū)分的)來獲取jclass
如: jclass str= env->FindClass("java/lang/String");獲取Java中的String對(duì)象的class對(duì)象。
jclass GetObjectClass(jobject obj):通過對(duì)象實(shí)例來獲取jclass,相當(dāng)於java中的getClass方法
jclass GetSuperClass(jclass obj):通過jclass可以獲取其父類的jclass對(duì)象
在C/C++本地代碼中訪問Java端的代碼,一個(gè)常見的應(yīng)用就是獲取類的屬性和調(diào)用類的方法,為了在C/C++中表示屬性和方法,JNI在jni.h頭文件中定義了jfieldId,jmethodID類型來分別代表Java端的屬性和方法
我們?cè)谠L問,或者設(shè)置Java屬性的時(shí)候,首先就要先在本地代碼取得代表該Java屬性的jfieldID,然后才能在本地代碼中進(jìn)行Java屬性操作,同樣的,我們需要呼叫Java端的方法時(shí),也是需要取得代表該方法的jmethodID才能進(jìn)行Java方法調(diào)用
使用JNIEnv的:
GetFieldID/GetMethodID
GetStaticFieldID/GetStaticMethodID
來取得相應(yīng)的jfieldID和jmethodID
下面來具體看一下這幾個(gè)方法:
GetFieldID(jclass clazz,const char* name,const char* sign)
方法的參數(shù)說明:
clazz:這個(gè)簡(jiǎn)單就是這個(gè)方法依賴的類對(duì)象的class對(duì)象
name:這個(gè)是這個(gè)字段的名稱
sign:這個(gè)是這個(gè)字段的簽名(我們知道每個(gè)變量,每個(gè)方法都是有簽名的)
GetMethodID也能夠取得構(gòu)造函數(shù)的jmethodID,創(chuàng)建一個(gè)Java對(duì)象時(shí)可以調(diào)用指定的構(gòu)造方法,這個(gè)將在后面向大家介紹:
如:env->GetMethodID(data_Class,"","()V");
下面看一下簽名的格式:
通過例子來看一下這些方法的使用
packagecom.jni.demo;public classJNIDemo {public int number = 0;//定義一個(gè)屬性//定義一個(gè)本地方法
public native voidsayHello();public static voidmain(String[] args){//調(diào)用動(dòng)態(tài)鏈接庫
System.loadLibrary("JNIDemo");
JNIDemo jniDemo= newJNIDemo();
jniDemo.sayHello();
System.out.print(jniDemo.number);
}
}
在來看一下C++代碼:
#include#include"com_jni_demo_JNIDemo.h"JNIEXPORTvoid JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv *env, jobject obj)
{//獲取obj中對(duì)象的class對(duì)象
jclass clazz = env->GetObjectClass(obj);//獲取Java中的number字段的id(最后一個(gè)參數(shù)是number的簽名)
jfieldID id_number = env->GetFieldID(clazz,"number","I");//獲取number的值
jint number = env->GetIntField(obj,id_number);//輸出到控制臺(tái)
cout<
env->SetIntField(obj,id_number,100L);
}
編譯成功后,在Eclipse運(yùn)行后的結(jié)果:
第一個(gè)0是在C++代碼中的cout<
第二個(gè)100是在Java中的System.out.println(jniDemo.number);
JNIEnv提供了眾多的CallMethod和CallStaticMethod,還有CallNonvirtualMethod函數(shù),需要通過GetMethodID取得相應(yīng)方法的jmethodID來傳入到上述函數(shù)的參數(shù)中
調(diào)用示例方法的三種形式:
CallMethod(jobject obj,jmethodID id,....);
CallMethod(jobject obj,jmethodID id,va_list lst);
CallMethod(jobject obj,jmethodID id,jvalue* v);
第一種是最常用的方式
第二種是當(dāng)調(diào)用這個(gè)函數(shù)的時(shí)候有一個(gè)指向參數(shù)表的va_list變量時(shí)使用的(很少使用)
第三種是當(dāng)調(diào)用這個(gè)函數(shù)的時(shí)候有一個(gè)指向jvalue或jvalue數(shù)組的指針時(shí)用的
說明:
jvalue在jni.h頭文件中定義是一個(gè)union聯(lián)合體,在C/C++中,我們知道union是可以存放不同類型的值,但是當(dāng)你給其中一個(gè)類型賦值之后,這個(gè)union就是這種類型了,比如你給jvalue中的s賦值的話,jvalue就變成了jshort類型了,所以我們可以定義一個(gè)jvalue數(shù)組(這樣就可以包含多種類型的參數(shù)了)傳遞到方法中。
假如現(xiàn)在Java中有這樣的一個(gè)方法:
boolean function(int a,double b,char c)
{
........
}
(1) 在C++中使用第一種方式調(diào)用function方法:
env->CallBooleanMethod(obj , id_function , 10L, 3.4 , L'a')
obj是方法funtion的對(duì)象
id_function是方法function的id;可以通過GetMethodID()方法獲取
然后就是對(duì)應(yīng)的參數(shù),這個(gè)和Java中的可變參數(shù)類似,對(duì)於最后一個(gè)char類型的參數(shù)L'a',為什么前面要加一個(gè)L,原因是Java中的字符時(shí)Unicode雙字節(jié)的,而C++中的字符時(shí)單字節(jié)的,所以要變成寬字符,前面加一個(gè)L
(2) 在C++中使用第三種法師調(diào)用function方法:
jvalue* args = new jvalue[3];//定義jvalue數(shù)組
args[0].i = 10L;//i是jvalue中的jint值
args[1].d = 3.44;
args[2].c = L'a';
env->CallBooleanMethod(obj, id_function, args);
delete[] args;//是否指針堆內(nèi)存
例子:C++中調(diào)用Java中的方法:
Java代碼:
public double max(double value1,double value2){
return value1>value2 ? value1:value2;
}
JNIEXPORT void JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv *env, jobject obj)
{//獲取obj中對(duì)象的class對(duì)象
jclass clazz = env->GetObjectClass(obj);//獲取Java中的max方法的id(最后一個(gè)參數(shù)是max方法的簽名)
jmethodID id_max = env->GetMethodID(clazz,"max","(DD)D");//調(diào)用max方法
jdouble doubles = env->CallDoubleMethod(obj,id_max,1.2,3.4);//輸出返回值
cout<
}
C++和Java對(duì)於繼承后執(zhí)行的是父類的還是子類的方法是有區(qū)別的,在Java中所有的方法都是virtual的,所以總是調(diào)用子類的方法,所以CallNonVirtualMethod這個(gè)方法就出來了,這個(gè)方法就可以幫助我們調(diào)用Java中的父類的方法:
在JNI中定義的CallNonvirtualMethod就能夠?qū)崿F(xiàn)子類對(duì)象調(diào)用父類方法的功能,如果想要調(diào)用一個(gè)對(duì)象的父類方法,而不是子類的方法的話,就可以使用CallNonvirtualMethod了,要使用它,首先要獲得父類及其要調(diào)用的父類方法的jmethodID,然后傳入到這個(gè)函數(shù)就能通過子類對(duì)象調(diào)用被覆寫的父類的方法了
例子:在Java中定義Father類:
packagecom.jni.demo;public classFather {public voidfunction(){
System.out.println("Father:function");
}
}
在定義一個(gè)子類Child:繼承Father類,從寫父類中的function方法
packagecom.jni.demo;public class Child extendsFather{
@Overridepublic voidfunction(){
System.out.println("Child:function");
}
}
在JNIDemo代碼:定義Father類型的屬性
packagecom.jni.demo;public classJNIDemo {public Father father = newChild();//定義一個(gè)本地方法
public native voidsayHello();public static voidmain(String[] args){//調(diào)用動(dòng)態(tài)鏈接庫
System.loadLibrary("JNIDemo");
JNIDemo jniDemo= newJNIDemo();
jniDemo.sayHello();
}
}
在來看一下C++中的代碼:
#include#include"com_jni_demo_JNIDemo.h"JNIEXPORTvoid JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv *env, jobject obj)
{//獲取obj中對(duì)象的class對(duì)象
jclass clazz = env->GetObjectClass(obj);//獲取Java中的father字段的id(最后一個(gè)參數(shù)是father字段的簽名)
jfieldID id_father = env->GetFieldID(clazz,"father","Lcom/jni/demo/Father;");//獲取father字段的對(duì)象類型
jobject father = env->GetObjectField(obj,id_father);//獲取father對(duì)象的class對(duì)象
jclass clazz_father = env->FindClass("com/jni/demo/Father");//獲取father對(duì)象中的function方法的id
jmethodID id_father_function = env->GetMethodID(clazz_father,"function","()V");//調(diào)用父類中的function方法(但是會(huì)執(zhí)行子類的方法)
env->CallVoidMethod(father,id_father_function);//調(diào)用父類中的function方法(執(zhí)行就是父類中的function方法)
env->CallNonvirtualVoidMethod(father,clazz_father,id_father_function);
}
Child:function是調(diào)用env->CallVoidMethod(...)方法的
Father:function是調(diào)用env->CallNonvirtualMethod(...)方法的
這樣就能夠控制到底調(diào)用哪個(gè)類的function方法了。
總結(jié)
以上是生活随笔為你收集整理的android jni 中jnienv,android JNI中JNIEnv類型和jobject類型的解釋的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java url特殊字符转义字符_URL
- 下一篇: linux逻辑文件块,linux逻辑卷组