Jyoc Java Cap08 Principios Poo
Jyoc Java Cap08 Principios Poo
Jyoc Java Cap08 Principios Poo
TEMARIO DE CURSO
PROGRAMACIÓN JAVA SE
Iñaki Martín
CAPÍTULO 8
PRINCIPIOS DE
©
PROGRAMACIÓN
Temario de curso JavaSE
© Iñaki Martín
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-SinObraDerivada 4.0 Internacional.
8.- !XPrincipios P.O.O. Principios POO. Resumen 2
Encapsulado Sobrecarga
Impedir que los atributos de la clase sean directamente Posibilidad de tener varios métodos con el mismo nombre
modificados o consultados desde fuera de la clase. • Los métodos no pueden tener los mismos argumentos
• Los atributos serán private y se usan getters y setters como métodos de acceso
Abstracción
Sobrescritura
Métodos abstractos son aquellos no tienen código.
Volver a escribir un método heredado, de modo que el nuevo
Iñaki Martín
• No se heredan los constructores. Una interfaz es una clase en la que todos los métodos son métodos
• La subclase puede tener sus propios miembros (métodos y atributos propios), que abstractos.
no comparte con su superclase, ni con sus “hermanas"
• La herencia se puede aplicar múltiples veces, en cascada,
Al implementarse, las clases deben desarrollar todos los métodos
• Java no permite herencia múltiple, descritos por la interfaz
• Una clase hereda de Object si no hereda directamente de ninguna otra. • Una interfaz no se puede instanciar, no se pueden hacer objetos de ella.
• La subclase no puede elegir lo que hereda, hereda todos los miembros de la • Todos los métodos que tenga serán obligatoriamente abstractos y públicos
superclase, pero puede sobrescribir métodos de la madre • Una interfaz no tiene constructor
• La superclase puede elegir lo que deja en herencia, pues los miembros private no • Una interfaz puede tener atributos, pero han de ser public static final
se heredan. • Si la clase que implementa una interfaz no sobrescribe todos los métodos, ha de ser
• Con protected se permite visibilidad de miembros solo a los herederos abstracta.
• Una interfaz no necesita declararse abstract ni public, ni tampoco sus métodos.
Polimorfismo • Los métodos de una interfaz no pueden ser static o final
• Una clase puede implementar varias interfaces.
Un objeto de una superclase puede apuntar a un objeto de • Una interfaz NO puede implementar otra interfaz.
cualquiera de sus subclases, esto es, se puede crear un • Una interfaz NO puede heredar de otra clase.
objeto y asignarlo a un objeto de una clase “madre” • Una interfaz SÍ puede heredar de interfaces.
• permite ejecutar acciones iguales sobre objetos de tipos distintos
8.- !XPrincipios P.O.O. Conceptos POO. Introducción 3
๏ Hasta ahora, se han explicado muchos conceptos y elementos para hacer hacer un programa.
๏ La existencia de tipos de datos básicos (int, double, char, boolean,…) sentencias condicionales (if, switch),
bucles (for, while), arrays y matrices, son elementos de programación estructurada, elementos que tienen
casi todos los lenguajes de programación existentes (C,C++,Pascal, .NET, Fortran, Php, etc.)
Iñaki Martín
๏ Lo que hace diferente Java a estos lenguajes, y lo que es propio de la Programación Orientada a Objetos, es
la esencia del concepto de clase. La esencia, y es muy importante siempre recordar asi la POO, de que se
puede trabajar con tipos de datos no solo estándar (int, double, char, boolean,…) , sino con nuevos tipos de
datos (Coche, Persona, CuentaCorriente,…) que pueden crearse a nuestra necesidad.
©
๏ Sin embargo, la POO no solo se diferencia de otros lenguaje por la existencia del concepto de clase, sino que
la existencia de éstas promueve una seria de técnicas que hacen a la POO un enorme paradigma a la hora de
Temario de curso JavaSE
Encapsulado
๏ El encapsulado consiste en el poder de juntar en una clase las características y comportamientos, esto
es, las variables y métodos. Es tener todo esto junto es una sola entidad. En los lenguajes estructurados
esto es imposible, pero en POO, atributos y métodos, dentro del cajón de la clase, da mucho potencial.
๏
Iñaki Martín
El encapsulado permite además mantener ocultos los procesos internos que necesita una clase para
hacer lo que sea que haga, dándo al exterior acceso sólo lo que necesita (ocultación). Se puede por lo
tanto aislar atributos dentro de una clase y permitir su acceso solo por métodos de la propia clase (getters y
setters).
๏ De este modo se prohíbe que los atributos de la clase sean directamente modificados o consultados
©
๏ Con el encapsulamiento de atributos y métodos se consiguen dos grandes beneficios a los desarrolladores
de software:
‣ Modularidad, esto es, el código fuente de un objeto puede ser escrito, así como darle mantenimiento,
independientemente del código fuente de otros objetos
‣ Ocultamiento de la información, es decir, un objeto tiene un “acceso público" que otros objetos
pueden utilizar para comunicarse con él. Pero el objeto puede mantener información y métodos
privados que pueden ser cambiados en cualquier tiempo sin afectar a los otros objetos que dependan
de ello.
๏ Con estos principios, un programador obtiene de los objetos el beneficio de la modularidad y el
ocultamiento de la información, y de las clases, obtiene el beneficio de la reutilización
8.- !XPrincipios P.O.O. Herencia (I) 5
Herencia
๏ La herencia es un mecanismo que permite la definición de una clase a partir de la definición de otra ya
existente. Permite crear una clase (subclase) que automáticamente (sin necesidad de volver a escribirlos)
añaden la funcionalidad (métodos y atributos) de otra clase (superclase).
๏ ¿Cuándo se ve que es útil establecer una relación de herencia? Normalmente se ve cuando se da una de
Iñaki Martín
b) Generalización: Se tienen varias clases que tienen muchos elementos comunes. Es posible que se pueda
Temario de curso JavaSE
hacer una superclase con solo lo común y dejar a las “hijas” con aquello que es diferente
• Ejemplo, se tiene una estructura de clases como las indicadas a la izquierda, es mucho mas útil no
tener que repetir atributos muchas veces, hacer una clase con los atributos comunes, y otras nuevas
que hereden (tomen) lo que es común y se queden solo con lo que les es especial a cada una:
Atributos Clase Vehículo
comunes
int matricula
Clase Coche Clase Moto Clase Camion String marca
int matricula int matricula int matricula String color
String marca String marca String marca double precio
String color String color String color
double precio double precio double precio
int numeroPlazas int numeroCadena int largoRemolque
int capacidadMaletero boolean tieneSidecar boolean tieneLitera Clase Coche Clase Moto Clase Camion
int numeroPlazas int numeroCadena int largoRemolque
int capacidadMaletero boolean tieneSidecar boolean tieneLitera
8.- !XPrincipios P.O.O. Herencia (II) 6
๏ Para que una clase herede de otra, en la declaración de la subclase, tras el nombre de esta, se debe añadir la
palabra extends seguida del nombre de la superclase
// **** CLASE COCHE, QUE HEREDA DE VEHICULO
class Coche extends Vehiculo{
......
} // fin de Coche
Iñaki Martín
๏ Ahora, al crear un objeto de la clase Coche, se puede acceder a los atributos y métodos de la superclase, por
que tambien los tiene la subclase:
Coche c1 = new Coche();
c1.setMarca(“Seat”);
c1.setPrecio(2000);
c1.pintar("Verde");
Iñaki Martín
๏ La herencia supone un ahorro enorme a la hora de escribir código, pues se pueden heredar funcionalidades
de otras clases y usarse como si fueran funcionalidades propias.
©
Temario de curso JavaSE
8.- !XPrincipios P.O.O. Herencia: Reglas (I) 8
Reglas de la herencia
✓ La clase "madre" es comunmente conocida como superclase, y las clases "hijas", como subclases
✓ Una subclase no puede "elegir" lo que hereda de su superclase, se heredan (casi) todos los miembros de la clase
superclase.
Una subclase, por lo tanto, puede utilizar los atributos y métodos de su superclase como si fueran propios. La subclase, por lo tanto, es
Iñaki Martín
Por lo tanto, aunque no se diga expresamente, una clase nueva public class SeleccionFutbol {...}
✓ Los arrays, como objetos que son, también heredan los métodos de Object, como cualquier clase:
equals(), toString(), etc
8.- !XPrincipios P.O.O. Herencia: Reglas (II) 9
✓ Java no permite herencia múltiple, esto es, un hijo de dos padres (otros lenguajes como C++ sí).
Esto puede chocar si acabamos de decir que todas las clases nuevas heredan de Object.
Si es así, ¿cómo puedo luego heredar a la vez de otra clase?.
Realmente una clase hereda implícitamente de Object si no hereda directamente de ninguna otra.
Iñaki Martín
Si una clase hereda de otra, en realidad hereda también de Object, pues la clase de la que hereda ya
heredaba de Object… Asi que de modo directo o indirecto, todas heredan de Object.
✓ Se denomina supertipo a cualquiera de las superclases del árbol de herencia de una clase (a su padre, o a
su abuelo, o a su bisabuelo, etc)
©
Temario de curso JavaSE
8.- !XPrincipios P.O.O. Herencia: Restricciones 10
Restricciones en la herencia
๏ La subclase no puede elegir lo que hereda, hereda todos los miembros de la superclase, pero puede realizar
algunas acciones que eliminen la herencia:
✓ Si una subclase no desea heredar un método tal y como está reflejado en la clase madre, puede redefinirlo.
Iñaki Martín
adelante
๏ Un método o atributo se hereda siempre salvo que la clase “madre” limite la herencia al aplicar limites a la
visibilidad en las clases hijas, declarando los métodos y atributos private, en cuyo caso, no se puede tener
visibilidad desde las subclases, con lo que NO se heredan.
Esto significa que los métodos private de la superclase, desde sus subclases, no se pueden ejecutar
directamente (aunque sí de modo indirecto, como se verá luego), y a los atributos private de una superclase,
desde sus subclases, solo se puede acceder indirectamente con métodos públicos (con getters y setters, p.e.)
Dejar claro que se “heredan” todos los métodos no private, y que un método private, puesto que no se hereda, no se puede sobrescribir. Esto no
impide que en una subclase haya un método con la misma firma que un método private existente en su superclase. Puede ocurrir, pero no es
sobrescritura, no aplican las reglas de sobrescritura. Es simplemente un método que tiene el mismo nombre que otro, en otro contexto diferente.
8.- !XPrincipios P.O.O. Herencia: Protected 11
Protected
๏ Marcando en una clase private a sus atributos, no los puede ver nadie, ni siquiera los hijos... esto parece quitar
poder a la herencia
๏ Si por otro lado, ponemos public a los atributos, se está perdiendo el principio de encapsulación, y dejando a
cualquiera acceder directamente a los miembros de una clase.
Iñaki Martín
• protected: miembro accesible desde el paquete y desde sus subclases en cualquier paquete
• <default>: Si no se indica modificador, el miembro es accesible desde las clases del mismo paquete
Herencia y constructores
๏ Es necesario tener en cuenta que, al hablar de herencia, no se heredan los constructores, asi que las
subclases deben definir su propio constructor.
๏ “Una clase hija debe tener un constructor que, lo primero que haga, es llamar al constructor de su
clase madre”. Este es uno de los principios básicos de la herencia.
Iñaki Martín
Cuidado : Si se usa una instrucción super, esta debe ser siempre la primera línea dentro del constructor
Cuidado : En el ejemplo anterior, si la superclase no tiene un constructor con los parámetros indicados, se produciría
un error de compilación.
Si no se añade constructor a la subclase, se usa el constructor de ésta por defecto (ya mencionado anteriormente), que en
este caso, hace una llamada al constructor por defecto de la superclase, que debe existir
8.- !XPrincipios P.O.O. Herencia: this 13
Uso de this
๏ this hace referencia a la propia clase donde se usa. Tiene dos usos :
1. Como si fuera un objeto, usando el punto para acceder a sus miembros. Es un uso típico en un constructor.
this.nombreAtributoPropio ;
Iñaki Martín
this.nombreMetodoPropio ;
2. Para llamar desde un constructor, a otro constructor de la misma clase
this (parametrosDeUnConstructorPropio) ;
©
class Vehiculo {
private String color;
private int numSerie;
Temario de curso JavaSE
Uso de super
๏ super hace referencia a la clase madre de la clase donde se escribe. Igual que this, tiene dos usos :
1.Como si fuera un objeto, usando el punto para acceder los miembros de la madre.
Útil cuando se ha sobrescrito un método en la clase hija, y se desea llamar al método original, o se ha hecho
shadowing de un atributo
Iñaki Martín
No se puede acceder a miembros "superiores" a la superclase (no se puede acceder a los abuelos...)
super.nombreAtributoSuperclase ;
super.nombreMetodoSuperclase;
©
2.Para llamar desde el constructor de la clase hija a algún constructor de la clase madre, como se ha visto en
los ejemplos anteriores de herencia
Temario de curso JavaSE
super (parametrosDeUnConstructorDeLaSuperclase) ;
class Coche extends Vehiculo {
private int cilindrada;
marca = mar;
} public Coche(int id, String mar, String co, double pre, int np, int cp) {
// otros métodos this(id, mar, co, pre);
public void pintar(String colorNuevo){ numPlazas = np;
color = colorNuevo; capacidadMaletero = cp;
} }
Sobrescritura
๏ La subclase hereda todos los métodos de la superclase tal como son. Si por alguna causa, un método de la
superclase no se adecúa del todo a sus necesidades, se puede sobrescribir estos métodos, es decir, volver a
escribirlos.
๏ Cuando una clase hija sobrescribe un método heredado de su superclase, anula el heredado y vale solo el
Iñaki Martín
nuevo método.
๏ Para sobrescribir se vuelve a escribir el método, manteniendo iguales la firma (esto es, tipo, nombre y
parámetros) y el tipo de retorno
O bien que el nuevo tipo de retorno sea un subtipo del heredado (retorno covariante, del cual se hablará mas adelante con otros ejemplos)
©
Override
๏ Cuando una clase sobrescribe un método, puede añadir antes del nombre del método la línea
@Override
๏ Estos elementos de Java que comienzan por @ se llama anotaciones.
Iñaki Martín
Sirven para explicar alguna característica del código, una indicación en el código de que en ese lugar ocurren cosas, que el compilador de Java debe
controlar.
๏ Esta anotación Override le dice al compilador que lo que viene a continuación es un método que
intencionadamente se desea sobrescribir
๏ ¿Como y por qué usarlo? Imaginemos que estamos escribiendo una subclase, y que queremos explícitamente
©
correctamente (en número u orden) ¿Que ocurriría en este caso? Que no estaríamos sobrescribiendo, sino
sobrecargando el método, con unos resultados no deseados.
๏ Para ello, podemos poner antes del método que deseo sobrecargar la anotación @Override. Con ella, el
compilador comprobará que realmente lo que viene detrás es un método sobrescrito, y si no, si nos
confundimos, nos avisará y no dejará que compile correctamente.
๏ Override no es obligatorio, pero es aconsejable.
8.- !XPrincipios P.O.O. Abstracción 18
Abstracción
๏ En el mundo real, no de programación, algo abstracto es algo que existe solo en el mundo mental. Existen
perros, gatos, lobos, y todos ellos son Animales. Animal es un concepto abstracto, que contiene a los otros
indicados, y que indica ciertas características de todos ellos.
๏ En programación, una clase abstracta es una clase sobre la que no se va a crear nada real, una clase que
Iñaki Martín
define las características de todas las que la hereden, una clase de la que no vamos a poder crear objetos
(comparando con el mundo real, normalmente no vamos a crear objetos de “Animal”, sino que crearemos
objetos de animales concretos: Perros, Gatos, etc).
๏ En definitiva, en ocasiones es útil definir clases de las que no pretendemos crear objetos, su único objetivo es
©
que sirvan de superclases a las clases “reales”. Nos valen así para crear moldes que obliguen a las subclases
a actuar como se haya definido en la superclase.
Temario de curso JavaSE
๏ Estas clases están solo para ser heredadas y sobrescribir métodos, y así servir de guía a las clases hijas. Es
como si una clase “obliga” a sus hijas a hacer algo que ella misma no sabe aun hacer.
๏ Para construir clases abstractas, es necesario saber como declarar métodos abstractos.
8.- !XPrincipios P.O.O. Métodos abstractos 19
Métodos abstractos
๏ Se declaran poniendo el identificador abstract en la declaración del método, antes del nombre.
๏ Como no tienen cuerpo (contenido) no llevan llaves, acaban con los paréntesis y los parámetros con los
que queremos identificar el comportamiento de la clase, y un punto y coma final:
©
Cuidado : Un método nunca puede ser declarado abstract y final a la vez. Parece bastante evidente, si
con final impedimos que un método se sobrescriba, un método abstracto que no se pueda sobrescribir
tiene poco sentido
Cuidado : Un método nunca puede ser declarado abstract y private a la vez. Se aplica el mismo
razonamiento que antes, pues un método private no se puede tampoco sobrescribir
8.- !XPrincipios P.O.O. Clases Abstractas 20
Clases abstractas
...
}
๏ Características:
a) Una clase abstracta puede tener lo mismo que una clase normal, atributos, métodos y constructores
©
De hecho es obligatorio que, como toda clase, tengan constructor, explícito o implícito.
c) Si una clase tiene algún método abstracto, ha de ser declarada abstracta obligatoriamente.
d) Sin embargo, una clase definida como abstracta puede no tener métodos abstractos, es opcional.
e) Una clase abstracta no se puede instanciar (no se pueden crear objetos de ella).
Gracias al polimorfismo, sí que se puede declarar un objeto e inicializarlo con un objeto de una clase hija, pero no de la propia clase abstracta
(ver más adelante polimorfismo)
f) Una clase abstracta se usa heredándola desde otra clase, y en esta clase, se sobrescriben los métodos
abstractos. Se han de sobrescribir obligatoriamente TODOS los métodos abstractos.
Si no se desea sobrescribir un método abstracto en la clase hija, se puede definir en ésta última el método nuevamente como abstracto (solo
que en este caso, la clase hija también habrá de ser abstracta)
8.- !XPrincipios P.O.O. Interfaces (I) 21
Interfaces
๏ Una interface es un elemento parecido a una clase, realmente, es como una clase destinada a ser en la que
todos los métodos son métodos abstractos.
๏ Está modelada para ser totalmente heredada y sobrescrita. Al “heredarse”, las clases deben desarrollar todos
los métodos descritos por la interfaz
Iñaki Martín
Hay que pensar que una interface es algo así como “un contrato”. La clase debe desarrollar lo que la interfaz ha definido, con los métodos que impone,
y de cada método, con los parámetros y retornos que se especifican en la interfaz (es la idea ya vista de método abstracto, pero llevada al conjunto de
la clase, esto es, con la idea de sobrescribir todo un conjunto de métodos).
๏ Una interfaz se “hereda” en otra clase. A la hora de heredar una interface, no se usa el verbo heredar, sino que se
©
usa implementar, y por ello, en la definición de la clase se cambia extends por implements
Temario de curso JavaSE
๏ Características:
a) Una interfaz no se puede instanciar, no se pueden hacer objetos de ella.
b) Todos los métodos que tenga serán obligatoriamente abstractos y públicos
c) Una interfaz no tiene constructor
8.- !XPrincipios P.O.O. Interfaces (II) 22
d) Una interfaz puede tener atributos, pero han de ser public static final (aunque como es obligatorio que sean
de este tipo, no es necesario que se indique explícitamente).
Estas constantes se deben inicializar en la misma instrucción de declaración.
e) Una clase que implementa una interfaz esta obligada a "implementar" todos los métodos de la interfaz.
La firma del método ha de mantenerse exactamente
Iñaki Martín
El término "sobrescribir" se usa para las clases, y para las interfaces, se usa "implementar".
f) Si la clase que implementa una interfaz no sobrescribe todos los métodos, ha de ser abstracta.
En este caso no necesita implementar los no “sobrescritos” (no necesita ni siquiera declararlos como abstractos en ella misma)
g) Una interfaz no necesita declararse abstract ni public, ni tampoco sus métodos. Implícitamente todos los
métodos son abstractos, y por ello, la interfaz tambien, así que no es necesario poner abstract al definirlos.
©
Igual pasa con los métodos que contiene, como han de ser abstracta obligatoriamente, no es necesario
indicarlo.
Temario de curso JavaSE
Además, los métodos de una interfaz no pueden ser static o final (pues no podrían sobrescribirse)
¿Y por qué son públicos los métodos? El sentido de una interfaz es "mostrar al mundo" lo que va a ser una clase. No tiene mucho sentido hacer que
sus métodos no sean públicos
h) El archivo de una interfaz se usa en el proyecto igual que una clase normal: se guarda en un fichero .java , su bytecode en un fichero .class, y existe
en los paquetes con las mismas reglas que una clase.
i) Una clase que implemente una interfaz no tiene que sobrescribir explícitamente los métodos. Puede ya haberlo hecho un supertipo de dicha clase.
Por ejemplo, si una clase Coche hereda de Vehiculo e implementa la interfaz ICirculable, los métodos de esta interfaz pueden ya estar en Vehiculo,
con lo que Coche no ha de sobrescribirlos, los hereda.
8.- !XPrincipios P.O.O. Interfaces (III) 23
implementa varias interfaces esta obligada a implementar los métodos de todas las interfaces.
No pasa nada si existe un mismo método en varias de las interfaces implementadas.
Si tienen los dos métodos la misma firma, entonces es como si fueran lo mismo, con lo que se puede sobrescribir y afecta a los dos. Si
ambos tienen la misma firma, pero distinto valor de retorno, se da un error de compilación
Iñaki Martín
✓ Implementar es “hacer que quien me implemente haya de desarrollar (escribir) mis métodos abstractos”.
✓ Pero aquí está el problema, pues una interface no puede verse obligada a desarrollar nada, dado que
puede sobrescribir nada, ni tener contenido propio, por lo que el concepto de herencia (heredar
código y poder sobrescribirlo) no tiene sentido.
m) En complemento a lo anterior, una interfaz sí puede heredar de interfaces.
✓ Esto se entiende al ver que herencia significa “todo lo que es mío es de mis hijos”, pero al contrario que
en el caso anterior, aquí una interface no hereda ningún código desarrollado, solo hereda métodos
abstractos, que en realidad es lo que ella misma tiene.
✓ Así, una interfaz al “heredar” de otra, lo que hacer es añadir los métodos de ésta última a los que ella
misma tenga
✓ Como es una herencia, se define con extends, no es implements, pues implements (implementar)
ellas.
8.- !XPrincipios P.O.O. Herencia e Implementación: gráfica actuación 24
Relación de Herencia
Relación de Implementación
Casos válidos
Temario de curso JavaSE
Dicho de otro modo, como se pueden comportar clases e interfaces al heredar o implementar;
una clase puede heredar de SOLO UNA clase
una clase puede implementar MUCHAS interfaces
una interfaz puede heredar MUCHAS interfaces
8.- !XPrincipios P.O.O. Polimorfismo (I) 25
Polimorfismo
๏ El polimorfismo se puede definir como “propiedad por la que es posible llamar a meodos sintácticamente iguales de
objetos de tipos distintos”. El significado de la definición puede ser ocnfuso, pero se podrá ver más claro según
vayamos viendo como aplicar y usar el polimorfismo en Java
๏ Java, aplicando propiedades del polimorfismo, puede hacer cosas tan interesantes como esta:
Iñaki Martín
Un objeto de una superclase puede apuntar a un objeto de cualquiera de sus subclases. Ver este código:
// Sin polimorfismo: Se crea un objeto de coche, normalmente
Coche co1 = new Coche ( 23311729,"Opel", "Azul", 39000);
๏ La ventaja mas inmediata del polimorfismo es la posibilidad de Upcasting entre clases: puedo construir
colecciones de datos (arrays por ejemplo) que contengan objetos de Vehículo... y que estos sean cosas
diferentes (Coches, Motos...). Así puedo mezclar distintos tipos de cosas en un mismo sitio:
Vehiculo v1 = new Coche ( 5252222,"Ford", "Negro", 15000);
Vehiculo Vehiculo v2 = new Moto ( 332423,"Honda", "Azul", 1200);
Vehiculo v3 = new Camion ( 665565,"Mercedes", "Blanco", 23000);
Iñaki Martín
Los métodos que ejecuta cada objeto son los de la subclase (Coche, Moto, Camion), no los de Vehículo.
arrayVe[0], como realmente es un Coche, ejecuta los métodos de un Coche:
Temario de curso JavaSE
lo cual es enormemente útil... si hacemos que un bucle opere con todos los elementos a la vez
for (int i = 0; i < arrayVe.length; i++) {
double im = arrayVe[i].calculoImpuestos(); // cada elemento hará el método de su objeto
}
Cada elemento que contiene el array, aunque todos ellos bajo el tipo Vehiculo, son internamente en realidad cosas
diferentes (Coche, Moto, Camion...).... con lo que aplicar el método calculoImpuestos() con cada uno de ellos, hará cosas
diferentes... cada objeto aplica el método que le toque. Así pues el polimorfismo se ve en que :
‣ arrayVe[i] es un objeto polimórfico pues adopta distintas formas (poli-formas): a veces es Moto, a veces, Coche…
‣ calculoImpuestos() tiene un comportamiento polimórfico, dado que hace cosas distintas, dependiendo de la
forma que tenga arrayVe[i]
8.- !XPrincipios P.O.O. Polimorfismo (III) 27
๏ Los métodos que se pueden usar polimórficamente deben existir tanto en la superclase como en las
subclases
Iñaki Martín
En el ejemplo anterior, el método calculoImpuestos() debe existir tanto en las subclases (Coche, Moto,
Camión) como en la superclase (Vehiculo)
๏ Polimorfismo permite que un objeto de una superclase pueda apuntar a un objeto de cualquiera de sus
subclases, pero no al revés
Temario de curso JavaSE
Operador InstanceOf()
๏ Anteriormente se ha mostrado un bucle que nos permitía recorrer un array de Vehiculos que realmente no se
sabe que contenían, si Vehiculos o cualquiera de sus hijos:
for (int i = 0; i < arrayVe.length; i++) {
double im = arrayVe[i].calculoImpuestos(); // cada elemento hará el método de su objeto
Iñaki Martín
Este mecanismo es enormemente potente, pero.... ¿qué ocurre si dentro del bucle deseo saber de qué tipo es
realmente cada elemento del array?
๏ Para saber a qué clase pertenece un objeto cualquiera se usa la instrucción instanceof:
©
๏ Importante: instanceof dice si un objeto es referencia de una clase .. o de cualquiera de sus subclases
arrayVe[i] instanceof Coche --> // true si arrayVe[i] es un objeto de la clase Coche o DE
// ALGUNA DE LAS SUBCLASES QUE TENGA COCHE
arrayVe[i] instanceof Vehiculo --> // true si arrayVe[i] es un objeto de la clase Vehiculo o DE
// ALGUNA DE LAS SUBCLASES QUE TENGA VEHICULO
8.- !XPrincipios P.O.O. Polimorfismo: upcasting y downcasting 29
Upcasting y downcasting
Coche
Coche co1 = unVehiculoCoche ; // ERROR
Coche
Coche co1 = (Coche) unVehiculoCoche ; // correcto
El hecho es que unVehiculoCoche es internamente un Coche, vale, pero para el mundo es un Vehiculo. Visto desde fuera, un Vehiculo puede
ser... muchas cosas (por polimorfismo...:-), asi que una asignación directa de un Vehiculo a un objeto Coche no sabe resolverla (¿será
unVehiculoCoche realmente un Coche? :-). Hay que decirle en qué queremos convertir el Vehiculo... con un casting.
Upcasting viene a significar "ascender en el arbol familiar", esto es, un elemento se asigna a un "elemento superior en el album"
Downcasting viene a significar "descender en el arbol familiar", esto es, un elemento se asigna a un "elemento inferior en el album"
8.- !XPrincipios P.O.O. Polimorfismo: upcasting en parámetros 30
Polimorfismo en interfaces
๏ Se puede aplicar polimorfismo a las Interfaces, del mismo modo
que se aplica a las herencias entre clases. Como definición:
Al igual que las clases abstractas, una interfaz no © crear objetos de si misma, pero sí de clases que la
implementan, esto es, una variable de tipo interfaz puede almacenar objetos de sus subclases
Iñaki Martín
class Fruta{
- Ejemplo: String nombre;
int precio;
‣ En el primer caso creamos un objeto de Manzana int abonoNecesario;
usando su superClase Fruta. void ponerPrecio(int f) {
precio = f;
‣ En el segundo caso creamos un objeto de }
©
‣ En ambos casos no puedo usar métodos en estos class Manzana extends Fruta implements ICampo{
void ponerNombre(String n) {
objetos que no esten declarados en la
Temario de curso JavaSE
nombre = n;
}
superInterfaz o superClase @Override
public void echarComida(int k) {
interface ICampo{ abonoNecesario = k;
public void echarComida(int kil); }
} }
๏ instanceof también considera las “herencias” por interfaz igual que las de por clase, esto es,
unObjeto instanceof unaInterfaz da true, si el objeto es de una clase que implemente la interfaz unaInterfaz
8.- !XPrincipios P.O.O. toString() 33
toString()
๏ toString() es un método heredado de Object, por lo que lo tienen todas las clases de Java. Pretende devolver en un
String el valor de un objeto.
๏ Pero claro, cuando se trata de clases propias, Java no sabe como “escribir” el valor de nuestros atributos…
๏ Por ello, el método toString() que se hereda inicialmente devuelve una cadena compuesta por el paquete al que
Iñaki Martín
๏ La mejor práctica es que en nuestras clases se sobrescribe devolviendo un String a nuestro gusto, que será cómo
se desea representar un objeto de la clase:
Temario de curso JavaSE
class MiClaseCoche {
String marca;
String modelo;
double consumo;
int precio;
๏ El método toString() se invoca de forma automática cuando se nuestra un objeto mediante la instrucción
System.out.println o System.out.print. Esto quiere decir que las siguientes instrucciones son equivalentes:
System.out.println(unObjeto.toString());
System.out.println(unObjeto);
8.- !XPrincipios P.O.O. Polimorfismo : covariant y genéricos 34
Desde Java 5, se permite que el tipo de retorno de un método sobrescrito sea un subtipo del tipo declarado como valor de
retorno del método que se sobrescribe. A esto se le denomina covariant return o retorno covariante
public class Animal {
Iñaki Martín
Animal salta(int c) {
return new Animal();
}
}
class Gato extends Animal {
Gato salta(int c) { // Esto vale desde JSE5
return new Gato();
}
©
}
Temario de curso JavaSE
Supongamos que tengo una clase Vehículo y una subclase Coche (que hereda de vehículo)
Suponiendo una aplicación normal de polimorfismo, siendo Coche subclase de Vehiculo, cabría esperar que esta declaración fuera correcta;
ArrayList <Vehiculo> lista = new ArrayList<Coche>(); }
class PruebaWidening {
static void probar(int x) { System.out.println("eligiendo método con int "); }
static void probar(long x) { System.out.println("eligiendo método con long "); }
static void probar(double x) {System.out.println("eligiendo método con double "); }
long l = 9;
float f = 9.0f;
probar(b); // imprime ”eligiendo método con int”
probar(s); // imprime ”eligiendo método con int”
probar(l); // imprime ”eligiendo método con long”
Temario de curso JavaSE
• Si se ha de decider entre hacer boxing o hacerse widening, el compliador siempre elige widening
• Si se ha de decider entre usar var-args o hacerse widening, el compliador siempre elige widening
class PruebaWidening2 {
static void probar(Integer x) { System.out.println("eligiendo método con Integer "); }
static void probar(long x) { System.out.println("eligiendo método con long "); }
static void probar(int a, int b) { System.out.println("eligiendo método con int, int "); }
static void probar(short... k) { System.out.println("eligiendo método con var-args de short "); }
public static void main(String[] args) {
int i = 34;
short s = 56;
probar(i); // imprime ”eligiendo método con long”
probar(s); // imprime ”eligiendo método con int, int”
}
}
• Y puestos a comparar, si se ha de decider entre usar var-args o hacerse boxing, el compliador siempre ellige boxing
8.- !XPrincipios P.O.O. Widening (II) 37
• Cuidado, que no se puede aplicar widenenig y luego boxing de modo conjunto y en ese orden.
Por ejemplo, un argumento int no puede aplicarse a un método con parametro Long (Long, como wrapper), pues deberia
hacer estas conversiones:
Iñaki Martín
class PruebaMalUsoWidening {
int k = 34;
probar(k); // ERROR !! No puedo pasar de int a Long. Si fuera long, no habria problema
}
}
Pero ¿que ocurre en la tercera llamada, que versión sobrecargada se usará? Se podría pensar: la del Perro, pues en
tiempo de ejecución, se pasa un objeto Perro al método. Pero no, no es así. La salida por pantalla es ;
Version con param Animal
puesto que la sobrecarga se resuelve en tiempo de compilación, con lo que aun no hay objeto Perro, y se compila el
método del objeto base (Animal) , el del parámetro (new Perro() ) . Hay un segundo ejemplo en la pagina siguiente.
Dicho de otro modo, con polimorfismo no se determnina que método sobrecargado se va a usar. Polimorfismo solo se
aplica cuando se debe decidir que método sobrescrito hay que usar.
8.- !XPrincipios P.O.O. Sobrecarga/sobrescritura en ejecución/compilación (II) 39
caballoObj.salta();
animalRefCaballoObj.salta();
ma.pinta(animalObj);
ma.pinta(caballoObj);
ma.pinta(animalRefCaballoObj);
}
}
• En este ejemplo se tiene, por un lado, una sobrescritura del método salta(), y por otra una sobrecarga del método pinta()
• Posteriormente creamos tres objetos, con y sin aplicación de polimorfirmo
• ¿Qué resultados dan las llamadas de los dos métodos con los tres objetos creados?
Saltamos en el método salta de un Animal
Saltamos en el método salta de un Caballo
Saltamos en el método salta de un Caballo
Pintamos en el método pinta con un Animal
Pintamos en el método pinta con un Caballo
Pintamos en el método pinta con un Animal