Java 单身合同会被打破吗?如果是,有多少种方式?

Java 单身合同会被打破吗?如果是,有多少种方式?,java,singleton,synchronized,volatile,cloning,Java,Singleton,Synchronized,Volatile,Cloning,最近,我参加了面试,她/他问了我一个问题——你的单亲班级还不到,你必须打破单亲合同,告诉我怎么做?我想了又想,但我无法想出解决办法,因为每一张支票都是为了防止违规,比如—— 要从主存读/写的Volatile关键字 围绕方法和块同步 获取实例的静态方法 仔细检查实例是否可用 私有构造函数 以下是守则- /** * */ package com.test.singleton; /** * @author * */ public class SingletonInstance impl

最近,我参加了面试,她/他问了我一个问题——你的单亲班级还不到,你必须打破单亲合同,告诉我怎么做?我想了又想,但我无法想出解决办法,因为每一张支票都是为了防止违规,比如——

  • 要从主存读/写的Volatile关键字
  • 围绕方法和块同步
  • 获取实例的静态方法
  • 仔细检查实例是否可用
  • 私有构造函数
  • 以下是守则-

    /**
     * 
     */
    package com.test.singleton;
    
    /**
     * @author 
     *
     */
    public class SingletonInstance implements Cloneable{
    
        private String name;
    
        private static volatile SingletonInstance instance;
    
         private SingletonInstance(){
    
            System.out.println("constructor called");
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        static synchronized SingletonInstance getInstance(){
    
        if(instance == null){
    
            synchronized(SingletonInstance.class){
                instance = new SingletonInstance();
            }
    
        }
        return instance;
    }
    
        /* (non-Javadoc)
         * @see java.lang.Object#clone()
         */
        @Override
        protected Object clone() throws CloneNotSupportedException {
            // TODO Auto-generated method stub
            return super.clone();
        }
    
    }
    

    请建议是否有可能以任何方式破坏singleton契约?

    构造函数虽然是私有的,但可以使用反射调用:

    Class<SingletonInstance> klass = SingletonInstance.class;
    Constructor<SingletonInstance> defaultConstructor = klass.getConstructor();
    
    defaultConstructor.setAccessible(true);
    SingletonInstance newInstance = defaultConstructor.newInstance();
    

    有几种情况下,您的Singleton类可能有多个实例。到目前为止,我有两点想法

  • 通过反射调用私有构造函数
  • 通过序列化和反序列化
  • 下面是通过私有构造函数调用停止创建对象的方法

    private SingletonInstance(){
              if(instance != null){
                    throw new OperationNotSupportedException("You can't create object of singletone class using this operation");
             }
           }
    
    另外,通过添加readObject和readResolve方法,可以停止通过序列化和反序列化创建singleton类的多个对象,如下所示

    private void readObject(ObjectInputStream inputStream) throws ClassNotFoundException, IOException  {
        inputStream.defaultReadObject();
        instance = this;
    }
    
    private Object readResolve() {
        return instance;
    }
    
    此外,您的克隆方法还应该通过一个异常

      protected Object clone() throws CloneNotSupportedException {
           throw new CloneNotSupportedException("Clone not supported for this class");
        }
    

    你没有具体说明“违约”是什么意思。无论如何,此代码是不正确的,当调用
    getInstance()
    时(有效地
    synchronized(null)
    ),它将始终抛出NPE,因此它将永远不会初始化实例。您尝试过克隆,但它返回了相同的实例?我不相信你。谢谢吉姆指出这一点。更正了代码。从术语“break the contract”开始,我的意思是无论如何都可以创建类的两个实例,@Ernest已经用反射和如何防止that@shmosel从术语“同一实例”开始,我在写问题时想到了实例的相同内容。现在我意识到措辞是不正确的。我做了问题的更正。谢谢我仍然不明白为什么不能使用克隆来解决这个问题。如果从单独的线程调用,反射仍然可以击败您的私有构造函数。您需要同步null测试,以强制
    volatile
    的有效性。您有一个类型
    抛出异常
    您不能在此处使用序列化,由于
    singletonistance
    没有实现
    Serializable
    ,其
    private
    构造函数有效地阻止了可序列化的子类。如果从单独的线程调用,反射仍然可以击败您的私有构造函数。您需要同步null测试,以强制
    volatile
    @Bohemian的有效性,即使
    synchronized
    在这里也没有帮助,因为您可以在第一次调用
    getInstance()
    之前创建自己的实例,而不涉及任何并发。
      protected Object clone() throws CloneNotSupportedException {
           throw new CloneNotSupportedException("Clone not supported for this class");
        }