Está en la página 1de 340

MÓDULO A

UNIDADES DIDÁCTICAS:

1. Introducción

2. Conceptos básicos. Objeto, atributo, método,

interfaz, clase

3. Paradigmas de la Orientación a Objetos:

Abstracción, encapsulación, ocultamiento,

herencia y polimorfismo.
MÓDULO A

Introducción

Tema 1.1

Índice de la unidad:

1. Historia

2. Ventajas de la Orientación a Objetos


Unidad 1.1 Introducción

En esta unidad veremos el origen de la programación Orientada a Objetos, y


cuales son sus principales características.

1. Historia

Una de las características para poder clasificar los lenguajes de programación es su


nivel de abstracción. Este nivel puede ser expresado en base a la complejidad del
problema que se está intentando resolver. Por ejemplo, el lenguaje Ensamblador,
primer lenguaje de programación, tiene un pequeño nivel de abstracción
relacionado totalmente con la máquina en la que se está ejecutando, por lo que el
nivel de abstracción que se aplicaba al ámbito de la solución era muy bajo.

Muchos de los lenguajes que siguieron al Ensamblador, llamados lenguajes


imperativos, como es el caso de Fortran, Basic y C, fueron abstracciones de este
primer lenguaje de programación. El nivel de abstracción de estos lenguajes es
mucho más elevado que el del lenguaje original, pero siguen estando muy
relacionados con la estructura del ordenador en el que se ejecutan, en lugar de la
estructura del problema a resolver y del mundo real. Debido a esta relación, los
programas desarrollados son difíciles de escribir y bastante costosos de mantener.

Así, acercando el modelo de abstracción al problema a resolver y no a la máquina


física, aparecieron en los años 60 los primeros lenguajes Orientados a Objetos,
también denominados O.O., tales como LISP (todos los problemas se reducen a
listas), APL (todos los problemas se reducen a algoritmos) y PROLOG (todos los
problemas se reducen a cadenas de decision).

El primer lenguaje considerado totalmente Orientado a Objetos y sobre el que se


basa Java, es Smalltalk. Este lenguaje recoge las cinco principales características
que tienen que tener estos lenguajes de programación y que se verán más en
profundidad en la Unidad 1.2:

 Todo puede ser representado como un objeto, siendo capaz de


almacenar cierta información y realizar operaciones sobre ella.

 Un programa es un conjunto de objetos colaborando entre sí,


indicando que es lo que hay que hacer mediante el envío de
mensajes.

 Cada objeto esta contruido en base a otros objetos,


permitiendo alcanzar grados mayores de complejidad.

 Cada objeto pertenece a un tipo, denominado clase.

 Todos los objetos del mismo tipo pueden recibir los mismos
mensajes.

1
MÓDULO 1

A continuación, se muestra la evolución de los lenguajes Orientados a Objetos


hasta la aparición del lenguaje Java, objeto de nuestro estudio.

No hay que olvidar, que la Orientación a Objetos aplica también al Análisis y Diseño
de las soluciones. El método más utilizado a día de hoy es el UML (siglas de Unified
Modeling Language) sucesor de los métodos de Análisis y Diseño Orientado a
Objetos de finales de los 80 y comienzo de los 90, tales como: Booch, Rumbaugh
(OMT) y Jacobson.

UML es un método visual, basado en diagramas, que permite modelar sistemas, en


base a Especificaciones, Arquitectura, Diseño y/o Implementación.

2
Unidad 1.1 Introducción

2. Ventajas de la Orientación a Objetos

Habiendo visto la evolución de los lenguajes de programación en base a su nivel de


abstracción, el principal objetivo de los lenguajes Orientados a Objetos fue reducir
la complejidad del desarrollo y mantenimiento del Software. Así las principales
ventajas de estos lenguajes son:

 Suministra modelos similares a los del mundo real.

 Facilita el desarrollo de sistemas complejos.

 Facilita la reutilización

 Permite el desarrollo iterativo de aplicaciones.

 Facilita la interoperabilidad de aplicaciones.

2.1 Similitud con el mundo real

Mediante la abstracción del mundo real, lo que se pretende es definirlo tal y


como es en base al problema a resolver y ciñéndonos al ámbito de la solución.
Nos permitirá definir que entidades como tales vamos a necesitar que existan
para solucionar nuestro problema y las relaciones entre ellas, tales como
relaciones jerárquicas, relaciones de interacción.

 Ejemplo: Tenemos que desarrollar un programa para una tienda de


animales donde solo van a tratar mamíferos y solo ciertos tipos de mamíferos.
Por lo tanto, los peces, las aves ... quedan fuera del ámbito de nuestro mundo
real.

3
MÓDULO 1

2.2 Facilita el desarrollo de sistemas complejos.

El sistema de abstracción del mundo real, permite centrarnos por una parte
en cuales son las entidades del dominio, qué información de toda la posible es
la que ayuda a solventar nuestro problema, que tipo de acciones u
operaciones son relevantes en estas entidades, etc. para una vez que
tengamos toda esta información, ver las interrelaciones entre todos ellos y su
convivencia.

Este tipo de abstracción nos permite realizar un tipo de programación Botton-


Up (de abajo a arriba), donde partiendo de piezas más pequeñas se va
conformando el todo.

Se puede llegar a comparar con el mecanismo de contrucción del Hardware,


que para la construcción de un todo, es necesario la utilización de piezas
pequeñas que se van ensamblando para conformar las piezas más grandes,
que a su vez conforman el elemento Hardware final como puede ser un
ordenador.

Los elementos fundamentales del modelo de Objetos, en el que se van a


basar el desarrollo de estos sistemas, y que se verán más en profundidad en
la Unidad 1.3 son:

 Abstracción. Capacidad de definir los datos y operaciones que


se necesitan, de las entidades de nuestro mundo real.

4
Unidad 1.1 Introducción

 Encapsulamiento. Permite ocultar que és lo que proporciona


una entidad, sin necesidad de conocer como lo proporciona.

 Modularidad. División de las soluciones en componentes más


pequeños o módulos independientes que se integran entre sí. Una
solución compleja desarrollada en un solo módulo es imposible de
abarcar por un solo lector, debido al número de caminos de control,
variables ...

 Herencia. Relación de jerarquía entre las entidades, en cuanto


a funcionalidad.

2.3 Facilita la reutilización

La reutilización de código es una de las grandes ventajas de los lenguajes


Orientados a Objetos. ¿Cuáles son las características que permiten obtener
dicha ventaja? Se consigue mediante la herencia (relaciones jeráquicas de
entidades), composición (creación de entidades en base a otras) y
parametrización (reutilización de operaciones en función de los parámetros
que se les pasan a dichas operaciones).

La Orientación a Objetos soporta la reutilización basada en la utilización de


librerías de componentes (agrupación de entidades con un significado
relacionado), patrones de diseño (soluciones dadas a problemas ya
existentes) y arquitecturas software (también conocidas con el nombre de
framework).

2.4 Permite el desarrollo iterativo.

El desarrollo iterativo, permite ir paso a paso en el ciclo de desarrollo. No se


pretende empezar desde 0 y terminar el 100% del desarrollo en una sola
etapa.

Con el desarrollo iterativo, se van definiendo etapas e hitos a conseguir,


consiguiendo fases de pruebas y aprobación de lo desarrollado hasta el
momento en fases mucho mas tempranas que en el desarrollo tradicional. De

5
MÓDULO 1

esta forma se consigue un prototipado controlado: se crea un prototipo al cual


se le añaden capacidades de forma incremental.

El cliente puede ir probando versiones mucho antes que en el desarrollo


tradicional. De esta manera se comprueba que la solución dada al problema a
resolver es realmente lo que se está esperando y no tenemos que esperar a la
finalización del desarrollo, para verificar que la solución final satisface el
problema a resolver en su totalidad.

Actualmente, el desarrollo iterativo, se basa en la utilización de ‘Casos de


Uso’, uno de los diagramas definidos por UML. Describen una visión externa
del comportamiento del Sistema desde el punto de vista del usuario,
constituyendo un modelo de lo que el Sistema hará sin tener en cuenta el
cómo lo hará.

A continuación se muestra como sería el ciclo iterativo de desarrollo. Por cada


conjunto de casos de uso elegidos, se pasará por cada una de las fases,
permitiendo tener casos de usos finalizados mientras que otros están
pendientes de iniciarse.

6
Unidad 1.1 Introducción

2.5 Facilita la interoperabilidad

Las arquitecturas Orientadas a Objetos permiten un mejor aislamiento de las


dependencias de la topología en la que se ejecuta la solución. De esta manera
no nos tendremos que preocupar en que topología se va a ejecutar nuestra
solución, ni en el caso de que la solución vaya a estar dividida en distintas
partes, las plataformas de ejecución de las mismas. De esta manera la
entidad oficina, con la definición de sus datos y de sus operaciones, será la
misma independientemente de que se ejecute en un PC, en un Servidor o en
un Mainframe.

Es una diferencia a tener en cuenta, con respecto a C++ que sí que necesita
saber en que topología se va a ejecutar.

7
MÓDULO 1

 Los lenguajes orientados a objetos, miden su nivel de abstracción


con respecto a la definición del mundo real.

 Las principales ventajas son:


- Suministra modelos similares a los del mundo real.
- Facilita el desarrollo de sistemas complejos.
- Facilita la reutilización.
- Permite el desarrollo iterativo de aplicaciones.
- Facilita la interoperabilidad de aplicaciones.
- Facilita el desarrollo de sistemas complejos.
MÓDULO A

Conceptos básicos. Objeto, atributo,


método, interfaz, clase

Tema 1.2

Índice de la unidad:

1. Conceptos básicos

2. Objeto

3. Clase
Unidad 1.2 Conceptos básicos

En esta unidad veremos cuales son los conceptos básicos en los que se apoya la
Orientación a Objetos, tanto a nivel de Análisis y Diseño, como en la Programación.

1. Conceptos básicos

Como se ha comentado en la Unidad 1.1, los lenguajes de programación Orientados


a Objetos, se caracterizan por tener su nivel de abstracción basado en el mundo
real. Así, el énfasis está en la abstracción de datos, y los problemas del mundo real
son representados por un conjunto de objetos de datos para los que se adjunta un
conjunto correspondiente de operaciones.

Así, al igual que otros lenguajes de programación, introducen un nuevo conjunto de


términos, o conceptos básicos que son esenciales comprender, para poder realizar
cualquier análisis, diseño o desarrollo Orientado a Objetos:

 Objeto

 Atributo

 Método

 Interfaz

 Clase

A continuación veremos en más detalle cada uno de estos conceptos básicos.

2. Objeto

Hay muchas definiciones que pueden darse de un objeto, entre las cuales se en-
cuentran:

 Es cualquier cosa que vemos a nuestro alrededor, algo tangi-


ble y/o visible, animado o inanimado. Por ejemplo, un camión, un
perro, una cuenta bancaria ...

11
MÓDULO 1

 Algo que puede comprenderse intelectualmente. Por ejemplo,


una proceso de ordenación

 Una entidad Software. Por ejemplo una lista de cosas.

Definiciones dadas por creadores de metodologías Orientadas a Objetos como pue-


den ser:

 Un objeto se caracteriza por un número de operaciones y un


estado que recuerda el efecto de estas operaciones. Ivar Jacobson

 Un objeto tiene un estado, comportamiento e identidad; la


estructura y comportamiento de objetos similares se definen en sus
clases comunes. Grady Booch

 Un objeto es una entidad que tiene un estado (cuya represen-


tación está oculta) y un conjunto definido de operaciones que ope-
ran sobre ese estado. Ian Sommerville

 Un objeto es una identidad con unos límites bien definidos que


encapsulan estado y comportamiento. El estado se representa por
atributos y relaciones, el comportamiento es representado por ope-
raciones y métodos. Object Management Group

Los términos objeto e instancia son usados indistintamente.

12
Unidad 1.2 Conceptos básicos

2.1 Características de un objeto

Todos los objetos, tienen intrínsecos las siguientes características, como se


han visto en alguna de definiciones del apartado anterior:

 Identidad. Es un identificador unívoco para cada uno de los


objetos. En el caso de que los valores de los atributos fueran los
mismos, es la única manera de poder determinar cada uno de los ob-
jetos. Así si tenemos dos cuentas corrientes con el mismo titular, y el
mismo importe, la única forma de diferenciarlas es vía dicha identi-
dad.

 Comportamiento. Conjunto de operaciones o métodos que


proporcionan servicios a otros objetos que solicitan dichos servicios
cuando necesitan que se realice una cierta operativa.

 Estado. Conjunto de propiedades o atributos que recuerdan el


efecto de las operaciones.

 Ejemplo: Para un reloj determinado, la identidad o identificador podría ser


unReloj, con los atributos hora (horas, min, seg), dia (dia, mes, año), modelo y
numSerie y cuyos métodos u operaciones serían getHora, getDia, incrementar-
Hora, incrementarDia, limpiarPantalla y traducirFrecuencia.

2.2 Estructura de un objeto

En base a las características del objeto mencionadas anteriormente, todo ob-


jeto está formado por atributos o estructura encapsulada de los datos y por
los métodos u operaciones permitidas por dicho objeto, ya sean visibles para
el usuario o no.

Los métodos pueden clasificarse de la siguiente manera:

 Modificador (setter): altera el estado de un objeto. Por ejem-


plo, setHora()

 Selector (getter): accede al estado de un objeto sin alterarlo.


Por ejemplo getHora(X)

13
MÓDULO 1

 Iterador: permite acceder a todas los elementos de un objeto.


Solo disponible para colecciones de objetos.

 Constructor: crea un objeto e inicializa su estado. Por ejemplo


Reloj().

 Destructor: limpia el estado de un objeto y lo destruye. Por


ejemplo ~Reloj(). No existe en Java.

 Propósito general: la lógica del programa. Por ejemplo, lim-


piarPantalla(), incrementarDia().

Gráficamente, se puede visualizar la estructura de un objeto de la siguiente ma-


nera:

 Ejemplo: Para el objeto unReloj mencionado anteriormente, la estructura


sería la siguiente:

14
Unidad 1.2 Conceptos básicos

Atributo: Es una característica fundamental de cada objeto y por lo tan-


to como veremos posteriormente de una clase. Todos los atributos tie-
nen algún valor, siendo este una cantidad, una relación con otro objeto
... Si el valor del atributo es un valor fijo para todos los objetos, se dice
que es un atributo estático

Método: Es una acción que se realiza sobre un objeto para consultar o


modificar su estado.

2.3 El aspecto de los objetos.

Cuando se habla del aspecto de los objetos, no nos estamos refiriendo a los
conceptos de buen o mal aspecto visual. Nos referimos a como el objeto se ve
internamente o aspecto interno y como ven al objeto desde otros objetos
también llamado aspecto exterior.

15
MÓDULO 1

Este aspecto exterior, es llamado también interfaz, siendo la parte visible y


accesible para el resto de objetos. Puede estar formado por uno o varios mé-
todos. También se le define como el protocolo de comunicación de un objeto.

Es posible que exista algún método que solo pertenezca al aspecto interno pe-
ro no pertenezca al interfaz. En este caso, estos métodos no pueden ser lla-
mados desde otros objetos, sino que solamente pueden ser llamados desde
métodos del propio objeto.

 Ejemplo: Para el objeto unReloj, el interfaz estaría formado por los métodos
getHora, getDia, incrementarHora e incrementarDia. Los métodos limpiarPan-
talla y traducirFrecuencia solamente pertenecen (conjuntamente con los que
forman el interfaz) al aspecto interno. Así el método limpiarPantalla, es llamado
por getHora y getDia antes de mostrar la información pedida en el método

Interfaz: Aspecto exterior que es visible al resto de objetos. Puede es-


tar formado por uno o varios métodos.

16
Unidad 1.2 Conceptos básicos

3. Clase

Hasta ahora hemos visto que define a un objeto. Una de las definiciones más senci-
llas es algo del mundo real, tangible o visible.

Hemos visto que los objetos están formados por atributos y métodos. La definición
de estructura y comportamiento de un objeto es a lo que se denomina clase. Es por
tanto un patrón para la definición de atributos y métodos para un tipo particular de
objetos.

Todos los objetos de una clase dada son idénticos en estructura y comportamiento
pero son únicos (aunque tengan los mismos valores en sus atributos).

Instancia es el término utilizado para referirse a un objeto que pertenece a una cla-
se concreta.

Una clase, por tanto es solamente la definición. Mientras que un objeto o instancia
es algo real con la estructura y comportamiento de la clase a la que pertenece.

La estructura de una clase, por tanto, viene determinada por un nombre, los atribu-
tos que contiene y los métodos que realiza.

 Ejemplo: El objeto unReloj, pertenece a la clase Reloj, cuyo nombre es Re-


loj, cuyos atributos son dia, hora, modelo y numSerie y cuyos métodos son
getHora, getDia, incrementarHora, incrementarDia, limpiarPantalla y traducir-

17
MÓDULO 1

Frecuencia

Como se puede ver en la imagen anterior, en los diagramas UML, la definición de


una clase, se realiza mediante un rectángulo, divido en tres partes y conteniendo
en el siguiente orden: Nombre, Atributos y Métodos.

3.1 Clases versus Objetos.

Es importante saber diferenciar que es una clase y que es un objeto y en que


consiste cada una de ellas. Por ello, recapitulamos toda la información mos-
trada hasta el momento.

Una clase es un patrón para la definición del estado y el comportamiento de


un tipo particular de objetos.

Todos los objetos de una clase dada son idénticos en estructura y comporta-
miento, pero tienen identidad única.

Un objeto pertenece a una clase en particular.

Los objetos son creados y destruidos en tiempo de ejecución. Residen en el


espacio de memoria.

18
Unidad 1.2 Conceptos básicos

Así para la clase Reloj descrita anteriormente, tendremos los objetos unReloj
(dia=”01-03-2010”, hora=”13:01:03”, modelo=”Rolex”, numSerie=”123456”)
y otroReloj (dia=”01-03-2010”, hora=”13:01:03”, modelo=”Swatch”, numSe-
rie=”Sab748”).

Pero si nos paramos a pensar, ¿qué surge antes? ¿La clase y por lo tanto
creamos los objetos del mundo real? O partiendo de los objetos del mundo re-
al ¿podemos definir su estructura y comportamiento?.

Para solventar esta problemática, aparece el concepto de Clasificación. La cla-


sificación es el medio por el que ordenamos el conocimiento, ya que funda-
mentalmente es un problema de búsqueda de similitudes. Al clasificar busca-
mos grupos de cosas que tengan una misma estructura o exhiban un compor-
tamiento común.

La clasificación dentro de la Orientación a Objetos, sobre todo en las fases de


Análisis y Diseño, permite que los objetos con la misma estructura de datos y
con el mismo comportamiento se agrupan para formar una clase.

19
MÓDULO 1

Decidir cual es el concepto o conceptos (Clase, Objeto, Método, Atributo) que


cuadran con las siguientes definiciones. Pensar la solución antes de pasar al
siguiente cuadro:

1. El valor de mis atributos puede ser distinto al de los de mi semejante:


2. Yo me comporto como una plantilla:
3. A mi me gusta hacer cosas:
4. Yo puedo tener muchos métodos:
5. Yo represento el estado:
6. Yo represento el comportamiento:
7. Yo estoy en los objetos:
8. Yo vivo en memoria:
9. Yo soy usado para crear instancias:
10. Mi estado puede cambiar:
11. Yo declaro métodos:
12. Yo puedo cambiar en ejecución:

Las soluciones a las preguntas anteriores son:

1. El valor de mis atributos puede ser distinto al de los de mi semejante: Ob-


jeto
2. Yo me comporto como una plantilla: Clase
3. A mi me gusta hacer cosas: Objeto, método
4. Yo puedo tener muchos métodos: Clase, objeto
5. Yo represento el estado: Atributo
6. Yo represento el comportamiento: Método
7. Yo estoy en los objetos: Atributo, método
8. Yo vivo en memoria: Objeto
9. Yo soy usado para crear instancias: Clase
10.Mi estado puede cambiar: Objeto
11.Yo declaro métodos: Clase
12.Yo puedo cambiar en ejecución: Objeto, atributo

20
Título de unidad didáctica

 En esta Unidad hemos visto los conceptos básicos en los que se


apoya la Orientación a objetos:
- Objeto.
- Atributo.
- Método.
- Interfaz.
- Clase
MÓDULO A

Paradigmas de la OO

Tema 1.3

Índice de la unidad:

1. Paradigmas de la Orientación a Objetos

2. Abstracción

3. Encapsulación y ocultamiento

4. Relaciones

5. Polimorfismo
Unidad 1.3 Paradigmas de la Orientación a Objetos

En esta unidad veremos cuales son los paradigmas en los que se apoya la Orienta-
ción a Objetos, tanto a nivel de Análisis y Diseño, como en la Programación.

1. Paradigmas de la Orientación a Objetos.

Como se ha comentado en la Unidad 1.1, los lenguajes de programación Orientados


a Objetos, se caracterizan por tener su nivel de abstracción basado en el mundo
real. Así, el énfasis está en la abstracción de datos, y los problemas del mundo real
son representados por un conjunto de objetos de datos para los que se adjunta un
conjunto correspondiente de operaciones.

El paradigma de la Orientación a Objeto es una disciplina de ingeniería de desarro-


llo y modelado de Software que permite construir más fácilmente sistemas comple-
jos a partir de los componentes individuales vistos en la Unidad 1.2, tales como ob-
jetos, clases, atributos, métodos e interfaces, todos ellos utilizados para construir
un programa.

Esta disciplina y por tanto cualquier lenguaje de Orientación a Objetos que perte-
nezca a ella, debe de cumplir con los siguientes paradigmas (aunque cada lenguaje
tenga sus propias peculiaridades al respecto):

 Abstracción

 Encapsulación y Ocultamiento

 Herencia

 Polimorfismo

A continuación veremos en más detalle cada uno de estos paradigmas.

2. Abstracción

Consiste en la generalización conceptual de los atributos y comportamiento de un


determinado conjunto de objetos.

25
MÓDULO 1

La clave de la programación Orientada a Objetos está en abstraer los métodos y los


datos comunes a un conjunto de objetos y almacenarlos en una clase. Así todos los
objetos de una clase, se diferenciaran solamente en el estado, teniendo todos ellos
el mismo comportamiento.

Primeramente hay que centrarse en lo que es y lo que hace un objeto (atributos y


comportamiento), antes de decidir cómo debería ser implementado. Nos centramos
por tanto en la definición, en lugar de la implementación.

 Ejemplo de abstracción: En nuestro mundo real, tenemos los siguientes


objetos, miGato, miPerro, miLeon, miTigre y miLobo. Si abstraemos los atribu-
tos comunes que queremos tener contemplados en el ámbito de nuestra solu-
ción, encontramos que en todos ellos, queremos tener una foto, que tipo de ali-
mentación, donde habitan y su tamaño, y como comportamiento, queremos sa-
ber como hacen ruido, como comen, como duermen y como rugen. Así de una
realidad, hemos abstraído estado y comportamiento y hemos definido la clase
Animal.

3. Encapsulación y Ocultamiento

Se tratan los dos paradigmas de forma conjunta, puesto que se utilizan normal-
mente de forma simultánea.

Encapsular, significa reunir a todos los elementos que pueden considerarse perte-
necientes a una misma entidad, al mismo nivel de abstracción.

Ocultamiento, consiste en separar el aspecto externo del objeto o interfaz, al cual


pueden acceder otros objetos, del aspecto interno e implementación del mismo,

26
Unidad 1.3 Paradigmas de la Orientación a Objetos

que es inaccesible para los demás. Permite tratar a un objeto como una caja ne-
gra, la cual solo es tratada por el resto de objetos por su el interfaz.

Permite, por tanto que se modifique la implementación interna de un objeto sin


afectar a los clientes que lo utilizan. De esta manera, mientras el interfaz no varíe,
se puede modificar la implementación o el aspecto interno, sin que los objetos con
los que interrelaciona se vean afectados.

4. Relaciones

Las clases no existen de forma aislada sino que muchas veces tienen dependencias
entre ellas. Estas dependencias es a lo que se llama relación y existen distintos ti-
pos o grados, que se enumeran a continuación:

 Asociación: Relación simple.

 Agregación: Contenido en ...

 Composición: Obligatoriedad. Uno no puede existir sin el otro.

 Herencia: Relación Jerárquica. Son del tipo de

 Relaciones dinámicas: Mensajes.

4.1 Relación de Asociación

Representa la dependencia más general entre clases, siendo una dependencia


de tipo semántico. Por defecto es bidireccional, aunque se puede restringir a
una sola dirección.

Esta relación tiene multiplicidad (propiedad que expresa el número de instan-


cias de cada clase que participa en la relación):

 0..1 : cero o uno

 1 : uno y solo uno

 0..* o * : cero o muchos

27
MÓDULO 1

 1..* : uno o muchos

En los diagramas UML, la linea recta se utiliza para


representar la asociación bidireccional y la flecha (linea discontinua o conti-
nua) cuando es unidireccional.

 Ejemplo de asociación unidireccional: Un pedido puedo acceder a un


producto, pero desde un producto no puedo acceder a un pedido. Otro ejemplo,
sería miPrograma puede acceder a un producto, pero un producto no puede ac-
ceder a miPrograma.

 Ejemplo de asociación bidireccional: Un cliente puede acceder a un pedi-


do, y un pedido puede acceder a un cliente.

4.2 Relación de Agregación

Es una forma particular de asociación que expresa un acoplamiento mas fuer-


te entre objetos.

Indica que los objetos de una clase contienen o están formados por objetos de
otras clases, aunque no siempre precisa una contención física, sino al menos
lógica.

28
Unidad 1.3 Paradigmas de la Orientación a Objetos

Por tanto, un objeto que representa el ‘todo’, está asociado con un conjunto
de objetos que representan sus componentes.

En los diagramas UML, el rombo blanco se utiliza para repre-


sentar la agregación.

 Ejemplo de agregación: Una centralita puede contener llamadas. Pero


puede existir sin ellas.

4.3 Relación de Composición

Se trata de una relación de agregación fuerte.

Un objeto no puede existir si no existen los objetos de los que está compues-
to.

En los diagramas UML, el rombo negro se utiliza para repre-


sentar la composición.

 Ejemplo de composición: Un coche no puede existir, sin las partes que le


componen, en este caso, las ruedas, la carrocería y el motor.

29
MÓDULO 1

4.4 Relación de Herencia

Se basa en la existencia de relaciones de generalización/especialización entre


clases.

Las clases se disponen en una jerarquía, donde una clase hereda los atributos
y operaciones de las clases superiores en la jerarquía.

Una clase puede tener sus propios atributos y operaciones adicionales a los
heredados y puede modificar los atributos y operaciones heredadas si necesita
cambiar su implementación.

En los diagramas UML, la flecha cerrada blanca se utiliza para represen-


tar la herencia.

 Ejemplo de herencia: En nuestro mundo real, estamos modelizando a los


animales. Todos ellos, deben de hacerRuido, comer, dormir y rugir. Cada una de
las especializaciones, tanto los Felinos como los Caninos saben como rugir. A su
vez, cada una de las especializaciones saben como comer, y como hacerRuido.
Todos ellos, realizan la operación de dormir de la misma manera que se ha de-
terminado en la clase Animal.

