miércoles, 9 de junio de 2010

Sobreescritura, Sobrecarga y Constructores: Conceptos




Sobreescritura, Sobrecarga y Constructores: Conceptos


La sobrescritura de métodos es una característica que ofrecen lenguajes orientados a objetos, que permite a una clase hija (subclase) implementar a su forma un comportamiento heredado de su clase padre (superclase). Es bueno recordar que para que haya sobrescritura la subclase debe heredar los miembros de la superclase, es decir, no puede haber sobrescritura sin herencia.

El método a ejecutar se determina en tiempo de ejecución y depende del objeto de donde se invoque, es obvio que si se crea un objeto de la superclase, el método a ejecutar será el de la superclase y no el de la clase hija o subclase, mientras que si se crea un objeto de la clase hija con el tipo de referencia de el mismo o de la clase padre, el método que se ejecutara será el método implementado por la subclase en caso de que lo haya sobrescrito.

Existen algunas cosas que saber al momento de sobrescribir métodos, aunque no es nuevo para algunos, esto es solo un review o repaso de las más destacadas:

·         El modificador de acceso del método que sobrescribe no puede ser más restrictivo que el de  la superclase, en cambio se permite lo contrario.
·         El tipo de retorno debe coincidir o en su defecto debe ser un suptipo del tipo declarado en la firma del método de la superclase, esto es tipo covariant.
·         La lista de argumentos entre ambos métodos, el de la subclase y superclase, deben coincidir o de lo contrario lo que se está haciendo es sobrecargando el método.
·         Si el método de la superclase esta marcado con el keyword final, quiere decir que las subclases de esta no pueden sobrescribirlo, es decir, con la palabra reservada final se asegura que un método no sea sobrescrito en demás clases hijas.
·         En caso de que en el método que sobrescribe o en algún otro lugar en el código, se necesite el método de la superclase solo hay que hacer referencia a él con el keyword super. Ej: super.metodoSobrescrito();

La sobrecarga de métodos es otra característica de la programación orientada a objetos, la cual nos permite utilizar el mismo nombre de un método, ya sea que este método este en la misma clase o en la superclase en tal caso, con diferentes argumentos. Sobrecarga es reutilización del identificador del método para provecho del usuario que utiliza nuestra clase, le proporciona al usuario la opción o posibilidad de utilizar el mismo método con diferentes datos de entrada (argumentos).

También en la sobrecarga existen algunas cosas que recordar:

·         Para que haya sobrecarga, es obligatorio el cambio en los argumentos, ya sea de cantidad o de tipos de argumentos.
·         A diferencia de los métodos que sobreescriben, los métodos que sobrecargan se les puede cambiar el modificador de acceso como uno quiera.
·         Tampoco hay restricciones en cuanto al tipo de retorno, es decir, pueden no ser iguales.
·         Cual método sobrecargado a ejecutar se decide en base a los argumentos que este recibe, por eso es la obligatoriedad del cambio en los argumentos.
·         Que método sobrecargado se ejecuta en un momento se determina en tiempo de compilación y no en tiempo de ejecución como los métodos sobreescritos, además este depende del tipo de referencia del objeto y no del objeto instanciado.
·         La sobrecarga y el polimorfismo de ninguna forma se relacionan, al menos en el sentido en el que la sobrescritura lo hace con este último.

Personalmente, antes creía que la sobrecarga era polimorfismo porque en algún otro libro lo había leído así, mas sin embargo, luego de leer este libro el de scjp 6 y otros, además de la edificante clase del profesor y comentarios de compañeros sobre este tema me di cuenta que no, que la sobrecarga es solo reutilización de nombre de métodos. Creo que es bueno pensar como lo hacía Aristóteles: “El ignorante afirma, el sabio duda y reflexiona”.

Bueno los constructores no son más que el código que se ejecuta al momento de crear o un objeto, instanciar nuestra clase. Se utilizan para inicializar el estado de nuestro nuevo objeto. Por estado, entiéndase variables de instancia.

De los constructores se puede decir que:

