`
dandy
  • 浏览: 67274 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

特别论

    博客分类:
  • java
阅读更多
出自《java puzzle》


某些时候,对于一个类来说,跟踪其创建出来的实例个数会非常用有,其典型实现是通过让它的构造器递增一个私有静态域来完成的。在下面的程序中,Creature类展示了这种技巧,而Creator类对其进行了操练,将打印出已经创建的Creature实例的数量。那么,这个程序会打印出什么呢?
public class Creator {
  public static void main(String[] args) {
    for (int i = 0; i < 100; i++)
      Creature creature = new Creature();
    System.out.println(Creature.numCreated());
  }
}
class Creature {
  private static long numCreated = 0;
  public Creature() {
    numCreated++;
  }
  public static long numCreated() {
   return numCreated;
  }
}


这是一个捉弄人的问题。该程序看起来似乎应该打印100,但是它没有打印任何东西,因为它根本就不能编译。如果你尝试着去编译它,你就会发现编译器的诊断信息基本没什么用处。下面就是javac打印的东西:

Creator.java:4: not a statement
Creature creature = new Creature();
^
Creator.java:4: ';' expected
Creature creature = new Creature();
^
一个本地变量声明看起来像是一条语句,但是从技术上说,它不是;它应该是一个本地变量声明语句(local variable declaration statement)[JLS 14.4]。Java语言规范不允许一个本地变量声明语句作为一条语句在for、while或do循环中重复执行[JLS 14.12-14]。一个本地变量声明作为一条语句只能直接出现在一个语句块中。(一个语句块是由一对花括号以及包含在这对花括展中的语句和声明构成的。)

有两种方式可以订正这个问题。最显而易见的方式是将这个声明至于一个语句块中:

for (int i = 0; i < 100; i++) {
Creature creature = new Creature();
}

然而,请注意,该程序没有使用本地变量creature。因此,将该声明用一个无任何
修饰的构造器调用来替代将更具实际意义,这样可以强调对新创建对象的引用正在被丢弃:

for (int i = 0; i < 100; i++)
new Creature();
无论我们做出了上面的哪种修改,该程序都将打印出我们所期望的100

请注意,用于跟踪Creature实例个数的变量(numCreated)是long类型而不是int类型的。我们很容易想象到,一个程序创建出的某个类的实例可能会多余int数值的最大值,但是它不会多于long数值的最大值。

int数值的最大值是231-1,即大约2.1×109,而long数值的最大值是263-1,即大约9.2×1018。当前,每秒钟创建108个对象是可能的,这意味着一个程序在long类型的对象计数器溢出之前,不得不运行大约三千年。即使是面对硬件速度的提升,long类型的对象计数器也应该足以应付可预见的未来。
还要注意的是,本谜题中的创建计数策略并不是线程安全的。如果多个线程可以并行地创建对象,那么递增计数器的代码和读取计数器的代码都应该被同步:
// Thread-safe creation counter
class Creature {
private static long numCreated;
public Creature() {
synchronized (Creature.class) {
numCreated++;
}
}
public static synchronized long numCreated() {
return numCreated;
}
}


或者,如果你使用的是5.0或更新的版本,你可以使用一个AtomicLong实例,它在面临并发时可以绕过对同步的需求
// Thread-safe creation counter using AtomicLong;
import java.util.concurrent.atomic.AtomicLong;
class Creature {
private static AtomicLong numCreated = new AtomicLong();
public Creature() {
numCreated.incrementAndGet();
}
public static long numCreated() {
return numCreated.get();
}
}


请注意,把numCreated声明为瞬时的是不足以解决问题的,因为volatile修饰符可以保证其他线程将看到最近赋予该域的值,但是它不能进行原子性的递增操作。

总之,一个本地变量声明不能被用作for、while或do循环中的重复执行语句,它作为一条语句只能出现在一个语句块中。另外,在使用一个变量来对实例的创建进行计数时,要使用long类型而不是int类型的变量,以防止溢出。最后,如果你打算在多线程中创建实例,要么将对实例计数器的访问进行同步,要么使用一个AtomicLong类型的计数器。
1
0
分享到:
评论

相关推荐

    系统论、信息论、控制论浅说

    控制论是研究系统的控制机制,特别是生物系统和机器的控制与通信问题。它研究系统的反馈机制,通过反馈信息实现对系统行为的调节与控制。控制论的诞生与自动化技术的发展紧密相关,它的核心思想是通过调节控制参数来...

    控制论/控制论基础.pdf

    特别是在人工智能领域,控制论理论和技术对于开发更加智能、自主的机器具有重要意义。此外,随着大数据和云计算技术的进步,未来的控制论研究还将更多地关注如何处理大规模数据集,以及如何在不确定性和复杂性更高的...

    引力论与宇宙论(温伯格)

    作者还讨论了对称空间,特别是最大对称空间及其性质,这些对称性对于理解物理定律的普适性有重要意义。 《引力论与宇宙论》的内容结构严谨,涉及到的领域广泛,涵盖了广义相对论的几乎所有重要方面。读者可以通过...

    商标标志着作权案件的裁判标准.docx

    特别论指出,这种做法可能导致在先商标实际上获得了全类保护,与商标法的商品类别限制相冲突,也可能使商标权的地域性和申请原则变得无效。此外,无类别限制和无地域限制的保护可能会破坏商标法律制度的平衡。 针对...

    信息论基础第二版答案

    至于标签中的“托马斯”,很可能是对信息论领域的某一重要人物或某本重要著作的提及,但遗憾的是,在信息论领域并没有特别著名的托马斯与之对应,可能是一个OCR扫描错误,或者是文档内容的一个不明确的提及。...

    信息论的应用

    在本论文中,我们将探讨信息论如何应用于实际生活,特别是针对社团合并这一社会现象进行分析。 首先,我们从信息论的基本概念出发。熵是信息论中的核心概念,它衡量的是一个信息源的不确定性。在社团合并的场景下,...

    矩阵论考试试题及答案

    矩阵论是线性代数的一个重要分支,主要研究矩阵的性质、运算以及它们在数学、物理学、工程学等领域的应用。这份"矩阵论考试试题及答案"的压缩包,包含了多份不同学校的矩阵论考试真题及对应的解答,是备考矩阵论考试...

    博弈论试题及答案.pdf

    在这个答案中,考生描述了一个情侣博弈的情形,那就是周末和女朋友去逛商场,考生需要根据女朋友的喜好和需求来选择商品,并且需要在女朋友特别喜欢的商品上作出让步,同时也需要在女朋友不合理的购买选择时进行干预...

    排队论模型_排队论_排队模型_matlab编程:排队论模型_选址建模_数学建模

    "选址建模"是应用排队论的一个实际场景,特别是在商业策略或公共服务设施规划中。例如,确定零售店、医院或消防站的最佳位置,以最大化覆盖和服务效率。最大选址覆盖理论在此发挥作用,它旨在找出最少数量的设施位置...

    排队论模型,排队论模型及实例,matlab

    在本主题中,我们将深入探讨排队论模型及其在实际问题中的应用,特别是与MATLAB编程相结合的实例,以及如何利用这些模型解决基础设施选址问题。 首先,让我们理解基本的排队论模型。最常见的排队模型有M/M/1、M/M/k...

    矩阵论参考_矩阵论第二版答案(徐仲版)_

    1. 对角化与相似对角化:当一个矩阵可以被对角化,意味着它可以通过适当的基变换转化为对角矩阵,这在处理实对称矩阵、正常矩阵等问题时特别有用。 2. Schur分解:这是一种将任意复数矩阵转化为上三角矩阵的分解...

    博弈论简介 .ppt

    其次,博弈论与现代经济学的联系在于,经济学研究的是人的决策行为,特别是理性的决策行为。传统的价格理论假设市场是竞争性的,参与者众多,信息完全。然而,现实中的市场往往不符合这些假设,存在非对称信息和寡头...

    复变函数论

    复变函数论是一门数学分支,它主要研究复数域上的函数,特别是那些在复数域的某个区域内具有导数的函数,即解析函数。复变函数论的核心是复分析,其理论框架和方法论不仅在数学内部,如几何、数论、偏微分方程等领域...

    集合论基础

    “对角线论证”是由康托尔提出的一种用于证明某些集合比其他集合“更大”的方法,它揭示了无限集合的复杂性,特别是在比较不同无限集合大小时。 在计算机科学中,集合论的概念被用于数据库系统、数据结构、算法分析...

    信息论 信息论基础 考题

    标题与描述概述的知识点主要集中在信息论的基础理论与考试题目的准备上,特别是涉及复旦大学的信息论课程考试。信息论作为一门研究信息传输、存储和处理效率的学科,其核心概念包括熵(Entropy)、互信息(Mutual ...

    控制论(控制论之父维纳的原著)

    控制论是一门研究控制过程、通信过程和生物系统的数学理论的学科,它关注的是在动态变化的环境中保持稳定的科学。控制论之父维纳(Norbert Wiener)的著作对这一领域产生了深远的影响。维纳与罗森勃吕特博士共同研究...

Global site tag (gtag.js) - Google Analytics