miércoles, 29 de agosto de 2012

Herencias

Muy buenas amigos, en este nuevo tema veremos la relación "padre-hijo" que pueden tener las diferentes clases y a lo que denominamos "Herencia". Esto significa que podremos crear nuevas clases partiendo de clases ya existentes que "heredarán" todos los atributos y métodos de la "clase padre" e incluso le podremos agregar nuevos atributos y métodos.



Imaginemos que tenemos una clase "Coche" que englobe todos los coches. Bien, sabemos que todos los coches tienen ruedas, motores,  volante...etc. Ahora creamos dos clases distintas que hereden de coche, una sería "volkswagen Golf" y otra "Ferrari Formula 1". Bien, no creo que deba explicar mucho la diferencias entre ambos coches, aunque ambos poseen ruedas, motores, volantes...etc,  cada uno es totalmente distinto al otro, por esta razón al heredar de "Coche", heredamos los atributos y métodos de éste, pero posteriormente deberemos declarar atributos y métodos diferentes en cada una de las otras dos clases sobre en los aspectos que no se parecen....(aerodinámica, prestaciones... ). Espero que entendáis la analogía, pero continuemos.

Pongamos algunos conceptos básicos para la utilización de la Herencia:


  • La Herencia consiste básicamente en la creación de clases basadas en clases ya existentes, con lo cual es muy útil a la hora de reutilizar código ya desarrollado, por lo que permite mayor fluidez.
  • Cuando una clase hereda de otra, la clase heredada es denominada "clase padre" y la que hereda "clase hija"
  • Para indicar a una clase que hereda de otra se utiliza la palabra "extend"
    • public class ClaseHija extend ClasePadre{}
  • Cuando una clase hereda de otra, se apropia de todos sus métodos y variables.
  • Los constructores no se heredan.
  • La clase "hija" puede redifinir nuevos métodos y variables. e incluso puede redifinirlos.
  • No es posible heredar múltiples clases, es decir, solo podemos heredar de una clase.
  • Cualquier clase que se cree tendrá una clase padre, es decir, siempre se hereda. Si no se pone explícitamente que se hereda, Java nos creará una herencia implícita, la cual hereda de Object, que es la clase raíz de toda la jerarquía de Java, por lo que, al igual que los constructores, que, si tu no lo creabas, Java te creaba uno invisible, la Herencia funciona igual, si tu no la creas, Java te crea una invisible que hereda de "Object".
Aunque a veces parece que me repito mucho, es muy importante que os quedéis con estos conceptos.

Bien, cuando heredamos de otra clase, nos debe quedar claro unas cosillas sobre los atributos y los métodos:
  • Cuando heredamos los atributos no se pueden redefinir, si en la clase "hija" definimos un atributo con el mismo nombre que en la clase "padre", el de la clase "padre" no podrá ser accedido. Con lo cual, solo podremos funcionar con el atributo de la clase "hija", pero recordar, SOLO si se llaman igual.
  • Un método heredado si puede ser redefinido, excepto si posee el modificador "final", ya que este nos indica que ese método es único, si no posee dicho modificador, es libre de ser redefinido sustituyendo al método heredado, es decir, el método a utilizar es el de la "clase hija", aunque es posible seguir invocando al método de la clase "padre" con la palabra "super" (super.metodo();)
  • Los métodos redefinidos pueden ampliar sus modificadores de acceso, pero nunca restringirlas, es decir, podemos pasar de un método con modificador de acceso "private" a "public", pero no a la inversa.
  • Los modificadores de acceso de menor visibilidad a mayor visibilidad son:
    • private---package---protected---public
  • En lo que a constructores se refiere, la llamada al constructor de la clase "padre" debe ser la primera sentencia del constructor de la clase "hija", excepto si se llama a otro constructor de la clase "hija" con la palabra this().
  • Como ya he explicado en el tema anterior, Constructores, java nos coloca un constructor implícito si no se le indica, con el mismo nombre y modificador de acceso de la clase y con una sola linea de código "super()". Esto hace que se cree una cadena de llamadas hasta que se llegue a la raiz jerárquica de java, la clase "Object", es decir, si tengo mi clase "FerrariFormula1" que hereda de "coche" y "coche" que hereda de "Object" (Como ya dije antes, si creamos una clase y no le indicamos de donde hereda, java creará una herencia implícita que herede de "Object"), así pues, la clase "FerrariFormula1" llamará al constructor de la clase "coche" con la palabra clave super(), y el constructor de la clase "coche" al ser ejecutado, lo primero que hará será realizar la llamada super() sobre su clase "padre", la cual es "Object"
Pongamos unos ejemplos:




Bien, tenemos una clase "coche" con 3 métodos. Como podéis observar estos métodos son muy relativos, ya que no todos los coches tienen 5 puertas, ni todos tienen una potencia de 105 caballos, pero bueno, engloba todos los coches y se aproxima al estándar.


En esta clase tenemos un Golf, este coche se asemeja al modelo estándar, 5 puertas, 105 caballos...por lo tanto no le vamos a modificar nada, creamos un objeto "coche" y solo tenemos que llamar a los métodos de la clase "padre". Para ello observaréis que la llamada la realizo con Coche c=new Golf(), esto es debido a que cualquier coche puede ser un golf, pero un Golf no puede ser cualquier coche y como estamos heredando esta linea de código es totalmente factible, de todas formas esto será profundizado posteriormente en el tema del polimorfismo.

Bien, una vez creado el objeto, solo tenemos que ir llamando los métodos de la clase "padre" como si estuviesen en la clase "hija".


En esta otra clase, tenemos una clase "FerrariFormula1" en la cual hemos redefinido 2 métodos de la clase "coche", ya que, como sabréis, un Formula 1 no tiene puertas, no tiene 105 caballos y demás prestaciones que le hemos incluido en otro método propio de la clase "hija". Por lo tanto redefinimos los métodos "numeroPuertas() y potenciaMotor()", en la clase "padre" numeroPuertas() tiene visibilidad por defecto (package), en esta nueva clase pasa a ser "public", algo totalmente aceptado por las reglas de java, si probáis a ponerlo "private" comprobaréis que os salta un error.

Creamos el objeto "coche" y comenzamos a llamar a los métodos, y como ya sabéis, un método redefinido en la clase "hija", pasa a ser el ejecutado, aunque esto no nos impide invocar al método de la clase "padre" utilizando la palabra reservada "super" en vez del nombre del objeto, en mi caso "c".

Hasta aquí la punta del iceberg de las herencia. Debe quedar claro este concepto para seguir progresando en la programación java. Si por alguna razón no me he podido expresar o he resultado difícil de comprender, pido disculpas, pero este tema es un poco pasteloso y desde aquí os animo a que sigáis buscando información, puesto que Internet es maravilloso y le sobra gente que puede explicar esto mucho mejor que yo.

Un saludo desde un rinconcito del mundo.


2 comentarios:

  1. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  2. Si se redefine el metodo numeroPuertas, de default a public, se afecta el método del padre también o solo el método heredado

    ResponderEliminar