You are on page 1of 31

HERENCIA

GENERALIZACION / ESPECIALIZACION

ING. PILAR ROJAS P.


HERENCIA SIMPLE: La herencia es
la jerarquía “de clases” más
importante y un elemento esencial en
los sistemas orientados a objetos. La
herencia define una relación entre
clases, en la que una clase comparte la
estructura de comportamiento
definida en una o más clases( lo que se
denomina herencia simple)
Se puede construir un objeto (de una Subclase) a partir de otro ya existente
(de una SuperClase) mediante el mecanismo de la herencia.

La palabra extends es utilizada para generar o crear una subclase


(Especialización) de un conjunto de objetos.
Las clases derivadas ó subclases o clases hijas heredan todas las
variables y métodos de la superclase. Igualmente la subclase tienen la
propiedad de definir ó añadir nuevas variables y métodos.
En Java no existe el concepto de Herencia Múltiple y todas las clases
derivan de una clase anterior. La clase raíz en Java es llamada clase
Object del paquete java.lang
Simbología en UML

Persona

Es-Un

Proveedor Cliente Empleado

Es-Un Es-Un

CteSecundario Preferencial Operario Maquinista


SINTAXIS

[modificador] class ClasePadre {


// definición de atributos
// definición de métodos
}

[modificador] class ClaseHija extends ClasePadre {


// definición de atributos propios
// definición de métodos propios
}
Ejemplo:
Cuando se desea que nadie pueda derivar de una clase se utiliza el
modificador final. Igualmente cuando se tiene un método en la
superclase y no se quiere que sea sobreescrito por ninguna
subclase, se adiciona el modificador final.

Contrario del modificador abstract que es utilizado para crear


subclases a partir de ella, no siendo posible crear objetos de una
clase que utilice el modificador abstract.

Lista de los modificadores de acceso en la declaración de miembros


( atributos y métodos) de clase
La sobreescritura es la capacidad que tiene una clase Derivada para redefinir un
elemento (no estático) de la clase Base o clase padre.
Una clase Derivada puede definir:
•Un método con la misma signatura (firma) que uno de la clase base (igual
tipo de retorno, parámetros y nombre del método)

Los métodos declarados estáticos en una clase base se pueden sobreescribir


siempre y cuando sean declarados estáticos en la subclase.

Una clase puede redefinir (volver a definir) cualquiera de los métodos heredados
de su super-clase que no sean final. El nuevo método sustituye al heredado para
todos los efectos en la clase que lo ha redefinido.
Se podrá sobreescribir un método en una clase Hija siempre y cuando
en la clase Padre el acceso de visibilidad sea el adecuado. Si por
ejemplo en la clase Padre se tiene un método privado será imposible
que el hijo pueda tener acceso al método y por lo tanto
sobreescribirlo. Por lo tanto las reglas de visibilidad son importantes
En la redefinición, se puede ampliar el nivel de acceso, haciéndolo más
público pero nunca más privado. (De menos a más).
Clase Padre Clase Hija
public public
protected public, protected
private no se puede sobreescribir
default protected, public, default
Ejemplo de sobreescritura en Herencia:

1 public class Employee {


2 protected String name;
3 protected double salary;
4 protected Date birthDate;
5
6 public String getDetails() {
7 return “Name: “ + name + “\n” + “Salary: “ + salary;
8 }
9 }
1 public class Manager extends Employee {
2 protected String department;
3
4 public String getDetails() {
5 return “Name: “ + name + “\n” + “Salary: “ + salary + "\n" +
6 “Manager of: “ + department;
7 }
8 }
La sobreescritura en las clases derivadas nunca puede ser de
menor acceso que de la clase padre.

1 public class Parent {


2 public void doSomething() {}
3 }

1 public class Child extends Parent {


2 private void doSomething() {} // illegal
3 }

1 public class UseBoth {


2 public void doOtherThing() {
3 Parent p1 = new Parent();
4 Parent p2 = new Child();
5 p1.doSomething();
6 p2.doSomething();
7 }
8 }
Un método de una subclase puede invocar métodos de una
SuperClase, usando la palabra reservada super .
La palabra super es usada en una clase para referirse a los
miembros de la superclase (tanto atributos como métodos) o el llamado
de constructores de la superClase.

