next up previous contents
Siguiente: 8 Paquetes e Interfaces Subir: Introducción a Java y Anterior: 6 Métodos y clases   Índice General

Subsecciones

7 Herencia

La herencia es uno de los pilares de la PDO ya que permite la creación de clasificaciones jerárquicas.

1 Fundamentos

P17/DemoBoxWeight.java

// Este programa utiliza la herencia para extender la clase Box.
class Box {
  double width;
  double height;
  double depth;
  Box(Box ob) {
    width = ob.width;
    height = ob.height;
    depth = ob.depth;
  }
  Box(double w, double h, double d) {
    width = w;
    height = h;
    depth = d;
  }

  Box() {
    width = -1;
    height = -1;
    depth = -1;
  }
  Box(double len) {
    width = height = depth = len;
  }
  double volume() {
    return width * height * depth;
  }
}
class BoxWeight extends Box {
  double weight; // peso de la caja
  BoxWeight(double w, double h, double d, double m) {
    width = w;
    height = h;
    depth = d;
    weight = m;
  }
}
class DemoBoxWeight {
  public static void main(String args[]) {
    BoxWeight mybox1 = new BoxWeight(10, 20, 15, 34.3);
    BoxWeight mybox2 = new BoxWeight(2, 3, 4, 0.076);
    double vol;
    vol = mybox1.volume();
    System.out.println("Volumen de mybox1 es " + vol);
    System.out.println("Peso de mybox1 es " + mybox1.weight);
    System.out.println();
    vol = mybox2.volume();
    System.out.println("Volumen de mybox2 es " + vol);
    System.out.println("Peso de mybox2 es " + mybox2.weight);
  }
}

1 Una variable de la superclase puede referenciar a un objeto de la subclase

El tipo de la variable referencia, (y no el del objeto al que apunta) es el que determina los miembros que son accesibles.

P18/RefDemo.java

class RefDemo {
  public static void main(String args[]) {
    BoxWeight weightbox = new BoxWeight(3, 5, 7, 8.37);
    Box plainbox = new Box();
    double vol;

    vol = weightbox.volume();
    System.out.println("El volumen de weightbox ex " + vol);
    System.out.println("El peso de weightbox es " +
                       weightbox.weight);
    System.out.println();

    // asigna una referencia de BoxWeight a una referencia de Box
    plainbox = weightbox;
    vol = plainbox.volume(); // OK,  volume() definido en Box
    System.out.println("Volumen de plainbox es " + vol);

    /* La siguiente sentencia no es válida porque plainbox
       no define un miembro llamado weight. */
//  System.out.println("El peso de plainbox es " +
                      //  plainbox.weight);
  }
}

2 Uso de super

La palabra reservada super permite a una subclase referenciar a su superclase inmediata. Es utilizada en las siguientes situaciones:

  1. Para llamar al constructor de la superclase desde el constructor de la subclase.
    En este caso super() debe ser la primera sentencia ejecutada dentro del constructor.
  2. Para acceder a un miembro de la superclase que ha sido ocultado por un miembro de la subclase.

Ejemplo de uso en caso 1

class BoxWeight extends Box {
  double weight;

  BoxWeight(double w, double h, double d, double m) {
    super(w, h, d); // llama al constructor de la superclase
    weight = m;
  }
  BoxWeight(BoxWeight ob) {
    super(ob);
    weight = ob.weight;
  }
}

Ejemplo de uso en caso 2: P19/UseSuper.java

// Utilización de super para evitar la ocultación de nombres
class A {
  int i;
}

class B extends A {
  int i; // esta i oculta la i de A

  B(int a, int b) {
    super.i = a; // i in A
    i = b; // i in B
  }

  void show() {
    System.out.println("i en la superclase: " + super.i);
    System.out.println("i en la subclase: " + i);
  }
}

class UseSuper {
  public static void main(String args[]) {
    B subOb = new B(1, 2);

    subOb.show();
  }
}

3 Orden de ejecución de constructores

Los constructores de una jerarquía de clases se ejecutan en el orden de derivación.

Ejemplo: P20/CallingCons.java

// Muestra cuando se ejecutan los constructores.
class A {
  A() {
    System.out.println("En el constructor de A.");
  }
}
class B extends A {
  B() {
    System.out.println("En el constructor de B.");
  }
}
class C extends B {
  C() {
    System.out.println("En el constructor de C.");
  }
}
class CallingCons {
  public static void main(String args[]) {
    C c = new C();
  }
}

La salida del programa es:

En el constructor de A.
En el constructor de B.
En el constructor de C.

4 Sobreescritura de métodos (Overriding)

Consiste en construir un método en una subclase con el mismo nombre, parámetros y tipo que otro método de una de sus superclases (inmediata o no).

Ejemplo: P21/Override.java

