JNI/NDK 开发指南(六)——C/C++ 访问 Java 实例方法和静态方法

本贴最后更新于 1963 天前,其中的信息可能已经事过境迁

通过前面 5 章的学习,我们知道了如何通过 JNI 函数来访问 JVM 中的基本数据类型、字符串和数组这些数据类型。下一步我们来学习本地代码如何与 JVM 中任意对象的属性和方法进行交互。比如本地代码调用 Java 层某个对象的方法或属性,也就是通常我们所说的来自 C/C++ 层本地函数的 callback(回调)。这个知识点分 2 篇文章分别介绍,本篇先介绍方法回调,在第七章中介绍本地代码访问 Java 的属性。

   在这之前,先回顾一下在Java中调用一个方法时在JVM中的实现原理,有助于下面讲解本地代码调用Java方法实现的机制。写过Java的童鞋都知道,调用一个类的静态方法,直接通过 类名.方法 就可以调用。这也太简单了,有什么好讲的呢。。。但在这个调用过程中,JVM是帮我们做了很多工作的。当我们在运行一个Java程序时,JVM会先将程序运行时所要用到所有相关的class文件加载到JVM中,并采用按需加载的方式加载,也就是说某个类只有在被用到的时候才会被加载,这样设计的目的也是为了提高程序的性能和节约内存。所以我们在用类名调用一个静态方法之前,JVM首先会判断该类是否已经加载,如果没有被ClassLoader加载到JVM中,JVM会从classpath路径下查找该类,如果找到了,会将其加载到JVM中,然后才是调用该类的静态方法。如果没有找到,JVM会抛出java.lang.ClassNotFoundException异常,提示找不到这个类。ClassLoader是JVM加载class字节码文件的一种机制,不太了解的童鞋,请移步阅读《深入分析Java ClassLoader原理》一文。其实在JNI开发当中,本地代码也是按照上面的流程来访问类的静态方法或实例方法的,下面通过一个例子,详细介绍本地代码调用Java方法流程当中的每个步聚:

package com.study.jnilearn;

