Jyoc Java Cap08 Principios Poo

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 39

8.- !XPrincipios P.O.O.

TEMARIO DE CURSO
PROGRAMACIÓN JAVA SE
Iñaki Martín

CAPÍTULO 8
PRINCIPIOS DE
©

PROGRAMACIÓN
Temario de curso JavaSE

ORIENTADA A OBJETOS (POO)

© 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

Una clase con un método abstracto es a su vez una clase abstracta


método sustituya al de la madre Se construyen con la intención de que las clases heredadas tengan
• Los métodos deben tener los mismos argumentos, en numero y orden
• El método sobrescrito puede tener un modificador de acceso menos restrictivo
que sobrescribir obligatoriamente el método con algún código.
• Los métodos y la clase deben llevar la palabra abstract.
• Los métodos no llevan llaves, acaban con los paréntesis y dos puntos
Herencia • Una clase abstracta no se puede instanciar (no se pueden crear objetos de ella).
©

La herencia es un mecanismo que permite la definición de una


clase a partir de la definición de otra ya existente. Interfaz
• La subclase (clase hija) incorpora todos los métodos y atributos de la clase madre
Temario de curso JavaSE

• 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

programar. Veremos en este capítulo esas técnicas, que son:

๏ Sobrecarga (éste ya se analizó previamente, al estudiar los métodos)


๏ Encapsulado
๏ Herencia
๏ Sobrescritura
๏ Abstracción
๏ Polimorfismo
8.- !XPrincipios P.O.O. Encapsulado 4

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
©

desde fuera de la clase.


Es la clase con sus métodos de acceso quien controla y valida cómo o quién puede trabajar con sus atributos.
Temario de curso JavaSE

๏ 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

estas dos vías: especialización o generalización.


a) Especialización: Se tiene una clase (Vehiculo). Si se le añade mas información, se hace otra cosa
(Coche). Se puede intuir que se puede hacer una superclase con la clase que ya tse tenia (Vehiculo) y una
clase hija que solo tenga lo que la hace especial (Coche). Además, se puede reutilizar lo que es un
Vehículo para "especializar" y crear nuevos vehiculos especiales (moto, camión, furgoneta, ...)
©

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

Ejemplo de superclase y subclases


// ****** CLASE VEHICULO
class Vehiculo{
// atributos
private int numIdendificador;
private String marca;
private String color; Vehiculo
©

private double precio;


// métodos getters y setters (solo 1 como ejemplo)
public String getMarca(){
return marca;
Temario de curso JavaSE

} Coche Moto Camion


public void setMarca(String mar){
marca = mar; Clases de mi familia
}
// otros métodos
public void pintar(String colorNuevo){
color = colorNuevo;
}
}// fin de Vehiculo

// ****** CLASE COCHE // ****** CLASE MOTO // ****** CLASE CAMION


