lunes, 12 de mayo de 2014

Sobreescritura y SobreCarga de Métodos en Java ( Overriding y Overloading )

Después de un tiempo sin publicar debido a problemas técnicos (Casi muere mi PC) regreso con 2 conceptos de POO que me han pedido que aborde..... me refiero a la sobreescritura y sobrecarga de métodos...........2 conceptos que pueden parecer confusos pero veremos que en sí representan algo muy simple.........

Debemos saber que estas propiedades de la Programación Orientada a Objetos nos traen algunas ventajas como por ejemplo la facilidad, extensibilidad y flexibilidad en el código......

Pero que son?

La sobrecarga y sobreescritura no son mas que dos conceptos aplicados al trabajo con métodos, específicamente en el uso que le queremos dar...... estos conceptos dependen principalmente de nuestra lógica de programación y el enfoque o forma de trabajo.... depende de lo que queremos hacer....... ¿Como así?...... veamos de forma mas clara cada concepto....

Sobrecarga de métodos (Overloading)

En java sabemos que si ya declaramos una variable o un método con un nombre en especifico, no podemos declarar otra variable o método que se llame igual..... sin embargo esta regla no aplica cuando usamos la Sobrecarga de métodos, ya que esta permite usar el mismo nombre del método pero solo si se tiene diferente firma..... ¿firma?....... cuando hablamos de la firma de un método, nos referimos a sus parámetros......

en resumen la sobrecarga permite declarar métodos que se llamen igual pero que reciban parámetros diferentes (no pueden haber 2 métodos con el mismo nombre y los mismos parámetros), por esta razón lo que define a que método se ingresa, son los argumentos que se envían como parámetros....

Anteriormente mencioné algo sobre la forma de trabajo o lógica de programación, esto es porque supongamos que yo quiero hacer sumas, pero mi programa debe sumar por aparte 2 números enteros o 2 números doubles.... para esto tengo 2 opciones.

1. crear 2 métodos, uno llamado sumaEnteros(int a, int b) y otro sumaDoubles(double a, double b)

2. Aplicar el concepto de sobrecarga, donde aunque también vamos a crear 2 metodos, los vamos a llamar con el mismo nombre pero con diferentes parametros....sumar(int a, int b) y sumar(double a, double b) quedando algo como esto:
public void sumar(int a, int b)
    {
        int suma=a+b;
        System.out.println("la suma es: "+suma);
    }
    
    public void sumar(double a, double b)
    {    
        double suma=a+b;
        System.out.println("la suma es: "+suma);
    }

podemos ver que los 2 métodos se llaman igual pero poseen parámetros diferentes, así cuando sean llamados, dependiendo del parámetro enviado se accede al método.

Y No es igual? para que sobrecargar si en ultimas se crea el mismo numero de métodos?  

La pregunta anterior es muy valida y tiene mucha lógica, pero como en otros casos la respuesta también gira en torno a la facilidad, las buenas practicas y la búsqueda de aplicaciones optimizadas..... el ejemplo es muy simple y poco complejo.... pero imaginemos una aplicación donde se tenga la misma acción pero con procesos diferentes? 

Por ejemplo encender un motor..... y si tenemos diferentes tipos de encendido como el eléctrico, encendido térmico, encendido de combustión etc etc... donde los procesos son muy diferentes pero en ultimas el objetivo es el mismo, pero cada uno necesita ciertas características únicas para encender.... aquí podríamos aplicar la sobrecarga para no preocuparnos por llamar los métodos por su nombre sino tan solo llamando al mismo pero enviando los parámetros (características) propios de cada tipo de motor y listo, dependiendo de lo que mandemos java sabrá que motor queremos iniciar.....

Les comparto este video que complementa el concepto...

 

Sobreescritura de métodos (Overriding)

La Sobreescritura es la forma por la cual una clase que hereda puede re-definir los métodos de su clase Padre, de esta manera puede crear nuevos métodos con el mismo nombre de su superClase....(si no conoces la herencia deberías ver este ejemplo...)

