2009-03-20 14 views
63

¿Hay alguna utilidad para la clonación de profundidad para las colecciones de Java:clon profundo recomendación utilidad

  • matrices
  • Listas
  • Mapas

NOTA: prefiera alguna solución sin el uso de serialización, pero con el uso del método Object.clone() Puedo estar seguro de que mi objeto personalizado método clone() implementará y usará sólo clases Java estándar que son cloneable ...

+0

posible duplicado de [¿Cómo se hace una copia profunda de un objeto en Java?] (Http://stackoverflow.com/questions/64036/how-do-you-make-a-deep-copy-of- an-object-in-java) –

Respuesta

51

Creo que la respuesta verde anterior fue mala, ¿por qué podría preguntar?

  • Se añade una gran cantidad de código
  • Se requiere que enumerar todos los campos que va a copiar y hacer esto
  • Esto no funcionará para las listas al utilizar clone() (Esto es lo clone() pues dice HashMap: Devuelve una copia superficial de esta instancia HashMap:. las llaves y valuesthemselves no se clonan) por lo que terminan haciendo de forma manual (esto me hace llorar)

Ah, y por cierto serialización también es malo , es posible que tenga que agregar Serializable por todas partes (esto también me hace cr y)

Entonces, ¿cuál es la solución:

biblioteca de Java profundas clonación La biblioteca de clonación es una biblioteca de Java fuente pequeña y abierta (licencia Apache) que en el fondo clones de objetos. Los objetos no tienen que implementar la interfaz Cloneable. Efectivamente, esta biblioteca puede clonar CUALQUIER objeto Java. Se puede utilizar, es decir, en implementaciones de caché, si no desea que se modifique el objeto en caché o cuando quiera crear una copia profunda de los objetos.

Cloner cloner=new Cloner(); 
XX clone = cloner.deepClone(someObjectOfTypeXX); 

echarle un vistazo en https://github.com/kostaskougios/cloning

+3

Cloner es una gran biblioteca (solo su rendimiento a veces me hace llorar ... pero supongo que no se puede hacer mucho mejor con la reflexión) – mik01aj

+0

Esta solución se ve mejor. No lo intenté, pero hay un par de comentarios en este hilo que son muy positivos sobre el clonador. – Juraj

+1

No funciona en Android ... – wieczorek1990

9

Una forma general de clonar una colección arbitraria consiste en serializarla en una secuencia, y luego volver a leerla en una nueva colección. Va a rehidratar objetos completamente nuevos que no tienen ninguna relación con los anteriores, que no sean copias idénticas.

Salida respuesta de Bruno para un enlace a la Apache Commons serialization utility classes, que será muy útil si esta es la ruta que decida tomar.

+0

Serialización la solución está bien, pero pensé en algo sin eso. Puedo garantizar que mi objeto personalizado se clonará profundamente con el método clone(), pero quiero un ayudante que lo haga para las clases estándar de Java ... – Juraj

+0

La forma de serialización para clonar está bien, pero tenía algunos campos que no son bajo mi control y que no son serializables ... – Juraj

0

uso de serialización y deserialización, pero tenga en cuenta que este método sólo funciona con las clases serializables sin campos transitorios. Además, sus singletons ya no serán singletons.

+0

El uso de serialización y deserialización para el trabajo de clonar objetos de memoria en tiempo de ejecución, o entre ejecuciones separadas de un programa es una mala idea. Para obtener más información sobre por qué esto es, google: "por qué la serialización y la deserialización son malas". –

18

Todos los enfoques para copiar objetos en Java tienen defectos graves:

Clon

  1. El método clone() está protegido, por lo que no se puede llamar directamente a no ser que la clase de las anulaciones de interrogación con un método público.
  2. clone() no llama al constructor. Cualquier constructor. Asignará memoria, asignará el campo interno class (que puede leer a través del getClass()) y copiará los campos del original.

Para más problemas con clone(): véase el punto 11 del libro de Joshua Bloch "Effective Java, Second Edition"

Serialize

Serialize es aún peor; tiene muchos de los defectos de clone() y algo más. Joshua tiene un capítulo completo con cuatro elementos solo para este tema.

mi solución

Mi solución es añadir una nueva interfaz para mis proyectos:

public interface Copyable<T> { 
    T copy(); 
    T createForCopy(); 
    void copyTo (T dest); 
} 

El código es el siguiente:

class Demo implements Copyable<Demo> { 
    public Demo copy() { 
     Demo copy = createForCopy(); 
     copyTo (copy); 
     return copy; 
    } 
    public Demo createForCopy() { 
     return new Demo(); 
    } 
    public void copyTo (Demo dest) 
     super.copyTo (dest); 
     ...copy fields of Demo here... 
    } 
} 

Por desgracia, tengo que copiar este código para todos mis objetos, pero siempre es el mismo código, por lo que puedo usar una plantilla de editor de Eclipse. Ventajas:

  1. Puedo decidir qué constructor llamar y cómo inicializar qué campo.
  2. inicialización sucede en un orden determinista (clase raíz de la clase ejemplo)
  3. puedo reutilizar objetos existentes y sobrescribir
  4. Tipo seguras
  5. Singleton estancia únicos