class Coche extends Vehiculo{ class Moto extends Vehiculo{ class Camion extends Vehiculo{
private int numPlazas; private int numCadena; private int lRemolque;
private int capacidadMaletero; private boolean sidecar; private boolean litera;

public int getNumeroPlazas(){ public int getNumCadena(){ public int getLRemolque(){


return numPlazas; return numCadena; return lRemolque;
} } }
public void setNumPlazas(int numpla){ public void getNumCadena(int numcad){ public void getLRemolque(int lrem){
numPlazas = numpla; numCadena = numcad; lRemolque = lrem;
} } }
} // fin de Coche } // fin de moto } // fin de camion
8.- !XPrincipios P.O.O. Herencia (III) 7

๏ 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

todo lo que es la superclase y además sus propios atributos


✓ No se heredan los constructores. Es una de las excepciones al anterior "se hereda todo".
Un constructor vale para construir un tipo de objeto, con lo que es específico para esa clase, no puede usarse directamente por dos
clases distintas, madre e hija. Cada clase de be tener su propio constructor (y en herencia, con más razón, como se ve mas adelante)
✓ La subclase puede tener sus propios miembros (métodos y atributos propios), que no comparte con su
©

superclase, ni con sus "hermanas" (otras clases que hereden de su superclase).


✓ La herencia se puede aplicar múltiples veces, en cascada, dando lugar a una jerarquía de clases (abuelos,
Temario de curso JavaSE

padres, hijos, nietos… hermanas, tías, primas…)


✓ Realmente, el lenguaje Java es una estructura completa de herencia, todas las clases parten de una superclase
inicial (llamada Object) de la que heredan otra clases, y de estas otras más, hasta construir todos los elementos
del lenguaje. Object es, asi dicho, como la “madre de todas las clases de Java”.
Cualquier clase que un programador construya, sin que él lo indique explícitamente, hereda de la clase Object, con lo que tiene algunos
comportamientos predefinidos que puede usar (se verán algunos más adelante).

Por lo tanto, aunque no se diga expresamente, una clase nueva public class SeleccionFutbol {...}

realmente es public class SeleccionFutbol extends Object {}

✓ 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

Para ello, puede volver a escribir (sobrescribir) el método de la superclase.


A veces, el método de la madre no vale completamente para cada hijo, sino que estos necesitan algo un poco mas especial para ellos.
Esta acción (sobrescritura) tiene sus propias reglas, descritas más adelante
✓ Si una subclase no desea heredar un atributo tal y como está, puede redefinirlo. Para ello, puede volver a
©

escribir el atributo de la superclase.


Esta acción (parecido a la sobrescritura) se denomina shadowing, y tiene sus propias reglas, descritas más
Temario de curso JavaSE

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

๏ ¿No existe un modificador de acceso intermedio? Efectivamente, se trata de protected


๏ Un atributo (o método) marcado como protected puede ser usado por una clase y cualquiera de sus
descendientes
๏ En resumen, así quedan los modificados de acceso hasta ahora conocidos:
©

• public: miembro (atributo o método) accesible desde todo el programa


• private: miembro accesible sólo desde la clase donde se declara. No es accesible ni siquiera por subclases
Temario de curso JavaSE

• 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

Si uso en una variable el modificador …


Se puede acceder a esa variable desde …? public protected default private

Un miembro de la misma clase? SI SI SI SI


Un miembro de una clase del mismo paquete? SI SI SI NO
Un miembro de una subclase del mismo paquete? SI SI SI NO
SI SI, pero solo a través
Un miembro de una subclase de distinto paquete? NO NO
de herencia
Un miembro de un clase (que no es subclase) de
SI NO NO NO
distinto paquete?
8.- !XPrincipios P.O.O. Herencia: Constructores 12

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

๏ ¿Cómo se hace la llamada al constructor de la clase madre?


a) Explícitamente: Utilizando la llamada super(parametros), que asi se llama al constructor de la clase
madre.
Se puede llamar a cualquiera de los constructores de la superclase, siempre coincidiendo con la
©

firma del constructor (numero, tipo y orden de los parámetros).


b) Implícitamente: Si no se hace llamada al constructor de la superclase, el compilador añade la llamada al
Temario de curso JavaSE

constructor sin parámetros de la superclase ( super() )


public Coche(int id, String mar, String co, double pre, int np, int cp) {
super(id, mar, co, pre);
numPlazas = np;
capacidadMaletero = cp;
}

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

public Vehiculo(String color, int numSerie) {


this.color = color; // this.color hace referencia al atributo color de ESTA clase
this.numSerie = numSerie;
}
public Vehiculo(String solocolor){
this(solocolor, 0); // this() hace una llamada a otro constructor de ESTA clase
}

public void rellamarAPintar(String col){


this.pintar(col); // this.pintar() hace una llamada a un método de ESTA clase
}
}
8.- !XPrincipios P.O.O. Herencia: super 14

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;

public Coche(String color, int numSerie, int cilindrada) {


super(color, numSerie); super() hace una llamada a algun
this.cilindrada = cilindrada; constructor de la CLASE MADRE
}

