我正在寻找一些有关Java的教程 Cloneable, ,但没有任何良好的链接,无论如何,堆栈溢出变得越来越明显。

我想知道以下内容:

  1. Cloneable 意味着我们可以通过实现该物体的克隆或对象的副本 Cloneable 界面。这样做的优点和缺点是什么?
  2. 如果对象是复合对象,则如何发生递归克隆?
有帮助吗?

解决方案

您应该知道的第一件事 Cloneable 是 - 不要使用它。

很难实现克隆 Cloneable 是的,努力是不值得的。

而不是使用其他选项,例如Apache-Commons SerializationUtils (深欺骗)或 BeanUtils (浅词),或简单地使用复制构建器。

看这里 乔什·布洛克(Josh Bloch)关于克隆的观点 Cloneable, ,这解释了该方法的许多缺点。 ((约书亚·布洛克(Joshua Bloch) 是一名太阳员工,并领导了许多Java功能的发展。)

其他提示

不幸的是,可克隆本身只是一个标记界面,也就是说:它不能定义clone()方法。

做什么,是更改受保护对象的行为。clone()方法,该方法将为无法实现可克隆的类的cloneNotsupportedException抛出一个clonotsupportedexception,并对会成员进行成员的浅副本。

即使这是您要寻找的行为,您仍然需要实现自己的clone()方法才能公开它。

当实现自己的clone()时,想法是从super.clone()的对象开始,该对象保证为正确的类你要。从clone()调用构造函数将是有问题的,因为如果子类希望添加自己的附加可克隆逻辑,这将破坏继承;如果要调用super.clone(),在这种情况下,将会有一个错误类的对象。

这种方法绕过了您的构造函数中可能定义的任何逻辑,这可能是有问题的。

另一个问题是,任何忘记覆盖clone()的子类都会自动继承默认浅副本,这可能不是您想要的,如果您在可变状态下(现在将在源和复制之间共享)。

大多数开发人员出于这些原因不使用可包隆,而是简单地实现复制构造函数。

有关更多信息和潜在的可讨化陷阱,我强烈推荐Joshua Bloch的《有效Java》一书

  1. 克隆调用了一种语言的构造对象的方式 - 没有构造函数。
  2. 克隆要求您以克洛诺底皮PpportedException的方式治疗或打扰客户代码以治疗它。
  3. 好处很小 - 您只是不必手动编写复制构造函数。

因此,明智地使用可克隆。与您需要申请做正确的一切所需的努力相比,它并不能为您带来足够的好处。

克隆是基本的编程范式。 Java可能在许多方面实现了很差的事实并不能完全减少克隆的需求。而且,很容易实施克隆,但是您希望它能起作用,浅,深,混合等。您甚至可以将名称克隆用于该函数,并且如果愿意,则不能实现可克隆。

假设我有A,B和C类,其中B和C源自A。如果我有类型A的对象列表:

ArrayList<A> list1;

现在,该列表可以包含A类,B或C的对象。您不知道这些对象是什么类型。因此,您无法复制这样的列表:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    list2.add(new A(a));
}

如果对象实际上是B或C型的,则您将无法获得正确的副本。而且,如果A抽象怎么办?现在,有些人提出了这一点:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    if(a instanceof A) {
        list2.add(new A(a));
    } else if(a instanceof B) {
        list2.add(new B(a));
    } else if(a instanceof C) {
        list2.add(new C(a));
    }
}

这是一个非常非常糟糕的主意。如果您添加新的派生类型怎么办?如果B或C在另一个软件包中,并且您无法在此类中访问它们怎么办?

您想做的是:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    list2.add(a.clone());
}

很多人都指出了为什么克隆的基本Java实施是有问题的。但是,这很容易克服:

在A类:

public A clone() {
    return new A(this);
}

在B级:

@Override
public B clone() {
    return new B(this);
}

在C级中:

@Override
public C clone() {
    return new C(this):
}

我不使用相同的函数名称实现可克隆。如果您不喜欢那样,请将其命名。

a)克隆比复制构造函数没有很多优点。最大的一个可能是能够创建完全相同的动态类型的新对象(假设声明的类型是可克隆的并且具有公共克隆方法)。

b)默认克隆会创建浅副本,除非您的克隆实施更改,否则它将保持浅副本。这可能很困难,尤其是如果您的班级有最终领域

Bozho是对的,克隆可能很难正确。复制构造函数/工厂将满足大多数需求。

可克隆的缺点是什么?

如果您要复制的对象有构图,克隆非常危险。在这种情况下,您需要考虑以下可能的副作用,因为克隆会创建浅副本:

假设您有一个可以处理与数据库相关的操作的对象。说,那个对象有 Connection 对象是其中之一。

因此,当某人创建克隆时 originalObject, ,正在创建的对象,可以说, cloneObject。在这里 originalObjectcloneObject 持有相同的参考 Connection 目的。

originalObject 关闭 Connection 对象,所以现在 cloneObject 不会起作用,因为 connection 它们之间共享对象,并且它是由 originalObject.

如果假设要克隆具有iostream作为属性的对象,则可能会发生类似的问题。

如果对象是复合对象,则如何发生递归克隆?

可克隆的性能浅副本。意思是原始对象和克隆对象的数据将指向相同的参考/内存。相反,在深拷贝的情况下,将原始对象内存的数据复制到克隆对象的内存。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top