使用NDK进行JNI编程与实践三:在C/C++代码中修改java类中属性

一、修改java类中非静态属性:

  1. java类中代码:
    public String str = "hello";
    /* JNI改变类中变量str的值 */
    public native void changeStr();
  1. 中间头文件省略,直接C++代码:
JNIEXPORT void JNICALL Java_com_example_jnitest_JNITest_changeStr
        (JNIEnv *env, jobject jobj)
{
    /* 获取JNITest的字节码 */
    jclass clazz = env->GetObjectClass(jobj);

    /* 获取java类中变量num的Field */
    jfieldID jId = env->GetFieldID(clazz, "str", "Ljava/lang/String;");

    /* 获取java中str的值 */
    jstring jstr = (jstring)env->GetObjectField(jobj, jId);

    /* 将jstring转化为char */
    char* cstr = (char* )env->GetStringUTFChars(jstr, NULL);

    /* 修改值 */
    char newstr[20] = "world!";
    strcat(newstr, cstr);

    /* 将char转成jstring */
    jstring jstrnew = env->NewStringUTF(newstr);

    /* 重新设置到java类变量里面去 */
    env->SetObjectField(jobj, jId, jstrnew);

    /* 释放JNI层资源 */
    env->ReleaseStringUTFChars(jstr, cstr);
}
  1. 测试代码:
	JNITest obj = new JNITest();
	obj.changeStr();
	Toast.makeText(MainActivity.this, obj.str, Toast.LENGTH_SHORT).show();

二、 修改java类中静态属性:
5. java代码:

    public  static int age = 18;
    /* JNI改变类中static变量age的值 */
    public native void changeAge();
  1. C++代码实现:
JNIEXPORT void JNICALL Java_com_example_jnitest_JNITest_changeAge
        (JNIEnv *env, jobject jobj)
{
    /* 获取JNITest的字节码 */
    jclass clazz = env->GetObjectClass(jobj);

    /* 获取java类中变量num的Field */
    jfieldID jId = env->GetStaticFieldID(clazz, "age", "I");

    /* 获取num的值 */
    jint jAge = env->GetStaticIntField(clazz, jId);

    jAge = 28;

    env->SetStaticIntField(clazz, jId, jAge);
}
  1. java测试代码:
	JNITest obj = new JNITest();
	obj.changeAge();
	Toast.makeText(MainActivity.this, "age = " + JNITest.age, Toast.LENGTH_SHORT).show();

三、总结:
5. JNI层就是JAVA层和C/C++层中间的桥梁,java类型数据想要在C/C++层进行修改,必须先要转换为jni类型,然后借助传下来的java虚拟机变量env调用合适的函数指针将其转换为C/C++中可以访问的变量类型,进行操作,完成之后再通过JNI转换回去;
6. 静态和非静态变量的区别是调用的JNI方法也会变为静态或者非静态;

四、补充:

  1. 如何查看类中成员变量和方法的签名:
    a. 如果是java公共类,直接使用cmd的javap指令即可,示例:
javap -s java.lang.String

b.如果是自己编写的类,Android studio 3.5版本:
在这里插入图片描述
将Android studio的视图选为project,进入app->build->javac->debug->classes,右键选择show in explorer,然后进入classes目录,弹出cmd,输入上述指令,示例:

javap -s com.example.jnitest.JNITest

当然,也可以直接使用Android studio的terminal进行操作,这里顺便补充一下如何获取自己编写的类的全类名,鼠标类名右键:
在这里插入图片描述
选择copy reference即可;

  1. 如何在C/C++代码中添加打印:
    a. 在Android.mk中加入如下代码:
LOCAL_PATH := $(call my-dir)    #接收当前Android.mk文件的绝对路径

include $(CLEAR_VARS)           #类似于工具初始化的操作

LOCAL_MODULE := libhellojni     #模块名
LOCAL_SRC_FILES := hello.cpp    #依赖的源文件

LOCAL_LDLIBS    := -llog        #引用log对应的库文件

include $(BUILD_SHARED_LIBRARY) #将该模块编译成一个动态库

LOCAL_LDLIBS := -llog为引入log需要的库文件,库的话会从system/lib下面去动态加载;

b. 代码中的修改:

#include <Android/log.h>
#define LOG "JNITest"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__)

进入上述代码之后我们可以在文件中直接使用LOGE进行打印,并添加更多的打印级别。
代码路径:

https://github.com/jiyi666/apk-demo/tree/master/JNITest
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值