您的位置:首页 > 编程语言 > C语言/C++

JNI进阶一 (C++调用java属性和方法,javap的使用)

2018-03-04 19:19 676 查看
一、C/C++函数分析:
//获取jclass对象,参数:this的意思,就是native方法所在的类
1.GetObjectClass(jobject) 
//获取普通属性id,第一个参数:类对象, 第二个参数:属性名,第三个参数:属性签名(不知道的同学点击这里
2.GetFieldID(jclass clazz, const char* name, const char* sig)
//设置int属性的值, 第一个参数:this的意思, 第二个参数:获取属性id, 第三个参数:要设置的值
3.SetIntField(jobject obj, jfieldID fieldID, jint value)
当然这里就只列举SetIntField函数了,同理还有很多,比如:SetCharField,SetFloatField,SetObjectField ......。有Set函数肯定也会有Get函数,与之对应的就是GetIntField(jobject obj, jfieldID fieldID),这个函数是获取指定属性的值,参数含义同SetIntField函数
//获取静态属性Id,  第一个参数:类对象, 第二个参数: 属性名, 第三个参数: 属性签名
4.GetStaticFieldID(jclass clazz, const char* name, const char* sig)
//设置静态属性的值, 第一个参数: 类对象, 第二个参数: 属性id, 第三个参数: 要设置的值
5.SetStaticIntField(jclass clazz, jfieldID fieldID, jint value)
//获取函数id, 第一参数:类对象, 第二个参数:函数名, 第三个参数: 函数签名(不知道的同学点击这里
6.GetMethodID(jclass clazz, const char* name, const char* sig)
//调用java中的无返回值函数, 第一个参数: this的意思, 第二个参数: 函数id, 第三个参数:需要传入的实参
7.CallVoidMethod(jobject obj, jmethodID methodID, ...)
//获取静态函数id, 第一个参数: 类对象, 第二个参数: 函数名, 第三个参数: 函数签名
8.GetStaticMethodID(jclass clazz, const char* name, const char* sig)
//调用java中无返回值的静态函数, 第一个参数: 类对象, 第二个参数: 函数id, 第三个参数: 需要传入的实参
9.CallStaticVoidMethod(jclass clazz, jmethodID methodID, ...)//生成一个jstring类型的方法转换,该方法会返回一个jstring类型
10.NewStringUTF(const char* bytes)
//调用java中的对象类型(String类型被认为对象类型),第一参数:this的意思, 第二个参数:函数Id, 第三个参数:需要传入的实参
11.CallObjectMethod(jobject, jmethodID, ...);
//获取类中的对象属性,第一个参数:this的意思 , 第二个参数:属性id
12.GetObjectField(jobject obj, jfieldID fieldID)
//根据子类的类对象,获取父类的类对象, 第一参数:子类类对象
13.GetSuperclass(jclass clazz)
//调用java中父类的方法,第一个参数:子类的对象, 第二个参数:父类的类对象, 第三个参数:父类的函数id, 第四个参数:需要传入的实参
14.CallNonvirtualVoidMethod(jobject obj, jclass clazz, jmethodID methodID, ...)
了解完这些函数之后我们来看具体使用:Java_com_liyahong_jni_1field_1method_MainActivity_stringFromJNI(
JNIEnv *env, jobject jobj) {

//修改普通成员变量
jclass jclazz = env->GetObjectClass(jobj);
jfieldID jfieilId = env->GetFieldID(jclazz, "anInt", "I");
jint anInt = 35;
env->SetIntField(jobj, jfieilId, anInt);

//修改静态成员变量
jfieldID jstaticFieldId = env->GetStaticFieldID(jclazz, "anIntS", "I");
env->SetStaticIntField(jclazz, jstaticFieldId, 55);

//通过jni调用普通java方法
jmethodID jmethodId = env->GetMethodID(jclazz, "test", "()V");
env->CallVoidMethod(jobj, jmethodId);

//通过jni调用静态java方法
jmethodID jstaticMethodId = env->GetStaticMethodID(jclazz, "staticTest", "(I)V");
env->CallStaticVoidMethod(jclazz, jstaticMethodId, 55);

//通过jni调用java中带参方法
jmethodID methodId = env->GetMethodID(jclazz, "test", "(ILjava/lang/String;)Ljava/lang/String;");
jstring str = env->NewStringUTF("小丽");
env->CallObjectMethod(jobj, methodId, 18, str);

//通过jni调用其他类中的方法
jfieldID sonJfieldId = env->GetFieldID(jclazz, "son", "Lcom/liyahong/jni_field_method/Son;");
jobject sonJobj = env->GetObjectField(jobj, sonJfieldId);
jclass sonClazz = env->GetObjectClass(sonJobj);
jmethodID sonMethodId = env->GetMethodID(sonClazz, "ride", "()V");
env->CallVoidMethod(sonJobj, sonMethodId);

//通过jni调用父类中的方法
jclass jfatherClazz = env->GetSuperclass(sonClazz);
jmethodID jfatherMethodId = env->GetMethodID(jfatherClazz, "ride", "()V");
env->CallNonvirtualVoidMethod(sonJobj, jfatherClazz, jfatherMethodId);

std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}二、当使用jni调用java中的构造方法的时候:
其中的方法名需要写为<init>,例如:public Student(){
......
}这时候不应该写Student,而是应该写为:<init>
方便大家理解这里特意写了一个例子://通过jni实例父类的构造方法
jmethodID fatherMethodId = env->GetMethodID(jfatherClazz, "<init>", "()V");
jobject fatherJobj = env->NewObject(jfatherClazz, fatherMethodId);
//获取父类中的属性fatherName
jfieldID fatherFieldId = env->GetFieldID(jfatherClazz, "fatherName", "Ljava/lang/String;");
jstring fatherName = env->NewStringUTF("My name is 张三");
//修改fatherName的值为My name is 张三
env->SetObjectField(fatherJobj, fatherFieldId, fatherName);
jmethodID fatherGetNameId = env->GetMethodID(jfatherClazz, "getFatherName", "()Ljava/lang/String;");
//调用父类中的getFatherName方法,获取属性值
fatherName = (jstring) env->CallObjectMethod(fatherJobj, fatherGetNameId);
char* resultName = jstringToChar(env, fatherName);
LOGE("%s", resultName);①这里涉及到新函数NewObject,其实这个函数很简单就是一个实例对象的函数,我们知道java中的构造函数都是用来实例对象的,所以顾名思义的,我们要通过jni来调用java中的构造函数,就应该调用NewObject这个函数,这个函数会返回一个jobject对象,这个对象就是我们实例好的java对象。
②这里还涉及到了jstringToChar函数,这个函数看名字想必大家都应该知道什么意思了,这个函数其实就是一个jstring 和 char*的一个类型转换,原因都不细说了,直接上代码:#include <string.h>
#include <stdlib.h>

// 由于jvm和c++对中文的编码不一样,因此需要转码。 utf8/16转换成gb2312
char* jstringToChar(JNIEnv* env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("UTF-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0) {
rtn = (char*) malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}三、javap的使用:
1.预热工作,首先我们要进入classes目录下使用命令:cd app/build/intermediates/classes/debug/包名例如:cd app/build/intermediates/classes/debug/com/xxx/jni_field_method下面开始命令://获取MainAtivity下的所有属性和方法
javap -p MainActivity
//获取MainAtivity的属性和方法的签名
javap -s -p MainActivity
JNI进阶二(C++调用java数组 和 JNI引用):传送门
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: