先有Class还是先有Object?
Java的对象模型中:
- 所有的类都是Class类的实例,Object是类,那么Object也是Class类的一个实例。
- 所有的类都最终继承自Object类,Class是类,那么Class也继承自Object。
这就像是先有鸡还是先有蛋的问题,请问实际中JVM是怎么处理的?
此外,可能的话,介绍一下其它面向对象语言是怎么处理这个问题的。
RednaxelaFX,从事JVM研发
首要要引用题主的问题并指出它的问题:
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.
// ...
}
就是这样。
先有Class还是先有Object?的更多相关文章
- CoreCLR源码探索(一) Object是什么
.Net程序员们每天都在和Object在打交道 如果你问一个.Net程序员什么是Object,他可能会信誓旦旦的告诉你"Object还不简单吗,就是所有类型的基类" 这个答案是对的 ...
- JavaScript Object对象
目录 1. 介绍:阐述 Object 对象. 2. 构造函数:介绍 Object 对象的构造函数. 3. 实例属性:介绍 Object 对象的实例属性:prototype.constructor等等. ...
- javascript之Object.defineProperty的奥妙
直切主题 今天遇到一个这样的功能: 写一个函数,该函数传递两个参数,第一个参数为返回对象的总数据量,第二个参数为初始化对象的数据.如: var o = obj (4, {name: 'xu', age ...
- c# 基础 object ,new操作符,类型转换
参考页面: http://www.yuanjiaocheng.net/webapi/config-webapi.html http://www.yuanjiaocheng.net/webapi/web ...
- APEX:对object中数据进行简单处理?
在Salesforce中,常常要对各种数据进行处理,已满足业务逻辑.本篇文章会介绍如何实现从object获取数据,然后将取得的数据进行一系列简单处理. 第一步:SongName__c 是一个新建的ob ...
- 笔记:Memory Notification: Library Cache Object loaded into SGA
笔记:Memory Notification: Library Cache Object loaded into SGA在警告日志中发现一些这样的警告信息:Mon Nov 21 14:24:22 20 ...
- Selenium的PO模式(Page Object Model)[python版]
Page Object Model 简称POM 普通的测试用例代码: .... #测试用例 def test_login_mail(self): driver = self.driver driv ...
- Object是什么
Object是什么 .Net程序员们每天都在和Object在打交道如果你问一个.Net程序员什么是Object,他可能会信誓旦旦的告诉你"Object还不简单吗,就是所有类型的基类" ...
- a different object with the same identifier value was already associated with the session:
hibernate操作: 实例化两个model类,更新时会提示 a different object with the same identifier value was already assoc ...
- CSharpGL - Object Oriented OpenGL in C#
Object Oriented OpenGL in C#
随机推荐
- 集成 SOLR 到 TOMCAT 中(傻瓜教程)
按照如下配置,整个 Solr 是绿色版的,可以将 Tomcat 目录复制到任何一个地方运行 1.下载 solr 4.3 版本 2.下载 Tomcat 7 ( 6 也可以),另外可以根据系统下载 32 ...
- Django项目部署(django+guncorn+virtualenv+nginx)
一.说明 为了django项目部署到生产环境上,能够稳定的运行,且能够同时指出http和https的访问,对django的部署进行了一些研究,决定采用django + gunicorn + virtu ...
- hdu5646(数学)
小学数学,脑补 一开始看到这题,猜了个规律想写但是我是拒绝的. 因为我无法证明. 好吧,主要还是小学数学没学好吧. 要理解这题,首先得搞懂一个重要问题.假设C=A+B,怎样选择两个正整数使得A*B最大 ...
- 【BZOJ3638】Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)
[BZOJ3638]Cf172 k-Maximum Subsequence Sum Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交 ...
- 《从零开始学Swift》学习笔记(Day 18)——有几个分支语句?
原创文章,欢迎转载.转载请注明:关东升的博客 分支语句又称条件语句,Swift编程语言提供了if.switch和guard三种分支语句. if语句 由if语句引导的选择结构有if结构.if ...
- MVC5学习系列
前言 嗷~小弟我又出现了~咳咳..嚎过头了, 先说一说为什么写这个吧,~首先肯定是我自己需要学(废话 - -,)//,之前也写过MVC4的项目,嗯..但是仅限于使用并没有很深入的每个模块去了解, 这段 ...
- Hystrix 基于注解开发
不对地方,请指出!相互学习! 背景:Hystrix 没有无参构造函数,所以Spring管理bean时候没办法进行管理, 每个类都进行编码 个人感觉不方便,基于注解开发!方便速度快,不侵入代码!引入的j ...
- MySQL中InnoDB存储引擎中的哈希算法
InnoDB存储引擎使用哈希算法来对字典进行查找,其冲突机制采用链表方式,哈希函数采用除法散列方式.对于缓冲池页的哈希表来说,在缓冲池中的Page页都有一个chain指针.它指向相同哈希函数值的页的. ...
- document write & close
在载入页面后,浏览器输出流自动关闭.在此之后,任何一个对当前页面进行操作的document.write()方法将打开—个新的输出流,它将清除当前页面内容. 必须确保调用document.close() ...
- Solr schema.xml中修改id的类型为int
使用solr6的版本的时候(solr5不存在这个问题),在修改schema.xml的field时,想使用int做为id的数据类型,修改后重新加载配置的时候报错.原来schema.xml中field i ...