Pregunta

Estoy tratando de implementar un clone() método en un DoubleLinkedList. Ahora, el problema es que implementarlo por "la convención" es mucho más problemático que solo crear un nuevo DoubleLinkedList y llenándolo con todos los elementos de mi actualización duplicada actual.

¿Hay algún inconveniente que no esté viendo al hacer eso?

Aquí está mi enfoque actual:

@Override
public DoubleLinkedList<T> clone() {
    DoubleLinkedList<T> dll = new DoubleLinkedList<T>();

    for (T element : dll) {
        dll.add(element);
    }

    return dll;
}

Esto es lo que sería por la convención:

@Override
public DoubleLinkedList<T> clone() {
    try {
        DoubleLinkedList<T> dll = (DoubleLinkedList<T>)super.clone();
        //kinda complex code to copy elements
        return dll;
    } catch (CloneNotSupportedException e) {
        throw new InternalError(e.toString());
    }
}
¿Fue útil?

Solución

Como señala correctamente, la convención es siempre llamar super.clone() al comienzo de una implementación de clone(). Desde el API Docios en Object#clone():

Por convención, el objeto devuelto debe obtenerse llamando a Super.Clone. Si una clase y todas sus superclase (excepto el objeto) obedecen esta convención, será el caso de que X.Clone (). GetClass () == X.GetClass ().

Tu primer intento (sin usar super.clone()) tiene el siguiente problema:

Supongamos que tengo

class IntDoubleLinkedList extends DoubleLinkedList<Integer> implements Cloneable

(y eso IntDoubleLinkedList no se molesta en anular clone()) y ejecuto el siguiente código:

IntDoubleLinkedList idll = new IntDoubleLinkedList();
IntDoubleLinkedList idll2 = (IntDoubleLinkedList) idll.clone();

¿Lo que sucederá? El método clon de su DoubleLinkedList se ejecutará, que, si no pasa por super.clone (), devuelve una instancia de DoubleLinkedList que a su vez no se puede lanzar a un IntDoubleLinkedList. A ClassCastException ¡Será lanzado!

Entonces, ¿cómo lo hace? super.clone() ¿Resolver este problema? Bueno, si todos se adhieren a la convención de llamar super.clone() En un método de clonos de anulación, Object.clone() eventualmente se llamará, y esta implementación creará una instancia de un tipo adecuado (IntDoubleLinkedList en este caso)!

Otros consejos

Como otros han explicado, si vas a anular clone Debes obedecer su contrato.

Si te gusta la forma en que lo tienes actualmente, solo haz DoubleLinkedList no Cloneable y convierta su implementación en un constructor de copias o método de fábrica estática. Un método de fábrica estática tiene el beneficio adicional de proporcionar un poco de inferencia de tipo para los argumentos de tipo genérico.

PD LinkedList es una lista doblemente vinculada.

Si lo hace creando una nueva lista y agregando todos los elementos de la fuente, si hace algo como:

DoubleLinkedList<Foo> l1 = new DoubleLinkedList<Foo>();
l1.add (new Foo(params));
DoubleLinkedList<Foo> l2 = l1.clone();
Foo foo = l2.get(0);
foo.setProperty("new Value");

Foo.Property será "nuevo valor" en ambas listas (lo mismo al revés; si lo cambia en L1, los cambios aparecerán en L2). La forma correcta sería realmente clonar cada elemento y agregar el clon para garantizar que las listas sean independientes. Tenga en cuenta que esto solo sucede si cambia las propiedades de los elementos, no si agrega, mueve, elimina las de la lista.

Editar: Acabo de darme cuenta de que, dado que es una lista vinculada, los elementos siguientes/anteriores son las propiedades del elemento, por lo que incluso agregar, eliminar, afectará a ambas listas.

La razón por la que la "Convención" es llamar super.clone() es asegurarse de que el tipo último del objeto clonado coincida con el objeto que se está clonando. Por ejemplo, si instancías tu propia nueva DoubleLinkedList en el clone() Método, bueno, eso es bueno por ahora, pero más tarde si una subclase no anula clone() Terminará devolviendo un clon que es un DoubleLinkedList en lugar de su propia clase. (¡Tampoco fallará en clonar sus campos adicionales, si los hay, probablemente! Por lo tanto, hay problemas más grandes).

En ese sentido, se prefiere el método convencional, y de hecho es torpe.

Sin embargo, ambas implementaciones tienen un problema similar: no está copiando las estructuras de datos. El clon es solo un policía superficial. Probablemente esto no sea lo que la persona que llama espera. Debería pasar y reemplazar cada valor en el DoubleLinkedList con un clon del valor, y igualmente para otros campos no propicionales.

¡En ese sentido, el método convencional dará el resultado incorrecto aquí! Necesitas una tercera vía. Su primer método probablemente solo funciona, excepto que necesita agregar element.clone() por ejemplo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top