当前位置:编程学习 > JAVA >>

特创论

有时候,对于一个类来说,跟踪其创建出来的实例个数会非常有用,其典型实现是通过它的构造器递增一个私有静态字段来完成的。
[java]  
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次,所以应该打印100。其实该程序根本不能编译。因为在main方法中的循环中,只有一条局部变量声明语句,而JLS[JLS 14.4]规定在for,while,do循环中不允许重复执行局部变量声明语句,局部变量声明语句只能放在语句块中,也就是放在大括号中。另外,由于创建了对象并没有使用,因此,没有必要保存其引用,在适当时机GC会对它进行垃圾回收。
改进后的代码如下:
[java]  
public class Creator {  
  
    public static void main(String[] args) {  
        for(int i = 0; i < 100; i++)   
            new Creature();  
        System.out.println(Creature.numCreated());  
    }  
  
}  
  
class Creature {  
    private static long numCreated = 0;  
      
    public Creature() {  
        numCreated++;  
    }  
      
    public static long numCreated() {  
        return numCreated;  
    }  
}  
 
这样编译后运行,打印出了预期的值:100.
这里保存实例个数的变量类型设为long是有依据的。目的是防止溢出。因为int是有符号的整型,它的最大值为pow(2,31)-1。而一个程序每秒钟创建1亿个对象是有可能的,因此可能存在溢出现象。如果将int类型改为long,long的最大值为pow(2,63)-1,约为9.2*pow(10,18),这意味着程序在对象计数器溢出之前,不得不运行大约三千年。
另外,还需注意的是,如果在多线程中创建该对象存在线程安全性,因此此代码需对递增计数器进行同步:
[java]  
class Creature {  
    private static long numCreated = 0;  
      
    public Creature() {  
        synchronized (Creature.class) {  
            numCreated++;  
        }  
  
    }  
      
    public synchronized static long numCreated() {  
        return numCreated;  
    }  
}  
 
如果使用的是5.0或更新的版本,可以使用AtomicLong实例,这样就无需再使用syncrhonized了:
[java]  
class Creature {  
    private static AtomicLong numCreated = new AtomicLong();  
      
    public Creature() {  
        numCreated.incrementAndGet();  
    }  
      
    public static long numCreated() {  
        return numCreated.get();  
    }  
}  
 
总之,一个局部变量声明不能被用作for,while 或do循环中的重复执行语句,它作为一条语句只能出现在一个语句块中。另外,在使用一个变量来对实例的创建进行计数时,要使用long类型而不是int类型的变量,以防止溢出。最后,如果你打算在多线程中创建实例,要么将对实例计数器的访问进行同步,要么使用一个AtomicLong类型的计数器。
补充:软件开发 , Java ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,