Computing">
Herencia, Polimorfismo y Composicion
Herencia, Polimorfismo y Composicion
Herencia, Polimorfismo y Composicion
PROGRAMACIÓN clases
CONTENIDO
Composición
Herencia
Concepto
Herencia en Java
Superclases y subclases
Polimorfismo
Concepto
Upcasting y downcasting
El operador de casting
El operador instanceOf
1
22/04/2019
COMPOSICIÓN
Vamos a ver el concepto de herencia que es imprescindible para
la reutilización de código y la descomposición de problemas en
subproblemas para su resolución.
Pero antes hagamos un repaso al concepto de composición visto
con anterioridad y que nos ha servido para reutilizar código
COMPOSICIÓN
Revisaremos con la reutilización de las clases a través de la composición, a través de
ejemplos. Comenzaremos con la clase Autor (Author)
2
22/04/2019
COMPOSICIÓN
Un libro (Book) es escrito por un autor (Author): usando un variable miembro "Objeto"
3
22/04/2019
COMPOSICIÓN
Veamos otro ejemplo de reutilización de una clase a través de la composición,
supongamos que tenemos una clase llamada Punto (Point), definida como se muestra
en el diagrama de clase anterior.
COMPOSICIÓN
Supongamos que necesitamos una nueva clase llamada Línea (Line), podemos diseñar
la clase Línea reutilizando la clase Punto a través de la composición. Decimos que
"Una línea se compone de dos puntos" o "Una línea tiene dos puntos". La composición
exhibe una relación “tiene-un".
4
22/04/2019
ACTIVIDAD 1
COMPOSICIÓN
Supongamos que tenemos una clase llamada Punto (Point), definida como se muestra
en el diagrama de clases. Una clase llamada Círculo (Circle) está diseñada como se
muestra en el diagrama de clase.
5
22/04/2019
HERENCIA
Al inicio hemos dicho que la herencia es imprescindible para la reutilización
de código y la descomposición de problemas en subproblemas para su
resolución.
En la POO la herencia consiste en la creación de clases a partir de otras ya
existentes. De este modo, la nueva clase o clase hija (subclase, clase
derivada o clase hija) “hereda” los atributos y métodos de la clase padre
(superclase, clase base o clase padre) además de y crear nuevos atributos y
métodos e incluso modificar los heredados.
6
22/04/2019
HERENCIA
Es la base de la reutilización de código ya que cuando una clase hereda de
una clase padre obtiene los miembros y métodos de este sin tener que
duplicar el código.
En general todas las subclases no sólo adoptan las variables y
comportamientos de las superclases sino que los amplían y/o modifican
HERENCIA
La herencia genera una jerarquía de clases que se basa en la existencia de
relaciones de generalización y especialización entre clases.
En JAVA sólo está permitida la herencia simple, es decir, una clase puede tener muchas
subclases pero una clase sólo puede tener una superclase
7
22/04/2019
HERENCIA
La herencia es transitiva, es decir si B hereda de A y C hereda de B, entonces
también C hereda de A.
C->B->A
C no sólo hereda de B sino que también hereda de A.
Los métodos y atributos siempre se pueden heredar exactamente igual que en los
ancestros o modificarlos (generalmente modificando su comportamiento pero
manteniendo su esencia).
En algunas ocasiones una subclase puede seguir utilizando ambos
comportamientos, el heredado y el redefinido.
HERENCIA
Cuando una clase hereda de otra, la clase hija tiene acceso a todos (o casi todos) los
elementos de la clase padre, pero la clase padre no puede acceder a los elementos
de la clase hija. Ejemplo:
8
22/04/2019
HERENCIA
HERENCIA EN JAVA
Por defecto en JAVA todas las clases heredan de la clase java.lang.Object.
Si al definir nuestra clase no indicamos nada, esta por defecto será una clase
de la clase object.
9
22/04/2019
HERENCIA EN JAVA
Para indicar que una clase hereda de otra se utiliza la palabra reservada extends
mod_acceso Clase_hija extends Clase_padre {
//código de la clase
}
Public class Cuadrado extends Poligono {
//código de la clase
}
HERENCIA
class Goalkeeper extends SoccerPlayer {......}
10
22/04/2019
HERENCIA
Notación UML
Notación UML: La notación UML para herencia es una línea sólida con una punta de flecha
hueca que va de la subclase a su superclase. Por convención, la superclase se dibuja sobre sus
subclases como se muestra.
HERENCIA EN JAVA
Hasta ahora trabajamos principalmente con public y private. Con la herencia
utilizaremos frecuentemente un nuevo tipo: protected.
public: Todos pueden acceder a el.
private: Sólo es accesible desde la propia clase.
protected: : Accesible por las clases del mismo paquete y subclases.
11
22/04/2019
HERENCIA EN JAVA
Por tanto al heredar de una clase, heredamos todos los métodos y atributos
públicos y protected de la clase padre.
Los constructores nunca se heredan, aunque se pueden invocar desde los
constructores de la clase hija para reutilizarlos (lo veremos más adelante).
Al heredar de una clase, podemos acceder y utilizar los atributos y métodos
de esta clase como si fueran propios , simplemente por haber hecho
referencia a la clase padre con la palabra reservada extends
HERENCIA EN JAVA
Cuando heredamos un método de una clase, podemos utilizarlo de forma
idéntica al padre o adaptarlo para que encaje mejor en la nueva clase.
En definitiva redefinir un método consiste en reimplementar lo en la clase
hija
Para redefinir un método en una subclase basta con declararlo con el
mismo nombre, los mismos atributos y el mismo tipo de dato devuelto.
12
22/04/2019
HERENCIA EN JAVA
No confundir redefinir un método con sobrecargar un método
Sobrecargar un método consiste en definir 2 o más métodos con el mismo nombre y
tipo de dato devuelto pero que difieren en el número y/o tipo de argumentos que
reciben
HERENCIA EN JAVA
13
22/04/2019
SUPERCLASES Y SUBCLASES
A pesar de redefinir un método, desde una clase hija se puede seguir
utilizando el método original de la clase padre.
Esto es especialmente útil cuando el nuevo método realiza las mismas
acciones que el método padre más otras nuevas.
Para ello se utilizan los modificadores this y super.
SUPERCLASES Y SUBCLASES
this hace referencia al objeto de la clase actual (hijo):
this.atributo; this.método();
14
22/04/2019
SUPERCLASES Y SUBCLASES
Ejemplo
SUPERCLASES Y SUBCLASES
Ejemplo
15
22/04/2019
SUPERCLASES Y SUBCLASES
Recuerda que la subclase hereda todas las variables y métodos de sus superclases.
No obstante, una subclase no hereda a los constructores de sus superclases. Cada
clase en Java define sus propios constructores.
En el cuerpo de un constructor, puede usar super(args) para invocar a un constructor
de su superclase inmediata. Ten en cuenta que super(args), si se usa, debe ser la
primera declaración en el constructor de la subclase.
Esto sigue al hecho de que el padre debe nacer antes de que el niño pueda nacer.
Se debe construir correctamente las superclases antes de poder construir la subclase.
16
22/04/2019
SUPERCLASES Y SUBCLASES
Una subclase hereda todas las variables y métodos miembros de sus superclases
(el padre inmediato y todos sus ancestros). Puede utilizar los métodos y variables
heredados como son. También puede redefinir un método heredado al proporcionar
su propia versión u ocultar una variable heredada al definir una variable del mismo
nombre.
Por ejemplo, el método heredado getArea() en un objeto Cilindro calcula el área
base del cilindro. Supongamos que decidimos redefinir getArea() para calcular el
área de superficie del cilindro en la subclase Cilindro. A continuación se presentan los
cambios:
ACTIVIDAD 2
Crea las clases Circulo, Cilindro y PruebaCilindro
En este ejemplo, derivamos una subclase llamada
Cilindro de la superclase Círculo, que hemos creado
revisando el concepto de composición.
Es importante tener en cuenta que reutilizamos la clase
Círculo. La reutilización es una de las propiedades más
importantes de la POO.
(¿Por qué reinventar las ruedas?) La clase Cylinder
hereda todas las variables miembro (radio y color) y
métodos (getRadius (), getArea (), entre otros) de su
superclase Circle. Además, define una variable llamada
altura, dos métodos públicos: getHeight () y getVolume()
y sus propios constructores, como se muestra:
17
22/04/2019
18
22/04/2019
ANOTACIÓN OVERRIDE
El "@override" se conoce como anotación (introducida en JDK 1.5), que le pide al
compilador que verifique si existe un método de este tipo en la superclase a ser
redefinido.
Esto ayuda enormemente si escribe incorrectamente el nombre del método que se va
a redefinir. Por ejemplo, suponga que desea redefinir el método toString () en una
subclase. Si no se usa @override y toString () se escribe mal como TOString (), se
tratará como un nuevo método en la subclase, en lugar de reemplazar la superclase.
Si se usa @override, el compilador señalará un error.
La anotación de @override es opcional, pero ciertamente agradable de tener.
Las anotaciones no son construcciones de programación. No tienen efecto en la salida
del programa. Solo lo usa el compilador, se desecha después de la compilación y no
lo usa el tiempo de ejecución.
ACTIVIDAD 3
Crea las clases Punto2D, Punto3D y
una clase PruebaPuntos
19
22/04/2019
20
22/04/2019
ACTIVIDAD 4
Crea las clases Persona,
Alumno, Profesor y
PruebaPersona
21
22/04/2019
COMPOSICIÓN VS HERENCIA
"Una línea se compone de 2 puntos" vs. "Una línea es un punto
extendido por otro punto“
Recuerda que hay dos formas de reutilizar las clases existentes: la
composición y la herencia.
22
22/04/2019
COMPOSICIÓN VS HERENCIA
Hemos visto que una clase de
línea se puede implementar
utilizando la composición de la
clase de puntos: "Una línea se
compone de dos puntos", en la
sección anterior
También se puede implementar
una línea, utilizando la herencia
de la clase Punto: "Una línea es
un punto extendido por otro
punto". Llamemos a esta
subclase LineSub (para
diferenciarnos de la clase Line
usando composición).
ACTIVIDAD 5
Crea las clases
LineSub
Y TestLineSub
23
22/04/2019
ACTIVIDAD 5
Estudia ambas versiones de la clase Linea (Line y
LineSub). Supongo que es más fácil decir que
"Una línea se compone de dos puntos" que
"Una línea es un punto extendido por otro
punto".
COMPOSICIÓN VS HERENCIA
24
22/04/2019
ACTIVIDAD 6
Las clases de Circle y Cylinder usando composición
Intenta volver a escribir el Círculo-Cilindro del ejercicio anterior
usando la composición (como se muestra en el diagrama de
clase) en lugar de la herencia. Es decir, "un cilindro está
compuesto por un círculo base y una altura".
HERENCIA VS COMPOSICIÓN
25
22/04/2019
ACTIVIDAD 7
ACTIVIDAD 8
26
22/04/2019
ACTIVIDAD 9
Enunciado en el aula virtual
POLIMORFISMO
La palabra "polimorfismo" significa "muchas formas". Viene de la palabra griega
"poli" (significa muchos) y "morfos" (significa forma).
Por ejemplo, en química, el carbono exhibe polimorfismo porque se puede encontrar
en más de una forma: grafito y diamante. Pero, cada una de las formas tiene
propiedades distintas (y precio).
27
22/04/2019
POLIMORFISMO
Sustituibilidad
Una subclase posee todos los atributos y operaciones de su superclase (porque una
subclase hereda los atributos y operaciones de su superclase).
Esto significa que un objeto de subclase puede hacer lo que su superclase puede
hacer.
Como resultado, podemos sustituir una instancia de subclase cuando se espera
una instancia de superclase, y todo funcionará bien. Esto se llama sustituibilidad.
POLIMORFISMO
28
22/04/2019
POLIMORFISMO
POLIMORFISMO
Mediante la posibilidad de sustitución, podemos crear una instancia de Cilindro y
asignarla a una referencia de Círculo (su superclase), de la siguiente manera:
Puedes invocar todos los métodos definidos en la clase Circulo para la referencia c1,
(que en realidad contiene un objeto Cilindro), por ejemplo.
29
22/04/2019
POLIMORFISMO
Esto se debe a que una instancia de subclase posee todas las propiedades de su
superclase. Sin embargo, NO PUEDES invocar los métodos definidos en la clase de
Cilindro para la referencia c1, por ejemplo.
Esto se debe a que c1 es una referencia a la clase Circulo, que no conoce los
métodos definidos en la subclase Cilindro.
POLIMORFISMO
c1 es una referencia a la clase Circulo, pero contiene un objeto de su subclase
Cilindro. La referencia c1, sin embargo, conserva su identidad interna.
En nuestro ejemplo, la subclase Cilindro reemplaza los métodos getArea() y
toString().
c1.getArea() o c1.toString() invoca la versión anulada definida en la subclase
Cilindro, en lugar de la versión definida en Circulo. Esto se debe a que, de hecho, c1
contiene un objeto Cilindro internamente.
30
22/04/2019
POLIMORFISMO
Resumen
Se puede asignar (sustituir) una instancia de subclase a una referencia de
superclase.
Una vez sustituido, podemos invocar métodos definidos en la superclase; No
podemos invocar métodos definidos en la subclase.
Sin embargo, si la subclase sobreescribe los métodos heredados de la
superclase, se invocarán las versiones de la subclase.
POLIMORFISMO. EJEMPLO
El polimorfismo es muy poderoso en la programación orientada a objetos para
separar la interfaz y la implementación.
Considera el siguiente ejemplo.
Supongamos que nuestro programa utiliza muchos tipos de formas, como triángulos,
rectángulos, etc. Deberíamos diseñar una superclase llamada Shape, que define las
interfaces públicas (o comportamientos) de todas las formas.
Por ejemplo, nos gustaría que todas las formas tengan un método llamado getArea(),
que devuelve el área de esa forma en particular. La clase de forma se puede
escribir de la siguiente manera.
31
22/04/2019
POLIMORFISMO. EJEMPLO
POLIMORFISMO. EJEMPLO
32
22/04/2019
POLIMORFISMO. EJEMPLO
Las subclases sobrescriben el método getArea() heredado de la superclase y
proporcionan las implementaciones adecuadas para getArea().
POLIMORFISMO. EJEMPLO
En nuestra aplicación, podríamos crear referencias de Shape y asignarles instancias
de subclases de la siguiente manera:
33
22/04/2019
POLIMORFISMO. EJEMPLO
Los resultados esperados son:
La belleza de este código es que todas las referencias son de la superclase (es decir,
la programación en el nivel de interfaz).
Podrías crear instancias de subclases diferentes y el código aún funciona. Puede
extender su programa fácilmente agregando más subclases, como Círculo, Cuadrado,
etc., con facilidad.
POLIMORFISMO. EJEMPLO
No obstante, la definición anterior de la clase Shape plantea un problema, si alguien
crea una instancia de un objeto Shape e invoca getArea() desde el objeto Shape, el
programa se interrumpe.
Esto se debe a que la clase Shape está diseñada para proporcionar una interfaz
común a todas sus subclases, que se supone que proporcionan la implementación real.
No queremos que nadie cree una instancia de Shape. Este problema se puede
resolver utilizando la llamada clase abstracta.
34
22/04/2019
35
22/04/2019
UPCASTING Y DOWNCASTING
Upcasting (o conversión ascendente) de una instancia de subclase a una
referencia de superclase.
Sustituir una instancia de subclase por su superclase se llama "upcasting".
La conversión ascendente –upcasting- siempre es segura porque una instancia de
subclase posee todas las propiedades de su superclase y puede hacer lo que su
superclase puede hacer. El compilador comprueba si hay una conversión ascendente
válida y emite errores de "tipos incompatibles" de lo contrario. Por ejemplo,
36
22/04/2019
UPCASTING Y DOWNCASTING
Downcasting (conversión descendente) de una referencia sustituida a su clase original
Puede revertir una instancia sustituida de nuevo a una referencia de subclase. Esto se llama
"downcasting". Por ejemplo
37
22/04/2019
EL OPERADOR INSTANCEOF
Una instancia de subclase es también una instancia de su superclase. Por ejemplo,
38
22/04/2019
POLIMORFISMO
Resumen
Una instancia de subclase procesa todas las operaciones de atributos de su superclase.
Cuando se espera una instancia de superclase, se puede sustituir por una instancia de
subclase. En otras palabras, una referencia a una clase puede contener una instancia de
esa clase o una instancia de una de sus subclases, se llama sustituibilidad.
Si una instancia de subclase se asigna a una referencia de superclase, puede invocar los
métodos definidos en la superclase solamente. No puede invocar métodos definidos en la
subclase.
Sin embargo, la instancia sustituida conserva su propia identidad en términos de métodos
sobreescritos y ocultando variables. Si la subclase sobreescribe los métodos de la superclase,
se ejecutará la versión de la subclase, en lugar de la versión de la superclase.
CLASES ABSTRACTAS
Métodos y clases abstractas
En los ejemplos anteriores de Shape y Monster, encontramos un problema cuando
creamos instancias de Shape y Monster y ejecutamos getArea() o attack(). Esto se
puede resolver a través de métodos abstractos y clases abstractas.
Un método abstracto es un método con solo cabecera (es decir, el nombre del
método, la lista de argumentos y el tipo de retorno) sin implementación (es decir, el
cuerpo del método). Utiliza la palabra clave abstract para declarar un método
abstracto.
39
22/04/2019
CLASES ABSTRACTAS
Por ejemplo, en la clase Shape, podemos declarar los métodos abstractos getArea(),
draw (), etc., de la siguiente manera:
CLASES ABSTRACTAS
Una clase que contiene uno o más
métodos abstractos se llama una
clase abstracta.
Una clase abstracta debe ser
declarada con el modificador de
clase abstract.
Una clase abstracta NO PUEDE
ser instanciada, ya que su
definición no está completa.
Notación UML: la clase abstracta y
el método se muestran en cursiva.
40
22/04/2019
41
22/04/2019
42
22/04/2019
43
22/04/2019
CLASES ABSTRACTAS.
Notas:
Un método abstracto no puede ser declarado final, ya que el método final no
puede ser sobreescrito. Un método abstracto, por otro lado, debe ser sobreescrito en
un descendiente antes de que pueda ser utilizado.
Un método abstracto no puede ser privado (lo que genera un error de
compilación). Esto se debe a que el método privado no es visible para la subclase y,
por lo tanto, no se puede sobreescribir.
Si una clase contiene un método abstract, entonces la clase deberá ser declarada
como abstract forzosamente.
Por el contrario una clase abstract no tiene por que tener métodos abstract
forzosamente.
CLASES ABSTRACTAS.
las clases abstractas pueden tener constructores, pero SOLAMENTE para ser
usados desde los constructores de las clases hijas, no puedes usarlos directamente
porque por definición no se puede instanciar una clase abstracta.
Un método abstract nunca podrá ser static.
En definitiva abstract es sinónimo de genérico
La utilidad de las clases abstractas es crear clases genéricas o plantillas, cuya
funcionalidad será implementada por las subclases.
De esta manera, todas las subclases tendrán una interfaz común. Es decir funcionarán
con los mismos métodos y realizarán las mismas operaciones. Pero cada subclase
tendrá una funcionalidad interna diferente.
44
22/04/2019
CLASES ABSTRACTAS
Regla de oro: programa en la interfaz, no en la implementación.
(Es decir, haz referencias en la superclase; sustitúyelas por
instancias de subclase; invoca los métodos definidos solo en la
superclase).
45
22/04/2019
46
22/04/2019
En este caso ninguna clase que herede este método podrá redefinir su funcionalidad, solo
podrá invocarlo igual que en la clase padre.
47
22/04/2019
INTERFACES
En JAVA sólo se puede heredar de una
única clase. En otros lenguajes como
smalltalk y C++ se puede heredar de
varias clases lo que se conoce como
herencia múltiple. Este tipo de herencia es
muy potente pero también es fuente de
incoherencias y errores.
Para solucionar esto en JAVA se definen
las interfaces, de forma que una clase
puede heredar de una única superclase
pero además implementar todas las
interfaces que desee.
INTERFACES
Pero entonces ¿Qué es una interfaz?
Una interfaz Java es una superclase abstracta al 100% que define un conjunto de
métodos que sus subclases deben soportar.
Una interfaz contiene solo métodos abstractos públicos (métodos con cabecera y
sin implementación) y posiblemente constantes (variables finales públicas estáticas).
Debe utilizar la palabra clave "interfaz" para definir una interfaz (en lugar de la
palabra clave "clase" para las clases normales). La palabra clave public y abstract
no son necesarias para sus métodos abstractos, ya que son obligatorios.
48
22/04/2019
INTERFACES
Similar a una superclase abstracta, una interfaz no puede ser instanciada. Debe
crear una "subclase" que implemente una interfaz y proporcionar la implementación
real de todos los métodos abstractos.
A diferencia de una clase normal, donde se usa la palabra clave “extends" para
derivar una subclase. Para la interfaz, usamos la palabra clave “implements" para
derivar una subclase.
Una interfaz es un contrato para lo que las clases pueden hacer. Sin embargo, no
especifica cómo deben hacerlo las clases.
INTERFACES
Una interfaz proporciona una forma, un protocolo, un estándar, un contrato, una
especificación, un conjunto de reglas, una interfaz, para todos los objetos que la
implementan. Es una especificación y reglas que cualquier objeto que lo
implemente se compromete a seguir.
49
22/04/2019
INTERFACES
Convención de nomenclatura de interfaz: usa un adjetivo (normalmente termina con
“able") que consiste en una o más palabras. Cada palabra debe tener mayúscula
inicial (camell case).
Por ejemplo,
Serializable, Extenalizable, Movible, Clonable, Ejecutable, etc.
ACTIVIDAD 12
La interface de Shape y sus implementaciones.
Podemos volver a escribir la superclase abstracta
como una interfaz, que contiene solo métodos
abstractos, como muestra la figura
50
22/04/2019
ACTIVIDAD 12
INTERFACES
Una interfaz es un tipo de clase especial en la que no se implementa ninguno de
sus métodos, todos son abstractos (una clase abstracta podía implementarlos o no).
Además en una interfaz sólo se pueden definir atributos constantes.
Una interfaz sólo define los métodos que se van a utilizar, que parámetros reciben y
que tipo de dato devuelven. Dejando libertad para implementar la funcionalidad
en cada una de las clases que implementan la interfaz.
Cuando se “hereda” de una interfaz, se dice que se implementa dicha interfaz, ya
que no se hereda ninguna funcionalidad, sino que se lo que se va a hacer es
implementar los métodos de esta.
Cuando se implementa una interfaz, hay que implementar todos sus métodos o
declarar la clase como abstracta.
51
22/04/2019
Similar a una clase abstracta, una interfaz no puede ser instanciada; porque está
incompleta (falta el cuerpo de los métodos abstractos).
Para usar una interfaz, nuevamente, debe derivar subclases y proporcionar
implementación a todos los métodos abstractos declarados en la interfaz. Las
subclases ahora están completas y pueden ser instanciadas.
52
22/04/2019
53
22/04/2019
54
22/04/2019
INTERFACES
La sintaxis formal para declarar interfaz es:
55
22/04/2019
INTERFACES
Todos los métodos en una interfaz serán públicos y abstractos (por defecto).
No puede usar otro modificador de acceso, como privado, protegido y
predeterminado, o modificadores, como static , final.
Todos los campos serán públicos, estáticos y finales (por defecto).
Una interfaz puede "extenderse" desde una super-interfaz.
INTERFACES
Notación UML: la notación UML utiliza una flecha de línea continua que une la
subclase con una superclase concreta o abstracta, y la flecha de línea discontinua con
una interfaz como se ilustra. La clase abstracta y el método abstracto se muestran en
cursiva.
56
22/04/2019
57
22/04/2019
58
22/04/2019
ACTIVIDAD 13
ACTIVIDAD 14
59
22/04/2019
RESUMEN
Utilizaremos una clase que no herede de nadie cuando la clase no cumpla la
condición de es-un para el problema a resolver.
Utilizaremos una subclase cuando sea la relación e especialización es-un de
la superclase mediante la sobrescritura o añadiendo nuevos metodosy/o
atributos para el problema a resolver
Utilizaremos una clase final cuando queramos impedir que otras clases
puedan heredar de esta.
Utilizaremos métodos finales cuando queramos permitir la herencia pero no
permitamos redefinir el método.
RESUMEN
Utilizaremos una clase abstracta cuando se quiera definir un grupo genérico
de clases que compartan algunos métodos implementados que reutilizar.
También cuando queramos que nadie pueda crear objetos de dicha clase.
Utilizaremos una interfaz cuando se quiera definir un grupo genérico de
clases y no existan métodos implementados que reutilizar. O cuando nos
veamos forzados a heredar de más de una clase.
60
22/04/2019
LA INTERFACE COMPARABLE
61
22/04/2019
EJEMPLO DE COMPARABLE
62
22/04/2019
63
22/04/2019
64
22/04/2019
65
22/04/2019
RECURSOS
Curso youtube : Java desde 0
Libro Java 9. Manual imprescindible. F. Javier Moldes Teo. Editorial Anaya
App SoloLearn: Aprende a Programar. Curso Java
66