JNI之访问方法和域

NDK  2023年7月20日 am8:09发布1年前 (2023)更新 城堡大人
73 0 0

前言

JNI允许本地方法访问Java对象的域和调用方法。今天就介绍一下放问java方法和对象的域。

记录一下,方便自己查阅。

正文

JNI访问对象域和方法,主要涉及如下几步骤:

  1. 获取到对象域的jfieldID或jmethodID

  2. 通过jfieldID获取对象域的值或者通过jmethodID调用对应的方法。

  3. 对于对象域,还可以通过jfieldID改变值。

下面单独介绍使用。

访问方法

在介绍前,主要注意带有static的方法跟没有static方法的是有区别的。

# Hello.java中
# 非静态
public int add(int x, int y) {
    return x + y;
}
# 非静态
public int sub(int x, int y) {
    return x - y;
}
# 静态
public static int multiply(int x, int y) {
    return x * y;
}
第一步

静态和非静态jmethodID的获取方法存在不一,JNI中有区分的。

非静态方法
jmethodID addMethodID = env->GetMethodID(clazz, "add", "(II)I");
jmethodID subMethodID = env->GetMethodID(clazz, "sub", "(II)I");
静态方法
jmethodID multiplyMethodId = env->GetStaticMethodID(clazz, "multiply", "(II)I");

PS: GetxxxMethodID()中是否有static取决于方法中是否有static声明。

看完到上面,你或许跟我一样的想法,static方法是属于类,也属于对象的,那如果我不用JNI定义的static方法获取jmethodID呢?

我尝试了一下,编译是OK的,但运行是异常了。

JNI DETECTED ERROR IN APPLICATION: JNI CallIntMethodV called with pending exception java.lang.NoSuchMethodError: no non-static method "Lcom/biumall/dynamic/one/Hello;.multiply(II)I"

异常中也告诉我们 no non-static method "Lcom/biumall/dynamic/one/Hello;.multiply(II)I"(multiply是静态类),意思就是需要使用静态的方法访问他。

第二步

JNI的函数中可以通过jmethodID进行调用Java的方法。

非静态方法
if(NULL != addMethodID){
    count = env->CallIntMethod(object, addMethodID, x, y);
}
if(NULL != subMethodID){
    count = env->CallIntMethod(object, subMethodID, x, y);
}

CallIntMethod()表示调用非静态的返回值为int的addMethodID或subMethodID方法。

jni.h中还有其他返回类型的方法。

