没有实现可克隆接口的对象克隆

时间:2011-11-19 05:56:56

标签: java clone

克隆对象我需要实现'可克隆'接口。因为这里我的类是一个jar文件(我的意思是API)。所以我无法编辑课程。我听说所有类都扩展了基础对象类,这个对象类实现了可克隆的接口。这是否意味着我们可以直接克隆对象而不实现接口。如果是这样,在我的日食中,我没有任何克隆对象的选择。 是否有其他方法可以在不实现可克隆接口的情况下克隆对象。请解释。

8 个答案:

答案 0 :(得分:8)

通常最好避免使用clone(),因为它很难正确执行(http://www.javapractices.com/topic/TopicAction.do?Id=71)。也许这个类有一个复制构造函数?

或者,如果它实现Serializable或Externalizable,您可以通过将其写入字节流并在

中读取来深度复制它。
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Object deepCopy = ois.readObject();

(来自http://www.jguru.com/faq/view.jsp?EID=20435)。这很快捷,但并不漂亮...我通常认为这是最后的手段。

答案 1 :(得分:7)

Java Object类未实现Cloneable接口。但它确实有clone()方法。但是这个方法是protected,如果在没有实现CloneNotSupportedException接口的对象上调用,它将抛出Cloneable。因此,如果您无法修改要克隆的类,那么您将失去运气,并且必须找到另一种方法来复制实例。

但应该注意的是,Java中的克隆系统充满了漏洞而且通常不再使用。从2002年开始,与Josh Bloch一起查看interview,解释一些问题。

答案 2 :(得分:1)

它们是一个api,可以在不实现可克隆接口的情况下克隆对象。

试试这个

https://github.com/kostaskougios/cloning

此外,您可以在此处找到有关克隆对象的更多详细信息

http://javatechniques.com/blog/faster-deep-copies-of-java-objects/

答案 3 :(得分:1)

使用Reflection API可以实现它

答案 4 :(得分:0)

尝试在未实现Cloneable抛出的类上调用clone方法CloneNotSupported异常且没有Object类不实现Cloneable。

这是来自Object类

的clone方法的javadoc
CloneNotSupportedException  if the object's class does not
 *               support the <code>Cloneable</code> interface. Subclasses
 *               that override the <code>clone</code> method can also
 *               throw this exception to indicate that an instance cannot
 *               be cloned.

此外,Object#clone方法受到保护,因此您需要在类中实现clone方法并将其公开,以便类可以访问类的对象,然后可以调用克隆。一个很好的例子是在ArrayList中实现clone的方式

ArrayList实现了如下的cloneable      public class ArrayList扩展了AbstractList         实现List,RandomAccess,Cloneable,java.io.Serializable

然后实现克隆方法:

/**
 * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
 * elements themselves are not copied.)
 *
 * @return a clone of this <tt>ArrayList</tt> instance
 */
public Object clone() {
try {
    ArrayList<E> v = (ArrayList<E>) super.clone();
    v.elementData = Arrays.copyOf(elementData, size);
    v.modCount = 0;
    return v;
} catch (CloneNotSupportedException e) {
    // this shouldn't happen, since we are Cloneable
    throw new InternalError();
}
}

答案 5 :(得分:0)

Object类中的clone()方法受到保护,这意味着所有类都将使用受保护的访问修饰符继承它,因此如果您尝试在该类之外访问它而不克隆它,您将看不到它,它也会抛出CloneNotSupportedException,如果你尝试在不实现Cloneable接口的情况下调用它。

如果你正在寻找一种创建克隆行为的方法,你需要在你的类中编写一个新方法,然后你创建一个所有字段的副本,它基本上就像创建一个现有的新副本对象的状态。

public class TestCloneable {
private String name = null;

/**
 * @param name the name to set
 */
public void setName(String name) {
    this.name = name;
}

/**
 * @return the name
 */
public String getName() {
    return name;
}


public TestCloneable createCopy(){
    TestCloneable testCloneable = new TestCloneable();
    testCloneable.setName(this.getName());
    return testCloneable;
}

}

答案 6 :(得分:0)

实现可克隆接口以实现对象的克隆不是必需的。 您可以在要克隆其对象的类中编写自己的克隆方法。

答案 7 :(得分:0)

您可以使用Unsafe创建对象的实例,然后通过使用Java Reflection将值复制到新实例中。但是就像Unsafe这个名字所说的那样,这并不是一个很好的解决方案。

public static Unsafe unsafe;
static {
    Field f;
    try {
        f = Unsafe.class.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        unsafe = (Unsafe) f.get(null);
    } catch (NoSuchFieldException | IllegalAccessException e) {
        e.printStackTrace();
    }

}

public static <T> T clone(T object) throws InstantiationException {
    T instance = (T) unsafe.allocateInstance(object.getClass());
    copyInto(object,instance);
    return instance;
}

public static void copyInto(Object source,Object destination){
    Class<?> clazz = source.getClass();
    while (!clazz.equals(Object.class)) {
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            try {
                field.set(destination, field.get(source));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        clazz = clazz.getSuperclass();
    }
}