【Android NDK 开发】JNI 方法解析 ( C/C++ 调用 Java 方法 | 函数签名 | 调用对象方法 | 调用静态方法 )(一)

简介: 【Android NDK 开发】JNI 方法解析 ( C/C++ 调用 Java 方法 | 函数签名 | 调用对象方法 | 调用静态方法 )(一)

I . 调用 Java 方法流程


JNI 中调用 Java 方法流程 :



① 获取 jclass 类型变量 :


调用 jclass GetObjectClass(jobject obj) 或 jclass FindClass(const char* name) 方法 , 获取 jclass 类型变量 ;


② 通过反射获取方法 :


调用 jmethodID GetMethodID(jclass clazz, const char* name, const char* sig) 获取 Java 对象方法 ,

调用 jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig) 获取 Java 类的静态方法 ;


③ 调用方法 :


void CallVoidMethod(jobject obj, jmethodID methodID, …) 调用 Java 对象方法 ,

void CallStaticVoidMethod(jclass clazz, jmethodID methodID, …) 调用 Java 的静态方法 ;



CalXxxMethod 方法 , 其中的 Xxx 是 Java 对象的 返回值 , 不同的返回值调用不同的方法 ;




II . 获取 jclass 对象 ( GetObjectClass )


1 . 函数原型 : 通过传入 Java 对象 ( jobject 类型变量 ) , 获取 Java 类对象 ( jclass 类型变量 )


返回值 : 返回 Java 字节码 Class 对象 , 对应 C/C++ 中的 jclass 对象 ;

参数 : 传入 Java 对象 ; ( 该对象一般是由 JNI 方法传入的 )


struct _JNIEnv {
    /* _JNIEnv  结构体中封装了 JNINativeInterface 结构体指针 */
    const struct JNINativeInterface* functions;
    ...
    // 最终 调用的 还是 JNINativeInterface 结构体中封装的 GetObjectClass方法
    jclass GetObjectClass(jobject obj)
    { return functions->GetObjectClass(this, obj); }
    ...
}



2 . 代码示例 :


extern "C"
JNIEXPORT void JNICALL
Java_kim_hsl_jni_MainActivity_jniObjectTest(JNIEnv *env, jobject instance, jobject student) {
    //获取 Java 对应的 Class 对象
    jclass student_class = env->GetObjectClass(student);
  ...
}



III . 获取 jclass 对象 ( FindClass )


函数原型 : 通过传入完整的 包名.类名 获取 Java 类对应的 C/C++ 环境下的 jclass 类型变量 ;


返回值 : 返回 Java 字节码 Class 对象 , 对应 C/C++ 中的 jclass 对象 ;

参数 : 传入 完整的 包名/类名 , 注意包名中使用 “/” 代替 “.” , 如 “kim/hsl/jni/Teacher” ;


struct _JNIEnv {
    /* _JNIEnv  结构体中封装了 JNINativeInterface 结构体指针 */
    const struct JNINativeInterface* functions;
    ...
    // 最终 调用的 还是 JNINativeInterface 结构体中封装的 FindClass 方法
    jclass FindClass(const char* name)
    { return functions->FindClass(this, name); }
    ...
}


2 . 代码示例 : 获取 kim.hsl.jni.Teacher 对应的 jclass 对象 ;


extern "C"
JNIEXPORT void JNICALL
Java_kim_hsl_jni_MainActivity_jniObjectTest(JNIEnv *env, jobject instance, jobject student) {
    ...
    // 5.2 获取 Teacher 类 ( 该变量需要释放 )
    jclass class_teacher = env->FindClass("kim/hsl/jni/Teacher");
  ...
}




IV . JNI 函数签名规则


参考 : JNI 函数签名规则




V . javap 获取函数签名 ( 推荐 )


自己写函数签名容易出错 , 还麻烦 , 推荐使用 javap 工具 ;



1 . 字节码文件 : 首先要先编译出 Student 的 class 字节码文件 , javap 命令要直接作用于该字节码文件 ;



2 . Android Studio 中 Java 代码编译后的 class 字节码文件位置 : 不同版本的 AS 编译后的字节码位置不同 , 建议在各自的 Module 下的 build 目录中进行文件查找 , 找到 class 字节码所在目录 ;



3 . 我的 AS 中目录位置是 : Y:\002_WorkSpace\001_AS\001_NDK_Hello\app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes , 在这个目录下执行 javap -s kim.hsl.jni.Student 命令 , 即可获取类中的函数签名 ;


image.png



4 . javap 命令格式 : javap -s 完整包名.类名 ;