public void pintar(String col) { // Este metodo esta sobrescrito


super.pintar(col); super.pintar() hace una llamada al
if (color.equals("Negro")) { método sobrescrito de LA CLASE
System.out.println("¡Rebajado este mes!"); MADRE
}
Muy util cuando se quiere hacer lo
}
que hace la clase madre, y algo
} // fin de Coche
mas
8.- !XPrincipios P.O.O. Herencia : Ejemplo completo 15

Llamada al método de la superclase al que se está


Ejemplo completo de superclase y subclase sobrescribiendo. Se obtiene el valor del impuesto segun método
de la superclase, y luego se especializa con operaciones propias
// ****************** CLASE VEHICULO Vehiculo
class Vehiculo{ Llamada al otro constructor
// atributos de la propia clase, para que
protected int numIdentificador; haga el trabajo básico (incluido
protected String marca; llamar al constructor super), y
protected String color; Llamada al constructor de luego asigne los atributos
Coche
Iñaki Martín

protected double precio; la superclase, con los propios


public Vehiculo(int id, String ma, String co, double p) { parámetros que ésta
numIdentificador = id; necesita
marca = ma;
color = co;
precio = p; // *************************** CLASE COCHE
} class Coche extends Vehiculo{
private int numPlazas;
// métodos getters y setters (uno de ejemplo, añadir el resto) private int capacidadMaletero;
©

public String getMarca(){


return marca; public Coche(int id, String mar, String co, double pre) {
} super(id, mar, co, pre);
public void setMarca(String mar){ }
Temario de curso JavaSE

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;
} }

// imaginamos el impuesto un 10% precio public int getNumeroPlazas(){


public double calculoImpuestos(){ return numPlazas;
return precio * 0.10; } Método propio de Coche,
} public void setNumPlazas(int numpla){ no existe en Vehiculo
}// -- fin de Vehiculo numPlazas = numpla;
}
public void setNumPlazas(int numpla){
numPlazas = numpla;
Atributos de la subclase (propios) }
public void recortarMaletero(int tam){
Constructor de la subclase solo capacidadMaletero -= tam;
con los atributos de la superclase }
@Override
// imaginamos este impuesto un 5% precio mas de lo normal
Constructor de la subclase con los
atributos de la superclase y os propios public double calculoImpuestos(){
double importeNormal = super.calculoImpuestos();
Método sobrescrito que return importeNormal *1.05;
sustituye al de la superclase }
} // -- fin de Coche
8.- !XPrincipios P.O.O. Sobrescritura (I) 16

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)
©

๏ El nuevo método puede:


‣usar la funcionalidad del padre y hacer más cosas: programación incremental
Temario de curso JavaSE

‣ser totalmente diferente


๏ Si cuando se desea sobrescribir un método se modifican los parámetros o el valor de retorno, no estamos ante un caso de sobrescritura, sino que
realizaría una sobrecarga de métodos: dos métodos que tienen con el mismo nombre, pero distintos parámetros. En definitiva, dos métodos
diferentes, que no se anulan.
๏ No se puede sobrescribir un método si es STATIC o FINAL
๏ Cuidado, que solo se sobrescribe un método que se hereda. Si el método no se hereda, por ejemplo, por que tiene un modificador private, como
no se puede sobrescribir, se está creando un método nuevo.
๏ El método sobrescrito puede tener un modificador de acceso menos restrictivo que el de la superclase. Por ejemplo, el método de la superclase
puede ser protected y la versión sobrescrita puede ser public. Pero nunca puede aplicarse un modificador más restrictivo (p.e., en la clase padre
sea protected y en la hija private)
๏ El tipo de retorno de un método sobrescrito ha de ser el mismo que el tipo de retorno de la superclase, o de una subclase de este tipo.
๏ En el capítulo de excepciones se verán las reglas que aplican a estas con la sobrescritura.
8.- !XPrincipios P.O.O. Sobrescritura (II) 17

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
©

sobrescribir un método de la superclase.


๏ Puede ocurrir que a la hora de escribir el método, no lo hagamos correctamente, no indiquemos los parámetros
Temario de curso JavaSE

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 denominan métodos abstractos a aquellos que se construyen con la intención de que no se


