--- category: - Java核心 tag: - Java --- # 先有Class还是先有Object? Java 对象模型中: - 所有的类都是Class类的实例,Object是类,那么Object也是Class类的一个实例。 - 所有的类都最终继承自Object类,Class是类,那么Class也继承自Object。 那到底是先有Class还是先有Object? JVM 是怎么处理这个“鸡·蛋”问题呢? ![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/basic-extra-meal/class-object-2f47490c-70b8-41b8-9551-42c2f98eea91.png) 针对这个问题,我在知乎上看到了 R 大的一个回答,正好解答了我心中的疑惑,就分享出来给各位小伙伴一个参考和启发~ >作者:RednaxelaFX,整理:沉默王二,参考链接:https://www.zhihu.com/question/30301819/answer/47539163 ----- “鸡・蛋”问题通常都是通过一种叫“自举”(bootstrap)的过程来解决的。 “鸡蛋问题”的根本矛盾就在于假定了“鸡”或“蛋”的其中一个要先进入“完全可用”的状态。而许多现实中被简化为“鸡蛋问题”的情况实际可以在“混沌”中把“鸡”和“蛋”都初始化好,而不存在先后问题;在它们初始化的过程中,两者都不处于“完全可用”状态,而完成初始化后它们就同时都进入了可用状态。 打个比方,番茄炒蛋。并不是要先把番茄完全炒好,然后把鸡蛋完全炒好,然后把它们混起来;而是先炒番茄炒到半熟,再炒鸡蛋炒到半熟,然后把两个半熟的部分混在一起同时炒熟。 对于**先有Class还是先有Object**这个问题来说,题主假设所有的类都是Class类的实例,Object是类,那么Object也是Class类的一个实例,这个假设就是错的。 `java.lang.Object`是一个Java类,但并不是`java.lang.Class`的一个实例。后者只是一个用于描述Java类与接口的、用于支持反射操作的类型。这点上Java跟其它一些更纯粹的面向对象语言(例如Python和Ruby)不同。 第二个假设“所有的类都最终继承自Object类,Class是类,那么Class也继承自Object”是对的,`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阶段还是已经完全初始化好: ``` static bool is_bootstrapping() { return _bootstrapping; } static bool is_fully_initialized() { return _fully_initialized; } ``` 然后`Universe::genesis()`函数会在bootstrap阶段中创建核心类型的对象模型,其中会调用`SystemDictionary::initialize()`来初始化对象系统的核心类型,其中会进一步跑到`SystemDictionary::initialize_preloaded_classes()`来创建`java.lang.Object`、`java.lang.Class`等核心类型。 这个函数在加载了`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); 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. // ... } ``` 就是这样:“**Object里有一个成员变量指向Class类实例c,c保存这个Object成员、方法的名字和地址的Map映射用作反射**。”涉及到主类有这么几个: ``` http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/ade5be2b1758/src/share/vm/memory/universe.hpp#l399 http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/ade5be2b1758/src/share/vm/memory/universe.cpp#l259 http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/ade5be2b1758/src/share/vm/classfile/systemDictionary.cpp#l1814 ``` 分享的最后,二哥要简单说两句,每次看 R 大的内容,总是感觉膝盖忍不住要跪一下,只能说写过 JVM 的男人就是不一样。喜欢研究 CPP 源码的话小伙伴可以再深入学习下,一定会有所收获。 ---- 最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html) 关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。 ![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)