·         Se ejecutan cuando creamos un objeto mediante la palabra new.
·         No se heredan, y por tanto no se sobrescriben.
·         Se pueden sobrecargar.
·         Pueden tener cualquiera de los modificadores de acceso (public, protected, incluso private).
·         No tienen tipo de retorno, esto es lo que lo diferencia especialmente con los métodos normales.
·         Solo se invocan con el keyword new y/o dentro de otros constructores utilizando alguno de estos (this(), super()).
·         No pueden ser marcados static o final.
·         Deben tener el mismo nombre que la clase.
·         Si no se digita ningún constructor, el compilador introduce uno por defecto; uno que no tiene argumentos.

Creo que todo esto se explica mejor con un pequeños ejemplo:

// Clase Coordenada
public class Coordenada {

            private double abscisa;
            private double ordenada;
           
           
            public Coordenada() {
                        this(15.0, 25.0);                     
            }
           
            public Coordenada(double x, double y) {
                        this.abscisa = x;
                        this.ordenada = y;
            }
           
           
            // getters
           
            public double getAbscisa() {
                        return abscisa;
            }
           
            public double getOrdenada() {
                        return ordenada;
            }
                       
           
            // setters
           
            public void setAbscisa(double x) {
                        this.abscisa = x;
            }
           
            public void setOrdenada(double y) {
                        this.ordenada = y;
            }

}

// Clase FormaGeometrica
public class FormaGeometrica {
           
            private String tipoForma;
            private Coordenada punto;
           
            // Constructores
           
            public FormaGeometrica() {
                        this("FormaGeometrica", new Coordenada(50.0, 50.0));
            }
           
            public FormaGeometrica(String tipo, Coordenada punto) {
                        this.tipoForma = tipo;
                        this.punto = punto;
            }
           
           
            // getter
           
            public String getTipoForma() {
                        return tipoForma;
            }
           
            public Coordenada getPunto() {
                        return punto;
            }
           
           
            // setter
           
            public void setTipoForma(String tipo) {
                        this.tipoForma = tipo;
            }
           
            public void setPunto(Coordenada pto) {
                        this.punto = pto;
            }
           
           
            // ej de sobrescritura
            public void dibujar() {  //  este método se sobrescribirá y sobrecargara en la clase hija Circulo y demas
                        System.out.println("Me dibujo como una forma en general");
            }          
           
            public double calcularArea() {
                        System.out.println("Yo calculo el area de una forma geometrica en general");
                        return 0.0;
            }          
}


// Clase Circulo
public class Circulo extends FormaGeometrica {
           
            //private Coordenada punto;
            private double radio;
           
           
            // Constructores
           
            public Circulo() {
                        this(new Coordenada(15.0, 25.0), 5.0);
            }
           
            public Circulo(Coordenada pto, double radio) {
                        super("Circulo", pto);
                        this.radio = radio;
            }
           
           
            public double getRadio() {
                        return radio;
            }
           
            public void setRadio(double radio) {
                        this.radio = radio;
            }
           
            // gral methods
           
            public void dibujar() { // método sobrescrito
                        System.out.println("Me dibujo como solo un circulo lo puede hacer.");
                        this.dibujar(this.getPunto());
            }

            public void dibujar(Coordenada pto) { // ejemplo de sobrecarga
                        System.out.printf("Circulo dibujandose en el punto %.2f, %.2f del espacio. \n", pto.getAbscisa(), pto.getOrdenada());
            }
           
            public double calcularArea() { // este metodo devuelve el area de el mismo
                        return this.calcularArea(this.radio);
            }
           
            public double calcularArea(double radio) { // este metodo devuelve el area de cualquier circulo
                        return Math.PI * (radio * radio);
            }
}

// Clase Triangulo
public class Triangulo extends FormaGeometrica {

            private double ladoA;
            private double ladoB;
            private double ladoC;
           
            // constructores
           
            public Triangulo() {
                        this(new Coordenada(15.0, 40.0), 5.0, 5.0, 5.0);
            }
           
            public Triangulo(Coordenada pto, double lA, double lB, double lC) {
                        super("Triangulo", pto);
                        this.ladoA = lA;
                        this.ladoB = lB;
                        this.ladoC = lC;                     
            }
           
           
            // getters
           
            public double getLadoA() {
                        return ladoA;
            }
           
            public double getLadoB() {
                        return ladoB;
            }
           
            public double getLadoC() {
                        return ladoC;
            }
           

            // setters
           
            public void setLadoA(double lado) {
                        this.ladoA = lado;
            }
           