es decir, si tengo una clase padre con el método ingresar() yo puedo crear en la clase hija un método que también se llame ingresar() pero implementándolo según lo que necesite (siguiendo obviamente unas reglas que veremos mas adelante)....  a esto se le llama sobreescritura.....

Y para que? si cuando se hereda se pueden usar los métodos de la superClase sin tener que declararlos otra vez, entonces porque sobreescribirlos?

Esta pregunta es muy común, la respuesta es que también depende de lo que queremos hacer.... si lo que queremos es extender una funcionalidad por medio de la herencia y si bien, en la clase padre existe el método ingresar(), el método y la lógica que tenga es propia de esa clase.... si yo quiero vincularle algo mas a ese método pero que sea especifico para la clase hija, no podría, ya que tendría que modificarlo en la clase padre y de esta manera ya se perdería el enfoque como tal, pues dicha funcionalidad sería común para todas las clases hijas que hereden de la superClase.... 

por la razón anterior, la sobreescritura nos permite extender la funcionalidad de un método heredado para hacerlo especifico a lo que necesitemos, pudiendo implementar la lógica que queramos en nuestras clases hijas para el mismo método......

y cuales son las reglas?

Así como en la sobrecarga nos fijamos en los parámetros, en la sobreescritura nos debemos fijar en que la estructura del método sea igual a la de su superClase, no solo el mismo nombre sino el mismo numero de argumentos y tipo de retorno (o al menos un subtipo de este), así como no tener un nivel de acceso mas restrictivo que el original (que en la clase padre sea protected y en la hija sea private por ejemplo).... tampoco se pueden sobreescribir métodos static ni final.... (ya que static representa métodos globales y final constantes...)

Algo que también debemos mencionar es que podemos identificar un método sobreescrito cuando tiene la anotación @override, esto es muy común encontrarlo cuando trabajamos con clases abstractas o interfaces, donde se obliga a implementar los métodos de estas si son heredadas o implementadas respectivamente...... sin embargo no es obligatorio ponerlo pero si  es recomendable (tal como lo menciona "David" en un comentario de esta entrada sobre el polimorfismo) pues de esta manera el compilador reconoce que se están sobreescribiendo los métodos ayudando a que si nos equivocamos al crear un método distinto, el compilador nos avisaría....... adicionalmente si tenemos la anotación inmediatamente podremos saber que se está aplicando el concepto, algo muy útil cuando trabajamos con código de otras personas...

Veamos un ejemplo donde se sobreescribe el método tocar()

Public class Instrumento{
          
  public String tipo;

  public void tocar()
   {
    System.out.println("Tocar un Instrumento");
   }
}


class Guitarra extends Instrumento {
 
 @Override         
 public void tocar() {
    System.out.println("Tocar La Guitarra");
 }

}

Como vemos la clase Guitarra hereda de la clase Instrumento, esta ultima tiene el método tocar() con una implementación diferente a la del método en la clase Guitarra (el mensaje es distinto), al tener la anotación @Override nos damos cuenta que se está sobreescribiendo dicho método y se le puede dar la lógica que queramos especifica para la clase Guitarra.... 

Ingresar a uno u otro método depende de la lógica del llamado.... también es algo muy ligado al polimorfismo donde por medio de este se puede acceder a uno u otro método..... por ejemplo si queremos acceder al método tocar() de la clase guitarra aplicando la sobreescritura y el polimorfismo tendríamos que hacer una instancia de la clase padre con un objeto de la clase hija así:
Instrumento miGuitarra=new Guitarra();
miGuitarra.tocar();

con esto accederíamos al método tocar de la clase guitarra...... (si te queda confuso este concepto te invito a ver estas entradas sobre el polimorfismo aquí y aquí.....)


Adicionalmente igual que el concepto anterior, te comparto este video como complemento...





Conclusiones!!!

Como pudimos ver los 2 conceptos son muy similares pero con enfoques totalmente diferentes, en sí el concepto como tal no es confuso y a medida que se va conociendo de a pocos su aplicación tampoco lo será.....

