出自《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通过讲解和举例,帮助我们理解这一概念。 在英语中...
总结起来,《生命生命》这篇课文不仅让学生认识到了生命的可贵,更重要的是激发了他们对生命敬畏之心,鼓励他们在生活中积极进取。生命的意义并不遥远,它存在于我们的每一个行动中,每一次选择中。通过深入地阅读和...
【生命教育:教育的核心议题】 ...通过生命教育,大学生可以更好地理解自我,认识生命的多重维度,学会珍视和尊重生命,形成健康的人生观和价值观,从而更好地应对生活中的困难和压力,实现个人和社会的和谐发展。
【正文】 《浅谈孔子生命观在当代大学生生命观...通过深入学习和实践孔子的生命观,我们可以助力大学生树立正确的生命观,让他们在面临压力和困境时,能以健康的心态和行动去面对和解决问题,从而更好地成长和发展。
通过一系列生动的故事和事例,这份课件不仅仅传递了知识,更是一种对生命深层次感悟的传递,鼓励学生反思自我与生命的关系,从而在认知和情感上获得双重成长。 课件中提到的马航MH370事件,不仅仅是一起影响深远的...
总的来说,生命观念视域下的生物学大概念深度学习实践强调了在教学中不仅传授知识,更要培养学生的思维方式和价值观。通过精心设计的教学策略,教师可以引导学生形成科学的生命观念,提高他们的生物学素养,为未来...
《生命探测仪:一款创新的蓝牙通信应用》 在当今科技日新月异的时代,通信技术的发展极大...随着技术的不断进步,我们期待看到更多像“生命探测仪”这样富有创意和实用性的应用出现,为人类生活带来更多的便利与安全。
《生命生命》这篇文章以一种直击心灵的方式呈现了生命的复杂与深邃,它不仅仅是一篇简单的课件阅读材料,更是一次对生命哲学的深刻反思与探讨。在我们的日常生活中,生命这个概念往往被我们认为是理所当然,而文章则...
它的每一次振翅,不仅是对生命的本能渴望,更是对生命尊严的捍卫。人类社会中,我们常常对微小的生命视而不见,甚至轻易摧毁。然而,正是这些看似弱小的生命,以其顽强不屈的生存意志,让我们重新审视生命的敬畏感。...
文中提到校长讲述钱穆的故事,强调即使在艰难环境中,也要坚守文化和学术的使命与尊严,这对于学生来说,比获得学位更重要。 3. 学术信念的传承:钱穆的《国史大纲》和他的教学理念,体现了他对传统文化的热爱和对...
自1998年《数据仓库生命周期工具箱(第2版)》第一版出版以来,经过十多年的发展,数据仓库行业已经完全成熟,而且软硬件都有了极大的进步。那一版所提出的方法几乎已经被所有的数据仓库厂商和从业人员所采纳。现在,...
《种子的力》讲述了种子冲破重重阻碍,最终发芽成长的故事,象征着即使面临再大的困难,生命总有力量冲破阻碍,绽放光彩。而冰心的诗句则用简洁而深邃的语言,展现了生命的宏大和美丽,使读者能够在优美的文字中感受...
【大学生生命教育及心理危机应对】是针对大学生群体进行的一项教育活动,旨在引导学生理解生命的价值,...通过这样的教育,大学生能够更好地理解生命,勇敢面对生活中的挑战,以及有效地预防和应对可能出现的心理危机。
通过积极行动,我们可以使自己的生命在短暂的时间内焕发出更大的光彩,即使生命结束,留下的贡献也能让生命的价值得以延续。 7. 悦纳生命:接纳自己的不完美,珍爱并提升自我生命的同时,也要理解和尊重他人的生命...
这个观点鼓励人们在有限的生命里,为更大的目标和事业付出努力,而不是追求个人的安逸和享乐。 3. 反复修辞的作用:在标题和描述中,“生命生命”被重复使用,这是一种修辞手法,强调了对生命的重要性和紧迫感。...
近期举办的“大学生感恩主题班会——珍惜生命,学会感恩”活动,就是一次深刻的教育实践,旨在引导大学生们珍视生命中每一个人的贡献,学会感恩。活动内容丰富,通过多个环节,使学生们在参与和体验中深刻领悟感恩的...