1 public class Employee { 1 public class Manager extends Employee {


2 private String name; 2 private String department;
3 private double salary; 3
4 private Date birthDate; 4 public String getDetails() {
5 5 // call parent method
6 public String getDetails() { 6 return super.getDetails() +
7 return "Name: " + name + "\nSalary: 7 “\nDepartment: " + department;
8 " + salary; 8 }
9 } 9 }
10 }
Una subclase hereda todos los métodos y variables de la
superclase excepto los constructores que no son heredados.

Un constructor de una clase puede llamar por medio de la palabra


this a otro constructor previamente definido en la misma clase. En
este contexto, la palabra this sólo puede aparecer en la primera
sentencia de un constructor.

De forma análoga el constructor de una clase derivada(hija) puede


llamar al constructor pariente de la super-clase por medio de la
palabra super( ), seguida entre paréntesis de los argumentos
apropiados para uno de los constructores de la super-clase. De esta
forma, un constructor sólo tiene que inicializar directamente las
variables no heredadas.
La llamada al constructor de la super-clase debe ser la primera
sentencia del constructor, excepto si se llama a otro constructor de
la misma clase con this(). Si el programador no la incluye, Java
incluye automáticamente una llamada al constructor por defecto de
la super-clase, super().

Esta llamada en cadena a los constructores de las super-clases


llega hasta el origen de la jerarquía de clases, esto es al constructor
de Object.

Si una Clase Padre tiene definido un constructor con argumentos,


y a este no le proporcionan los argumentos correspondientes, el
compilador generará un error de compilación.
La esencia de la sobreescritura es que se pueda utilizar un método
preestablecido por un padre y reimplementarlo por un hijo, o mejor
aún, utilizar la implementación del padre y añadirle más funcionalidad
en el hijo. La sobreescritura en combinación con la Herencia, conforma
uno de los aspectos del paradigma Orientado a Objetos más poderoso
y es conocido como POLIMORFISMO
Se puede hablar sobre que una variable de Referencia puede referirse
a objetos de diferente forma.
En una Jerarquía de Herencia existe compatibilidad ascendente. Por
ello, a una referencia se le puede asignar un objeto de la clase
declarada o de cualquier clase derivada de ella. Igualmente, es posible
invocar un método del objeto y que se ejecute el método
correspondiente a la clase a la que pertenece el objeto, siempre y
cuando el método esté sobreescrito.
Ejemplo: suponga que existe un método imprime( ), tanto en la
superclase Padre y sobreescrito en la subclase Hijo ( Extendida
de Padre).
1. Padre p = new Hijo( );
2. Hijo h = new Hijo( );
3. p.imprime( ); // ejecuta imprime( ) de Hijo
4. h.imprime( ); // ejecuta imprime ( ) de Hijo

En la línea 3, se observa que el método imprime sobreescrito por la


subclase Hijo está siendo ejecutado a través de una variable de tipo
Padre.
Sin embargo, se puede dar el caso que la clase Hijo tenga información
que no necesariamente conozca la Clase Padre, y en este caso la
variable de tipo Padre no podrá nunca acceder a la información
específica del Hijo.
Ejemplo:
public class ClasePadre{
int dato=5;
void metodoPadre(){
System.out.println(“Ejecución del metodo del padre”);
}
}
class ClaseHijo extends ClasePadre{
int dato=10;
void metodoPadre(){
System.out.println(“Ejecución del metodo del hijo” + dato);
}
public static void main (String [] arg){
ClasePadre objp=new ClaseHijo( );
objp.metodoPadre(); // se ejecuta la implementación del Hijo
System.out.println(objp.dato);// se imprime 5
}
}
Igualmente, si se tiene algún método específico de la clase Hija, no
heredado, este método no va a poder ser referenciado por la
variable de tipo Padre.
Ejemplo:
public class ClasePadre{
int dato=5;
void metodoPadre(){
System.out.println(“Ejecución del metodo del padre”);
}
}
class ClaseHijo extends ClasePadre{
int dato=10;
void metodoPadre(){
System.out.println(“Ejecución del metodo del hijo” + dato);
}
void metodoHijo(){
System.out.println(“Ejecución del segundo metodo del hijo” + dato);
}
public static void main (String [] arg){
ClasePadre objp=new ClaseHijo( );
objp.metodoPadre();
System.out.println(objp.dato);
objp.metodoHijo(); // Error compilación
}
}
1. ClasePadre objp;
2. objp = new ClaseHijo( );
Para el caso de la línea 1. objp estará conformado por las
variables y firmas de los métodos que posee la ClasePadre.
Para el caso de la línea 2. objp se le asigna un Objeto de tipo
ClaseHijo, antes de producirse la instanciación y en tiempo de
ejecución Java valida si los tipos de datos son compatibles.
Para nuestro caso ClaseHijo extiende de ClasePadre, por lo tanto
ClaseHijo tiene la funcionalidad de ClasePadre, y Java permite
Compilar. Ahora, en memoria se carga un Objeto de ClaseHijo
(donde tiene lo heredado de ClasePadre y sus atributos y métodos
propios). Aquellos métodos que tienen una misma firma tanto en
el padre como en el Hijo, solamente quedará en memoria el
método más actualizado, es decir los del Hijo.
Razón por la cual, la variable objp de tipo ClasePadre tiene acceso
a los métodos sobreescritos por la ClaseHijo, sin poder acceder a
variables y métodos exclusivos de la ClaseHijo.
Para devolver el 100% de la funcionalidad se aplica Casting de
Objetos
NOTA: El llamado de un método sobreescrito es resuelto en momento de
ejecución y no en tiempo de compilación, esto a causa de que los métodos
sobreescitos soportan polimorfismo.

El POLIMORFISMO consiste en: Un objeto puede ser asignado a una


referencia declarada de la misma clase o de cualquiera de las clases base, es
decir, puede ser visto de muchas formas distintas. Pero su comportamiento
viene determinado por la clase que se instancia (la generada por la sentencia
new ), que es independiente de la referencia usada. Entonces, cuando
diferentes tipos de objetos son referidos mediante una variable de referencia
superclase, diferentes versiones del método son ejecutadas.

Por qué aplicar POLIMORFISMO? El polimorfismo permite a una


superclase especifique métodos que serán comunes a todas sus subclases, lo
que permite simultáneamente que las subclases definan la implementación
específica de algunos o todos esos métodos.
Figura
-ancho: double
-alto: double
- nombre: String
Figura( );
Figura(double ancho,double alto,String nombre);
Figura(double x,String nombre);
double getAncho( );
double getAlto( );
String getNombre( );
double area( );

Triangulo Rectangulo

Triangulo( ) ; Rectangulo( ) ;
Triangulo(double ancho, double alto); Rectangulo(double ancho, double alto);
Triangulo(double x); Rectangulo(double x);
double area( ); double area( );
// CODIGO DE LA SUPERCLASE FIGURA
public class Figura{

private double ancho,alto;


private String nombre;
//cosntructor por defecto

public Figura( ){
ancho=alto=0.0;
nombre="null";
}
public Figura(double ancho,double alto,String nombre){
this.ancho=ancho;
this.alto=alto;
this.nombre=nombre;
}
public Figura(double x,String nombre){
ancho=alto=x;
this.nombre=nombre;
}
public double getAncho( ){
return ancho;
}
public double getAlto( ){
return alto;
}
public String getNombre( ){
return nombre;
}
public double area( ){
System.out.println("Area ( ) debe ser sobreescrita ");
return 0.0;
}
}
//CODIGO DE LA SUBCLASE TRIANGULO //CODIGO DE LA SUBCLASE RECTANGULO
public class Triangulo extends Figura{ public class Rectangulo extends Figura{

public Triangulo(){ public Rectangulo( ){


super(); super();
} }

public Triangulo(double ancho, double alto){ public Rectangulo(double ancho, double alto){
super(ancho,alto," Triángulo "); super(ancho,alto," Rectangulo ");
} }
public Triangulo(double x){
super(x,"Triángulo"); public Rectangulo(double x){
} super(x,"Rectángulo");
}

public double area(){


return getAncho()*getAlto()/2; public double area(){
} return getAncho()*getAlto();
}
} }
// Codigo del programa prueba ejecucion main( )
public class TestFigura{
public static void main(String [ ] arg){
Figura objfig[]=new Figura[5];
objfig[0]=new Triangulo(12.0,20.0);
objfig[1]=new Rectangulo(40);
objfig[2]=new Rectangulo(20,30);
objfig[3]=new Triangulo(7.0);
objfig[4]=new Figura(10,20,"Generico");
for(int i=0;i<objfig.length;i++){
System.out.println("Objeto es: "+objfig[i].getNombre());
System.out.println("Area es: "+ objfig[i].area());
System.out.println();
}//ciclo for
}//metodo main
} //clase
Cabe mencionar que dentro de una clase podemos contar con
variables de clase ó estáticas, variables de instancia, bloques
estáticos y bloques no estáticos.
Para el caso la máquina virtual ejecuta de la siguiente forma:
1. Siempre se carga la clase, por consiguiente, se cargan los
elementos estáticos en el orden que aparecen.
2. Se cargan las variables de instancia (asignación de valores)
3. Luego se cargan los bloques no estáticos
4. Se ejecuta los constructores

Se menciona, que la clase Padre se carga primero a pesar de que se


esté creando un objeto de la Clase Hija
public class ClasePadre{
private int var1=10;
private static int var2=5;
//constructor
public ClasePadre(){
System.out.println("Constructor de la clase padre");
}
//bloque estático
static {
System.out.println("Ejecución del bloque estatico del padre" + var2);
}
//bloque no estático
{
var1=100;
System.out.println("Ejecución del bloque No estatico del padre");
}
public ClasePadre(int var1){
this.var1=var1;
System.out.println("Ejecución del constructor con parametro del padre");
}
public int getVar1(){
return this.var1;
}
public void metodo1(){
System.out.println("Ejecucion del metodo1 del padre");
}
}
public class ClaseHijo extends ClasePadre{
//constructor dos
public ClaseHijo(String text){
System.out.println("valor de la variable de instancia de la clase padre: "+getVar1());
System.out.println("Ejecución: "+text);
}

//constructor uno
public ClaseHijo(){
this("Constructor Hijo dos Con parametro");
System.out.println("Constructor Hijo por defecto");
}

//bloque estatico
static {
System.out.println("Ejecucion bloque estatico del Hijo");
}

//metodo sobreescrito del padre


public void metodo1(){
System.out.println("Ejecucion del metodo1 del hijo");
}
}
public class TestHerencia{

public static void main(String [] arg){


ClaseHijo obj= new ClaseHijo();
obj.metodo1();
}
}

You might also like