创建单例对象,最好的方法

时间:2013-10-17 20:09:33

标签: java singleton

我想创建一个单例对象,我找到了3种方法,其中一种更好,为什么其他方式不好。假设构造函数是私有的。

方法1:

class ClassX{  
   private static ClassX objX = null;

      static{
          objX = new ClassX();
      }

   //get objX method
 }

方法2:

 class ClassX{  
   private static ClassX objX = new ClassX();

   //get objX method
 }

方法3:

 class ClassX{  
   private static ClassX objX = null;

   public ClassX getInstance(){
      if(objX == null)
          return new ClassX();
      else
          return objX;
   }
 }

5 个答案:

答案 0 :(得分:7)

您可以尝试使用这样的枚举: -

public enum Foo
{
   INSTANCE;
}

另请查看相关答案: - What is an efficient way to implement a singleton pattern in Java?

引用Stephen Denne在上述答案中使用的Enforce the Singleton Property with a Private Constructor or an enum Type中的几行: -

  

这种方法在功能上等同于公共领域方法,   除了它更简洁,提供序列化机制   免费,并提供反对多重的铁定保证   实例化,即使面对复杂的序列化或   反思攻击。虽然这种方法尚未被广泛采用,   单元素枚举类型是实现单例的最佳方式。

答案 1 :(得分:1)

class ClassX {
    private static volatile ClassX instance = null;

    private ClassX() { }

    public ClassX getInstance() {
        if (instance == null) {
            synchronized (ClassX.class) {
                if (instance == null) {
                    instance = new ClassX();
                }
            }
        }
        return instance;
    }
}

答案 2 :(得分:0)

方法3不是线程安全的,这意味着如果多个呼叫者同时进入,则最终可能会有多个单例。方法1和2将起作用并且基本上是相同的。您可能需要使用double check locking

来考虑此示例
Class ClassX{  
   private static ClassX objX = null;

   public static ClassX getInstance(){
      if(objX == null)
          synchronized(this) {
              if(objX == null)
              objX = new ClassX();
          }

      return objX;
   }
}

这可能看起来很愚蠢,但是双重检查锁定是线程安全的,比使用synchronizedgetInstance()便宜得多,这绝对可以确保您只有1 ClassX实例。此外,如果您选择将数据用作创建或存储单例的工作或服务定位器,则允许您将数据传递到getInstance()

答案 3 :(得分:0)

创建一个静态的最终私有实例&使用静态getter访问它,construtor是私有的。

private static final ClassX classX = new ClassX();

public static ClassX getInstance(){
  return classX;
}

或使用依赖注入。

答案 4 :(得分:0)

您不需要延迟初始化:

class Foo {
    public static final Foo INSTANCE = new Foo();
    private Foo();
}

这可能不会抵抗序列化或反射,但它应该足够好w / r / t线程安全。 (当然,你也可以只创建一个我在评论中隐含的实例。)