我们可以在java中设计一个真正的单例类吗?

时间:2014-02-03 17:13:24

标签: java design-patterns reflection singleton

是否存在可以完全阻止创建多个对象的单例设计?

请记住这个问题,请记住,在Java中,我们可以使用序列化 - 反序列化和反射来重新创建“单例对象”。

6 个答案:

答案 0 :(得分:3)

是的,我们可以设计一个真正的单例类(也是线程安全的) 但是每个单例类只是给定类加载器中的单例,
在运行时不在整个JVM中。

有关详细信息,请查看这些相关问题。

What is an efficient way to implement a singleton pattern in Java?

How does Singleton behave when two threads call the "getInstance()" at the same time?

How to correctly make a thread safe Singleton Factory in Java?

答案 1 :(得分:2)

是的,Java 5引入了枚举,这些枚举不能通过序列化等创建其他实例。

在Java 5+中创建单例的标准方法是使用一个常量枚举。

答案 2 :(得分:1)

可能是或否,取决于您要采取的步骤以及您的想法。

纯粹在JVM中,我会说不。由不同类加载器加载的资源被认为是不同的。因此,无论您采取何种检查,您的单个Foo.class文件都可以由不同的类加载器加载,并且将创建静态对象的两个实例。他们提到的静态变量会有所不同,因此其中一个变量无法看到已经创建了另一个变量。

但是,如果您愿意使用外部资源(例如本地文件系统上的文件,假设您肯定可以写入目录),那么它可能是可能的。这假设外部系统具有比较和设置或其他同步语义,否则您有潜在的竞争条件,可能导致两个潜在的实例看到另一个未运行,然后启动。

后一种情况可能是相关的,这取决于您如此确定第二个实例不存在的原因。如果是因为它可能会破坏某些外部资源,请将约束放在该资源本身上。

答案 3 :(得分:0)

你可以使用枚举来制作单例模式,这是最好的在java中实现单例,但要记住每个类加载器只有一个单例

Serializable singleton

 public enum Elvis {
       INSTANCE;
       private final String[] favoriteSongs =
           { "ABC", "DEF" };
       public void printFavorites() {
           System.out.println(Arrays.toString(favoriteSongs));
       }
   }

答案 4 :(得分:0)

单元素枚举类型是实现单例的最佳方式。

它将免费提供序列化机制,并提供一个 铁定的保证反对多重实例化,即使面对复杂 序列化或反射攻击。

答案 5 :(得分:0)

是的,你可以在java中创建一个真正的单例类。

例如:

public class Foo {

private Foo f = null;
//More Variables

private Foo(){    //Constructor
}

public static Foo getInstance() {
if (f == null) { //f is the instance of the class Foo.
f = new Foo();
} 
return f; 
}

public void display() {
System.out.println("Display");
}

//...More Methods
}

In order to call, you may use it as:
Foo.getInstance().display();

每次调用getInstance()时,它只会在应用程序的生命周期内生成一次Foo类的实例。