先有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#
随机推荐
- PHP中如何配置smarty框架实现PHP代码和HTML代码分离
header('Cache-Control:Private');//保留用户填写的信息 session_start();//开启缓存 define('MYCMS','UTF-8');//定义网站编码常 ...
- 使用RestTemplate post方式提交表单数据
HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODE ...
- JQuery处理DOM元素
现有一个id为txtMyTest的元素 获取属性值 $('#id').attr('属性名'); 设置属性值 $('#id').attr('属性名','需要设置的值'); 设置多个属性 如下同时设置va ...
- Redis 单机版本安装
亲装! 1.linux 系统镜像 redis 版本 使用redis-3.2.8.tar.gz(截止2017年4月的最新稳定版) 在安装之前先安装下redis 需要的环境 wget http://do ...
- 打日志--以python为例
日志报错要去修,要不然是隐患,总有一天会爆炸 增加日志是排错的好方法,不要不舍得加日志,比如怕代码变难看,怕日志输出太多. python logging exc_info sys.exc_info() ...
- sql的reader方法注意事项
如果恢复注释. 在数据只有一条时,list将始终为空 原因很简单. 第一个红框已经跑完了.第二次调用的时候,就是第二条了,此时数据为空
- Centos中查询目录中内容命名ls(六)
首先解释下这块, root代表当前登录用户,localhost代表主机名, ~代表当前主机目录,#代表用户权限 #表示超级用户,$表示普通用户: 查询目录中内容命令 ls (list缩写) 格式 l ...
- 接口测试工具 — postman(post请求)
1.登录接口 2.添加学生信息,这个接口是用来讲入参是json类型的 3.学生金币充值接口,这个接口是为了讲添加cookie以及身份验证的 4.上传文件接口
- 什么是PHP闭包???
闭包函数:临时创建一个没有名称的函数,经常作为回调函数来用. 通俗的说就是:子函数可以使用父函数中的局部变量,这种行为叫做闭包. 1.匿名函数赋值 $demo=function($str){ echo ...
- Docker介绍及优缺点对比分析
1.什么是Docker Docker最初是dotCloud公司创始人Solomon Hykes在法国期间发起的一个公司内部项目,于2013年3月以Apache 2.0授权协议开源,主要项目代码在Git ...