Acerca de Java clonable

Estaba buscando algunos tutoriales que explicaran sobre Java Cloneable , pero no Cloneable ningún enlace bueno, y Stack Overflow se está convirtiendo en una opción más obvia de todos modos.

Me gustaría saber lo siguiente:

  1. Cloneable significa que podemos tener un clon o una copia de objetos, mediante la implementación de la interfaz Cloneable . ¿Cuáles son las ventajas y desventajas de hacer eso?
  2. ¿Cómo ocurre la clonación recursiva si el objeto es un objeto compuesto?

Lo primero que debes saber sobre Cloneable es: no lo uses.

Es muy difícil implementar la clonación con derecho de clonación, y el esfuerzo no vale la pena.

En lugar de eso, use algunas otras opciones, como Apache-commons SerializationUtils (deep-clone) o BeanUtils (shallow-clone), o simplemente use un copy-constructor.

Consulte aquí las opiniones de Josh Bloch sobre la clonación con Cloneable , que explica los muchos inconvenientes del enfoque. ( Joshua Bloch era un empleado de Sun y dirigió el desarrollo de numerosas funciones de Java).

La clonación en sí misma es desafortunadamente solo una interfaz de marcador, es decir: no define el método clone ().

Lo que sí es, es cambiar el comportamiento del método Object.clone () protegido, que generará una CloneNotSupportedException para las clases que no implementen Cloneable, y realizará una copia poco profunda para miembros para las clases que sí lo hacen.

Incluso si este es el comportamiento que está buscando, igual tendrá que implementar su propio método clone () para hacerlo público.

Al implementar su propio clon (), la idea es comenzar con el objeto creado por super.clone (), que se garantiza que es de la clase correcta, y luego hacer cualquier población adicional de campos en caso de que una copia superficial no sea lo que usted quiere. Llamar a un constructor desde clone () sería problemático ya que esto rompería la herencia en caso de que una subclase quiera agregar su propia lógica clonable adicional; si fuera a llamar a super.clone (), obtendría un objeto de la clase incorrecta en este caso.

Sin embargo, este enfoque omite cualquier lógica que pueda definirse en sus constructores, lo que podría ser potencialmente problemático.

Otro problema es que cualquier subclase que se olvide de anular clone () heredará automáticamente la copia superficial predeterminada, que probablemente no sea la que desea en caso de estado mutable (que ahora se compartirá entre el origen y la copia).

La mayoría de los desarrolladores no usan Cloneable por estos motivos, y simplemente implementan un constructor de copia.

Para obtener más información y riesgos potenciales de Cloneable, recomiendo encarecidamente el libro Effective Java de Joshua Bloch.

  1. La clonación invoca una forma extralingüística de construir objetos, sin constructores.
  2. La clonación requiere tratar de alguna manera con CloneNotSupportedException, o molestar al código del cliente para tratarlo.
  3. Los beneficios son pequeños; no es necesario que escriba manualmente un constructor de copiado.

Por lo tanto, use Cloneable juiciosamente. No le brinda suficientes beneficios en comparación con el esfuerzo que necesita para hacer las cosas bien.

La clonación es un paradigma de progtwigción básica. El hecho de que Java lo haya implementado deficientemente de muchas maneras no disminuye en absoluto la necesidad de la clonación. Además, es fácil implementar la clonación que funcionará como usted quiera, superficial, profunda, mixta, lo que sea. Incluso puede usar el nombre clon para la función y no implementar Cloneable si lo desea.

Supongamos que tengo las clases A, B y C, donde B y C se derivan de A. Si tengo una lista de objetos de tipo A como este:

 ArrayList list1; 

Ahora, esa lista puede contener objetos de tipo A, B o C. No sabe de qué tipo son los objetos. Entonces, no puedes copiar la lista como esta:

 ArrayList list2 = new ArrayList(); for(A a : list1) { list2.add(new A(a)); } 

Si el objeto es realmente de tipo B o C, no obtendrá la copia correcta. Y, ¿qué pasa si A es abstracto? Ahora, algunas personas han sugerido esto:

 ArrayList list2 = new ArrayList(); for(A a : list1) { if(a instanceof A) { list2.add(new A(a)); } else if(a instanceof B) { list2.add(new B(a)); } else if(a instanceof C) { list2.add(new C(a)); } } 

Esta es una muy, muy mala idea. ¿Qué sucede si agrega un nuevo tipo derivado? ¿Qué pasa si B o C están en otro paquete y no tienes acceso a ellos en esta clase?

Lo que le gustaría hacer es esto:

 ArrayList list2 = new ArrayList(); for(A a : list1) { list2.add(a.clone()); } 

Mucha gente ha indicado por qué la implementación básica de Java de clon es problemática. Pero, se supera fácilmente de esta manera:

En la clase A:

 public A clone() { return new A(this); } 

En la clase B:

 @Override public B clone() { return new B(this); } 

En la clase C:

 @Override public C clone() { return new C(this): } 

No estoy implementando Cloneable, simplemente usando el mismo nombre de función. Si no te gusta, ponle otro nombre.

A) No hay muchas ventajas de clonar sobre un constructor de copia. Probablemente el más grande es la capacidad de crear un nuevo objeto del mismo tipo dynamic exacto (suponiendo que el tipo declarado es clonable y tiene un método público de clonación).

B) El clon predeterminado crea una copia superficial, y seguirá siendo una copia superficial a menos que su implementación de clonación cambie eso. Esto puede ser difícil, especialmente si su clase tiene campos finales

Bozho tiene razón, el clon puede ser difícil de acertar. Un constructor / fábrica de copias atenderá la mayoría de las necesidades.

¿Cuáles son las desventajas de Cloneable?

La clonación es muy peligrosa si el objeto al que está copiando tiene composición. En este caso, debe pensar en el posible efecto secundario porque el clon crea una copia superficial:

Supongamos que tiene un objeto para manejar la manipulación relacionada con db. Supongamos que ese objeto tiene el objeto Connection como uno de la propiedad.

Entonces, cuando alguien crea el clon de originalObject , el objeto que se está creando, digamos, cloneObject . Aquí el originalObject y cloneObject mantienen la misma referencia para el objeto Connection .

Digamos que originalObject cierra el objeto Connection , por lo que ahora cloneObject no funcionará porque el objeto de connection se compartió entre ellos y fue cerrado por el originalObject .

Se puede producir un problema similar si digamos que desea clonar un objeto que tiene IOStream como una propiedad.

¿Cómo ocurre la clonación recursiva si el objeto es un objeto compuesto?

Clonable realiza una copia superficial. El significado es que los datos del objeto original y del objeto clonar señalarán la misma referencia / memoria. al contrario en el caso de la copia profunda, los datos de la memoria del objeto original se copian en la memoria del objeto clonar.

    Intereting Posts