2

使用 clone 方法,我们可以得到许多单例类的实例吗?

此外,是否有必要编写“实现 Cloneable”,因为我了解到所有对象都从 Object 类扩展,因此在 Object 的另一个子级上调用 protected clone() 的子对象应该没有访问问题

4

3 回答 3

3

Java-Doc 说Object.clone()

创建并返回此对象的副本。“复制”的确切含义可能取决于对象的类别。

这取决于您对clone()方法的实现,您获得什么样的副本或克隆。但是Java-Doc进一步说:

按照惯例,此方法返回的对象应独立于此对象(正在克隆)。

按照这个约定,一个克隆将是以前单例实例的另一个独立实例。

继续使用 Java-Doc:

Object 类本身并没有实现接口 Cloneable,因此在类为 Object 的对象上调用 clone 方法将导致在运行时抛出异常。

所以你必须明确声明你的类implements Cloneable. 只要您不这样做,clone()您的实例上就没有公共方法。但是你不会对单例这样做,因为这会使你的类设计(单例)无用。

如果您没有声明单例类final并使用另一个类扩展它,该类的实例将调用super.clone()这将抛出提到的CloneNotSupportedException.

如果您要根据 Java-Doc明确声明您的单例类:implements Cloneable

创建这个对象的类的一个新实例,并用这个对象的相应字段的内容来初始化它的所有字段,就像通过赋值一样;字段的内容本身不会被克隆。因此,此方法执行此对象的“浅拷贝”,而不是“深拷贝”操作。

要获得正确的克隆,Java-DocCloneable说:

... 实现此接口的类应该覆盖 Object.clone ... 因此,不可能仅凭借实现此接口的事实来克隆对象。

所以你真的必须明确地做到这一点。


回答问题:
可能吗?是的,但只有在您允许的情况下。
是有意的吗?不。

另请注意:
除了上面提到的使用反射之外,您还可以尝试绕过单例类的可见性限制来创建更多实例。

于 2018-07-04T08:27:35.303 回答
3

在您通过单例实现之前不会发生这种情况Cloneable(这是一种反模式,因为它与单例的目的相矛盾)。因此,只有当您执行以下操作时才会发生这种情况:

SomeClass.java

class SomeClass implements Cloneable {
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

单例.java

class Singleton extends SomeClass {
    public static Singleton instance = new Singleton();
    private Singleton() {}
}

主.java

class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Singleton singleton1 = Singleton.instance;
        Singleton singleton2 = singleton1.clone();
        System.out.println("singleton1 : "
                       + singleton1.hashCode());
        System.out.println("singleton2 : "
                       + singleton2.hashCode()); 
    }
}    

输出

单例1:445884362

单例2:1793329556

即使在这种情况下,您也可以通过覆盖并抛出异常来解决此clone问题Singleton

于 2018-07-04T08:45:58.870 回答
0

首先,永远不要使用克隆。看这里

二、clone做浅拷贝。看这里

最后,建议对单例使用枚举,这是由 VM 保证的。看这里

于 2018-07-04T09:03:48.883 回答