Conceptos más avanzados de Programación Orientada a Objetos Programación 2008 Licenciatura de Lingüística y Nuevas Tecnologías Repaso: API de Java • API = Application Programming Interface • Una API describe la especificación de los datos y subrutinas para una aplicación especifica que cualquier programador puede integrar en su código. • La API estándar de Java define una librería jerarquizada de clases con la definición de sus métodos y datos asociados. • La API de Java esta organizada por paquetes (packages). • Las clases en la API de Java están organizadas como un árbol, con Object como la clase raíz. Todas las demás clases son subclases (directas o indirectas) de Object. • Cualquiera nueva clase que creamos es automáticamente una sub-clase de Object. Herencia • La herencia permite definir una clase muy general y luego definir clases más especializadas que contienen más detalle. – Clase general = super-clase, clase madre, clase de base – Clase especializada = sub-clase, clase hija, clase derivada • Después de desarrollar la clase general, solo tenemos que escribir la diferencia, o el código especializado de la clase derivada. • Conseguimos una jerarquía de clases – Clase arriba de la jerarquía = clase ancestro – Clase abajo de la jerarquía = clase decendiente • Una clase hija hereda los métodos y variables de instancia de una clase madre (y de todos sus ancestros). 3 Herencia • Ejemplo 1: La clase Morpho tiene como subclases Verb, Noun, etc. Morpho.java , Noun.java ,Verb.java, Main.java • La palabra clave extends permite definir una clase madre para una subclase. • Verb y Noun heredan de Morpho: heredan las variables de instancia “lemma” y “category” e el método imprimir(). • Verb y Noun definen sus propias variables y métodos. • EL constructor de Verb llama de forma explicita al constructor de su super-clase con la palabra clave super. • El constructor de Noun llama de forma implicita al constructor por defecto de su super-clase. • En el Main de Ejemplo 1, una variable de objeto de tipo Morpho puede apuntar a cualquier objeto de tipo Morpho o de una subclase de Morpho. 4 public class Morpho { String lemma; String category; public class Verb extends Morpho { String tense; String person; String number; String aspect; public Morpho() { } public Morpho(String l,String c) { lemma = l; category = c; } } public void imprimir() { System.out.println(lemma + "/" + category); } } public Verb(String lemma,String tense,String person,String number,String aspect) { super(lemma,"Verb"); this.tense = tense; this.person = person; this.number = number; this.aspect = aspect; } public class Noun extends Morpho { String gender; String person; String number; } public Noun(String lemma, String gender, String person, String number) { this.lemma = lemma; this.category = "Noun"; this.person = person; this.number = number; this.gender = gender; } public class Main { public static void main(String[] args) { Noun thisNoun = new Noun("perro","masculine","third","singular"); Verb thisVerb = new Verb("ladra","present","third","singular","indicative"); } } thisNoun.imprimir(); thisVerb.imprimir(); Morpho thisMorpho = new Verb("ladra","present","third","singular","indicative"); thisMorpho.imprimir(); thisMorpho = new Morpho("el","Det"); thisMorpho.imprimir(); 5 Overriding • Ejemplo 2: Las subclases pueden redefinir los métodos de su superclase. Se llama overriding Morpho.java , Noun.java ,Verb.java, Main.java • Noun y Verb redefinen el método imprimir de Verb. Al llamar el imprimir de un objeto de tipo Verb, se llama el imprimir de Verb (y no al imprimir de Morpho). 6 public class Morpho { String lemma; String category; public Morpho() { } public class Verb extends Morpho { String tense; String person; String number; String aspect; //... MISMO CONSTRUCTOR QUE ANTES public Morpho(String l,String c) { lemma = l; category = c; } } public void imprimir() { System.out.println(lemma + "/" + category); } } } public void imprimir() { System.out.println(lemma + "/" + category + "[TENSE: " + tense + " ASPECT: " + aspect + " PERSON: " + person + " NUMBER: " + number + "]"); public class Noun extends Morpho { String gender; String person; String number; // ....MISMO CONSTRUCTOR QUE ANTES } public void imprimir() { System.out.println(lemma + "/" + category + "[GENDER: " + gender + " PERSON: " + person + " NUMBER: " + number); } public class Main { public static void main(String[ ] args) { Noun thisNoun = new Noun("perro","masculine","third","singular"); Verb thisVerb = new Verb("ladra","present","third","singular","indicative"); thisNoun.imprimir(); thisVerb.imprimir(); } } Morpho thisMorpho = new Verb("ladra","present","third","singular","indicative"); thisMorpho.imprimir(); thisMorpho = new Morpho("el","Det"); thisMorpho.imprimir(); 7 Herencia y API de Java • En la documentación de la API de Java, se da para cada clase su posición en la jerarquia (cuales son sus super-clases) y sus subclases directas. Por ejemplo, la clase Number tiene como super-clase Object y como subclases directas (entre otras) Integer, Double, Float: http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Number.html • Además del listado de los métodos de la clase, se proporciona las listas de los métodos heredados de cada super-clase. Por ejemplo, con FileWriter utilizamos el método void write(String s) de su super-clase indirecta Write: http://java.sun.com/j2se/1.4.2/docs/api/java/io/FileWriter.html • Overriding: La clase Object define el método equals(). Su subclase String lo redefine para la comparación de objetos de tipo String. 8 Clases abstractas • • • • Definición de la clase Number en la API de Java: public abstract class Number extends Object {...} Una clase abstracta es una clase que nunca se puede instanciar. O sea que no podemos tener objetos del tipo de una clase abstracta. No podemos tener objetos de tipo Number, pero sí podemos instanciar objetos con las subclases de Number (que no son abstractas). Por ejemplo lo siguiente provoca un error de compilación: Number n = new Number(); java.lang.Number is abstract; cannot be instantiated Una clase abstracta sirve para agrupar conceptualmente sub-clases y definir métodos y variables que heredan sus sub-clases. 9 Métodos abstractos • Una clase abstracta puede definir métodos abstractos. • • Un método abstracto no tiene definición (o cuerpo). Lo hereden las subclases, y cada una tiene que darle una implementación especifica, o sea redefinirla (overrides). Un método abstracto se declara así (con el punto coma al final y sin llaves): abstract tipoDeStalida methodName(parametros-entrada); • La clase Number define los siguientes métodos abstractos: doubleValue() , floatValue() , intValue(), longValue(), shortValue(). • Estos métodos están redefinidos (overriden) por obligación por las subclases de Number: Integer, Float, Double. Por ejemplo, podemos ver estos métodos en la API de Integer: http://java.sun.com/j2se/1.3/docs/api/java/lang/Integer.html 10 Clases y métodos abstractos • ¿Tiene sentido tener a la clase Morpho como una clase abstracta? • ¿Tiene sentido tener el método imprimir de Morpho como método abstracto? • Ejemplo 3: Morpho.java, Verb.java, Noun.java, Main.java 11 public abstract class Morpho { String lemma; String category; public Morpho() { } public Morpho(String l,String c) { lemma = l; category = c; } } Si Noun y Verb no definen el método imprimir, tendremos un error de compilación! public abstract void imprimir(); public class Main { public static void main(String[] args) { Noun thisNoun = new Noun("perro","masculine","third","singular"); Verb thisVerb = new Verb("ladra","present","third","singular","indicative"); thisNoun.imprimir(); thisVerb.imprimir(); } } Morpho thisMorpho = new Verb("ladra","present","third","singular","indicative"); thisMorpho.imprimir(); // Estas llamadas no las podemos hacer: no se puede instanciar un objeto de tipo Morpho //thisMorpho = new Morpho("el","Det"); //thisMorpho.imprimir(); 12 Polimorfismo con Overriding • • • Una variable de objeto puede apuntar a cualquier objeto de la clase que le corresponde o de las sub-clases de esta clase. Por ejemplo, partiendo del Ejemplo 3: – Morpho morpho1= new Verb(....); – Morpho morpho2= new Noun(....); morpho1.imprimir() llama al imprimir de Verb; morpho2.imprimir() llama al imprimir de Noun. Esta capacidad de diferentes objetos de comportarse de diferentes formas con el mismo mensaje (i.e., método) se llama polimorfismo. 13 Polimorfismo con Overriding • ¿En qué nos interesa el polimorfismo? Por ejemplo, podemos tener un ArrayList de categorias (Verb, Noun,etc). Podemos imprimir en bucle cada uno de los objetos del ArrayList con imprimir(), confiando que se llamará el método imprimir() relevante para cada caso. 14 Overloading • • • El nombre del método no es suficiente para identificar de manera única a un método dentro de una clase. También sirven el número y tipo de los argumentos de entrada. El nombre de un método juntos con su argumentos de entrada se llama signature (firma), porque identifica de manera única a un método. Por ejemplo, la clase String tiene dos métodos substring distintos (el segundo tiene un argumento extra): – – • Otro ejemplo: la clase Math tiene cuatro métodos con nombre max para devolver el máximo de dos numero, entre otros: – – • public String substring(int beginIndex) public String substring(int beginIndex,int endIndex) public static double max(double a, double b) public static int max(int a, int b) Esta habilidad de métodos (y constructores) a tener el mismo nombre pero a distinguirse por los argumentos de entrada se llama method overloading. 15 Polimorfismo con Overloading • La clase java.io.PrintStream tiene varios métodos print() con firmas diferentes: – – – – – – – – – • public void print(boolean b) public void print(char c) public void print(char[] s) public void print(float f) public void print(double d) public void print(int i) public void print(long l) public void print(Object obj) public void print(String s) Cuando escribimos: System.out.print(variable), el método llamado depende del tipo de variable. Esto es polimorfismo con overloading de método. 16 Interfaz • • • • • Una interfaz contiene las firmas (signature) de unos métodos. No implementa ninguno. La clase que implementa una interfaz tiene que implementar los métodos declarados en la interfaz. Dicho de otro modo: una interfaz define un contrato que una clase que la implementa tiene que cumplir. Esto no es lo mismo que la herencia. Una interfaz no forma parte de la jerarquia de clases de Java. Una interfaz se define con la palabra clave interface: public interface Collection { ... } • Se dice que una clase implementa una interfaz y se utiliza la palabra clave implements. Por ejemplo: public class ArrayList ... implements List {...} 17 Interfaz • Los ventajas de una interfaz sobre una super-clase (abstracta) son: – No tenemos que forzar una jerarquía de clases si lo único que queremos es que se cumpla algun contrato. Por ejemplo, queremos poder decir que un Coche (o una Casa) es un Bien Imponible sin tener que decir que Coche es una subclase de BienImponible. – Como en Java no es posible tener más de una clase madre, usamos interfaces para describir propiedades adicionales de los objetos. Por ejemplo, un Coche es un Vehiculo (super-clase) pero también un Bien Imponible (interfaz que define las propiedades de los bienes imponibles) y un Objeto Polutante (interfaz que define las propiedades de los objetos polutantes). 18