Para los tipos estándar de Java (como colecciones, etc.), utilizo una clase de utilidad que puede copiarlos. Los métodos tienen indicadores y devoluciones de llamada, por lo que puedo controlar qué tan profunda debe ser una copia.

+2

Hice algo similar al implementar clone() en todas las clases que necesito clonar. El mayor problema es que si tengo una colección, tengo que iterar sobre ella y copiarla por mi cuenta ... – Juraj

+0

Use una función auxiliar que acepte una Colección y devuelva una ArrayList: Dado que conoce el tamaño, eso asignará memoria solo una vez y ArrayList es rápido para los tipos habituales de acceso. –

+0

createForCopy necesita devolver una demostración – TimP

15

superficial clonación de una colección es fácil, pero si quieres a lo profundo del clon, una biblioteca probablemente le hará mejor que la mano de codificación que (ya que desea clonar los elementos dentro de la colección también).

Al igual que this answer, he usado el Cloner library y he probado específicamente el rendimiento contra XStream (que puede 'clonar' serializando y luego deserializando) y la serialización binaria. Aunque xstream es muy rápido en la serialización a/desde XML, Cloner es mucho más rápido a la clonación:

0,0851 ms: xstream (clon serializando/deserializar)
0,0223 ms: la serialización binaria (clon serializando/deserializar)
0.0017 ms: cloner
* tiempo promedio para clonar un objeto simple (dos campos) y ningún constructor público predeterminado. Ejecutar 10,000 veces.

Además de ser rápido, aquí hay más razones para elegir clonador:

  1. realiza una profunda clon de cualquier objeto (incluso aquellos que no escribe usted mismo)
  2. usted no tiene para mantener su método clone() hasta a la fecha en que cada vez que se agrega un campo
  3. puede clonar objetos que no tienen un constructor público predeterminado
  4. obras con la primavera
  5. (optimización) doesn 'clonar objetos inmutables conocidos (como entero, cadena, etc.)
  6. fácil de usar. Ejemplo:

    cloner.deepClone (anyObject);

+1

buena visión general, gracias – kostja

11

Soy el creador del cloner lib, el que presentó Brad. Esta es una solución para clonar objetos sin tener que escribir ningún código adicional (sin necesidad de objetos serializables o método impl clone())

Es bastante rápido como dijo Brad, y recientemente subí una versión que es incluso más rápida. Tenga en cuenta que implementar manualmente un método clone() será más rápido que clonear lib, pero luego tendrá que escribir mucho código.

Cloner lib me ha funcionado bastante bien ya que lo estoy usando en una implementación de caché para un sitio con un tráfico muy intenso (~ 1 millón de solicitudes/día). La memoria caché debe clonar aproximadamente 10 objetos por solicitud. Es bastante confiable y estable. Pero tenga en cuenta que la clonación no está exenta de riesgos. La lib se puede configurar para imprimir en cada instancia de clase que clona durante el desarrollo. De esta forma puede verificar si clona lo que cree que debería clonarse: los gráficos de objetos pueden ser muy profundos y pueden contener referencias a una cantidad sorprendentemente grande de objetos. Con clonear lib, puede indicarle que no clone los objetos que no desea, es decir, singletons.

+0

La biblioteca se ve bien, se comprobará más tarde ... – Juraj

+0

"Con clonear lib, puede indicarle que no clone los objetos que no quiere" intenté esto, pero no pude, ¿cómo puedo pedirle que no clone ciertos campos? – Sudarshan

+0

Saludos Konstantinos. Estoy utilizando su biblioteca en lugar de Apache utils one (estaba teniendo problemas con los moldes con SerializableUtils). El tuyo está trabajando sin problemas. ¡Buen trabajo!. – will824

2

He utilizado esta biblioteca cloning y me pareció bastante útil. Dado que tenía algunas limitaciones (necesitaba un control de grano más fino durante el proceso de clonación: en qué campo, en qué contexto y con qué profundidad debe clonarse , etc.), he creado una versión extendida de este. Usted controla la clonación de los campos al anotarlos en la clase de entidad.

sólo para obtener un sabor de ella, aquí es una clase de ejemplo:

public class CloneMePlease { 
    @Clone(Skip.class) 
    String id3 = UUID.randomUUID().toString(); 

    @Clone(Null.class) 
    String id4 = UUID.randomUUID().toString(); 

    @Clone(value = RandomUUID.class, groups=CustomActivationGroup1.class) 
    String id5 = UUID.randomUUID().toString(); 

    @Clone.List({ 
      @Clone(groups=CustomActivationGroup2.class, value=Skip.class), 
      @Clone(groups=CustomActivationGroup3.class, value=Copy.class)}) 
    Object activationGroupOrderTest = new Object(); 

    @Clone(LongIncrement.class) 
    long version = 1l; 

    @PostClone 
    private void postClone(CloneMePlease original, @CloneInject CloneInjectedService service){ 
     //do stuff with the original source object in the context of the cloned object 
     //you can inject whatewer service you want, from spring/guice to perform custom logic here 
    } 
} 

Más detalles aquí: https://github.com/mnorbi/fluidity-cloning

También hay una extensión específica de hibernación en el caso de que uno lo necesita.