深度复制Java中的通用LinkedList

时间:2018-10-18 18:13:16

标签: java

我正在尝试创建一种方法来深复制我的链接列表。在我的get(index)方法中,我正在创建一个新的Node。仍然没有用,但是正在通过参考。

        SLinkedList<E> newLinkedList=new SLinkedList<E>();

        for(int i=0;i<size();i++)
        {
        newLinkedList.addLast(get(i));
        }
        return newLinkedList;
    }

3 个答案:

答案 0 :(得分:0)

每个E类型的实例都需要深度复制

深层复制,意味着取消对字段的引用:不是对要复制的对象进行引用,而是为任何引用的对象创建新的复制对象,并将这些引用放置在副本中。结果与浅表副本给出的结果不同,副本副本所引用的对象与原点引用的对象不同,并且是独立的。

您可以执行以下操作之一:

  • 通过实现可克隆的界面(作为标记)和替代克隆方法
  • 或使用复制构造函数

广告2)

    // example class 
    class E {

       // exampe field 
       private B someField; 

       // copy constructor 
       public E(E origin) {
           // deep copy item field here 
           somefield = origin != null 
                        ? new B(origin.someField)
                        : null;
       }
    }

ad 1)覆盖并实现克隆方法

    /**
     * Creates and returns a copy of this object.  The precise meaning
     * of "copy" may depend on the class of the object. The general
     * intent is that, for any object {@code x}, the expression:
     * <blockquote>
     * <pre>
     * x.clone() != x</pre></blockquote>
     * will be true, and that the expression:
     * <blockquote>
     * <pre>
     * x.clone().getClass() == x.getClass()</pre></blockquote>
     * will be {@code true}, but these are not absolute requirements.
     * While it is typically the case that:
     * <blockquote>
     * <pre>
     * x.clone().equals(x)</pre></blockquote>
     * will be {@code true}, this is not an absolute requirement.
     * <p>
     * By convention, the returned object should be obtained by calling
     * {@code super.clone}.  If a class and all of its superclasses (except
     * {@code Object}) obey this convention, it will be the case that
     * {@code x.clone().getClass() == x.getClass()}.
     * <p>
     * By convention, the object returned by this method should be independent
     * of this object (which is being cloned).  To achieve this independence,
     * it may be necessary to modify one or more fields of the object returned
     * by {@code super.clone} before returning it.  Typically, this means
     * copying any mutable objects that comprise the internal "deep structure"
     * of the object being cloned and replacing the references to these
     * objects with references to the copies.  If a class contains only
     * primitive fields or references to immutable objects, then it is usually
     * the case that no fields in the object returned by {@code super.clone}
     * need to be modified.
     * <p>
     * The method {@code clone} for class {@code Object} performs a
     * specific cloning operation. First, if the class of this object does
     * not implement the interface {@code Cloneable}, then a
     * {@code CloneNotSupportedException} is thrown. Note that all arrays
     * are considered to implement the interface {@code Cloneable} and that
     * the return type of the {@code clone} method of an array type {@code T[]}
     * is {@code T[]} where T is any reference or primitive type.
     * Otherwise, this method creates a new instance of the class of this
     * object and initializes all its fields with exactly the contents of
     * the corresponding fields of this object, as if by assignment; the
     * contents of the fields are not themselves cloned. Thus, this method
     * performs a "shallow copy" of this object, not a "deep copy" operation.
     * <p>
     * The class {@code Object} does not itself implement the interface
     * {@code Cloneable}, so calling the {@code clone} method on an object
     * whose class is {@code Object} will result in throwing an
     * exception at run time.
     *
     * @return a clone of this instance.
     * @throws CloneNotSupportedException if the object's class does not
     *                                    support the {@code Cloneable} interface. Subclasses
     *                                    that override the {@code clone} method can also
     *                                    throw this exception to indicate that an instance cannot
     *                                    be cloned.
     * @see Cloneable
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

我认为没有办法强制使用泛型使用复制构造函数。可克隆是这里唯一的选择-@Ivan

所有OP的冷杉都没有提到E是否为通用类型 但是...如果是这样的话?

interface Copyable<T> { 
   T copy(); 
}

final class Wrapped <E extends Copyable<E>> {

   private E theObject; 

   public Wrapped(E arg) { theObject = arg.copy(); }

   public void setObject(E arg) { theObject = arg.copy(); }

   public E getObject() { return theObject.copy(); }

   public boolean equals(Object other) { 
       if (other == null) return false; 
       if (! (other instanceof Wrapped))  return false; 
     return (this.theObject.equals(((Wrapped)other).theObject)); 
   } 
}

GENERICS HOW TO COPY –如何最好地实现泛型类型的clone方法?

请记住,最好使用克隆方法来构造副本:)

因此,在REFLECTION的帮助下,我们可以执行以下操作:

public static <E> E createCopy(E item) throws UnsupportedOperationException {
    try {
       Class<?> clazz = item.getClass();
       Constructor<?> copyConstructor = clazz.getConstructor(clazz);
       @SuppressWarnings("unchecked")
       E copy = (E) copyConstructor.newInstance(item);
       return copy;
    } catch (Exception e) {
        throw new UnsupportedOperationException(e.getCause());
    }
}

编辑:我最终以递归的方式进行了工作,并且有效。 C流

也许JAVA更少混乱(不是通用解决方案,但是当您知道E是具有深度克隆方法的具体类型时)?

    java.util.LinkedList<DeepCloneable> origin;
    java.util.LinkedList<DeepCloneable> copy = origin != null
            ? new java.util.LinkedList<>(origin.size())
            : null;
    java.util.Iterator<DeepCloneable> iterator = origin != null 
            ? origin.iterator()
            : null;
    while (iterator != null 
            && iterator.hasNext()) {
        DeepCloneable next = iterator.next();
        DeepCloneable dcCopy =  next.deepClone();
        copy.add(dcCopy);
    }

答案 1 :(得分:0)

要进行深复制,您需要知道如何复制E

由于您不知道E是什么,因此需要告知您如何复制E,例如通过接受UnaryOperator<E>进行复制操作。

以下内容将显示使用标准LinkedList的方法示例,但是它很容易适应您的自定义实现。

public static <E> LinkedList<E> deepCopy(LinkedList<E> original, UnaryOperator<E> copyOperator) {
    LinkedList<E> newList = new LinkedList<>();
    for (E e : original)
        newList.add(copyOperator.apply(e));
    return newList;
}

对象可复制的一种常见方式是实现Cloneable

class CloneableObject implements Cloneable {
    private String value;
    public CloneableObject(String value) {
        this.value = value;
    }
    @Override
    public CloneableObject clone() {
        try {
            return (CloneableObject) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(e.toString(), e); // cannot happen
        }
    }
    public String getValue() {
        return this.value;
    }
    public void setValue(String value) {
        this.value = value;
    }
}
LinkedList<CloneableObject> cloneableList = /*...*/;
LinkedList<CloneableObject> cloneableCopy = deepCopy(cloneableList, CloneableObject::clone);

