作者:RednaxelaFX
链接:https://www.zhihu.com/question/30301819/answer/47539163
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
简短答案:“鸡・蛋”问题通常都是通过一种叫“自举”(bootstrap)的过程来解决的。
其实“鸡蛋问题”的根本矛盾就在于假定了“鸡”或“蛋”的其中一个要先进入“完全可用”的状态。而许多现实中被简化为“鸡蛋问题”的情况实际可以在“混沌”中把“鸡”和“蛋”都初始化好,而不存在先后问题;在它们初始化的过程中,两者都不处于“完全可用”状态,而完成初始化后它们就同时都进入了可用状态。
打个比方,番茄炒蛋。并不是要先把番茄完全炒好,然后把鸡蛋完全炒好,然后把它们混起来;而是先炒番茄炒到半熟,再炒鸡蛋炒到半熟,然后把两个半熟的部分混在一起同时炒熟。
引用题主的问题:
Java的对象模型中:
- 所有的类都是Class类的实例,Object是类,那么Object也是Class类的一个实例。
- 所有的类都最终继承自Object类,Class是类,那么Class也继承自Object。
这个问题中,第1个假设是错的:java.lang.Object是一个Java类,但并不是java.lang.Class的一个实例。后者只是一个用于描述Java类与接口的、用于支持反射操作的类型。这点上Java跟其它一些更纯粹的面向对象语言(例如Python和Ruby)不同。
而第2个假设是对的:java.lang.Class是java.lang.Object的派生类,前者继承自后者。
虽然第1个假设不对,但“鸡蛋问题”仍然存在:在一个已经启动完毕、可以使用的Java对象系统里,必须要有一个java.lang.Class实例对应java.lang.Object这个类;而java.lang.Class是java.lang.Object的派生类,按“一般思维”前者应该要在后者完成初始化之后才可以初始化…
事实是:这些相互依赖的核心类型完全可以在“混沌”中一口气都初始化好,然后对象系统的状态才叫做完成了“bootstrap”,后面就可以按照Java对象系统的一般规则去运行。JVM、JavaScript、Python、Ruby等的运行时都有这样的bootstrap过程。
在“混沌”(boostrap过程)里,
- JVM可以为对象系统中最重要的一些核心类型先分配好内存空间,让它们进入[已分配空间]但[尚未完全初始化]状态。此时这些对象虽然已经分配了空间,但因为状态还不完整所以尚不可使用。
- 然后,通过这些分配好的空间把这些核心类型之间的引用关系串好。到此为止所有动作都由JVM完成,尚未执行任何Java字节码。
- 然后这些核心类型就进入了[完全初始化]状态,对象系统就可以开始自我运行下去,也就是可以开始执行Java字节码来进一步完成Java系统的初始化了。
在HotSpot VM里,有一个叫做“Universe”的C++类用于记录对象系统的总体状态。它有这么两个有趣的字段记录当前是处于bootstrapping阶段还是已经完全初始化好:
jdk8u/jdk8u/hotspot: ade5be2b1758 src/share/vm/memory/universe.hpp
static bool is_bootstrapping() { return _bootstrapping; }
static bool is_fully_initialized() { return _fully_initialized; }
然后Universe::genesis()函数会在bootstrap阶段中创建核心类型的对象模型:
jdk8u/jdk8u/hotspot: ade5be2b1758 src/share/vm/memory/universe.cpp
(“genesis”是创世纪的意思,多么形象)
其中会调用SystemDictionary::initialize()来初始化对象系统的核心类型:
jdk8u/jdk8u/hotspot: ade5be2b1758 src/share/vm/classfile/systemDictionary.cpp
其中会进一步跑到SystemDictionary::initialize_preloaded_classes()来创建java.lang.Object、java.lang.Class等核心类型:
jdk8u/jdk8u/hotspot: ade5be2b1758 src/share/vm/classfile/systemDictionary.cpp
这个函数在加载了java.lang.Object、java.lang.Class等核心类型后会调用Universe::fixup_mirrors()来完成前面说的“把引用关系串起来”的动作:
// Fixup mirrors for classes loaded before java.lang.Class.
// These calls iterate over the objects currently in the perm gen
// so calling them at this point is matters (not before when there
// are fewer objects and not later after there are more objects
// in the perm gen.
Universe::initialize_basic_type_mirrors(CHECK);
Universe::fixup_mirrors(CHECK);
jdk8u/jdk8u/hotspot: ade5be2b1758 src/share/vm/memory/universe.cpp
void Universe::fixup_mirrors(TRAPS) {
// Bootstrap problem: all classes gets a mirror (java.lang.Class instance) assigned eagerly,
// but we cannot do that for classes created before java.lang.Class is loaded. Here we simply
// walk over permanent objects created so far (mostly classes) and fixup their mirrors. Note
// that the number of objects allocated at this point is very small.
// ...
}
就是这样。
=======================================================
Python里的对象系统里也有这种“鸡蛋问题”,也是通过一个bootstrap过程来解决。
“鸡蛋问题”在于:Python里的所有类型都确实用一个type object表示,而所有类型都是object类的子类。
换句话说,<type 'type'>类是<type 'object'>的子类;而<type 'object'>既是类又是个对象,是<type 'type'>的实例。这个情况就跟题主原本所想像的Java里的情况一样——虽然Java并非如此。
关于CPython 2.5的对象系统初始化的剖析,可以参考《Python源码剖析》的第12章。
具体到CPython 2.7.x的代码,pythonrun.c的Py_InitializeEx()会做Python运行时的初始化,其中会调用object.c的_Py_ReadyTypes()来按照一个列表的顺序初始化核心类型的type对象,具体的初始化动作在typeobject.c的PyType_Ready()。
这些核心类型的type对象在CPython里的C层面的类型是PyTypeObject,其结构是确定的;它们的存储空间通过静态变量分配,例如<type 'type'>就声明为在object.h的PyTypeObject PyType_Type,对应的还有<type 'object'>的PyTypeObject PyBaseObject_Type。
所以在进行初始化动作之前它们的存储空间就已经有着落了,真正做初始化时只要把它们的相互引用串起来就好。
=======================================================
Ruby里的鸡蛋问题跟Python比较相似。Ruby里的所有类都是Class类的实例,而Class类是Object类的子类。
以CRuby 2.2.1为例,核心类型的初始化在这里:class.c的Init_class_hierarchy(),可以看到也是典型的bootstrap过程:先分配空间,再把相互引用关系串起来,然后完成bootstrap开始进入正常的对象系统运作。
void
Init_class_hierarchy(void)
{
/* 给核心类型的Class对象实例分配空间并串上它们的继承关系 */
rb_cBasicObject = boot_defclass("BasicObject", 0);
rb_cObject = boot_defclass("Object", rb_cBasicObject);
rb_cModule = boot_defclass("Module", rb_cObject);
rb_cClass = boot_defclass("Class", rb_cModule);
rb_const_set(rb_cObject, rb_intern_const("BasicObject"), rb_cBasicObject);
/* 让上面创建的Class对象实例的类型信息(klass字段)指向Class对象 */
RBASIC_SET_CLASS(rb_cClass, rb_cClass);
RBASIC_SET_CLASS(rb_cModule, rb_cClass);
RBASIC_SET_CLASS(rb_cObject, rb_cClass);
RBASIC_SET_CLASS(rb_cBasicObject, rb_cClass);
}
然后看调用它的上层函数:
/*!
* Initializes the world of objects and classes.
*
* At first, the function bootstraps the class hierarchy.
* It initializes the most fundamental classes and their metaclasses.
* - \c BasicObject
* - \c Object
* - \c Module
* - \c Class
* After the bootstrap step, the class hierarchy becomes as the following
* diagram.
*
* \image html boottime-classes.png
*
* Then, the function defines classes, modules and methods as usual.
* \ingroup class
*/
/* ... */
void
Init_Object(void)
{
Init_class_hierarchy();
/* ... */
}
赞同 87163 条评论
分享
收藏感谢收起
音频码农/业余编曲渣/Vimer/应邀看心情
24 人赞同了该回答
object.h:
typedef struct _Object Object;
typedef struct _Class Class;
struct _Object {
Class* klass; // each Object should contain a pointer to its metaclass,
// which also works as a vtable
};
typedef void (*Ctor)(Object* self, ...);
typedef void (*Dtor)(Object* self);
struct _Class {
Object base; // a Class is an Object, so it
// must derive from Object
char* name; // name of the type
Class* baseClass; // the base class
size_t instanceSize; // size of an instance
Ctor instanceCtor; // constructor of the corresponding
// instance type
Dtor instanceDtor; // destructor of the corresponding
// instance type
};
extern Class ObjectType; // the 'Object' object
extern Class ClassType; // the 'Class' object
Object* New(Class* type, ...); // allocate an object
void Delete(Object* self); // deallocate an object
void Object_ctor(Object* self); // constructor of Object
void Object_dtor(Object* self); // destructor of Object
void Class_ctor(Class* self); // constructor of Class
void Class_dtor(Class* self); // destructor of Class
char* Class_getName(Class* self);
Class* Object_getClass(Object* self); // get the type of an object
Class* Object_getBaseClass(Object* self); // get the type of the base class
// of an object
object.c:
#include <stdlib.h>
#include "object.h"
Class ObjectType = {
{ &ClassType }, // the "Object" object is a Class
"Object",
&ObjectType, // Object's base is Object
sizeof(Object),
(Ctor)Object_ctor,
(Dtor)Object_dtor,
};
Class ClassType = {
{ &ClassType }, // the "Class" object is also a Class!
"Class",
&ObjectType, // Class's base is Object!
sizeof(Class),
(Ctor)Class_ctor,
(Dtor)Class_dtor,
};
void Object_ctor(Object* self)
{}
void Object_dtor(Object* self)
{}
void Class_ctor(Class* self)
{}
void Class_dtor(Class* self)
{}
char* Class_getName(Class* self)
{
return self->name;
}
Class* Object_getClass(Object* self)
{
return self->klass;
}
Class* Object_getBaseClass(Object* self)
{
return self->klass->baseClass;
}
Object* New(Class* type, ...)
{
Object* obj = malloc(type->instanceSize);
obj->klass = type;
type->instanceCtor(obj);
return obj;
}
void Delete(Object* self)
{
self->klass->instanceDtor(self);
free(self);
}
main.c:
#include <stdio.h>
#include "object.h"
// define a type called "MyObject"
typedef struct _MyObject MyObject;
typedef struct _MyObjectClass MyObjectClass;
struct _MyObject {
Object base; // MyObject derives from Object
};
struct _MyObjectClass {
Class base; // MyObjectClass derives from Class
};
MyObjectClass MyObjectType = {
{
{ &ClassType }, // the "MyObject" object is a Class
"MyObject",
&ObjectType, // MyObject is derived from Object
sizeof(MyObject),
(Ctor)Object_ctor,
(Dtor)Object_dtor,
},
};
int main(void)
{
Object* obj1 = New(&ObjectType);
MyObject* obj2 = (MyObject*)New((Class*)&MyObjectType);
printf("%s\n", Class_getName(Object_getClass(obj1))); // "Object"
printf("%s\n", Class_getName(Object_getBaseClass(obj1))); // "Object"
printf("%s\n", Class_getName(Object_getClass((Object*)obj2))); // "MyObject"
printf("%s\n", Class_getName(Object_getBaseClass((Object*)obj2))); // "Object"
printf("%s\n", Class_getName(Object_getClass((Object*)&MyObjectType))); // "Class"
printf("%s\n", Class_getName(Object_getBaseClass((Object*)&MyObjectType))); // "Object"
printf("%s\n", Class_getName(Object_getClass((Object*)&ObjectType))); // "Class"
printf("%s\n", Class_getName(Object_getBaseClass((Object*)&ObjectType))); // "Object"
printf("%s\n", Class_getName(Object_getClass((Object*)&ClassType))); // "Class"
printf("%s\n", Class_getName(Object_getBaseClass((Object*)&ClassType))); // "Object"
Delete(obj1);
Delete((Object*)obj2);
return 0;
}
Clang 3.6 测试通过