martes, 15 de febrero de 2011

C3, 11/02/11: Bloque I.6: Herencia

  • Introducción

  • El comportamiento de una clase se puede modificar y extender para crear nuevas clases a partir de clases ya existentes


    A la clase original se le llama clase base o padre, mientras que a la que modifica y extiende las características se le llama clase heredada o hija. A este mecanismo se le conoce como el nombre de Herencia


    En Java, existe una nueva construcción que permite especificar qué métodos debe implementar una clase. Esta nueva construcción se llama <<interface>>.


    Además introduciremos las enumeraciones, nueva construcción en Java desde la versión 5.


    Finalmente veremos como agrupar las clases que están lógicamente relacionadas a través de los paquetes.



  1. Herencia


  2. public class Punto3D extends Punto { //"Punto3D" se extiende a la clase "Punto"
    protected float z; //Los nuevos atributos de la clase "Punto3D"
    public Punto3D() {
    super();
    this.z = 0.0f;
    }

    public Punto3D(float x, float y) {
    super(x, y);
    this.z = 0.0f;
    }

    public Punto3D(Punto unPunto) {
    super(unPunto.getX(), unPunto.getY());
    this.z = 0.0f;
    }
    // Como vemos en los 3 métodos siempre utilizamos "super()" al principio.



    public Punto3D(float x, float y, float z) {
    super(x, y);
    this.z = z;
    }

    public float getZ() { //Este método es nuevo
    return z;
    }
    //El resto de métodos se han sobrescrito
    public Punto inverso() {
    return new Punto3D(-x, -y, -z);
    }

    public String toString() {
    return "("+x+", "+y+", "+z+")";
    }

    public void print() {
    System.out.println("Coordenadas del punto "+this);
    }

    A una variable referencia a una clase A, siempre que se le puede asignar un objeto de cualquier clase hija.


    Al conrario nunca es posible y generará un error.




    //En es te código no hay errores ¿Qué se imprime?
    public class herenciaPunto3D {

    public static void main(String args[]) {
    Punto3D punto3D = new Punto3D(1.0f, 2.0f, 3.0f);
    Punto punto = unPunto3D;
    punto.print();
    punto.inverso().print();
    }
    }
    //Vinculación dinámica
    Coordenadas del punto (1.0, 2.0, 3.0)
    Coordenadas del punto (-1.0, -2.0, -3.0)


    Punto punto = new Punto(1.0f, 2.0f);
    Punto3D punto3D = unPunto;
    //¿Es esto posible?


  3. Sobrescritura de variables y métodos


  4. Los atributos y métodos de la clase padre siempre serán accesibles desde la hija a través de super.



    class Entero {
    public int dato;
    public void metodo() {};
    }
    class Real extends Entero {
    public float dato; //Sobrescribe a "dato" de la clase padre "Entero".
    public void metodo() {}; //Sobrescribe a "metodo" de la clase padre "Entero".
    }


  5. Sobrescritura de constructores


  6. //Error
    public class A {
    private int a;
    public A(int a) {
    this.a = a;
    }
    }

    public class B extends A {
    private int b;
    public B(int b) {
    this.b = b;
    }
    }

    public static void main (String args[]) {
    B b = new B(2);
    }

  7. Vinculación dinámica


  8. public class A {
    public A() {};
    public void metodo() {
    System.out.println("Clase A");
    }
    }
    class B extends A {
    public B() {};
    public void metodo() {
    System.out.println("Clase B");
    }
    }


    public static void main(String args[]) {
    System.out.println("Dame un numero:");
    int entero = Teclado.leeEntero();
    A a;
    if(entero > 100) a = new A();
    else a = new B();
    a.metodo();
    }


  9. El operador instanceof

  10. Como ya sabemos, a través de la herencia podemos utilizar referencias de una clase base sobre objetos de sus clases hijas, y al llamar a los métodos se vincularán los del objeto instanciado y no los que indique la referencia.


    Con el operador instanceof, podemos saber el tipo de objeto a través de una referencia.


    Este operador será de mucha utilidad cuando veamos las Colecciones



    public static void main(String args[]) {
    A a = new A();
    B b = new B();
    System.out.println("Es a instancia de A: "+(a instanceof A));
    System.out.println("Es b instancia de B: "+(b instanceof B));
    System.out.println("Es a instancia de B: "+(a instanceof B));
    System.out.println("Es b instancia de A: "+(b instanceof A));
    a = b;
    System.out.println("-----------------");
    System.out.println("Es a instancia de A: "+(a instanceof A));
    System.out.println("Es b instancia de B: "+(b instanceof B));
    System.out.println("Es a instancia de B: "+(a instanceof B));
    System.out.println("Es b instancia de A: "+(b instanceof A));
    }

  11. Clases abstractas


  12. public abstract class ClaseAbstracta {
    int a;
    public ClaseAbstracta() {};
    public abstract void metodo(); //Un método abstracto no se define
    public void noAbstracto() { // La clase puede tener otros métodos NO abstractos
    System.out.println(“Hola”);
    }
    }
    // No se pueden crear instancias de una clase abstracta

  13. Interfaces

  14. Como Java sólo permite herencia simple no podremos modelar el comportamiento de una clase mediante varias clases abstractas.


    Para poder añadir varios "comportamientis" a nuestra clase lo haremos a través de interfaces.


    Una clase sólo tiene una línea de herencia, pero puede implementar varios interfaces.


    Los interfaces son una generalización de las clases abstractas.



    interface SeDibuja {
    static final Color rojo = Color.RED;
    //No se implementa ningún método
    void dibujate();
    void ponColor(Color unColor);
    Color dameColor();
    }
    public class PuntoVisible implements SeDibuja {
    private Color color;
    // La clase implementa el interface, debe definir el método dibujate()
    public void dibujate() {
    System.out.println("Se dibuja el punto");
    }
    }



    public class CirculoVisible implements SeDibuja {
    public void dibujate() {
    System.out.println("Se dibuja el circulo");
    }
    }
    // En el programa principal
    PuntoVisible pv = new PuntoVisible();
    CirculoVisible cv = new CirculoVisible();
    SeDibuja spd = pv; //Utilizamos una referencia al interfaz
    spd.dibujate();
    spd = cv;
    spd.dibujate();

    Los interfaces también se pueden extender



    interface Vehiculo {
    public float getVelocidadMaxima();
    }
    interface Furgoneta extends Vehiculo { // <--- public float getCilindrada(); public int getPlazas; }

    Incluso un interfaz puede extender más de un padre.




    interface Vehiculo {
    interface Vehiculo {
    public float getVelocidadMaxima();
    }
    interface Imposiciones {
    public float getImpuestoCirculacion();
    }
    interface Furgoneta extends Vehiculo, Imposiciones {
    public float getCilindrada();
    public int getPlazas;
    }


  15. Enumeraciones

  16. Desde la Versión 5, se ha introducido en el lenguaje las enumeraciones


    Las enumeraciones son tipos de datos que permiten ser enumerados (se les puede asignar valores enteros)


    La definición de una enumeración es muy sencilla:



    enum Semana {LUNES, MARTES, MIERCOLES,
    JUEVES, VIERNES, SABADO, DOMINGO};
    Semana dia = Semana.LUNES

    Características:


    Las enumeraciones extienden implicitamente a clase "java.lang.Enum", por lo que no pueden extender a ninguna otra clase


    Sí que pueden implementar interfaces.


    Pueden implementar métodos como cualquier otra clase.


    No se pueden extender.


    Poseen dos métodos interesantes:


    • values(); que devuelve un array con los elementos de la enumeración.

    • ordinal(); que nos devuelve el orden del elemento dentro del array, empezando desde 0.


    Semana dia = Semana.LUNES;
    System.out.println("Día: " + dia + " orden: " + dia.ordinal());
    // Día: LUNES orden: 0


    public enum Semana {
    LUNES("Los lunes no me puedo levantar"),
    MARTES("Ni te cases ni te embarques"),
    MIERCOLES("Sin comentarios"),
    JUEVES("Siempre en medio"),
    VIERNES("Quedamos para salir"),
    SABADO("Volvemos a quedar"),
    DOMINGO("Mañana a clase de nuevo");
    private String comentario;

    // Constructor acceso de paquete o private.
    Semana(String comentario) {
    this.comentario = comentario;
    }
    public String getComentario() {
    return comentario;
    }
    public static void main(String args[]) {
    for(Semana dia: Semana.values())
    System.out.println(dia + " : " +
    dia.getComentario());
    }
    }

  17. Paquetes

  18. Los paquetes sirven para organizar jerárquicamente las clases


    Una clase se asigna a un paquete con la siguiente línea antes de la definición de la clase:



    package directorio.del.paquete;
    public class A {//...

    El fichero con los bytecodes de la clase A debe estar en un directorio directorio/del/paquete.


    Otra clase, la importa de este modo:



    import directorio.del.paquete.*;

    Puede acceder a...?
    misma claseSISISISI
    subclase del paqueteNOSISISI
    clase del paqueteNOSINOSI
    Subclase otro paqueteNONOSISI
    clase otro paqueteNONONOSI



  • Resumen

  • La herencia es el mecanismo utilizado en POO para crear nuevas clases a partir de clases ya existentes. En Java sólo existe herencia simple.


    Las clases hijas añaden nuevos atributos y métodos. Asimismo, pueden “ocultar” o sobrescribir atributos y métodos de la clase base.


    Una referencia a una clase base puede contener un objeto de cualquier clase hija, pero nunca al revés.


    La sobrescritura se resuelve en tiempo de ejecución mediante vinculación dinámica.


    Una clase base puede forzar que sus hijas definan algún método declarándolos como abstract. No se pueden crear instancias de una clase abstracta.


    La generalización de las clases abstractas son los interface. Un interface es una plantilla, declara todos los métodos que una clase que implemente el interface debe definir. Una clase puede implementar cuantos interfaces haga falta.


    Los paquetes son de utilidad para estructurar de un modo jerárquico las clase. Los paquetes imponen restricciones de acceso a sus clases.


No hay comentarios:

Publicar un comentario