2008-11-06 8 views
14

Un colega me preguntó recientemente cómo clonar profundamente un mapa y me di cuenta de que probablemente nunca he usado el método clone(), lo que me preocupa.¿Para qué has usado Object.clone()?

¿Cuáles son los escenarios más comunes que ha encontrado donde necesita clonar un objeto?

Respuesta

15

Supongo que se refiere a Object.clone() en Java. En caso afirmativo, tenga en cuenta que Object.clone() tiene algunos problemas importantes, y su uso se desaconseja en la mayoría de los casos. Consulte el artículo 11, del "Effective Java" de Joshua Bloch para obtener una respuesta completa. Creo que puedes usar Object.clone() de forma segura en matrices de tipo primitivo, pero aparte de eso, debes ser prudente sobre el uso y sobreescritura del clon. Probablemente sea mejor que defina un constructor de copia o un método de fábrica estático que clone explícitamente el objeto de acuerdo con su semántica.

+2

Correcto - el escenario más común es "no usar clonar". –

+0

El enlace estaba roto. –

+0

Obtuve este enlace del sitio artima: http://www.artima.com/intv/bloch13.html –

5

Más comúnmente, cuando tengo que devolver un objeto mutable a una persona que llama que me preocupa que la persona que llama pueda ensuciar, a menudo de una manera poco amistosa. Las listas y la fecha son las que le hago esto a la mayoría. Si la persona que llama es probable que quiera iterar sobre una lista y posiblemente tengo hilos que la actualicen, es más seguro devolver una copia o clonarla.

En realidad, eso plantea algo que voy a tener que abrir otra pregunta para: copiar los constructores o clonar? Cuando hice C++, SIEMPRE hicimos un constructor de copia e implementamos el clon con él, pero a FindBugs no le gusta si implementa su clon usando un constructor de copia.

+0

Si utiliza un constructor de copia para implementar clone(), en lugar de invocar super.clone(), cuando alguien subclasifica su clase e invoca clon obtendrán un objeto del tipo de superclase, no del tipo de subclase. –

+0

@Dan, sí, eso es más o menos lo que FindBugs dijo. Y después de haber leído algo que estaba vinculado desde una respuesta de StackOverflow a una pregunta sobre C++, ahora puedo entender que hacerlo de esa manera en C++ no fue genial. –

+0

Implementando el clon con el constructor de copia en C++: Herb Sutter diría "Here be dragons". Lea los detalles aquí: http://www.gotw.ca/publications/advice97.htm –

3

Cuando necesito hacer un duplicado de algo para modificar el duplicado sin afectar el original, y por supuesto en este escenario, la clonación profunda (solo) será suficiente. Tuve que hacer esto en un sistema en el que clonaba una instancia de clase de dominio, aplicaba los cambios del usuario y luego realizaba una comparación de los dos para que el usuario verificara sus cambios.

2

El método Object.clone() no especifica si la copia de una subclase es una copia profunda o superficial, es completamente dependiente de la clase específica. El método Object.clone() mismo hace una copia superficial (copia el estado interno de la clase Object), pero las subclases deben anularlo, llamar a super.clone() y copiar su estado interno según sea necesario (superficial o profundo).

Especifica algunas convenciones, que puede o no seguir. Para (a.getClass() == a.clone(). GetClass()) para devolver true, debe llamarse a super.clone() en lugar de simplemente 'new Subclass()', ya que supuestamente super.clone() lo haría correctamente crea una instancia de la clase de este objeto (incluso en subclases) y copia todo el estado interno, incluidos los campos privados, que no pudieron ser copiados por subclases usando un constructor de copia, reglas de visibilidad debidas. O se vería obligado a exponer un constructor que no debería estar expuesto, para una mejor encapsulación.

Ejemplo:

//simple clone 
class A implements Cloneable { 
    private int value; 
    public A clone() { 
    try { 
     A copy = (A) super.clone(); 
     copy.value = this.value; 
     return copy; 
    } catch (CloneNotSupportedException ex) {} 
    } 
} 

//clone with deep and shallow copying 
class B extends A { 
    Calendar date; 
    Date date; 
    public B clone() { 
    B copy = (B) super.clone(); 
    copy.date = (Calendar) this.date.clone(); // clones the object 
    copy.date = this.date; // copies the reference 
    return copy; 
    } 
} 

copia profunda se utiliza generalmente cuando los objetos dependientes son mutables (como Calendar), y la copia debe ser completamente independiente de la original.

Cuando los objetos dependientes son inmutables (como Fecha), compartir la misma instancia generalmente no es un problema, y ​​una copia superficial puede ser suficiente.

Al usar Object.clone() debe seguir algunas reglas, pero son lo suficientemente simples para ser comprensibles. Probablemente la parte más difícil es definir correctamente qué tan profundo debe copiar en su gráfico de objetos. Un problema lógico, no un problema de idioma, eso es.

0

He utilizado Object.clone() en una aplicación de flujo web Spring para verificar qué ha cambiado cuando un usuario edita/ingresa datos en un formulario para fines de auditoría.

Al comienzo del flujo, llamo al método de clonación que se implementó en el objeto de respaldo de formulario utilizado en el flujo web de primavera y guardo la instancia del clon en la sesión del usuario. Una vez que el usuario ha completado la edición de datos en el formulario html y presionado el botón Guardar, comparo los valores nuevos vinculados al objeto de respaldo con el valor clonado para determinar qué datos ha cambiado el usuario.

Esto funcionó bien y fue muy fácil de implementar, realmente no he tenido ningún problema con la clonación en Java.

Cuestiones relacionadas