definan donde se crean, sino que se espera que clases heredadas lo hagan,
๏ Un método abstracto es un método declarado pero sin código alguno.
Sirven para identificar qué han de hacer las cosas, no cómo.
Iñaki Martín

๏ 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:
©

public abstract double superficie();


Temario de curso JavaSE

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

๏ Una clase abstracta es la que contiene, al menos, un método abstracto


๏ Se identifican por llevar el identificador abstract en la declaración de la clase, antes del nombre de la clase.
public abstract class Figura{
Iñaki Martín

...
}

๏ 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.

b) Los métodos pueden ser tanto abstractos como normales


Temario de curso JavaSE

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

[modificadorAcceso] interface nombreInterfaz { (métodos) }


public interface movimientos {
void mover(int x, int y); // método abstracto, no lleva código
int girar(int g); // método abstracto, no lleva código
}

public class EstaClase implements movimientos { … }

๏ 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

public interface movimientos // no es necesario public abstract interface movimientos


int girar(int g); // no es necesario public abstract int girar (int g);
}

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

j) Una clase puede implementar varias interfaces.


✓ Una clase no tiene herencia multiple, pero sí implementación múltiple. En estos casos, la clase que

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

k) Una interfaz NO puede implementar otra interfaz.


✓ Esto tiene lógica entendiendo qué es una interfaz y qué es implementar.

✓ 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

no puede tener código desarrollado, solo declaraciones de acciones (métodos abstractos).


©

l) Una interfaz NO puede heredar de otra clase.


✓ Esto tiene la misma no-lógica del caso anterior. Si una interface no puede desarrollar ningún código, no
Temario de curso JavaSE

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)

supondría que algo "se va a desarrollar", que no es el caso.


✓ Una interfaz que herede de otras, al ser usada, obligará a la clase a impementar los métodos de todas

ellas.
8.- !XPrincipios P.O.O. Herencia e Implementación: gráfica actuación 24

Relación de Herencia
Relación de Implementación

Clase A Interfaz X Interfaz Y


Iñaki Martín

Clase B Clase C Interfaz R Clase D Interfaz Z


©

Casos válidos
Temario de curso JavaSE

• La Clase B hereda de Clase A


• La Clase C hereda de Clase A e implementa la Interfaz X
• La Clase D implementa la Interface X y la Interface Y
• La Interfaz Z hereda de Interface X y de Interface Y
Casos inválidos
• La Interfaz R no puede heredar de Clase A
• La Interfaz R no puede implementar la Interfaz X

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);

// Con polimorfismo: Se crea un objeto de coche, y se ASOCIA A UN OBJETO DE VEHICULO


Vehiculo v1 = new Coche ( 5252222,"Ford", "Negro", 15000);
©

// Con polimorfismo: Se crea un objeto de moto, y se ASOCIA A UN OBJETO DE VEHICULO


Vehiculo v2 = new Moto ( 332423,"Honda", "Negro", 1200);
Temario de curso JavaSE

Al hacer Vehiculo v1 = new Coche(...), se construye un objeto v1 que “es un


coche, pero vestido con una capucha de Vehículo. Internamente es un Coche, pero
para el exterior, actúa como un Vehículo, y todo el mundo lo ve como un vehículo”
En realidad, lo que tenemos es un referencia de un objeto tipo Vehículo, pero que apunta a un objeto Coche.
Por pasarlo al lenguaje habitual, v1 se comporta como “la parte heredada de Vehículo que hay en Coche”, si se quiere, algo más vulgar,
podemos llamarlo un “Vehículo-Coche”, Vehículo por fuera, Coche por dentro

Vehiculo v1 = new Coche ( 5222,"Ford");


