Está en la página 1de 18

Universidad Tecnológica de El Salvador

Programación III MSc. René Alberto Castro Velásquez

UNIDAD II – CREACIÓN DE PAQUETES PARA TRABAJAR CON CLASES Y


OBJETOS.

2.4. HERENCIA
FUNDAMENTOS DE LA HERENCIA.
La herencia es uno de los principios
fundamentales de la programación
orientada a objetos porque permite la
creación de clasificaciones jerárquicas.
Con el uso de la herencia puede crear una
clase general que defina rasgos comunes
a un conjunto de elementos relacionados.
Luego, otras clases más específicas
pueden heredar esta clase y agregar cada
una de ellas lo que las hace únicas.
En el lenguaje Java, a una clase que se hereda se le conoce como superclase. A la clase que recibe
la herencia se le denomina subclase. Por lo tanto, una subclase es una versión especializada de
una superclase. Hereda todas las variables y los métodos definidos por la superclase (excepto los
declarados como privados) y agrega sus propios elementos únicos.
Java soporta la herencia al permitir que una clase incorpore a otra su declaración. Esto se hace
mediante el uso de la palabra clave extends. Así, la subclase se añade (extiende) a la superclase.
Al implementar Herencia se utilizan cualquiera de los nombres siguientes:

Clase A Superclase, Clase Padre, Clase Base

(Observe la correspondencia de colores en el


Generalización Especialización uso de estos nombres)

Clase B Subclase, Clase Hija, Clase Derivada

