我已经阅读了所有关于“不使用静态”的声音,我明白它会减少OOP并搞砸单元测试,并且在多线程时可能会破坏代码。但是,我没有尝试过这些。
我正在构建一个Java单例实用程序,它包含一个用于发出ID的公共静态数字生成器 - 无法复制的数字。我选择了单身,因此它可以跟踪程序生命周期中发出的数字,而不必重建一百万,并且不必担心有人不解除多个实例。初始化有效,但它永远不会超出其第一次调用。
我试过这种方式:
public class SClass {
public static final SClass SINGLETON = getInstance();
...
public static final int GEN_ID = genID();
private static int base = 999999;
...
...
private static int genID() {
SClass.SINGLETON.base += 1;
return base
}
}
我试过这样的方式:
public class SClass {
public static final SClass SINGLETON = getInstance();
...
public static int GEN_ID = genID();
private int base;
...
private SClass () {
...
this.base = 999999;
...
}
...
...
private int genID() {
this.base += 1;
return base;
}
}
是的,我已尝试将'final'从所有内容中移除......
在每个实现中,我严格静态地调用或者使用实例(SClass s = SClass.SINGLETON; s.Gen_ID)以及上面描述的静态和对象实现。我只得到任何初始和任何连续调用(任何一种方法)的“1000000”。有人愿意解释这里发生了什么吗?
我不是在问我是否应该实现静态(已经有很多页面已经存在) - 我只是简单地询问如何完成这项工作。虽然我对更优雅的解决方案持开放态度..提前致谢!
答案 0 :(得分:0)
试试这个
public class IdGenerator {
public static IdGenerator generator = new IdGenerator();
private IdGenerator(){}
private static int currentID=0;
private int getNextID(){
synchronized (this) {
currentID=currentID+1;
}
return currentID;
}
public static IdGenerator getInstance(){
return generator;
}
public static void main(String[] args) {
IdGenerator generator = IdGenerator.getInstance();
for(int i=0;i<10;i++)
System.out.println(generator.getNextID());
}
}
答案 1 :(得分:0)
你可以试试这个
class SClass {
static final AtomicInteger COUNTER = new AtomicInteger();
final int id = 1000000 + COUNTER.getAndIncrement();
}
无需使用synchronized,因为AtomicInteger是线程安全的。
答案 2 :(得分:0)
感谢Jon,Peter和Upog在我的问题上帮助我。我想展示我的原始问题的真实代码,然后显示解决它的代码,希望其他人可以从这个特定情况中受益。
我最初的问题是我无法增加一个静态的,不可重复的计数器:
/**
* Generate numbers and increment
*/
public class BuggedGenerator {
/************** Public Constants / Factory ***********/
private static BuggedGenerator INSTANCE = null; // to contain the single instance
/**
* The single instance of BuggedGenerator.
*/
public static final BuggedGenerator READ_IN = getInstance();
public static final int GEN_ID = genID();
private static int base = 999999;
/************ Singleton SetUp ************/
/**
* Utility Constructor.
*/
private BuggedGenerator() {
super(); // unnessesary, but I always invoke super()
}
/**
* Initialize the counter singleton
*/
private static int genID() {
BuggedGenerator.SINGLETON.base += 1;
return base
}
/**
* Determine whether BuggedGenerator already has an instance
* and return that instance.
*/
public static BuggedGenerator getInstance() {
if (null == BuggedGenerator.INSTANCE) {
BuggedGenerator.INSTANCE = new BuggedGenerator();
}
return BuggedGenerator.INSTANCE;
} // end getInstance()
}
这是我从这个实现中获得的:
> BuggedGenerator.READ_IN.GEN_ID
> 1000000
> BuggedGenerator.READ_IN.GEN_ID
> 1000000
> BuggedGenerator b = BuggedGenerator.READ_IN
> b.GEN_ID
> 1000000
当提示帮助时,我使用AtomicInteger类来替换GEN_ID实现,如Peter的示例所示,但我收到了有关静态初始化的编译时错误。我认为反对OOP并将AtomicInteger实现为传统的单例,作为对象的属性是太痛苦了。根据Jon的建议,我已经包含了整个代码而不是快照。随意使用:
/**
* Copyright 2013, Phil Reason. preason intisive com
* Permission to copy, modify, resell and or freely distribute - provided an
* exact copy of this file is explicitly accompanied and unaltered alongside
* of any distribution of works using this file or any modified version of
* this file.
*/
import java.util.concurrent.atomic.AtomicInteger;
/**
* This is a class to generate numbers for various purposes.
* @author Phil Reason
* @conceptionDate 9/6/13
* @version 1.1
* @revisionDate 9/8/13
*/
public class Generator {
/************** Constants *********************/
/**
* The single instance of Generator.
*/
public static final Generator READ_IN = getInstance();
private static Generator INSTANCE = null; // to contain the single instance
/******** Instance Vars: *******************/
private AtomicInteger counter; // construct an AtomicInteger
private int iDRange;
/************ Singleton SetUp ************/
/**
* non-public default constructor override.
*/
private Generator() {
super(); // unnessesary, but I always invoke super()
this.iDRange = 1000000; // the starting number to range increments
this.counter = new AtomicInteger(); // the AtomicInteger instance
} //END Generator()
/**
* Determine whether Generator already has an instance
* and return that instance.
*/
private static Generator getInstance() {
if (null == Generator.INSTANCE) { // upon first use...
Generator.INSTANCE = new Generator(); // construct the single instance
}
return Generator.INSTANCE; // return ony that instance
} // END Generator getInstance()
/**
* Generate non-repeating numbers. This can be useful for serializing when
* inherited serialization isn't useful or needed.
*
* Return the current count generation then increment the AtomicInteger.
* @ensure genID() >= 1000000 && genID() != genID() (never repeats a number)
*/
public int genID () {
return iDRange + counter.getAndIncrement(); // increments the sum of counter
} // END int genID()
}
此实现的输出正是我所需要的,因为它适用于类的内存驻留的生命周期。对于该属性,我只需要在setUp()重新运行时在测试之间预测JUnit的每个增量 - 这不会从内存中取消引用静态类引用。对于我正在测试的包,这实际上对我有利。这是我从后一个工具的输出中获得的:
> Generator.READ_IN.GEN_ID
> 1000000
> Generator.READ_IN.GEN_ID
> 1000001
> Generator b = Generator.READ_IN
> b.GEN_ID
> 1000002
... and so on ...
在此实现中,AtomicInteger与传统方法调用的任何其他对象一样使用,但作为单例。它不仅适用于我需要的东西,而且还能够避免破坏OOP设计。在我适应静态工厂之前,我需要更多的练习。再次感谢你们三个花时间回答我的问题! 〜菲尔