Vehiculo v2 = new Moto ( 3323,”Honda");
Vehiculo v3 = new Camion (5345,"Pegaso");
SOY UN SOY UN SOY UN
VEHICULO VEHICULO VEHICULO

Parecen Vehículos, pero la verdad es que son otras cosas….


8.- !XPrincipios P.O.O. Polimorfismo (II) 26

๏ 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

Vehiculo[] arrayVe = new Vehiculo[3];


arrayVe[0] = v1; // meto un Coche en el array
Coche Moto Camion arrayVe[1] = v2; // meto una Moto en el array
Clases de mi familia arrayVe[2] = v3; // meto un Camión en el array

★ ¿Cómo actúan los elementos del array?


©

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

double imp1 = v1.calculoImpuestos(); // efectua el método calculoImpuestos... de la clase COCHE


double imp2 = v2.calculoImpuestos(); // efectua el método calculoImpuestos... de la clase MOTO
double imp3 = v3.calculoImpuestos(); // efectua el método calculoImpuestos... de la clase CAMION

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

Polimorfismo: escenarios y reglas

Métodos que se pueden usar

๏ 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)

Dirección del polimorfismo


©

๏ 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

Vehiculo v1 = new Coche(...); // permitido


Coche c = new Vehiculo(…); //¡NO permitido!

¿por qué? pues se ve claro si se analiza que:


• caso 1, un coche es un vehículo, así que cualquier método de la clase Vehículo existe (ya esté
sobrescrito o no) en la clase Coche, así que v1.cualquierOperación(...); será siempre correcto
• caso 2, un vehículo no es un coche, por lo que sería un error tratar de invocar al método
c.recortarMaletero(); pues éste no existe para un vehículo

Ante la duda de cuando usar polimorfismo, como norma:


“Un array de objetos puede contener cualquier objeto que pase la prueba del ES-UN sobre el tipo de dato
con el que se declaro el array. Si tengo un array de Vehiculos, puedo tener un objeto que sea de tipo
Coche, pues un Coche ES-UN Vehiculo (suponiendo que un Coche hereda de Vehiculo)”
8.- !XPrincipios P.O.O. Polimorfismo : instanceof 28

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:
©

UnObjeto instanceof UnaClase devuelve true si UnObjeto es una instancia de UnaClase


Temario de curso JavaSE

for (int i = 0; i < arrayVe.length; i++) {


if (arrayVe[i] instanceof Coche) {
double im = 0; // este mes es gratis :-)
}else{
double im = arrayVe[i].calculoImpuestos();
}
}

๏ 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

★ Upcasting: Se trata de asignar a una superclase un objeto de una subclase.


Este es el concepto que se ha visto anteriormente al hablar de polimormismo
No necesita de casting explícito (añadido expresamente en el programa) Se hace casting automático si es necesario
Iñaki Martín

Vehiculo v1 = new Coche(...); // upCasting clásico de polimorfismo Vehiculo


Coche = Coche

★ Downcasting: Se trata de asignar a una subclase un objeto de una superclase.


©

Necesita de casting explícito (añadido expresamente en el programa)


Vehiculo unVehiculoCoche = new Coche( );
= Vehiculo
Temario de curso JavaSE

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 llamadas a métodos (upcasting en parámetros)


๏ Se puede aplicar polimorfismo en los parámetros de un método, al definir el método.
๏ Se define el parámetro en el método con el nombre de la superclase.
๏ Así, cuando se llame al método, se puede indicar en el parámetro un objeto de la superclase o
cualquiera de sus subclases
Iñaki Martín

