You are on page 1of 15

Herencia Java

20/11/2013by Disco Duro de Roer

Hola a todos, hoy os explicare en que consiste la herencia en Java, es algo que
debemos tener claro, para conseguir un mximo provecho a las clases y
objetos.
La herencia en Java consiste en la creacin de clases a partir de otras ya
existentes. Tenemos lo que llamamos una clase padre (superclase) y clases
hijas(clases derivadas), que heredan los mtodos y atributos de su clase
padre.
Vamos a ver un ejemplo, tenemos una clase empleado que sera
una superclase y las clases hijas sern el tipo de empleados que puede
haber como comerciales o repartidores.
La idea es que los empleados sean del tipo que sean tienen atributos o
mtodos comunes y para optimizar las clases creamos una clase padre que
contenga todo lo comn a todas las hijas y en las hijas, ademas de los atributos
del padre pueden tener sus propios atributos o mtodos.
Una buena forma de ver la herencia, es con la frase es un. Por ejemplo, un
Comercial es un Empleado o un Repartidor es un Empleado.
Ahora lo vemos de forma practica:
Clase padre Empleado
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

/**
* Clase Empleado
*
* Contiene informacion de cada empleado
*
* @author Fernando
* @version 1.0
*/
public class Empleado {
//Atributos
/**
* Nombre del empleado
*/
protected String nombre;
/**
* Apellido del empleado

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

*/
protected String apellido;
/**
* Edad del empleado
*/
protected int edad;
/**
* Salario del empleado
*/
protected double salario;
//Metodos publicos
/**
* Devuelve el nombre del empleado
* @return nombre del empleado
*/
public String getNombre() {
return nombre;
}
/**
* Modifica el nombre de un empleado
* @param nombre
*/
public void setNombre(String nombre) {
this.nombre = nombre;
}
/**
* Devuelve la edad de un empleado
* @return edad del empleado
*/
public int getEdad() {
return edad;
}
/**
* Modifica la edad de un empleado
* @param edad
*/
public void setEdad(int edad) {
this.edad = edad;
}
/**
* Devuelve el salario de un empleado
* @return salario del empleado
*/
public double getSalario() {
return salario;
}

/**
* Suma un plus al salario del empleado si el empleado tiene mas de 40 aos
* @param sueldoPlus
* @return <ul>
*
<li>true: se suma el plus al sueldo</li>
*
<li>false: no se suma el plus al sueldo</li>
*
</ul>

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

*/
public boolean plus (double sueldoPlus){
boolean aumento=false;
if (edad>40 && compruebaNombre()){
salario+=sueldoPlus;
aumento=true;
}
return aumento;
}
//Metodos privados
/**
* Comprueba que el nombre no este vacio
* @return <ul>
*
<li>true: el nombre es una cadena vacia</li>
*
<li>false: el nombre no es una cadena vacia</li>
*
</ul>
*/
private boolean compruebaNombre(){
if(nombre.equals("")){
return false;
}
return true;
}
//Constructores
/**
* Constructor por defecto
*/
public Empleado(){
this ("", "", 0, 0);
}
/**
* Constructor con 4 parametros
* @param nombre nombre del empleado
* @param apellido nombre del empleado
* @param edad edad del empleado
* @param salario salario del empleado
*/
public Empleado(String nombre, String apellido, int edad, double salario){
this.nombre=nombre;
this.apellido=apellido;
this.edad=edad;
this.salario=salario;
}
}

116
117
118
119
120
121
122
123
124
125
Clase hija Comercial
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