30
Unidad 1.3 Paradigmas de la Orientación a Objetos

4.5 Relación dinámica: Mensaje

Un mensaje es un comando o petición que se le envía a otro objeto, para que


realice una operación.

El objeto llamante requiere el conocimiento previo del interfaz del objeto re-
ceptor, porque sino no tiene manera de saber que peticiones tiene disponibles
y los formatos del mensaje a enviar.

Esta relación se indica que es dinámica ya que se observa en ejecución, no en


el diseño (en diseño solo se observan las interfaces y las relaciones). En una
clase, por tanto no se define, ningún tipo de mensaje. Es en ejecución, donde
se aprecia los mensajes que un objeto llamante envía a uno receptor para que
modifique su estado o cambie su comportamiento.

 Ejemplo de mensaje: El mensaje en este ejemplo es la llamada desde una-


Persona al objeto unReloj, para que le de la hora mediante el método getHora.
Para ello, el objeto unaPersona tiene que conocer el interfaz de unReloj, para
saber que método es el que tiene que llamar, si tiene que pasarle parámetros,
de que tipos y si le va a devolver alguna información y una vez más, de que ti-
po.

31
MÓDULO 1

5. Polimorfismo

Permite implementar múltiples formas de un mismo método, dependiendo cada una


de ellas de la clase sobre la que se realice la implementación. Esta basado en el
concepto especialización de la herencia, donde cada clase hija, sabe implementar
mejor que el padre alguno o todos sus métodos.

Esto posibilita desencadenar implementaciones de operaciones diferentes como


respuesta a un mismo mensaje, en función del objeto que lo reciba.

En el polimorfismo, una vez creados los objetos, se abstraen a la clase padre que
proporciona el interfaz, para que el objeto llamante generalice su envío de mensaje
independientemente del tipo de objeto específico o clase hija; solamente debe de
ser consciente del interfaz del mismo, mediante la clase padre. Es en ejecución,
cuando dependiendo realmente del tipo de objeto real, se ejecutará la implementa-
ción concreta de cada objeto.

 Ejemplo de polimormismo: En el ejemplo, el Matemático, solo va a tener


relación con Figura para calcularArea y calcularPerimetro. Pero realmente es ca-
da una de las figuras, la que sabe como tiene que calcularArea o calcularPeri-
metro. Por eso, cada una de ellas, Cuadrado, Triangulo y Circulo van a imple-
mentar cada uno de los métodos de una manera mas especializada que el padre

32
Unidad 1.3 Paradigmas de la Orientación a Objetos

Construir un Diagrama de Clases UML a partir de las siguientes observacio-


nes:

 Una margarita es un tipo de flor.


 Una rosa es un tipo de flor.
 Las rosas rojas y las rosas amarillas son tipos de rosas.
 Un pétalo es una parte de ambos tipos de flores.
 Los pájaros se comen a ciertas plagas como los pulgones, que pueden
infectar a ciertos tipos de flores.

Del enunciado de la práctica, se pueden determinar distintas relaciones:

 Existe una clase Flor que contiene Pétalos: Relación de composición. Aunque
en el mundo real existen flores sin pétalos (sería una relación de agrega-
ción) en el ámbito de nuestro problema, solo contemplamos flores con ellos.

 Las clases Rosa y Margarita tienen son Flores, por lo que tienen una rela-
ción de herencia con Flor.

33
MÓDULO 1

 Como solución también válida, se podría tener una relación de herencia con
Rosa, las clases RosaAmarilla y RosaRoja, pero de esta manera, teniendo un
atributo color permite una mejor reutilización en el caso de que pueda apa-
recer otra rosa de otro color.

 A su vez, como tipos de Plaga que pueden asolar a nuestras Flores son los
Pulgones , por lo que tiene una relación de herencia entre Plaga y Pulgon y
una relación de asociación entre Plaga y Flor. La Flor conoce a la Plaga pero
no a la inversa.

 Como los Pajaros se comen a las plagas, tienen relación de asociación con
ellas, con cualquier tipo, ya sea un Pulgon o en un futuro una ArañaRoja.

34
Unidad 1.3 Paradigmas de la Orientación a Objetos

En esta Unidad hemos estudiado los diferentes paradigmas de la programación


Orientada a Objetos. Estos son:
 Abstracción
 Encapsulación y Ocultamiento
 Relaciones
- asociación
- agregación
- composición
- herencia
- mensaje
 Polimorfismo

35
MÓDULO B

UNIDADES DIDÁCTICAS:

1. Introducción a Java. Características del lenguaje

2. Entorno de desarrollo

3. Sintáxis. Identificadores, keywords, variables,

tipos de datos, operadores, tipos de sentencias

4. Clases, objetos, herencia, polimorfismo

5. Otros conceptos. Paquetes, modificadores de

acceso, static, final, constantes


MÓDULO B

Introducción a Java. Características


del lenguaje

Tema 2.1

Índice de la unidad:

1. Introducción

2. Características del lenguaje

3. La plataforma Java
Unidad 2.1 Introducción a Java. Características del lenguaje

En esta unidad veremos el origen del lenguaje de programación Java y cuales son
sus principales características.

1. Introducción

Fue creado por Sun Microsystems en el año 1991 e inicialmente se denómino OAK y
se desarrolló principalmente orientándolo a la programación de microsistemas y
componentes electrónicos.

Tras el cambio de nombre y modificaciones de diseño, el lenguaje Java fue presen-


tado en sociedad en Enero de 1995 con una nueva orientación: Internet. Fue pre-
sentado conjuntamente con un navegador Web denominado HotJava.

Tiene una sintaxis muy similar a la de C++, pero tiene un modelo de objetos mas
simple y elimina elementos de bajo nivel que suelen inducir a muchos errores, co-
mo pueden ser la manipulación directa de punteros o memoria.

Entre noviembre de 2006 y mayo de 2007, Sun Microsystems cedió la mayor parte
de sus tecnologías Java a GNU GPL, de tal forma que prácticamente todo el Java de
Sun es ahora Software libre.

La idea inicial del lenguaje se basó en el paradigma de Write Once, Run Anywhere
(Escribe una vez, ejecuta en cualquier lugar), proporcionando un lenguaje indepen-
diente de la plataforma en la que se ejecute.

Java ha sufrido numerosos cambios desde la versión inicial, JDK (Java Depelopment
Kit o entorno de desarrollo) 1.0, así como un aumento increíble en el número de
clases y paquetes que componen la biblioteca estándar. Esta biblioteca estándar se
ha visto ampliada por numerosas bibliotecas de carácter específico, como pueden
ser las bibliotecas visuales, comunicaciones, etc.

43
MÓDULO 2

2. Características del lenguaje

A continuación enumeramos todas las características de este lenguaje de progra-


mación Orientado a Objetos, que además de cumplir con los paradigmas de esta
disciplina de programación (Abstracción, Encapsulación y Ocultamiento, Herencia,
Polimorfismo y Reutilización), posee las siguientes propiedades:

 Sencillo

 Distribuido

 Interpretado

 Robusto

 Seguro

 Arquitectura neutra y portabilidad

 Altas prestaciones

 Multithread

 Dinámico

A continuación veremos en más detalle cada una de las características mencio-


nadas.

2.1 Sencillo

Los creadores de Java se basaron en el lenguaje de programación C++, pero


eliminaron la mayoría de sus complejidades, para facilitar su aprendizaje, su lec-
tura y el mantenimiento de los programas. A continuación se listan algunas de
las complejidades que se eliminaron:

 No soporta tipos de datos: struct, union, y puntero

 No soporta typedef ni #define

44
Unidad 2.1 Introducción a Java. Características del lenguaje

 No permite la sobrecarga de operadores.

 No soporta la herencia múltiple.

 No soporta destructores.

 Posee una clase String, en vez del array de tipo char[] finali-
zado con nulo.

 Cuenta con un sistema automático para asignar y liberar


memoria: el Garbage Collector. Uno de los grandes problemas de
C++ es la reserva y liberación de la memoria de forma programática,
provocando indeseados memory leaks.

2.2 Distribuido

Está concebido para trabajar en un entorno conectado en red.

Cuenta con una amplia biblioteca de clases para comunicarse mediante los
protocolos de comunicaciones TCP/IP: HTTP, FTP… abriendo sockets, estable-
ciendo y aceptando conexiones con servidores o clientes remotos.

Permite manipular con gran facilidad recursos vía URL.

2.3 Interpretado

Para que un programa Java puede ejecutarse, tiene que ser compilado pre-
viamente mediante un compilador. Es la principal diferencia con el resto de
lenguajes interpretados. Necesita ser válidado y compilado en un paso previo
al de su ejecución.

El compilador de Java traduce el código fuente o programa java a un código


intermedio (bytecode) o código máquina similar a las instrucciones de ensam-
blador pero independiente de la máquina física en la que se ejecuta.

45
MÓDULO 2

Los bytecodes son interpretados (ejecutados) en cualquier entorno donde


exista un intérprete de Java generando código máquina. El intérprete de Java
se llama Máquina Virtual Java o Java Virtual Machine (JVM) y este si que es
dependiente de la plataforma en la que se ejecuta, existiendo un instalable
para la mayoría de sistemas operativos y arquitecturas como veremos en la
Unidad 2.2.

A continuación se muestra cual sería el procedimiento a seguir, para poder


ejecutar un programa java.

Esta característica es la que posibilita el propósito inicial de Write Once, Run


Everywhere.

46
Unidad 2.1 Introducción a Java. Características del lenguaje

2.4 Robusto

Un software robusto es aquel que no se ‘interrumpe’ fácilmente a consecuen-


cia de fallos. Al ser previamente compilado, todos los errores sintácticos son
detectados en este fase y obligatoriamente tienen que ser eliminados.

Un lenguaje de estas características suele tener más restricciones a la hora de


programar y realiza numerosas comprobaciones tanto en compilación como
en ejecución. Facilita el manejo de excepciones, para poder tratar los fallos en
ejecución (se verán en más detalle en la Unidad 3.5).

El tratamiento automático de la memoria impide poder sobrescribirla y co-


rromper o modificar otros datos mediante punteros.

2.5 Seguro

Por su naturaleza distribuida, donde por ejemplo, los applets se bajan desde
cualquier punto de la red y se ejecutan en local, el tema de la seguridad es
muy crítico. A nadie le gustaría ejecutar en su propio ordenador programas
que tuvieran total acceso a su sistema, donde por ejemplo, pudieran coger in-
formación confidencial, tales como passwords o cuentas bancarias o incluso
poder formatear el ordenador personal.

Todos los navegadores poseen una ‘sand box’ o entorno de ejecución contro-
lado donde no se permite realizar ninguna ejecución fuera de ella (como pue-
de ser acceso al sistema de ficheros) a menos que se indiquen explícitamente
excepciones por parte del usuario que lo ejecuta.

Estas excepciones pueden venir determinadas por tecnologías de firma digital


para confiar en un determinado código Java y/o mediante políticas de seguri-
dad para controlar de una manera más precisa que puede o no puede hacer
(por ejemplo leer ciertos ficheros, poder abrir sockets ...).

2.6 Arquitectura neutra y portabilidad

Los bytecodes, resultados de la compilación de los programas java, son inter-


pretados en cualquier plataforma donde exista una JVM, ya sea por ejemplo,
una plataforma Windows, Unix, Mac, entre otras.

47
MÓDULO 2

Son independientes de que su ejecución se realicen en estaciones de trabajo,


o en servidores, o en arquitecturas físicas con el mismo sistema operativo o
sistemas hetereogéneos.

Por tanto, el código bytecode es independiente no solo de la plataforma Soft-


ware en la que se ejecuta, sino también de la plataforma Hardware.

La portabilidad entre las plataformas, se consigue, debido a que la JVM espe-


cifica el tamaño de sus tipos básicos, el comportamiento de los operadores
aritméticos y el uso de estándares como UNICODE, IEEE 754 etc… que per-
miten representar cualquier carácter mediante 2 bytes en lugar de uno solo,
como ocurre con el ASCII.

2.7 Altas prestaciones

Existen intérpretes JIT (Just-in-time) que interpretan el código en el momento


de la ejecución, generando código máquina una sola vez y en las sucesivas
ejecuciones reutiliza dicho código máquina en lugar de volver a generar cada
vez que pasa la ejecución por ahí.

A partir de la JVM 1.2.2 se introdujo un nuevo JIT llamado HotSpot.

48
Unidad 2.1 Introducción a Java. Características del lenguaje

A pesar de todo, existe algún compilador ‘real’ de Java (perdemos la portabili-


dad y ganamos en rendimiento). Es decir, que se compila antes de su ejecu-
ción, generando un ejecutable (no código interpretable) atado a dicha plata-
forma. Este tipo de compilador se encuentran en desuso.

2.8 Multithread

El término multithread o multihilo en castellano, se refiere a la ejecución de


varias tareas a la vez en un mismo proceso, limitadas estrictamente en tiem-
po real por el número de procesadores.

 Ejemplo: Mientras que un thread se encarga de interactuar con el


usuario, y otro thread realiza ciertos cálculos. Por ejemplo, es bastante frecuen-
te la existencia de un thread que espera que un usuario lance una petición de
operación y en el momento de la llegada se abra otro thread para ejecutar dicha
operación, mientras el thread de comunicación con el usuario queda a la espera
de nuevas peticiones. Así, si tres usuarios realicen tres peticiones al mismo
tiempo el número total de threads serían 4, uno por cada operación ejecutándo-
se más el thread que sigue quedando a la espera de nuevas comunicaciones.
Cuando la ejecución de cada operación termine, el thread correspondiente ter-
minará y desaparecerá.

Para poder realizar esta ejecución simultanea de varias tareas, Java posee
una serie de clases que facilitan su utilización.

2.9 Dinámico

El código C++, a menudo requiere una recompilación y lincado completa si


cambia una clase.

Java utiliza una fase de linkado o utilización de clases en tiempo de ejecución


en modo dinámico. Así las clases solo son utilizadas cuando son necesitadas.
Permite utilizar nuevas clases bajo demanda, procedentes de fuentes diver-
sas, inclusive internet.

Para conseguir esto, Java emplea un método de interfaces para evitar estas
dependencias y recompilaciones.

Además, Java permite la indirección. Es decir, en lugar de indicarle de forma


directa que utilice la clase X, se le puede indicar que busque entre todas las

49
MÓDULO 2

clases vía programática, una clase denominada X, y una vez encontrada que
la ejecute. Este acceso se puede realizar tanto a nivel de clase, como a nivel
de método y atributo.

3. La plataforma Java

Como hemos mencionado anteriormente, una plataforma es tanto el entorno hard-


ware y/o software donde se ejecuta un programa.

 Ejemplo: Ejemplos de estas plataformas son:

1. Plataformas Intel, RISC, SPARC…

2. Plataformas Win32, Linux, AIX, Solaris, HP-UX, z/OS…

3. Plataformas IBM, Sun, HP, Microsoft…

La plataforma Java es una plataforma solo software que se ejecuta sobre otra pla-
taforma hardware/software.

Tiene dos componentes diferenciables:

 La máquina virtual Java (JVM) o intérprete de Java.

 La Interfaz de Programación de Aplicaciones (API). El API Ja-


va es un conjunto de clases ya desarrolladas que ofrecen un gran
abanico de posibilidades al programador. El conjunto de las APIs son
controlados por el grupo JCP (Java Component Process)

Existen distintas ediciones de la plataforma Java:

50
Unidad 2.1 Introducción a Java. Características del lenguaje

 Java ME: Java Micro Edition. Orientado a entornos con recur-


sos limitados como teléfonos móviles, PDAs,

 Java SE: Java Standard Edition. Orientados a entornos de


gama media y estaciones de trabajo, como por ejemplo un usuario
medio en un PC de escritorio.

 Java EE: Java Enterprise Edition. Orientados a entornos em-


presariales distribuidos o Internet.

51
MÓDULO 2 PROGRAMACIÓN JAVA

En esta unidad se ha visto el origen del lenguaje de programación Java y las


características que lo conforman:
- Orientado a Objetos
- Seguro
- Distribuido
- Interpretado
- Robusto
- Seguro
- Arquitectura neutra y portabilidad
- Altas prestaciones
- Multithread
- Dinámico

Además se han categorizado los distintos tipos de plataformas Java:

- Java ME
- Java SE
- Java EE
MÓDULO B

Entorno de desarrollo

Tema 2.2

Índice de la unidad:

1. Java Development Kit

2. Contenido y componentes del JDK

3. IDE o Entorno integrado de desarrollo


Unidad 2.2 Entorno de Desarrollo

En esta unidad veremos el entorno de desarrollo de Java, denominado JDK (Java


Development Kit) y sus principales características.

1. Java Development Kit

Es el entorno de desarrollo de referencia para programas desarrollados del lenguaje


de programación Java.

El JDK como tál, es un conjunto de especificaciones que son implementadas por


distintos proveedores, tales como:

 Sun, que tiene una JDK para las siguientes plataformas: Win-
dows en sus distintas versiones, Linux y Solaris (Sun). Descargable
de forma gratuita de la siguiente URL
http://java.sun.com/javase/downloads

 IBM, que tiene una JDK para las siguientes plataformas: Win-
dows en sus distintas versiones, Linux, AIX, OS/2, OS/400 y z/OS.

 Apple, que tiene una JDK para las siguientes plataformas: Ma-
cintosh .

1. 1 Historia

La primera versión del JDK fué el JDK 1.0.0 que se retiró de circulación con la
aparición del JDK 1.1.0

El nombre ha ido cambiando entre JDK (Java Development Kit) y SDK (Soft-
ware Development Kit), quedando de nuevo JDK como nombre actual. Tam-
bién ha ido cambiando el sistema de numeración, cambiando a 5.0 en lugar de
1.5.

A su vez, y a partir de la versión 1.2, el nombre "J2SE" (Java 2 Platform,


Standard Edition), reemplazó a JDK para distinguir la plataforma base de J2EE
(Java 2 Platform, Enterprise Edition) y J2ME (Java 2 Platform, Micro Edition).

55
MÓDULO 2

A partir de la versión 5 se ha quitado el 2 del nombre, quedando la nomencla-


tura Java SE, Java EE y Java ME respectivamente

Cada una de estas plataformas, contienen tanto una JDK (o entorno de desa-
rrollo y ejecución) como un JRE (o Java Runtime Environment, solamente uti-
lizado en ejecución), también llamado JVM. En este curso, solamente nos cen-
traremos en el JDK del Java SE.

Desde la versión 1.4 de J2SE, la evolución del lenguaje de programación Java


ha sido regulada por el JCP (Java Community Process), que utiliza Java Speci-
fication Requests (JSRs) para proponer y especificar cambios en la plataforma
Java. El lenguaje en sí mismo está descrito en el Java Language Specification
(JLS), o Especificación del Lenguaje Java. Los cambios en los JLS son gestio-
nados en JSR 901.

Veamos a continuación un breve resumen de las versiones y los cambios im-


portantes que hubo en cada una de ellas:

 JDK 1.0: Aparece el 23 de Enero de 1996.

 JDK 1.1: Aparece el 19 de Febrero de 1997. Los cambios que


incluye son:

56
Unidad 2.2 Entorno de Desarrollo

 Una reestructuración amplia del modelo de eventos


AWT (Abstract Windowing Toolkit).

 Clases internas (inner clases), JavaBeans, JDBC (Java


Database Connectivity) para la integración con bases de
datos, RMI (Remote Method Invocation)

 SDK 1.2: Aparece el 8 de diciembre de 1998, con el nombre en


clave Playground. Esta y las siguientes versiones fueron recogidas
bajo la denominación Java 2. Otras mejoras añadidas incluían:

 La palabra reservada (o keyword) strictfp,

 Reflexión en la programación (Reflection API)

 La API gráfica, Swing, fue integrada en las clases bási-


cas

 La máquina virtual (JVM) de Sun fue equipada con un


compilador JIT (Just in Time) por primera vez

 El Java Plug-in para ejecución de Java en los navegado-


res.

 Java IDL, una implementación de IDL (Lenguaje de


Descripción de Interfaz) para la interoperabilidad con
CORBA

 Colecciones (Collections)

 SDK 1.3: Aparece el 8 de mayo de 2000 con el nombre clave


Kestrel. Los cambios más notables fueron:

 La inclusión de la máquina virtual de HotSpot JVM (la


JVM de HotSpot fue lanzada inicialmente en abril de 1999,
para la JVM de J2SE 1.2)

 RMI fue cambiado para que se basara en CORBA

 JavaSound API

57
MÓDULO 2

 Se incluyó el Java Naming and Directory Interface


(JNDI) en el paquete de bibliotecas principales (anterior-
mente disponible como una extensión)

 Java Platform Debugger Architecture (JPDA)

 SDK 1.4: Aparece el 6 de febrero de 2002 con el nombre en


clave Merlin. Este fue el primer lanzamiento de la plataforma Java
desarrollado bajo el JCP como JSR 59. Los cambios más notables
fueron:

 Palabra reservada o keyworkd assert

 Expresiones regulares modeladas al estilo de las expre-


siones regulares Perl

 Encadenación de excepciones Permite a una excepción


encapsular la excepción de bajo nivel original.

 Non-blocking NIO (New Input/Output)

 Logging API

 API I/O para la lectura y escritura de imágenes en for-


matos como JPEG o PNG

 Parser XML integrado y procesador XSLT (JAXP)

 Seguridad integrada y extensiones criptográficas (JCE,


JSSE, JAAS)

 Java Web Start incluido (El primer lanzamiento ocurrió


en marzo de 2001 para J2SE 1.3)

 JDK 5.0: Aparece el 30 de septiembre de 2004 con el nombre


clave Tiger. Los cambios más notables fueron:

 Plantillas (generics) que proporcionan conversion de ti-


pos (type safety) en tiempo de compilación para coleccio-

58
Unidad 2.2 Entorno de Desarrollo

nes y elimina la necesidad de la mayoría de conversion de


tipos (type casting).

 Metadatos, también llamados anotaciones, permite a


estructuras del lenguaje como las clases o los métodos,
ser etiquetados con datos adicionales, que puedan ser
procesados posteriormente por utilidades de proceso de
metadatos.

 Autoboxing/unboxing o conversiones automáticas entre


tipos primitivos (como los int) y clases de wrapper para
tipos primitivos (como los Integer).

 Enumeraciones; la palabra reservada enum crea una


typesafe, lista ordenada de valores (como Dia.LUNES,
Dia.MARTES, etc.). Anteriormente, esto solo podía ser lle-
vado a cabo por constantes enteras o clases construidas
manualmente.

 Varargs o número de argumentos variable. El último


parámetro de un método puede ser declarado con el nom-
bre del tipo seguido por tres puntos (por ejemplo: void
drawtext(String... lines)). En la llamada al método, puede
usarse cualquier número de parámetros de ese tipo, que
serán almacenados en un array para pasarlos al método.

 Bucle for mejorado. La sintaxis para el bucle for se ha


extendido con una sintaxis especial para iterar sobre cada
miembro de un array o sobre cualquier clase que imple-
mente el interfaz Iterable, como la clase estándar Collec-
tion

 JDK 6.0: Aparece el 11 de diciembre de 2006 con el nombre


clave Mustang. Los cambios más importantes introducidos en esta
versión son:

 Incluye un nuevo marco de trabajo y APIs que hacen


posible la combinación de Java con lenguajes dinámicos
como PHP, Python, Ruby y JavaScript.

59
MÓDULO 2

 Incluye el motor Rhino, de Mozilla, una implementación


de Javascript en Java.

 Incluye un cliente completo de Servicios Web y soporta


las últimas especificaciones para Servicios Web, como
JAX-WS 2.0, JAXB 2.0, STAX y JAXP.

 Mejoras en la interfaz gráfica y en el rendimiento.

 Incluye JavaDB (el conocido Derby de Apache).

2.Contenido y componentes del JDK

Antes de empezar a trabajar con un IDE (o Entorno Integrado de Desarrollo) que


facilita el desarrollo y ejecución de los programas Java, vamos a trabajar con el JDK
directamente, para poder afianzar ciertos conceptos imprescindibles.

Ver la Unidad Instalación del JDK y Eclipse para los detalles de la instalación.

Hay dos variables de entorno de gran relevancia para el JDK, PATH y CLASSPATH:

 PATH: Variable de entorno del Sistema Operativo en la que se


listan los directorios donde se encuentran los ejecutables de los pro-
gramas instalados en una máquina. En el caso del JDK, se encuen-
tran en el directorio bin de la instalación.

 CLASSPATH: Variable de entorno del Sistema Operativo en la


que se le indican donde se van a encontrar las clases Java para la
compilación y ejecución de los programas. Esta variable solo será ne-
cesaria en la ejecución de los programas Java. Desde el JDK 1.4.0 si
no hay variable CLASSPATH definida, el JDK asume el . (punto), es
decir, el directorio desde donde ejecutemos las herramientas como
punto de partida para buscar.

2.1 Contenido

A continuación se muestran que directorios contiene el JDK y para que se utili-


zan:

60
Unidad 2.2 Entorno de Desarrollo

 /bin: las herramientas y utilidades del JDK (ejecutables).

 /db: gestor de base de datos (nuevo de la versión 6.0).

 /lib:las librerías del JDK, utilidadas por él mismo.

 /include: los archivos C/C++ utilizados para construir la JVM.

 /demo: una variedad de ejemplos escritos en Java.

 /jre: la JVM sin herramientas de desarrollo

 /src.zip: el código fuente de las APIs Java.

2.2 Componentes

A continuación se muestran los componentes que conforman el JDK.

 javac.exe: Compilador de Java.

 java.exe: Intérprete de Java (JVM).

 appletviewer.exe: Intérprete de applets Java.

 jdb.exe: Depurador de Java.

 javadoc.exe: Generador de documentación.

 javah.exe: Integrador de C y C++ (JNI).

 javap.exe: Desensamblador.

Existe documentación online acerca del JDK en la siguiente URL


http://java.sun.com/javase/6/docs/api/index.html

3. IDEs o Entorno Integrado de Desarrollo

En el capítulo anterior, hemos estado viendo el JDK no visual. Pero existen herra-
mientas gráficas que simplifican el desarrollo, compilación y ejecución de los pro-

61
MÓDULO 2

gramas Java (al menos en entornos de desarrollo). Mencionamos a continuación las


mas importantes y las URLs de referencia:

 Eclipse: Es Open Source. Es la herramienta gráfica que utiliza-


remos durante el curso. http://www.eclipse.org (ver la Unidad Insta-

lación del JDK y Eclipse para su instalación)

 Rational Application Developer: Es de IBM


http://www.ibm.com/software/awdtools/developer/application y está

construido sobre Eclipse.

 NetBeans IDE: Es Open Source. http://www.netbeans.org

 Sun Java Studio Creator: Es de Sun

http://developers.sun.com/jscreator

 JBuilder: Es de Borland

http://www.codegear.com/products/jbuilder

 IntelliJ IDEA: Es de jetBrains http://www.jetbrains.com/idea

PRÁCTICA A: Requiere instalar el JDK. Desde una sesión de DOS, ir a un directorio


distinto del de la instalación del JDK y ejecutar los comandos java.exe -version

62
Unidad 2.2 Entorno de Desarrollo

y javac.exe

En el caso de que no aparezcan correctamente la salida de los comandos mencio-


nados anteriormente, verificar el valor de la variable de entorno PATH comprobando
que contiene el directorio bin donde se haya instalado el JDK.

PRÁCTICA B: Requiere instalar el JDK. Desarrollar un programa Java que muestre


por pantalla el texto “¡Hola Mundo!” con el JDK de Sun.

63
MÓDULO 2

En el caso de que no esté puesta la variable de entorno PATH, abrir una sesión DOS
y ajustar la variable PATH para que el Sistema Operativo sepa encontrar las herra-
mientas del JDK. Para respetar el valor que ya tuviese la variable PATH le añadimos
%PATH%.

Creamos un directorio de trabajo donde guardar el programa Java.

Ajustar la variable CLASSPATH para que las herramientas del JDK sepan encontrar
nuestras clases Java. Tenemos dos opciones, o añadir el . (punto) y siempre
ejecutar las herramientas en el directorio donde se encuentre el código, o añadir el
directorio de trabajo y ejecutar las herramientas donde queramos. Para respetar el
valor que ya tuviese la variable CLASSPATH le añadimos %CLASSPATH%.

64
Unidad 2.2 Entorno de Desarrollo

Ahora arrancamos un editor de texto (por ejemplo Notepad) para escribir el código
fuente de nuestro programa que guardaremos en el fichero Practica1.java; el
nombre del fichero debe ser exactamente igual (incluyendo mayúsculas y
minúsculas) al de la clase Java que vamos a desarrollar.

Y aceptamos la creación de un fichero nuevo.

65
MÓDULO 2

Escribimos el código y salvamos los cambios. Cerramos el Notepad.

Compilamos el programa Java con el compilador “javac”. Al compilador hay que


darle el nombre del fichero incluyendo su extensión.

66
Unidad 2.2 Entorno de Desarrollo

Si no sale ningún mensaje significa que todo ha ido bien y que ha creado el
bytecode, es decir, Practica1.class

Por último, ejecutamos el programa Java con la JVM “java”. A la JVM hay que darle
el nombre del fichero del bytecode sin la extensión.

67
MÓDULO 2

PRÁCTICA C: Requiere instalar Eclipse. Desarrollar un programa Java que mues-


tre por pantalla el texto “¡Hola Mundo!” con Eclipse

Arrancar Eclipse, ejecutando c:\eclipse3.5.2\eclipse.exe

Seleccionar la ubicación del “workspace” (o área de trabajo).

Cerrar la ventana de bienvenida si aparece (esta ventana aparece la primera vez


que se arranca Eclipse).

68
Unidad 2.2 Entorno de Desarrollo

69
MÓDULO 2

Verificar que la perspectiva Java está abierta, y sino cambiar a ella

Crear un proyecto nuevo de nombre Practica2.

Darle el nombre y seleccionar Finish.

70
Unidad 2.2 Entorno de Desarrollo

Crear una clase Java nueva llamada Practica2 con el método main.

71
MÓDULO 2

Seleccionar Finish
Escribir el código dentro del método main y salvar con Ctrl + S o File -> Save

72
Unidad 2.2 Entorno de Desarrollo

Por defecto, en eclipse, al salvar los cambios realizados en un fichero, se realiza la


compilación de las clases que están en el worskpace.

En el caso de producirse algún error de compilación, se pueden ver en la vista Pro-


blems

Seleccionando la clase Java, con el botón derecho del ratón ejecutarla como Java
Application

73
MÓDULO 2

Y veremos como se abre una consola con el resultado.

74
Título de unidad didáctica

En este unidad hemos visto la historia del JDK desde su comienzo hasta el mo-
mento actual, viendo las distintas posiblidades de desarrollo, vía el JDK directa-
mente (entorno no gráfico) o vía los entornos gráficos o IDEs, tales como Eclipse,
Rational Application Development ...

Se han visto también el contenido y componentes que forman un JDK y dos


variables muy importantes a tener en cuenta en entornos de desarrollo Java que
son PATH y CLASSPATH.
MÓDULO B

Sintáxis

Tema 2.3

Índice de la unidad:

1. Comentarios

2. Puntos y coma, bloques y espacios en blanco

3. Identificadores

4. Variables

5. Tipos de datos

6. Variables primitivas versus complejas

7.
Unidad 2.3 Sintaxis

En esta unidad trataremos en detalle la sintaxis del lenguaje de programación Java.


Dicha sintaxis es comprobada por el compilador y en caso de no ser correcta, este
nos indicará los errores o avisos existentes. Por defecto, no se pueden ejecutar
programas Java con errores de compilación, por lo que la sintaxis del programa de-
be ser 100% correcta.

1. Comentarios

Los comentarios son líneas de código que no son ejecutadas en tiempo de ejecu-
ción, ni siquiera son incluidas en el byte code compilado. Estos comentarios, permi-
ten incluir explicaciones acerca de qué es lo que está haciendo nuestro código, do-
cumentación, inhabilitar líneas de código que ya no son necesarias en runtime, etc.

Existen tres formas distintas de escribir los comentarios:

 // comentario de una sola línea. Abarca desde el comienzo del


comentario // hasta el final de línea.

 /* */ Comentario de una o más líneas. Abarca desde el co-


mienzo del comentario /* hasta el final del mismo */

 /** */ Comentario de documentación, utilizado por la


herramienta javadoc.exe. Abarca desde el comienzo del comentario
/** hasta el final del mismo */.

 Ejemplo: A continuación se muestra un ejemplo con los distintos ti-


pos de comentarios mencionados anteriormente.

79
MÓDULO 2

2. Puntos y coma, bloques y espacios en blanco

Uno de los caracteres más importantes a tener en cuenta en Java es el punto y co-
ma o ;.

El punto y coma define una sentencia Java o lo que es lo mismo una línea simple de
código terminada en un punto y coma. La línea simple de código puede o no estar
físicamente formada en una línea física.

 Ejemplo: A continuación se muestra un ejemplo con los distintos ti-


pos de líneas simples de código mencionados anteriormente.

80
Unidad 2.3 Sintaxis

Otro concepto importante a tener en cuenta en Java es el de bloque de código. Un


bloque es un conjunto de sentencias (de 0 a n) agrupadas entre llaves ({ }). Los
bloques pueden estar anidados.

Suelen utilizarse conjuntamente con las sentencias de control de flujo (ver punto
8), pero también pueden utilizarse, por ejemplo, para minimizar el ámbito de cier-
tas variables, como son las variables de bloque (ver punto 4.2).

 Ejemplo: A continuación se muestra un ejemplo de bloques de códi-


go con una o varias sentencias y anidamientos de bloques

Java permite los espacios en blanco entre elementos de código fuente. Son utiliza-
dos principalmente para separar cada uno de los elementos de la sintaxis Java (al
menos un espacio en blanco como mínimo) y mejorar el entendimiento del código
(el número de espacios utilizado para este propósito es irrelevante).

 Ejemplo: A continuación se muestran ejemplos donde los espacios


se utilizan como separadores de elementos de la sintaxis (entre int e i, y en-
tre int y j entre otros) y como mejoras para el entendimiento del código:

81
MÓDULO 2

3. Identificadores

Son los nombres unívocos que se le dan a las clases, métodos y variables. Hay que
tener presente las siguientes reglas:

 El identificador debe empezar por una letra, subrayado (_) o


dólar ($).

 Después del primer carácter se pueden usar números.

 Java distingue entre mayúsculas y minúsculas (es “case sensi-


tive”). Los identificadores VARIABLE y variable son dos identificado-
res distintos.

 Nunca pueden coincidir con una ‘keyword’ o palabra reservada


del lenguaje. A continuación se muestra un listado de las keyword
mas utilizadas en Java y que por tanto tienen un significado especial
para el lenguaje

82
Unidad 2.3 Sintaxis

 Ejemplo: Los siguientes identificadores son válidos: variable, $va-


riable2, CONSTANTE, nombre_usuario, nombreUsuario, _variable_sistema

 Ejemplo: Los siguientes identificadores no son válidos: 1variable,


int, #variable, variable%Final

4. Variables

Una variable es un contenedor de datos identificado mediante un identificador o


nombre. Dicho identificador se utilizará para referenciar el dato que contiene.

Toda variable debe llevar asociado un tipo que describe el tipo de dato (ver punto
5) que guarda. Por tanto, una variable tiene:

 Un tipo

 Un identificador

 Un dato o valor.

4. 1 Declaración de variables

83
MÓDULO 2

La declaración es la sentencia mediante la cual se define una variable, asig-


nándola un tipo y un identificador. El formato es tipo identificador;

 Ejemplo: int contador; // tendrá el valor por defecto 0

Adicionalmente se le puede asignar un valor inicial mediante una asignación.


El formato es tipo identificador = valor;

 Ejemplo: int contador = 10;

En el caso de que no se le asigna un valor, se inicializará con el valor por de-


fecto para ese tipo (veremos los distintos tipos y sus valores por defecto en el
punto 5 Tipos de Datos).

4. 2 Ámbito de las variables

El ámbito de una variable es la zona de código donde se puede referenciar di-


cha variable a través de su identificador.

El lugar de declaración de una variable establece su ámbito. Los distintos ám-


bitos existentes son:

 Atributos (o variables miembro de una clase). Se pueden utili-


zar solamente asociados a la clase a la que pertenecen.

 Parámetros de método. Se pueden utilizar solamente en el


método del cual son parámetros.

 Variables locales: (o de método) siempre hay que inicializar-


las. Solamente puede accederse a ellas, dentro del método donde
han sido declaradas.

 Variables de bloque: siempre hay que inicializarlas. Solamente


puede accederse a ellas, dentro del bloque donde han sido declara-
das.

84
Unidad 2.3 Sintaxis

En el caso de que se declaren variables con el mismo identificador en ámbitos


distintos (en el mismo no se puede), tienen preferencia las del ámbito más in-
terno. Las variables de bloque tienen preferencia frente a las locales; estas tie-
nen preferencia frente a los parámetros y por último las de menor preferencia
son los atributos.

 Ejemplo: El siguiente ejemplo muestra el error de compilación al in-


tentar referenciar una variable fuera de su ámbito.

85
MÓDULO 2

 Ejemplo: El siguiente ejemplo muestra cual es la variable utilizada,


según el ámbito en el que está declarada.

86
Unidad 2.3 Sintaxis

5. Tipos de datos.

En Java existen dos tipos de datos genéricos:

 Tipos Primitivos. Existen ocho tipos de datos primitivos clasifi-


cados en cuatro grupos diferentes:
 Lógico: boolean.
 Carácter: char.
 Números enteros: byte, short, int y long.
 Números reales: double y float.

 Tipos Complejos o clases. Existe un caso especial que es el de


enumeración: enum que aparece en Java JSE 5.0

5.1 Tipo de dato lógico

La ‘keyword’ utilizada para definir un tipo de dato lógico es boolean. Sus posibles
valores son:

 true: o verdadero

 false: o falso. Es el valor por defecto.

 Ejemplos: boolean switch1 = true;

boolean switch2; // Su valor es false.

Se suelen utilizar en las sentencias de control de flujo del tipo bifurcaciones del
tipo if-then-else (ver punto 8).

5.2 Tipo de dato carácter

La ‘keyword’ utilizada para definir un tipo de dato carácter es char y representa


un carácter UNICODE, siendo su tamaño de: 16 bits (2 bytes). Desde la versión
5.0 Java soporta UNICODE 4.0 que define algunos caracteres que no caben en
16 bits por lo que se necesita un int para representarlos (o dos char dentro de
un String).

Sus posibles valores son:

 Un carácter entre comillas simples: ‘a’.

87
MÓDULO 2

 Un carácter especial con \ por delante: ‘\n’, ‘\t’, etc.

 Un código UNICODE: ‘\uxxxx’ (donde xxxx es un valor en


hexadecimal).

 El valor por defecto es ‘\u0000’ -> null. Nota: No es un espa-


cio en blanco.

 Ejemplos: char letra1 = ‘a’;

char letra2 = ‘\n’;

char letra3 = ‘\u0041’;

char letra4; // su valor es null

Para las cadenas de caracteres existe un tipo complejo: la clase String que se
verá en más detalle en la Unidad 2.6 Clases básicas.

Se suelen utilizar para el tratamiento de caracteres, ya sea como caracteres in-


dividuales dentro de un String, caracteres contenidos en un fichero, etc.

5.3 Tipo de datos enteros

Las ‘keyword’ utilizadas para definir un tipo de dato entero son byte, short, int y
long. Sus tamaños son:

 byte: 8 bits (1 byte), por tanto el rango de valores es de -128


a 127.

 short: 16 bits (2 bytes), por tanto el rango de valores es de -


32768 a 32767

 int: 32 bits (4 bytes), por tanto el rango de valores es de -


2147483468 a 2147483467

 long: 64 bits (8 bytes), por tanto el rango de valores es de -


enorme a enorme

Sus posibles valores son:

88
Unidad 2.3 Sintaxis

 Un valor decimal entero: 2 (por defecto para tipo int) o 2L


(para tipo long).

 Un valor octal: 077 (comenzando por cero).

 Un valor hexadecimal: 0xBAAC

 El valor por defecto es 0.

 Ejemplos: byte unByte = 12;

short unShort; // tiene el valor 0

short unShort; // tiene el valor 0

int unInt = -199;

int otroInt = 065;

long unLong = 2; (o long unLong = 2L;)

long otroLong = 0xABCD;

Se suelen utilizar en operaciones ariméticas, en sentencias de control de tipo bu-


cle (en concreto la sentencia for y el tipo int), etc.

5.4 Tipo de datos reales

Las ‘keyword’ utilizadas para definir un tipo de dato real son float y double. Sus
tamaños son:

 float: 32 bits (4 bytes). Su precisión varía según la platafor-


ma.

 double: 64 bits (8 bytes). Su precisión también varía según la


plataforma.

Sus posibles valores son:

 Un valor decimal entero: 2 (por defecto para tipo int).

 Un valor decimal real: 0.17 o 6.02E23 (por defecto double).

 Un valor decimal real: 0.17F o 0.17D (redundante).

89
MÓDULO 2

 El valor por defecto es 0.0 (cero).

 Ejemplos: float unFloat = 0.17F;

double unDouble; // su valor es 0.0

double otroDouble = -12.01E30;

Se suelen utilizar en operaciones ariméticas, etc.

5.5 Tipo de dato complejo

Las ‘keyword’ es el nombre de la clase del objeto que va a contener la variable.

Sus posibles valores son:

 Referencias a objetos (o instancias) en memoria.

 El valor por defecto es null

 Ejemplos: String unString = new String(“Hola”);

String otroString; // su valor es null

Se suelen utilizar para contener objetos de nuestro mundo real.

5.6 Tipo de dato enumeración

La ‘keyword’ utilizada para definir un tipo de dato enumeración es enum.

Se trata de un tipo de dato complejo algo especial que surge con la versión 5.0
de Java. Implementa una clase que tiene un atributo que puede tomar varios va-
lores y solo esos.

 Ejemplo: enum Semaforo { VERDE, AMBAR, ROJO }

Se suelen utilizar para tener una lista de posibles valores asociados a una varia-
ble y solamente dichos valores.

5.7 Ejemplos de variables con distintos tipos de datos

El siguiente ejemplo muestra el valor de variables de distintos tipos con sus va-
lores por defecto.

90
Unidad 2.3 Sintaxis

El siguiente ejemplo muestra el valor de variables de distintos tipos con sus va-
lores asignados en la declaración

5.8 Conversiones entre tipos

91
MÓDULO 2

Un tipo de dato númerico puede llegar a convertirse a otro tipo. Existen cuatro
entornos de conversión en Java:

 Promoción aritmética. Por ejemplo: de short a int y este a


float.

 Asignación. Por ejemplo: long l = 42; // un int se convierte en


long

 Llamada a métodos con parámetros. Por ejemplo: f(long p) ->


f(5) //se llama a un método con un int y se convierte a un long

 Casting. Por ejemplo: int i = (int)42L //un long se convierte en


int. Ver la explicación de downcasting.

Las conversiones implícitas se resuelven en tiempo de compilación. El upcasting


(de un tipo más pequeño convertirlo a uno más grande) se realiza implícitamen-
te.

El downcasting (de un tipo más grande convertirlo a uno más pequeño) se reali-
zan explícitamente (hay que indicar a que tipo se quiere convertir) y se resuelve
en tiempo de ejecución. Nota: puede perderse información, por lo que se obliga
a que sean realizados explícitamente.

6. Variables primitivas versus complejas

Una variable de tipo primitivo contiene el dato directamen-

te:

Una variable de tipo complejo contiene una referencia (puntero) a la zona de me-
moria donde está el objeto:

92
Unidad 2.3 Sintaxis

7. Operadores

Los operadores realizan funciones sobre uno, dos o tres operandos (op). Por tanto,
una primera clasificación puede ser esta:

 Operadores unarios: pueden ser de tipo prefijos o postfijos.


op operador u operador op.

 Ejemplo: contador++; // operador postfijo de sumar 1 a la propia


variable contador. La variable se queda con el valor sumado

 Operadores binarios: operador op operador

 Ejemplo: contador + 2; // operador de sumar un número a una va-


riable. La variable en si misma no se queda con la suma.

 Operadores ternarios: op ? op : op

 Ejemplo: contador > 2 ? true : false; // es similar a un if-then-else


de la siguiente manera if ? Then : else ;

Los operadores siempre devuelven un valor que depende del operador y del tipo
de los operandos.

Otra posible clasificación es por la naturaleza del operador:

 Aritméticos

 Relacionales

 Condicionales

 De desplazamiento

93
MÓDULO 2

 Lógicos

 De asignación

 Otros

7.1 Operadores aritméticos

A similitud con el mundo mátematico, existen los siguientes operadores aritméti-


cos binarios:

 +: suma dos operandos op1 + op2. Hay que tener cuidado


con las variables de tipo String, porque en este caso concatena los
valores.

 - : resta dos operandos op1 – op2

 * : multiplica dos operandos op1 * op2

 / : divide dos operandos op1 / op2

 % : calcula el resto de la división op1 % op2

Los valores que devuelven estos operadores depende de los tipos de los ope-
randos:

 int: cuando ninguno de los operandos es float, double o long.


En el caso del operador % siempre devuelve un int.

 long: cuando ninguno de los operandos es float o double y hay


al menos uno que es long.

 float: cuando ninguno de los operandos es double y hay al


menos uno que es float.

 double: cuando al menos hay uno de los operandos es double.

También existen operadores aritméticos unarios (actúan solo sobre un operan-


do):

94
Unidad 2.3 Sintaxis

 +op: convierten al operando en int en caso de que fuese byte,


short o char.

 -op: cambia el signo al operando.

 ++op: incrementa al operando en 1 (evaluando el operando


después de incrementarse).

 op++: incrementa el operando en 1 (evaluando el operando


antes de incrementarse).

 --op: decrementa el operando en 1 (evaluando el operando


después de decrementarse).

 op--: decrementa el operando en 1 (evaluando el operando


antes de decrementarse).

 Ejemplo: En el ejemplo siguiente se muestran los operadores autoin-


crementales, diferenciando si se evalúa el valor de la variable antes o des-
pués del incremento.

7.2 Operadores relacionales

Java tiene los siguientes operadores relacionales:

95
MÓDULO 2

 >: compara si un operando es mayor que otro op1 > op2

 <: compara si un operando es menor que otro op1 < op2

 ==: compara si un operando es igual que otro op1 == op2.


Cuidado con no confundir con el operador de asignación =

 !=: compara si un operando es distinto que otro op1 != op2

 >=: compara si un operando es mayor o igual que otro op1


>= op2

 <=: compara si un operando es menor o igual que otro op1


<= op2

Todos estos operandos devuelven un boolean indicando si cumple la compara-


ción.

 Ejemplo: if (5 < 7) { ... } // La condición se ejecutará al devolver el


operador < un true o verdadero.

7.3 Operadores condicionales

Suelen combinarse con los operadores relacionales para crear expresiones más
complejas, devolviendo un boolean. Java tiene los siguientes operadores
condicionales:

 &&: AND lógico. Comprueba si ambos operandos son verdade-


ros op1 && op2

 ||: OR lógico. Comprueba si uno de los dos operandos es ver-


dadero op1 || op2

 !: NOT lógico. Niega al operadondo !op

 Ejemplo: if (5 < 7 && 4 < 8) { ... } // La condición se ejecutará al


devolver el primer operador < un true y el segundo operador < un true.

7.4 Operadores de desplazamiento

Java tiene los siguientes operadores de desplazamiento:

96
Unidad 2.3 Sintaxis

 >>: desplaza los bits del primer operando hacia la derecha


tantas veces como indique el segundo operando op1 >> op2. Reali-
za la misma función que multiplicar por 2, tantas veces se desplace.

 <<: desplaza los bits del primer operando hacia la izquierda


tantas veces como indique el segundo operando op1 << op2. Reali-
za la misma función que dividir por 2, tantas veces se desplace.

 >>>: desplaza los bits del primer operando hacia la derecha


tantas veces como indique el segundo operando pero sin signo op1
>>> op2. Realiza la misma función que multiplicar por 2, tantas ve-
ces se desplace, pero sin tener en cuenta la posición de signo.

 Ejemplo: En los siguientes ejemplos se muestran los operadores de


desplazamiento

97
MÓDULO 2

7.5 Operadores lógicos

Java tiene los siguientes operadores lógicos:

 &: AND lógico a nivel de bit de los operandos (el resultado es


uno si los bits de ambos operandos son uno) op1 & op2. Cuidado
con no confundir con el operador lógico &&

 |: OR lógico a nivel de bit de los operandos (el resultado es


uno si alguno de los bits de los operandos es uno) op1 | op2. Cui-
dado con no confundir con el operador lógico ||

98
Unidad 2.3 Sintaxis

 ^: XOR lógico a nivel de bit de los operandos (el resultado es


uno si alguno de los bits de los operandos es uno, pero no los dos a
la vez) op1 ^ op2

 ~: complemento a nivel de bit del operando (cambia los ceros


por uno y viceversa) ~op1

7.6 Operadores de asignación

Java tiene los siguientes operadores de asignación:

 = : guarda el valor del segundo operando en el primero op1 =


op2

 += : guarda la suma de los dos operandos en el primero op1


+= op2

 -= : guarda la resta de los dos operandos en el primero op1 -


= op2

99
MÓDULO 2

 *= : guarda la multiplicación de los dos operandos en el pri-


mero op1 *= op2

 /=, %=, &=, |=, ^=, <<=, >>=, >>>=: Similar al anterior,
para cada uno de los operadores indicados.

7.7 Otros operadores

Existen otros operadores en Java como son:

 ?: : se trata de una abreviatura de la estructura if-then-else (if


op1? then op2 : else op3) op1?op2:op3

 [] : utilizado para declarar, crear y acceder a arrays (se verán


en la Unidad 3.1).

 . : utilizado para acceder a los atributos y métodos de los ob-


jetos (se verán en la Unidad 2.4).

 (parámetros) : utilizado para pasar parámetros a un método.

 (tipo) : utilizado para realizar castings (conversiones de tipo).

 new : utilizado para crear objetos nuevos (se verá en la Uni-


dad 2.4).

 instanceof : utilizado para chequear si el primer operando es


una instancia del tipo indicado en el segundo operando.

8. Sentencias de control de flujo

Sin las sentencias de control de flujo, el código Java se ejecutaría linealmente des-
de la primera línea hasta la última.

Existen cuatro tipos de sentencias de control de flujo:

 Bucles: while, do-while, for y for/in

100
Unidad 2.3 Sintaxis

 Bifurcaciones: if-then-else y switch-case.

 Gestión de excepciones: try-catch-finally y throw. Las veremos


con más detalle en la Unidad 3.5 Manejo de excepciones.

 De ruptura: break, continue, label: y return.

8.1 Sentencias while y do-while

La sentencia while se utiliza para ejecutar continuamente un bloque de código


mientras que la condición del while sea cumpla (es decir la evaluación de la
condición sea true o verdadera).

while(expresión)
{
sentencias;
}

La sentencia do-while es parecida a la sentencia while pero asegura que como


mínimo el bloque de código se ejecuta una vez.

do
{
sentencias;
}
while(expresión);

8.2 Sentencia for

La sentencia for facilita la ejecución de un bloque de código un número deter-


minado de veces, mientras la evaluación de la expresión de terminación se
cumpla o sea true.

for(inicialización; terminación; incremento)


{
sentencias;
}

Las variables definidas en la sentencia de inicialización son locales al bloque. Por


tanto dejan de existir una vez se haya terminado el bucle.

 Ejemplo: se muestra un ejemplo de las sentencias de control de tipo


bucles vistas hasta el momento

101
MÓDULO 2

8.3 Sentencia for/in

Esta nueva sentencia que aparece en el Java SE 5.0 nos facilita la iteración por
los elementos de cualquier tipo de colección: arrays, listas, etc…

for(inicialización: colección) Nota: Se usa “:” en vez de “;”.


{
sentencias;
}

Las variables definidas en la sentencia de inicialización son locales al bloque. Por


tanto dejan de existir una vez se haya terminado el bucle.

 Ejemplo: se muestra un ejemplo de la sentencia de control for/in

public void listar(int[] param)


{
for(int i: param)
System.out.println(i);
}
Básicamente, se trata de una simplificación a la hora de codificar. Es decir, al fi-
nal, el compilador convierte el código en una sentencia for convencional como la
siguiente:

102
Unidad 2.3 Sintaxis

public void listar(int[] param)


{
int i = 0;
for(int j=0; j<param.length; j++)
i = param[j];
System.out.println(i);
}

8.4 Sentencia if–then-else

La sentencia if-then-else permite elegir qué bloque de código ejecutar entre dos
posibilidades dependiendo de la evaluación de la expresión. Si se cumple (true)
ejecuta el primer bloque o bloque del if. Sino se cumple se ejecuta el bloque del
else.
La sintaxis del if sin else sería la siguiente:

if(expresión)
{
sentencias;
}

La sentencia if-then-else sería

if(expresión)
{
sentencias;
}
else
{
sentencias;
}

Las sentencias if pueden estar concatenadas. Su sintaxis sería:

if(expresión)
{
sentencias;
}
else if (expresión2)
{
sentencias;
}else
{
sentencias;
}

 Ejemplo: se muestra un ejemplo de la sentencia de control if anida-


das

103
MÓDULO 2

public void evaluar(int param)


{
if (param < 5)
{
//ejecutamos algo
} else if (param >=5 && param < 10){
//ejecutamos algo
} else {
//ejecutamos algo
}
}

8.5 Sentencia switch

La sentencia switch es un caso particular de la sentencia if-then-else if-else.


Evalúa una expresión del tipo int o que pueda ser convertida a int de forma im-
plícita (como puede ser un char).
Así se evalúa la expresión intExpresión y va comparando cada uno de los case a
ver si cumple la condición. En el caso de que la comparación sea true, se ejecu-
tan las sentencias siguientes hasta que se encuentre la siguiente sentencia
break o llegue al final de la sentencia switch.
En el caso de que todas las comparaciones sean false se ejecutará las senten-
cias del default (en el caso de existir, puesto que es optativo).