public void nuevaMarca2( Vehiculo miv ){


char inicial = miv.getMarca().charAt(0);
String resto = miv.getMarca().substring(1);
miv.setMarca(inicial + resto);
©

Coche coche1 = new Coche(5252222, "Ford", "Negro", 15000);


Temario de curso JavaSE

Moto moto1 = new Moto (332423, "Honda", "Negro", 1200);


Vehiculo vehi1 = new Coche(8872222, "Dacia", "Gris", 150);
nuevaMarca(coche1);
nuevaMarca(moto1);
nuevaMarca(vehi1);

Habiendo definido el parámetro como


Vehiculo, admite argumentos de tipo
Vehiculo, Coche, Moto o Vehiculo-Coche
8.- !XPrincipios P.O.O. Polimorfismo: upcasting en retorno 31

Polimorfismo en llamadas a métodos (upcasting en resultado)


๏ Se puede aplicar polimorfismo en los valores de retorno de un método, al definir el método.
๏ Se define el valor de retorno en el método con el nombre de la superclase.
๏ Asi, cuando se llame al método, se puede esperar recoger un objeto de la superclase o cualquiera de
sus subclases
Iñaki Martín

Sin problemas, ejecución correcta


public Vehiculo elMasCaro(Coche c, Moto m) {
if (c.getPrecio() > m.getPrecio()) { ERROR: un coche no puede
return c; recibir un Vehiculo (el
Vehiculo carete = elMasCaro(coche1, moto1); polimorfismo no es bidireccional)
}
return m;
©

Coche cochecaro1 = elMasCaro(coche1, moto1);


}
Coche cochecaro2 = (Coche) elMasCaro(coche1, moto1);
System.out.println(cochecaro2.getPrecio());
Temario de curso JavaSE

Interesante. Al convertir con casting lo


que se devuelve en un Coche, puedo
almacenarlo en un Coche...en
compilación no da error. Pero si en
ejecución resulta que el método no
Combinando con el apartado anterior, los parámetros del método también devuelve un Coche, se da un
podían ser polimórficos, funcionando todo exactamente igual ClassCastException
public Vehiculo elMasCaro(Vehiculo c, Vehiculo m) {
if (c.getPrecio() > m.getPrecio()) {
return c;
}
return m;
}
8.- !XPrincipios P.O.O. Polimorfismo en interfaces 32

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 }
©

Manzana usando su superInterfaz Campo. }

‣ 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); }
} }

public class PoliInterfaces3 {


public static void main (String ... args) {
Fruta f = new Manzana();
f.ponerPrecio (23);
// f.ponerNombre(23); // no se puede, pues ponerNombre no esta en Fruta

ICampo c = new Manzana();


c.echarComida(8);
// c.ponerNombre(78); // no se puede, pues ponerNombre no esta en Campo
}
}

๏ 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

pertenece la clase del objeto, el nombre de la propia y la referencia de memoria de este.

MiClaseCoche m = new MiClaseCoche ();


System.out.println (m.toString ()); // La salida por consola es : prueba.MiClaseCoche@677327b6
©

๏ 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;

public String toString() {


return “La marca es " marca + " y el modelo es " + modelo;
}
}

๏ 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

Temas avanzados Polimorfismo en metodos sobrescritos (covariant return)

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

Temas avanzados Polimorfismo con tipos genéricos

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>(); }

Sin embargo, da error !! ¿Por que?


Pues por que aunque Coche es una subclase de Vehiculo, un ArrayList de Coche no es una subclase de un ArrayList de Vehiculo
Un ArrayList no es una subclase de un Arraylist, mas allá de lo que contenga cada uno.
Y es que, dada la declaración anterior que se ha hecho, si se permitiera, se debería permitir que alguien escribiera luego:
lista.add( new Vehiculo() )
puesto que el ArrayList se ha declarado de tipo Vehiculo, pero como se ha construido con Coches, no puede almacenar Vehículos
(Recordar que la herencia es en dirección contraría, un Vehículo NO ES un Coche)
8.- !XPrincipios P.O.O. Comparativa sobrecarga - sobrescritura 35

Temas avanzados Resumen comparación Sobrecarga - Sobrescritura

En un método sobrecargado En un método sobrescrito


Iñaki Martín

Argumentos a pasar Deben cambiar No pueden cambiar

Tipo que devuelve


Pueden cambiar No pueden cambiar, salvo uso de covariant return
(retorno)
Pueden eliminarse o reducer su ambito
©

Excepciones Pueden cambiar No deben enviar checked exceptions nuevas o de


Temario de curso JavaSE

ambito más amplio al del “supermétodo”


No puede ser mas restrictivo,
Nivel de acceso Pueden cambiar
aunque puede ser menos restrictive
Como parámetro se slige el tipo referencia Como parámetro se slige el tipo Objecto (el que esta
Llamada al método (NO el que esta en el heap). Esta seleccion en el heap). Esta seleccion se hace en tiempo de
se hace en tiempo de compilacion ejecucion (runtime)
8.- !XPrincipios P.O.O. Widening (I) 36

