一文明白 Android JNI C/C++ 访问Java的属性、方法

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的属性、方法

有以下几种情况:

  1. 访问Java类的非静态属性。
  2. 访问Java类的静态属性。
  3. 访问Java类的非静态方法
  4. 访问Java类的静态方法
  5. 间接方法Java类的父类方法
  6. 访问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);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值