class A {
  int i, j;
  A(int a, int b) {
    i = a;
    j = b;
  }
  void show() {
    System.out.println("i y j: " + i + " " + j);
  }
}
class B extends A {
  int k;
  B(int a, int b, int c) {
    super(a, b);
    k = c;
  }
  // muestra k -- sobreescribe el metodo show() de A
  void show() {
    System.out.println("k: " + k);
  }
}
class Override {
  public static void main(String args[]) {
    B subOb = new B(1, 2, 3);
    subOb.show(); // llama al metodo show() de B
  }
}

5 Selección de método dinámica

Es el mecanismo mediante el cual una llamada a una función sobreescrita se resuelve en tiempo de ejecución en lugar de en tiempo de compilación: polimorfismo en tiempo de ejecución
Cuando un método sobreescrito se llama a través de una referencia de la superclase, Java determina la versión del método que debe ejecutar en función del objeto que está siendo referenciado.

Ejemplo: P22/Dispatch.java

class A {
   void callme() {
     System.out.println("Llama al metodo callme dentro de A");
  }
}

class B extends A {
  void callme() {
    System.out.println("Llama al metodo callme dentro de B");
  }
}

class C extends A {
  void callme() {
    System.out.println("Llama al metodo callme dentro de C");
  }
}

class Dispatch {
  public static void main(String args[]) {
    A a = new A(); // objeto de tipo A
    B b = new B(); // objeto de tipo B
    C c = new C(); // objeto de tipo C
    A r; // obtiene una referencia del tipo A
    r = a; // r hace referencia a un objeto A
    r.callme(); // llama al metodo callme() de A
    r = b; // r hace referencia a un objeto B
    r.callme(); // llama al metodo callme() de B
    r = c; // r hace referencia a un objeto C
    r.callme(); // llama al metodo callme() de C
  }
}

1 Aplicación de sobreescritura de métodos

Ejemplo: P23/FindAreas.java

class Figure {
  double dim1;
  double dim2;
  Figure(double a, double b) {
    dim1 = a;
    dim2 = b;
  }
  double area() {
    System.out.println("Area para Figure es indefinida.");
    return 0;
  }
}
class Rectangle extends Figure {
  Rectangle(double a, double b) {
    super(a, b);
  }
  double area() {
    System.out.println("Dentro de Area para Rectangle.");
    return dim1 * dim2;
  }
}
class Triangle extends Figure {
  Triangle(double a, double b) {
    super(a, b);
  }
  double area() {
    System.out.println("Dentro de Area para Triangle.");
    return dim1 * dim2 / 2;
  }
}
class FindAreas {
  public static void main(String args[]) {
    Figure f = new Figure(10, 10);
    Rectangle r = new Rectangle(9, 5);
    Triangle t = new Triangle(10, 8);
    Figure figref;
    figref = r;
    System.out.println("Area es " + figref.area());
    figref = t;
    System.out.println("Area es " + figref.area());
    figref = f;
    System.out.println("Area es " + figref.area());
  }
}

6 Clases abstractas

Permiten definir una superclase que define la estructura de las subclases, sin proporcionar una implementación completa de sus métodos.

Ejemplo: P24/AbstractAreas.java

abstract class Figure {
  double dim1, dim2;
  Figure(double a, double b) {
    dim1 = a;
    dim2 = b;
  }
  abstract double area();
}
class Rectangle extends Figure {
  Rectangle(double a, double b) {
    super(a, b);
  }
  double area() {
    System.out.println("Dentro del metodo area para un Rectangle.");
    return dim1 * dim2;
  }
}

class Triangle extends Figure {
  Triangle(double a, double b) {
    super(a, b);
  }
  double area() {
    System.out.println("Dentro del metodo area para un Triangle.");
    return dim1 * dim2 / 2;
  }
}
class AbstractAreas {
  public static void main(String args[]) {
  // Figure f = new Figure(10, 10); // Esto no es correcto
    Rectangle r = new Rectangle(9, 5);
    Triangle t = new Triangle(10, 8);
    Figure figref; // esto es CORRECTO, no se crea ningún objeto
    figref = r;
    System.out.println("Area es " + figref.area());
    figref = t;
    System.out.println("Area es " + figref.area());
  }
}

7 Utilización de final con la herencia

La palabra reservada final tiene tres usos:
  1. Para creación de constantes con nombre.
  2. Para evitar sobreescritura de métodos
    Los métodos declarados como final no pueden ser sobreescritos
  3. Para evitar la herencia
    Se usa final en la declaración de la clase para evitar que la clase sea heredada: O sea, todos sus métodos serán final implícitamente.

Ejemplo de uso en caso 2

class A {
  final void meth() {
    System.out.println("Este es un metodo final.");
  }
}

class B extends A {
  void meth() { // ERROR! No se puede sobreescribir.
    System.out.println("No es correcto!");
  }
}

Ejemplo de uso en caso 3

final class A {
  // ...
}

// La clase siguiente no es válida.
class B extends A { // ERROR! No se puede crear una subclase de A
  // ...
}

next up previous contents
Siguiente: 8 Paquetes e Interfaces Subir: Introducción a Java y Anterior: 6 Métodos y clases   Índice General
Andres Cano Utrera 2006-09-23