Temas avanzados Widening ( I )


• Cuando hay varios métodos sobrecargados, ¿cuál de ellos se elige si el argumento que se pasa en la llamada es ambiguo?
El compilador, siempre que dude entre parámetros de tipo PRIMITIVO (no vale con objetos) elige simpre:
- Si hay una version del método con parámetro igual que el tipo del dato pasado, elige esta (algo normal, ¿no?)
- Si no existe un tipo igual, se usa el método con el argumento más pequeño disponible, que sea más grande que el
parametro. A esta acción se le denomima widening
Iñaki Martín

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 "); }

public static void main(String[] args) {


byte b = 9;
short s = 9;
©

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

probar(f); // imprime ”eligiendo método con double”


}
}

• 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

Temas avanzados Widening ( II )

• 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

‣ Primero de int a long mediante widening


‣ Luego de long a Long, por autoboxing, pero es demasiado ya para el compilador encadenar ambas acciones

class PruebaMalUsoWidening {

static void probar(Long x) {


©

System.out.println("eligiendo método con Long ");


}

public static void main(String[] args) {


Temario de curso JavaSE

int k = 34;
probar(k); // ERROR !! No puedo pasar de int a Long. Si fuera long, no habria problema
}
}

• Resumen de reglas de widening


1. Widening busca el mas pequeño de los mayores tipos de parametros disponible
2. No se puede hacer widening entre wrappers
3. No se puede hacer widening y luego boxing
4. Se pueden combinar métodos sobrescritos que obliguen a aplicar var-args o widening or boxing. Siempre se
prefiere widening
8.- !XPrincipios P.O.O. Sobrecarga/sobrescritura en ejecución/compilación (I) 38

Temas avanzados Sobrecarga/Sobrescritura en compilación/ejecución (I)


• Cuando se va a ejecutar un método sobrescrito, la elección de qué método se ejecuta (esto es, de qué clase en el árbol
de clases se va a coger el método) se realiza en tiempo de ejecución, dependiendo de la referencia del objeto que llame
al método.
class Animal { }
class Perro extends Animal { }
• Sin embargo, con la sobrecarga, qué método se class ProbarAnimales {
Iñaki Martín

llama se decide en tiempo de compilación, con el


public void probar (Animal a) {
tipo de referencia del parámetro que se invoca. Si se System.out.println (“Version con param Animal");
invoca a un método pasando una referencia de un }
public void probar (Perro h) {
objeto Vehículo, aunque el método espera recibir un System.out.println ("Version con param Perro");
Coche, se llama al método de Vehículo, aunque el }
Vehículo se haya declarado como un objeto Coche
©

public static void main (String[] args) {


ProbarAnimales a = new ProbarAnimales ();
Animal animalObj = new Animal ();
La salida de las dos primeras llamadas a probar()
Temario de curso JavaSE

Perro perroObj = new Perro ();


es lo esperado normalmente: a.probar (animalObj);
a.probar (perroObj);
Version con param Animal Animal referenciaDeAnimalAPerro = new Perro();
Version con param Perro a.probar(referenciaDeAnimalAPerro);
}
}

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

Temas avanzados Sobrecarga/Sobrescritura en compilación/ejecución (II)


• Otro ejemplo del caso explicado en el apartado anterior
class Animal {
public void salta() {
System.out.println("Saltamos en el método salta de un Animal"); }
}
class Caballo extends Animal {
Iñaki Martín

public void salta() {


System.out.println("Saltamos en el método salta de un Caballo"); }
}
class MisAnimales {
public void pinta(Animal a) { System.out.println("Estamos en el método pinta con un Animal"); }
public void pinta(Caballo c) { System.out.println("Estamos en el método pinta con un Caballo "); }

public static void main (String [] args) {


MisAnimales ma = new MisAnimales();
©

Animal animalObj = new Animal();


Caballo caballoObj = new Caballo();
Animal animalRefCaballoObj = new Caballo();
animalObj.salta();
Temario de curso JavaSE

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

También podría gustarte

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy