Herencia POO en Java IV: Herencia (Parte 1) Escuela de Ingeniería Industrial Pontificia Universidad Católica de Valparaíso, Chile fguidi@ucv.cl Es la derivación de una clase a partir de otra existente. El objetivo es la reutilización del software desarrollado. Herencia Actualización: 22 de Agosto de 2011 2 Súperclases y subclases La clase de la cual se deriva otra clase se denomina clase base, súperclase o clase padre. Una clase derivada de una súperclase recibe también el nombre de subclase o clase hija. Vehículo Súperclase Clase base Clase padre Súperclases y subclases La subclases heredan propiedades de su súperclase. Una subclase, respecto de su súperclase: Agrega nuevas propiedades Modifica propiedades heredadas. Vehículo Patente Marca ----- Avanza Camión Subclase Clase derivada Clase hija La herencia aplica en relaciones de naturaleza B es un tipo de A Camión Patente Marca Carga máxima ----- Avanza Activa tolva 3 4
Herencia simple Una clase es subclase de una única súperclase. Herencia múltiple Una clase es subclase de más de una súperclase. Vehículos terrestres Vehículos acuáticos Vehículo Camión Vehículos anfibios Java no soporta la herencia múltiple. 5 6 Jerarquías de Herencia Ejemplo (1/2) La herencia organiza clases bases y derivadas en jerarquías de clases. + Universidad + set y get Universidad + Carrera pregrado + set y get Carrera magíster Persona Rut, nombre set y get nombre Profesor + Tesis + set y get Tesis + Especialidad + set y get Especialidad Profesor hora + Horas + set y get Horas 7 Determinar si en las siguientes situaciones existe una relación de herencia entre las clases (indicadas en negrita): Caso 1 Caso 2 Caso 3 Todo Electrodoméstico se enciende y apaga. El Horno microondas además abre y cierra su puerta. Electrodoméstico Horno Microondas Los Bienes raíces tienen un Rol de identificación. Una Casa tiene también un Jefe de hogar y un Negocio tiene una Patente comercial Bien Raíz Casa Negocio X Un Camión tiene Patente. Un Conductor tiene un camión conducido. 8
Ejemplo (2/2) Determinar si en las siguientes situaciones existe una relación de herencia entre las clases (indicadas en negrita): Caso 4 Caso 5 Caso 6 Implementación de jerarquías de herencia Para crear una subclase a partir de una superclase, en Java la subclase debe declararse: Los Archivos Multimediales pueden ser Imágenes o Música. Las imágenes pueden ser a Color o Blanco y Negro. Un Avión tiene Fuselaje, Alas y Motores. Una Gaviota vuela. Una Abeja vuela y además tiene aguijón. public class NombreSubclase extends NombreSuperclase Ejemplo: Multimedia Música Imagen Color B/N X X Persona public class extends Persona 9 10 Implementación de jerarquías de herencia: ejemplo Implementación de jerarquías de herencia Implementar las clases Persona y, de acuerdo con lo siguiente: public class extends Persona { Persona Atributos: - RUT - Nombre Atributos: - RUT - Nombre - Rol UCV Operaciones: -set y get RUT - set y get Nombre Operaciones: -set y get RUT - set y get Nombre - set y get Rol UCV NOTA: Supondremos, por el momento, todos los miembros públicos. public String rut; public String nombre; public Persona() { rut = "00000000-0"; nombre = ""; public void setrut(string r){ rut = r; return rut; public void setnombre(string n){ nombre = n; return nombre; Súperclase public String rolucv; public () { rolucv = 000000-0"; public void setrolucv(string r){ rolucv = r; public String getrolucv(){ return rolucv; public String quiénsoy(){ return rut + nombre + rolucv; Subclase 11 12
Miembros heredados (verdad parcial) Una subclase hereda de su súperclase (por el momento): Variables de instancia públicas Métodos públicos Todos los anteriores pueden ser utilizados en la subclase como si hubieran sido declarados en ella. POO en Java IV: Herencia (Parte 2) Escuela de Ingeniería Industrial Pontificia Universidad Católica de Valparaíso, Chile fguidi@ucv.cl Actualización: 22 de Agosto de 2011 13 Presentación Hemos visto: La definición de herencia (y la relación subyacente entre tipos ) El concepto de súperclase y subclase La definición de jerarquía de herencia La declaración de una subclase en Java La extensión de clases que poseen miembros públicos. Veremos: Un problema de diseño e implementación con herencia, utilizando miembros públicos. Se desarrollará una extensión del sistema desarrollado en el problema. Ejercicio Implemente las clases Vehículo, Autobús y Camión, dados los siguientes antecedentes: Todo Vehículo tiene patente y marca. Los Autobuses y los Camiones son Vehículos. Todo Autobús tiene cantidad de asientos. Todo Camión tiene carga en toneladas. 15 16
Análisis Jerarquía de clases Implementación Vehículo: public class Vehiculo{ Vehículo Patente, marca Asientos Autobús Camión Carga public String patente; public String marca; public void setpatente(string p){ patente = p; public String setmarca(string m){ marca = m; public String getpatente(){ return patente; public String getmarca(){ return marca; 17 18 Implementación Autobús Implementación Camión: public class Autobus extends Vehiculo{ public int asientos; public class Camion extends Vehiculo{ public int carga; public void setasientos(int a){ asientos = a; public int getasientos(){ return asientos; public void setcarga(int c){ carga = c; public int getcarga(){ return carga; 19 20
Uso de las clases desarrolladas Entonces una aplicación podría realizar lo siguiente: public class Ejemplo { public static void main( String arg[]){ Autobus bus1 = new Autobus(); bus1.setpatente( AX1313 ); bus1.setmarca( Mercedes ); bus1.setasientos( 40 ); Camion cam1 = new Camion(); cam1.setpatente( BX1515 ); cam1.setmarca( Iveco ); cam1.setcarga( 2000 ); Métodos heredados de Vehículo Métodos heredados de Vehículo Una extensión al problema Suponga que se desea agregar al sistema un Camión con compartimientos, el cual posee patente, marca, carga máxima y una cantidad de compartimientos. Este camión es capaz de calcular la capacidad de carga por compartimiento (equivalente a la carga total, dividida por la cantidad de compartimientos). Además provee un método que retorna un String de descripción, compuesto por Marca + Cantidad de compartimientos Qué se debe hacer? 21 22 Análisis El Camión con compartimientos es una subclase de Camión. Implementación Camión con compartimientos: public class CamionCompartimientos extends Camion{ Asientos Autobús Compartimientos Vehículo Camión Patente, marca Camión con compartimientos Carga public int compartimientos=1; public void setcompartimientos(int c){ compartimientos = c; public int getcompartimientos(){ return compartimientos; public int getcargacompartimiento(){ return carga/compartimientos; public String getdescripción(){ return marca + compartimientos; 23 24 carga: es heredado (desde Camión) marca: es heredado (desde Vehículo)
Uso de la nueva clase public class Ejemplo2 { public static void main( String arg[]){ CamionCompartimientos cam2 = new CamionCompartimientos(); cam2.setpatente( CX1818 ); cam2.setmarca( Ford ); cam2.setcarga( 2500 ); cam2.setcompartimientos( 5 ); Métodos heredados de Vehículo Método heredado de Camión System.out.println( cam2.getcargacompartimiento() ); System.out.println( cam2.getdescripción() ); POO en Java IV: Herencia (Parte 3) Escuela de Ingeniería Industrial Pontificia Universidad Católica de Valparaíso, Chile fguidi@ucv.cl Actualización: 22 de Agosto de 2011 25 Presentación Hemos visto: Los conceptos funamentales asociados a la herencia. La implementación de subclases en Java, en presencia de miembros públicos en la súperclase. Veremos: La implementación de subclases en Java, cuando la súperclase posee variables de instancia privadas. La relación entre constructores de súperclases y subclases. La relación de las clases con la clase Object. Repaso: extensión de una clase con miembros públicos public String rut; public String nombre; public Persona() { rut = "00000000-0"; nombre = ""; public void setrut(string r){ rut = r; return rut; public void setnombre(string n){ nombre = n; return nombre; public class extends Persona { public String rolucv; public () { rolucv = 000000-0"; public void setrolucv(string r){ rolucv = r; public String getrolucv(){ return rolucv; public String quiénsoy(){ return rut + nombre + rolucv; Súperclase Subclase 27 28
Miembros heredados (verdad parcial) Una subclase hereda de su súperclase (por el momento): Variables de instancia públicas Métodos públicos Todos los anteriores pueden ser utilizados en la subclase como si hubieran sido declarados en ella. Miembros no heredados Una subclase no hereda: Propiedades privadas Constructores Los miembros no heredados no pueden aparecer en el código de la subclase. 29 30 Miembros no heredados: variables de instancia privadas Miembros no heredados: variables de instancia privadas No funciona: private String rut; private String nombre; public Persona() { rut = "00000000-0"; nombre = ""; public void setrut(string r){ rut = r; return rut; public void setnombre(string n){ nombre = n; return nombre; public class extends Persona { private String rolucv; public () { rolucv = 000000-0"; public void setrolucv(string r){ rolucv = r; public String getrolucv(){ return rolucv; public String quiénsoy(){ return rut + nombre + rolucv; Las variables privadas no son heredadas, por lo que no pueden aparecer en el código de la subclase. Sin embargo se puede hacer uso indirecto de ellas en la subclase, a través de los métodos públicos de manipulación implementados en la respectiva súperclase. Error: no pueden ser accesadas directamente (No compila) 31 32
Miembros no heredados: variables de instancia privadas Ejemplo correcto: private String rut; private String nombre; public Persona() { rut = "00000000-0"; nombre = ""; public void setrut(string r){ rut = r; return rut; public void setnombre(string n){ nombre = n; return nombre; public class extends Persona { private String rolucv; public () { rolucv = 000000-0"; public void setrolucv(string r){ rolucv = r; public String getrolucv(){ return rolucv; public String quiénsoy(){ return getrut() + getnombre() + rolucv; Miembros no heredados: constructores Los constructores no son heredados, por lo que cada subclase debe tener su(s) propio(s) constructor(es). Sin embargo en los constructores se puede invocar al constructor de la superclase con la instrucción: super( lista parámetros ) La instrucción super debe ser la primera instrucción del constructor. Esto sí funciona 33 34 Uso de super en constructores Ejemplo 1: Uso de super en constructores Ejemplo 2: public class extends Persona { public class extends Persona { private String rut; private String nombre; public Persona(String r, String n) { rut = r; nombre = n; public void setrut(string r){ rut = r; return rut; public void setnombre(string n){ nombre = n; return nombre; private String rolucv; public () { super( 000000-0, N/A ); rolucv = 000000-0"; public void setrolucv(string r){ rolucv = r; public String getrolucv(){ return rolucv; public String quiénsoy(){ return getrut() + getnombre() + rolucv; private String rut; private String nombre; public Persona(String r, String n) { rut = r; nombre = n; public void setrut(string r){ rut = r; return rut; public void setnombre(string n){ nombre = n; return nombre; private String rolucv; public (String r, String n, String l) { super( r, n ); rolucv = l; public void setrolucv(string r){ rolucv = r; public String getrolucv(){ return rolucv; public String quiénsoy(){ return getrut() + getnombre() + rolucv; 35 36
Herencia y constructores: la verdad parcial Herencia y constructores Todo subclase debe incluir una referencia super a algún constructor de la superclase. Si no se incluye la referencia super, Java incluye automáticamente una referencia al constructor sin parámetros de la superclase. Es decir incluye: super() Notar que se produce un error cuando no existe un constructor sin parámetros en la superclase y se omite la referencia super en la subclase por qué? Dos clases equivalentes: public class extends Persona { private String rolucv; public () { super(); rolucv = 000000-0"; public void setrolucv(string r){ rolucv = r; public String getrolucv(){ return rolucv; public String quiénsoy(){ return getrut() + getnombre() + rolucv; public class extends Persona { private String rolucv; public () { rolucv = 000000-0"; public void setrolucv(string r){ rolucv = r; public String getrolucv(){ return rolucv; public String quiénsoy(){ return getrut() + getnombre() + rolucv; 37 38 Herencia y constructores: Atención! Qué pasa en el siguiente caso? private String rut; private String nombre; public Persona(String r, String n) { rut = r; nombre = n; public void setrut(string r){ rut = r; No compila Java return incluye rut; automáticamente una public referencia void setnombre(string super(), pero a n){ nombre = n; un constructor inexistente en la súperclase. return nombre; public class extends Persona { private String rolucv; public () { rolucv = 000000-0"; public void setrolucv(string r){ rolucv = r; public String getrolucv(){ return rolucv; public () { super(); rolucv = 000000-0"; public String quiénsoy(){ return getrut() + getnombre() + rolucv; 39 Herencia y constructores: la verdad total En Java toda clase extiende otra clase. Las clases que no declaran extender a otras, extienden a la clase Object (del package java.lang). Object es la superclase (directa o indirecta) de todas las clases. Todas las clases son subclases de Object o de otra subclase. Por lo tanto: todos los constructores incluyen (explícitamente o no) una referencia al constructor de su superclase. 40
Herencia y constructores: la verdad total Object Vehículo Persona Bien Raíz POO en Java IV: Herencia (Parte 4) Camión Profesor Casa Negocio Escuela de Ingeniería Industrial Pontificia Universidad Católica de Valparaíso, Chile pregrado magíster Profesor hora fguidi@ucv.cl Actualización: 22 de Agosto de 2011 41 Presentación Hemos visto: Implementación de jerarquías de herencia con variables de instancia públicas y privadas. Invocación de constructores de súperclases mediante super. La clase Object como la súperclase de toda jerarquía de herencia en Java. Veremos: Un ejercicio de desarrollo de una jerarquía de herencia con variables de instancia privadas, y con referencias explícitas a constructor de la súperclase. La representación de clases y jerarquías de herencia mediante diagramas de clases de UML. Ejercicio: Implementar las siguientes clases Un videojuego tiene Personajes. Cada personaje tiene un nombre (String) y un nivel propio de energía (int). Además implementan el método alimentarse, que recibe por parámetro una cantidad de energía (int) con el que incrementa el nivel propio de energía. Los personajes pueden ser: Guerreros: tienen además un arma (String). Al momento de la instanciación reciben su nombre, arma y nivel propio de energía inicial. Los guerreros tienen un método combatir que recibe por parámetro la cantidad de energía a gastar en el ataque, la cual es descontada de su nivel propio de energía. El método combatir retorna el arma y la cantidad de energía del ataque concatenados. Magos: tienen además un poder (String). Al momento de la instanciación reciben su nombre y poder. Los magos son siempre creados con un nivel propio de energía igual a 100. Proveen un método encantar, que disminuye en 2 unidades el nivel propio de energía y que retorna el poder del mago. 43 44
Análisis y diseño Análisis y diseño La clase Personaje: Personaje Visibilidad privada (-)! Visibilidad pública (+)! - nombre: String - energía: int Personaje +getnombre(): String +getenergia(): int +alimentarse(energianueva:int) +consumirenergia(gastoenergia:int) +Personaje(nombre:String, energia:int) Nombre de la clase! Variables de instancia! Métodos y constructores! -arma: String Guerrero - nombre: String - energía: int +getnombre(): String +getenergia(): int +alimentarse(energianueva:int) +consumirenergia(gastoenergia:int) +Personaje(nombre:String, energia:int) -poder: String Mago Los constructores van subrayados! +combatir(energ:int):string +Guerrero(nombre:String, energía:int, arma:string) +encantar():string +Mago(nombre:String, poder:string) 45 46 Implementación Clase Personaje: public class Personaje{ private String nombre; private int energia; public Personaje(String nombre, int energia){ this.nombre = nombre; this.energia = energia; return nombre; public int getenergia(){ return energia; - nombre: String - energía: int public void alimentarse(int energianueva){ energia = energia + energianueva; Personaje +getnombre(): String +getenergia(): int +alimentarse(energianueva:int) +consumirenergia(gastoenergia:int) +Personaje(nombre:String, energia:int) public void consumirenergia(int gastoenerg){ energia = energia - gastoenerg; 47 Implementación Clase Guerrero: public class Guerrero extends Personaje{ private String arma; -arma: String Personaje Guerrero +combatir(energ:int):string +Guerrero(nombre:String, energía:int, arma:string) public Guerrero(String nombre, int energia, String arma){ super(nombre, energia); this.arma = arma; public String combatir(int energ){ actualizaenergia( -1*energ ); return arma + energ; 48
Implementación Clase Mago: Personaje Mago Uso de las clases Ejemplo: public class Mago extends Personaje{ private String poder; public Mago(String nombre, String poder){ super(nombre, 100); this.poder = poder; public String encantar(){ actualizaenergia( -2 ); return poder; -poder: String +encantar(energ:int):string +Mago(nombre:String, poder:string) Guerrero g1 = new Guerrero( Alfa, 50, Burbujitas de jabón ); g1.combatir( 2 ); System.out.println( El nivel de energía de + g1.getnombre() + es + g1.getenergia() ); Mago m1 = new Mago( Harry, Quemar ); m1.encantar(); System.out.println( El nivel de energía de + m1.getnombre() + es + m1.getenergia() ); 49 50 Presentación POO en Java IV: Herencia (Parte 5) Escuela de Ingeniería Industrial Pontificia Universidad Católica de Valparaíso, Chile fguidi@ucv.cl Hemos visto: Implementación de jerarquías de herencia con variables de instancia públicas y privadas e invocación de constructores de súperclases mediante super. La clase Object como la súperclase de toda jerarquía de herencia en Java. La notación del Diagrama de Clases de UML para clases y relaciones de herencia. Veremos: Tratamiento de variables que referencian subtipos. Sobreescritura de métodos. Uso del operador instanceof para conocer el tipo de un objeto. Casting en jerarquías de herencia. Clases con miembros protegidos (protected). Actualización: 22 de Agosto de 2011 52
Referencias, tipos y subtipos Referencias, tipos y subtipos Persona Tesista Una variable de referencia puede referenciar objetos del mismo tipo de la variable (esto ya lo sabíamos). Ejemplo: Persona p = new Persona(); Una variable de referencia puede referenciar objetos de cualquier subtipo de la variable. Ejemplos: Persona p = new (); Persona p = new Tesista(); Dado que toda clase es subclase directa o indirecta de la clase Object, una variable de este tipo puede referenciar objetos de cualquier tipo. Ejemplos: Object o = new Persona(); Object o = new Tesista(); Object o = new Lavadora(); En consecuencia, un arreglo de tipo Object puede almacenar cualquier tipo de objeto en sus posiciones: Object[] arr = new Object[10]; arr[1] = new Persona(); arr[2] = new Tesista(); arr[3] = new Lavadora(); 53 54 Referencias, tipos y subtipos Reconocimiento de clases: operador instanceof Persona Tesista Una variable de referencia de un determinado tipo NO puede referenciar objetos de un súpertipo. Por lo anterior, las siguientes asignaciones NO son válidas: a = new Persona(); Tesista t = new (); Tesista t = new Persona(); El operador instanceof permite reconocer la clase a la que pertenece un objeto referenciado desde una variable determinada. Formato: NombreVar instanceof NombreClase Ejemplo: if( pers instanceof Persona ) System.out.println( La variable pers referencia a una Persona ); else System.out.println( La variable pers no referencia a una Persona ); 55 56
Operador instanceof y herencia Operador instanceof: ejemplo Todo objeto es instancia de la clase a la que pertenece, como también instancia de su superclase. Suponer: Persona Persona p1 =null: Profesor p2 = new Profesor(); p3 = new (); if( p1 instanceof Persona ) --> false! Electrodoméstico Lavadora Un objeto de la clase lavadora es también un electrodoméstico Profesor if( p2 instanceof Profesor ) --> true! if( p2 instanceof Persona ) --> true! if( p2 instanceof ) --> false! if( p3 instanceof ) --> true! if( p3 instanceof Persona ) --> true! if( p3 instanceof Profesor ) --> false! 57 58 Operador instanceof: ejemplo Persona personas = new Persona[100]; // Supongamos que aquí se ingresan // al arreglo Personas, s // y Tesistas. Persona Tesista //Aquí se muestra la cantidad de tesistas cantidadtesistas = 0; for(int i=0; i< personas.length; i++) if( personas[i] instanceof Tesista ) cantidadtesistas++; System.out.println( Hay + cantidadtesistas + tesistas ); Sobreescritura de métodos Un método declarado e implementado en una súperclase puede ser reimplementado en una subclase. Esto se denomina sobreescritura de métodos. Conceptualmente significa que la subclase realiza la misma operación de la súper clase, pero de un modo distinto. Esto es un caso de polimorfismo. private String rut; private String nombre; return rut; return nombre; public String identificarse(){ return rut + nombre; //otros miembros de la clase public class extends Persona { private String carrera; public String identificarse(){ return getrut() + getnombre() + carrera; //otros miembros de la clase 59 60
Sobreescritura de métodos Consideremos estas clases en los siguientes ejemplos: private String rut, nombre; public Persona(String r, String n){ rut = r; nombre = n; return rut; return nombre; public String identificarse(){ return rut + nombre; public class extends Persona { private String carrera; public (String r, String n, String c){ super(r,n); carrera = c; public String identificarse(){ return getrut() + getnombre() + carrera; Qué ocurre en las siguientes situaciones? Persona a = new Persona( 100, Matías ); System.out.println( a.identificarse() ); a 100 Matías getrut() getnombre() identificarse() b = new ( 100, Matías, Ind ); System.out.println( b.identificarse() ); b 100 Matías Ind getrut() getnombre() identificarse() 100Matías public String identificarse(){ return rut + nombre; 100MatíasInd public String identificarse(){ return getrut() + getnombre() + carrera; 61 62 Qué ocurre en la siguiente situación? Sobreescritura de métodos Persona a = new ( 100, Matías, Ind ); System.out.println( a.identificarse() ); a 100 Matías Ind getrut() getnombre() identificarse() public String identificarse(){ 100MatíasInd return getrut() + getnombre() + carrera; private String rut, nombre; public Persona(String r, String n){ rut = r; nombre = n; return rut; return nombre; public String identificarse(){ return rut + nombre; public class extends Persona { private String carrera; public (String r, String n, String c){ super(r,n); carrera = c; public String identificarse(){ return getrut() + getnombre() + + carrera; Java resuelve en tiempo de ejecución la asociación entre la variable de referencia y el método que debe invocar, en función del objeto que se encuentre referenciado en ella. Persona a = new ( 100, Matías, Ind ); System.out.println( a.identificarse() ); 100MatíasInd 63 64
Sobreescritura de métodos Herencia y acceso a miembros de una clase Persona a = new ( 100, Matías, Ind ); System.out.println( a.identificarse() ); El compilador Java es responsable de verificar que el método pertenezca al tipo de dato declarado por la variable. El intérprete Java es responsable de identificar y ejecutar la implementación del método correspondiente al tipo de objeto referenciado en el momento por la variable. private String rut; private String nombre; public setdatos(string r, String n) { rut = r; nombre = n; return rut; return nombre; Esto debe funcionar: Persona a = new Persona(); a.setdatos( 1000-2, Luis ); b = new (); b.setdatos( 2000-3, Pamela ); b.matricularse( Industrial ); public class extends Persona { private String carrera; public String matricularse( String c){ carrera = c; 65 66 Herencia y acceso a miembros de una clase Casting private String rut; private String nombre; public setdatos(string r, String n) { rut = r; nombre = n; return rut; return nombre; public class extends Persona { private String carrera; public String matricularse( String c){ carrera = c; private String rut; private String nombre; public setdatos(string r, String n) { rut = r; nombre = n; return rut; return nombre; public class extends Persona { private String carrera; public String matricularse( String c){ carrera = c; Esto funciona? Persona c = new (); c.setdatos( 1000-2, Luis ); c.matricularse( Comercial ); Error: el compilador determina que este método no pertenece a Persona. Sin embargo la variable contiene referencia a un, que es un tipo de Persona (y que posee este método). Es necesario introducir un casting para indicar al compilador que el objeto referenciado en la variable es efectivamente una instancia de : Persona c = new (); c.setdatos( 1000-2, Luis ); ( ()c ).matricularse( Industrial ); 67 68
Casting El casting no convierte objetos, simplemente explicita el tipo de objeto referenciado en una variable. Profesor Persona Persona a = new Profesor(); Profesor b = a; // ERROR Persona a = new Profesor(); Profesor b = (Profesor) a; // OK c = () a; // ERROR Persona a = new Persona(); Profesor b = (Profesor) a; // ERROR c = () a; // ERROR Miembros protegidos de una clase El modificador de visibilidad protected, permite declarar visibilidad protegida en variables de instancia y métodos. Los miembros de una clase con visibilidad protegida son sólo accesibles desde la misma clase o desde cualquier subclase de ella (no son accesibles desde otras clases). a = new (); Profesor b = (Profesor) a; // ERROR 69 70 Miembros protegidos de una clase Miembros protegidos de una clase Por lo tanto, una subclase hereda de su superclase: Variables de instancia protegidas y públicas Métodos protegidos y públicos Ejemplo: protected String rut; protected String nombre; public Persona(String r, String n) { rut = r; nombre = n; public void setrut(string r){ rut = r; return rut; public void setnombre(string n){ nombre = n; return nombre; public class extends Persona { private String rolucv; public () { super( 000000-0, N/A ); rolucv = 000000-0"; public String quiénsoy(){ return rut + nombre + rolucv; 71 72
Identificación de superclases Contexto: se está desarrollando una aplicación que trabaja con CD s, DVD s y discos de vinilo. POO en Java IV: Herencia (Parte 6) Escuela de Ingeniería Industrial Pontificia Universidad Católica de Valparaíso, Chile fguidi@ucv.cl Problema: se establece que a pesar de tener sus propios atributos, todos ellos disponen de código, sello discográfico y autor. Se desea evitar duplicidad de código. Decisión: se determina la conveniencia de crear la clase ProductoMusical, que agrupa las propiedades comunes de los tres tipos de productos. CD ProductoMusical código sello autor DVD Vinilo Actualización: 22 de Agosto de 2011 La superclase aparece por factorización de propiedades comunes 74 Clases abstractas En el ejemplo anterior la clase ProductoMusical es abstracta (no representa entidades presentes en el dominio). Esta condición se explicita en el diseño, declarando la clase como abstracta. ProductoMusical {abstract código sello autor public abstract class ProductoMusical { private int código; private String sello;... Clases abstractas Otro ejemplo: un software trabaja con distintas figuras geométricas, todas ellas polígonos, con algunas propiedades en común (ej. cantidad de lados). Polígono CD DVD Vinilo Una clase abstracta no puede ser instanciada, ha sido diseñada sólo para ser extendida. 75 76
Clases abstractas Métodos abstractos Polígono public abstract class Poligono { protected int lados; public void setlados(int l){ lados = l;... Supongamos que en el ejemplo anterior todos los polígonos deben proveer un método de cálculo de área. Conflicto de fuerzas en diseño: Todos los polígonos deben proveer el método, por lo tanto debiese aparecer a nivel de la superclase Polígono. La operación del método depende de cada polígono concreto (ej. área de cuagrado: lado 2, área de triángulo base * altura /2, etc.), por lo tanto no puede establecerse una lógica común a nivel de superclase. Solución: declarar método como abstracto en la superclase. Polígono public class Cuadrado extends Poligono { private int longitud; public void setlongitud(double l) { longitud = l;... 77 78 Métodos abstractos Métodos abstractos Un método abstracto es un método que se declara en una superclase, pero sin proveer implementación. La implementación de un método abstracto se difiere para sus subclases. Una clase que declara uno o más métodos abstractos es necesariamente abstracta (y debe ser declarada como tal). Si una subclase no provee implementación para un método abstracto que hereda de su superclase, es necesariamente abstracta (y debe ser declarada como tal). Polígono public abstract class Poligono { protected int lados; public int setlados(int l){ lados = l; public abstract double getarea();... public class Cuadrado extends Poligono { private double longitud; public void setlongitud(double l) { longitud = l; public double getarea(){ return longitud*longitud;... 80 79 80
Consecuencias del uso de métodos abstractos Si una superclase declara algún método abstracto, entonces: Las subclases concretas deben implementarlo. Las variables de referencia declaradas del tipo de la superclase pueden recibir invocaciones al método abstracto, sin necesidad de casting. Ejemplo: Polígono figura = new Triángulo(); double sup = figura.getarea(); getarea() fue declarado como método abstracto en Polígono. 81