从 C 对象模型 → JNI → HAL → Linux 内核接口——一条贯穿系统软件的完整认知链

补充知识点:

从 C 对象模型看 JNI:一行 (*env)->CallVoidMethod 背后的系统级真相

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

一、所有系统接口的起点:C 语言"对象模型"

C 语言没有 class、没有 interface、没有 virtual。

但 Linux、Android、JVM、驱动、图形系统,全都需要:

  • 抽象接口
  • 模块解耦
  • 运行时切换实现
  • 多态能力

于是 C 世界形成了一套事实标准:

👉 struct 保存状态 + 函数指针保存行为

这就是所谓:

✅ C 语言对象模型

1. 最小对象模型

cpp 复制代码
struct Counter {
    int value;                         // 状态
    void (*inc)(struct Counter* self); // 行为
};
cpp 复制代码
void counter_inc(struct Counter* self) {
    self->value++;
}
cpp 复制代码
Counter c;
c.value = 0;
c.inc = counter_inc;
c.inc(&c);

你已经拥有了:

  • 对象(状态)
  • 方法(函数指针)
  • this(self)

👉 这在语义上已经是"面向对象"。

2. vtable(虚函数表)模型

系统里更常见的是这一层:

cpp 复制代码
struct CounterVTable {
    void (*inc)(struct Counter* self);
};

struct Counter {
    int value;
    const struct CounterVTable* vptr;
};

调用方式:

cpp 复制代码
counter->vptr->inc(counter);

👉 这已经和 C++ 虚函数机制几乎完全一致。

二、JNI:C 对象模型在虚拟机边界的体现

当你学 JNI 时,看到的是:

cpp 复制代码
(*env)->FindClass(env, "java/lang/String");

如果站在 C 对象模型视角,它非常直白:

  • env → 对象
  • JNINativeInterface_ → vtable
  • FindClass → 虚函数
  • env 作为第一个参数 → this

1. JNI 的真实结构

cpp 复制代码
struct JNINativeInterface_ {
    jclass (*FindClass)(JNIEnv*, const char*);
    jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
    jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
    ...
};

typedef const struct JNINativeInterface_* JNIEnv;

调用:

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

等价于:

env.vptr->CallVoidMethod(env, obj, mid);

👉 JNI 不是"库函数调用",

👉 JNI 是"通过接口表调用虚拟机能力"。

2. JNI 在整条链里的位置

cpp 复制代码
Java / Kotlin
     ↓
JNI (接口边界)
     ↓
C 对象模型(函数表)
     ↓
ART 虚拟机内部实现

JNI 本质是:

✅ 虚拟机向 native 世界暴露的一套"对象接口"。

三、HAL:系统服务与驱动之间的对象接口层

HAL(Hardware Abstraction Layer)是 Android 非常典型的系统层。

它的核心作用只有一句话:

👉 用统一接口,屏蔽不同硬件实现。

而它在代码层的实现,仍然是:

👉 struct + 函数指针

1. 典型 HAL 结构

cpp 复制代码
struct audio_hw_device {
    int (*init)(struct audio_hw_device* dev);
    int (*start)(struct audio_hw_device* dev);
    int (*stop)(struct audio_hw_device* dev);
};

不同厂商提供不同实现:

cpp 复制代码
struct audio_hw_device my_audio_dev = {
    .init = my_init,
    .start = my_start,
    .stop = my_stop
};

Framework 统一调用:

dev->start(dev);

👉 HAL 本质就是:

系统级接口对象 + 不同厂商的 vtable 实现。

2. HAL 在整条链的位置

cpp 复制代码
App / Framework
       ↓
   JNI / Binder
       ↓
   System Service
       ↓
        HAL   ←(统一接口层)
       ↓
   Vendor 实现
       ↓
    Driver

HAL 不是"模块",

HAL 是接口层设计思想的产物。

四、Linux 内核:这套模型的源头

如果你进 Linux 内核,你会发现:

👉 几乎每一个子系统,都是"对象模型"。

1. 最经典的例子:file_operations

cpp 复制代码
struct file_operations {
    ssize_t (*read)(struct file*, char __user*, size_t, loff_t*);
    ssize_t (*write)(struct file*, const char __user*, size_t, loff_t*);
    int (*open)(struct inode*, struct file*);
};

ext4、procfs、设备文件,各自提供不同实现。

内核统一调用:

cpp 复制代码
file->f_op->read(file, buf, len, &pos);

👉 这就是内核级"多态"。

2. 再看几个你以后一定会遇到的

  • net_device_ops
  • usb_driver
  • tty_operations
  • inode_operations
  • platform_driver

它们结构完全一样:

👉 状态 struct + 操作表 ops

五、把四个层级放到一张统一认知图里

cpp 复制代码
【应用世界】
Java / Kotlin / Flutter
    ↓
【语言边界】
JNI / FFI
    ↓
【系统抽象层】
HAL / Service / Middleware
    ↓
【操作系统层】
Linux Kernel (VFS / Net / Driver)
    ↓
【硬件】

而贯穿全部层级的唯一共性是:

✅ struct + 函数指针

✅ 对象 + 方法表

✅ self / ctx 作为第一个参数

六、你以后如何"系统级读代码"

以后你再看到这种代码:

cpp 复制代码
dev->ops->write(dev, buf, len);
(*env)->CallVoidMethod(env, obj, mid);
engine->vptr->start(engine);

你要自动翻译成:

👉 对象

👉 接口表

👉 虚函数

👉 动态分发

👉 系统边界

这是一种系统工程视角,不是 API 视角。

七、一句话系统级总结

JNI 是虚拟机的对象接口

HAL 是系统的对象接口

Linux 内核是操作系统的对象接口

C 对象模型,是它们共同的语言。

八、检验你是否真正进入"系统层视角"

如果你现在看到:

struct xxx_ops { ... };

xxx->ops->do(xxx);

你脑子里出现的是:

👉 "对象模型 + vtable + 边界 + 可替换实现"

而不是:

👉 "这是什么 API"

那你已经不在"学技术",

你在进入系统工程世界。

相关推荐
LHICOD9 分钟前
Linux-2
java·linux·后端·jar·vmware·svm·vm
4ever.ov014 分钟前
精学C++第一站 从命名空间到引用:C++入门核心语法全梳理(13000字长文)
开发语言·c++·clion
余额瞒着我当琳14 分钟前
Linux初识:Linux的历史,计算机的发展脉络,发行版本,选购云服务器,安装Xshell,第一次连接,基础命令指南
linux·运维·服务器
小杨互联网15 分钟前
Go 现代 CLI 工具离线镜像合集
开发语言·后端·golang·开源·go·命令行
揽星河..22 分钟前
【C语言】数组
c语言·开发语言·算法
FRing0325 分钟前
JavaScript入门到精通三十三(异常处理、call方法、apply方法、bind方法、防抖、节流)
开发语言·前端·javascript
geovindu31 分钟前
rust: Semaphore Pattern
开发语言·后端·设计模式·rust·代理模式·企业级信号量模式·同步型模式
垆边人似月.37 分钟前
RDMA 文件传输踩坑(四):从固定延时改造为 READY/ACK 协议
linux·服务器·网络
水饺编程39 分钟前
第2章:Linux 基础,制作【.tar.xz】压缩包文件
linux·c语言·汇编
阿里云基础软件1 小时前
Agent 任务提速 10.71%,内存占用降低 21.60%|Alibaba Cloud Linux 4 重大发布
java·linux·人工智能·操作系统·agent