boolean jboolean byte jbyte char jchar short jshort int jint long jlong float jfloat double jdouble void void
String jstring Object jobject 数组,基本数据类型的数组 byte[] jByteArray 对象数组 object[](String[]) jobjectArray
属性的签名
数据类型 签名 boolean Z byte B char C short S int I long L float F double D void V object L开头,然后以/分隔包的完整类型,后面再加;如果说String签名就是Ljava/lang/String; Array 以 [ 开头在加上数组元素类型的签名;比如 int[ ] 签名就是 [ I ,在比如int[ ][ ]的签名就是[ [ I ,object数组前面就是 [Ljava/lang/Object;
C/C++ 访问Java的属性、方法
有以下几种情况:
- 访问Java类的非静态属性。
- 访问Java类的静态属性。
- 访问Java类的非静态方法
- 访问Java类的静态方法
- 间接方法Java类的父类方法
- 访问Java类的构造方法。
Java的属性
访问Java的非静态属性
extern "C" JNIEXPORT void JNICALL Java_com_example_asus1_ndklearn_MainActivity_accessFiled(JNIEnv *env, jobject instance) { // TODO //通过对象拿到Class jclass clz = env->GetObjectClass(instance); //拿到对应属性的ID jfieldID fid = env->GetFieldID(clz,"str","Ljava/lang/String;"); //通过属性ID拿到属性的值 jstring jstr = (jstring)(env->GetObjectField(instance,fid)); //通过Java字符串拿到c字符串,第二个参数是一个出参,用来告诉我们GetStringUTFChars内部是否复制了一份字符串 //如果没有复制,那么出参为isCopy,这时候就不能修改字符串的值了,因为Java中常量池中的字符串是不允许修改的(但是jstr可以指向另外一个字符串) const char * cstr = env->GetStringUTFChars(jstr,NULL); //在c层修改这个属性的值 char res[20] = "I LOVE YOU,"; strcat(res,cstr); //重新生成Jasva的字符串,并且设置给对应的属性 jstring jstr_new = env->NewStringUTF(res); env->SetObjectField(instance,fid,jstr_new); //最后释放资源,通知垃圾回收器来回收 env->ReleaseStringUTFChars(jstr,cstr); }
java中,直接调用:
TextView tv = (TextView) findViewById(R.id.sample_text);
accessFiled(); //jni 给字段str赋值
tv.setText(str);
访问Java的静态属性
extern "C" JNIEXPORT void JNICALL Java_com_example_asus1_ndklearn_MainActivity_accessStaticFiled(JNIEnv *env, jobject instance) { // TODO jclass clz = env->GetObjectClass(instance); jfieldID fid = env->GetStaticFieldID(clz,"NUM","I"); jint jInt = env->GetStaticIntField(clz,fid); jInt++; env->SetStaticIntField(clz,fid,jInt); }
Java的方法
访问Java的非静态方法
extern "C" JNIEXPORT void JNICALL Java_com_example_asus1_ndklearn_MainActivity_accessMethd(JNIEnv *env, jobject instance) { // TODO jclass clz = env->GetObjectClass(instance); jmethodID mid = env->GetMethodID(clz,"genRandomInt","(I)I"); //调用该方法,最后一个是可变参数,就是调用该方法所传入的参数 jint jInt = env->CallIntMethod(instance,mid,100); //printf("output from C: %d",jInt); LOGD("output from C : %d",jInt); }
访问Java的静态方法
extern "C" JNIEXPORT void JNICALL Java_com_example_asus1_ndklearn_MainActivity_accessStaticMathod(JNIEnv *env, jobject instance) { // TODO jclass clz = env->GetObjectClass(instance); jmethodID mid = env->GetStaticMethodID(clz,"getUUID","()Ljava/lang/String;"); //调用java的静态方法,拿到返回值 jstring jstr = (jstring)(env->CallStaticObjectMethod(clz,mid,NULL)); //把拿到的Java字符串转换为C的字符串 const char * cstr = env->GetStringUTFChars(jstr,NULL); //后续操作,产生以UUID为文件名的文件 char fileName[100]; sprintf(fileName,"G:\\%s.txt",cstr); FILE * f = fopen(fileName,"w"); fputs(cstr,f); fclose(f); LOGD("output from C : File had saved", jstr); }
间接访问Java类的父类方法
public class Human { protected void speek(){ System.out.println("Human Speek"); } } public class Man extends Human { @Override protected void speek() { //super.speek(); System.out.println("Man Speek"); } }
extern "C" JNIEXPORT void JNICALL Java_com_example_asus1_ndklearn_MainActivity_accessNonVirtualMathod(JNIEnv *env, jobject instance) { // 先拿到属性man jclass clz = env->GetObjectClass(instance); jfieldID fid = env->GetFieldID(clz,"man","Lcom/example/asus1/ndklearn/Human;"); jobject man = env->GetObjectField(instance,fid); //拿到父类的类,以及speek的方法的id jclass clz_human = env->FindClass("com/example/asus1/ndklearn/Human"); jmethodID mid = env->GetMethodID(clz_human,"speek","()V"); //调用自己的speek实现 env->CallVoidMethod(man,mid); //调用父类的speek实现 env->CallNonvirtualVoidMethod(man,clz_human,mid); }
访问Java类的构造方法
extern "C" JNIEXPORT jlong JNICALL Java_com_example_asus1_ndklearn_MainActivity_accessConstructor(JNIEnv *env, jobject instance) { jclass clz_date = env->FindClass("java/util/Date"); //构造方法的函数名格式是:<init> //不能写类名,因为构造方法函数名都一样区分不了,只能通过参数列表<签名>区分 jmethodID mid_Date = env->GetMethodID(clz_date,"<init>","()V"); //调用构造函数 jobject date = env->NewObject(clz_date,mid_Date); //注意签名 jmethodID mid_getTime = env->GetMethodID(clz_date,"getTime","()J"); //调用getTime方法 jlong jtime = env->CallLongMethod(date,mid_getTime); return jtime; }
数组的处理
int compare(const void * a, const void * b)
{
return (*(int *)a)-(*(int *)b);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_asus1_ndklearn_MainActivity_sortArray(JNIEnv *env, jobject instance,
jintArray array_) {
//创建Java数组
//env->NewIntArray(len);
//通过Jva数组,拿到C的数组指针
jint * c_arr = env->GetIntArrayElements(array_,NULL);
jsize len = env->GetArrayLength(array_);
//排序
qsort(c_arr,len, sizeof(jint),compare);
//操作完后需要同步C的数组到Java数组中
env->ReleaseIntArrayElements(array_,c_arr,0);
}
局部引用
extern "C"
JNIEXPORT void JNICALL
Java_com_example_asus1_ndklearn_MainActivity_localRef(JNIEnv *env, jobject instance) {
int i = 0;
for(;i<10;i++)
{
jclass clz_date = env->FindClass("java/util/Date");
jmethodID mid = env->GetMethodID(clz_date,"<init>","()V");
jobject jobject_date = env->NewObject(clz_date,mid);
//此处省略一万行代码
//不再使用jobject对象
//通知垃圾回收器回收这些对象,确保内存充足
env->DeleteLocalRef(jobject_date);
}
}
全局引用
//全局引用的字符串对象
jstring global_str;
//创建全局引用
extern "C"
JNIEXPORT void JNICALL
Java_com_example_asus1_ndklearn_MainActivity_createGlobalRef(JNIEnv *env, jobject instance) {
global_str = env->NewStringUTF("I LOVE YOU");
//通过NewGlobalRef创建全局引用
env->NewGlobalRef(global_str);
}
//获取全局引用
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_asus1_ndklearn_MainActivity_getGlobalRef(JNIEnv *env, jobject instance) {
// TODO
return global_str;
}
//删除全局引用
extern "C"
JNIEXPORT void JNICALL
Java_com_example_asus1_ndklearn_MainActivity_deleteGlobalRef(JNIEnv *env, jobject instance) {
// 通过DelteGlobalRef删除全局变量
env->DeleteGlobalRef(global_str);
}