2010-03-11 16 views
115

clonar método vs copiar constructor en java. cuál es la solución correcta. dónde usar cada caso?Clonar() vs Copiar constructor - que se recomienda en java

+6

http://stackoverflow.com/questions/1106102/clone-vs-copy-constructor-vs-factory-method –

+3

Evite 'clone' * cueste lo que cueste * y busque su propia solución de copia. – dimitarvp

+0

Los constructores de copia son mejores que Object.clone() porque ellos No nos fuerce a implementar ninguna interfaz ni a lanzar ninguna excepción, pero seguramente podemos hacerlo si es necesario, No requiere ninguna conversión, No necesita que dependamos de un objeto desconocido mecanismo de creación, No requiere que la clase padre siga cualquier contrato o implemente nada, Permítanos modificar los campos finales, Permítanos tener control total sobre la creación de objetos, podemos escribir nuestra lógica de inicialización en él. Leer más https://programmingmitra.blogspot.in/2017/01/Java-cloning-copy-constructor-versus-Object-clone-or-cloning.html –

Respuesta

90

El clon está roto, así que no lo use.

EL MÉTODO clon de la clase Object es un método algo mágico que hace lo que ningún método Java pura jamás podría hacer: Produce una copia idéntica de su objeto. Ha estado presente en la superclase Objeto primordial desde Días de publicación beta del compilador Java *; y, como todos antigua magia, requiere la encantamiento apropiado para prevenir el hechizo de inesperadamente backfiring

prefiere un método que copia el objeto

Foo copyFoo (Foo foo){ 
    Foo f = new Foo(); 
    //for all properties in FOo 
    f.set(foo.get()); 
    return f; 
} 

Más http://adtmag.com/articles/2000/01/18/effective-javaeffective-cloning.aspx

+18

Um, el clon no está roto. ¿Por qué crees que es? Si es porque no funciona si no lo anulas, bueno, ese es su contrato. – Bozho

+23

@Bozho, lee _Eficaz Java 2nd Edition_, Bloch lo explicó bastante bien. Doug Lea ya no usa 'clone()', excepto para clonar matrices (http://www.artima.com/intv/bloch13.html). – polygenelubricants

+1

Realmente no entiendo por qué la clonación no puede ser más sencilla. ¿Es esta una elección? o hay problemas realmente duros detrás de eso en el caso general? – LB40

47

Tenga en cuenta que clone() no funciona de la caja. Deberá implementar Cloneable y anular el método clone() en public.

Hay algunas alternativas, que son preferibles (ya que el método clone() tiene un montón de problemas de diseño, como se ha dicho en otras respuestas), y el constructor de copia requeriría el trabajo manual:

+1

¿Cómo funciona esa biblioteca de clonación profunda en cualquier objeto? Huelo código que probablemente está plagado de reflexión – Cruncher

+0

sí, mucha reflexión :) – Bozho

+0

¿cuál de estos no copia referencias y copia por valores? BeanUtils.cloneBean (bean) está copiando referencias, pero estoy usando una versión de Android (android-java-air-bridge.jar), no es la versión original de apache. –

3

Véase también : How to properly override clone method?. La clonación se rompe en Java, es tan difícil para hacerlo bien, e incluso cuando lo hace realmente no ofrece mucho, por lo que realmente no vale la pena la molestia.

+0

Es mucho más fácil hacerlo bien cuando tienes una clase 'final' que hereda de' java.lang.Object'. Es complicado cuando la clase contiene estructuras de datos mutables (y por lo tanto requiere una copia profunda), pero el mismo desafío también se presentaría en un constructor de copia. – IceArdor

18

Tenga en cuenta que el constructor de copia limita el tipo de clase al del constructor de copia. Considere el ejemplo:

// Need to clone person, which is type Person 
Person clone = new Person(person); 

Esto no funciona si person podría ser una subclase de Person (o si Person es una interfaz). Este es el punto principal de la clonación, es que puede clonar el tipo apropiado dinámicamente en el tiempo de ejecución (suponiendo que el clon esté implementado correctamente).

Person clone = (Person)person.clone(); 

o

Person clone = (Person)SomeCloneUtil.clone(person); // See Bozho's answer 

Ahora person puede ser cualquier tipo de Person asumiendo que clone se implementa correctamente.

+0

