You are on page 1of 4

Clonación de objetos en Java

Autor: Edgar González González

Recientemente en un proyecto, necesitaba suministrar crear una “copia” de un objeto a fin


de pasarla como parámetro a un método garantizando asi que el objeto original no fuera
modificado. A este proceso es lo que se llama clonación (‘cloning’) de objetos. En otras
palabras la clonación es el proceso de duplicación de un objeto para que en memoria
existan dos objetos idénticos en el mismo instante de tiempo. Usualmente el objeto se clona
directamente llamando al método:

cualquierObjeto.cualquierMetodo(miObjetoImportante.clone());

Al igual que en muchos lenguajes orientados-a-objeto, en Java los objetos son pasados por
referencia. Esto implica que cualquier acción tomada por el método “llamado” afectará el
objeto que tiene el método “que llamó”, esto debido a que ambos objetos son el mismo.

La clase java.lang.Object contiene una implementación native y protected del


método clone. Esta implementación (que depende de la máquina sobre la que se ejecute el
código) determina cuanta memoria está siendo usada por el objeto a ser clonado, reserva la
misma cantidad de memoria para el objeto clon, y copia los valores de memoria de la vieja
dirección de memoria a la nueva. Y al final se devuelve un java.lang.Object el cual es la
referencia al nuevo objeto (el clon).

Para implementar la clonación en una clase, se deben hacer dos cosas:

1. La clase debe implementar la interfaz Cloneable, esta interfaz no tiene métodos


que implementar. El propósito de Cloneable es indicar al método clone de
java.lang.Object que el programador ha dado permiso explícito a la clase para
permitir que los objetos instanciados a partir de ella sean clonados.
2. El método clone de la clase java.lang.Object debe ser sobreescrito con un
acceso de tipo public en vez de protected. Es en este método que se implementará el
código que clona del objeto. Un ejemplo de una implementación sencilla de clone
es:

public Object clone()


{
Object clone = null;
try
{
clone = super.clone();
}
catch(CloneNotSupportedException e)
{
// No deberia suceder
}
return clone;
}
La excepción CloneNotSupportedException es arrojada por el método clone de la clase
java.lang.Object para prevenir que la operación de clonación se ejecute si no se ha
otorgado el permiso para ello (es decir, se implemente la interfaz Cloneable).

En términos sencillos el método clone de la clase java.lang.Object crea un nuevo


objeto mediante la copia exacta de los bytes de memoria y devolviendo una referencia, de
esto se tiene que los objetos miembros de un clon apuntan a los mismos objetos que los
objetos miembros del objeto original. Por ejemplo, consideremos la siguiente clase:

public class CloneTest() implements Cloneable


{
public String objetoInterno;

public Object clone()


{
Object clone = null;
try
{
clone = super.clone();
}
catch(CloneNotSupportedException e)
{
// No deberia ocurrir
}
return clone;
}
}

Cuando un objeto de la clase CloneTest es creado y a su atributo miembro se le asigna un


valor, por ejemplo, “prueba”, la memoria de este objeto realmente solo contiene los bits que
representan una referencia a un objeto String que contiene “prueba”. Cuando el método
clone es ejecutado, el objeto es duplicado byte por byte y el clon contendrá una copia de la
misma referencia que apunta al mismo objeto Stringque contiene “prueba”. El resultado
final es que existe solamente una copia de “prueba” y que una llamada sobre el objeto o su
clon para modificar su valor resultará en cambios para ambos. Esto es conocido como
‘shallow copy’, donde solamente los miembros primitivos (y referencias a objetos) del
objeto que están completamente contenidos en la memoria del objeto son duplicados, pero
el resto de los objetos miembros en el objeto no lo son.

Este enfoque no es suficientemente bueno para algunos casos, ya que en general los objetos
no están compuestos solamente de tipos primitivos. String, Hashtable, Vector y otras
clases que residen en el objeto a ser clonado, necesitan a su vez ser clonados, para que el
proceso de clonación sea efectivo, esto es el que se conoce como clonación “profunda”
(‘deep cloning’). A continuación un ejemplo de esto:
import java.util.Hashtable;
import java.util.Vector;

public class CloneTest implements Cloneable


{
public Object clone()
{
Object clone = null;
try
{
clone = super.clone();
}
catch(CloneNotSupportedException e)
{
// No debería ocurrir
}
// Aqui viene la implementacion de la clonación "profunda"
('deep clone')
((CloneTest)clone).setVector((Vector)mVector.clone());
((CloneTest)clone).setHashtable((Hashtable)mHashtable.clone());
((CloneTest)clone).setString(new String(mString));
return clone;
}

private Vector mVector;

public Vector getThings()


{
return mVector;
}

public void setVector(Vector pVector)


{
mVector = pVector;
}

private Hashtable mHashtable;

public Hashtable getStuff()


{
return mHashtable;
}

public void setHashtable(Hashtable pHashtable)


{
mHashtable = pHashtable;
}

private String mString;

public String getString()


{
return mString;
}

public void setString(String pString)


{
mString = pString;
}

public String toString()


{
return getClass() + " " + hashCode() + "\n mVector=" + mVector+
"\n mHashtable=" + mHashtable +
"\n mString=" + mString;
}
}

A pesar que la clonación puede ser necesaria, tambien existen situaciones (usualmente de
seguridad) donde se desea prohibir la clonación de una clase, para esto existen varias
alternativas, de las cuales las dos más importantes son:

• Declarar la clase como final. Haciendo esto se previene que se puedan definir
subclases para esta clase, e impedir que cualquiera pueda llamar al método clone
desde dentro de la clase (usando el alcance protected). Si se usa esta alternativa
para impedir la clonación se debe verificar que ninguna de las superclases se pueda
clonar. En el caso que esto sea asi, se debe sobreescribir el método clone en la clase
final y arrojar una CloneNotSupportedException. A pesar que esta es la
alternativa efectivamente impide la clonación, establece restricciones acerca de las
capacidades de extender la clase, las cuales pueden no ser aceptable.
• Implementar Cloneable y sobreescribir el método clone con un alcance public, y
hacer que arroje una CloneNotSupportedException. A pesar que esto impide que
la clase sea clonada, cualquier subclase puede hacer su propia implementación del
método clone e implementar la clonación copiando los atributos uno por uno.

Existe otra forma (considerada como “oscura”) de clonar un objeto, que es la serialización
(‘serializing’) del objeto. La serialización usa un método nativo externo al objeto, es
similiar a la clonación en el sentido en que el estado binario del objeto es capturado desde
memoria, pero en vez de copiarlo hacia otra dirección de memoria es copiado hacia un
‘stream’. En un futuro post pienso conversar un poco acerca de la serialización.

You might also like