另一种普遍接受的方法是使对象实现一个复制构造函数:

class CopyableObject {
    private String value;
    public CopyableObject(String value) {
        this.value = value;
    }
    public CopyableObject(CopyableObject original) { // copy constructor
        this.value = original.value;
    }
    public String getValue() {
        return this.value;
    }
    public void setValue(String value) {
        this.value = value;
    }
}
LinkedList<CopyableObject> copyableList = /*...*/;
LinkedList<CopyableObject> copyableCopy = deepCopy(copyableList, CopyableObject::new);

当然,如果该类未实现自我复制的方法,则始终可以自己进行:

class SimpleObject {
    private String value;
    public String getValue() {
        return this.value;
    }
    public void setValue(String value) {
        this.value = value;
    }
}
LinkedList<SimpleObject> simpleList = /*...*/;
LinkedList<SimpleObject> simpleCopy = deepCopy(simpleList, o -> {
    SimpleObject copy = new SimpleObject();
    copy.setValue(o.getValue());
    return copy;
});

答案 2 :(得分:-1)

我最终以递归的方式进行了工作,并且成功了。

    SLinkedList<E> newLinkedList=new SLinkedList<E>();
    SNode<E> cur=head;
    if(cur==null) {
    return newLinkedList;
    }
    while(cur!=null) {
    newLinkedList.addLast(cur.element.deepClone());
        cur=cur.next;   
    }
    return newLinkedList;
}