jobject     (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
jboolean    (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);
jbyte       (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);
jchar       (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...);
jshort      (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...);
jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
jlong       (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...);
jfloat      (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...);
jdouble     (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...);
void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
静态方法
if(NULL == multiplyMethodId){
    count = env->CallStaticIntMethod(clazz, multiplyMethodId, x, y);
}

CallStaticIntMethod()表示调用非静态的返回值为int的multiplyMethodId方法。

需要注意的,因为是static方法,所以第二个参数传入的类引用!(重点)

jni.h中还有其他返回类型的方法。

jobject     (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...);
jboolean    (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...);
jbyte       (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...);
jchar       (*CallStaticCharMethod)(JNIEnv*, jclass, jmethodID, ...);
jshort      (*CallStaticShortMethod)(JNIEnv*, jclass, jmethodID, ...);
jint        (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...);
jfloat      (*CallStaticFloatMethod)(JNIEnv*, jclass, jmethodID, ...);
jdouble     (*CallStaticDoubleMethod)(JNIEnv*, jclass, jmethodID, ...);
void        (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);

如果这里不也不使用CallStaticIntMethod(),而是用CallIntMethod()也是会异常的,如下

JNI DETECTED ERROR IN APPLICATION: calling static method int com.biumall.dynamic.one.Hello.multiply(int, int) with CallIntMethodV

访问域

域也分为静态域和非静态的域。

如果乱使用也是会有异常的,显示使用GetFieldID()去获取static的域出现的异常。

JNI DETECTED ERROR IN APPLICATION: JNI GetStringUTFChars called with pending exception java.lang.NoSuchFieldError: no "Z" field "mBooleanValue" in class "Lcom/biumall/dynamic/one/Hello;" or its superclasses

由于域跟访问方法差不多,这就简单的介绍一下。

public int mIntValue = -0Xff;
public static boolean mBooleanValue = true;
非静态
jfieldID intFieldID = env->GetFieldID(clazz, "mIntValue", "I");

if(NULL != intFieldID){
    //获取对象域中的值
    int intValue = env->GetIntField(object, intFieldID);
    //修改对象域中的值
    env->SetIntField(object, intFieldID, 99);
}
静态
jfieldID booleanFieldID = env->GetStaticFieldID(clazz, "mBooleanValue", "Z");
if(NULL !=  booleanFieldID){
    //获取对象域中的值
    int booleanValue = env->GetStaticBooleanField(clazz, booleanFieldID);
    //修改对象域中的值
    env->SetStaticBooleanField(clazz, booleanFieldID, false);
}

上面只涉及int和boolean类,其他的类型jni.h中也有定义哈。

其实只要理解了一个,其他的都很容易的。无非有static和无static的区别。

参考文章

  1. NDK中jni.h头文件完整内容

 历史上的今天

  1. 2022: [代码片]获取状态栏高度和导航栏高度(0条评论)
  2. 2021: 毕淑敏:你不能要求没有风暴的海洋(0条评论)
  3. 2019: 俞平伯:浆声灯影里的秦淮河(0条评论)
版权声明 1、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

鲁迅:两地书(节选)

广平兄:仿佛记得收到来信有好几天了,但是今天才能写回信。“一步步的现在过去”,自然可以比较的不为环境所苦,但“现在的我”中,既然“含有原来的我”,而这“我”又有不满于时代环境之心,则苦痛也依然相续。不过能够随遇而安——即有船坐船云云——则比起幻想太多的人们来,可以稍为安稳,能够敷衍下去而已。总之,...

林语堂:人生的乐趣

我们只有知道一个国家人民生活的乐趣,才会真正了解这个国家,正如我们只有知道一个人怎样利用闲暇时光,才会真正了解这个人一样。只有当一个人歇下他手头不得不干的事情,开始做他所喜欢做的事情时,他的个性才会显露出来。只有当社会与公务的压力消失,金钱、名誉和野心的刺激离去,精神可以随心所欲地游荡之时,我们才会...

李月亮:那些你所不知道的大事

在你的生命里,经历了一些很重大的事情,可是你并不知道。5岁那年,爸爸下班回来,你跑去迎接他,不小心摔了个狗啃泥,不过没有受伤。你并不知道,就在你摔倒的地方往左两厘米,立着一根小钉子,如果你稍微偏一偏,左眼就失明了。10岁那年,你一个人在家煮方便面,刚把水壶放到煤气炉上,就接到妈妈的电话让你去姥...

Android多线程介绍

前言记录一下Android主线程,子线程等相关知识。我们知道Android3.0后如果在主线程进行网络请求是会抛出异常的,这是为了避免主线程被耗时操作阻塞从而导致ANR。因此有必要学习一下子线程相关知识。正文搞懂什么是线程前,也需要搞懂什么是进程。什么是进程进程是操作系统结构的基础。...

王小波:卡尔维诺与未来的一千年

朋友寄来一本书,卡尔维诺的《未来千年备忘录》,我正在看着。这本书是他的讲演稿,还没来得及讲,稿也没写完,人就死了。这些讲演稿分别冠以如下题目:轻逸、迅速、易见、确切和繁复。还有一篇"连贯",没有动笔写,所以我整天在捉摸他到底会写些什么,什么叫做"连贯"。卡尔维诺指出,在未来的一千年里,文学会继续繁荣...

[摘]Android面试题目整合

Java相关容器(HashMap、HashSet、LinkedList、ArrayList、数组等)内存模型垃圾回收算法(JVM)垃圾回收机制和调用System.gc()的区别?类加载过程(需要多看看,重在理解,对于热修复和插件化比较重要)反射多线程和线程池设计模式(六大基本原则、...