make - java deep copy
Interfaz clonable obligatoria en Java (6)
Tengo un pequeño problema en Java. Tengo una interfaz llamada Modificable. Los objetos que implementan esta interfaz son modificables.
También tengo una clase ModifyCommand (con el patrón Command) que recibe dos objetos Modificables (para intercambiarlos en una lista más adelante, esa no es mi pregunta, ya diseñé esa solución).
La clase ModifyCommand comienza haciendo clones de los objetos modificables. Lógicamente, hice que mi interfaz modificable se extendiera a Cloneable. La interfaz luego define un método clone () que sus clases de implementación deben redefinir.
Luego, en ModifyCommand, puedo hacer: firstModifiableObject.clone (). Mi lógica es que las clases que implementan Modifiable tendrán que redefinir el método de clonación desde Object, ya que serán clonables (eso es lo que quiero hacer).
La cuestión es que cuando defino clases implementa Modificable y quiero anular clone (), no me lo permite, indicando que el método clone () de la clase Object oculta el de Modificable.
¿Que debería hacer? Tengo la impresión de que "lo estoy haciendo mal" ...
Gracias,
Guillaume.
Editar: creo que olvidaré el clon (). Yo a) asumiré que el objeto pasado al objeto modificable (implementando la interfaz) ya está clonado ob) haré otro método llamado, por ejemplo, copy (), que básicamente haría una copia en profundidad del objeto modificable ( o tal vez la solución genérica funcionará ...).
¿Cómo se ve la firma de tu método de clonación? Para que coincida con la interfaz Clonable, debería devolver un Objeto. Si lo declaras como una devolución modificable, ese podría ser el problema.
¿Definió la firma exactamente como está en el objeto?
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
Esto debería compilarse: agregar código personalizado al cuerpo. Wikipedia fue sorprendentemente útil en este caso.
No necesita redefinir el método de clonación en la interfaz Modificable.
Consulte la documentación: http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Cloneable.html
Entiendo que intenta obligar a todos a anular el método de clonación (), pero no puede hacerlo.
De otra manera, no puede anular una clase en una interfaz:
El método clone () siempre se asocia con Object.class y no con la interfaz clonable. Solo puede anularlo en otro objeto, no en una interfaz.
Agregando a la respuesta de Sean Reilly, esto debería resolver su problema, y es más seguro. Compila y funciona bien conmigo en JDK6:
public interface Modifiable<T extends Modifiable<T>> extends Cloneable {
T clone();
}
public class Test implements Modifiable<Test> {
@Override
public Test clone() {
System.out.println("clone");
return null;
}
public static void main(String[] args) {
Test t = new Test().clone();
}
}
No pude probarlo con Java 5 porque no lo tengo instalado, pero creo que funcionaría bien.
Si usa Java 1.5 o superior, puede obtener el comportamiento que desea y eliminar la conversión de esta manera:
public interface Modifiable<T extends Modifiable<T>> extends Cloneable {
T clone();
}
public class Foo implements Modifiable<Foo> {
public Foo clone() { //this is required
return null; //todo: real work
}
}
Dado que Foo amplía Object, esto aún satisface el contrato original de la clase Object. El código que no refina correctamente el método clone () no se compilará debido a las restricciones adicionales impuestas por la interfaz modificable. Como beneficio adicional, el código de llamada no tiene que emitir el resultado del método de clonación.
clase pública CloningExample implementa Cloneable {
private LinkedList names = new LinkedList();
public CloningExample() {
names.add("Alex");
names.add("Melody");
names.add("Jeff");
}
public String toString() {
StringBuffer sb = new StringBuffer();
Iterator i = names.iterator();
while (i.hasNext()) {
sb.append("/n/t" + i.next());
}
return sb.toString();
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new Error("This should not occur since we implement Cloneable");
}
}
public Object deepClone() {
try {
CloningExample copy = (CloningExample)super.clone();
copy.names = (LinkedList)names.clone();
return copy;
} catch (CloneNotSupportedException e) {
throw new Error("This should not occur since we implement Cloneable");
}
}
public boolean equals(Object obj) {
/* is obj reference this object being compared */
if (obj == this) {
return true;
}
/* is obj reference null */
if (obj == null) {
return false;
}
/* Make sure references are of same type */
if (!(this.getClass() == obj.getClass())) {
return false;
} else {
CloningExample tmp = (CloningExample)obj;
if (this.names == tmp.names) {
return true;
} else {
return false;
}
}
}
public static void main(String[] args) {
CloningExample ce1 = new CloningExample();
System.out.println("/nCloningExample[1]/n" +
"-----------------" + ce1);
CloningExample ce2 = (CloningExample)ce1.clone();
System.out.println("/nCloningExample[2]/n" +
"-----------------" + ce2);
System.out.println("/nCompare Shallow Copy/n" +
"--------------------/n" +
" ce1 == ce2 : " + (ce1 == ce2) + "/n" +
" ce1.equals(ce2) : " + ce1.equals(ce2));
CloningExample ce3 = (CloningExample)ce1.deepClone();
System.out.println("/nCompare Deep Copy/n" +
"--------------------/n" +
" ce1 == ce3 : " + (ce1 == ce3) + "/n" +
" ce1.equals(ce3) : " + ce1.equals(ce3));
System.out.println();
}
}