            public void setLadoB(double lado) {
                        this.ladoB = lado;
            }
           
            public void setLadoC(double lado) {
                        this.ladoC = lado;
            }
           
           
            // gral methods
           
            public void dibujar() { // método sobrescrito
                        System.out.println("Me dibujo como solo un triangulo lo puede hacer.");
                        this.dibujar(this.getPunto());
            }

            public void dibujar(Coordenada pto) { // ejemplo de sobrecarga
                        System.out.printf("Triangulo dibujandose en el punto %.2f, %.2f del espacio.\n", pto.getAbscisa(), pto.getOrdenada());
            }
                       
            public double calcularArea() { // este metodo devuelve el area de el mismo
                        return this.calcularArea(this.ladoA, this.ladoB, this.ladoC);
            }
           
            public double calcularArea(double lA, double lB, double lC) { // este metodo devuelve el area de cualquier circulo
                        // segun el Matematico griego Heron, la formula para calcular el area de cualquier triangulo es AT = raiz cuadrada de ( S ( S-A )( S-B )( S-C ) ) 
                        // *** S = semiperimetro = ( A + B + C ) / 2
                       
                        double semiPerimetro = (lA + lB + lC) / 2;
                        double area = Math.sqrt(semiPerimetro * ((semiPerimetro - lA) * (semiPerimetro - lB) * (semiPerimetro - lC)));
                       
                        return area;
            }
           
}

// Clase Cuadrado
public class Cuadrado extends FormaGeometrica {
           
            private double lado;
           
            // constructores
           
            public Cuadrado() {
                        this(new Coordenada(15.0, 55.0), 5.0);
            }

            public Cuadrado(Coordenada pto, double lado) {
                        super("Cuadrado", pto);
                        this.lado = lado;
            }
           
           
            // getter
           
            public double getLado() {
                        return lado;
            }
           
           
            // setter
           
            public void setLado(double lado) {
                        this.lado = lado;
            }
           
           
            // gral methods
           
            public void dibujar() { // método sobrescrito
                        System.out.println("Me dibujo como solo un Cuadrado lo puede hacer.");
                        this.dibujar(this.getPunto());
            }

            public void dibujar(Coordenada pto) { // ejemplo de sobrecarga
                        System.out.printf("Cuadrado dibujandose en el punto %.2f, %.2f del espacio.\n", pto.getAbscisa(), pto.getOrdenada());
            }
           
            public double calcularArea() { // este metodo devuelve el area de el mismo
                        return this.calcularArea(this.lado);
            }
           
            public double calcularArea(double lado) { // este metodo devuelve el area de cualquier circulo
                        return lado * lado;
            }
           
}

// Clase TestFormaGeometrica
public class TestFormaGeometrica {

            public static void main(String[] args) {
                        System.out.println("\n.... Probando Sobrescritura, Sobrecarga y Constructores ....\n");
                        FormaGeometrica[] formasGeometricas = new FormaGeometrica[] {new Circulo(), new Cuadrado(), new Triangulo()};
                        new TestFormaGeometrica().testFormas(formasGeometricas);
            }

            public void testFormas(FormaGeometrica[] formas) {
                        for (FormaGeometrica fg : formas) {
                                   System.out.printf("Forma: %s\n", fg.getTipoForma());
                                   fg.dibujar();
                                   System.out.printf("Mi Area: %.2f\n\n", fg.calcularArea());
                        }
            }
           
}


Salida de la aplicación TestFormaGeometrica:

.... Probando Sobrescritura, Sobrecarga y Constructores ...

Forma: Circulo
Me dibujo como solo un circulo lo puede hacer.
Circulo dibujandose en el punto 15.00, 25.00 del espacio.
Mi Area: 78.54

Forma: Cuadrado
Me dibujo como solo un Cuadrado lo puede hacer.
Cuadrado dibujandose en el punto 15.00, 55.00 del espacio.
Mi Area: 25.00

Forma: Triangulo
Me dibujo como solo un triangulo lo puede hacer.
Triangulo dibujandose en el punto 15.00, 40.00 del espacio.
Mi Area: 10.83


 --


Edwin A. Bratini
Computer Science Student - UASD
Cel.: 809-705-6361
edwin.bratini@gmail.com
edwin_bratini@hotmail.com

No hay comentarios:

Publicar un comentario