0

我已经阅读了所有关于“不要使用静态”的呼声,并且我知道它减少了 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;
      }
    }

是的,我已经尝试过从所有内容中删除“最终”...

在每个实现中,我要么严格静态调用,要么使用实例 (SClass s = SClass.SINGLETON; s.Gen_ID) 以及上面描述的静态和对象实现。对于任何初始调用和任何连续调用(任一方法),我都只能得到“1000000”。有人愿意解释这里发生了什么吗?

我不是在问我是否应该实现静态(已经有很多页面)-我只是在问如何使这项工作变得简单。虽然我愿意接受更优雅的解决方案..提前谢谢!

4

3 回答 3

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 设计。在我足够舒适地致力于静态工厂之前,我需要更多的练习。再次感谢三位花时间回答我的问题!〜菲尔

于 2013-09-09T02:45:21.463 回答
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());
    }

}
于 2013-09-08T06:35:22.370 回答
0

你可以试试这个

class SClass {
    static final AtomicInteger COUNTER = new AtomicInteger();
    final int id = 1000000 + COUNTER.getAndIncrement();
}

无需使用同步,因为 AtomicInteger 是线程安全的。

于 2013-09-08T06:46:10.130 回答