news 2026/4/3 1:27:48

从函数表到 JNIEnv:彻底看懂 JNI 中的二级指针、结构体函数表与 -> 语法糖

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从函数表到 JNIEnv:彻底看懂 JNI 中的二级指针、结构体函数表与 -> 语法糖

关键词:JNI / JNIEnv / 二级指针 / 函数表 / 函数指针 / C 对象模型 /->语法糖 / 系统接口
适合人群:Android NDK / C / 系统层方向学习者

一、先给结论:JNI 不是函数库,是函数表

几乎所有 JNI 教程都会从这句开始:

(*env)->CallVoidMethod(env, obj, mid);

很多人被这行代码吓住,是因为:

  • 二级指针
  • *
  • ->
  • 函数指针
  • 可变参数

全叠在了一起。

但如果从系统层视角看,这行代码非常“朴素”:

👉 JNI 不是函数集合
👉 JNI 是 JVM 给 native 世界的一张函数表(能力表)

而这行代码,本质就是:

👉从函数表中取一个函数地址,然后跳过去执行。

二、什么叫“结构体函数表”?

先不谈 JNI,看一个纯 C 结构体。

1️⃣ 普通结构体(存数据)

struct Person { int age; float height; };

这是“数据结构”。

2️⃣ 函数表结构体(存函数地址)

struct Ops { void (*open)(); int (*read)(int); void (*close)(); };

这个结构体:

  • 不存业务数据
  • 每个成员都是函数指针

内存形态是:

open -> 某个函数地址 read -> 某个函数地址 close -> 某个函数地址

👉 这种结构体,在系统层就叫:

函数表 / 操作表 / 虚函数表(vtable)

一句话定义:

👉结构体里几乎全是函数指针,它就是函数表

三、JNI 的函数表是什么?

jni.h中(简化):

struct JNINativeInterface_ { jclass (*FindClass)(JNIEnv*, const char*); jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); ... };

这个结构体是什么?

👉 JVM 对外暴露的全部能力入口表

FindClass / CallVoidMethod / NewObject
都只是这张表里的“函数地址槽位”。

四、JNIEnv 到底是什么?

接着看这一句:

typedef const struct JNINativeInterface_* JNIEnv;

这句话极其关键:

👉JNIEnv本身就是一个指针类型

也就是:

JNIEnv == struct JNINativeInterface_*

所以:

👉 JNIEnv 不是对象
👉 是“指向函数表结构体的指针”

五、那JNIEnv* env又是什么?

native 方法参数是:

JNIEnv* env

把 JNIEnv 展开:

struct JNINativeInterface_** env;

所以真实关系是:

env ---> JNIEnv ---> JNINativeInterface_ 指针 指针 结构体(函数表)

结论非常清楚:

  • env:二级指针
  • *env:一级指针(函数表指针)
  • **env:函数表结构体本体

六、env 和 *env 分别是什么?

类比最普通的 C 指针:

int x = 10; int* p = &x; int** pp = &p;
表达式含义
pp指向 p 的指针
*pp
**px

JNI 中:

表达式含义
env指向函数表指针的指针
*env函数表指针
**env函数表结构体

所以这句话完全正确:

👉*env仍然是指针
👉 它是指向函数表结构体的指针

七、->到底在干嘛?(核心解惑点)

C 语言里有一个定义级别等价式

p->field ≡ (*p).field

也就是说:

👉->不是新机制
👉 它只是(*p).语法糖

作用只有一个:

先解引用指针,再访问结构体成员。

1️⃣ 普通例子

struct S { int x; }; struct S s; struct S* p = &s; p->x 等价于 (*p).x

p 是指针,
但它指向 struct,所以可以用->

2️⃣ 套回 JNI

你已经知道:

*env == struct JNINativeInterface_*

那:

(*env)->CallVoidMethod

严格展开就是:

(*(*env)).CallVoidMethod

也就是:

👉 解一次指针
👉 得到“指向结构体的指针”
👉 再解一次
👉 访问结构体里的字段

八、->CallVoidMethod到底是什么意思?

回到结构体定义:

struct JNINativeInterface_ { void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); };

所以:

table->CallVoidMethod

含义是:

👉 从结构体中,取出一个成员变量
👉 这个变量的类型是:函数指针

它不是在“调用函数”,
👉 是在取函数地址。

九、整句 JNI 拆成三行白话 C