/**
* Clase Comercial
*
* Contiene informacin de un comercial, un tipo de empleado
*
* @author Fernando
* @version 1.0
*/
public class Comercial extends Empleado{
//Atributos, aunque no indiquemos nada es como si tuviera los atributos del
/**
* Comision por venta del comercial
*/
private double comision;
/**
* Constructor por defecto
*/
public Comercial(){
this.comision=0;
}

/**
* Constructor con 5 parametros
* @param nombre nombre del comercial
* @param apellido apellido del comercial
* @param edad edad del comercial
* @param salario salario del comercial
* @param comision comision del comercial
*/
public Comercial(String nombre, String apellido, int edad, double salario, do
super(nombre, apellido, edad, salario);
this.comision=comision;
}

Clase hija Repartidor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

/**
* Clase Repartidor
*
* Contiene informacin de un repartidor, un tipo de empleado
*
* @author Fernando
* @version 1.0
*/
public class Repartidor extends Empleado{
//Atributos, aunque no indiquemos nada es como si tuviera los atributos del
/**
* Zona del repartidor
*/
private String zona;
/**
* Constructor por defecto
*/
public Repartidor(){
this.zona="";
}

/**
* Constructor con 5 parametros
* @param nombre nombre del repartidor
* @param apellido apellido del repartidor
* @param edad edad del repartidor
* @param salario salario del repartidor
* @param zona zona del repartidor
*/
public Repartidor(String nombre, String apellido, int edad, double salario, S
super(nombre, apellido, edad, salario);
this.zona=zona;
}

Vayamos por partes, en la clase padre, vemos que los atributos en lugar
de private usamos protected, haciendo que los atributos se hereden a las
clases hijas.
En las clases hijas, vemos que despus del nombre de la clase
escribimos extends

nombre_clase_padre,

tambin

tienen

sus

propios

atributos.
Debemos tener en cuenta varios aspectos, los constructores de la clase hija
siempre llaman al constructor por defecto (el que no tiene parmetros) de la

clase padre, tambin podemos indicar que constructor debe de llamar, se indica
con super(parametros);, despus podemos hacer lo queramos. Si no
indicamos nada es como si escribiramos super();.
Tambin debemos tener en cuenta que los mtodos no es necesario que los
heredemos, ya que con public las clases hijas podrn acceder a los mtodos
de la clase padre.
Tambin

podemos

llamar

mtodos

de

la

clase

padre

con super.nombre_mtodo(parmetros) podemos usarlo para que llame a un


mtodo que necesitamos para un mtodo de la clase hija. Nos ahorrara trabajo,
es mejor que copiar y pegar cdigo.
Ahora vamos a ver un ejemplo de crear objetos de estas clases heredadas:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

public class EmpleadoApp {


public static void main(String[] args) {

//Creamos objetos de las clases hijas


Comercial comercial1=new Comercial("Antonio", "Lopez", 24, 600, 50);
Repartidor repartidor1=new Repartidor("Fernando", "Urea", 43, 400, "Est
//Invocamos los metodos de la clase padre
comercial1.plus(300);
repartidor1.plus(300);

//Mostramos los atributos, usando los metodos get de la clase padre


System.out.println("El salario actual del comercial es "+comercial1.getS
System.out.println("El salario actual del repartidor es "+repartidor1.ge
}
}

Por ltimo, recuerda que que la herencia va de arriba a abajo, es decir, que una
clase padre no podr acceder la clase hija pero si al revs. Ademas solo
podemos heredar una sola clase.

14.5.2. Composicin vs. herencia


La composicin y la herencia colocan subobjetos dentro de la
clase. Ambos usan la lista de inicializacin del constructor para
construir esos subobjetos. Pero se preguntar cul es la diferencia
entre los dos, y cuando escoger una y no la otra.
La composicin generalmente se usa cuando se quieren las
caractersticas de una clase existente dentro se su clase, pero no en
su interfaz. Esto es, aloja un objeto para implementar caractersticas
en su clase, pero el usuario de su clase ve el interfaz que se ha
definido, en vez del interfaz de la clase original. Para hacer esto, se
sigue el tpico patrn de alojar objetos privados de clases existentes
en su nueva clase.
En ocasiones, sin embargo, tiene sentido permitir que el usuario
de la clase acceda a la composicin de su clase, esto es, hacer
pblicos los miembros objeto. Los miembros objeto usan su control
de accesos, entonces es seguro y cuando el usuario conoce que
esta formando un conjunto de piezas, hace que la interfaz sea ms
fcil de entender. Un buen ejemplo es la clase Car:
//: C14:Car.cpp
// Public composition

class Engine {
public:
void start() const {}
void rev() const {}
void stop() const {}
};

class Wheel {

public:
void inflate(int psi) const {}
};

class Window {
public:
void rollup() const {}
void rolldown() const {}
};

class Door {
public:
Window window;
void open() const {}
void close() const {}
};

class Car {
public:
Engine engine;
Wheel wheel[4];
Door left, right; // 2-door
};

int main() {

Car car;
car.left.window.rollup();
car.wheel[0].inflate(72);
} ///:~

Listado 14.11. C14/Car.cpp

Como la composicin de Car es parte del anlisis del problema (y


no una simple capa del diseo), hace pblicos los miembros y
ayudan al programador a entender como se utiliza la clase y
requiere menos complejidad de cdigo para el creador de la clase.
Si piensa un poco, observar que no tiene sentido componer un
Car usando un objeto "vehculo" - un coche no contiene un vehculo,
es un vehculo. La relacin "es-un" es expresado con la herencia y la
relacin "tiene un" es expresado con la composicin.
Subtipado

Ahora suponga que desea crear un objeto del tipo ifstream que no
solo abre un fichero sino que tambin guarde el nombre del fichero.
Puede usar la composicin e alojar un objeto ifstream y un string en
la nueva clase:
//: C14:FName1.cpp
// An fstream with a file name
#include "../require.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class FName1 {
ifstream file;
string fileName;
bool named;
public:
FName1() : named(false) {}
FName1(const string& fname)
: fileName(fname), file(fname.c_str()) {
assure(file, fileName);
named = true;
}
string name() const { return fileName; }
void name(const string& newName) {
if(named) return; // Don't overwrite
fileName = newName;
named = true;
}
operator ifstream&() { return file; }
};

int main() {
FName1 file("FName1.cpp");
cout << file.name() << endl;
// Error: close() not a member:
//!

file.close();

} ///:~

Listado 14.12. C14/FName1.cpp

Sin embargo, existe un problema. Se intenta permitir el uso de un


objeto FName1 en cualquier lugar dnde se utilice un objeto
ifstream, incluyendo una conversin automtica del tipo desde
FName1 a ifstream&. Pero en main, la lnea
file.close();

no compilar porque la conversin automtica de tipo slo ocurre


cuando se llama a la funcin, no durante la seleccin del miembro.
Por ello, esta manera no funcionar.
Una segunda manera es aadir la definicin Close() a FName1:
void close() { file.close(); }

Esto funcionar si slo existen unas cuantas funciones a las que


se desea hacer funcionar como una clase ifstream. En este caso,
solo una parte de la clase y la composicin apropiada.
Pero qu ocurre si se quiere que todo funcione cmo la clase
deseada? A eso se le llama subtipos porque esta creando un nuevo
tipo desde uno ya existente y lo que se quiere es que el nuevo tipo
tenga la misma interfaz que el tipo existente (adems de otras
funciones que se deseen aadir) para que se pueda utilizar en
cualquier lugar donde se utilizaba el tipo existente. Aqu es dnde la
herencia es esencial. Puede ver que el subtipo resuelve
perfectamente el problema anterior:
//: C14:FName2.cpp
// Subtyping solves the problem

#include "../require.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class FName2 : public ifstream {


string fileName;
bool named;
public:
FName2() : named(false) {}
FName2(const string& fname)
: ifstream(fname.c_str()), fileName(fname) {
assure(*this, fileName);
named = true;
}
string name() const { return fileName; }
void name(const string& newName) {
if(named) return; // Don't overwrite
fileName = newName;
named = true;
}
};

int main() {

FName2 file("FName2.cpp");
assure(file, "FName2.cpp");
cout << "name: " << file.name() << endl;
string s;
getline(file, s); // These work too!
file.seekg(-200, ios::end);
file.close();
} ///:~

Listado 14.13. C14/FName2.cpp

Ahora cualquier funcin que este disponible para el objeto


sfstream tambin esta disponible para el objeto FName2. Asimismo
se observan funciones no miembro como getline() que esperan un
objeto ifstream y que pueden funcionar con un objeto FName2. Esto
es porque FName2 es un tipo de ifstream; esto no significa
simplemente que lo contiene. Esto es un tema muy importante que
ser explorado al final de este capitulo y el siguiente.
Herencia privada

Puede heredar utilizando una clase base de forma privada


borrando public en la lista de la clase base o explcitamente
utilizando private (definitivamente la mejor poltica a tomar pues
indica al usuario lo que desea hacer). Cuando se hereda de forma
privada, esta "implementado en trminos de", esto es, se esta
creando una nueva clase que tiene todos los datos y funcionalidad
de la clase base, pero la funcionalidad esta oculta, solo una parte de
capa de implementacin. La clase derivada no tiene acceso a la
capa de funcionalidad y un objeto no puede ser creado como
instancia de la clase base (como ocurri en FName2.cpp).
Se sorprender del propsito de la herencia privada, porque la
alternativa, usar la composicin para crear un objeto privado en la
nueva clase parece ms apropiada. La herencia privada esta
incluida para completar el lenguaje pero para reducir confusin,

normalmente se usar la composicin en vez de la herencia privada.


Sin embargo, existen ocasiones donde se desea el mismo interfaz
como la clase base y anular tratamiento del objeto. La herencia
privada proporciona esta habilidad.
Publicar los miembros heredados de forma privada

Cuando se hereda de forma privada, todos los miembros pblicos


de la clase base llegan como privados. Si desea que cualquiera de
ellos sea visible, solo use sus nombres (sin argumentos o valores de
retorno) junto con la palabra clave using en una seccin pblica de
la clase derivada:
//: C14:PrivateInheritance.cpp
class Pet {
public:
char eat() const { return 'a'; }
int speak() const { return 2; }
float sleep() const { return 3.0; }
float sleep(int) const { return 4.0; }
};

class Goldfish : Pet { // Private inheritance


public:
using Pet::eat; // Name publicizes member
using Pet::sleep; // Both members exposed
};

int main() {
Goldfish bob;

bob.eat();
bob.sleep();
bob.sleep(1);
//! bob.speak();// Error: private member function
} ///:~

You might also like