sábado, 19 de noviembre de 2011

Overload vs. Override en Java

votar
   Overload y override, al ser dos términos que empiezan igual y al ser ambos utilizados con métodos, son muy dados a confusiones.

   He visto traducidos estos verbos al castellano como sobrecargar y sobrepasar, que utilizaré también aquí, pero a los que estéis pensando estudiar programación os recomiendo encarecidamente que, si no aprendéis a hablar inglés, al menos aprendáis a leerlo. Pensad que la mayoría de las novedades y libros de consulta sobre programación se escriben en ese idioma, y que, o bien no se traducen nunca al castellano, o cuando lo hacen, a veces ya han quedado desfasados.

   Volviendo con el tema, un método overloaded o sobrecargado no es más que la reutilización del nombre de un método. En la entrada anterior veíamos que esto también lo hacían los constructores.

   Supongamos que tienes el método suma( ) que tiene como argumentos a y b de tipo int y que utilizas ese método para sumar los argumentos

      int suma(int a, int b){
         //código que sume a+b
      }


pero después te encuentras con un par de decimales que también quieres sumar. Bastará con que hagas esto:

      double suma(double c, double d){
         //código que sume c+d
     }

   Como habéis visto, nos hemos limitado a cambiar los argumentos. El tipo de retorno es también diferente, pero eso no es necesario para sobrecargar un método. Podríamos haber escrito en los dos métodos void suma() y seguiría siendo overload.

   Lo importante es que los argumentos sean distintos, para que el compilador sepa qué método usar en cada caso. Eso sí, es mucho más lógico usar métodos con el mismo nombre que hagan lo mismo, porque sería un poco tonto llamar suma a un método que suma enteros y a otro que reste, aunque sea a decimales.

   Otros puntos a tener en cuenta son que al ser diferentes métodos pueden tener distintos modificadores de acceso (uno puede ser public y otro private, por ejemplo) y pueden lanzar diferentes excepciones. Los métodos de las subclases pueden sobrecargar a los métodos de las superclases, y aquí es donde a mayor confusión se presta con override.

   Override o sobrepasar un método es implementar eses método de una manera diferente. Por supuesto, eso es lo que hace una subclase con los métodos abstractos de su superclase, pero no es necesario que un método sea abstracto para que sea sobrepasado.

   Imaginemos un juego que tiene una clase Vehículos que a su vez tiene un método correr(). Esta clase tiene dos subclases, Coches y Motos que heredan el método correr() pero cada una lo implementa de forma distinta dependiendo de las diferentes características de las dos clases de vehículos. Eso es sobrepasar un método:

      public class TestVehículos{
         public static void main(String[] args){
            Vehículos v = new Vehículos();
            Coches c = new Coches();
            Motos m = new Motos();
            v.correr(); //ejecuta la versión correr() de Vehículos
            c.correr(); //ejecuta la versión correr() de Coches
            m.correr(); //ejecuta la versión correr() de Motos
         }
      }

   Ahora bien, sabemos que, aplicando el polimorfismo (otro día hablaremos de esto), podemos hacer algo así:

      Vehículos c = new Coches();
      Vehículos m = new Motos();
      c.correr();
      m.correr();

   ¿Qué versión de correr() se ejecutaría en estos casos? En tiempo de ejecución se aplica el tipo del Objeto (Coches y Motos) no el tipo de la variable de referencia (Vehículos), así que se ejecutará el método correr() de Coches y Motos.
 
   Pero cuidado, supongamos que la clase Coches tiene el método abrirPuertas(). Lo siguiente no sería legal:

      Vehículos c = new Coches();
      c.abrirPuertas();

   Porque el compilador no nos dejará que apliquemos un método de la clase Coches a una referencia de la clase Vehículos que no tiene ese método.

   Un método que sobrepase a otro no puede tener un modificador de acceso más restrictivo que el método sobrepasado, pero si más amplio. Por ejemplo, si correr() en Vehículos es protected, en Motos podría ser public pero no private.


   Tampoco puede lanzar excepciones nuevas o más amplias. El tipo de retorno tiene que ser el mismo o bien el de una subclase (esto último desde Java 5).

   Pero sobre todo, lo que nos ayuda a distinguir un overriding de un overloading es que si en este último la lista de argumentos tenía que ser distinta, en el primero debe ser exactamente igual.

   Espero que esta entrada os haya ayudado a aclarar conceptos, si no, ya sabéis que podéis enviar vuestras preguntas y comentarios.

4 comentarios:

  1. mas claro echale agua.Buen blog. Saludos :)

    ResponderEliminar
  2. Muchas gracias, Anónimo. Un saludo. :-)

    ResponderEliminar
  3. Muchas gracias, no puede estar mejor explicado! Excelente!

    ResponderEliminar
    Respuestas
    1. Me alegro de que te haya gustado, elkin21. ¡Muchas gracias!

      Eliminar