如 : 要获取 kim.hsl.jni.Student 类中的函数签名 , 使用 javap -s kim.hsl.jni.Student 命令 ;



5 . 执行命令 : 在 class 目录下执行 javap -s kim.hsl.jni.Student 命令 ;


Y:\002_WorkSpace\001_AS\001_NDK_Hello\app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes>javap -s kim.hsl.jni.Student
Compiled from "Student.java"
public class kim.hsl.jni.Student {
  public kim.hsl.jni.Student();
    descriptor: ()V
  public kim.hsl.jni.Student(int, java.lang.String);
    descriptor: (ILjava/lang/String;)V
  public int getAge();
    descriptor: ()I
  public void setAge(int);
    descriptor: (I)V
  public java.lang.String getName();
    descriptor: ()Ljava/lang/String;
  public void setName(java.lang.String);
    descriptor: (Ljava/lang/String;)V
}



VI . 反射获取对象方法 ( GetMethodID )


函数原型 : 通过 jclass 对象 , 方法名称 , 和 方法签名 , 获取 Java 类对象对应的方法 ID 即 jmethodID 类型变量 ;


返回值 : Java 类对象对应的方法 ID ( jmethodID 类型变量 )


参数 :


jclass clazz : 要获取的 Java 对象方法对应的 Java 类对象 ;
const char* name : 方法名称 ;
const char* sig : 方法签名 , 使用 javap 命令获得 ;
struct _JNIEnv {
    /* _JNIEnv  结构体中封装了 JNINativeInterface 结构体指针 */
    const struct JNINativeInterface* functions;
    ...
    // 最终 调用的 还是 JNINativeInterface 结构体中封装的 GetMethodID 方法
    jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
    { return functions->GetMethodID(this, clazz, name, sig); }
    ...
}



2 . 代码示例 : 获取 Student 类的 getAge 方法 ;


student_class 是 Student 类对应的 C/C++ 中的 jclass 类型变量 ,
“getAge” 是方法名称 ,
“()I” 是方法签名 , 左侧的括号是参数列表类型签名 , 括号右的 I 是返回值类型 int ;
extern "C"
JNIEXPORT void JNICALL
Java_kim_hsl_jni_MainActivity_jniObjectTest(JNIEnv *env, jobject instance, jobject student) {
    ...
  //1 . 获取 Java 对应的 Class 对象
    jclass student_class = env->GetObjectClass(student);
    //2 . 获取 Student 的 public int getAge() 方法
    jmethodID method_getAge = env->GetMethodID(student_class, "getAge" , "()I");
  ...
}


目录
相关文章
|
SQL 数据挖掘 测试技术
南大通用GBase8s数据库:LISTAGG函数的解析
南大通用GBase8s数据库:LISTAGG函数的解析
|
Java 开发工具 Android开发
Android与iOS开发环境搭建全解析####
本文深入探讨了Android与iOS两大移动操作系统的开发环境搭建流程,旨在为初学者及有一定基础的开发者提供详尽指南。我们将从开发工具的选择、环境配置到第一个简单应用的创建,一步步引导读者步入移动应用开发的殿堂。无论你是Android Studio的新手还是Xcode的探索者,本文都将为你扫清开发道路上的障碍,助你快速上手并享受跨平台移动开发的乐趣。 ####
|
XML JavaScript Android开发
【Android】网络技术知识总结之WebView,HttpURLConnection,OKHttp,XML的pull解析方式
本文总结了Android中几种常用的网络技术,包括WebView、HttpURLConnection、OKHttp和XML的Pull解析方式。每种技术都有其独特的特点和适用场景。理解并熟练运用这些技术,可以帮助开发者构建高效、可靠的网络应用程序。通过示例代码和详细解释,本文为开发者提供了实用的参考和指导。
592 15
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
10428 2
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
|
C语言 开发者
【C语言】断言函数 -《深入解析C语言调试利器 !》
断言(assert)是一种调试工具,用于在程序运行时检查某些条件是否成立。如果条件不成立,断言会触发错误,并通常会终止程序的执行。断言有助于在开发和测试阶段捕捉逻辑错误。
536 5
|
机器学习/深度学习 自然语言处理 语音技术
揭秘深度学习中的注意力机制:兼容性函数的深度解析
揭秘深度学习中的注意力机制:兼容性函数的深度解析
|
数据处理 Python
深入探索:Python中的并发编程新纪元——协程与异步函数解析
深入探索:Python中的并发编程新纪元——协程与异步函数解析
218 3
|
存储
atoi函数解析以及自定义类型经典练习题
atoi函数解析以及自定义类型经典练习题
505 0
|
编译器 Android开发
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目

推荐镜像

更多
  • DNS