Y Listo!!!!! con esto vimos a nivel general lo que representan la sobrecarga y sobreescritura de métodos........ recuerden que la forma de dominarles es la práctica y ver su comportamiento con diferentes ejercicios......  un saludo y nos vemos en una próxima entrada ;)



También te podría Interesar. 


¿Hay algo que quieras anexar o comentar sobre esta entrada?  no dudes en hacerlo.....y si te gustó, te invito a compartir y Suscribirte ingresando al botón "Participar en este sitio" para darte cuenta de mas entradas como esta ;)

22 comentarios:

  1. Excelente, muy claro y buenos ejemplos. Gracias.-

    ResponderEliminar
    Respuestas
    1. Gracias a ti know, me alegra que te sirva ;)

      Eliminar
  2. Muy buena la explicación, sencilla de entender,

    ResponderEliminar
  3. Gracias Cristian! una duda, al declarar un método como abstracto la clase no debería serlo también?, un saludo!.

    ResponderEliminar
    Respuestas
    1. Hola si señor, una clase que tenga un metodo abstracto debe ser abstracta.... pero ojo, una clase abstracta no está obligada a tener metodos abstractos, sin embargo no tendria sentido que esto fuera así..... un saludo y te invito a ver la entrada sobre clases abstractas que hice, la puedes encontrar en el indice de contenido...

      Eliminar
  4. excelente buen aporte, éxitos y adelante
    !!!!1

    ResponderEliminar
  5. Buen aporte, pero el metodo abstracto no tiene body en la clase base

    ResponderEliminar
  6. Con respecto a esto:
    Public class Instrumento{

    public String tipo;

    public abstract void tocar()
    {
    System.out.println("Tocar un Instrumento");
    }
    }

    Si anteriormente dijistes q si un solo método es abstracto entonces la clase está obligada a ser abastracta y ahí no lo estás indicando.
    También dijistes que si el método es abstracto (en la teoría de clases abstractas) entonces debería de ir sin corchetes y no implementada!
    Entonces quisiera una aclaración por favor!

    ResponderEliminar
    Respuestas
    1. Hola Cesar, tienes toda la razòn, que pena ahì hay un error en el codigo, cosa que pasè por alto, el metodo no deberia tener la palabra abstract ya que lo que se intenta explicar es como la clase hija va a darle implementaciòn propia a ese........ por ende el error fue mio al escribir la palabra ahì, ya la modificaciòn se hizo y de nuevo muchas gracias por avisarme, no se como se me pudo pasar por alto ese detalle, tal vez el afan de publicar, muchas gracias otra vez.

      Eliminar
    2. Revisando tal vez fue al momento de copiar el codigo de la entrada sobre clases abstractas olvidè eliminar la palabra...

      Eliminar
  7. Muy buen aporte.
    Seria chevere que colocaras un ejemplo con el manejo de excepciones en la sobreescritura.
    Un metodo que sobreescribe no esta obligado a lanzar la excepción pero si lo hace debe ser la misma excepción o un subtipo de esta,

    ResponderEliminar
  8. si existe la forma de sobrescribir los métodos heredados porque existe las clases abtractas si es lo mismo . por favor aclarare esa duda que me revienta la cabeza .

    ResponderEliminar
  9. Muchas gracias, fue de muchísima ayuda... :)

    ResponderEliminar
  10. Muy bien explicado, muchas gracias :D
    Nose si podrias crear un tema, donde apliques carios temas en uno solo, es decir, por ejemplo, sobreescritura y polimorfismo a la vez.

    ResponderEliminar
  11. Excelente tu explicación! Te mereces un nobel. Saludos

    ResponderEliminar
  12. Sumamente claro, felicitaciones y gracias.

    ResponderEliminar
  13. Por fin pude entender,Muchas gracias por compartir.

    ResponderEliminar
  14. Gracias, me aclaró la duda que tenía respecto a este tema. Muy bien explicado.Sigue así!

    ResponderEliminar

Eres libre de realizar cualquier comentario, desde que pueda ayudar con gusto lo atenderé, y si es un critica, bienvenida sea!!!