Duplicación de objetos (objetos)

prev.gif (997 bytes)chapter.gif (1105 bytes)home.gif (1054 bytes)next.gif (998 bytes)

Pasando datos a una función

El interface Cloneable

Duplicación de un objeto simple

Duplicación de un objeto compuesto


En algunas situaciones deseamos que un objeto que se pasa a una función, o bien, que un objeto que llama a una función miembro no se modifiquen en el curso de la llamada. Por ejemplo, un objeto de la clase Lista al llamar a la función miembro ordenar modifica la posición de los datos en el array. Podríamos estar interesados en mantener la misma secuencia original no ordenada de datos.

Al hallar el determinante de una matriz, efectuamos una serie de trasformaciones sobre la matriz original que la convierte en una matriz triangular. Prodríamos estar interesados en mantener la matriz original para realizar otras operaciones.

En todos estos casos, puede ser muy útil para el programador realizar una copia del objeto original y realizar las trasformaciones en la copia dejando intacto el original.

disco.gif (1035 bytes)clonico: Punto.java, Rectangulo.java, ClonicoApp.java

 

El interface Cloneable

Un interface como hemos estudiado declara un conjunto de funciones, pero sin implementarlas. El interface Cloneable es muy simple ya que no define ninguna función.

public interface Cloneable { 
}

Una clase que implemente este interface le indica al método clone de la clase base Object que puede hacer una copia miembro a miembro de las instancias de dicha clase. Si una clase no implementa esta interface, e intenta hacer una duplicación del objeto a través de la llamada al método clone de la clase base Object, da como resultado una excepción del tipo  CloneNotSupportedException.

 

Duplicación de un objeto simple

La clase base Object de todas las clases en el lenguaje Java, tiene una función miembro denominada clone, que se redefine en la clase derivada para realizar una duplicación de un objeto de dicha clase. 

Sea la clase Punto ya estudiada en páginas anteriores. Para hacer una copia de un objeto de esta clase, se ha de agregar a la misma el siguiente código:

public class Punto implements Cloneable{
    private int x;
    private int y;
//constructores ...

    public Object clone(){
        Object obj=null;
        try{
            obj=super.clone();
        }catch(CloneNotSupportedException ex){
            System.out.println(" no se puede duplicar");
        }
        return obj;
    }
//otras funciones miembro
}

En la redefinición de clone, se llama a la versión clone de la clase base desde super. Esta llamada se ha de hacer forzosamente dentro de un bloque try... catch, para capturar la excepción CloneNotSuportedException que nunca se producirá si la clase implementa el interface Cloneable. Como vemos la llamada a la versión clone de la clase base devuelve un objeto de la clase base Object, que es a su vez devuelto por la versión clone de la clase derivada.

Para crear un objeto pCopia que es una copia de otro objeto punto se escribe.

        Punto punto=new Punto(20, 30);
        Punto pCopia=(Punto)punto.clone();

La promoción (casting) es necesaria ya que clone devuelve un objeto de la clase base Object que ha de ser promocionado a la clase Punto.

Si hemos redefinido en la clase Punto la función miembro toString de la clase base Object, podemos comprobar que los objetos punto y pCopia guardan los mismos valores en sus miembros dato.

        System.out.println("punto "+ punto);
        System.out.println("copia "+ pCopia);
public class Punto implements Cloneable{
    private int x;
    private int y;
   public Punto(int x, int y) {
        this.x = x;
	    this.y = y;
    }
    public Punto() {
        x=0;
        y=0;
    }
    public Object clone(){
        Object obj=null;
        try{
            obj=super.clone();
        }catch(CloneNotSupportedException ex){
            System.out.println(" no se puede duplicar");
        }
        return obj;
    }
    public void trasladar(int dx, int dy){
        x+=dx;
        y+=dy;
    }
    public String toString(){
        String texto="origen: ("+x+", "+y+")";
        return texto;
    }
} 

 

Duplicación de un objeto compuesto

Volvamos de nuevo sobre la clase Rectangulo estudiada en páginas anteriores. Los miembros dato de la clase Rectangulo son un objeto de la clase Punto, el origen, y las dimensiones: ancho y alto del rectángulo.

Veamos ahora el código que tenemos que agregar a la clase Rectangulo para que se puedan efectuar copias de los objetos de dicha clase.

public class Rectangulo implements Cloneable{
    private int ancho ;
    private int alto ;
    private Punto origen;
//los constructores
    public Object clone(){
        Rectangulo obj=null;
        try{
            obj=(Rectangulo)super.clone();
        }catch(CloneNotSupportedException ex){
            System.out.println(" no se puede duplicar");
        }
        obj.origen=(Punto)obj.origen.clone();
        return obj;
    }
//otras funciones miembro
}

Un objeto de la clase Rectangulo contiene un subobjeto de la clase Punto. En la redefinición de la función miembro clone de la clase Rectangulo se ha de efectuar una duplicación de dicho subobjeto llamando a la versión clone definida en la clase Punto.

Recuérdese que la llamada a clone siempre devuelve un objeto de la clase base Object que ha de ser promocionado (casting) a la clase derivada adecuada.

Veamos ahora, como se crea un objeto de la clase Rectangulo y se duplica. Para crear un objeto rCopia que es una copia del objeto rect de la clase Rectangulo, se escribe.

        Rectangulo rect=new Rectangulo(new Punto(0, 0), 4, 5);
        Rectangulo rCopia=(Rectangulo)rect.clone();

Si hemos redefinido en la clase Rectangulo la función miembro toString de la clase base Object, podemos comprobar que los objetos rect y rCopia guardan los mismos valores en sus miembros dato.

        System.out.println("rectángulo "+ rect);
        System.out.println("copia "+ rCopia);
public class Rectangulo implements Cloneable{
    private int ancho ;
    private int alto ;
    private Punto origen;

    public Rectangulo() {
	    origen = new Punto(0, 0);
	    ancho=0;
	    alto=0;
    }
    public Rectangulo(Punto p) {
	    this(p, 0, 0);
    }
    public Rectangulo(int w, int h) {
	    this(new Punto(0, 0), w, h);
    }
    public Rectangulo(Punto p, int w, int h) {
	    origen = p;
	    ancho = w;
	    alto = h;
    }
    public Object clone(){
        Rectangulo obj=null;
        try{
            obj=(Rectangulo)super.clone();
        }catch(CloneNotSupportedException ex){
            System.out.println(" no se puede duplicar");
        }
        obj.origen=(Punto)obj.origen.clone();
        return obj;
    }
    public void mover(int dx, int dy) {
	    origen.trasladar(dx, dy);
    }
    public int area() {
	    return ancho * alto;
    }
    public String toString(){
        String texto=origen+" ancho: "+ancho+" alto: "+alto;
        return texto;
    }
}