switch(intExpresión)
{
case intExpresión:
sentencias;
break;
……
……
default: // es optativo
sentencias;
}

 Ejemplo: se muestra un ejemplo de la sentencia de control switch

public void listar(int param)


{
switch(param){
case 1:
// ejecutar algo
break;
case 2:
// ejecutar algo
break;
default:
// ejecutar algo
break;
}

104
Unidad 2.3 Sintaxis

8.6 Sentencia de ruptura

Java proporciona las siguientes sentencias de ruptura de ejecución:

 break: sirve para detener la ejecución tanto de los bucles co-


mo de la sentencia switch. Por tanto, salta a la siguiente línea de có-
digo después del bucle o switch.

 continue: sirve para detener la ejecución del bloque de código


de un bucle y volver a evaluar la condición de este.

 return: sirve para finalizar la ejecución de un método (y devol-


ver un valor en el caso de ser necesario).

Nota: Las guías de programación estructurada prohiben el uso de estas senten-


cias o aconsejan un uso muy límitado para facilitar la legibilidad y mantenimien-
to del código

105
MÓDULO 2

PRÁCTICA A: Identificar que sentencias son correctas y cuáles no (se irán utili-
zando las variables según se va avanzando en el ejercicio):

1. int x = 34.5;
2. boolean boo = x;
3. int g = 17;
4. int y = g;
5. y = y + 10;
6. short s;
7. s = y;
8. byte b = 3;
9. byte v = b;
10. short n = 12;
11. v = n;
12. byte k = 128;
13. int p = 3 * g + y;

Solución:

1. int x = 34.5; -> int x = (int)34.5; // Posible con downcasting


2. boolean boo = x; -> No hay solución
3. int g = 17;
4. int y = g;
5. y = y + 10;
6. short s;
7. s = y; -> s = (short)y; // posible con downcasting
8. byte b = 3;
9. byte v = b;
10. short n = 12;
11. v = n; -> v = (byte)n; // posible con downcasting
12. byte k = 128; -> byte k = (byte)128; // posible con downcasting
13. int p = 3 * g + y;

PRÁCTICA B: Identificar si este código compila bien. Si no compila solucionarlo. Si


compila decir cuál sería la salida.

public class Temp


{
public static void main(String[] args)
{
int x = 1;

106
Unidad 2.3 Sintaxis

while(x<10)
{
if(x>3)
{
System.out.println("Hola");
}
}
}
}

Solución:
El código compila bien. Pero entra en un bucle infinito. Habría que modificarlo con
la línea roja y saldría la palabra “Hola” siete veces por pantalla.

public class Temp


{
public static void main(String[] args)
{
int x = 1;
while(x<10)
{
x = x + 1;
if(x>3)
{
System.out.println("Hola");
}
}
}
}

PRÁCTICA C: Identificar si este código compila bien. Si no compila solucionarlo.


Si compila decir cuál sería la salida.

public class Temp


{
public static void main(String[] args)
{
int x = 5;
while(x>1)
{
x = x - 1;
if(x<3)
{
System.out.println("Hola");
}
}
}
}

Solución:
Compila y saldría la palabra “Hola” dos veces por pantalla.

107
MÓDULO 2

PRÁCTICA D: Al siguiente programa Java le falta un trozo de código

public class Temp


{
public static void main(String[] args)
{
int x = 0;
int y = 0;
while(x<5)
{
//TROZO DE CODIGO A SUSTITUIR
System.out.print(x + “ ” + y + “ “);
x = x + 1;
}
}
}

Seleccionar para cada trozo de código de la izquierda, la salida por pantalla al


ejecutar el programa anterior con ese trozo de código

Solución

108
Unidad 2.3 Sintaxis

PRÁCTICA E: Desarrollar un programa Java que muestre por pantalla los números
primos del 1 al 1000 y todos los años bisiestos entre el año 2000 y el 3000.

Vamos a realizar la práctica con el con el JDK de Sun.

En el caso de que no esté puesta la variable de entorno PATH, abrir una sesión DOS
y ajustar la variable de entorno PATH para que el Sistema Operativo sepa encontrar
las herramientas del JDK. Para respetar el valor que ya tuviese la variable PATH le
añadimos %PATH%.

109
MÓDULO 2

Creamos un directorio de trabajo donde guardar el programa Java.

Ajustar la variable de entorno CLASSPATH para que las herramientas del JDK sepan
encontrar nuestras clases Java. Tenemos dos opciones, o añadir el . (punto) y
siempre ejecutar las herramientas en el directorio donde se encuentre el código, o
añadir el directorio de trabajo y ejecutar las herramientas donde queramos. Para
respetar el valor que ya tuviese la variable CLASSPATH le añadimos %CLASS-

110
Unidad 2.3 Sintaxis

PATH%.

Ahora arrancamos un editor de texto (por ejemplo Notepad) para escribir el código
fuente de nuestro programa que guardaremos en el fichero PracticaE.java; el
nombre del fichero debe ser exactamente igual (incluyendo mayúsculas y
minúsculas) al de la clase Java que vamos a desarrollar.

Y aceptamos la creación de un fichero nuevo.

111
MÓDULO 2

Escribimos el código y salvamos los cambios. Cerramos el Notepad.


En la Unidad 2.4 veremos el concepto de clase y método main. Mientras tanto,
nuestro código estará incluido entre las línea de código
public class PracticaE
{
public static void main(String[] args)
{
}
}

112
Unidad 2.3 Sintaxis

Compilamos el programa Java con el compilador “javac”. Al compilador hay que


darle el nombre del fichero incluyendo su extensión.

Si no sale ningún mensaje significa que todo ha ido bien y que ha creado el byteco-
de, es decir, PracticaE.class

Por último, ejecutamos el programa Java con la JVM “java”. A la JVM hay que darle
el nombre del fichero del bytecode sin la extensión.

113
MÓDULO 2

Ahora realizaremos la misma practica con Eclipse

Arrancar Eclipse, ejecutando c:\eclipse3.5.2\eclipse.exe

Seleccionar la ubicación del “workspace” (o área de trabajo).

Cerrar la ventana de bienvenida si aparece (esta ventana aparece la primera vez


que se arranca Eclipse).

114
Unidad 2.3 Sintaxis

115
MÓDULO 2

Verificar que la perspectiva Java está abierta, y sino cambiar a ella

Crear un proyecto nuevo de nombre PracticaE

Darle el nombre y seleccionar Finish.

116
Unidad 2.3 Sintaxis

Crear una clase Java nueva llamada PracticaE con el método main.

117
MÓDULO 2

Seleccionar Finish
Escribir el código dentro de la clase y salvar con Ctrl + S o File -> Save

118
Unidad 2.3 Sintaxis

Por defecto, en eclipse, al salvar los cambios realizados en un fichero, se realiza la


compilación de las clases que están en el worskpace.

En el caso de producirse algún error de compilación, se pueden ver en la vista Pro-


blems

Seleccionando la clase Java, con el botón derecho del ratón ejecutarla como Java
Application

119
MÓDULO 2

Y veremos como se abre una consola con el resultado.

120
Unidad 2.3 Sintaxis

En esta unidad hemos visto la sintaxis del código Java, aprendiendo a utilizar co-
mentarios, delimitar una sentencia Java con el ; y el uso de los espacios en
blanco.

Se han definido los Identificadores, las Keywords, las Variables y los ámbitos
donde se pueden utilizar:
Atributos
Parámetros de método.
Variables locales
Variables de bloque

Se han visto los distintos Tipos de datos:


 tipos primitivos:
Lógico: boolean
Carácter: char.
Números enteros: byte, short, int y long.
Números reales: double y float.

 tipos complejos o clases: viendo el tipo especial enum

Se han visto además los distintos tipos de Operadores:


Aritméticos
Relacionales
Condicionales
De desplazamiento
Lógicos
De asignación.
Otros

Por último se han determinado los distintos tipos de Sentencias de control de flujo,
que permiten ejecutar el código de una manera no secuencial:
Bucles: while, do-while, for y for/in
Bifurcaciones: if-then-else y switch-case
Gestión de excepciones: try-catch-finally y throw
De ruptura: break, continue, label: y return.
MÓDULO B

Clases, objetos, herencia y


polimorfismo

Tema 2.4

Índice de la unidad:

1. Clases

2. Objetos

3. Relación de herencia

4. Polimorfismo
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

En esta unidad veremos los cuatro paradigmas básicos en los que se apoya los len-
guajes orientados a objetos y por tanto el lenguaje de programación Java.

1. Clases

Una clase representa la abstracción de las operaciones y los datos (o atributos y


métodos) comunes a un conjunto de objetos, en relación a nuestro mundo real.

La implementación de una clase Java debe ir en un fichero físico en formato texto,


con la extensión *.java y nombre idéntico a la clase implementada.

 Ejemplo: La clase MiClase debe ir en un fichero: MiClase.java

La declaración de una clase Java se realiza mediante la keyword: class seguida de


su nombre.

La keyword siempre va precedida por un modificador de acceso: public, protected,


private o default (nada) que ya explicaremos más adelante.

La implementación de la clase irá contenida en un bloque { } justo después de la


declaración. La sintaxis de la declaración de una clase es:

modificador_acceso class nombre_clase


{
}

 Ejemplo: public class MiClase


{
}

1. 1 Atributos y métodos

La implementación de una clase consiste en una serie de:

 Atributos o datos.

 Métodos u operaciones.

125
MÓDULO 2

La sintaxis de la declaración de un atributo es la siguiente:

modificador_acceso tipo nombre; // sin inicialización


modificador_acceso tipo nombre = valor_inicial;

 Ejemplo: private boolean sw = true;

private int i; // sin inicializar. Su valor por defecto es 0

La sintaxis de la declaración de un método es la siguiente:

modificador_acceso tipo_retorno nombre([tipo parametro,..])


{
}

La implementación del método irá contenida en un bloque { } justo después


de la declaración.

 Ejemplo:

public int suma(int param1, int param2)

{
return param1 + param2;
}

Java SE 5.0 añade una novedad a la definición de un método mediante la ca-


racterística: varargs.

Se permite definir un número indefinido de parámetros del mismo tipo me-


diante: ... Lo que recibimos es un array del tipo definido.

 Ejemplo:

public int suma(int… params)


{
int acum = 0;
for(int num: params) { // He usado también el nuevo for/in
acum = acum + num;
}
return acum;
}

Hay que tener en cuenta que podemos recibir, cero, uno o varios valores en
dicho parámetro y que tiene las siguientes restricciones:

126
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

 Solo puede usarse una vez por método.

 Siempre debe ser el último parámetro de todos en la defini-


ción.

 Ejemplo:

public int metodo(String param1, int param2, int… params)


{
}
// en este ejemplo, siempre se recibirá param1 y param2, mientras
que params será una array de un tamaño indeterminado hasta su
ejecución.

1. 2 Constructores

Existe un tipo de método especial en Java llamado constructor.

Se utiliza para la construcción (instanciación) de objetos (o instancias) a partir


de esa clase.

En su implementación se suele dar valores a los atributos para ese objeto para
asegurar que los atributos estén inicializados.

Su declaración es idéntica a la de los métodos convencionales con dos salve-


dades:

 No tienen tipo de retorno.

 Se tiene que llamar igual que la clase.

La sintaxis de la declaración de un constructor es la siguiente:

modificador_acceso nombre([tipo parametro,..])


{
}

 Ejemplo:

public MiClase(int param1, boolean param2)


{

127
MÓDULO 2

Si nuestra clase no tiene constructores, el compilador añade por defecto uno


sin parámetros; pero si hemos declarado alguno, el compilador no añade na-
da.

1. 3 Sobrecarga de métodos

Se dice que un método está sobrecargado cuando existen dos métodos con el
mismo nombre y tipo de retorno pero con parámetros distintos.

De esta manera podemos tener en una clase varios constructores.

 Ejemplo:

public MiClase()
{
}

public MiClase(int param1, boolean param2)


{
}

Java SE 5.0 añade una novedad al respecto. Se permite la sobrecarga de mé-


todos cambiando también el tipo de retorno, pero siempre que:

 El método que se está sobrecargando sea de una clase padre


(de la que heredamos directa o indirectamente).

 El nuevo tipo de retorno sea hijo del tipo de retorno del méto-
do original (es decir, que herede de él directa o indirectamente).

Por tanto, no es válido para tipos primitivos.

1. 4 Convenciones en Java

Aunque no está obligado por la sintaxis, existen una serie de convenciones


respecto a en la nomenclatura de clases, métodos y atributos, que todo pro-
gramador de Java suele seguir para hacer mas legible el código.

128
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

 El nombre de las clases comenzará con mayúsculas

 Ejemplo: MiClase, String, Circulo, Cuenta, CuentaCorriente

 El nombre de los atributos comenzará con minúsculas

 Ejemplo: contador, sw, i, segundoContador

 El nombre de los métodos comenzará con minúsculas (a ex-


cepción de los constructores)

 Ejemplo: ingresar, miMetodo, sumar

 Ejemplo: a continuación se muestra un ejemplo de una clase

completa, con sus métodos y atributos

129
MÓDULO 2

2. Objetos

Los objetos en Java no son mas que variables de tipo complejo, frente a las de tipo
primitivo.

El tipo de un objeto es la clase de la que se ha instanciado o creado.

La declaración de un objeto es idéntica a la declaración de una variable de tipo pri-


mitivo:

tipo identificador;

 Ejemplo: Cuenta miCuenta;

El valor por defecto de un objeto sin inicializar es: null.

La inicialización de un objeto si que es algo distinta a la inicialización de las varia-


bles de tipo primitivo:

 Se utiliza el operador new.

130
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

 Se llama a un constructor de la clase de la que queremos ins-


tanciar.

La sintaxis de la inicialización sería la siguiente:

tipo identificador = new tipo([parametro,…]);

 Ejemplo: Cuenta miCuenta = new Cuenta(1200.75);

2.1 Variables primitivas versus variables complejas

Como vimos en la Unidad 2.3 Sintaxis, una variable de tipo primitivo contiene
el dato directamen-
te:

Mientras que una variable de tipo complejo contiene una referencia (puntero)
a la zona de memoria donde está el objeto:

 Ejemplo:

131
MÓDULO 2

2.2 Manejo de objetos

El trabajo con un objeto consiste en acceder:

 A sus atributos.

 A sus métodos.

En ambos casos utilizaremos el operador . (punto).

La sintaxis para acceder a un atributo de un objeto es la siguiente:

objeto.atributo

 Ejemplo: miCuenta.saldo = 0;

La sintaxis para acceder a un método (lo que en Orientación a Objetos se de-


nominaba mensaje) es la siguiente:

objeto.metodo([parametro,..])

132
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

 Ejemplo: miCuenta.reintegro(13.7);

La posibilidad de acceso a un atributo o a un método de un objeto dependerá


del modificador de acceso que exista en su definición.

 Ejemplo: partiendo de la siguiente definición de la clase cuenta

Podemos tener el siguiente código que utiliza la clase Cuenta:

133
MÓDULO 2

Las llamadas a métodos se pueden encadenar para evitar tener que crear va-
riables intermedias entre distintas ejecuciónes de métodos:

String s1 = new String(“abc");


char c = s1.toUpperCase().charAt(0);

Equivaldría a:

String s1 = new String(“abc");


String s2 = s1.toUpperCase();
char c = s2.charAt(0);

2.3 El método main y la clase “truco”

Existe un método especial en Java llamado main cuya sintaxis es la siguiente:

public static void main(String[] args)

Es el método donde comienza la ejecución de un programa Java. Por lo tanto


es el método ejecutado cuando desde la JDK de Sun ejecutamos java Nom-
breDeClase o desde Eclipse ejecutamos Run as Java Application.

134
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

El parámetro args es un array (ver Unidad 3.1) donde permite pasarle argu-
mentos al programa Java para su ejecución, en caso de necesitarlos.

Si las clases representan entidades que participan en la resolución de un pro-


blema. ¿En qué entidad tiene sentido incluir el método main?. En ninguna. Por
eso crearemos siempre una clase a parte (de ahi el denominarla “truco”), que
solo tenga el método main. Debido a que no está relacionado con ninguna cla-
se en concreto, no se necesita la creación de ningún objeto para llamarla.

2.4 Destructores y Garbage Collector

Los destructores son unos métodos encargados de eliminar los objetos de


memoria, aunque en Java no existe este tipo de métodos (si existen en otros
lenguajes de programación como C++).

En Java lo que existe es un proceso automático que se ejecuta en la JVM a la


vez que nuestra aplicación y que se encarga de buscar todos aquellos objetos
en memoria no utilizados y limpiarlos. Este proceso se llama Garbage Collec-
tor.

¿Cómo sabe el Garbage Collector que un objeto ya no está siendo utilizado


por la aplicación y que por tanto puede ser eliminado? Porque no está referen-
ciado por ninguna variable.

Existen tres motivos por los que una variable deja de referenciar a un objeto:

 Se iguala a null. Deja de referenciar a un objeto.

 Se iguala a otro objeto. Por lo que el objeto al que referencia-


ba puede ser eliminado.

 Se termina su ámbito. Por lo que la variable deja de tener va-


lidez.

 Ejemplo: En cuanto pun es igualado a null, deja de referenciar al ob-


jeto creado vía new. Pero ¡ojo!, el objeto al que referenciaba pun no se pue-
de limpiar porque sigue referenciado por centro desde un atributo del objeto
referenciado por

135
MÓDULO 2

cir.

3. Relación de herencia

Se basa en la existencia de relaciones de generalización/especialización entre cla-


ses.

Las clases se disponen en una jerarquía, donde una clase hereda los atributos y
métodos de las clases superiores en la jerarquía. Es decir, definimos una especie de
interfaz (API) para un grupo de clases relacionados mediante la herencia.

Una clase puede tener sus propios atributos y métodos adicionales a lo heredado.

Una clase puede modificar los atributos y métodos heredados.

Las clases por encima en la jerarquía a una clase dada, se denominan superclases
o clases padre.

Las clases por debajo en la jerarquía a una clase dada, se denominan subclases o
clases hijas.

136
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

Una clase puede ser superclase y subclase al mismo tiempo.

Existen distintos tipos de herencia:

 Simple. Solo puede heredar de una clase.

 Múltiple (no soportada en Java)

 Ejemplo:

La implementación de la herencia se realiza mediante la keyword: extends. La sin-


taxis de la declaración de la herencia es la siguiente:

modificador_acceso class nom_clase extends nom_clase


{
}

 Ejemplo:

public class MiClase extends OtraClase


{
}

 Ejemplo:

137
MÓDULO 2

3.1 La clase Object

En Java todas las clases heredan de otra clase:

 Si lo especificamos en el código con la keyword extends, nues-


tra clase heredará de la clase especificada.

138
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

 Si no lo especificamos en el código, el compilador hace que


nuestra clase herede de la clase Object (raíz de la jerarquía de clases
en Java).

 Ejemplo:

public class MiClase extends Object


{
// Es redundante escribirlo puesto que el
// compilador lo hará por nosotros.
}

Esto significa que nuestras clases siempre van a contar con los atributos y mé-
todos de la clase Object por lo que es importante conocerlos. Algunos de sus
métodos más utilizados son:

 public boolean equals(Object o); //Compara dos objetos y dice


si son iguales.

 public String toString(); //Devuelve la representación literal de


un objeto.

 public Class getClass(); //Devuelve la clase de la cual es ins-


tancia el objeto.

 public int hashCode(); //Devuelve un identificador unívoco


después de aplicarle un algoritmo hash.

 public Object clone(); //Devuelve una copia del objeto.

 public void finalize(); //Un método llamado por el Garbage Co-


llector.

 public void wait(); public void notify(); public void notifyAll();


//Tienen que ver con el manejo de threads.

 Ejemplo:

139
MÓDULO 2

3.2 Casting

El casting es una forma de realizar conversiones de tipos. Hay dos tipos de


casting:

 UpCasting: conversión de un tipo en otro superior en la jerar-


quía de clases. No hace falta especificarlo.

 DownCasting: conversión de un tipo en otro inferior en la je-


rarquía de clases.

Se especifica precediendo al objeto a convertir con el nuevo tipo entre parén-


tesis.

 Ejemplo:

140
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

3.3 Sobrescribir un método

Sobrescribir un método significa que una subclase reimplementa un método


heredado.

Para sobrescribir un método hay que respetar totalmente la declaración del


método:

 El nombre ha de ser el mismo.

 Los parámetros y tipo de retorno han de ser los mismos.

 El modificador de acceso no puede ser más restrictivo.

Al ejecutar un método, se busca su implementación de abajo hacia arriba en la


jerarquía de clases.

 Ejemplo:

141
MÓDULO 2

 Ejemplo: de sobrescribir un método

142
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

143
MÓDULO 2

3.4 Sobrecargar versus Sobrescribir

Sobrecargar un método es un concepto distinto a sobrescribir un método.

La sobrecarga de un método significa tener varias implementaciones del mis-


mo método con parámetros distintos:

 El nombre ha de ser el mismo.

 El tipo de retorno ha de ser el mismo.

 Los parámetros tienen que ser distintos.

 El modificador de acceso puede ser distinto.

Habrá que tener muy en cuenta los parámetros que se envían y las conversio-
nes por defecto para saber qué método se ejecuta.

 Ejemplo: Veremos la sobrecarga de un método que recibe un float y un dou-


ble:

public void miMetodo(float param) { }


miObjeto.miMetodo(1.3); //llamará sin problemas al método anterior

Sobrecargamos el método para que reciba un double.


public void miMetodo(double param) { }
miObjeto.miMetodo(1.3); //ya no llama al método con float.

Recordemos que un número real por defecto es double.


Para seguir llamando al método con float debemos especificarlo im-
plícitamente:
miObjeto.miMetodo(1.3F); o miObjeto.miMetodo((float)1.3);

 Ejemplo:

144
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

3.5 El uso de la herencia

Debemos usar herencia cuando hay una clase deun tipo mas específico que
una superclase. Es decir, se trata de una especialización.

145
MÓDULO 2

 Ejemplo: Lobo es mas específico que Canino. Luego tiene sentido que Lobo
herede de Canino.

Debemos usar herencia cuando tengamos un comportamiento que se puede


reutilizar entre varias otras clases del mismo tipo genérico.

 Ejemplo: Las clases Cuadrado, Circulo y Triangulo tiene que calcular su área
y perímetro luego tiene sentido poner esa funcionalidad en una clase genérica
como Figura.

No debemos usar herencia solo por el hecho de reutilizar código. Nunca de-
bemos romper las dos primeras reglas.

 Ejemplo: Podemos tener el comportamiento cerrar en Puerta. Pero aunque


necesitemos ese mismo comportamiento en Coche no vamos a hacer que Coche
herede de Puerta. En todo caso, coche tendrá un atributo del tipo Puerta.

No debemos usar herencia cuando no se cumpla la regla: Es-un (Is-a).

 Ejemplo: Refresco es una Bebida. La herencia puede tener sentido. Bebida


es un Refresco. ¿? No encaja luego la herencia no tiene sentido.

3.6 super y this

super y this son dos keywords de Java.

super es una referencia al objeto actual pero apuntando al padre. super se


utiliza para acceder desde un objeto a atributos y métodos (incluyendo cons-
tructores) del padre.

Cuando el atributo o método al que accedemos no ha sido sobrescrito en la


subclase, el uso de super es redundante. Los constructores de las subclases
incluyen una llamada a super() si no existe un super o un this.

 Ejemplo: Ejemplo de acceso a un atributo.

146
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

 Ejemplo: Ejemplo de acceso a un constructor

 Ejemplo: Ejemplo de acceso a un método

147
MÓDULO 2

this es una referencia al objeto actual.

this se utiliza para acceder desde un objeto a atributos y métodos (incluyendo


constructores) del propio objeto.

Existen dos ocasiones en las que su uso no es redundante:

 Acceso a un constructor desde otro constructor.

 Acceso a un atributo desde un método donde hay definida una


variable local con el mismo nombre que el atributo.

 Ejemplo: Ejemplo de acceso a un atributo

 Ejemplo: Ejemplo de acceso a un constructor

148
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

4. Polimorfismo

Es otro de los paradigmas de la Orientación a Objetos.

Consiste en que una vez se ha definido una superclase para un grupo de subclases,
cualquier instancia de esas subclases puede ser usada en el lugar de la superclase.

Esto significa que podemos referenciar un objeto de una subclase mediante una re-
ferencia declarada como una de sus superclases. Ver punto 3.2 Casting para las
conversiones de tipos.

 Ejemplo: Object o = new String(“Hola”);

149
MÓDULO 2

Por tanto mediante el polimorfismo podemos asignar a una referencia de un tipo


superior en la jerarquía de herencia, una instancia de un tipo inferior (que herede).

Ahora bien, que la referencia sea de otro tipo no significa que los métodos que se
ejecuten sean distintos. Siguen siendo los de la instancia.

Algunos usos habituales del polimorfismo en Java son:

 Implementación de colecciones genéricas.

 Implementación de métodos genéricos.

 Ejemplo: Ejemplo de colección genérica.

150
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

Nota: Los arrays se verán mas en detalle en la Unidad 3.1

 Ejemplo: Ejemplo de método genérico.

Con el polimorfismo podemos desarrollar código que no tiene que ser modificado
por la introducción en el programa de nuevas subclases o tipos debido a:

 Cambio en las especificaciones.

151
MÓDULO 2

 Rediseño

 Ejemplo: la clase Matematico seguirá funcionando aunque desarrolle-

mos nuevas figuras como Cuadrado, Ameba, etc…. siempre y cuando


hereden de la superclase Figura.

 Ejemplo: Supongamos que necesitamos implementar una clase para

almacenar dos lobos en nuestro proyecto

Ahora nos diden que en el mismo proyecto también necesitamos alma-


cenar dos gatos. Tenemos distintas alternativas:

• Crear una clase nueva MiLista2

• Añadir a MiLista dos atributos nuevos del topo Gato y otro método
add() que reciba un Gato

• Modificar MiLista para que maneje el tipo genérico Animal y así nos
valga tanto para Lobos como pata Gatos e incluso otros animales en
le futuro. Nos decidimos por este último.

152
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

Hablando con un compañero de otro proyecto, nos comenta que en su


proyecto necesita implementar una clas par almacenar dos Triángulos.

Le podríamos pasar nuestra clase si la hubiéramos hecho más genéri-


ca. ¿No heredaba en Java todo de la clase Object?

En Java encontraremos multitud de ejemplos que usen el Polimormis-


mo con este fin.

153
MÓDULO 2

4.1 Clases abstractas

A menudo existen clases que sirven para definir un tipo genérico pero que no
tiene sentido instanciar (crear objetos de ella). Por ejemplo, puede tener sen-
tido instanciar un Circulo pero a lo mejor no instanciar una Figura, porqué…
¿qué figura es? ¿cuál es su área? ¿y su perímetro?

Estas clases pueden estar siendo usadas simplemente para agrupar bajo un
mismo tipo a otras clases, o para contener código reutilizable, o para forzar un
API a sus subclases…..

La clases se definen como abstractas mediante la keyword: abstract. La sin-


taxis de la declaración de una clase abstracta es la siguiente:

modificador_acceso abstract class nom_clase


{
}

 Ejemplo:

public abstract class MiClase


{
}

 Ejemplo:

154
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

4.2 Métodos abstractos

Además de clases abstractas, también podemos tener métodos abstractos.

Una clase abstracta significaba que tenía que ser heredada. No podía ser ins-
tanciada.

Un método abstracto significa que tiene que ser sobrescrito. No está imple-
mentado.

Una clase con uno o varios métodos abstractos tiene que ser declarada abs-
tracta.

No obstante una clase abstracta no tiene porque tener métodos abstractos.

Los métodos se definen como abstractos mediante la keyword: abstract. La


sintaxis de la declaración de una clase abstracta es la siguiente:

modif_acceso abstract tipo_retorno nombre([tipo param,…]);

155
MÓDULO 2

 Ejemplo: public abstract void miMetodo();

El objetivo de un método abstracto es forzar una interfaz (API) pero no una


implementación.

 Ejemplo:

4.3 Ejemplo práctico de Polimorfismo

Partimos del diseño de animales visto anteriormente.

156
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

¿Qué ocurre si queremos reusar el diseño para un aplicativo de Tienda de


Mascotas? Una primera aproximación sería añadir a la clase Animal todos los
métodos específicos de una mascota como son jugar, vacunar.

Automáticamente todas las mascotas tendrán los métodos necesarios. Pero


también los tendrán las no mascotas. Y seguro que hay que retocar cada mas-
cota reescribiendo sus métodos porque tengan alguna peculiaridad.

Modificamos la primera aproximación definiendo los métodos de las mascotas


en la clase Animal como abstractos de manera que cada mascota los imple-
mente.

157
MÓDULO 2

Así todas las mascotas heredan el interfaz e implementan su comportamiento


dependiendo de la mascota en concreto. Pero no solo el resto de animales
heredarán también el interfaz si no que tienen que implementarlo aunque sea
vacío.

158
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

Otra aproximación sería introducir los nuevos métodos solo en las mascotas.
Así ya no nos tenemos que preocupar de que haya clases que sin ser masco-
tas tengan métodos de estas.

Sin embargo esto implica otro tipo de problemas como que los programadores
de mascotas tendrán que ponerse de acuerdo en el interfaz de estas y siempre
llevarlo a raja tabla puesto que ahora no se hereda y el compilador no nos
ayuda con los posibles errores.

Otro inconveniente muy importante es que no tenemos posibilidad de usar el


polimorfismo con las mascotas.

159
MÓDULO 2

La solución que parece óptima, sería tener otra clase abstracta llamada Mas-
cota con los métodos abstractos de las mascotas. Y que todas las mascotas
heredasen de ella.

Así, ya no nos tenemos que preocupar de que haya clases que sin ser masco-
tas tengan métodos de estas.

Todas las mascotas cumplirán forzosamente el API de las mascotas y el com-


pilador nos ayudará a asegurarlo. Y también tendremos la posibilidad de usar
el polimorfismo con las mascotas.

Pero eso significa que habrá clases que heredarán de dos clases a la vez y en
Java no existe la herencia múltiple.

160
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

5. Interfaces

Los interfaces en Java nos solucionan en parte la no existencia de la herencia múlti-


ple; habilitando así las posibilidades del polimorfismo en la herencia múltiple sin los
problemas que esta conlleva.

Los interfaces son un tipo de clase especial que no implementa ninguno de sus mé-
todos. Todos son abstractos. Por tanto no se pueden instanciar.

La declaración de un interface Java se realiza mediante la keyword: interface segui-


do de su nombre. La sintaxis de la declaración de un interface es la siguiente:

modificador_acceso interface nombre_interface


{
}

 Ejemplo:

public interface MiInterface

161
MÓDULO 2

{
}

Siguen siendo clases Java por lo que su código fuente se guarda en un fichero texto
de extensión *.java y al compilarlo se generará un *.class

Los métodos se definen como abstractos mediante la keyword: abstract. La sintaxis


de la declaración de un método abstracto es la siguiente:

modif_acceso abstract tipo_retorno nombre([tipo param,…]);

 Ejemplo: public abstract void miMetodo();

El objetivo de un método abstracto es forzar una interfaz (API) pero no una imple-
mentación.

De los interfaces también se hereda, aunque se suele utilizar más el término im-
plementa por la keyword utilizada. Se realiza mediante la keyword: implements.

La sintaxis de la declaración de la herencia de un interface es la siguiente:

modif_acceso class nom_clase implements nom_interface[,nom_int….]


{
}

 Ejemplo:

public class MiClase implements MiInterface


{
}

Una clase puede heredar o implementar múltiples interfaces consiguiendo así la


herencia múltiple. Y también un interface puede heredar de otros interfaces

Una clase puede heredar de otra clase (como máximo de una) y a la vez heredar de
múltiples interfaces.

Un interface puede también definir constantes.

Si una clase que hereda de un interface, no implementa todos los métodos de este,
deberá ser definida como abstracta.

162
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

 Ejemplo:

Un interface se trata como un tipo cualquiera. Por tanto, cuando hablamos de poli-
morfismo, significa que una instancia de una clase puede ser referenciada por un
tipo interface siempre y cuando esa clase o una de sus superclases implemente

dicho interface.

 Ejemplo: Este sería el diseño final de la tienda de mascotas

163
MÓDULO 2

5.1 Interface versus Clases abstractas

Las interfaces se diferencian de las clases abstractas principalmente en:

 Un interface no puede implementar ningún método.

 Una clase puede implementar n interfaces pero solo una clase.

 Un interface no forma parte de la jerarquía de clases. Clases


dispares pueden implementar el mismo interface.

 El objetivo de un método abstracto es forzar una interfaz (API)


pero no una implementación.

5.2 Clases, Subclases, Clases abstractas e Interfaces

A continuación se verán ciertas directrices de cuando utilizar se pueden utilizar


las Clases, Subclases, Clases abstractas e Interfaces:

164
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

 Haremos una clase que no herede de nadie cuando la clase no


pase la prueba de Es-Un. Veremos por ejemplo, si un Circulo Es-Una
Figura (por lo que heredará de Figura), pero que Figura no es un Cir-
culo, ni un Triangulo .... por lo que no heredará de nadie.

 Haremos una subclase cuando necesitemos hacer una especia-


lización de la superclase mediante sobreescritura o añadiendo nuevos
métodos.

 Haremos una clase abstracta cuando queramos definir un gru-


po genérico de clases y además tengamos algunos métodos imple-
mentados que reutilizar. También cuando no queramos que nadie
instancie dicha clase.

 Haremos un interface cuando queramos definir un grupo gené-


rico de clases y no tengamos métodos implementados que reutilizar.
O cuando nos veamos forzados por la falta de herencia múltiple en
Java.

PRÁCTICA A: Identificar si hay algo mal en el siguiente código:

165
MÓDULO 2

Solución:

Estaba mal. No habíamos creado el objeto r.

PRÁCTICA B: Identificar si hay algo mal en este código:

Solución:

Estaba mal. Se estaba llamando a un método inexistente.

166
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

PRÁCTICA C: Identificar si hay algo mal en este código,suponiendo que la clase


Rectangulo existe.

Solución:

Estaba mal. El objeto miRect no está inicializado, por tanto vale null. Con null no
podemos hablarnos.

167
MÓDULO 2

PRÁCTICA D: Basándonos en el siguiente ejemplo

Contesta a las siguientes preguntas:

1. ¿Cuántos atributos tiene la clase Cirujano?:__.


2. ¿Cuántos atributos tiene la clase MedicoDeCabecera?:__.
3. ¿Cuántos métodos tiene la clase Medico?:__.
4. ¿Cuántos métodos tiene la clase Cirujano?:__.
5. ¿Cuántos métodos tiene la clase MedicoDeCabecera?:__.
6. ¿Puede un MedicoDeCabecera tratar pacientes?:___.
7. ¿Puede un MedicoDeCabecera hacer incisiones?:___.

Solución:

1. ¿Cuántos atributos tiene la clase Cirujano?:_1_.


2. ¿Cuántos atributos tiene la clase MedicoDeCabecera?:_2_.
3. ¿Cuántos métodos tiene la clase Medico?:_1_.
4. ¿Cuántos métodos tiene la clase Cirujano?:_2_.
5. ¿Cuántos métodos tiene la clase MedicoDeCabecera?:_2_.
6. ¿Puede un MedicoDeCabecera tratar pacientes?:_SI__.
7. ¿Puede un MedicoDeCabecera hacer incisiones?:_NO__.

PRÁCTICA E: Desarrollar el siguiente programa tanto en la JDK de Sun como en


Eclipse. Hay que tener en cuenta que hay que desarrollar los siguientes elementos:

168
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

Desarrollar una clase llamada Punto que:

 Tenga dos atributos private de tipo double.


 Tenga un constructor con dos parámetros de tipo double que inicialice los
dos atributos.
 Tenga un constructor por defecto (sin parámetros) que inicialice los dos atri-
butos al valor que se quiera.
 Tenga un getter para cada uno de los atributos.
 Tenga un método calcularDistanciaDesde que recibe un parámetro de tipo
Punto y que devuelve un double.

Desarrollar una clase llamada Circulo que:

 Tenga dos atributos private de tipo Punto y double.


 Tenga un constructor con dos parámetros de tipo Punto y double que iniciali-
ce los dos atributos.
 Tenga un constructor por defecto (sin parámetros) que inicialice los dos atri-
butos al valor que se quiera.
 Tenga un constructor con tres parámetros de tipo double que inicialice los
dos atributos.
 Tenga un getter para cada uno de los atributos.
 Tenga un método calcularDistanciaDesde que recibe un parámetro de tipo
Punto y que devuelve un double.
 Tenga un método calcularArea que no recibe ningún parámetro y devuelve
un double.
 Tenga un método calcularPerimetro que no recibe ningún parámetro y de-
vuelve un double.

Desarrollar una clase llamada Triangulo que:

 Tenga tres atributos private de tipo Punto.


 Tenga un constructor con tres parámetros de tipo Punto que inicialice los dos
atributos.
 Tenga un constructor por defecto (sin parámetros) que inicialice los tres
atributos al valor que se quiera.
 Tenga un constructor con seis parámetros de tipo double que inicialice los
tres atributos.
 Tenga un getter para cada uno de los atributos.
 Tenga un método calcularDistanciaDesde que recibe un parámetro de tipo
Punto y que devuelve un double.
 Tenga un método calcularArea que no recibe ningún parámetro y devuelve
un double.
 Tenga un método calcularPerimetro que no recibe ningún parámetro y de-
vuelve un double.

Desarrollar una clase llamada Practica5a que en su método main:

 Cree e inicialice dos objetos de la clase Punto y muestre la distancia entre


ambos.
 Cree un objeto de la clase Circulo y muestre su área, perímetro y distancia a
uno de los dos puntos creados al comienzo.
 Cree un objeto de la clase Triangulo y muestre su área, perímetro y distan-
cia a un nuevo punto.

Nota 1: No seremos rigurosos con las matemáticas y supondremos que los triángu-
los siempre son rectángulos.

169
MÓDULO 2

Nota 2: Para calcular la raíz cuadrada de un número usaremos Math.sqrt(¿?) siendo


¿? el número.

Solución con la JDK De Sun

En el caso de que no esté puesta la variable de entorno PATH, abrir una sesión DOS
y ajustar la variable de entorno PATH para que el Sistema Operativo sepa encontrar
las herramientas del JDK. Para respetar el valor que ya tuviese la variable PATH le
añadimos %PATH%.

Creamos un directorio de trabajo donde guardar el programa Java.

Ajustar la variable de entorno CLASSPATH para que las herramientas del JDK sepan
encontrar nuestras clases Java. Tenemos dos opciones, o añadir el . (punto) y
siempre ejecutar las herramientas en el directorio donde se encuentre el código, o

170
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

añadir el directorio de trabajo y ejecutar las herramientas donde queramos. Para


respetar el valor que ya tuviese la variable CLASSPATH le añadimos %CLASS-
PATH%

Ahora arrancamos un editor de texto (por ejemplo Notepad) para escribir el código
fuente de cada uno de nuestras clases java; el nombre del fichero debe ser
exactamente igual (incluyendo mayúsculas y minúsculas) al de la clase Java que
vamos a desarrollar.
Empezamos con Punto.java

Y aceptamos la creación de un fichero nuevo.

171
MÓDULO 2

Escribimos el código y salvamos los cambios. Cerramos el Notepad.

Los atributos les aplicamos el modificador de acceso private (los veremos en detalle
en la Unidad 2.5)

Compilamos el programa Java con el compilador “javac”. Al compilador hay que


darle el nombre del fichero incluyendo su extensión.

172
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

Todavía no podemos ejecutar ningún programa Java, porque no tenemos un méto-


do main al que llamar y nos faltan por desarrollar más clases.

Creamos con el notepad las siguientes clases y las compilamos al igual que hemos
hecho con el Punto.java : Circulo.java y Triangulo.java

173
MÓDULO 2

174
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

Por último crearemos nuestra clase “truco” con el método main que guardaremos
en el fichero PracticaE.java

175
MÓDULO 2

Salvamos los cambios y compilamos la clase con javac. Debemos de tener los byte-
code de todas las clases

176
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

Ahora si que podemos ejecutar el programa llamando a la clase PracticaE mediante


el ejecutable java.

La salida por consola queda como sigue:

Ahora realizaremos la misma practica con Eclipse

Arrancar Eclipse, ejecutando c:\eclipse3.5.2\eclipse.exe

Seleccionar la ubicación del “workspace” (o área de trabajo).

177
MÓDULO 2

Aparecerá la pantalla para empezar a trabajar.

Verificar que la perspectiva Java está abierta, y sino cambiar a ella

178
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

Crear un proyecto nuevo de nombre PracticaE

Darle el nombre y seleccionar Finish.

179
MÓDULO 2

Crear una clase Java nueva llamada Punto sin el método main

180
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

Seleccionar Finish

Escribir el código dentro del bloque de la clase y salvar con Ctrl + S o File -> Save

181
MÓDULO 2

Hacer lo mismo para las clases Circulo y Triangulo.

182
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

Continuación de la implementación de la clase Triangulo

Crear una clase Java nueva llamada PracticaE con el método main.

183
MÓDULO 2

184
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

Seleccionando la clase Java PracticaE, con el botón derecho del ratón ejecutarla
como Java Application

Y veremos como se abre una consola con el resultado.

185
MÓDULO 2

186
Unidad 2.4 Clases Objetos Herencia y Polimorfismo

En esta unidad hemos visto los cuatro paradigmas básicos en los que se apoya los
lenguajes orientados a objetos y por tanto el lenguaje de programación Java.

 Clases, donde su implementación consta normalmente de una serie de


atributos y métodos.
- Existen ciertos métodos especiales llamados Cons-
tructores, que permiten crear objetos.
- Se pueden sobrecargar los métodos, teniendo el
mismo nombre de método y distintos parámetros.

 Objetos, que son instancias de una clase determinada. Para poder acce-
der a sus atributos y métodos se utiliza el operador punto.
- El método main se utiliza directamente sin la crea-
ción de un objeto, para empezar la ejecución de un
programa Java.
- La eliminación de los objetos en memoria se utiliza
via el Garbage Collector.
 La relación de herencia, se basa en la existencia de relaciones de ge-
neralización/especialización entre clases.

- Todas las clases por defecto heredan de la clase


Object
- Se puede generalizar o especializar entre las su-
perclases y subclases mediante los casting.
- Se pueden reimplementar métodos heredados me-
diante la sobrescritura de métodos.

 La relación de polimorfismo, consiste en que una vez se ha definido


una superclase para un grupo de subclases, cualquier instancia de esas
subclases puede ser usada en el lugar de la superclase.
- Utilización de clases abstractas, o genéricas que
no pueden ser instanciadas.
- Si se utilizan métodos abstractos, la clase debe
ser identificada como abstracta, y alguna de las
subclases tiene que implementar dichos métodos.

 Los Interfaces, que proporcionan el API que cualquier clase que imple-
mente dicho interface debe de desarrollar.

PA-
MÓDULO B

Otros conceptos

Tema 2.5

Índice de la unidad:

1. Paquetes

2. Modificadores de acceso

3. Métodos estáticos

4. final

5. Paso por valor o por referencia

6. Cosas que ocurren por defecto

7. Instanceof
Unidad 2.5 Otros conceptos

En las unidades anteriores se ha visto la sintaxis de Java, y paradigmas básicos de


la programación orientada a objetos. Existen otros conceptos, a nivel organizativo
de las clases y de acceso de las clases y objetos que son los que veremos en esta
Unidad.

1. Paquetes

Los paquetes Java son una característica más del lenguaje que nos permite
organizar el código en grupos.

Adicionalmente, ayudan a evitar colisiones en los nombres de las clases. De manera


que en un programa que va a usar un framework (conjunto de clases con un propó-
sito en concreto) de un tercero, tenga un 99% de seguridad de que no tiene ningu-
na clase con el mismo nombre, que las del framework.

Para especificar el paquete al que pertenece una clase se utiliza la keyword: pac-
kage. La sintaxis de la declaración de un paquete es la siguiente:

package nombre_del_paquete;

 Ejemplo: es.java.aula.mentor.figuras;

El nombre de una clase no se limita solamente al identificador utilizado en la defini-


ción, sino a la suma del paquete al que pertenece más el del identificador: Nombre
de paquete + Identificador de la Clase

 Ejemplo: La clase Circulo del paquete es.java.aula.mentor.figuras es la clase


es.java.aula.mentor.figuras.Circulo. La clase Circulo del paquete es.figuras es la
clase es.figuras.Circulo

Por tanto, al ir a utilizar una clase debemos conocer siempre el paquete al que per-
tenece para poder referenciarla porque si no el compilador no va a saber encontrar-
la.

Toda clase Java pertenece a un paquete. Si no se especifica nada, pertenece al ‘pa-


quete por defecto’ (que es un paquete raíz sin nombre o nada, pero no está reco-
mendado su uso). En el caso de especificarlo, la sentencia package tiene que ser la
primera línea del fichero con el código fuente de la clase.

191
MÓDULO 2

Existe una convención aceptada por todos los desarrolladores en cuanto a la no-
menclatura de los paquetes Java:

 Todas las palabras que componen el nombre del paquete van


en minúsculas.

 Se suele utilizar el nombre de dominio de la empresa,


organización o institución invertido para intentar asegurar nombres
unívocos y evitar colisiones.

 Ejemplos: com.ibm.test

es.miempresa.utilidades

es.practicas.tema1

Para poder utilizar una clase en nuestro código tenemos que escribir su nombre
completo cada vez que la utilicemos: paquete + clase. Para mejorar la legibilidad
del código, existe otro mecanismo para facilitar la codificación y facilitar la vida al
desarrollador que es el uso de la keyword: import. La sintaxis de la declaración de
la sentencia es la siguiente:

import nombre_del_paquete.nombre_de_la_clase;
import nombre_del_paquete.*;

 Ejemplos: es.java.aula.mentor.figuras.Circulo;

es.java.aula.mentor.figuras.*;

Las sentencias import se ubican entre la sentencia package y la definición de la cla-


se.

Las clases importadas de esta manera pueden ser referenciadas en el código direc-
tamente por su nombre de clase sin necesidad de escribir el paquete al que perte-
necen.

Un import genérico (es decir, con el *) importa solo las clases de ese paquete, pero
no de los subpaquetes.

 Ejemplo: Si se utiliza el import es.java.aula.* importará las clases del pa-


quete es.java.aula pero no las clases de paquetes que estén en nomenclatura

192
Unidad 2.5 Otros conceptos

por debajo de este, como es el caso de la clase


es.java.aula.mentor.figuras.Circulo

Por tanto para utilizar una clase tenemos tres alternativas:

 Utilizar su nombre completo: paquete + clase (unidos


mediante el punto)

 Importar la clase: import paquete + clase (unidos mediante el


punto)

 Importar el paquete completo: import paquete + * (unidos


mediante el punto)

Un import no implica la inclusión de código como ocurre en un #include de C++.


Simplemente son vías de acceso para buscar el código. El código se va cargando
según se necesita.

Al igual que las clases Java tienen un reflejo en el Sistema de Archivos (una clase
Java equivale a un fichero texto de extensión *.java), lo mismo ocurre con los pa-
quetes Java.

Los paquetes Java equivalen a directorios. Es decir, cada miembro del paquete (se-
parado por puntos) se traduce a un directorio en el Sistema de Archivos.

 Ejemplo:

package es.java.aula.mentor.figuras;
public class Circulo {...}

Para compilar una clase que pertenece a un paquete tenemos distintas opciones:

 Desde c:\trabajo ejecutamos: javac


es\java\aula\mentor\figuras\Circulo.java

193
MÓDULO 2

 Desde c:\trabajo\es\java\aula\mentor\figuras ejecutamos:


javac Circulo.java

Para ejecutar una clase solo tenemos una opción posible:

 Desde cualquier punto del sistema ejecutamos: java


es.java.aula.mentor.figuras.Circulo.java. Nota: el directorio
c:\trabajo debe estar en el CLASSPATH (o si estamos en el directorio
c:\trabajo, con que estuviera el . en el CLASSPATH también sería
suficiente)

A continuación mostramos distintos ejemplos de utilización de clases teniendo en


cuenta los paquetes a los que pertenecen:

 Ejemplo: Ambas clases están en el paquete por defecto y por tanto se en-
cuentran.

 Ejemplo: Las clases están en paquetes distintos y no se utilizan las clases


con el nombre completo ni con la sentencia import

194
Unidad 2.5 Otros conceptos

 Ejemplo: Las clases están en paquetes distintos y se utilizan las clases con el
nombre completo

195
MÓDULO 2

 Ejemplo: Las clases están en paquetes distintos y se utilizan las clases con la
sentencia import

 Ejemplo: Las clases están en paquetes distintos y se utilizan las clases con la
sentencia import genérica

196
Unidad 2.5 Otros conceptos

 Ejemplo: Las clases están en el mismo paquete

1. 1 Características de los Paquetes Java

197
MÓDULO 2

Las clases básicas System, String, Math, etc… pertenecen al paquete


java.lang.*. (las veremos con más detalle en la Unidad 2.6).

¿Cómo compilaban todas nuestras prácticas si no conocíamos los paquetes


Java (y por tanto la keyword import)? La respuestas es porque el compilador,
por defecto, siempre añade la siguiente línea a nuestro código:

import java.lang.*;

Aunque no es frecuente, es posible que provoquemos ambigüedades en el uso


de los imports, y por tanto errores de compilación.

¿Qué ocurre al usar una clase cuyo nombre existe a la vez en dos paquetes
que hemos importado? ¿Cuál de las dos clases es la que se debe utilizar?

En esos casos, hay que importar o referirse a la clase conflictiva mediante su


identificador completo: paquete + clase.

 Ejemplo: Necesitamos utilizar dos clases con el mismo nombre que están en
paquetes distintos. Utilizamos solamente la sentencia import genérico

198
Unidad 2.5 Otros conceptos

 Ejemplo: Necesitamos utilizar dos clases con el mismo nombre que están en
paquetes distintos. Utilizamos la sentencia import genérico y en la clase conflic-
tiva utilizamos el nombre completo.

 Ejemplo: Necesitamos utilizar dos clases con el mismo nombre que están en
paquetes distintos. Utilizamos la sentencia import genérico e import específico.

199
MÓDULO 2

 Ejemplo: Necesitamos utilizar dos clases con el mismo nombre que están en
paquetes distintos. Utilizamos la sentencia import específico.

200
Unidad 2.5 Otros conceptos

Hemos visto que existe el llamado ‘paquete por defecto’ al que pertenecen
todas aquellas clases que no indican de forma explícita un paquete
determinado en su código.

Desde la versión 1.4.x, el compilador no permite importar desde una clase que
pertenece a un paquete explícito, una clase que pertenece al ‘paquete por
defecto’.

Esto no tendría que ser un problema en la mayoría de los casos porque


siempre deberíamos ubicar las clase en paquetes Java de forma explícita.

Cuando consultamos el API, por ejemplo, via online en la documentación de


SUN http://java.sun.com/javase/6/docs/api/index.html, podemos apreciar la
categorización de los paquetes y las clases que pertenecen a cada uno de
ellos.

2. Modificadores de acceso

Hasta ahora hemos visto que podemos utilizar cualquier clase, método y atributo
desde cualquier punto de nuestro código sin ningún tipo de problema. Pero el
lenguaje de programación Java, nos permite poder delimitar quién o desde donde
se puede acceder a una clase, a un método o a un atributo.

Existen cuatro tipos de modificadores de acceso y por tanto, cuatro keywords. Las
hemos ordenados de menor a mayor restricción.

201
MÓDULO 2

 public -> Público

 protected -> Protegido.

 -> Paquete, identificado por la ausencia de keyword.

 private -> Privado.

La siguiente tabla muestra a qué se puede acceder desde una clase dada:

Los modificadores de acceso se utilizan en las definiciones de:

 Clases e interfaces: solo se puede utilizar public y package (o


paquete en castellano)

 Atributos: se permiten cualquiera de los cuatro.

 Métodos: se permiten cualquiera de los cuatro.

 Ejemplo: Ejemplo de modificadores de acceso con atributos.

202
Unidad 2.5 Otros conceptos

 Ejemplo: Ejemplo de modificadores de acceso con métodos.

 Ejemplo: Ejemplo del modificador de acceso paquete utilizado con

203
MÓDULO 2

clases

3. Métodos estáticos

Existen casos en los que nos encontramos con clases cuyos métodos no dependen
en absoluto de los atributo de la clase, y en todo caso de los parámetros de los
métodos. Por ejemplo, la clase java.lang.Math:

 Su método round recibe un número decimal y lo devuelve


redondeado.

 Su método sqrt recibe un número y devuelve su raiz cuadrada.

 Su método min recibe dos números y devuelve el menor.

Son métodos que parece no pertenecer a una entidad concreta. Son genéricos,
globales, independientes de cualquier estado del objeto.

¿Tiene sentido instanciar un objeto para ejecutar algo que no depende de nada de
dicho objeto?

204
Unidad 2.5 Otros conceptos

La respuesta es no. Y para ello contamos en Java con los métodos estáticos. Están
asociados a una clase solamente desde un punto de vista organizativo.

Para definir un método estático utilizamos la keyword: static. La sintaxis de la


declaración es la siguiente:

modifi_acceso static tipo_retorno nombre([tipo parametro,..])


{
}

 Ejemplo:

public static void miMetodo()


{
}

Para ejecutar por tanto un método estático no hace falta instanciar un objeto de la
clase. Se puede ejecutar el método directamente sobre la clase.

 Ejemplo: int a = Math.min(10,17);

Mientras que los métodos convencionales requieren de un objeto:


String s = new String(“Hola”);
int a = s.indexOf(‘a’);

No se puede realizar la siguiente llamada


int a = String.indexOf(‘a’);

Una clase puede perfectamente mezclar métodos estáticos con métodos


convencionales. Un ejemplo clásico es el método main:

public static void main(String[] args) { … }

Hay ciertas reglas que hay que tener en cuenta en el uso de métodos estáticos:

 Un método estático jamás puede acceder a un atributo de


instancia (no estático).

 Un método estático jamás puede acceder a un método de


instancia (no estático).

 Pero desde un método convencional si que se puede acceder a


atributos y métodos estáticos.

205
MÓDULO 2

 Ejemplo: Utilización de atributos desde un método estático

 Ejemplo: Utilización de métodos estáticos desde un método estático

206
Unidad 2.5 Otros conceptos

3.1 Atributos estáticos

Los atributos estáticos (o variables estáticas) son atributos cuyo valor es com-
partido por todos los objetos de una clase.

Para definir un atributo estático utilizamos la keyword: static. La sintaxis de


la declaración es la siguiente:

modifi_acceso static tipo nombre [= valor_inicial];

 Ejemplo: public static int contador = 0;

Hay que tratarlos con cuidado puesto que son fuente de problemas difíciles de
detectar. Como todos los objetos de una misma clase comparte el mismo atri-
buto estático, si un objeto ‘a’ modifica el valor del atributo, cuando el objeto
‘b’ vaya a usar dicho atributo, lo usa con un valor modificado.

Recordemos que sin embargo los atributos convencionales (de instancia) son
propios de cada objeto.

Los atributos estáticos son cargados en memoria cuando se carga la clase.


Siempre antes de que:

 Se pueda instanciar un objeto de dicha clase.

 Se pueda ejecutar un método estático de dicha clase.

Para usar un atributo estático no hace falta instanciar un objeto de la clase.

 Ejemplo: System.out.println(“Hola”); // out es un atributo estático


de la clase java.lang.System.

 Ejemplo:

207
MÓDULO 2

3.2 Bloques de código estáticos

Los bloques de código estático son trozos de código que se ejecutan al cargar
una clase en memoria (no al instanciar objetos de esa clase).

Para definir un bloque de código estático utilizamos la keyword: static. La


sintaxis de la declaración es la siguiente:

static { …. }

 Ejemplo: static { System.out.println(“Hola”); }

 Ejemplo:

208
Unidad 2.5 Otros conceptos

4. final

final es una keyword que modifica el funcionamiento de:

 Clases

 Atributos

 Métodos

4.1 Clases finales

Definiendo una clase como final conseguimos que ninguna otra clase pueda
heredar de ella.

Para definir una clase final utilizamos la keyword: final. La sintaxis de la de-
claración es la siguiente:

209
MÓDULO 2

modificador_acceso final class nombre_clase


{
}

 Ejemplo:

public final class MiClase


{
}

 Ejemplo: Herencia de una clase final

4.2 Métodos finales

Definiendo un método como final conseguimos que ninguna otra clase pueda
sobrescribirlo.

Para definir un método como final utilizamos la keyword: final. La sintaxis de


la declaración es la siguiente:

modif_acceso final tipo_retorno nombre([tipo param,..])


{
}

 Ejemplo:

public final int suma(int param1, int param2)


{
return param1 + param2;
}

 Ejemplo:

210
Unidad 2.5 Otros conceptos

4.2 Atributos finales

Definiendo un atributo como final conseguimos constantes. Es decir, una vez


inicializados no se puede cambiar su valor.

Para definir un atributo como final utilizamos la keyword: final. La sintaxis de


la declaración es la siguiente:

modificador_acceso final tipo nombre [= valor_inicial];

 Ejemplo:

protected final boolean sw = true;


public final int i;

 Ejemplo:

211
MÓDULO 2

4.3 Definición de constantes

Las constantes en Java se suelen definir mediante la combinación de las key-


word: static y final. La sintaxis de la declaración es la siguiente:

modificador_acceso static final tipo nombre = valor;

 Ejemplo: public static final double PI = 3.141592653589;

Por convención, a la hora de programar, las constantes se suelen llamar con


todas las letras en mayúsculas.

 Ejemplo: Constantes ya existentes en las clases básicas:

java.lang.Math.PI: el número PI.

java.lang.Math.E: el número E.

javax.swing.SwingConstants.CENTER: centrado.

java.awt.event.KeyEvent.VK_ENTER: tecla de intro.

212
Unidad 2.5 Otros conceptos

En ocasiones cuando se crea una clase solo con constantes, se suele hacer
mediante un interface, debido a que no es necesario tener ningún método de-
finido ni implementado.

4.4 Static imports

Java SE 5.0 añadío una novedad al respecto, permitiendo la importación de


atributos y métodos estáticos, de manera que no haya que nombrar a la clase
para su acceso.

La sintaxis de la declaración es la siguiente:

import static nombredelpaquete.nombredelaclase.miembro;


import static nombredelpaquete.nombredelaclase.*;

 Ejemplo: import static java.lang.System.out;

 Ejemplo:

213
MÓDULO 2

4. Paso por valor o por referencia

En programación existen dos formas de pasar parámetros:

 Por valor (o copia): se realiza una copia del parámetro.

 Por referencia: se pasa una referencia al parámetro.

En C se decidía mediante la gestión de punteros con los operadores: * y &

En Java sin embargo no hay decisión posible: todo se pasa por valor. Si se modifica
el valor de la variable recibida, no se modifica la variable original..

 Ejemplo:

 Ejemplo:

214
Unidad 2.5 Otros conceptos

 Ejemplo: Realmente no se cambian las referencias sino los atributos internos


de esas referencias.

215
MÓDULO 2

5. Cosas que ocurren por defecto

El compilador realiza cosas por defecto de forma automática (sin que estén des-
arrolladas de forma explícita en nuestro código). Las enumeramos a continuación:

 Las clases que no importan explícitamente el paquete ja-


va.lang.* lo hacen de forma implícita:

import java.lang.*;

 Las clases que no heredan explícitamente de otra clase, here-


dan implícitamente de java.lang.Object:

public class MiClase extends Object

216
Unidad 2.5 Otros conceptos

 Las clases que no definan ningún constructor contienen implí-


citamente uno sin parámetros:

public MiClase()
{
super();
}

 Los constructores que no llamen a otro constructor de la mis-


ma clase o del padre, contienen una llamada implícita al del padre
sin parámetros:

public MiClase(int param)


{
super();
this.valor = param;
}

 Siempre que se haga referencia un atributo o método de la


propia clase, implícitamente se añade this:

this.miMetodo();

 Todos los métodos de un interfaz son definidos como abstract


de forma implícita:

public abstract int miMetodo();

 Todos los atributos son inicializados a su valor por defecto si


no se inicializan de forma explícita. Cuidado, que no ocurre lo mismo
con las variables locales.

 Si no se especifica ningún package, la clase pertenece al pac-


kage por defecto.

 Si no se especifica ningún modificador de acceso al definir una


clase, atributo o método, se le aplica el modificador package.

217
MÓDULO 2

6. Instanceof

Se trata de un operador especial del lenguaje Java representado por la keyword:


instanceof. La sintaxis de la declaración es la siguiente:

objeto instanceof clase

 Ejemplo: num instanceof Integer ó num instanceof java.util.Date

Este operador permite comprobar si un objeto es instancia de una clase o no. De-
vuelve un boolean por lo que puede utilizarse en expresiones lógicas (condiciones).

Básicamente lo que hace es comprobar si un casting concreto se puede realizar o


no.

 Ejemplo:

218
Unidad 2.5 Otros conceptos

PRÁCTICA A: ¿Cuál de estos programas compila sin errores?

Solución:

PRÁCTICA B: ¿Cuál de estos programas compila sin errores?

219
MÓDULO 2

Solución:

PRÁCTICA C: ¿Cuál de estos programas compila sin errores?

Solución:

220
Unidad 2.5 Otros conceptos

PRÁCTICA D: Desarrollar, tanto en la JDK de Sun como en Eclipse, el comienzo de


un juego de rol donde tengamos distintas criaturas: Elfos, Trolls y Enanos. Inventad
una serie de atributos (entre ellos la fuerza), constructores y métodos para todos
ellos. Deberán estar en el paquete es.java.aula.mentor.practicad.criaturas.

Al mismo tiempo, tendremos un interfaz con los puntos de fuerza de cada una de
las criaturas definidas como constantes en el paquete
es.java.aula.mentor.practicad.util. De esta manera un simple cambio en el interfaz
actualiza todo el juego.

La clase PracticaD que se encuentra en el paquete es.java.aula.mentor.practicad


tiene un método main en el que se crean una serie de criaturas y se muestran por
pantalla.

Aunque en esta primera fase del desarrollo del juego no utilicemos las criaturas,
realizar un diseño lo mas genérico, reutilizable y fácil de mantener que se pueda.

Solución con la JDK De Sun

En el caso de que no esté puesta la variable de entorno PATH, abrir una sesión DOS
y ajustar la variable de entorno PATH para que el Sistema Operativo sepa encontrar
las herramientas del JDK. Para respetar el valor que ya tuviese la variable PATH le
añadimos %PATH%.

221
MÓDULO 2

Creamos un directorio de trabajo donde guardar el programa Java.

Ajustar la variable de entorno CLASSPATH para que las herramientas del JDK sepan
encontrar nuestras clases Java. Tenemos dos opciones, o añadir el . (punto) y
siempre ejecutar las herramientas en el directorio donde se encuentre el código, o
añadir el directorio de trabajo y ejecutar las herramientas donde queramos. Para
respetar el valor que ya tuviese la variable CLASSPATH le añadimos %CLASS-
PATH%

222
Unidad 2.5 Otros conceptos

Creamos los directorios donde van a estar nuestras clases


es\java\aula\mentor\\practicad\criaturas y es\java\aula\mentor\practicad\util

Desde el directorio es\java\aula\mentor\practicad\criaturas, con un editor de texto


(por ejemplo Notepad) vamos a escribir el código fuente de cada una de nuestras
clases java; el nombre del fichero debe ser exactamente igual (incluyendo
mayúsculas y minúsculas) al de la clase Java que vamos a desarrollar.
Empezamos con Criatura.java

223
MÓDULO 2

Y aceptamos la creación de un fichero nuevo.

Escribimos el código y salvamos los cambios. Cerramos el Notepad.

Hacemos el mismo proceso para la clase Troll.java

224
Unidad 2.5 Otros conceptos

Para la clase Enano.java

Y para la clase Elfo.java

225
MÓDULO 2

Desde el directorio es\java\aula\mentor\practicad\util, escribimos el interface Cons-


tantes.java

Desde el directorio es\java\aula\mentor\practicad, escribimos la clase Practi-


caD.java que va a contener el método main.

226
Unidad 2.5 Otros conceptos

Compilamos el programa Java con el compilador “javac”. Al compilador hay que


darle el nombre del fichero incluyendo su extensión.

Podemos hacerlo desde cada uno de los directorios donde están las clases, indican-
do solamente el nombre de la clase sin paquete (por ejemplo javac Troll.java) o
desde el directorio trabajo, indicando el nombre completo de la clase (por ejemplo
javac es\java\aula\mentor\practicad\criaturas\Troll.java).

Para poder compilar las clases, es necesario que las clases que utilizan sean compi-
ladas previamente.

A continuación mostramos un posible orden de compilación:

Vemos como han quedado las clases compiladas en cada uno de los directorios

227
MÓDULO 2

Ejecutamos la clase PracticaD y vemos lo que sale por la consola

Ahora realizaremos la misma práctica con Eclipse

Arrancar Eclipse, ejecutando c:\eclipse3.5.2\eclipse.exe

Seleccionar la ubicación del “workspace” (o área de trabajo).

228
Unidad 2.5 Otros conceptos

Aparecerá la pantalla para empezar a trabajar.

Verificar que la perspectiva Java está abierta, y sino cambiar a ella

229
MÓDULO 2

Crear un proyecto nuevo de nombre PracticaD

Darle el nombre y seleccionar Finish.

230
Unidad 2.5 Otros conceptos

Crear un interface Java nuevo llamado Criatura, especificando el paquete


es.java.aula.mentor.practicad.criaturas.

231
MÓDULO 2

Seleccionar Finish
Escribir el código dentro del bloque del interface y salvar con Ctrl + S o File -> Sa-
ve

232
Unidad 2.5 Otros conceptos

Crear las siguientes clases Troll , Enano, Elfo (sin método main) dentro del mismo
paquete. Para no tener que volver a escribir el nombre del paquete, podemos se-
leccionarlo vía el botón derecho del ratón y luego seleccionar el crear una nueva
clase.

233
MÓDULO 2

234
Unidad 2.5 Otros conceptos

En Eclipse, cuando se salvan los cambios, se compila el código, por lo que no hace
falta realizar este paso.

Crear el interface Constantes en el paquete es.java.aula.mentor.practicad.util.

235
MÓDULO 2

Por último, creamos la clase que va a contener el main PracticaD, en el paquete ja-
va es.java.aula.mentor.practicad

236
Unidad 2.5 Otros conceptos

Seleccionando la clase Java PracticaD, con el botón derecho del ratón ejecutarla
como Java Application

Vemos la salida por la consola

237
MÓDULO 2

238
Unidad 2.5 Otros conceptos

En esta unidad hemos visto distintos conceptos que nos permiten organizar nues-
tro código y modificar el acceso a nuestras clases, métodos y atributos.

 Paquetes: son una característica del lenguaje que nos permite organizar
el código en grupos. Físicamente, cada uno de los subgrupos del paquete
se convierten en un directorio del sistema operativo.

 Modificadores de acceso: son una característica del lenguaje que nos


posibilita delimitar quién o desde donde se puede acceder a una clase, a
un método o a un atributo. Existen cuatro delimitadores:
- public: puede acceder todo el mundo.
- protected: Solamente se pueden acceder desde el mismo
paquete o subclases de otros paquetes.
- : Solamente se pueden acceder desde el mismo paquete.
- private: Solamente se puede acceder desde la misma clase.

Adicionalmente hemos visto otros keyword que modifican el comportamiento de


clases, atributos y métodos
 Métodos estáticos: son métodos que son dependientes de la clase a la
que pertenecen y no a una instancia de una clase.

 Atributos estáticos: son atributos de clase y son compartidos por todas


las instancias de la clase a la que pertenecen.

 Bloques estáticos: son bloques de código que se ejecutan una sola vez
cuando la clase es cargada en memoria.

 Clases finales: son clases de la que nadie más puede heredar.


MÓDULO 2 PROGRAMACIÓN JAVA

 Métodos finales: son métodos que no pueden ser sobreescritos.


 Atributos finales: son atributos que una vez definidos no se puede cambiar su
valor. Si se utilizan conjuntamente con la keyword static, se convierten en cons-
tantes a nivel de clase.
MÓDULO C

UNIDADES DIDÁCTICAS:

1. Clases básicas. String, StringBuffer, System,

Math, Integer, ….

2. Estructuras de datos. Arrays y colecciones


MÓDULO C

Clases básicas

Tema 3.1

Índice de la unidad:

1. Clase java.lang.String

2. Clase java.lang.StringBuffer

3. Clase java.lang.StringBuilder

4. Clase java.lang.System

5. Clase java.lang.Math

6. Otras clases

7. Wrapper de tipos primitivos


Unidad 3.1 Clases básicas

En el paquete java.lang, importado por defecto por el compilador en las clases Ja-
va, existen ciertas clases muy utilizadas a la hora de desarrollar un programa. Es
por este motivo, que es importante que se conozcan.

1. Clase java.lang.String

A diferencia de C++, en Java se usa la clase String para el manejo de cadenas de


caracteres. Existen distintas formas de crear un String:

 Mediante su constructor por defecto.

 Ejemplo: String s = new String(); // Se inicializa a “” (y no a “ “).

 Mediante su constructor con una cadena de caracteres.

 Ejemplo: String s = new String(“Hola”);

 Mediante la asignación de una cadena de caracteres.

Ejemplo: String s = “Hola”; // Es la única excepción al uso del new.

 Otros constructores:
http://java.sun.com/javase/6/docs/api/java/lang/String.html#constr
uctor_detail

Es importante tener en cuenta que para la clase String, la primera posición de la


cadena de caracteres es la cero (y no la uno).

Implementa una serie de métodos muy útiles para el manejo de las cadenas de ca-
racteres. Por ejemplo:

 public char charAt(int index); Devuelve el carácter que se


encuentra en la posición index.

 public String concat(String str); Devuelve la cadena con


str añadido al final del objeto String que realiza la llamada (es igual
que con el operador +).

 public int indexOf(int ch); Devuelve la primera ocurrencia


de ch (devuelve -1 si no está).

245
MÓDULO 3

 public int compareTo(String str); Compara la cadena con


str. Devuelve 0 si son iguales, < 1 si es menor o > 1 si es mayor (la
comparación se realiza siguiendo el abecedario).

 public String replace(char oldChar, char newChar);


Cambia todas las ocurrencias de oldChar por newChar y devuelve el
String cambiado.

 public int lastIndexOf(String str); Devuelve la última ocu-


rrencia de str (devuelve -1 si no se encuentra).

 public int length(); Devuelve la longitud de la cadena de ca-


racteres.

 public String substring(int beginIndex); Devuelve la ca-


dena desde la posición beginIndex hasta el final.

 public String substring(int beginIndex, int endIndex);


Devuelve la cadena desde la posición beginIndex hasta endIndex –
1.

 public String toLowerCase(); Devuelve la cadena en minús-


culas.

 public String toUpperCase(); Devuelve la cadena en ma-


yúsculas.

 public String trim(); Devuelve la cadena sin espacios en


blanco ni por delante ni por detrás.

 public static String valueOf(double d); Devuelve la cadena


de caracteres que representa d. Este método está sobrecargado va-
rias veces recibiendo como parámetro otros tipos primitivos (char,
int, float, long…).

 Otros métodos:
http://java.sun.com/javase/6/docs/api/java/lang/String.html#metho
d_detail

 Ejemplo:

246
Unidad 3.1 Clases básicas

La clase String, sobreescribe el método equals() de la clase java.lang.Object (re-


cordemos que método el equals de Object comparaba las posiciones de memoria, y
no el contenido de los objetos). De esta forma, podemos saber si dos objetos String
distintos, representan la misma cadena de caracteres o no.

 Ejemplo:

Hay un concepto muy importante relacionado con el uso de Strings: son inmuta-
bles. Es decir, jamás se modifica el valor de un String si no que se crean nuevos
objetos. En la ejecución del siguiente código

String s = "0";
for(int i=1; i <10; i++)
s = s + i;

247
MÓDULO 3

No existe un solo objeto de tipo String al que se le ha ido cambiando su valor inter-
no (atributos), sino que se han creado 10 objetos distintos.

Pero aún hay más… la JVM reserva un espacio en memoria llamado String Pool
donde va guardando todos los String. Y el Garbage Collector jamás los elimina.

Cada vez que se crea un objeto nuevo del tipo String, la JVM mira antes si ese
String ya existe, y si es así lo reutiliza.

Por este motivo, el uso de String es un tema no tan trivial como pudiera parecer.
Un uso indebido puede provocar problemas de rendimiento.

2. Clase java.lang.StringBuffer

StringBuffer es otra clase relacionada con las cadenas de caracteres. Pero en este
caso no son inmutables.

Existen distintas formas de crear un StringBuffer:

 Mediante su constructor por defecto.

 Ejemplo: StringBuffer s = new StringBuffer(); // Se inicializa a “”


(y no a “ “).

 Mediante su constructor con una cadena de caracteres.

 Ejemplo: StringBuffer s = new StringBuffer(“Hola”);

 Mediante su constructor con un parámetro de tipo int.

Ejemplo: StringBuffer s = new StringBuffer(3); // Tiene una capaci-


dad inicial para 3 caracteres

 Otros constructores:
http://java.sun.com/javase/6/docs/api/java/lang/StringBuffer.html#
constructor_detail

248
Unidad 3.1 Clases básicas

Para la clase StringBuffer, la primera posición de la cadena de caracteres es la cero


(y no la uno).

Algunos de sus métodos más importantes son:

 public StringBuffer append(char c); Añade el carácter c al


valor del StringBuffer. Este método está sobrecargado varias veces
recibiendo como parámetro otros tipos: String, Object, int, float,
long… Modifica el propio objeto que realiza la llamada.

 public char charAt(int index); Devuelve el carácter que se


encuentra en la posición index.

 public int indexOf(int ch); Devuelve la primera ocurrencia


de ch (devuelve -1 si no está).

 public int length(); Devuelve la longitud de la cadena de ca-


racteres.

 public int capacity(); Devuelve el número de caracteres que


puede contener sin necesidad de alocar o pedir más memoria.

 public String toString(); Devuelve un String representado


por el StringBuffer.

 public String substring(int beginIndex); Devuelve un


String desde la posición beginIndex hasta el final.

 public StringBuffer reverse(); Devuelve la cadena invertida


en orden. Modifica el propio objeto.

 public void setCharAt(int index, char ch); Reemplaza el


carácter de la posición index por ch.

 public StringBuffer replace(int start, int end, String str);


Reemplaza la cadena entre las posiciones start y end con str. Modifi-
ca el propio objeto que hace la llamada.

249
MÓDULO 3

 public StringBuffer insert(int offset, char c); Inserta c en


la posición offset de la cadena. Este método está sobrecargado varias
veces recibiendo como parámetro a insertar otros tipos: int, float,
long… Modifica el propio objeto que hace la llamada.

 public StringBuffer delete(int start, int end); Elimina los


caracteres entre las posiciones start y end.

 Otros métodos:
http://java.sun.com/javase/6/docs/api/java/lang/StringBuffer.html#
method_detail

 Ejemplo:

 Ejemplo:

250
Unidad 3.1 Clases básicas

El uso más habitual es la creación de Strings cuyo valor se calcula de forma dinámi-
ca. Al no ser inmutable, permite la creación del String final sin otros objetos inter-
medios que consumirán memoria de forma innecesaria. En la ejecución del siguien-
te código

StringBuffer tmp = new StringBuffer(10);


for(int i=0; i <10; i++)
tmp.append(i);
String s = tmp.toString();

Solo se han creado 2 objetos en memoria: un StringBuffer (el GC puede limpiarlo) y


un String.

3. Clase java.lang.StringBuilder

Java SE 5.0 añade la clase StringBuilder al tratamiento de cadenas de caracteres.

Su funcionalidad (constructores y métodos) es idéntica a la de StringBuffer. La úni-


ca diferencia es que sus métodos no están sincronizados (veremos qué significa es-
to en la Unidad 3.7 Threads).

251
MÓDULO 3

En ejecuciones paralelas tiene mejor rendimiento que StringBuffer. Se puede en-


contrar una información más detallada en
http://java.sun.com/javase/6/docs/api/java/lang/StringBuilder.html

 Ejemplo:

4. Clase java.lang.System

Se trata de una clase con utilidades genéricas del sistema. Todos sus atributos y
métodos son estáticos.

Tiene tres atributos muy utilizados:

 public static final PrintStream out; Representa por defecto


al stream de salida en pantalla.

 public static final InputStream in; Representa por defecto


al stream de entrada del teclado.

 public static final PrintStream err; Representa por defecto


al stream de salida de errores.

252
Unidad 3.1 Clases básicas

Para más información


http://java.sun.com/javase/6/docs/api/java/lang/System.html#field_detail

Y entre sus métodos más utilizados se encuentran:

 public static long currentTimeMillis(); Devuelve la diferen-


cia de entre la hora actual y la medianoche del 1 de enero de 1970
en milisegundos.

 public static long nanoTime(); Devuelve la hora actual en


nanosegundos. Es novedad del JSE 5.0

 public static void exit(int status); Termina la ejecución de


la JVM devolviendo status como código de retorno (cero significa que
todo ha ido bien).

 public static void gc(); Pide a la JVM que ejecute el Garbage


Collector. Se trata de un método muy peligroso. Utilizado sin cuidado
puede afectar muy negativamente al rendimiento.

 public static String getProperty(String key); Devuelve el


valor de la propiedad del sistema key, o null si no existiese.

 public static Properties getProperties(); Devuelve una


instancia de java.util.Properties encapsulando todas las propiedades
del sistema.

 public static void loadLibrary(String libname); Carga la


librería nativa libname. Se utiliza con la programación JNI (Java Na-
tive Interface).

 Otros métodos:
http://java.sun.com/javase/6/docs/api/java/lang/System.html#meth
od_detail

 Ejemplo:

253
MÓDULO 3

5. Clase java.lang.Math

Se trata de una clase con utilidades matemáticas. Todos sus atributos y métodos
son estáticos.

Tiene dos atributos (constantes) muy utilizados:

 public static final double E; Es el número e, utilizado en los


logaritmos neperianos.

 public static final double PI; Es el número π, utilizado en


trigonometría.

Para obtener más información:


http://java.sun.com/javase/6/docs/api/java/lang/Math.html#field_detail

Alguno de sus métodos más importantes son:

 public static double abs(double a); Devuelve el valor abso-


luto de a. Este método se encuentra sobrecargado recibiendo otros
tipos: int, long…

 public static double log10(double a); Devuelve el logarit-


mo base 10 de a.

254
Unidad 3.1 Clases básicas

 public static int max(int a, int b); Devuelve el número ma-


yor comparando a y b. Este método se encuentra sobrecargado reci-
biendo otros tipos: long, float…

 public static int min(int a, int b); Devuelve el número me-


nor comparando a y b. Este método se encuentra sobrecargado reci-
biendo otros tipos: long, float…

 public static double pow(double a, double b); Calcula po-


tencias de base a y exponente b.

 public static double random(); Devuelve un número aleato-


rio entre 0.0 y 1.0 (0.0 está incluido pero no así el 1.0).

 public static long round(double a); Redondea a al número


entero más cercano. Este método se encuentra sobrecargado con
otros tipos: float.

 public static double sqrt(double a); Calcula la raíz cuadra-


da de a.

 Otros métodos:
http://java.sun.com/javase/6/docs/api/java/lang/Math.html#method
_detail

 Ejemplo:

255
MÓDULO 3

6. Otras clases

A continuación se enumeran otras clases importantes a tener en cuenta pertene-


cientes a otros paquetes

 Para manejar fechas: java.util.Date y java.util.Calendar

 Para formatear fechas y números: java.text.DateFormat y


java.text.NumberFormat

 Para dividir una cadena de caracteres en tokens (o trozos de


cadena separados por un identificador): java.util.StringTokenizer

 Para trabajar con expresiones regulares: ja-


va.util.regex.Pattern y java.util.regex.Matcher

 Más información: http://java.sun.com/javase/6/docs/api/

256
Unidad 3.1 Clases básicas

7. Wrapper de tipos primitivos

Hay ocasiones en las que necesitaríamos usar un tipo primitivo como un objeto (ti-
po complejo). Por ejemplo, cuando queremos guardar números en una colección
que solo admite java.lang.Object.

En el paquete java.lang.* existe un wrapper para cada tipo primitivo (no siempre
coincide el nombre):

 Boolean: para el tipo primitivo boolean

 Character: para el tipo primitivo char

 Byte, Short, Integer, Long: para los tipos primitivos byte,


short, int y long respectivamente.

 Float, Double: para los tipos primitivos float y double respec-


tivamente

Como norma a seguir, suelen tener los siguientes métodos:

 Constructores que reciben un String o el tipo primitivo que re-


presentan:

 Ejemplo: Integer a = new Integer(3);

 Convertidores de tipo String a su tipo complejo (wrapper) me-


diante el método valueOf

 Ejemplo: Integer b = Integer.valueOf(“3”);

 Convertidores de tipo String al tipo primitivo que representan


mediante el método parseXXX

 Ejemplo: int c = Integer.parseInt(“3”);

 Convertidores de tipo primitivo a String mediante el método


toString

 Ejemplo: String d = Integer.toString(c);

257
MÓDULO 3

 Extractores del tipo primitivo que representan mediante el mé-


todo XXXValue

 Ejemplo: int e = b.intValue();

Todos los wrappers sobreescriben el método equals de la clase java.lang.Object. De


esta forma, podemos saber si dos objetos distintos de un mismo tipo de wrapper,
representan el mismo valor primitivo o no.

 Ejemplo:

7.1 Clase java.lang.Boolean

Es el wrapper del tipo primitivo boolean. Sus métodos más importantes son:

 public Boolean(boolean value); Constructor de un Boolean


con el boolean value.

 public Boolean(String s); Constructor de un Boolean con el


String s. Si s no vale “true” entonces siempre cogerá el valor false.

 public static Boolean valueOf(String s); Convierte el


String s en un Boolean. Si s no vale “true” entonces siempre devuel-
ve un Boolean con false.

 public static boolean parseBoolean(String s); Convierte el


String s en un boolean. Si s no vale “true” entonces siempre devuel-
ve false.

 public static String toString(boolean b); Convierte el


boolean b en un String.

258
Unidad 3.1 Clases básicas

 public String toString(); Devuelve su representación String


(sobrescribe el método toString() de java.lang.Object).

 public boolean booleanValue(); Extrae el boolean que re-


presenta.

 Más información y métodos:


http://java.sun.com/javase/6/docs/api/java/lang/Boolean.html

7.2 Clase java.lang.Character

Es el wrapper del tipo primitivo char. Sus métodos más importantes son:

 public Character(char value); Constructor de un Character


con el char value.

 public static String toString(char c); Convierte el char c en


un String.

 public String toString(); Devuelve su representación String


(sobrescribe el método toString() de java.lang.Object).

 public char charValue(); Extrae el char que representa.

 Más información y métodos:


http://java.sun.com/javase/6/docs/api/java/lang/Character.html

7.3 Clase java.lang.Byte

Es el wrapper del tipo primitivo byte. Sus métodos más importantes son:

 public Byte(byte value); Constructor de un Byte con el byte


value.

 public Byte(String s); Constructor de un Byte con el String


s.

259
MÓDULO 3

 public static Byte valueOf(String s); Convierte el String s


en un Byte.

 public static byte parseByte(String s); Convierte el String


s en un byte.

 public static String toString(byte b); Convierte el byte b


en un String.

 public String toString(); Devuelve su representación String


(sobrescribe el método toString() de java.lang.Object).

 public byte byteValue(); Extrae el byte que representa.

 Más información y métodos:


http://java.sun.com/javase/6/docs/api/java/lang/Byte.html

7.4 Clase java.lang.Short

Es el wrapper del tipo primitivo short. Sus métodos más importantes son:

 public Short(short value); Constructor de un Short con el


short value.

 public Short(String s); Constructor de un Short con el String


s.

 public static Short valueOf(String s); Convierte el String s


en un Short.

 public static short parseShort(String s); Convierte el


String s en un short.

 public static String toString(short s); Convierte el short s


en un String.

 public String toString(); Devuelve su representación String


(sobrescribe el método toString() de java.lang.Object).

 public short shortValue(); Extrae el short que representa.

260
Unidad 3.1 Clases básicas

 Más información y métodos:


http://java.sun.com/javase/6/docs/api/java/lang/Short.html

7.5 Clase java.lang.Integer

Es el wrapper del tipo primitivo int. Sus métodos más importantes son:

 public Integer(int value); Constructor de un Integer con el


int value.

 public Integer(String s); Constructor de un Integer con el


String s.

 public static Integer valueOf(String s); Convierte el String


s en un Integer.

 public static int parseInt(String s); Convierte el String s


en un int.

 public static String toString(int i); Convierte el int i en un


String.

 public String toString(); Devuelve su representación String


(sobrescribe el método toString() de java.lang.Object).

 public int intValue(); Extrae el int que representa.

 Más información y métodos:


http://java.sun.com/javase/6/docs/api/java/lang/Integer.html

7.6 Clase java.lang.Long

Es el wrapper del tipo primitivo long. Sus métodos más importantes son:

261
MÓDULO 3

 public Long(long value); Constructor de un Long con el long


value.

 public Long(String s); Constructor de un Long con el String


s.

 public static Long valueOf(String s); Convierte el String s


en un Long.

 public static Long valueOf(String s); Convierte el String s


en un Long.

 public static String toString(long l); Convierte el long l en


un String.

 public String toString(); Devuelve su representación String


(sobrescribe el método toString() de java.lang.Object).

 public long longValue(); Extrae el long que representa.

 Más información y métodos:


http://java.sun.com/javase/6/docs/api/java/lang/Long.html

7.7 Clase java.lang.Float

Es el wrapper del tipo primitivo float. Sus métodos más importantes son:

 public Float(float value); Constructor de un Float con el


float value.

 public Float(String s); Constructor de un Float con el String


s.

 public static Float valueOf(String s); Convierte el String s


en un Float.

 public static float parseFloat(String s); Convierte el String


s en un float.

262
Unidad 3.1 Clases básicas

 public static String toString(float f); Convierte el float f en


un String.

 public String toString(); Devuelve su representación String


(sobrescribe el método toString() de java.lang.Object).

 public float floatValue(); Extrae el float que representa.

 Más información y métodos:


http://java.sun.com/javase/6/docs/api/java/lang/Float.html

7.8 Clase java.lang.Double

Es el wrapper del tipo primitivo double. Sus métodos más importantes son:

 public Double(double value); Constructor de un Double con


el double value.

 public Double(String s); Constructor de un Double con el


String s.

 public static Double valueOf(String s); Convierte el String


s en un Double.

 public static double parseDouble(String s); Convierte el


String s en un double.

 public static String toString(double d); Convierte el dou-


ble d en un String.

 public String toString(); Devuelve su representación String


(sobrescribe el método toString() de java.lang.Object).

 public double doubleValue(); Extrae el double que


representa.

263
MÓDULO 3

 Más información y métodos:


http://java.sun.com/javase/6/docs/api/java/lang/Double.html

7.8 Ejemplo con los wrappers

A continuación mostramos un ejemplo de los wrappers de los tipos básicos.

7.9 Autoboxing/Auto-unboxing

Java SE 5.0 añade una novedad al respecto de los wrappers de tipo básico,
permitiendo que las conversiones entre tipos primitivos y sus wrappers se
hagan de forma automática.

Antes, para crear un wrapper a partir de un tipo primitivo se utilizaba su cons-


tructor:

264
Unidad 3.1 Clases básicas

Integer i = new Integer(1);

Sin embargo ahora se puede hacer directamente:

Integer i = 1;

El compilador se encarga de realizar la conversión de forma automática (auto-


boxing).

De igual forma, antes para extraer un tipo primitivo de su wrapper utilizába-


mos el siguiente método:

Integer a = new Integer(1); int b = a.intValue();

Sin embargo ahora se puede hacer directamente:

int b = a;

El compilador se encarga de realizar la extracción de forma automática (auto-


unboxing).

Esto nos permite también operar con los wrappers:

Integer a = 10; Integer b = 3; int c = a + b;

También se permiten las comparaciones:

Integer a = 5; int b = 6;
if(a == b)
System.out.println(“Iguales”);

El wrapper Boolean también se ve favorecido por esta nueva funcionalidad.


Antes no podía participar en condiciones, pero ahora si:

Boolean a = true; boolean b = false;


Boolean c = a && b;

Ante esta nueva funcionalidad, nos podemos preguntar ¿qué pasa con la so-
brecarga de métodos?

public void metodo(double param) { };


public void metodo(Integer param) { };

265
MÓDULO 3

int a = 5;
this.metodo(a);

Para evitar diferencias en la funcionalidad de una aplicación al migrar de ver-


siones anteriores, primero se busca el método a ejecutar sin tener en cuenta
el autoboxing y auto-unboxing. Si no se encuentra ninguno, entonces de bus-
ca teniendo en cuenta el autoboxing y auto-unboxing. Se llamaría por tanto a:
public void metodo(double param) { };

PRÁCTICA A: Desarrollar, tanto en la JDK de Sun como en Eclipse, una clase a la


que se le pase un parámetro de tipo String (sin blancos de separación) y muestre:

 la cadena de caracteres en mayúsculas.

 la cadena de caracteres en minúsculas.

 los dos primeros caracteres de la cadena (solo en caso de que la longitud de


esta sea de dos o más caracteres).

 los dos últimos caracteres de la cadena (solo en caso de que la longitud de


esta sea de dos o más caracteres).

 el número de ocurrencias en la cadena del último carácter.

 la cadena con todas las ocurrencias del primer carácter en mayúsculas.

 la cadena con tres asteriscos por delante y por detrás.

 La cadena invertida.

Solución con la JDK De Sun

En el caso de que no esté puesta la variable de entorno PATH, abrir una sesión DOS
y ajustar la variable de entorno PATH para que el Sistema Operativo sepa encontrar
las herramientas del JDK. Para respetar el valor que ya tuviese la variable PATH le
añadimos %PATH%.

266
Unidad 3.1 Clases básicas

Creamos un directorio de trabajo donde guardar el programa Java.

Ajustar la variable de entorno CLASSPATH para que las herramientas del JDK sepan
encontrar nuestras clases Java. Tenemos dos opciones, o añadir el . (punto) y
siempre ejecutar las herramientas en el directorio donde se encuentre el código, o
añadir el directorio de trabajo y ejecutar las herramientas donde queramos. Para
respetar el valor que ya tuviese la variable CLASSPATH le añadimos %CLASS-
PATH%

267
MÓDULO 3

Creamos el directorio donde va a estar nuestra clase


es\java\aula\mentor\\practicas26

Desde el directorio es\java\aula\mentor\practica26, con un editor de texto (por


ejemplo Notepad) vamos a escribir el código fuente de nuestra clases java; el
nombre del fichero PracticaA.java debe ser exactamente igual (incluyendo
mayúsculas y minúsculas) al de la clase Java que vamos a desarrollar.

268
Unidad 3.1 Clases básicas

Y aceptamos la creación de un fichero nuevo.

Para poder coger un parámetro pasado en la ejecución del programa, incluir las
siguientes líneas después del main. Veremos el tratamiento de los arrays en la
Unidad 3.1
if (args == null || args.length != 1){
System.out.println("Numero de parametros incorrectos");
System.exit(1);
}

String s = args[0];

Nuestra clase quedaría de la manera siguiente:

269
MÓDULO 3

Compilamos nuestra clase

Ejecutamos la clase, pasándole un parámetro en la ejecución:

270
Unidad 3.1 Clases básicas

Ahora realizaremos la misma práctica con Eclipse

Arrancar Eclipse, ejecutando c:\eclipse3.5.2\eclipse.exe

Seleccionar la ubicación del “workspace” (o área de trabajo).

Aparecerá la pantalla para empezar a trabajar.

271
MÓDULO 3

Verificar que la perspectiva Java está abierta, y sino cambiar a ella

Crear un proyecto nuevo de nombre Practicas26

272
Unidad 3.1 Clases básicas

Darle el nombre y seleccionar Finish.

Crear una clase Java nueva llamado PracticaA, especificando el paquete


es.java.aula.mentor.practicas26

273
MÓDULO 3

El código dentro del método main, quedaría como sigue:

274
Unidad 3.1 Clases básicas

Salvar los cambios con Ctrl + S o File -> Save

Para ejecutar la clase, pasándole un parámetro, seleccionamos la clase Java Practi-


caA, con el botón derecho del ratón ejecutarla como Run Configurations

275
MÓDULO 3

Indicar el parámetro en la pestaña Arguments

276
Unidad 3.1 Clases básicas

Y seleccionar el botón Run.

PRÁCTICA B: Desarrollar, tanto en la JDK de Sun como en Eclipse, una clase a la


que se le pasen dos parámetros de tipo String y que serán convertidos a dos núme-
ros decimales (double); estos números decimales serán los dos catetos de un trián-
gulo rectángulo.

Deberá tener un método que muestre:

 El mayor y menor de los catetos.

 El valor de la hipotenusa.

Adicionalmente, habrá que mostrar el tiempo que tarda en ejecutarse este método.

277
MÓDULO 3

Solución con la JDK De Sun

En el directorio es\java\aula\mentor\practicas26, creamos una clase nueva llamada


PracticaB.java con un editor de texto como notepad.

Para el paso de parámetros en ejecución, incluiremos las siguientes líneas en el


método máin.

if (args == null || args.length != 2){


System.out.println("Numero de parametros incorrectos");
System.exit(1);
}

String s1 = args[0]; // tenemos en primer parámetro de tipo String


String s2 = args[1]; // tenemos en segundo parámetro de tipo String

Nuestra clase quedaría como sigue:

compilamos la clase y ejecutamos pasándole los parámetros

278
Unidad 3.1 Clases básicas

Ahora realizaremos la misma práctica con Eclipse

Nos creamos una nueva clase en el paquete es.java.aula.mentor.practicas26, lla-


mada PracticaB

Desarrollamos el código de la clase

279
MÓDULO 3

Y ejecutamos mediante Run Configurations, verificando que en el Main class apare-


ce la clase PracticaB (en el caso de no aparecer cambiar el nombre o buscarla me-
diante el botón Search)

pasándole como argumentos 12.2 y 2.4

280
Unidad 3.1 Clases básicas

Seleccionamos el botón Run, obteniendo la siguiente salida:

281
TÍTULO DE MÓDULO O BLOQUE

En esta unidad se han visto una relación de clases básicas e imprescindibles de co-
nocer a la hora de la programación en Java.
 java.lang.String: utilizada para el tratamiento de cadenas de caracteres
o String. Se utiliza sobre todo para cadenas de caracteres inmutables

 Para el tratamiento de cadenas de caracteres que cambian de valor se


utilizan las clases
- java.lang.StringBuffer (sincronizada)
- java.lang.StringBuilder (no sincronizada)

 java.lang.System: se trata de una clase con utilidades genéricas del


sistema.

 java.lang.Math: e trata de una clase con utilidades matemáticas.

Además se han estudidado las clases wrappers de los tipos primitivos, como son:
 java.lang.Boolean
 java.lang.Character
 java.lang.Byte
 java.lang.Short
 java.lang.Integer
 java.lang.Long
 java.lang.Float
 java.lang.Double
MÓDULO C

Estructuras de datos. Arrays y


colecciones

Tema 3.2

Índice de la unidad:

1. Arrays

2. Colecciones

3. Importancia de los métodos equals() y hashCode()

4. Arrays vs. Colecciones


Unidad 3.2 Estructura de datos

En Unidades anteriores hemos estudiado los tipos de datos, tanto primitivos como
complejos. Hemos visto como trabajar con datos de ambos dos tipos, pero siempre
de una manera unitaria. En esta Unidad veremos como trabajar con los conjuntos
de datos, como una sola variable u objeto.

1. Arrays

Un array es una estructura de datos que permite albergar varios elementos del
mismo tipo.

La longitud de un array se establece durante su creación y una vez establecida la


longitud de un array, ya no se puede modificar, por lo que se puede considerar que
tiene una longitud fija.

Un elemento de un array, es el valor de una de sus posiciones, y se identifica me-


diante un índice.

Un array en Java, es un tipo de clase especial que hereda implícitamente de ja-


va.lang.Object.

La declaración de un array se realiza mediante el tipo de datos que va a albergar y


los corchetes [ ]. La sintaxis de la declaración de un array es la siguiente:

modificador_acceso tipo[] nombre [= valor_inicial];

 Ejemplos: private int[] numeros;

private String[] cadenas;

Los arrays pueden albergar tanto tipos primitivos como tipos complejos y para po-
der utilizarlos, hay que inicializarlos. Un array sin inicializar, por defecto vale null.

La creación de un array se realiza mediante la keyword: new, como con cualquier


otra clase, tanto para tipos primitivos como para tipos complejos. La sintaxis de la
creación de un array es:

modificador_acceso tipo[] nombre = new tipo[longitud];

285
MODULO 3

 Ejemplos: private int[] numeros = new int[5];

private String[] cadenas = new String[4];

Una vez hayamos creado un array, todas sus posiciones son inicializadas al valor
por defecto del tipo de variable que albergue.

Es decir, 0 o 0.0 si se trataba de un número, false si se trataba de un boolean y null


si se trataba de un tipo complejo.

Existe una forma de crear un array inicializando todas sus posiciones a un valor de-
terminado, igualándolo a un listado de elementos separados por comas entre { }.
El tamaño del array será el número de elementos del listado.

 Ejemplos: private int[] numeros = {1,2,3,4,5};

private String[] cadenas = {“hola”,”adios”};

private Integer[] ints = {new Integer(12), new Integer(98)};

Para el acceso al elemento de un array se utiliza en nombre del array seguido de


unos [ ] con la posición a la que queremos acceder, siendo siempre el índice de un
array de tipo int. Hay que tener en cuenta que la primera posición de un array es la
0.

 Ejemplos: numeros[2] = 3;

int a = numeros[0];

if(numeros[4] == 5)…..

Vemos como queda en memoria los arrays de tipos primitivos:

286
Unidad 3.2 Estructura de datos

Con un array de tipos complejos quedaría de la siguiente manera:

Para conocer la longitud de un array, podremos acceder a su atributo público:


length.

Al no ser dinámico, no podemos:

 Ni eliminar posiciones.

 Ni insertar posiciones.

El borrado será algo lógico, como igualar a null, a -1, etc….. las posiciones que no
se quieran o se necesiten utilizar, dependiendo de la lógica que necesite el progra-
ma o de la propia elección del programador.

287
MODULO 3

Es imposible acceder a una posición fuera del array en tiempo de ejecución. Llega-
do el caso se lanzará una excepción del tipo ArrayIndexOutOfBoundException
(se verán en más detalle en la Unidad 3.5).

 Ejemplo: Si seguimos la ejecución del siguiente


programa

public class Colecciones


{
public static void main(String[] args)
{
// Creación e inicialización.
String[] saludos = new String[4];

// Inserción.
saludos[0] = new String("Hola");
saludos[1] = new String("Adios");
saludos[2] = new String("Hello");
saludos[3] = new String("GoodBye");

// Extracción.
String tmp = saludos[2];

// Borrado.
saludos[2] = null;
saludos[3] = null;
// Recorrido.
for(int i=0; i<saludos.length; i++)
System.out.println(saludos[i]);

// Búsqueda.
boolean sw = false;
for(int i=0; i<saludos.length; i++)
{
if(saludos[i] != null && saludos[i].equals("Adios"))
{
System.out.println("Adios ha sido encontrado en la posición: "
+ i);
sw = true;
break;
}
}
}
}

288
Unidad 3.2 Estructura de datos

1. 1 Sentencia for/in

Esta nueva sentencia del Java SE 5.0 nos facilita la iteración por los elementos
de cualquier tipo de colección: arrays, listas, etc…

for(inicialización: colección) Nota: Se usa “:” en vez de “;”.


{
sentencias;
}

Las variables definidas en la sentencia de inicialización son locales al bloque.


Por tanto dejan de existir una vez se haya terminado el bucle.

 Ejemplo: se muestra un ejemplo de la sentencia de control for/in

public void listar(int[] param)


{
for(int i: param)
System.out.println(i);
}

Básicamente, se trata de una simplificación a la hora de codificar. Es decir, al


final, el compilador convierte el código en una sentencia for convencional co-
mo la siguiente:

public void listar(int[] param)


{
int i = 0;
for(int j=0; j<param.length; j++)
i = param[j];
System.out.println(i);
}

1. 2 Arrays multidimensionales

Un array multidimensional es un array de arrays o desde un punto de vista


matemático es una matriz. Es decir, una matriz de 4 x 2 en realidad en Java
está formada por 5 arrays: 1 array con 4 arrays.

Y si estuviéramos hablando de tres dimensiones entonces tendríamos un array


de arrays de arrays, aunque son bastante menos utilizados.

289
MODULO 3

La sintaxis de la creación de un array bidimensional es la siguiente:

modificador_acceso tipo[][] nombre = new tipo[long][long];

 Ejemplo: private int[][] numeros = new int[4][2];

Pero podemos tener arrays bidimensionales no cuadradas. Es decir, que la se-


gunda dimensión tenga longitud diferente para cada posición de la primera
dimensión.

La sintaxis de la creación de un array bidimensional no cuadrado es la siguien-


te:

modificador_acceso tipo[][] nombre = new tipo[long][];

 Ejemplo:

private int[][] numeros = new int[4][];


numeros[0] = new int[2];
numeros[1] = new int[10];
numeros[3] = new int[1];

Al igual que ocurriera en los arrays de una dimensión, los arrays bidimensio-
nales también se pueden inicializar en la creación con un listado de valores.

 Ejemplos: private int[][] numeros = { {1,2,3} , {1,2,3} };

private String[][] dias = { {“Lunes”,”Martes”} , {“Miércoles”} };

Vemos como queda en memoria los arrays bidimensionales:

290
Unidad 3.2 Estructura de datos

 Ejemplo: private int[][] numeros = { {1,2,3} , {1,2,3} };

 Ejemplo: Si seguimos la ejecución del siguiente programa, obten-


dremos la salida mostrada

public class Matriz


{
public static void main(String[] args)
{
int[][] matriz = new int[4][];

// Rellenar la matriz
for(int i=0; i<matriz.length; i++)
{
matriz[i] = new int[5];
for(int j=0; j<matriz[i].length; j++)
matriz[i][j] = i + j;
}

// Mostrar la matriz
for(int i=0; i<matriz.length; i++)
{
for(int j=0; j<matriz[i].length; j++)
System.out.print(matriz[i][j] + " ");
System.out.println();
}
}
}

291
MODULO 3

1. 3 El método main usa Arrays

El método main recibe un array de Strings que contine los argumentos envia-
dos en el arranque de la aplicación. La sintaxis del método main es la siguien-
te, y como podemos apreciar args es un array de elementos de tipo String:

public static void main(String[] args)

 Ejemplo:

public class Test


{
public static void main(String[] args)
{
for(int i=0; i<args.length; i++)
System.out.println("Argumento " + i + “: " + args[i]);
}
}

292
Unidad 3.2 Estructura de datos

2. Colecciones

Una colección es simplemente un objeto que agrupa varios elementos en uno solo.

Se utilizan para guardar y manipular datos así como transmitir información entre
métodos.

En Java tenemos un framework de colecciones, implementado mediante:

 Interfaces: representaciones abstractas de las colecciones


que permiten usarlas sin conocer sus detalles.

 Implementaciones: colecciones concretas.

 Algoritmos: métodos que permiten realizar operaciones co-


mo búsquedas, ordenaciones, etc…

A continuación se muestra la organización jerárquica de este framework y una for-


ma rápida de saber cual podría ser la elegida a utilizar en cada caso. En el caso de
los Collection, hay una clara diferenciación en cuanto si permite duplicados acce-
diendo por índice java.util.List, o sin duplicados sin posibilidad de acceso vía índice,
java.util.Set

293
MODULO 3

En el caso de los Map, se utilizan siempre que necesitemos trabajar con parejas de
datos clave/valor.

Todas las colecciones se encuentran en el paquete java.util.*; siendo ja-


va.util.Collection y java.util.Map las raices de la jerarquía de las colecciones.

Existirán especializaciones que permitan elementos duplicados o no, que permitan


ordenar los elementos o no, etc.

Estas interfaces contiene la definición de todos los métodos genéricos que deben
implementar las colecciones.

2.1 java.util.Collection

Los métodos básicos de este interfaz son:

 int size(); // Indica el número de elementos que contiene.

 boolean isEmpty(); // Indica sí no contiene ningún ele-


mento.

294
Unidad 3.2 Estructura de datos

 boolean contains(Object element); // Indica sí contiene


ese elemento.

 boolean add(Object element); // Añade un elemento.


Devuelve un boolean para indicar si ha tenido éxito o ha tenido pro-
blemas.

 remove(Object element); // Borra un elemento.

 Iterator iterator(); // Devuelve una instancia de Iterator.

Los métodos que corresponden a operaciones masivas son:

 boolean containsAll(Collection c); // Indica sí contiene


todos esos elementos.

 boolean addAll(Collection c); // Añade todos los elemen-


tos del parámetro pasado. Devuelve un boolean para indicar si ha
tenido éxito o ha tenido problemas.

 boolean removeAll(Collection c); // Borra todos los ele-


mentos del parámetro pasado. Devuelve un boolean para indicar si
ha tenido éxito o ha tenido problemas.

 boolean retainAll(Collection c); // Borrar todos los ele-


mentos menos los pasados en el parámetro. Devuelve un boolean
para indicar si ha tenido éxito o ha tenido problemas.

 void clear(); // Borra todos los elementos.

Los métodos que corresponden a operaciones con arrays son:

 Object[] toArray(); // Devuelve un array con todos los


elementos.

 Object[] toArray(Object a[]); // Devuelve un array con


todos los elementos. El tipo será el del array enviado.

295
MODULO 3

Hay que tener siempre en cuenta que las colecciones no permiten el uso de ti-
pos primitivos. Por tanto, siempre que necesitemos trabajar con ellos habrá
que hacer uso de los Wrappers de Tipos Primitivos.

2.2 java.util.Iterator

El interfaz Iterator representa un componente que permite iterar o recorrer


los elementos de una colección.

Todas las colecciones ofrecen una implementación de Iterator por medio del
método:

public Iterator iterator();

Sus métodos son:

 boolean hasNext(); // Indica sí tiene más elementos des-


de la posición en la que se encuentra el iterador.

 Object next(); // Devuelve el primer elemento y se queda


apuntando al siguiente. En la siguiente llamada, devolverá el segun-
do elemento y apuntará al siguiente y así sucesivamente hasta el fi-
nal de la colección que devolverá un null.

 void remove(); // Elimina el primer elemento y se queda


apuntando al siguiente. En el caso de que no estemos en la primera
posición, borrará el elemendo donde esté el iterador y apuntará al si-
guiente.

En el SDK 1.1.x existía otro interfaz, java.util.Enumeration, pero ya ha de-


jado de utilizarse.

2.2 java.util.Set

El interfaz Set hereda del interfaz Collection. Pero no añade la definición de


ningún método nuevo.

Representa colecciones que no permiten tener elementos duplicados. Para sa-


ber si un elemento está duplicado, hace uso del método:

296
Unidad 3.2 Estructura de datos

public boolean equals(Object o);

Existen distintas implementaciones de este interfaz:

 java.util.HashSet: Es nueva en el SDK 1.2.x. Ofrece el ac-


ceso más rápido cuando dicho acceso es aleatorio (no secuencial). Su
orden de iteración es impredecible.

 java.util.LinkedHashSet: Es nueva en el SDK 1.4.x. Su


orden de iteración es el orden de inserción.

 java.util.TreeSet: Es nueva en el SDK 1.2.x. Su orden de


iteración depende de la implementación que los elementos hagan del
interfaz java.lang.Comparable, mediante la implementación del
método public int compareTo(Object o);

 Ejemplo: Utilización de java.util.HashSet

import java.util.*;

public class TestHashSet


{
public static void main(String[] args)
{
HashSet ciudades = new HashSet();

ciudades.add("Madrid");
ciudades.add("Barcelona");
ciudades.add("Malaga");
ciudades.add("Vigo");
ciudades.add("Sevilla");
ciudades.add("Madrid"); // Repetido.

Iterator it = ciudades.iterator();

while(it.hasNext())
System.out.println("Ciudad: " + it.next());
}
}

297
MODULO 3

 Ejemplo: Utilización de java.util.LinkedHashSet

import java.util.*;

public class TestLinkedHashSet


{
public static void main(String[] args)
{
LinkedHashSet ciudades = new LinkedHashSet();

ciudades.add("Madrid");
ciudades.add("Barcelona");
ciudades.add("Malaga");
ciudades.add("Vigo");
ciudades.add("Sevilla");
ciudades.add("Madrid"); // Repetido.

Iterator it = ciudades.iterator();

while(it.hasNext())
System.out.println("Ciudad: " + it.next());
}
}

298
Unidad 3.2 Estructura de datos

 Ejemplo: Utilización de java.util.TreeSet

import java.util.*;

public class TestTreeSet


{
public static void main(String[] args)
{
TreeSet ciudades = new TreeSet();

ciudades.add("Madrid");
ciudades.add("Barcelona");
ciudades.add("Malaga");
ciudades.add("Vigo");
ciudades.add("Sevilla");
ciudades.add("Madrid"); // Repetido.

Iterator it = ciudades.iterator();

while(it.hasNext())
System.out.println("Ciudad: " + it.next());
}
}

2.3 java.util.List

El interfaz List hereda del interfaz Collection. Representa colecciones con ele-
mentos en secuencia. Es decir, con orden.

Permite tener duplicados.

Es accesible mediante índice, de manera que se puede:

 Acceder a un elemento concreto de una posición.

299
MODULO 3

 Insertar un elemento en una posición concreta.

Los métodos que añade este interfaz, para acceso posicional son:

 Object get(int index); // Devuelve el elemento de la posi-


ción indicada en el parámetro.

 Object set(int index, Object element); // Reemplaza el


elemento de la posición indicada en el parámetro, con el elemento
del parámetro.

 void add(int index, Object element); // Inserta el ele-


mento pasado por parámetro, en la posición pasada por parámetro.

 Object remove(int index); // Elimina el elemento de la


posición indicada por parámetro. Devuelve el objeto borrado.

 boolean addAll(int index, Collection c); // Inserta todos


los elementos pasados por parámetro, en la posición pasada por pa-
rámetro.

Los métodos que añade este interfaz para operaciones de búsqueda son:

 int indexOf(Object o); // Devuelve la posición de la pri-


mera ocurrencia del elemento pasado por parámetro.

 int lastIndexOf(Object o); // Devuelve la posición de la


última ocurrencia del elemento pasado por parámetro.

Los métodos que añade este interfaz para obtener subcolecciones son:

 List subList(int from, int to); // Devuelve una lista con


los elementos comprendidos entre las posiciones pasadas por pará-
metro.

A continuación se enumeran las distintas implementaciones de este interfaz:

 java.util.ArrayList: Es nueva en el SDK 1.2.x. Ofrece un


tiempo de acceso óptimo cuando dicho acceso es aleatorio.

300
Unidad 3.2 Estructura de datos

 java.util.LinkedList: Es nueva en el SDK 1.2.x. Ofrece un


tiempo de acceso óptimo cuando dicho acceso es para añadir o eli-
minar elementos del comienzo y final de la lista (típico para pilas).

 java.util.Vector: Es como el ArrayList, pero sincronizado,


lo que penaliza notablemente el rendimiento. La sincronización es
importante cuando más de un thread (hilo de ejecución) va a acceder
a la colección (los threads se verán en más detalle en la Unidad 3.7.

 Ejemplo: Utilización de java.util.ArrayList y java.util.Iterator

import java.util.*;

public class TestArrayList


{
public static void main(String[] args)
{
ArrayList ciudades = new ArrayList();

ciudades.add("Madrid");
ciudades.add("Barcelona");
ciudades.add("Malaga");
ciudades.add("Vigo");
ciudades.add(1,"Sevilla");
ciudades.add("Madrid"); // Repetido.

Iterator it = ciudades.iterator();

while(it.hasNext())
System.out.println("Ciudad: " + it.next());
}
}

 Ejemplo: Utilización de java.util.ArrayList

import java.util.*;

public class TestArrayList2


{

301
MODULO 3

public static void main(String[] args)


{
ArrayList ciudades = new ArrayList();

ciudades.add("Madrid");
ciudades.add("Barcelona");
ciudades.add("Malaga");
ciudades.add("Vigo");
ciudades.add(1,"Sevilla");
ciudades.add("Madrid"); // Repetido.

for(int i=ciudades.size()-1; i >=0; i--)


System.out.println("Ciudad: " + i + " es: " +
ciudades.get(i));
}
}

 Ejemplo: Utilización de java.util.LinkedList

import java.util.*;

public class TestLinkedList


{
public static void main(String[] args)
{
LinkedList ciudades = new LinkedList();

ciudades.add("Madrid");
ciudades.add("Barcelona");
ciudades.add("Malaga");
ciudades.add("Vigo");
ciudades.add(1,"Sevilla");
ciudades.add("Madrid"); // Repetido.

Iterator it = ciudades.iterator();

while(it.hasNext())
System.out.println("Ciudad: " + it.next());
}
}

302
Unidad 3.2 Estructura de datos

 Ejemplo: Utilización de java.util.Vector

import java.util.*;

public class TestVector


{
public static void main(String[] args)
{
Vector ciudades = new Vector();

ciudades.add("Madrid");
ciudades.add("Barcelona");
ciudades.add("Malaga");
ciudades.add("Vigo");
ciudades.add(1,"Sevilla");
ciudades.add("Madrid"); // Repetido.

for(int i=ciudades.size()-1; i >=0; i--)


System.out.println("Ciudad: " + i + " es: " +
ciudades.get(i));
}
}

303
MODULO 3

2.4 java.util.Map

El interfaz Map no hereda del interfaz Collection. Representa colecciones con


parejas de elementos: clave y valor.

No permite tener claves duplicadas. Pero si valores duplicados.

Para calcular la colocación de un elemento se basa en el uso del método:

public int hashCode();

Los métodos básicos de este interfaz son:

 Object put(Object key, Object value); // Inserta una


pareja de clave/valor pasados como parámetros.

 Object get(Object key); // Accede al valor de una clave


pasada como parámetro.

 Object remove(Object key); // Elimina una pareja de


clave/valor pasados como parámetros, devolviendo el objeto borra-
do.

 boolean containsKey(Object key); // Comprueba la


existencia de una clave pasada como parámetro.

 boolean containsValue(Object value); // Comprueba la


existencia de un valor pasado como parámetro.

 int size(); // Indica el número de pareja que contiene.

 boolean isEmpty(); // Indica sí no contiene ninguna pare-


ja.

Los métodos que realizan operaciones masivas son:

 void putAll(Map t); // Añade todas las parejas que existen


en el parámetro t.

 void clear(); // Elimina todas las parejas de clave/valor.

304
Unidad 3.2 Estructura de datos

Los métodos que realizan operaciones de obtención de colecciones son:

 public Set keySet(); // Devuelve las claves en un ja-


va.util.Set.

 public Collection values(); // Devuelve los valores en un


java.util. Collection.

A continuación enumeramos las distintas implementaciones de este interfaz:

 java.util.HashMap: Es nueva en el SDK 1.2.x. Ofrece un


tiempo de acceso óptimo cuando dicho acceso es aleatorio. Su orden
de iteración es imprevisible.

 java.util.Hashtable: Es la versión sincronizada de Hash-


Map.

 java.util.LinkedHashMap: Es nueva en el SDK 1.4.x. Su


orden de iteración es el de inserción.

 java.util.TreeMap: Su orden de iteración depende de la


implementación que los elementos hagan del interfaz ja-
va.lang.Comparable, mediante la implementación del método pu-
blic int compareTo(Object o);

 Ejemplo: Utilización de java.util.HashMap

import java.util.*;

public class TestHashMap


{
public static void main(String[] args)
{
HashMap codigos = new HashMap();
codigos.put("01","Urgente");
codigos.put("02","Importante");
codigos.put("03","Normal");
codigos.put("04","Baja prioridad");

System.out.println("Aleatorio 03: " + codigos.get("03"));


System.out.println("Aleatorio 01: " + codigos.get("01"));

Set s = codigos.keySet();
Iterator it = s.iterator();
while(it.hasNext())
{
String aux = (String)it.next();

305
MODULO 3

System.out.println(aux + ": " + codigos.get(aux));


}
}
}

 Ejemplo: Utilización de java.util.HashTable

import java.util.*;

public class TestHashtable


{
public static void main(String[] args)
{
Hashtable codigos = new Hashtable();
codigos.put("01","Urgente");
codigos.put("02","Importante");
codigos.put("03","Normal");
codigos.put("04","Baja prioridad");

System.out.println("Aleatorio 03: " + codigos.get("03"));


System.out.println("Aleatorio 01: " + codigos.get("01"));

Set s = codigos.keySet();
Iterator it = s.iterator();
while(it.hasNext())
{
String aux = (String)it.next();
System.out.println(aux + ": " + codigos.get(aux));
}
}
}

306
Unidad 3.2 Estructura de datos

 Ejemplo: Utilización de java.util.LinkedHashMap

import java.util.*;

public class TestLinkedHashMap


{
public static void main(String[] args)
{
LinkedHashMap codigos = new LinkedHashMap();
codigos.put("01","Urgente");
codigos.put("02","Importante");
codigos.put("03","Normal");
codigos.put("04","Baja prioridad");

System.out.println("Aleatorio 03: " + codigos.get("03"));


System.out.println("Aleatorio 01: " + codigos.get("01"));

Set s = codigos.keySet();
Iterator it = s.iterator();
while(it.hasNext())
{
String aux = (String)it.next();
System.out.println(aux + ": " + codigos.get(aux));
}
}
}

307
MODULO 3

 Ejemplo: Utilización de java.util.TreeMap

import java.util.*;

public class TestTreeMap


{
public static void main(String[] args)
{
TreeMap codigos = new TreeMap();
codigos.put("04","Baja prioridad");
codigos.put("01","Urgente");
codigos.put("03","Normal");
codigos.put("02","Importante");

System.out.println("Aleatorio 03: " + codigos.get("03"));


System.out.println("Aleatorio 01: " + codigos.get("01"));

Set s = codigos.keySet();
Iterator it = s.iterator();
while(it.hasNext())
{
String aux = (String)it.next();
System.out.println(aux + ": " + codigos.get(aux));
}
}
}

308
Unidad 3.2 Estructura de datos

2.5 Generics

Se trata de una de las grandes novedades que introdujo Java SE 5.0

Permite tipar el contenido de las colecciones, de manera que se restringe el


tipo utilizado y se elimina el uso masivo de castings.

Para definir el tipo del contenido de una colección se utiliza <tipo>:

tipo_coleccion<tipo_contenido> identificador = null;


identificador = new tipo_coleccion<tipo_contenido>();

 Ejemplo: List<String> lista = new ArrayList<String>();

En este caso, se trabajaría utilizando Strings directamente sin


necesidad de casting alguno:

String elemento = lista.get(0);

En el caso de colecciones de tipo Map, se definiría tanto el tipo de las claves


como el de los valores:

Map<Integer,String> mapa = new HashMap<Integer,String>();

309
MODULO 3

3. Importancia de los métodos equals() y hashCode()

Siempre que creemos nuestras propias claves para el uso de los Map, debemos so-
breescribir los métodos equals() y hashCode().

El motivo es que los Map utilizan estos dos métodos para llevar a cabo tanto las
inserciones como las extracciones de valores.

Para entender mejor el uso de estos dos métodos por parte de los Map, veamos un
poco más en detalle la estructura interna de este tipo de colección.

La estructura interna de un Map es la siguiente:

Un Map internamente contiene una secuencia de compartimentos (buckets) donde


se van almacenando todos los valores (clave/valor).

Para decidir en qué compartimento se almacena un valor, se llama al método hash-


Code() del objeto utilizado como clave.

Pero pueden ocurrir colisiones, es decir, que un compartimento ya esté utilizado por
una pareja clave/valor. Esto puede ser debido a que:

 Dos objetos distintos devolvieron el mismo código hash.

 Dos códigos hash distintos correspondieron al mismo com-


partimento.

310
Unidad 3.2 Estructura de datos

Imaginemos que hacemos un get del Map y el compartimento correspondiente tiene


colisiones. ¿Qué valor nos devuelve?

Lo sabe mediante el uso del método equals() de la clave. Va iterando por todas las
claves de ese compartimento para encontrar la que se ha pedido.

Imaginemos que hacemos un put en el Map con una clave ya existente. ¿Cómo sa-
be que ya existe y que hay que machacar el valor anterior?

Lo sabe mediante el uso del método equals() de la clave. Itera para comprobar si
ya existe.

La implementación del método equals() debe cumplir las siguientes normas:

 Reflexiva: x.equals(x) debe devolver true.

 Simétrica: Si x.equals(y) devuelve true, y.equals(x) debe


devolver también true.

 Transitiva: Si x.equals(y) devuelve true, e y.equals(z) de-


vuelve true, x.equals(z) debe devolver también true.

 Consistente: Si x.equals(y) devuelve true, entonces las su-


cesivas invocaciones de x.equals(y) sin haber modificado el estado
de x o y deben seguir devolviendo true.

 Null: x.equals(null) siempre debe devolver false.

 Ejemplo: Sobreescritura del método equals

public class TestEquals


{
private int valor1;
private Integer valor2;

public boolean equals(Object o)


{
if(this == o) // Primer paso.
return true;
if(!(o instanceof TestEquals)) // Segundo paso.
return false;
TestEquals param = (TestEquals)o; // Tercer paso.
return param.valor1 == valor1 &&
param.valor2.equals(valor2);
}
}

311
MODULO 3

public static void main(String[] args)


{
TestEquals test1 = new TestEquals(1, new Integer(2));
TestEquals test2 = new TestEquals(1, new Integer(2));
System.out.println(test1.equals(test2));
}

La implementación del método hashCode() debe cumplir las siguientes normas:

 La ejecución sucesiva del método hashCode() sobre un


mismo objeto sin haber modificado su estado interno entre medias,
debe devolver siempre el mismo código hash.

 Si x.equals(y) devuelve true, entonces tanto x como y de-


ben generar el mismo código hash.

 Sin embargo, si x.equals(y) devuelve false, no es obligato-


rio que tanto x como y deban generar un código hash distinto. No
obstante es lo deseable para evitar en la medida de lo posible las co-
lisiones en los Map y por tanto ofrecer un mejor rendimiento.

La implementación del método hashCode() no es una tarea tan trivial. No obstante,


aquí proponemos dos sugerencias bastante sencillas:

 Convertir a String los valores de los distintos atributos de la


clase. Concatenarlos y delegar la generación del código hash en el
método hashCode() del String resultante (la clase String posee una
implementación bastante eficaz del método hashCode()).

 Sumar el código hash de cada uno de los atributos de la


clase (los wrappers de tipos primitivos también tienen sobreescrito el
método hashcode()).

 Ejemplo: Sobreescritura del método hashcode

312
Unidad 3.2 Estructura de datos

public class TestHashCode


{
private int valor1;
private Integer valor2;

public int hashCode()


{
StringBuffer buffer = new StringBuffer();
buffer.append(Integer.toString(valor1));
buffer.append(valor2.toString());
return buffer.toString().hashCode();
}
}

public static void main(String[] args)


{
TestHashCode test1 = new TestHashCode(1, new Integer(2));
TestHashCode test2 = new TestHashCode(1, new Integer(2));
System.out.println(test1.hashCode());
System.out.println(test2.hashCode());
}

El método equals() también es importante para el resto de Colecciones.

Por ejemplo, ¿cómo funcionan los métodos contains(), add() y remove() de las co-
lecciones?

Para saber si un objeto está contenido en una colección se va llamando al método


equals() de todos los objetos de la colección. Para borrarlo de una colección, se le
busca de igual forma. Y para añadirlo en un Set que no permite duplicados, lo mis-
mo.

 Ejemplo: Sobreescritura del método equals

public static void main(String[] args)


{
TestEquals test1 = new TestEquals(1, new Integer(2));
List list = new ArrayList();
list.add(test1);
TestEquals test2 = new TestEquals(1, new Integer(2));
System.out.println(list.contains(test2));
}

313
MODULO 3

4. Arrays vs. Colecciones

A continuación mostraremos un resumen de las características vistas en esta Uni-


dad tanto de los Arrays como de las Colecciones, que nos permitirán poder discernir
cuando utilizar un tipo u otro.

Las características de los Arrays son:

 Tamaño estático.

 Su tamaño se conoce mediante el atributo length.

 Puede almacenar tanto tipos primitivos como tipos comple-


jos.

 Solo pueden albergar elementos de un tipo.

Las características de las Colecciones son:

 Tamaño dinámico.

 Su tamaño se conoce mediante el método size().

 Solo puede almacenar tipos complejos.

 Puede albergar elementos de distinto tipo.

314
Unidad 3.2 Estructura de datos

PRÁCTICA A: Desarrollar, tanto en la JDK de Sun como en Eclipse, un sistema de


gestión de un garaje siguiendo estas especificaciones.

En el garaje se cambian las ruedas tanto de coches como de motos. El precio del
cambio de una rueda se fija al abrir el garaje, al igual que la capacidad máxima de
vehículos, ya sean motos o coches. Si no hubiese hueco para registrar un vehículo
nuevo, habrá que tener contemplado un sistema de aviso para quien esté dejando
su vehículo.

El sistema de gestión del garaje requiere un mecanismo para ingresar y retirar los
vehículos, conocer el número total de vehículos recibidos en ese momento, el precio
que supondría cambiar todas las ruedas de todos los vehículos, y el kilometraje
medio de todos ellos.

La información que manejaremos de los coches entre otras cosas es la marca y el


número de puertas. Mientras que de las motos será la marca y la cilindrada.

Las clases relacionadas con los vehículos se guardarán en el paquete


es.java.aula.mentor.practicas31.vehiculos mientras que el Garaje y PracticaA se
guardarán en el paquete es.java.aula.mentor.practicas31.

La clase PracticaA tiene un método main en el que se crea un Garaje, una serie de
vehículos que se irán recibiendo en el garaje y por último se imprimirá por pantalla
toda la información general del garaje así como la información de cada vehículo.

NOTA: Realizar esta práctica mediante Arrays.

Solución con la JDK De Sun

En el caso de que no esté puesta la variable de entorno PATH, abrir una sesión DOS
y ajustar la variable de entorno PATH para que el Sistema Operativo sepa encontrar
las herramientas del JDK. Para respetar el valor que ya tuviese la variable PATH le
añadimos %PATH%.

315
MODULO 3

Creamos un directorio de trabajo donde guardar el programa Java.

Ajustar la variable de entorno CLASSPATH para que las herramientas del JDK sepan
encontrar nuestras clases Java. Tenemos dos opciones, o añadir el . (punto) y
siempre ejecutar las herramientas en el directorio donde se encuentre el código, o
añadir el directorio de trabajo y ejecutar las herramientas donde queramos. Para
respetar el valor que ya tuviese la variable CLASSPATH le añadimos %CLASS-
PATH%

316
Unidad 3.2 Estructura de datos

Creamos los directorios donde van a estar nuestras clases


es\java\aula\mentor\\practicas31 y es\java\aula\mentor\\practicas31\vehiculos

Desde el directorio es\java\aula\mentor\practicas31\vehiculos, con un editor de


texto (por ejemplo Notepad) vamos a escribir el código fuente de nuestras clases
java; el nombre del fichero de la clase debe ser exactamente igual (incluyendo ma-
yúsculas y minúsculas) al de la clase Java que vamos a desarrollar.
Empezamos con la clase Vehiculo.java

317
MODULO 3

El código del interface podría quedar como sigue:

Seguimos con la clase Coche que implementa el interface Vehiculo

318
Unidad 3.2 Estructura de datos

Ahora toca el turno a la clase Moto que también implementa el interface Vehiculo

Ya podemos implementar la clase Garaje, desde el directorio


es\java\aula\mentor\practicas31

319
MODULO 3

Por último la clase PracticaA, que contiene el método main podría quedar como si-
gue:

320
Unidad 3.2 Estructura de datos

Para compilar un posible orden sería el siguiente:

Para ejecutar la aplicación

Ahora realizaremos la misma práctica con Eclipse

Arrancar Eclipse, ejecutando c:\eclipse3.5.2\eclipse.exe

Seleccionar la ubicación del “workspace” (o área de trabajo).

321
MODULO 3

Aparecerá la pantalla para empezar a trabajar.

322
Unidad 3.2 Estructura de datos

Verificar que la perspectiva Java está abierta, y sino cambiar a


ella

Crear un proyecto nuevo de nombre Practicas31

Darle el nombre y seleccionar Finish.

Crear un interface Java nuevo llamado Vehiculo, especificando el paquete


es.java.aula.mentor.practicas31.vehiculos

323
MODULO 3

La interface quedaría como sigue:

A continuación creamos la clase Coche, en el mismo paquete que el interface Vehi-


culo e indicamos que vamos a implementar dicho interface

324
Unidad 3.2 Estructura de datos

325
MODULO 3

Realizamos el mismo proceso para la clase Moto

Creamos la clase Garaje en el paquete es.java.aula.mentor.practicas31, que es la


que va a contener a los distintos vehiculos

package es.java.aula.mentor.practicas31;
import es.java.aula.mentor.practicas31.vehiculos.Vehiculo;

public class Garaje {


// Atributos.
private Vehiculo[] vehiculos = null;
private int precio = 0;

326
Unidad 3.2 Estructura de datos

// Constructores.
public Garaje(int param1, int param2)
{
vehiculos = new Vehiculo[param1];
precio = param2;
}
// Métodos.
public boolean ingresarVehiculo(Vehiculo param)
{
boolean sw = false;
for(int i=0; i<vehiculos.length; i++) {
if(vehiculos[i] == null) {
sw = true;
vehiculos[i] = param;
break;
}
}
return sw;
}

public void retirarVehiculo(Vehiculo param)


{
for(int i=0; i<vehiculos.length; i++) {
if(vehiculos[i] == param) {
vehiculos[i] = null;
break;
}
}
}

public Vehiculo[] getVehiculos()


{
Vehiculo[] temp = new Vehiculo[this.getNumVehiculos()];
for(int j=0, i=0; j<temp.length && i<vehiculos.length; i++) {
if(vehiculos[i] != null) {
temp[j] = vehiculos[i];
j++;
}
}
return temp;
}

public double getKilometrajeMedio()


{
int cont = 0;
double acum = 0;
for(int i=0; i<vehiculos.length; i++) {
if(vehiculos[i] != null) {
cont++;
acum += vehiculos[i].getKilometraje();
}
}
return acum / cont;
}

public int getCosteTotal()


{
int acum = 0;
for(int i=0; i<vehiculos.length; i++) {
if(vehiculos[i] != null)
acum += vehiculos[i].getNumRuedas();
}
return acum * precio;
}

public int getNumVehiculos()


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

327
MODULO 3

if(vehiculos[i] != null)
cont++;
}
return cont;
}
}

Finalizamos creando la clase PracticaA, marcando que nos cree el método main

quedando la clase de la siguiente manera:

328
Unidad 3.2 Estructura de datos

Verificar que todas las clases están grabadas. Para ello utilizar Ctrl + S en cada cla-
se o en File -> Save All

Para ejecutar la aplicación, seleccionar encima de la clase PracticaA con el botón


derecho del ratón Run As -> Java Application

329
MODULO 3

330
Unidad 3.2 Estructura de datos

PRÁCTICA B: Desarrollar, tanto en la JDK de Sun como en Eclipse, un sistema de


gestión de pacientes.

Tendremos un archivador donde iremos guardando todas las fichas de los pacien-
tes. Las fichas contienen la siguiente información: nombre, apellidos y edad.

Todas las fichas que vayamos creando, se podrán guardar o eliminar del archiva-
dor. Al archivador también le podremos pedir un listado. Este listado consistirá en
imprimir por pantalla el número de fichas guardadas, así como el contenido de las
fichas.

Todas las clases se guardarán en el paquete es.java.aula.mentor.practicas31.

La clase PracticaB tiene un método main en el que se crea un archivador, dos o


tres fichas que se guardarán en el archivador, se listará el contenido, se eliminará
alguna ficha y se volverá a listar su contenido.

NOTA: Realizar esta práctica mediante Colecciones.

Reutilizaremos los directorios, paquetes .... realizados en la PracticaA.

Solución con la JDK De Sun

En el directorio es\java\aula\mentor\practicas31\, mediante el notepad, creamos la


clase Ficha

331
MODULO 3

A continuación nos creamos la clase Archivador, que es la que va a contener a las


fichas

Por último nos creamos la clase PracticaB con el main.

332
Unidad 3.2 Estructura de datos

El orden de compilación debe de ser el siguiente:

Ejecutamos la práctica

333
MODULO 3

Ahora realizaremos la misma práctica con Eclipse. Arrancar Eclipse, ejecutando


c:\eclipse3.5.2\eclipse.exe

Seleccionar la ubicación del “workspace” (o área de trabajo).

Ya tenemos creado el proyecto Practicas31, utilizado en la Práctica A. Vamos a


crear la clase Ficha, perteneciente al paquete es.java.aula.mentor.practicas31

Continuamos con la clase Archivador

334
Unidad 3.2 Estructura de datos

Y finalmente con la clase PracticaB

Ejecutamos la clase, obteniendo la siguiente salida

335
MODULO 3 JAVA AVANZADO

En esta Unidad hemos visto como trabajar con los conjuntos de datos, como una so-
la variable u objeto. Los dos grandes grupos que permiten tratar con conjuntos de
datos son:

 Arrays:
- Tienen un tamaño estático
- Su tamaño se conoce mediante el atributo length.
- Puede almacenar tanto tipos primitivos como tipos
complejos.
- Solo pueden albergar elementos de un tipo.

 Colecciones:
- Tienen un tamaño dinámico
- Su tamaño se conoce mediante método size().
- Puede almacenar solo tipo complejos, ya sean del
mismo o distinto tipo.

Las Colecciones se clasifican en dos grandes grupos:


 java.util.Collection que trabaja con elementos de tipos complejos de for-
ma conjunta. Se clasifican a su vez en:
- java.util.Set: Representa colecciones que no permi-
ten tener elementos duplicados. java.util.HashSet se
utiliza para acceso aleatorio, java.util.LinkedHashSet
se utiliza para el acceso según su orden de inserción
y java.util.TreeSet depende de la implementación del
método public int compareTo(Object o);
- java.util.List: Representa colecciones que pueden
- tener elementos duplicados. java.util.ArrayList utili-
zado para accesos aleatorios, java.util.LinkedList uti-
lizado cuando se necesita añadir o eliminar elemen-
tos del comienzo y final de la lista y java.util.Vector
que es como el ArrayList, pero sincronizado.
Unidad 3.1 Estructura de datos

 java.util.Map que trabaja con elementos del tipo clave/valor. Se clasifican


a su vez en:
- java.util.HashMap: Ofrece un tiempo de
acceso óptimo cuando dicho acceso es
aleatorio.
- java.util.Hashtable: Es la versión sincro-
nizada de HashMap.

También podría gustarte