Observe que la flecha de herencia parte de la subclase y la punta de la flecha señala la superclase.
La especialización se refiere a que la clase es más detallada respecto a los elementos que contiene
y aparece en las clases que se encuentran en los niveles más bajos de un esquema de herencia,
mientras que la generalización es el concepto opuesto (contiene elementos generales y se
encuentra en los niveles más altos de un esquema de herencia.

Página 1 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

Al usar UML (Unified Modeling Language), la herencia se representa de la manera siguiente:

Notación Abreviada Notación Sencilla Notación Detallada

Termostato Termostato Termostato

TemDeseada -TemDeseada = 22
TempMuestreada +TempMuestreada: Temp

SetTemp() SetTemp(valor: Temp)

Los tipos de herencia existentes son:

Clase A Clase A Clase A Clase B

Clase B Clase B Clase C Clase C

Lineal Jerárquica Múltiple

Página 2 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

Java permite implementar herencia Lineal y Jerárquica pero no herencia Múltiple, aunque permite
implementar múltiples interfaces.
Ejemplo:
class FormaDosD {
double ancho;
double alto;

void mostrarDim() {
System.out.println("El ancho es " + ancho + "\ny el alto es " + alto);
}
}

Subclase que recibe herencia:


class Triang extends FormaDosD {
String estilo;

double area() {
return ancho * alto / 2;
}

void mostrarEstilo() {
System.out.println("El triángulo es " + estilo);
}
}

Programa para usar la clase anterior.


class Formas {
public static void main (String [] args) {
Triang t1 = new Triang();
Triang t2 = new Triang();

t1.ancho = 4.0;
t1.alto = 4.0;
t1.estilo = "Isósceles";

t2.ancho = 8.0;
t2.alto = 12.0;
t2.estilo = "Recto";

System.out.println("Info para t1");


t1.mostrarEstilo();
t1.mostrarDim();
System.out.println("El área es " + t1.area());

System.out.println();
System.out.println("Info para t2");
t2.mostrarEstilo();
t2.mostrarDim();
System.out.println("El área es " + t2.area());
}
}

Página 3 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

ACCESO A MIEMBROS Y HERENCIA


A menudo las variables de instancia de una clase se declaran como private para evitar su uso no
autorizado o su modificación. La herencia de clase no sobrescribe la restricción de acceso de
private. Por tanto, aunque una subclase incluye a todos los miembros de su superclase, esta no
puede acceder a los miembros de la superclase que se han declarado como private. Por ejemplo,
al reescribir el código anterior se tiene:
/*
ATENCIÓN: Se usará numeración después del nombre
de cada clase para diferenciar las versiones de código
que se vayan presentando.
El código es el mismo pero las diferencias respecto a la
versión anterior serán marcadas con color amarillo.
*/

class FormaDosD2 {
private double ancho;
private double alto;

double getAncho() {
return ancho;
}

double getAlto() {
return alto;
}

void setAncho(double ancho) {


if (ancho <= 0)
this.ancho = 0.0;
else
this.ancho = ancho;
}

void setAlto(double alto) {


if (alto <= 0)
this.alto = 0.0;
else
this.alto = alto;
}

void mostrarDim() {
System.out.println("El ancho es " + ancho + "\ny el alto es " + alto);
}
}

Subclase que recibe herencia:


class Triang2 extends FormaDosD2 {

String estilo;

double area() {
return getAncho() * getAlto() / 2;
}

Página 4 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

void mostrarEstilo() {
System.out.println("El triángulo es " + estilo);
}
}

Programa para usar la clase anterior.


class Formas2 {
public static void main (String [] args) {
Triang2 t1 = new Triang2();
Triang2 t2 = new Triang2();

t1.setAncho(4.0);
t1.setAlto(4.0);
t1.estilo = "Isósceles";

t2.setAncho(8.0);
t2.setAlto(12.0);
t2.estilo = "Recto";

System.out.println("Info para t1");


t1.mostrarEstilo();
t1.mostrarDim();
System.out.println("El área es " + t1.area());

System.out.println("\nInfo para t2");


t2.mostrarEstilo();
t2.mostrarDim();
System.out.println("El área es " + t2.area());
}
}

CONSTRUCTORES Y HERENCIA
En una jerarquía es posible tener constructores tanto para la superclase como para la subclase.
Esto plantea una importante pregunta: ¿cuál constructor es responsable de construir un objeto de
la subclase – el de la superclase, el de la subclase o ambos? La respuesta es la siguiente: el
constructor de la superclase construye la porción de la superclase del objeto y el constructor de la
subclase construye la porción de la subclase del objeto. Esto tiene sentido porque la superclase no
tiene conocimiento o acceso a ninguno de los miembros de la subclase. Por tanto, su construcción
debe ser separada.
Cuando sólo la subclase define un constructor, el proceso es muy sencillo: simplemente construya
el objeto de la subclase. La porción de la superclase es construida automáticamente usando su
constructor por defecto.
Sin embargo, cuando la subclase y la superclase definen constructores, el proceso se vuelve un
poco más complicado porque ambos constructores deben ejecutarse. En este caso, debe usar la
palabra reservada super para llamar al constructor de la superclase.

Página 5 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

NOTA:
La palabra reservada super siempre hace referencia a la superclase inmediata superior de la clase
que llama y siempre debe ser la primera instrucción ejecutada dentro del constructor de la
subclase.
Ejemplo:
class FormaDosD3 {
private double ancho;
private double alto;

double getAncho() {
return ancho;
}

double getAlto() {
return alto;
}

void setAncho(double ancho) {


if (ancho <= 0)
this.ancho = 0.0;
else
this.ancho = ancho;
}

void setAlto(double alto) {


if (alto <= 0)
this.alto = 0.0;
else
this.alto = alto;
}

void mostrarDim() {
System.out.println("El ancho es " + ancho + "\ny el alto es " + alto);
}
}

Subclase que recibe herencia:


class Triang3 extends FormaDosD3 {
private String estilo;

double area() {
return getAncho() * getAlto() / 2;
}

void mostrarEstilo() {
System.out.println("El triángulo es " + estilo);
}

Triang3(String estilo, double ancho, double alto) {


this.estilo = estilo;
setAncho(ancho);

Página 6 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

setAlto(alto);
}
}

Programa para usar la clase anterior.


class Formas3 {
public static void main (String [] args) {
Triang3 t1 = new Triang3("Isósceles", 4.0, 4.0);
Triang3 t2 = new Triang3("Recto", 8.0, 12.0);

System.out.println("Info para t1");


t1.mostrarEstilo();
t1.mostrarDim();
System.out.println("El área es " + t1.area());

System.out.println("\nInfo para t2");


t2.mostrarEstilo();
t2.mostrarDim();
System.out.println("El área es " + t2.area());
}
}

USO DE SUPER PARA LLAMAR AL CONSTRUCTOR DE UNA SUPERCLASE.


Una subclase puede llamar a un constructor definido por su superclase, tal como se muestra en el
ejemplo siguiente:
class FormaDosD4 {
private double ancho;
private double alto;

double getAncho() {
return ancho;
}

double getAlto() {
return alto;
}

void setAncho(double ancho) {


if (ancho <= 0)
this.ancho = 0.0;
else
this.ancho = ancho;
}

void setAlto(double alto) {


if (alto <= 0)
this.alto = 0.0;
else
this.alto = alto;
}

Página 7 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

void mostrarDim() {
System.out.println("El ancho es " + ancho + "\ny el alto es " + alto);
}

FormaDosD4(double ancho, double alto) {


this.ancho = ancho;
this.alto = alto;
}
}

Subclase que recibe herencia:


class Triang4 extends FormaDosD4 {
private String estilo;

double area() {
return getAncho() * getAlto() / 2;
}

void mostrarEstilo() {
System.out.println("El triángulo es " + estilo);
}

Triang4(String estilo, double ancho, double alto) {


super(ancho, alto);
this.estilo = estilo;
}
}

Programa para usar la clase anterior.


class Formas4 {
public static void main (String [] args) {
Triang4 t1 = new Triang4("Isósceles", 4.0, 4.0);
Triang4 t2 = new Triang4("Recto", 8.0, 12.0);

System.out.println("Info para t1");


t1.mostrarEstilo();
t1.mostrarDim();
System.out.println("El área es " + t1.area());

System.out.println("\nInfo para t2");


t2.mostrarEstilo();
t2.mostrarDim();
System.out.println("El área es " + t2.area());
}
}

SOBRECARGA DE CONSTRUCTORES.
Puede agregar más de un constructor a la clase, ya que Java ejecutará el constructor que coincida
con los argumentos, tal como se muestra a continuación.
class FormaDosD5 {
private double ancho;
private double alto;

Página 8 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

double getAncho() {
return ancho;
}

double getAlto() {
return alto;
}

void setAncho(double ancho) {


if (ancho <= 0)
this.ancho = 0.0;
else
this.ancho = ancho;
}

void setAlto(double alto) {


if (alto <= 0)
this.alto = 0.0;
else
this.alto = alto;
}

void mostrarDim() {
System.out.println("El ancho es " + ancho + "\ny el alto es " + alto);
}

FormaDosD5() {
ancho = alto = 0.0;
}

FormaDosD5(double x) {
ancho = alto = x;
}

FormaDosD5(double ancho, double alto) {


this.ancho = ancho;
this.alto = alto;
}
}

Subclase que recibe herencia.


class Triang5 extends FormaDosD5 {
private String estilo;

double area() {
return getAncho() * getAlto() / 2;
}

void mostrarEstilo() {
System.out.println("El triángulo es " + estilo);
}

Página 9 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

Triang5() {
super();
estilo = "nulo";
}

Triang5(double x) {
super(x);
estilo = "Isósceles";
}

Triang5(String estilo, double ancho, double alto) {


super(ancho, alto);
this.estilo = estilo;
}
}

Programa para usar la clase anterior.


class Formas5 {
public static void main (String [] args) {
Triang5 t1 = new Triang5();
Triang5 t2 = new Triang5("Recto", 8.0, 12.0);
Triang5 t3 = new Triang5(4.0);

System.out.println("Info para t1");


t1.mostrarEstilo();
t1.mostrarDim();
System.out.println("El área es " + t1.area());

System.out.println("\nInfo para t2");


t2.mostrarEstilo();
t2.mostrarDim();
System.out.println("El área es " + t2.area());

System.out.println("\nInfo para t3");


t3.mostrarEstilo();
t3.mostrarDim();
System.out.println("El área es " + t3.area());

t1 = t2;
// El primer objeto es sujeto a eliminación después de esta línea
// Ahora el segundo objeto tiene dos referencias: t1 y t2

System.out.println("\nNueva información de t1");


t1.mostrarEstilo();
t1.mostrarDim();
System.out.println("El área es " + t1.area());

t1.setAncho(100);

System.out.println("\Nueva información en t2");


t2.mostrarEstilo();
t2.mostrarDim();
System.out.println("El área es " + t2.area());

Página 10 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

/*
Como es de esperar, la información mostrada a partir de la referencia t2
evidencia el cambio hecho desde la referencia t1. Esto tiene sentido
porque ambas referencias apuntan al mismo objeto.

Como ejercicio, haga alguna modificación desde la referencia t2 y


a continuación muestre el contenido del objeto desde la referencia t1.
*/
}
}

USO DE SUPER PARA ACCEDER A MIEMBROS DE UNA SUPERCLASE


Además del uso de la palabra reservada super para acceder al constructor de la superclase, hay
una segunda forma de uso que actúa en cierto modo como this, excepto que siempre alude a la
superclase de la subclase en la cual es utilizada. Este uso tiene la siguiente forma general:
super.miembro;

Aquí, miembro puede ser un método o una variable de instancia.


Esta forma de super es más aplicable a situaciones en las que los nombres de miembros de una
subclase ocultan a los miembros con los mismos nombres en la superclase.
Ejemplo:
class Padre {
int var1;
}

Subclase que recibe herencia.


class Hija extends Padre {
int var1; // Esta propiedad oculta a la propiedad var1 de la clase Padre
// debido a que tienen el mismo nombre.

Hija(int a, int b) {
super.var1 = a; // propiedad var1 de la clase Padre
var1 = b; // propiedad var1 de la clase Hija
}

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

Programa para usar la clase anterior.


class UsaSuper {
public static void main (String [] args) {
Hija ob1 = new Hija (1, 2);

ob1.mostrar();
}
}

Página 11 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

CREACIÓN DE UNA JERARQUÍA DE VARIOS NIVELES


Se pueden construir jerarquías que contengan todas las capas de herencia que desee. Es
perfectamente aceptable usar una subclase como superclase de otra. Por ejemplo:
class FormaDosD6 {
private double ancho;
private double alto;

double getAncho() {
return ancho;
}

double getAlto() {
return alto;
}

void setAncho(double ancho) {


if (ancho <= 0)
this.ancho = 0.0;
else
this.ancho = ancho;
}

void setAlto(double alto) {


if (alto <= 0)
this.alto = 0.0;
else
this.alto = alto;
}

void mostrarDim() {
System.out.println("El ancho es " + ancho + "\ny el alto es " + alto);
}

FormaDosD6() {
ancho = alto = 0.0;
}

FormaDosD6(double x) {
ancho = alto = x;
}

FormaDosD6(double ancho, double alto) {


this.ancho = ancho;
this.alto = alto;
}
}

Subclase que recibe herencia de FormaDosD6:


class Triang6 extends FormaDosD6 {
private String estilo;

Página 12 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

double area() {
return getAncho() * getAlto() / 2;
}

void mostrarEstilo() {
System.out.println("El triángulo es " + estilo);
}

Triang6() {
super();
estilo = "nulo";
}

Triang6(double x) {
super(x);
estilo = "Isósceles";
}

Triang6(String estilo, double ancho, double alto) {


super(ancho, alto);
this.estilo = estilo;
}
}

Subclase que recibe herencia de Triang6.


class ColorTriang extends Triang6 {
private String color;

ColorTriang(String color, String estilo, double ancho, double alto) {


super(estilo, ancho, alto);
this.color = color;
}

void mostrarColor() {
System.out.println("El color es: " + color);
}
}

Programa para usar la clase anterior.


class Formas6 {
public static void main (String [] args) {
ColorTriang t1 = new ColorTriang ("Azul", "Recto", 8.0, 12.0);
ColorTriang t2 = new ColorTriang ("Rojo", "Isósceles", 2.0, 2.0);

System.out.println("Info para t1");


t1.mostrarEstilo();
t1.mostrarDim();
t1.mostrarColor();
System.out.println("El área es " + t1.area());

System.out.println("\nInfo para t2");


t2.mostrarEstilo();
t2.mostrarDim();

Página 13 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

t2.mostrarColor();
System.out.println("El área es " + t2.area());
}
}

SOBRESCRITURA DE MÉTODOS
Aparte de las conversiones estándar y las promociones automáticas que se aplican a los tipos
primitivos, la compatibilidad de tipo está estrictamente impuesta. Por lo general, una variable de
referencia para un tipo de clase no tiene la capacidad de hacer referencia a un objeto de otro tipo
de clase.
Por ejemplo:
class PadreV1 {
int var1, var2;

PadreV1(int a, int b) {
var1 = a;
var2 = b;
}

void mostrar() {
System.out.println("var1 = " + var1 + "\ny var2 = " + var2);
}
}

Código de la clase hija.


class HijaV1 extends PadreV1 {
int var3;

HijaV1(int a, int b, int c) {


super(a, b);
var3 = c;
}

void mostrar() {
System.out.println("var3 = " + var3);
}
}

Código del programa principal.


class Sobresc {
public static void main (String [] args) {
HijaV1 ob1 = new HijaV1(1, 2, 3);

ob1.mostrar(); // Esto llama a mostrar() en HijaV1


}
}

Si se quiere acceder a la versión de la superclase de un método sobrescrito, puede hacerse


mediante el uso de super.

Página 14 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

Por ejemplo:
class HijaV1 extends PadreV1 {
int var3;

HijaV1(int a, int b, int c) {


super(a, b);
var3 = c;
}

void mostrar() {
super.mostrar(); // Esta línea llama a mostrar() en Padre1
System.out.println("var3 = " + var3);
}
}

La sobrescritura de métodos sólo ocurre cuando los tipos de regreso y las firmas de los dos
métodos son idénticos. Si no lo son, entonces los dos métodos simplemente están sobrecargados.
Por ejemplo:
class PadreV2 {
int var1, var2;

PadreV2(int a, int b) {
var1 = a;
var2 = b;
}

void mostrar() {
System.out.println("var1 = " + var1 + "\ny var2 = " + var2);
}
}

Código de la clase hija:


class HijaV2 extends PadreV2 {
int var3;

HijaV2(int a, int b, int c) {


super(a, b);
var3 = c;
}

// Sobrecarga del método mostrar()


void mostrar(String m) {
System.out.println(m + k);
}
}

Página 15 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

Código de la clase principal.


class Sobrecarga {
public static void main (String [] args) {
HijaV2 ob1 = new HijaV2(1, 2, 3);

ob1.mostrar("Esto es var3: "); // Llama al método mostrar() en HijaV2


ob1.mostrar(); // Llama al método mostrar() en PadreV2
}
}

REFERENCIA A SUPERCLASES Y OBJETOS DE SUBCLASES


Aparte de las conversiones estándar y las promociones automáticas que se aplican a los tipos
primitivos, la compatibilidad de tipo está estrictamente impuesta. Por lo general una variable de
referencia para un tipo de clase no tiene la capacidad de hacer referencia a un objeto de otro tipo
de clase.
Un lugar importante en el que las referencias a subclases son asignadas a variables de superclases
es cuando los constructores en una jerarquía de clases son llamados. Es común que una clase
defina a un constructor que tome un objeto de la clase como parámetro. Ello permite que la clase
construya una copia del objeto.
Por ejemplo:
class FormaDosD7 {
private double ancho;
private double alto;

double getAncho() {
return ancho;
}

double getAlto() {
return alto;
}

void setAncho(double ancho) {


if (ancho <= 0)
this.ancho = 0.0;
else
this.ancho = ancho;
}

void setAlto(double alto) {


if (alto <= 0)
this.alto = 0.0;
else
this.alto = alto;
}

Página 16 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

void mostrarDim() {
System.out.println("El ancho es " + ancho + "\ny el alto es " + alto);
}

FormaDosD7() {
ancho = alto = 0.0;
}

FormaDosD7(double x) {
ancho = alto = x;
}

FormaDosD7(double ancho, double alto) {


this.ancho = ancho;
this.alto = alto;
}
También podría escribir:
FormaDosD7(FormaDosD7 ob) {
this.ancho = ob.ancho; this.ancho = ob.getAncho();
this.alto = ob.alto; this.alto = ob.getAlto();
}
}

Subclase que recibe herencia de FormaDosD7


class Triang7 extends FormaDosD7 {
private String estilo;

double area() {
return getAncho() * getAlto() / 2;
}

void mostrarEstilo() {
System.out.println("El triángulo es " + estilo);
}

Triang7() {
super();
estilo = "nulo";
}

Triang7(double x) {
super(x);
estilo = "Isósceles";
}

Triang7(String estilo, double ancho, double alto) {


super(ancho, alto);
this.estilo = estilo;
}

Página 17 de 18
Universidad Tecnológica de El Salvador
Programación III MSc. René Alberto Castro Velásquez

Triang7(Triang7 ob) {
super(ob);
this.estilo = ob.estilo;
}
}

Programa para usar la clase anterior.


class Formas7 {
public static void main (String [] args) {
Triang7 t1 = new Triang7("Recto", 8.0, 12.0);
Triang7 t2 = new Triang7(t1);

System.out.println("Info para t1");


t1.mostrarEstilo();
t1.mostrarDim();
System.out.println("El área es " + t1.area());

System.out.println("\nInfo para t2");


t2.mostrarEstilo();
t2.mostrarDim();
System.out.println("El área es " + t2.area());

t1.setAncho(100);

System.out.println("\nMostrar nuevamente la información en t2");


t2.mostrarEstilo();
t2.mostrarDim();
System.out.println("El área es " + t2.area());

/*
Como es de esperar, la información mostrada a partir de la referencia t2
no presenta ningún cambio porque apunta hacia un objeto diferente
al que apunta la referencia t1,a pesar de haber sido construido
usando la información del primer objeto.

Como ejercicio, haga alguna modificación desde la referencia t2


y a continuación muestre el contenido de la referencia t1
para verificar que no hay cambios.
*/
}
}

Página 18 de 18

También podría gustarte