(*env)->CallVoidMethod(env, obj, mid);

等价于:

struct JNINativeInterface_* table = *env; // ① 取函数表指针 void (*func)(JNIEnv*, jobject, jmethodID, ...) = table->CallVoidMethod; // ② 取函数地址 func(env, obj, mid); // ③ 调用

这一刻你可以清楚看到:

👉 没有魔法
👉 全是指针 + 结构体 + 函数指针调用

十、为什么 JNI 一定要设计成“函数表 + 二级指针”?

因为 JNI 是系统级 ABI 边界

它必须:

  • 跨虚拟机实现(Dalvik / ART / 未来 JVM)
  • 跨 Android 版本
  • 跨 CPU 架构
  • 保证 so 的二进制兼容

系统世界最稳定的接口形式只有一种:

👉函数表(vtable / ops table)

Linux 内核、HAL、驱动、OpenGL、FFmpeg、COM,全是这套。

十一、把这条认知链彻底钉死

👉 函数表:结构体里全是函数指针
👉 JNIEnv:指向函数表的指针
👉 env:指向“函数表指针”的指针(二级指针)
👉*env:函数表指针
👉->(*p).的语法糖
👉->CallVoidMethod:从结构体中取函数指针
👉(...):真正调用

十二、你以后应该怎样“系统级读 JNI”

当你再看到:

(*env)->FindClass(env, ...); (*env)->CallObjectMethod(env, ...);

你脑中自动翻译成:

👉 通过函数表
👉 查到函数地址
👉 用 this(env)调用

而不是:

👉 JNI 的奇怪写法。

十三、一句话系统级总结

JNI 不是函数集合,
JNI 是 JVM 的能力函数表。
env 是这张表的对象句柄。
->只是解引用 + 取成员的语法糖。
一切 JNI 调用,本质都是“查表跳转”。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/31 3:03:05

如何用M2FP提升电商模特图的处理效率?

如何用M2FP提升电商模特图的处理效率? 在电商视觉内容生产中,模特图的精细化处理是商品展示的关键环节。传统的人工抠图与标注方式耗时耗力,难以满足高频上新需求。随着AI语义分割技术的发展,自动化人体解析方案逐渐成为提升图像处…

作者头像 李华
网站建设 2026/3/17 6:33:01

M2FP模型安全:模型水印保护技术

M2FP模型安全:模型水印保护技术 📌 引言:AI模型商业化中的知识产权挑战 随着深度学习在视觉理解领域的广泛应用,像 M2FP(Mask2Former-Parsing) 这样的高性能语义分割模型正逐步从研究走向产品化。特别是在…

作者头像 李华
网站建设 2026/3/6 5:45:59

持续集成实践:每次提交自动构建镜像并运行单元测试

持续集成实践:每次提交自动构建镜像并运行单元测试 📌 背景与挑战:AI 智能中英翻译服务的工程化需求 在现代软件交付流程中,自动化是提升研发效率、保障代码质量的核心手段。以“AI 智能中英翻译服务”为例,该项目基…

作者头像 李华
网站建设 2026/4/2 8:40:59

deepseek网页版入口慢?本地部署中英翻译镜像提速300%

deepseek网页版入口慢?本地部署中英翻译镜像提速300% 你是否也遇到过:在使用 DeepSeek 等在线 AI 翻译服务时,响应缓慢、接口超时、频繁排队?尤其是在处理长文本或多轮翻译任务时,等待时间令人抓狂? 这并非…

作者头像 李华
网站建设 2026/3/26 3:30:28

M2FP模型架构深度解读:ResNet-101的优化之道

M2FP模型架构深度解读:ResNet-101的优化之道 📌 引言:多人人体解析的技术挑战与M2FP的定位 在计算机视觉领域,人体解析(Human Parsing) 是一项细粒度语义分割任务,目标是将人体图像中的每个像素…

作者头像 李华
网站建设 2026/3/28 11:06:08

M2FP在医疗诊断中的应用:病灶区域标记

M2FP在医疗诊断中的应用:病灶区域标记 🧩 M2FP 多人人体解析服务 在现代智能医疗系统中,精准的病灶区域定位与标记是实现辅助诊断、治疗规划和术后评估的关键环节。传统的医学图像分析多依赖放射科医生手动勾画病变区域,耗时且主观…

作者头像 李华