如果您不考虑方法重写,那么您可以将 Java 类和方法视为一对 C 风格struct
以及一组对这些进行操作的函数struct
s。例如,如果你有一个这样的类:
public class MyJavaClass {
private int x;
public int getX() {
return x;
}
public int setX(int value) {
x = value;
}
}
这与编写 C 代码类似:
struct MyJavaClass {
int x;
};
int MyJavaClass_getX(struct MyJavaClass* this) {
return this->x;
}
void MyJavaClass_setX(struct MyJavaClass* this, int value) {
this->x = value;
}
主要思想是方法类似于将接收者对象作为隐式“this”参数的函数。在 C 中,您必须显式地将接收者作为参数传递给函数,而在 Java 中,这是通过隐式完成的object.method()
syntax.
如果您开始引入方法重写,这会变得有点复杂,因为您在对象上调用的方法取决于dynamic对象的类型,而不是static类型。模拟这种情况的一种方法是使用称为vtable or 虚函数表,因C++而得名virtual
关键词。这个想法是,每个对象存储一个指向函数指针表的指针,每个函数都有一个可以被重写的指针,并且当在对象上调用方法时,从表中选择适当的函数指针并调用。因此,更准确地说,上面的 Java 对象可能看起来像这样:
struct MyJavaClass_Vtable {
void (*getX)(struct MyJavaClass* this);
void (*setX)(struct MyJavaClass* this, int value);
};
struct MyJavaClass {
struct MyJavaClass_Vtable* vtable;
int x;
};
int MyJavaClass_getX(struct MyJavaClass* this) {
return this->x;
}
void MyJavaClass_setX(struct MyJavaClass* this, int value) {
this->x = value;
}
/* A global instance of the vtable for MyJavaClass */
struct MyJavaClass_Vtable MyJavaClassVtableInstance = {
&MyJavaClass_getX,
&MyJavaClass_setX
};
每当你创建一个实例时MyJavaClass
,您可以设置其 vtable 执行如下操作:
struct MyJavaClass* mjc = malloc(sizeof *mjc);
mjc->vtable = &MyJavaClassVtableInstance;
然后,当调用这样的函数时(在 Java 中):
myJavaClass.getX();
在C中它看起来像
myJavaClass->vtable->getX(myJavaClass);
所以从某种意义上说,Java 类只是一个带有一些额外元信息的结构。当然,对于程序员来说,它看起来完全不同 - 有封装、多态性、更严格的类型系统等 - 但在本机代码级别,常规 C 结构和 Java 类可能看起来非常相似。
希望这可以帮助!