出自《java puzzle》
假如小报是可信的,那么摇滚之王“猫王”就会直到今天仍然在世。下面的程序用来估算猫王当前的腰带尺寸,方法是根据在公开演出中所观察到的他的体态发展趋势来进行投射。该程序中使用了Calendar.getInstance().get(Calendar.YEAR)这个惯用法,它返回当前的日历年份。那么,该程序会打印出什么呢?
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private final int beltSize;
private static final int CURRENT_YEAR =
Calendar.getInstance().get(Calendar.YEAR);
private Elvis() {
beltSize = CURRENT_YEAR - 1930;
}
public int beltSize() {
return beltSize;
}
public static void main(String[] args) {
System.out.println("Elvis wears a size " +
INSTANCE.beltSize() + " belt.");
}
}
第一眼看去,这个程序是在计算当前的年份减去1930的值。如果它是正确的,那么在2006年,该程序将打印出Elvis wears a size 76 belt。如果你尝试着去运行该程序,你就会了解到小报是错误的,这证明你不能相信在报纸到读到的任何东西。该程序将打印出Elvis wears a size -1930 belt。也许猫王已经在反物质的宇宙中定居了。
该程序所遇到的问题是由类初始化顺序中的循环而引起的[JLS 12.4]。让我们来看看其细节。Elvis类的初始化是由虚拟机对其main方法的调用而触发的。首先,其静态域被设置为缺省值[JLS 4.12.5],其中INSTANCE域被设置为null,CURRENT_YEAR被设置为0。接下来,静态域初始器按照其出现的顺序执行。第一个静态域是INSTANCE,它的值是通过调用Elvis()构造器而计算出来的。
这个构造器会用一个涉及静态域CURRENT_YEAR的表达式来初始化beltSize。通常,读取一个静态域是会引起一个类被初始化的事件之一,但是我们已经在初始化Elvis类了。递归的初始化尝试会直接被忽略掉[JLS 12.4.2, 第3步]。因此,CURRENT_YEAR的值仍旧是其缺省值0。这就是为什么Elvis的腰带尺寸变成了-1930的原因。
最后,从构造器返回以完成Elvis类的初始化,假设我们是在2006年运行该程序,那么我们就将静态域CURRENT_YEAR初始化成了2006。遗憾的是,这个域现在所具有的正确值对于向Elvis.INSTANCE.beltSize的计算施加影响来说已经太晚了,beltSize的值已经是-1930了。这正是后续所有对Elvis.INSTANCE.beltSize()的调用将返回的值。
该程序表明,在final类型的静态域被初始化之前,存在着读取它的值的可能,而此时该静态域包含的还只是其所属类型的缺省值。这是与直觉相违背的,因为我们通常会将final类型的域看作是常量。final类型的域只有在其初始化表达式是常量表达式时才是常量[JLS 15.28]。
由类初始化中的循环所引发的问题是难以诊断的,但是一旦被诊断到,通常是很容易订正的。要想订正一个类初始化循环,需要重新对静态域的初始器进行排序,使得每一个初始器都出现在任何依赖于它的初始器之前。在这个程序中,CURRENT_YEAR的声明属于在INSTANCE声明之前的情况,因为Elvis实例的创建需要CURRENT_YEAR被初始化。一旦CURRENT_YEAR的声明被移走,Elvis就真的比生命更大了。
某些通用的设计模式本质上就是初始化循环的,特别是本谜题所展示的单例模式(Singleton)[Gamma95]和服务提供者框架(Service Provider Framework)[EJ Item 1]。类型安全的枚举模式(Typesafe Enum pattern)[EJ Item 21]也会引起类初始化的循环。5.0版本添加了对这种使用枚举类型的模式的语言级支持。为了减少问题发生的可能性,对枚举类型的静态初始器做了一些限制[JLS 16.5, 8.9]。
总之,要当心类初始化循环。最简单的循环只涉及到一个单一的类,但是它们也可能涉及多个类。类初始化循环也并非总是坏事,但是它们可能会导致在静态域被初始化之前就调用构造器。静态域,甚至是final类型的静态域,可能会在它们被初始化之前,被读走其缺省值。
分享到:
相关推荐
【大学生生命教育与心理危机应对】是一门关注大学生心理健康与成长的重要课程,旨在引导大学生正确认识生命的意义,提升自我心理调适能力,有效预防和应对可能出现的心理危机。生命教育,顾名思义,是对生命的理解和...
- **生命意义游戏化**:将生命的追求简化为游戏或娱乐,忽略了生命更深层次的意义。 #### 六、追寻生命的意义 - **追寻生命意义的必要性**: - **引领生命的方向**:明确生命的目标和价值,指引前进的方向。 - *...
《生命生命》这篇课文主要探讨了生命的意义和价值,通过三个不同的事例引导读者思考如何珍视和理解...通过深入阅读和思考,我们可以更好地理解和尊重生命,明白每一个生命都有其独特的价值,应该尽全力去珍惜和发挥。
【有生命主语句与无生命主语句】这一主题主要探讨的是在英语中,主语如何被分类为有生命和无生命,并分析了这两种类型的主语句在句法和语义上的特点。主讲人Susan通过讲解和举例,帮助我们理解这一概念。 在英语中...
【生命教育:教育的核心议题】 ...通过生命教育,大学生可以更好地理解自我,认识生命的多重维度,学会珍视和尊重生命,形成健康的人生观和价值观,从而更好地应对生活中的困难和压力,实现个人和社会的和谐发展。
当我们将个体命运与更大的集体联系在一起时,平凡也能闪耀出伟大。 最后,课程鼓励学生进行合作探究,思考如何让生命充盈,如何传递温暖,以及如何实现个人价值。同时,通过课后练习和反思,促进学生深入理解和内化...
3. 生命的来之不易:尽管我们最终都会面临死亡,但不能轻易放弃生命,因为生命是大自然的馈赠,每个生命都是经过无数复杂过程才得以诞生,这使生命变得尤为宝贵。我们应当尊重并感激这一份来之不易的礼物。 4. 对...
【正文】 《浅谈孔子生命观在当代大学生生命观...通过深入学习和实践孔子的生命观,我们可以助力大学生树立正确的生命观,让他们在面临压力和困境时,能以健康的心态和行动去面对和解决问题,从而更好地成长和发展。
总的来说,生命观念视域下的生物学大概念深度学习实践强调了在教学中不仅传授知识,更要培养学生的思维方式和价值观。通过精心设计的教学策略,教师可以引导学生形成科学的生命观念,提高他们的生物学素养,为未来...
《生命游戏Golly:探索细胞自动机与人工生命的奇妙世界》 生命游戏,全称“康威的生命游戏”,是由英国数学家约翰·何顿·康威在1970年提出的一种简单的计算机模拟系统,它是细胞自动机的一个经典实例。细胞自动机...
作者选择这些小生命,可能是为了更直观地展示生命的普遍性和顽强性,让读者深感生命的奇迹。 3. 尽管小瓜苗只存活了几天,但它在恶劣环境中萌发、成长,甚至努力开花的过程,无疑展现了一种不屈不挠的精神。这种...
每个人都有独一无二的生命,我们应当对自己负责,珍视每一刻,因为生命不仅仅是活着,更是在每一个瞬间体验和创造。 综上所述,这篇课件以生动的例子揭示了生命的顽强、不屈和独特价值。生命不仅在于生存,更在于...
《生命探测仪:一款创新的蓝牙通信应用》 在当今科技日新月异的时代,通信技术的发展极大...随着技术的不断进步,我们期待看到更多像“生命探测仪”这样富有创意和实用性的应用出现,为人类生活带来更多的便利与安全。
文中提到校长讲述钱穆的故事,强调即使在艰难环境中,也要坚守文化和学术的使命与尊严,这对于学生来说,比获得学位更重要。 3. 学术信念的传承:钱穆的《国史大纲》和他的教学理念,体现了他对传统文化的热爱和对...
自1998年《数据仓库生命周期工具箱(第2版)》第一版出版以来,经过十多年的发展,数据仓库行业已经完全成熟,而且软硬件都有了极大的进步。那一版所提出的方法几乎已经被所有的数据仓库厂商和从业人员所采纳。现在,...
【大学生生命教育及心理危机应对】是针对大学生群体进行的一项教育活动,旨在引导学生理解生命的价值,...通过这样的教育,大学生能够更好地理解生命,勇敢面对生活中的挑战,以及有效地预防和应对可能出现的心理危机。
《生命生命》这篇文章深深地触动了我,它不仅仅是一篇课件中的阅读材料,更是对生命哲学的深刻探讨。生命,这个看似简单却又深奥的概念,往往在我们的日常生活中被忽视或者浅尝辄止地理解。文章中提到的几种对生命的...
通过积极行动,我们可以使自己的生命在短暂的时间内焕发出更大的光彩,即使生命结束,留下的贡献也能让生命的价值得以延续。 7. 悦纳生命:接纳自己的不完美,珍爱并提升自我生命的同时,也要理解和尊重他人的生命...