有没有办法在java下面的单例代码中打破这个

时间:2012-10-25 10:22:44

标签: java java-ee

这是一个单身人士类。

我想知道在这段代码中打破单例逻辑的方法

class Employee{ // class starts
    private Employee(){} // private constructor

    private static Employee emp; 
    /*static block*/

    static {    
        if (emp==null)
        {
            emp=new Employee(); 
        }
    }      
    /* static method*/          
    public static Employee getEmployee()
    {   
        return emp;  
    }
}

4 个答案:

答案 0 :(得分:7)

您只需要一个Employee的实例?

class Employee{ // class starts
   private Employee(){}
   public static final Employee INSTANCE = new Employee(); 
}

不需要吸气剂,代码是安全的,只需使用:

Employee.INSTANCE

只是一个注释:Employee听起来像一个值对象,看起来很难有单例值对象。

更新:似乎我终于明白了问题是什么。这个单身人士是安全的,除非使用一些非常重的艺术品:

  • 使用反射制作构造函数public(参见 Marko Topolnik 的精彩答案)。我想这可以通过一些安全管理器设置来避免

  • Java序列化 - 不太可能,单例必须实现Serializable

  • 不同的类加载器(illustrated

除了这些常见问题之外,你的代码很好,但并不漂亮。

答案 1 :(得分:5)

如果要访问多个Employee实例,则只需将构造函数设置为public即可。如果您还希望此类的所有当前客户端每次都接收一个新实例而不是单例实例,那么将getEmployee()实现为{ return new Employee(); }。然后,您可以删除private static变量和static初始化程序块。

第三,如果你无法改变源代码,但想要获得许多Employee个实例,唯一的方法就是采用反思:

try {
  final Constructor<Employee> c = Employee.class.getDeclaredConstructor();
  c.setAccessible(true);
  final Employee e = c.newInstance();
} catch (Exception e) { throw new RuntimeException(e); }

第四,如果您的问题实际上是关于保护单例不受破坏,并且单例确实可序列化(在您的示例中未显示),则该类必须实现隐式参与反序列化的readResolve方法机构:

protected Object readResolve() {
    return emp;
}

请注意,除了启用SecurityManager并配置适当的权限外,没有任何内容可以防止反射。

答案 2 :(得分:0)

您还应该在构造函数中执行以下操作,以避免通过反射创建对象

private Employee(){ 
if(emp!=null){
   throws new InstantiationError("singleton breached ");
}

}

答案 3 :(得分:0)

想要多个实例?一块蛋糕:

    Constructor<Employee> constructor = Employee.class.getDeclaredConstructor();
    constructor.setAccessible(true);
    Employee wtf = constructor.newInstance();
    assertSame(wtf, Employee.getEmployee());

有两种方法可以保护单身人士。第二个最好的是使用单元素枚举:

enum Singleton {
    INSTANCE;
    void doSomething(){
        System.out.println("Doing something");
    }
}

// Usage:
Singleton.INSTANCE.doSomething();

最好和最简单的方法是根本不使用单身人士。