Es desafortunado que alguien sugirió una vez que una implementación adecuada del clon debería involucrar 'new' en lugar de' super.clone() ', ya que el comportamiento apropiado para' clone' es llamar a 'super.clone()' si ese método en sí mismo llama a 'super.clone()' (o es el clon integrado para miembros del objeto); si 'super.clone()' termina llamando a 'new', el único comportamiento no totalmente roto de' clone() 'es llamar a' new' en sí mismo, pero entonces cada clase secundaria debe anular 'clone()' para haga lo mismo si la clase secundaria de otro modo necesitaría anular 'clone()'. – supercat

+0

La pregunta "profundo vs superficial" no me parece ambigua en la mayoría de los casos. Existe una 'SomeCollection 'para contener las * identidades * de elementos de tipo' T', y al llamar 'clone()' a una, debe obtenerse una nueva instancia del mismo tipo que está separada del original pero contiene referencias a la misma 'T''s.Nada de lo que se puede hacer con el original o el clon debería afectar las * identidades * de los objetos almacenados en el otro. Realmente no entiendo cuál es la confusión. – supercat

30

clone() se diseñó con varios errores (consulte this question), por lo que es mejor evitarlo.

De Effective Java 2nd Edition, Tema 11: clon de anulación juiciosamente

Teniendo en cuenta todos los problemas asociados con Cloneable, es seguro decir que otras interfaces no deben extenderse, y que las clases diseñados para la herencia (artículo 17) no debería implementarlo. Debido a sus muchas deficiencias, algunos programadores expertos simplemente eligen nunca anular el método de clonación y nunca invocarlo excepto, tal vez, a copiar matrices. Si diseña una clase para herencia, tenga en cuenta que si elige no proporcionar un método de clonación protegido con buen comportamiento, será imposible que las subclases implementen Clonación.

Este libro también describe las muchas ventajas que tienen los constructores de copia sobre Cloneable/clone.

  • Ellos no se basan en un mecanismo de creación de objetos extralinguistico propensos al riesgo
  • No exigen la adhesión a las convenciones inaplicable escasamente documentados
  • no entren en conflicto con el uso adecuado de los campos finales
  • No lanzan excepciones marcadas innecesarias
  • No requieren moldes.

Todas las colecciones estándar tienen constructores de copias. Usalos, usalos a ellos.

List<Double> original = // some list 
List<Double> copy = new ArrayList<Double>(original); 
+3

Está copiando 'original' como' ArrayList' cuando puede haber sido otro tipo de lista (por ejemplo, 'LinkedList'). Esto es exactamente por qué el clon es mejor que un constructor de copia. –

2

gran tristeza: ni Cloneable/clon ni un constructor son grandes soluciones: NO QUIERO SABER LA IMPLEMENTACIÓN DE CLASE !!! (por ejemplo, tengo un mapa, que quiero copiar, usando la misma implementación oculta de MumbleMap). Solo quiero hacer una copia, si es compatible. Pero, por desgracia, Cloneable no tiene el método de clonación, por lo que no hay nada a lo que pueda escribir de forma segura para invocar clone().

Sea cual sea la mejor biblioteca de "objetos copiados" que exista, Oracle debería convertirla en un componente estándar de la próxima versión de Java (a menos que ya esté oculta en algún lugar).

Por supuesto, si más de la biblioteca (por ejemplo, Colecciones) son inmutables, esta tarea de "copia" simplemente desaparecerá. Pero luego comenzamos a diseñar programas Java con cosas como "invariantes de clase" en lugar de verdammt "patrón de frijol" (hacer un objeto roto y mutar hasta que sea bueno [suficiente]).

+0

Hay * alguna * esperanza para este tipo de cosas, al menos para objetos de valor que usted hace en su proyecto: https://projectlombok.org/features/experimental/Wither.html – Roboprog

+0

Si copiar fue fácil, ya tendría sido parte de Java. Pero no lo es. ¿Quieres una copia superficial, una copia profunda o algo intermedio? ¿Tienes diferentes comportamientos para diferentes clases dependiendo de lo que estás copiando y de lo que estás emitiendo? ¿Qué pasa con los genéricos? ¿Qué sucede cuando lo que estás copiando es un parámetro para un genérico? Esto podría ser un poco más fácil de razonar sin herencia y sin mutabilidad, pero esos están metidos en el corazón de Java (el lenguaje). Tal vez un lenguaje como Scala que garantice la mutabilidad facilitará la clonación. – IceArdor