补充知识点:
一、所有系统接口的起点: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_→ vtableFindClass→ 虚函数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_opsusb_drivertty_operationsinode_operationsplatform_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"
那你已经不在"学技术",
你在进入系统工程世界。