/**

  • AccessMethod.java

  • 本地代码访问类的实例方法和静态方法

  • @author yangxin
    */
    public class AccessMethod {

    public static native void callJavaStaticMethod();
    public static native void callJavaInstaceMethod();

    public static void main(String[] args) {
    callJavaStaticMethod();
    callJavaInstaceMethod();
    }

    static {
    System.loadLibrary("AccessMethod");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

package com.study.jnilearn;

/**

  • ClassMethod.java

  • 用于本地代码调用

  • @author yangxin
    */
    public class ClassMethod {

    private static void callStaticMethod(String str, int i) {
    System.out.format("ClassMethod::callStaticMethod called!-->str=%s," +
    " i=%d\n", str, i);
    }

    private void callInstanceMethod(String str, int i) {
    System.out.format("ClassMethod::callInstanceMethod called!-->str=%s, " +
    "i=%d\n", str, i);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    由 AccessMethod.class 生成的头文件:

/* DO NOT EDIT THIS FILE - it is machine generated /
#include <jni.h>
/
Header for class com_study_jnilearn_AccessMethod */

#ifndef _Included_com_study_jnilearn_AccessMethod
#define _Included_com_study_jnilearn_AccessMethod
#ifdef __cplusplus
extern "C" {
#endif
/*

  • Class: com_study_jnilearn_AccessMethod
  • Method: callJavaStaticMethod
  • Signature: ()V
    */
    JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessMethod_callJavaStaticMethod
    (JNIEnv *, jclass);

/*

  • Class: com_study_jnilearn_AccessMethod
  • Method: callJavaInstaceMethod
  • Signature: ()V
    */
    JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessMethod_callJavaInstaceMethod
    (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
本地代码对头文件中函数原型的实现:

// AccessMethod.c

#include "com_study_jnilearn_AccessMethod.h"

/*

  • Class: com_study_jnilearn_AccessMethod

  • Method: callJavaStaticMethod

  • Signature: ()V
    */
    JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessMethod_callJavaStaticMethod
    (JNIEnv *env, jclass cls)
    {
    jclass clazz = NULL;
    jstring str_arg = NULL;
    jmethodID mid_static_method;
    // 1、从 classpath 路径下搜索 ClassMethod 这个类,并返回该类的 Class 对象
    clazz =(*env)->FindClass(env,"com/study/jnilearn/ClassMethod");
    if (clazz == NULL) {
    return;
    }

    // 2、从 clazz 类中查找 callStaticMethod 方法
    mid_static_method = (*env)->GetStaticMethodID(env,clazz,"callStaticMethod","(Ljava/lang/String;I)V");
    if (mid_static_method == NULL) {
    printf("找不到 callStaticMethod 这个静态方法。");
    return;
    }

    // 3、调用 clazz 类的 callStaticMethod 静态方法
    str_arg = (*env)->NewStringUTF(env,"我是静态方法");
    (*env)->CallStaticVoidMethod(env,clazz,mid_static_method, str_arg, 100);

    // 删除局部引用
    (*env)->DeleteLocalRef(env,clazz);
    (*env)->DeleteLocalRef(env,str_arg);
    }

/*

  • Class: com_study_jnilearn_AccessMethod
  • Method: callJavaInstaceMethod
  • Signature: ()V
    */
    JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessMethod_callJavaInstaceMethod
    (JNIEnv *env, jclass cls)
    {
    jclass clazz = NULL;
    jobject jobj = NULL;
    jmethodID mid_construct = NULL;
    jmethodID mid_instance = NULL;
    jstring str_arg = NULL;
    // 1、从 classpath 路径下搜
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    106 引用 • 152 回帖 • 1 关注
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    333 引用 • 323 回帖 • 63 关注
  • ndk
    5 引用 • 2 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 酷鸟浏览器

    安全 · 稳定 · 快速
    为跨境从业人员提供专业的跨境浏览器

    3 引用 • 59 回帖 • 22 关注
  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1425 引用 • 10043 回帖 • 469 关注
  • Angular

    AngularAngularJS 的新版本。

    26 引用 • 66 回帖 • 510 关注
  • Dubbo

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是 [阿里巴巴] SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    60 引用 • 82 回帖 • 609 关注
  • 反馈

    Communication channel for makers and users.

    123 引用 • 906 回帖 • 195 关注
  • Bug

    Bug 本意是指臭虫、缺陷、损坏、犯贫、窃听器、小虫等。现在人们把在程序中一些缺陷或问题统称为 bug(漏洞)。

    76 引用 • 1738 回帖 • 2 关注
  • ActiveMQ

    ActiveMQ 是 Apache 旗下的一款开源消息总线系统,它完整实现了 JMS 规范,是一个企业级的消息中间件。

    19 引用 • 13 回帖 • 626 关注
  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    82 引用 • 122 回帖 • 620 关注
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    40 引用 • 40 回帖
  • 负能量

    上帝为你关上了一扇门,然后就去睡觉了....努力不一定能成功,但不努力一定很轻松 (° ー °〃)

    85 引用 • 1201 回帖 • 448 关注
  • 智能合约

    智能合约(Smart contract)是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于 1994 年由 Nick Szabo 首次提出。

    1 引用 • 11 回帖 • 3 关注
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    124 引用 • 580 回帖
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖 • 1 关注
  • V2EX

    V2EX 是创意工作者们的社区。这里目前汇聚了超过 400,000 名主要来自互联网行业、游戏行业和媒体行业的创意工作者。V2EX 希望能够成为创意工作者们的生活和事业的一部分。

    17 引用 • 236 回帖 • 411 关注
  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 604 关注
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    10 引用 • 54 回帖 • 124 关注
  • LaTeX

    LaTeX(音译“拉泰赫”)是一种基于 ΤΕΧ 的排版系统,由美国计算机学家莱斯利·兰伯特(Leslie Lamport)在 20 世纪 80 年代初期开发,利用这种格式,即使使用者没有排版和程序设计的知识也可以充分发挥由 TeX 所提供的强大功能,能在几天,甚至几小时内生成很多具有书籍质量的印刷品。对于生成复杂表格和数学公式,这一点表现得尤为突出。因此它非常适用于生成高印刷质量的科技和数学类文档。

    9 引用 • 32 回帖 • 159 关注
  • GitLab

    GitLab 是利用 Ruby 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面操作公开或私有项目。

    46 引用 • 72 回帖
  • 周末

    星期六到星期天晚,实行五天工作制后,指每周的最后两天。再过几年可能就是三天了。

    14 引用 • 297 回帖
  • 自由行
    3 关注
  • CentOS

    CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux 依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。两者的不同在于 CentOS 并不包含封闭源代码软件。

    238 引用 • 224 回帖
  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 40 关注
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    133 引用 • 3655 回帖
  • 生活

    生活是指人类生存过程中的各项活动的总和,范畴较广,一般指为幸福的意义而存在。生活实际上是对人生的一种诠释。生活包括人类在社会中与自己息息相关的日常活动和心理影射。

    228 引用 • 1450 回帖 • 2 关注
  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 17 关注
  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    711 引用 • 1173 回帖 • 162 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