SlideShare una empresa de Scribd logo
Id
Java 2, incluyena
JAVA 2
MANUAL DE PROGRAMACIÓN
JAVA 2
MANUAL DE PROGRAMACIÓN
Luis Joyanes Aguilar
Matilde Fernandez Azuela
Departamento de Lenguajes y Sistemas Informáticos e Ingeniería del Software
Facultad de Informática / Escuela Universitaria de informática
Universidad Pontificia de Salamanca. Campus Madrid
Osborne
McGraw-Hill
MADRID BUENOS AIRES CARACAS GUATEMALA LISBOA MÉXICO
NUEVA YORK PANAMA SAN JUAN SANTAFÉ DE BOGOTÁ SANTIAGO SA0 PAUL0
SAN FRANCISCO * SIDNEY SINGAPUR ST. LOUIS TOKIO * TORONTO
AUCKLAND HAMBURG0 LONDRES * MILÁN MONTREAL NUEVA DELHI PARiS
CONTENIDO
....<.<...........< .............................................< ........
Capítulo I . Introducción a .Java ................
1. I . La historia de Java .......... ........,...<....,...<.<........<.
1.3.;,Qué es .l¿l¿l? ....<..._......<..<.<...._.....<.<......................................
I .7.I . Java coi110 leiigua.jc de Internet
I.7.7. .lava con10 leng~ia.je
1.3.I . Sencillo ... .............I . . . . . . . . . . . . . . . . . . . . .
I .3.3. Orientado
I .3.3. Distribuido ..................................................................
1 .3. Características de J a ~ a......................
. <
.........<.............<.
1.3.6. Seguro .......................................
1.3.7. ,4rqiiitectur
1 .3.8. Portable .......~ ...............................................
1 .3.9. Alto i-endiiniento .... ..<..........<............<.......
I .3.10. Multihilo ......................................................
I .3.1I . r>inón1ico ....... ............<........._....<...<<.<.......<
I .4. La programación orientada a objetos como base de Java
I .5. Especificacioiies del lengua-je Java ......................................
1.6,Aplicaciones y u p p / c t ~.........................................
Seiiiejanzas y diterencias entre aplicaciones 4
Etapas para crear un programa ...................................
Componentes de ~ i n aaplicación ........................................
.‘l. Herrainientas de desarrollo Java ...... .<.............<
I .9,I , El entorno de desarrollo JDK .....................................
. I O. Una aplicación práctica de Java ........................... .......
I .h.1,
1 .7.I ,
1 .8.
xiii
1
2
3
3
4
5
5
6
7
7
8
8
9
9
I O
I o
11
1 1
12
13
13
15
15
18
21
71
27
V
vi Contenido
I,11. Estructura de un programa aplicación en Java ................................................
1.1 I . 1. Referencia a miembros de una clase .........................................................
I , 17.I Errores de compilaci ...............................................
I , 12.2. Errores de e-iecución
I . 12.3. Errores Ibgicos .......................................................
25
27
I . 12. Errores de programación ......................................................
....................................
Capítulo 2. Características del lenguaje Java .......................................................... 31
2.1. Palabras resercadas .. ......................................................
22. Identiíicadores ..... .................................................
7.3. Tipos de datos ....................................................
..................
2.6. constantes ................................................. ......................................
2.7. La biblioteca dc clases de Java ....................................................
7.8. Coiiceptos bisicos sobre excep ...................................................
2.9.
7.10. Las clases Character y Boolean ........................
La clase Nxmber y sus subclases ....................................
..........................
..................................
.....................................
2.13. La sentencia dc asignación .......
2.14. Expresiones .................. ..................................................
.................................................
2.15. ClaseMath ........... .........................................................
...............................
2.18. Operadores aritméticos ......................... .....................................
7.19. Operadores relacionales ................. .........................................
2.20. Operadores lb&''ICOS ............... ....................................................
.....................................................
...................................................
32
33
34
34
38
41
44
45
46
48
49
52
52
53
54
55
55
57
57
58
61
61
63
65
67
67
71
3.I . La sentencia i f ........... 72
3.3. La sentencia i f - e l s e 73
3.3. Las sentencias i f e I f - e l s e anidadas 74
3.4. La sentencia s w i t c h ..................................................... 78
803.5. La sentencia f o r ....................
3.6. La sentencia break 83
3.7. La sentencia continue ...... 85
Capítulo 3. Decisiones y bucles ................. ............................................
...................................................
....................................................
............................
.....................................................
................................. ...................................
...............................................
Contenido vi¡
3.8. Diferencias entre continue y break .........................................................
3.9. La sentencia while ......................................................................................
3.10. La sentencia do-while ................................................................................
Capítulo 4.Clases. objetos y mktodos .......................................................................
4.1.
4.2.
4.3.
4.4.
4.5.
4.6.
4.7.
4.8.
4.9.
4.IO.
4.11.
Ob-jetos y clases ..
Declaración y crea
Acceso a datos y n
Utilización de inétodos
Paso de paránietros .........................................................................................
Paso de parárnetros por valor .
Paso de parámetro
Constructores ......
Modificadores dc
private .................................
protected ....................................................................................................
4.12. public ...........................................................................................................
4.I3. Recursividad ...................................................................................................
. .
Capítulo 5.Herencia ...................................................................................................
5.I.
5.3. El inétodo c l o n e ............................................................................................
5.4. El método equals
5.5. El método f i n a l 1ze .....................................................................................
5.6. El método tostring
5.7. El método getclass .....................................................................................
Descripción de herencia ...................................................................................
5.2. La clase Object . ...............................
5.8. Ventajas de la herencia ....................................................
5.9. Superclases y subclases ...................................................................................
5.I0. Modificadores y herencia
5.1 I . Clases abstractas ...............................................................................................
5.12. Métodos abstractos
5.13. Interfaces ... ............................................................................................
5.14. Definición d
Capítulo 6.Encapsulamiento y polirnorfisrno ..........................................................
6.1.
6.2.
6.3.
6.4.
6.5.
6.6.
6.7.
6.8.
6.9.
Encapsulainiento .. ...............................
Modificadores de c
Modificadores de bariables ...............................
Modificadores de inétodos ...............................................................................
Clases internas ..... ............ ..........
Paquetes ...........................................................................................................
Declaración de un paquete .......
Paquetes incorporados .....................................................................................
Acceso a los elementos de un paquete
86
88
91
95
96
98
I o0
1O0
102
I03
103
104
107
1ox
109
1 1 1
1 1 1
117
118
I19
122
122
127
I73
123
124
124
I25
127
129
134
I35
141
142
142
143
144
144
149
150
151
152
vi¡¡ Contenido
6.I 0. Importacióii de pacliietes ...............................
6.I I , Control de acceso a paquetes
6.12. Polimortisino ....................................................... ............................
6.13. Ligadura .......................... _.........<.............<.<........_._..<...................
6.14, Ligadura diiiiiiiicn ...................................................... ...............
................................ <..
......................... <............_...................
......<..<.........
7.I . Concepto de array .............................. ........................... <................
7.2. Proceso de arrays
7.2.I DeclaraciOn ................................ .............................................
7.2.2. CreaciUn ........ ............................................ <.....
7.3. Arrays de objetos .. .....<.......................<......................
...................................
7.5. .4rrays mu ItidiniensioiiaIes ._....<.<.<._._._._......<..........._....<.<.........
7.6. Ordenación de arrays .........<..._._..................._..................
7.X. Burbuja ................ _..........<..._._._....<.<.........._._..............
7.1 1 . Ordenación ripida ........................................
7.12. Rúsclueda ........................ ............_......<..............._...........<....
7.7. Selection ...................<......................... _._..<....<...................<.............
7.9. Inserción ............,...................................
7.10. Shell ,..._._............. _....<...................<.<.........................
.........................................
..................................
......................
Capítulo 8. Cadenas y fechas ....................................... ........................
8. I . Creación de cadenas _............<...............................<.......
8.2. Comparación de cadenas .................... ........................................
8.3. Concatenación ...... .......................................... <.......
X.4. Otros métod .....<...........................
8.5. Laclase St
8.6. La clase StringBuffer ................................ .........................
8.7. Métodos de
8.8. La clase Date .........._........<................_..........
8.9. Los formatos de Fechas ... ._....<....<.......................................
8.10. La clase Calendar .............................................. ...................
..............
Capítulo 9. Interfaces grificas de usuario ..............................................
9.I . El AWT.......... ................................................
9.2. Realización d ..........................................
9.3. La clase Com
9.3. La clase Container ............................. ........<...........................<
9.5. Ventanas .............. ............<.<.......................................
9.5,I . Clase Frame ...................................... ...................................
153
153
154
156
157
161
162
163
164
164
165
167
169
171
172
178
179
I x0
181
1x3
1x5
I X6
1 XX
193
194
197
20 1
202
20X
209
210
212
213
214
217
218
219
222
224
225
225
9.5.2. Clase Dialog ............................................................................................ 229
Contenido ¡X
0.5.3. (’lase FileDialog ..................................................................................
9.6. Clase Par?el........................... .........................................
9.7. Clase Label ....................................................................................................
9.8. C’lasc Button ........................ ........................................
0.0. Clase T e x t C o r n p o n e n t ................................................................ ~ ................
0.10. (’lase canvas ........................
9.1 I . Clase Choice ..................................................................................................
9. 12. Clase Chec kbox ...................
............<......<..................<.............
............................
.............<.............<.....................<......................,,,,.......................
......................
9.15. Meniis . .................................... <........<.........................,,.,.,......................
9.16. Adininistradores de diseno ...... ..........................................
9.16.1, FlowLayout .....................................................................................
Capitulo 10. Gestión de eventos .......
10.2. Los componentes del AWT con
...................... <...............
10.1 . Tipos de eventos .....................
10.3. Receptores de eventos ............
10.4. Procesamiento de eventos ................................................................................
10.5. Clases adaptadoras ......................................................................
10.6. Clases receptoras anóniinas ..............................................................................
10.7. Problemas comunes en cl tratamiento de eventos
.........................................
....
Capitulo 11. Applets ........................... ......<..........
1 1 , 1 . Introducción a HTML .............
I 1 2. Incorporación de q 7 p / c ~ / . sa páginas Web .........................................................
I 1 2.I . Edición de un documento HTML y ejecución de applets .
1 1.4. Transforinación de aplicaciones en tipplefs ................................
1 1 .6. Incorporación de imágenes .........................................................
11.3. Estructura de un tr/~plet
1 I .5. Incorporación de sonido .......... ................................................
..........................................................................
Capitulo 12. Programacih concurrente: Hilos de ejecución .................................
12.1, La prograinacih niultihilo en Java .................................................................
12.2. Estados de un hilo ............................................
12.3. Creación de hilos ..........................................................................
12.4. Planiticaci6n y pri
12.6.Grupos de hilos ..........................................................................
12.7. Sincronizacióii ........................ .............<....<.........................<.<<
12.8. Animaciones ...............................................................................
. .
12.5. Hilos de tipo demonio ......................... ........................................... I....
12.9, Doble hi!fj’¿~/- ............................... .........<.<..................................<.
232
234
234
236
238
242
244
246
249
252
254
256
256
257
258
262
263
264
265
266
269
272
274
276
285
286
289
29 1
294
29X
306
306
311
312
313
3 I4
316
317
318
319
326
327
x Contenido
Capítulo 13. Rlanejo de excepciones .........................................................................
13.1.
13.7.
I 3.-3.
1.3.4.
13.5.
13.6.
13.7.
13.x.
Coiiceptos generales ..,.,.,...............................
Mane.jo de excepciones .........
Captura y tiatanliento de exce ,.<..............<..<.... ..........<........
.........<....<...................
....................... <..._...........<.<........
. ,
Laiizar la cxcepcioii .,...._....,..
Declarar la excepcioii ...................................... ..............
El bloque f inaliy ..........................
Creacicín de excepciones ................................................
Mitodos de la clase Throwable ..........
.....................
. I
._...<..<....._................................
..........................................
Capitulo 14. Archivos .................................................................................................
14.I . La clase File ........... ..................................................
.................................................................... ......................
14.3. Apertura de archivos .. ......................................... <...........
14.4,Eiicadenaimiento
14.5. Evcepciones en ar
.........<...............<.................
14.6. Mitodos de I n p .......................................
14.7. hldodos de Outputstream ........<.<........<................................
14.8. [;lbtodos de Reader ............................................... ........................
14.9. Xlitodos de Writer ........................ .................................................
14.10. Mitodos de DataInputStream ....................................
14.1I . Mitodos de DataOutputStream ..
13.12.Vitodos de RandomAcces s F i l e ..................................
14,13. Serializacióii de objetos .....................
........................ <......................
................................................
14.13. StringTokenizer y StreamTokenizer .............
14.15. Operaciones con
13.16.Archibos secuenciales ....
13.17.Archivos directo ..........................
14.I 8. Funciones de transformación de clave y tratamiento de colisiones ..........
...................<......................
Capítulo 15. Estructuras de datos definidas por el programador .........................
15.1. Lista ...................................... <........ .......................................
15.3. Lista ordenada ...............................................
15.4,
1.7.5. Listas doblemente enlazadas ......................................... ................
15.6. Pilas ............................................ ...........................................
15.7. Colas ......................... .............................................
15.8. Colas circulares ......................................... .......................................
15.7. Iiiiplementación de una lista ,..............._..<.........................
.............................
Listas genéricas y LISO de interfaces
339
340
343
343
345
347
348
353
358
361
362
368
370
373
375
378
379
379
379
380
38 1
38 1
382
3x3
383
384
395
396
411
412
415
417
422
434
435
438
442
A.
B.
C.
D.
E.
F.
G.
Contenido xi
APÉNDICES
Palabras reservadas Java ...................................................................................... 445
Prioridad de operadores 447
Guía de sintaxis ..............................................................................
Paquetes de la plataforma Java 2. Versiones 1 .3 y 1.4 Beta ...............................
Recursos: libros, revistas y WEB ........................................................................
índice analítico ............................................................................................................ 529
PRÓLOGO
Cinco años después de su lanzamiento, Java se ha convertido en
un estándar de la industria, en un lenguaje de programación para
desarrollo de aplicaciones tanto de propósito general como de
Internet, y también en un lenguaje para comenzar la formación en
programación, al tener características excelentes para el aprendi-
zaje.
Java, desarrollado por Sun Microsystems en 1995, es un mag-
nífico y completo lenguaje de programación orientado a objetos
diseñado para distribuir contenidos a través de una red. Una de sus
principales características es que permite operar de forma inde7
pendiente de la plataforma y del sistema operativo que se esté uti-
lizando. Esto quiere decir que permite crear una aplicación que
podrá descargarse de la red y funcionar posteriormente en cual-
quier tipo de plataforma de hardware o software. Generalmente, y
al contrario, todo programa o aplicación queda atado a dos cosas:
al hardware y al sistema operativo. Así, por ejemplo, una aplica-
ción Windows sólo funcionará en plataforma Wintel (equipada
con procesadores Intel y sistema operativo Windows) igual que
una versión creada para Mac sólo funciona sobre Power PC o
Imac y Mac OS o la misma aplicación desarrollada para Unix, sólo
lo hace sobre plataformas Unix y no hay forma de que funcione
sobre otra máquina.
La idea de Java, por el contrario, es poner una capa sobre
cualquier plataforma de hardware y sobre cualquier sistema ope-
rativo que permite que cualquier aplicación desarrollada en Java
quede ligada únicamente a Java, independizada por lo tanto de la
xiii
xiv Prólogo
plataforma. Esta concepción queda recogida en el concepto de máquina virtual
JVM (Java Virtual Machine), un software que interpreta instrucciones para cual-
quier máquina sobre la que esté corriendo y que permite, una vez instalado, que una
misma aplicación pueda funcionar en un PC o en un Mac sin tener que tocarla. Hoy
en día. cualquier sistema operativo moderno (Windows, Macintosh, Linux, Unix,
Solaris. etc.) cuenta con una JVM. Así, lo que hace Java en combinación con esta
«máquina» es funcionar como hardware y como sistema operativo virtual, emulan-
do en software una CPU universal. Al instalar Java, éste actuará como una capa de
abstracción entre un programa y el sistema operativo. otorgando una total indepen-
dencia de lo que haya por debajo; es decir, cualquier aplicación funcionará en cual-
quier máquina e incluso en cualquier dispositivo.
Otra gran ventaja es que los programadores no tendrán que desarrollar varias
versiones de la misma aplicación, puesto que el modelo de desarrollo es el mismo
se trate del dispositivo más pequeño o del más grande de los servidores. Otra gran
ventaja es que permite que todas las máquinas. plataformas y aplicaciones se comu-
niquen entre sí accediendo desde cualquier equipo, dondequiera que esté situado, a
las aplicaciones que residan en una red, ya sea Internet o una intranet o extranet.
En definitiva, se puede decir que Java es lo más cercano que existe hoy día a un
lenguaje de computación universal, lo que significa que puede correr en cualquier
plataforma siempre y cuando una máquina virtual haya sido escrita para ella.
LA GENEALOGíA DE JAVA
Java es un descendiente de C++ que a su vez es descendiente directo de C. Muchas
características de Java se han heredado de estos dos lenguajes. De C, Java ha here-
dado su sintaxis y de C++, las características fundamentales de programación orien-
tada a objetos.
El diseño original de Java fue concebido por James Gosling, Patrick Naughton,
Chris Warth, Ed Frank y Mike Sheridan, ingenieros y desarrolladores de Sun Mi-
crosystems en 1991, que tardaron 18 meses en terminar la primera versión de tra-
bajo. Este lenguaje se llamó inicialmente «Oak», y se le cambió el nombre por Java
en la primavera de 1995.
Sorprendentemente, la inquietud original para la creación de «Oak» no era
Internet. En realidad, se buscaba un lenguaje independiente de la plataforma (es
decir, de arquitectura neutra) que se pudiera utilizar para crear software que se
incrustara en dispositivos electrónicos diversos tales como controles remotos, auto-
móviles u hornos de microondas. Aunque el modelo de lenguaje elegido fue C++,
se encontraron con que, si bien se podía compilar un programa C++ en cualquier tipo
de CPU (Unidad Central de Proceso), se requería, sin embargo, un compilador C++
completo que corriese en esa CPU. El problema, en consecuencia, se convertía en
compiladores caros y en gran consumo de tiempo para crear los programas. Sobre
Prólogo XV
esas premisas, Gosling y sus colegas comenzaron a pensar en un lenguaje portable,
independiente de la plataforma que se pudiera utilizar para producir código que se
ejecutara en una amplia variedad de CPU y bajo diferentes entornos. Entonces
coinenz6 a aparecer el nuevo proyecto y se decidió llamarle Java.
¿Por qué Java es importante para Internet?
Internet ha ayudado considerablemente a «catapultar» a Java al cenit del mundo de
la programación de computadoras. y Java. a su vez, ha tenido un profundo impacto
en Internet. La razón es muy simple: Java extiende el universo de los objetos que se
mueven libremente en el ciberespacio que forma la red Internet. En una red existen
dos grandes categorías de ob-jetosque se transmiten entre las computadoras conec-
tadas (el servidor y la computadora personal): información pasiva y dinámica, pro-
gramas activos. Un ejemplo fácil de datos pasivos son los correos electrónicos que
usted recibe en su computadora o una página web que se baja de la red. Incluso si
descarga un programa, está recibiendo datos pasivos hasta tanto no ejecute dicho
programa. Sin embargo, existewotros tipos de objetos que se transmiten por la red:
programas dinámicos autoejecutables que son agentes activos en la computadora
cliente.
Estos programas dinámicos en red presentan serios problemas de seguridad y
portnhilidad. Java ha resuelto gran cantidad de problemas con un nuevo modelo de
programa: el upplot.
Java se puede utilizar para crear dos tipos de programas: aplicaciones y applets.
Una aplicucicín es un programa que se ejecuta en su computadora bajo el sistema
operativo de su computadora; en esencia, es un programa similar al creado utili-
zando C, C++ o Pascal. Cuando se utiliza para crear aplicaciones, Java es un len-
guaje de propósito general similar a cualquier otro y con características que lo hacen
idóneo para programación orientada a objetos. Este libro dedica buena parte de su
contenido a enseñar a diseñar, escribir y ejecutar aplicaciones,
Pero Java tiene una característica notable que no tienen otros lenguajes: la posi-
bilidad de crear applets. Un applet es una aplicación diseñada para ser transmitida
por Internet y ejecutada por un navegador Web compatible con Java. Un applet es
realmente un pequeño programa Java, descargado dinámicamente por la red, tal
como una imagen, un archivo de sonido, un archivo musical MP3 o divX, o una
secuencia de vídeo: pero con una notable propiedad, es un programa inteligente que
puede reaccionar dinámicamente a entradas y cambios del usuario.
Java es un lenguaje idóneo para resolver los problemas de seguridad y portabili-
dad inherentes a los sistemas que trabajan en red. La razón fundamental de este aser-
to reside en el hecho de que la salida de un compilador Java no es un código ejecutable,
sino códigos de bytes (bytecode).Un hvtecode es un conjunto de instrucciones muy
optimizadas diseñadas para ser ejecutadas por un sistema en tiempo de ejecución
xvi Prólogo
Java. denominado máquina virtual Java (JUVLIVit+mdMachine, JVM)que actúa como
un interprete para los bytecodes. La traducción de un programa en código4 de bytes
facilita la ejecución del programa en una amplia variedad de entorna y plataformas.
La razón es simple: sólo es preciso implementar JVM en cada plataforma.
EVOLUCIÓN DE LAS VERSIONES DE JAVA
Java comenzó a desarrollarse en 1991 con el nombre de Proyecto Ouk («roble»en
inglés) que era -según cuentan sus inventores- el árbol que veían desde su despa-
cho. Tras muchas peripecias, Java salió al mercado en 1995 y el cambio de nombre
parece que se debía a que era uno de los tipos de café que servían en una cafetería
cercana al lugar en que traba.jaban los desarrolladores y ésa es la razón de que el
logotipo de Java sea una humeante taza de café.
Una de las primeras aplicaciones que lo soportan con especificaciones comunes
para las que se comenzó a diseñar Java fue Internet; su objetivo era poder descar-
gar en cualquier tipo de máquina aplicaciones residentes en la Web y ejecutarlas
para trabajar con ellas contra la propia máquina del usuario. AI principio se trataba
de aplicaciones HTML -páginas de puro contenido estático- y fue evolucionando y
adaptándose a Internet y a sus innovaciones tecnológicas; eso significa que Java
soporta XML de modo muy eficiente y las nuevas tecnologías inalámbricas, celula-
res o móviles. Dos grandes especificaciones existen actualmente en torno a Java:
J2EE (Java 2 Enterprise Edition) y J2ME (Java 2 MicroEdition).
J2EE, está orientada al desarrollo de aplicaciones de propósito general y son
numerosos los grandes fabricantes (IBM. Nokia, Motorola, Hewlett-Packard ....) que
lo soportan con especificaciones comunes; J2EM, un nuevo estándar para disposi-
tivos inalámbricos (móviles, de bolsillo o de mano (handhrlds))que requieren una
integración en dispositivos con poco espacio físico y memoria de trabajo. J2EE es
ya un auténtico estándar así reconocido por la industria y J2EM va camino de con-
vertirse en otro gran estándar. que en este caso está contribuyendo a la revolución
inalátnbrica que está haciendo que Internet llegue a dispositivos electrónicos de
todo tipo, como teléfonos móviles (celulares), teléfonos de sobremesa, electrodo-
mésticos, decodificadores de TV digital, etc.
La versión original de Java que comenzó a comercializarse y expandirse con
rapidez fue la 1.O, aunque pronto apareció la versión I . I , que si bien sólo cambió el
segundo dígito del número, los cambios fueron más profundos de lo que el número
suele indicar en la nomenclatura de los programas de software (modificaciones y
pequeñas actualizaciones). De hecho, añadió numerosos elementos a la biblioteca.
redefinió los sucesos (eventos) y reconfiguró la citada biblioteca. Posteriormente la
versión 2, con sus diferentes kits de desarrollo, ha servido para asentar la eficiencia
y calidad Java. Se puede considerar que Sun ha lanzado cinco versiones importan-
tes del lenguaje Java:
Prólogo xvii
Java 1.0. Una pequeña versión centrada en la Web disponible uniformemente
para todos los navegadores Web populares y que se lanzó en 1995.
J m u 1.1. Una versión lanzada en 1997 con mejoras de la interfaz de usuario,
manipulación de sucesos (eventos) reescrita totalmente y una tecnología de
componentes denoniinada J uvuBeuns.
Juiw 2 cot7 SDK 1.2. Una versión ampliada significativamente y lanzada en
I Y98 con características de interfaces gráficas de usuario, conectividad de
bases de datos y muchas otras mejoras.
Juw 2 COIZSBK 1.3. Una versión lanzada en el 2000 que añade características
notables. como multimedia mejorada, más accesibilidad y compilación más
rápida.
Juvrr 2 ~ 0 1 1SDK 1.3 hetu. Una versión lanzada a primeros del mes de junio de
2001 que, entre otras me.joras. introduce la posibilidad de trabajar con XML. A
finales del 200 1 está prevista la salida de la versión definitiva.
Además de los kits de desarrollo de Java, existen numerosas herramientas
comerciales de desarrollo para los programadores de Java. Las más populares son:
Symantec Visual Café.
Borland Jbuilder.
IBM Visual Age for Java.
Sun Forte for Java.
Si usted trabaja con alguna herramienta distinta de SDK 1.3y 1.4para crear pro-
gramas Java a medida que lea este libro, necesita asegurarse que sus herramientas
de desarrollo están actualizadas para soportar Java 2.
Los programas de este libro fueron escritos y probados con Java SDK v. 1.3.1, la
versión más actual existente durante el proceso de escritura del libro. Sin embargo,
durante la fase de pruebas de imprenta de la obra, Sun presentó oficialmente el 29
de mayo de 2001 la versión Java SDK v. 1.4beta con la cual fueron compilados y
probados todos los programas de nuevo, por lo que usted no deberá tener ningún
problema. Bueno, realmente, sí se le presentará un «problema» como a nosotros,
pero que por fortuna nos resolvieron los ingenieros de Sun Microsystems (Andrew
Bennett y Bill Shannon), cuya ayuda y apoyo técnico destacamos de forma espe-
cial. El «problema» es que al tratar de ejecutar los applets bajo SDK v. 1.4 en el
navegador Web no le funcionarán completamente a menos que utilice unos progra-
mas plug-in descargados del sitio de Sun.
Los navegadores existentes normalmente no soportan -como es lógico- la última
versión de Java y sólo cuando ellos realizan la nueva versión es cuando tienen en
cuenta esta Última versión de Java. Sun ha resuelto esta situación proporcionando
un plug-in (añadido/actualización o «parche»).En realidad, cualquier clase añadida
a Java I .2 y posteriores no se encuentra en la implementación de Java proporcionada
xviii Prólogo
por los navegadores. por lo que se originarán errores al usar las nuevas clases. pero
no debiera haber problemas cuando se está escribiendo código que no usa estas nue-
vas características. No obstante, en Java 1.4 esto no es así. pues se ha eliminado la
opción de coinpilación por defecto del compilador ( j r r i ~ r c . )existente en Java 1.3que
iiutotiiáticliiiieiite dirigía el código a la versión I . 1 de la máquina virtual. Para solu-
cionar este <<problemanse tienen dos posibilidades: Lisir siempre Jriiw Plug-in, lo
cual le permitirá emplear las últiinas rne.joras del producto. o dirigir específicamen-
te SLI código a una máquina virtual determinada compatible con el navegador corres-
pondiente. mediante el empleo del modificador -tcrr,yet del cornpilador.
Las nuevas actualizaciones
Sun Microsystems es propietaria de Java; sin embargo, numerosos fabricantes con-
tribuyen a la me-jora y desarrollo de las especificaciones del ectándar. Sun propor-
ciona las licencias de esta tecnología pero e.jerce siempre un cierto control sobre las
implenientaciones que se hacen de la misma, con el ob.jetivo de mantener la inde-
pendencia de la plataforma. Ese objetivo se trata de conseguir con procesos contro-
lados por el programa JCP ( J m w Coinmimit~Procrss). en los que se determina el
proceso formal de estandarización y continuar asegurándose de que las especifica-
ciones siguen siendo compatibles. Es decir. que Java siga siendo Java.
Las actualizaciones más utilizadas actualmente son la versión Java 2 (J2SE)
y los kit de desarrollo JDK 1.2 y 1.3. Sin embargo, ya está disponible
(java .sun.corn/ j2 se/1.4 ) la versión más reciente. J2SE 1.4 (kit de desarro-
Ilo JDK 1.4).para las plataformas Solaris. Linux y Windows.
Java J2SE 1.4 (incluida en el libro y en el CD)
Las aportaciones más interesantes se encuentran en la integración en el núcleo de la
plataforma de la posibilidad de trabajar con XML. estableciendo así los fundamen-
tos básicos para la creación y consumo de servicios Web. Existen mejoras en las
JFC (JCIVCIFoundation Cln.w.7) que afectan al rendimiento de las aplicaciones
cliente basadas en Si.~.ingy gráficos Java 2D. También contempla el uso de arqui-
tecturas de 64 bits y se ha mejorado la seguridad con la integración de una nueva
API compatible Kerberos.
Direcciones Web de interés profesional
Internet está plagada de direcciones de interés y excelentes relativas a Java. No obs-
tante. además de los recursos que incluimos en el Apéndice G (que aconsejamos
Prólogo xix
visite gradualmente) le daremos unas direcciones de gran interés sobre todo para
descargar software y documentación actualizada.
http://~ava.sur~..com/j~se
h t t p : / / l d v a . s u n . c n m / ! Z s e / l . 3
h t t p : / / ! a v a . s u n . _ o m / 7 2 s e / 1 . 4 /
h t t p : / / j a v a . c u n . c o r r / j 2 c e / l . 3 / d o c s / .
n t t p : / / j a v a . c ~ ~ n . c o - / j ~ s e / l . 4 / d o e s /
kttp:/ / j a v a . c ¿ n . - c m / i : r ~ - i * ~ t s / p ~ . ~ g i n / l.3.
ir.dex, h t m l
h t t p : / / ] a v a . s u n . c o m / j ~ s ~ / l . 4 / ~ ~ ~ ~ / ~ ~ ~ ~ ~ /
p l u g i n / i n c i e x . h:il
-tto://]ava.sun.com/j2me
Platufornici Jnvtr 2, Srundurtl
Edition I:I .4
P1rrtufi)rmci Jaiw 2 Micro Ecli-
tion, J2ME (.ri.rtemci.r.inaldm-
17rico.r)
Como motor de búsqueda le recomendamos Google (www.g o o g l e . corn) ,
Altavista (www.alt a v i s t a . corn) o Ask (www.ask.corn),aunque
si está acostumbrado a otros buscadores (tales como los incluidos en Terra, Ya.
StarMedia, Excite...) es recomendable que haga pruebas prácticas para ver si real-
mente le puede ser ventajoso realizar el cambio.
EL LIBRO COMO HERRAMIENTA DIDÁCTICA
La obra J a ~ m2. Mutiid de progrumacicín ha sido diseñada y escrita pensando en
personas que desean iniciarse en el mundo de la programación de Java tanto para
desarrollo de aplicaciones como para desarrollo de upplets. Tiene como objetivo
primordial enseñar a programar en Java para entornos abiertos y entornos de
Internet en niveles de iniciación y medios. Si bien es un libro pensado en el profe-
sional y en el estudiante autodidacto, la experiencia docente de los autores se ha
volcado en el libro tratando de conseguir una obra didáctica que pueda servir no
sólo para su uso en cursos profesionales, sino en cursos de enseñanzas regladas
tales como los módulos formativos de ciclo superior de la formación profesional y
en los primeros semestres de estudios universitarios de ingeniería y ciencias. Se ha
buscado que el libro fuera autosuficiente, aunque el rendimiento mayor del libro se
xx Prólogo
conseguirá cuando el lector tenga una formación mínima de fundamentos de teoría
de progranmación. Conocimientos de otros lengua.jes de programación. fundamen-
talmente estilo C/C++. ayudará considerablemente al aprendizaje gradual no sólo
en el tiempo sino en el avance de contenidos.
Por todo ello. pensamos que el libro puede servir. además de aprendimje auto-
didacto. para cursos de introducción a la programación/prograninción en Java de un
semestre de duración o cursos profesionales de unas 30-40 horas que y a posean
experiencia en otros lengua-jesde programación.
CONTENIDO
Siempre que Sun lanza una nueva versión de Java hace un kit de desarrollo gratis
que pone disponible en su Web para soportar a dicha versión. Este libro se ha
creado utilizando el kit que se denomina Java 2 Software Development Kit,
Standard Edition, Versión 1.3 (JDK 1.3).Tras lanzar Sun la versión 1.4 beta, se
han probado todas las aplicaciones y applefs con esta nueva versión (JDK 1.4).
Así mismo, se han actualizado los paquetes de la plataforma Java 2 para incluir
ambas versiones y el contenido del CD ad.junto al libro que incluye dichas versio-
nes para los entornos Windows y Linux. El libro consta de quince capítiilos y siete
apéndices (A-G). Un breve contenido de los capítulos y apéndices se reseña a con-
tinuación:
Capítulo 1. Introducción CI JLiva. En este capítulo se realiza una descripción de
la historia de Java junto a una breve descripción de las características más notables.
Se describe el concepto de aplicación y de uppler y los métodos para crear un
programa Java. Sun tiene disponible en su página Web (www.sun.com) el Kit de
Desarrollo necesario para la compilación y ejecución de programas denominado
JDK (Jui’u Development Kif)y en este capítulo se explica este entorno de desarro-
llo, así como los errores típicos que se producen en la fase depuración y puesta a
punto de programas por parte del usuario.
Capítulo 2. Caructeri~ricusdel lenguaje Javu. Todo lenguaje de programación.
y Java no es una excepción, dispone de un conjunto de elementos básicos que cons-
tituyen su núcleo fundamental para la escritura de programas. En el capítulo se des-
criben: palabras reservadas. identificadores, tipos de datos. variables, constantes y
operadores. así como una breve introducción a las clases y bibliotecas de clases de
Java.
Capítulo 3. Decisiorzes y bucles. Los programas requieren siempre de sentencias
y estructuras de control para seguir la secuencia de e.jecución de sus instrucciones.
La ejecución secuencia1 de un programa requiere de modo continuo una toma de
decisiones e iteraciones o repeticiones: para ello, se utilizan sentencias de decisión
y de iteración para realizar los bucles o repeticiones de acciones. Se describen
Prólogo xxi
las sentencias básicas: i f , ef-else, f o r , while, do-while, break y
continue.
Capítulo 4. C1usr.s. ohjrro.s y inPtodos. El concepto de clase y de objeto como
instancia o e.jemplar de una clase se analizan con el apoyo de la sintaxis utilizada
para SLI escritura.
Capítulo 5. Herencicr. Una de las propiedades fundamentales del concepto de
orientación a objetos es la herencia. Se explica el concepto, así como el método de
implementar en Java dicha propiedad y sus ventajas e inconvenientes.
Capítulo 6. Eiic~rrp,sirlcin~ieiitoy polinzorflsmo. Otras dos propiedades fundamen-
tales de la orientación a objetos son el encapsulamiento de la información y el con-
cepto de polimorfismo. Ambas propiedades. los métodos y sintaxis se describen en
este capítulo.
Capítulo 7. Arruys. La información básica manejada por los programas se or-
ganiza en estructuras de datos. Se describe el array como representante genuino de
listas. tablas o vectores. así como métodos para ordenar estas estructuras de infor-
mación y realizar búsqueda de información en las mismas.
Capítulo 8. Cadenus y,fechus. El concepto de cadena como secuencia o lista de
caracteres y las clases específicas necesarias para su manipulación se analizan en este
capítulo. También se considera el concepto casi siempre necesario en un programa
del tratamiento de las fechas como elementos básicos de medición del tiempo.
Capítulo 9. iizterfilces ,qrcíficn.sde usuario. Una de las grandes virtudes de los
lenguajes de programación actuales, y Java en particular, es la facilidad que ofrece
al usuario para construir interfaces gráficas sencillas y adaptadas al entorno de tra-
bajo.
Capítulo 10. Gestión cíc eventos. La programación mediante eventos o sucesos
es otra de las características sobresalientes que aporta Java al mundo de la progra-
mación. El concepto y los tipos de eventos así como métodos para su gestión y
manipulación se describen en este capítulo.
Capítulo 11. Applers. Los programas conocidos como applets son, sin género de
dudas. el puente ideal para la conexión con el mundo Internet y una de las propie-
dades de Java que lo han hecho tan popular. Una breve introducción al lenguaje
HTML y el modo de realizar applrts son la base del capítulo.
Capítulo 12. Programucion concurrente: Hilos de ejecución. Otra propiedad
fundamental de Java como lenguaje de tiempo real es la posibilidad de manejar pro-
cesos en paralelo. El concepto de hilo (thread),su manipulación e implementación
se analizan en este capítulo.
Capítulo 13. Manqjo dr excepciones. El concepto de excepciones es vital en la
programación moderna. Lenguajes como Ada y C++ lo incorporaron a su sintaxis,
y Java, siguiendo los pasos de estos dos potentes lenguajes, ha incluido el trata-
miento de excepciones en sus compiladores.
Capítulo 14.Archivos. Las estructuras de datos organizados en torno a archivos
o ficheros son pieza fundamental en el proceso de información de cualquier orga-
xxii Contenido
nización. Su organización. diseño y construcción constituyen el contenido funda-
mental de este capítulo.
Capítulo 15. E.struc~tirrn.sde cirrtos defliiicíti.spor 01 progrtrniudor: Una vez que el
programador sabe mane.jar estructuras de datos básicas como arrays y archivos, sen-
tirá la necesidad con relativa frecuencia de utilizar estructuras de datos dinámicas
tales como listas, pilas y colas. Su concepto y métodos de iinplementación se expli-
can en este último capítulo.
En los apéndices. se incluyen herramientas de trabajo complementarias para el
programador tales como: Lisrndo de pa1cihrci.s r-eservad(is Juvci (A); fiihla de prio-
riúud de operadores (B);Guía de sintaxis de JLILYI2, que facilita la consulta al lec-
tor en la fase de escritura y depuración de prograinas (C);Paquetes de la platuforma
Jain 3 más utilizados e incluidos en las versiones de 1.3.1 y 1.4 de los kit de desa-
rrollo JDK (0);Una conzpuracicín eritw l o s 1rnguuje.s de progr-armickjn orientados
ci ohjetos mrís p o p l ~ i r e sen la uctucilidd: C++ y Java ( E ) ;Coriteriido del CD como
elemento de ayuda en el aprendizaje y formación en Java para el lector y herra-
mienta de software complementaria para cursos y seminarios en laboratorios de
programación (F);Recursos de Juiu: libros, revistas y sitios Web de interés.
CD QUE ACOMPAÑA AL LIBRO
El disco compacto que se adjunta en las tapas de este libro contiene la versión
Java 2 y el kit de desarrollo JDK de Sun versiones 1.3.1 y 1.4 para entornos
Windows y Linux. Así mismo, se han incluido todas las aplicaciones y applets
sobresalientes incluidos en el libro con el ob-jetivofundamental de ayudarle en el
proceso de compilación y ejecución.
AGRADECIMIENTOS
Como ya hemos indicado anteriormente, no podemos terminar este prólogo sin
expresar nuestra gratitud a todo el equipo de Sun Microsystems en Palo Alto (Ca-
lifornia), su disponibilidad y efectividad a la hora de resolver cualquier consulta ha
resultado una inestimable ayuda en el desarrollo de esta obra. Evidentemente com-
portamientos profesionales como &tos son algunos de los millones de razones para
usar Java. Así pues, reiteramos nuestro agradecimiento a Sun Microsystems y en
particular a los ingenieros:
Andrew Bennett
Engineering Manager. Sun Microsystems. Inc.
CONTENIDO
1. I . La historia de Java.
1.2. ‘Qué es Java?
1.3. Características de Java.
1.4.
1.5. Especificaciones del lenguaje Java.
1.6. Aplicaciones y applets.
1.7. Creación de programas.
1.8. Componentes de una aplicación.
1.9. Herramientas de desarrollo Java.
1.I O. Una aplicación práctica de Java.
1.I I . Estructura de un programa aplicación en Java.
1.I 2. Errores de programación.
La programación orientada a objetos como base
de Java.
m 1
2 Java 2. Manual de programación
Este capítulo introduce al lector en el mundo de Java, su fortaleza
y sus debilidades. Describe la programación en Java y por qué es
diferente de la programación en cualquier otro lenguaje, así como
las ventajas que estas diferencias pueden representar en la crea-
ción de aplicaciones nuevas y eficientes.
El futuro de la computación está influenciado por Internet y
Java es una parte importante de ese futuro. Java es el lenguaje de
programación de lnternet y es una plataforma cruzada, orientada
a objetos, usada en la Red y preparada para multimedia. Desde su
nacimiento real en 1995, Java se ha convertido en un .lenguaje
maduro para el desarrollo de aplicaciones críticas y eficientes.
Este capítulo comienza con una breve historia de Java y sus carac-
terísticas más sobresalientes, así como ejemplos sencillos de apli-
caciones y el concepto de applefs Java.
1.1. LA HISTORIA DE JAVA
Java no fue creado originalmente para la red internet. Sun Microsystems comenzó a
desarrollarlo con el objetivo de crear un lenguaje, independiente de la plataforma y
del sistema operativo, para el desarrollo de electrónica de consumo (dispositivos
electrónicos inteligentes, como televisores, vídeos, equipos de música, etc.).
El proyecto original, denominado Green comenzó apoyándose en C++, pero a
medida que se progresaba en su desarrollo el equipo creador de <<Green»comenzó
a encontrarse con dificultades, especialmente deportahilidad. Para evitar estas difi-
cultades, decidieron desarrollar su propio lenguaje y en agosto de 1991 nació un
nuevo lenguaje orientado a objetos. Este lenguaje fue bautizado con el nombre de
Oak. En 1993, el proyecto Green se volvió a renombrar y pasó a llamarse First
Penon Juc. Sun invirtió un gran presupuesto y esfuerzo humano para intentar ven-
der esta tecnología, hardware y software, sin gran éxito.
A mitad de 1993, se lanzó Mosaic, el primer navegador para la Web y comenzó a
crecer el interés por Internet (y en particular por la World Wide Web). Entonces, se
rediseñó el lenguaje para desarrollar aplicaciones para internet y, en enero de 1995,
Oak se convirtió en Java. Sun lanzó el entorno JDK 1.O en 1996, primera versión del
kit de desarrollo de dominio público, que se convirtió en la primera especificación for-
mal de la plataforma Java. Desde entonces se han lanzado diferentes versiones, aun-
que la primera comercial se denominó JDK 1.1 y se lanzó a principios de 1997.
Introducción a Java 3
En diciembre de 1998 Sun lanzó la plataforma Java 2 (que se conoció como JDK
1.2 durante su fase de pruebas beta). Esta versión de Java ya representó la madurez
de la plataforma Java. Sun renombró Java 1.2 como Java 2.
El paquete de Java que se utiliza en esta obra, incluye el compilador Java y otras
utilidades, se denomina oficialmente Java 2 JDK, versión 1.3.
Los programas Java se pueden incluir (((embeber))o ((empotrar)))en páginas
HTML y descargarse por navegadores Web para llevar animaciones e interacciones
a los clientes Web. Sin embargo, la potencia de Java no se limita a aplicaciones
Web, Java es un lenguaje de programación de propósito general que posee carac-
terísticas completas para programación de aplicaciones independientes o autóno-
mas. Java, como lenguaje, es fundamentalmente orientado a objetos. Se diseñó
desde sus orígenes como verdadero lenguaje orientado a objetos, al contrario que
otros lenguajes, como C++ y Ada, que tienen propiedades de lenguajes procedi-
mentales. La programación orientada a objetos (POO) es también, actualmente, un
enfoque de programación muy popular que está reemplazando poco a poco a las téc-
nicas tradicionales de programación procedimental o estructurada.
La última versión lanzada por Sun es Java 2 JDK 1.4 Beta. En la dirección
www .s u n . corn se pueden encontrar todas las versiones para Windows9x,
Windows 2000/NT, UNIX, Unix (Solaris), Macintosh,...
1.2. ¿QUÉ ES JAVA?
El significado de Java tal y como se le conoce en la actualidad es el de un len-
guaje de programación y un entorno para ejecución de programas escritos en el
lenguaje Java.AI contrario que los compiladores tradicionales, que convierten el códi-
go fuente en instrucciones a nivel de máquina, el compilador Java traduce el
código fuente Java en instrucciones que son interpretadas por la Máquina Virtual
Java (JVM, Java Virtual Machine). A diferencia de los lenguajes C y C++ en los
que está inspirado, Java es un lenguaje interpretado.
Aunque hoy en día Java es por excelencia el lenguaje de programación para
Internet y la World Wide Web en particular, Java no comenzó como proyecto
Internet y por esta circunstancia es idóneo para tareas de programación de pro-
pósito general y, de hecho, muchas de las herramientas Java están escritas en
Java.
1.2.1. Java como lenguaje de Internet
Java es un lenguaje para programar en Internet que trata de resolver dos problemas
claves con el contenido de Internet:
4 Java 2. Manual de programación
Computadora local
Sistema operativo
Navegador Java
Máquinavirtual
Java
En la actualidad, el contenido de la WWW es pasivo y estático.
La entrega (Deliverry) del contenido WWW es dependiente de la configura-
ción de cada navegador Web de usuario.
Computadoraservidor
(host)
Código
fuente Java
.Código fuente
En el mundo de la Web, Java es una tecnología facilitadora que permite a los
desarrolladores crear páginas Web que se entregarán de modo consistente a todos
los usuarios con un navegador habilitado para Java y con independencia de la pla-
taforma hardware y el sistema operativo que se esté utilizando'. Dado que el códi-
go fuente se interpreta, si existe un intérprete Java para una plataforma específica
hardware o sistema operativo, se pueden escribir programas con el conocimiento de
que serán útiles en esa plataforma.
La Figura 1.1 muestra cómo el código fuente Java se transfiere en Internet. En
la computadora servidor (host)se almacena el código fuente. Cuando un usuario de
una computadora local se conecta con el servidor a través de Internet mediante un
navegador habilitado para Java, el código fuente se transfiere de la computadora
servidor a la computadora local.
1.2.2. Java como lenguaje de propósito general
A medida que Java se populariza en desarrollos de Internet, gana también como len-
guaje de propósito general. Java es totalmente portable a gran variedad de platafor-
mas hardware y sistemas operativos.
Java tiene muchos conceptos de sintaxis de C y C++, especialmente de C++, del
que es un lenguaje derivado. Añade a C++ propiedades de gestión automática de
memoria y soporte a nivel de lenguaje para aplicaciones multihilo. Por otra parte,
Java, en principio a nivel medio, es más fácil de aprender y más fácil de utilizar que
C++ ya que las características más complejas de C++ han sido eliminadas de Java:
herencia múltiple, punteros (apuntadores) y sentencia g o to entre otras.
' En Cohn et al., Java. DeveloperS Reference, Indianapolis: Sams Net. 1996. se describen las caracte-
rísticas fundamentales del lenguaje Java original.
Introducción a Java 5
Las iinpleinentaciones de la Máquina Virtual Java pueden ser muy eficaces y eso
hace posible que los programas Java se ejecuten tan rápidamente como los programas
C++. Esta característica clave de Java, unida a sus fortalezas como lenguaje de Internet,
lo hacen muy adecuado para desarrollos en sistemas clienteiservidor, soporte masivo
de los sistemas informáticos de la mayoría de las empresas y organizaciones.
Las propiedades que se verán más adelante hacen a Java doblemente idóneo para
desarrollos cliente/servidor y para desarrollos de Internet.
1.3. CARACTERISTICAS DE JAVA
Java ha conseguido una enorme popularidad. Su rápida difusión e implantación en el
mundo de la programación en Internet y fuera de línea (offline)ha sido posible gra-
cias a sus importantes características. Los creadores de Java escribieron un artículo,
ya clásico, en el que definían al lenguaje como sencillo, orientado a objetos, distri-
buido, interpretado, robusto, seguro, arquitectura neutra, alto rendimiento, multihilo
y dinámico. Analicemos más detenidamente cada característica.
1.3.1. Sencillo
Los lenguajes de programación orientados a objetos no son sencillos ni fáciles de
utilizar, pero Java es un poco más fácil que el popular C++*,lenguaje de desarrollo
de software más popular hasta la implantación de Java.
Java ha simplificado la programación en C++, añadiendo características funda-
mentales de C++ y eliminando alguna de las características que hacen a C++ un len-
guaje difícil y complicado.
Java es simple porque consta sólo de tres tipos de datos primitivos: números,
boolean y arrays. Todo en Java es una clase. Por ejemplo, las cadenas son objetos
verdaderos y no arrays de caracteres. Otros conceptos que hacen la programación
en C++ más complicada son los punteros y la herencia múltiple. Java elimina los
punteros y reemplaza la herencia múltiple de C++ con una estructura única deno-
minada interfaz ( i nter face).
Java utiliza asignación y recolección automática de basura (garbage collection),
aunque C++ requiere al programador la asignación de memoria y recolección de
basura.
Otra característica importante es que la elegante sintaxis de Java hace más fácil
la escritura de programas.
En C++. Inicicición y Refereiicia (McCraw-Hill, 1999).de Luis Joyanes y Héctor Castán, podrá encon-
trar una guía de iniciación con enfoque similar a esta obra. si usted necesita iniciarse en C++.
6 Java 2. Manual de programación
1.3.2. Orientado a objetos
La programación orientada a objetos modela el inundo real, cualquier cosa del
inundo puede ser inodelada cotno un ob-jeto.Así una circunferencia es un objeto, un
autoiii¿hiI es un &jeto, una ventana es un objeto, un libro cs un ob.jeto e incluso un
préstamo o una tarjeta de crédito son objetos. Un prograina Java se denomina oricii-
ttrtio LI oi?jc'/o.s debido a que la programación en Java se centra en la creación, mani-
pulación y coiistruccih de objetos.
Un objeto tiene p i ~ ) p i ~ & ~ i c ~ , s(un estado) y un coniportainieiito. Las propiedades
o el estado se detinen iitilinndo datos y el coinportainiento se define utilizando
métodos. Los ob-jetos sc detitien utilizando clases en Java. Una clase es similar a
una plantilla para construir objetos. Con la excepcicín de los tipos de datos primiti-
os. todo en Ja.a es uti ob.jeto. En Java, al contrario de lo que sucede en C++, no
hay fuiicioiies globales: todas las iiinciones se in,ocan a tra,Cs de tin objeto.
Por e-jeinplo, se puede definir un objeto c u a d r a d o mediante una clase
c u a d r a d o (Fig. l.2), con un l a d o (propiedad) y caliularSuperficie
como el mt.todo qiie encuentre o calcule la superficie del cuadrado.
Clase
Instanoar I I d d T í 1 lnstanciar
cuadrado
de lado 1O
cuadrado
de lado25
Figura 1.2. Dos objetos , ~ dlrCricde lados 10 y 25
Se crean a partir de la clase r, i a j r ~ i
Un objeto es una realización concreta de una descripción de una clase. El pro-
ceso de creacicín de objetos se denomina ii~7~f~1~1~.i~rc,iÓi?(crear instancias) de una
clase.
AI iiufcrwitn. una clase. se crean objetos. Así. es posible crear un objeto c u a -
d r a d ~instaiiciando la clase con un lado determinado. por ejemplo se puede crear
un cuadrado de lado I O y otro cuadrado de lado 25. Se puede encontrar cl área de
los respecti os cuadrados usando el inktodo c a l c u l a r S u p e r fLcie.
Uti programa consta de una o más clases que se disponen en una jerarquía en
modo árbol, de modo qiie una clase hija puede heredar propiedades y comporta-
mientos de su clase padrc (ascendente). Java con un conjunto de clases pre-
dctinidas, agrupadas en paquetes que se pueden utilizar en los programas,
Introducción a Java 7
La programación orientada a objetos proporciona mayor flexibilidad, modulari-
dad y reusabilidad. En la actualidad está ya muy implantado este tipo de programa-
ción y Java se convertirá en breve plazo en uno de los lenguajes más usados de
propósito general.
1.3.3. Distribuido
La computación distribuida implica que varias computadoras trabajan juntas en la
red. Java ha sido diseñado para facilitar la construcción de aplicaciones distribuidas
mediante una colección de clases para uso en aplicaciones en red. La capacidad de
red está incorporada a Java. La escritura de programas en red es similar a enviar y
recibir datos a y desde un archivo. La utilización de una URL (Uniform Resource
Locator) de Java puede hacer que una aplicación acceda fácilmente a un servidor
remoto.
1.3.4. Interpretado
Java es interpretado y se necesita un intérprete para ejecutar programas Java. Los
programas se compilan en una Máquina Virtual Java generándose un código inter-
medio denominado bytecode. El bytecode es independiente de la máquina y se
puede ejecutar en cualquier máquina que tenga un intérprete Java.
Normalmente, un cornpilador traduce un programa en un lenguaje de alto nivel
a código máquina. El código sólo se puede ejecutar en la máquina nativa. Si se eje-
cuta el programa en otras máquinas, éste ha de ser recompilado. Así por ejemplo,
cuando un programa escrito en C++ se compila en Windows, el código ejecutable
generado por el compilador sólo se puede ejecutar en una plataforma Windows. En
el caso de Java, se compila el código fuente una sola vez y el bytecode generado por
el compilador Java se puede ejecutar en cualquier plataforma.
Nota: Los programas Java no necesitan ser recompilados en una máquina des-
tino. Se compilan en un lenguaje ensamblador para una máquina imaginaria,
denominada máquina virtual.
Sin embargo, los intérpretes Java tienen una seria desventaja sobre los sistemas
convencionales. Son, normalmente, mucho más lentos en ejecución. Innovaciones
recientes en el mundo Java han avanzado sobre las ideas de los intérpretes y han
aparecido compiladores JIT (just-in-time) que leen la representación en bytecode
independiente de la máquina de un programa Java, e inmediatamente antes de que
8 Java 2. Manual de programación
la ejecución traduzca la representación en b-ytecode en instrucciones de la máquina
real del sistema en el que el programa Java se está ejecutando. Dado que los progra-
mas Java se ejecutan a continuación como instrucciones máquina, pueden ser casi
tan rápidos como programas compilados en lenguajes más convencionales para pla-
taformas de hardware específicas y mantener la portabilidad de la máquina virtual.
1.3.5. Robusto
Robusto significa fiable. Ningún lenguaje puede asegurar fiabilidad completa. Java se
ha escrito pensando en la verificación de posibles errores y por ello como un lenguaje
fuertementetipificado (con tipos). Java ha eliminado ciertos tipos de construcciones de
programación presentes en otros lenguajes que son propensas a errores. No soporta,
por ejemplo, punteros (apuntadores) y tiene una característica de manejo de excepcio-
nes en tiempo de ejecución para proporcionar robustez en la programación.
Regla: Java utiliza recolección de basura en tiempo de ejecución en vez de
liberación explícita de memoria. En lenguajes como C++ es necesario borrar
o liberar memoria una vez que el programa ha terminado.
1.3.6. Seguro
Java, como lenguaje de programación para Internet, se utiliza en un entorno distri-
buido y en red. Se puede descargar un applet Java y ejecutarlo en su computadora
sin que se produzcan daños en su sistema, ya que Java implementa diversos meca-
nismos de seguridad para proteger su sistema de daños provocados por un progra-
ma stray. La seguridad se basa en la premisa de que nada debe ser trusted.
Naturalmente la seguridad absoluta no existe, pero, aunque se encuentran pro-
blemas de seguridad en Java, éstos no son lo suficientemente notables como para
producir trastornos apreciables.
Nota: Existen numerosos sitios en la Red para información sobre seguridad de
computadoras. Este sitio
de la universidad de Princeton (allí impartió clase el físico universal Einstein)
es excelente para estudiar problemas de seguridad informática, especialmente
para Java, ActiveX y JavaScript.
www.cs.princeton.edu/sip/.
Introducción a Java 9
1.3.7. Arquitectura neutral
Una de las características más notables de Java es que es de arquitectura neutral,
lo que también se define como independiente de la plataforma. Se puede escribir
un programa que se ejecute en cualquier plataforma con una Máquina Virtual
Java.
Se pueden ejecutar applets de Java en un navegador Web; pero Java es algo más
que escribir upplets de Java, ya que se pueden también ejecutar aplicaciones Java
autónomas (stand-alone)directamente en sistemas operativos que utilicen un intér-
prete Java.
I I
Importante: Utilizando Java, los desarrolladores necesitan escribir una Única
versión para ejecutarse en todas las plataformas, dado que los bytecodes no se
corresponden a ninguna máquina específica y trabajan en todas las máquinas.
Comentario: Un programa Java es el mismo si se ejecuta en un PC, un
Macintosh, o un sistema Unix. Es distinto de los lenguajes convencionales
tales como C/C++
1.3.8. Portable
Java es un lenguaje de alto nivel que permite escribir tanto programas convencio-
nales como aplicaciones para Internet (applets). Dado que Internet es una red for-
mada por equipos muy diferentes interconectados por todo el mundo, resulta
fundamental para los programas que rueden en ella su independencia de la plata-
forma en la que van a ser ejecutados. Dicha independencia se obtiene en Java gra-
cias a que el compilador Java genera un código intermedio, bytecode (código byte),
no ejecutable por sí mismo en ninguna plataforma, pero que puede ser ejecutado a
gran velocidad mediante un intérprete incorporado en la máquina virtual Java. En
las diferentes plataformas existirán máquinas virtuales específicas, y cuando el
código byte llegue a esas máquinas virtuales será interpretado pasándolo al código
adecuado para la computadora receptor de la aplicación. Las máquinas virtuales Java
son programas capaces, entre otras cosas, de interpretar el código byte, que pueden
venir incluidos en los navegadores, proporcionados con el sistema operativo, con el
entorno Java o bien obtenerse a través de Internet (mediante descarga del corres-
pondiente programa). Por tanto, los programas Java pueden ejecutarse en cualquier
plataforma sin necesidad de ser recompilados; es decir, son muy portables.
10 Java 2. Manual de programación
Pero la portabilidad de Java aún va más allá; Java fue diseñado de modo que
pueda ser transferido a nuekas arquitecturas.
En Java todos los tipos de datos primitivos son de tamaños definidos con inde-
pendencia de la máquina o sistema operativo en el que se ejecute el programa. Esta
característica es distinta de C o C++, en los que el tamaño de los tipos dependerá
del coinpilador y del sistema operativo.
Nota: El tamaño fijo de los números hace el programa portable.
I I
Regla: El entorno Java es portable a nuevos sistemas operativos y hardware.
El compilador Java está escrito en Java.
1 I
1.3.9. Alto rendimiento
Los coinpiladores de Java han ido mejorando sus prestaciones en las sucesivas
!ersiones. Los nuevos compiladores conocidos como JlT @st-in-tirvze) permiten
que prograinas Java independientes de la plataforma se ejecuten con casi el
mismo rendimiento en tiempo de ejecución que los lenguajes convencionales
coinpi1ados.
1.3.10. Multíhilo
Java es uno de los primeros lenguajes que se han diseñado explícitamente para tener
la posibilidad de múltiples hilos de ejecución; es decir, Java es multihilo (multith-
reudit7g).Multihilo es la capacidad de un programa de ejecutar varias tareas simul-
táneamente. Por ejemplo, la descarga de un archivo de vídeo mientras se graba el
vídeo. La Programación multihilo está integrada en Java. En otros lenguajes se tiene
que llamar a procedimientos específicos de sistemas operativos para permitir mul-
tihilo.
Los hilos sincronizados son muy Útiles en la creación de aplicaciones distribui-
das y en red. Por ejemplo, una aplicación puede comunicarse con un servidor remo-
to en un hilo, mientras que interactúa con un usuario en otro hilo diferente. Esta
propiedad es muy útil en programación de redes y de interfaces gráficas de usuario.
Un usuario de Internet puede oír una emisora de música mientras navega por una
página Web y un servidor puede servir a múltiples clientes al mismo tiempo.
introducción a Java 11
1.3.11. Dinámico
Como Java es interpretado, es un lenguaje muy dinámico. En tiempo de ejecución, el
entorno Java puede extenderse (ampliarse) mediante enlace en clases que pueden
estar localizadas en servidores remotos o en una red (por ejemplo, Intranet/Intemet).
Es una gran ventaja sobre lenguajes tradicionales como C++ que enlaza clases antes
del momento de la ejecución.
Se pueden añadir libremente nuevos métodos y propiedades a una clase sin afec-
tar a sus clientes. Por ejemplo, en la clase Cuadrado se pueden añadir nuevos
datos que indiquen el color del polígono y un nuevo método que calcule el períme-
tro del cuadrado. El programa cliente original que utiliza la clase Cuadrado per-
manece igual. En tiempo de ejecución, Java carga clases a medida que se necesitan.
1.4. LA PROGRAMACIÓN ORIENTADA A OBJETOS
COMO BASE DE JAVA
La programación orientada a objetos (POO) es la base de Java y constituye una nueva
forma de organización del conocimientoen la que las entidades centrales son los objetos.
En un objeto se unen una serie de datos con una relación lógica entre ellos, a los que se
denomina variables de instancia,con las rutinas necesarias para manipularlos,a las que
se denomina métodos. Los objetos se comunican unos con otros mediante interfaces bien
definidasa través depuso de mensajes;en PO0 los mensajes están asociados con méto-
dos, de forma que cuando un objeto recibe un mensaje, ejecuta el método asociado.
Cuando se escribe un programa utilizando programación orientada a objetos, no se
definen verdaderos objetos, sino clases; una clase es como una plantilla para construir
varios objetos con características similares. Los objetos se crean cuando se define una
variable de su clase. En las clases pueden existir unos métodos especiales denominados
constructores que se llaman siempre que se crea un objeto de esa clase y cuya misión
es iniciar el objeto. Los destructores son otros métodos especiales que pueden existir en
las clases y cuya misión es realizar cualquier tarea final que corresponda realizar en el
momento de destruir el objeto. Las propiedades fundamentales de los objetos son:
El encapsulamiento, que consiste en la combinación de los datos y las opera-
ciones que se pueden ejecutar sobre esos datos en un objeto, impidiendo usos
indebidos al forzar que el acceso a los datos se efectúe siempre a través de los
métodos del objeto. En Java, la base del encapsulamiento es la clase, donde se
define la estructura y el comportamiento que serán compartidos por el grupo
de objetos pertenecientes a la misma. Para hacer referencia a los componentes
accesibles de un objeto será necesario especificar su sintaxis:
nombreobjeto.nombreComponente.
12 Java 2. Manual de programación
La herencia es la capacidad para crear nuevas clases (descendientes) que se
construyen sobre otras existentes, permitiendo que éstas les transmitan sus pro-
piedades. En programación orientada a objetos, la reutilización de código se
efectúa creando una subclase que constituye una restricción o extensión de la
clase base, de la cual hereda sus propiedades.
El polimorjismo consigue que un mismo mensaje pueda actuar sobre diferen-
tes tipos de objetos y comportarse de modo distinto. El polimorfismo adquiere
su máxima expresión en la derivación o extensión de clases; es decir, cuando
se obtienen nuevas clases a partir de una ya existente mediante la propiedad de
derivación de clases o herencia.
1.5. ESPECIFICACIONES DEL LENGUAJE JAVA
Los lenguajes de computadoras tienen reglas estrictas de uso que deben seguirse cuan-
do se escriben programas con el objeto de ser comprendidos por la computadora. La
referencia completa del estándar Java se encuentra en el libro Java Languaje
Specification, de James Gosling, Prill Jorg y Grey Steele (Addison Wesley, 1996).
La especificación es una definición técnica del lenguaje que incluye sintaxis,
estructura y la interfaz de programación de aplicaciones (API, application pro-
gramming interfuce) que contiene clases predefinidas. El lenguaje evoluciona rápi-
damente y el mejor lugar para consultar las últimas versiones y actualizaciones del
mismo se encuentra en el sitio Web de internet de Sun
Las versiones de Java de Sun se incluyen en JDK (Java Deivlupment Kit), que
es un conjunto de tierramientas que incluyen un cornpilador, un intérprete, el entor-
no de ejecución Java, el lenguaje estándar Java y otras utilidades.
En la actualidad existen cuatro versiones JDK. Este libro es compatible con JDK
1.4 Beta, que es una mejora sustancial de las versiones anteriores JDK 1.O y JDK 1.1.
La nueva versión JDK 1.3 incluye un compilador JIT (jusf-in-time)para ejecutar el
código Java. El entorno JDK está disponible para Windows9Y98, Windows NT/2000
y Solaris, pero existen muchos entornos de desarrollo para Java: JBuilder de Borland,
Visual Age Windows de IBM, Visual J++ de Microsoft, Visual Café de Symantec, etc.
Nota: Todos los programas de este libro se pueden compilar y ejecutar en los
entornos JDK 1.2, JDK 1.3 y JDK 1.4 y deben poder trabajar con cualquier
herramienta de desarrollo que soporte las citadas versiones.
Introducción a Java 13
JDK consta de un conjunto de programas independientes cada uno de los cuales
se invoca desde una línea de órdenes. Las herramientas de desarrollo más impor-
tantes se pueden encontrar en los siguientes sitios de Internet:
Café de Symantec www.symantec.com
Sun Java Workshop www.javasof.com
Visual Age for Java by IBM
JFactory de Roge Wave www.rogewave.com
JBuilder de lmprise www.imprise.com
Visual J++ de Microsoft www.microsoft.com
Forte de Sun www.sun.com
www.ibm.com
Estas herramientas proporcionan un EíD (Entorno Integrado de Desarrollo) que
permite el rápido desarrollo de programas. Le recomendamos utilice herramientas
EID para desarrollo de programas y ejecute las tareas integradas en la interfaz grá-
fica de usuario, tales como: edición, compilación, construcción, depuración y
ayuda en linea.
1.6. APLICACIONES Y APPLETS
Los programas en Java se dividen en dos grandes categorías:aplicaciones y applets.
Las aplicaciones son programas autónomos independientes (standalone),tal como
cualquier programa escrito utilizando lenguajes de alto nivel, como C++, C, Ada,
etc.; las aplicaciones se pueden ejecutar en cualquier computadora con un intérpre-
te de Java y son ideales para desarrollo de software. Los applets son un tipo espe-
cial de programas Java que se pueden ejecutar directamente en un navegador Web
compatible Java; los applets son adecuados para desarrollar proyectos Web.
Los applets son programas que están incrustados, ((empotrados))(embedded)en
otro lenguaje; así cuando se utiliza Java en una página Web, el código Java se empo-
tra dentro del código HTML. Por el contrario, una aplicación es un programa Java
que no está incrustado en HTML ni en ningún otro lenguaje y puede ser ejecutado
de modo autónomo.
Naturalmente, a primera vista parece deducirse que las aplicaciones son más
grandes (y en principio más complejas) que los applets. Sin embargo, esto no es
necesariamente verdad.
1.6.1 Semejanzas y diferencias entre aplicaciones y applets
Una de las primeras preguntas que suele hacerse el programador principiante en
Java es: ;Cuándo debo utilizar una aplicación y cuándo un applet? La respuesta no
14 Java 2. Manual de programación
siempre es fácil, pero ineludiblemente pasa por conocer las semejanzas y diferen-
cias que tienen ambos tipos de programas. Gran parte del código de las aplicacio-
nes y los upplets es el mismo, presentándose las diferencias al considerar los
entornos de ejecución de los programas.
Regla:
Las aplicaciones se ejecutan como programas independientes o autónomos,
Los upplets deben ejecutarse en un navegador Web.
de modo similar a cualquier otro lenguaje de alto nivel.
El desarrollo de las aplicaciones Java suele ser algo más rápido de desarrollar
que los upplets, debido a que no necesita crear un archivo HTML y cargarlo en un
navegador Web para visualizar los resultados.
Sugerencia:Si su programa no necesita ejecutarse en un navegador Web, elija
crear aplicaciones.
Un aspecto muy importante en el desarrollo de programas es la seguridad. Los
upplets necesitan unas condiciones de seguridad para evitar daños en el sistema en
el que está funcionando el navegador, por tanto, tienen ciertas limitaciones. Algunas
limitaciones a considerar son:
Los applets no pueden leer o escribir en el sistema de archivos de la computa-
dora, pues en caso contrario podrían producir daños en archivos y propagar
virus.
Los upplets no pueden establecer conexiones entre la computadora de un usua-
rio y otra computadora, excepto que sea el servidor donde están almacenados
los applets'.
Los applets no pueden ejecutar programas de la computadora donde reside el
navegador, dado que podrían originar daños al sistema.
Por el contrario, las aplicaciones pueden interactuar directamente con la compu-
tadora sobre la que se ejecutan, sin las limitaciones anteriormente mencionadas.
Esta actividad comienza ya a desarrollarse con las tecnologías Napster creadas por Fanning, un estu-
diante norteamericano a primeros del año 2000. Otras tecnologías similares con Gnutella, Scour, etc., y se
las conoce de modo genérico como tecnologías P2P (peer-ro-peer).
Introducción a Java 15
Notas:
En general, se puede convertir un applet Java para ejecutarse como una apli-
Una aplicación no siempre se puede convertir para ejecutarse como un
cación sin pérdida de funcionalidad.
upplet, debido a las limitaciones de seguridad de los applets.
En este libro aprenderá fundamentalmente a escribir aplicaciones Java, aunque
también dedicaremos atención especial a desarrollar applets.
1.7. CREACIÓN DE PROGRAMAS
Antes de que una computadora pueda procesar un programa en un lenguaje de alto
nivel, el programador debe introducir el programa fuente en la computadora y la
computadora a su vez debe almacenarlo en un formato ejecutable en memoria. Las
etapas clásicas en un lenguaje tradicional son: edición, compilación, enlace, ejecu-
ción y depuración de un programa.
Las herramientas fundamentales empleadas en el proceso de creación de programas
son, por tanto: editor, compilador, depurador y, naturalmente, el sistema operativo.
El editor es un programa utilizado para crear, guardar (salvar o almacenar) y
corregir archivos fuente (escritos en lenguaje Java). El compilador es un programa
que traduce un programa escrito en un lenguaje de alto nivel a un lenguaje máqui-
na. El depurador es un programa que ayuda a localizar errores en otros programas.
El sistema operativo es el programa con el que interactúa el usuario con el objeto
de especificar qué programas de aplicación y/u operaciones del sistema debe ejecu-
tar la computadora (los sistemas operativos más utilizados son: Windows
9x/NT/2000, Linux, Unix, Solaris y Mac)'.
1.7.1 Etapas para crear un programa
La creación de un programa debe comenzar con la escritura del código fuente
correspondiente a la aplicación. Cada programa Java debe tener al menos una clase.
Un ejemplo de una aplicación Java sencilla que sirva de modelo es el popular
((Hola mundo)) de Stroustrup (el autor de C++), modificado para que visualice un
mensaje de bienvenida con el nombre de un pequeño pueblo andaluz.
' Microsoft ha anunciado el lanzamiento de la arquitectura .NETy el sistema operativo Windows XP para
el segundo trimestre de 200I .
16 Java 2. Manual de programación
//Esta aplicación visualiza: Hola Carchelejo. Bienvenido a Java
public class Bienvenido
I
public static void main (String[] argc)
t
Cyctem.out.println("Hola Carchelejo. Bienvenido a Java");
Las etapas que preparan un programa para su ejecución son:
1. Crear una carpeta de proyecto en la que se recojan todos los archivos signi-
ficativos, incluyendo clases que se desean incluir.
2. Utilizar un programa editor que introduzca cada línea del programa
fuente en memoria y lo guarde en la carpeta proyecto como un archivo
fuente.
3. Utilizar el programa compilador para traducir el programa fuente en byteco-
de (código en bytes). Si existen errores de sintaxis (un error gramatical de una
línea en un programa Java), el compilador visualiza esos errores en una ven-
tana.
4. Utilizar el programa editor para corregir esos errores, modificando y vol-
viendo a guardar el programa fuente. Cuando el programa fuente está
libre de errores, el compilador guarda su traducción en bytecode como un
archivo.
5 . El intérprete Java (JVM) traduce y ejecuta cada instrucción en bytecode.
6. Si el código no funciona correctamente se puede utilizar el depurador para
ejecutar el programa paso a paso y examinar el efecto de las instrucciones
individuales.
Edición
Editar el programa Bienvenido con un editor" escribiendo el texto correspon-
diente al programa fuente. Debe darle un nombre al archivo fuente que constituye
el programa (Bienvenido.j ava). Por convenio, el archivo del programa fuen-
te debe terminar con la extensión java.Almacene el programa en la carpeta
C :  jdkl.3 . O-02bin.
Los editores que se han utilizado en la preparación de este libro son Edit.com y Notepad.exe (se tra-
bajó bajo Windows 98).
Introducción a Java 17
Error típico: Palabras mal escritas: Java es sensible a las letras mayúsculas y
minúsculas y el siguiente programa daría error:
I
public class Bienvenido
I
public s t a t i c void Main (String[] args)
t
System.out .println("Hola Carchelejo. Bienvenido a Java");
pues main debe escribirse sólo en minúsculas.
y Los nombres de métodos y variables con una letra minúscula.
Los nombres de las clases comienzan normalmente con una letra mayúscula
Compilación
La orden siguiente compila Bienvenido.java:
javac Bienvenido.]ava
Si no existen errores de sintaxis, el compilador genera un archivo denominado
Bienvenido.class. El archivo no es un archivo objeto tal como se genera en
otros compiladores de lenguajes de alto nivel. Este archivo se llama bytecode. El
bytecode es similar a las instrucciones máquina, pero su arquitectura es neutral y se
puede ejecutar en cualquier plataforma que tenga el entorno en tiempo de ejecución
y el intérprete Java.
Nota: Una gran ventaja de Java es que el código bykcode puede ejecutarse en
diferentes plataformas hardware y sistemas operativos.
El cornpilador enlazará el archivo del código fuente en Java y objetos impor-
tados.
18 Java 2. Manual de programación
Archivo
fuente
Objetos
importados
1 Compilador 1
Figura 1.3. El código fuente de un programa se compila en bytecode.
Ejecución
Para ejecutar un programa Java, se debe ejecutar el bytecode del programa en cual-
quier plataforma que soporte un interprete Java. La siguiente orden ejecuta el códi-
go bytecode del programa aplicación Bienvenido.java:
java Bienvenido
La salida de este programa se muestra en la Figura 1.4.
Figura 1.4. La salida del programa Bienvenido.
1.8. COMPONENTES DE UNA APLICACIÓN
En un programa aplicación, destacan los siguientes elementos: Comentarios, 4
Palabras reservadas, Sentencias, Bloques, Clases, Métodos, el método main.
Comentarios
La primera línea del programa Bienvenido es un Comentario. Los
Comentarios sirven para documentar los programas y en ellos se escriben anota-
Introducción a Java 19
ciones sobre cómo funciona el programa o sobre cómo se ha construido. Los
comentarios ayudan a los programadores actuales y futuros o a los usuarios de los
mismos a comprender el programa. En Java, como en todos los lenguajes de pro-
gramación, los comentarios no son sentencias de programación y son, por consi-
guiente, ignorados por el cornpilador. En Java, los comentarios que constan de
una única línea están precedidos por dos barras inclinadas (/ /), si se extienden
sobre varias líneas están encerrados entre / * y * / . Cuando el compilador
encuentra un comentario del tipo / / ignora todo el texto que viene a continua-
ción hasta el final de línea, y cuando el compilador se encuentra con un comen-
tario de la forma / * y * / ignora todo el texto entre ambos juegos de caracteres.
Ejemplos de comentarios:
/ / Esto es un comentario relativo
/ * a l a S i e r r a de C a z o r l a , escrito
por Mackoy * /
Existen también otra clase de comentarios, denominados comentarios de docu-
rnentacion, que pueden ser extraídos a archivos HTML utilizandojavadoc. Es nece-
sario introducirlos entre los símbolos / ** ...* /.
Palabras reservadas
Las palabras reservadas o palabras clave (Keywords) son palabras que tienen un
determinado significado para el compilador y no pueden ser utilizadas para otros
fines. Por ejemplo, la palabra while significa que se habrá de evaluar la expre-
sión que viene a continuación y, en función del valor de la misma, se ejecutarán
o no se ejecutarán las sentencias siguientes. Otras palabras reservadas son
p u b l i c , s t a t i c , p r i v a t e , que representan modificadores. Otro ejemplo es
c l a s s , una palabra reservada muy utilizada, que significa que la palabra que
viene a continuación es el nombre de la estructura clase. Las palabras reservadas
se resaltarán en los códigos fuente que aparecen en el libro escribiéndolas en
negrita.
Precaución: Java es sensible a las mayúsculas, por consiguiente, w h i l e es
una palabra reservada y While no es palabra reservada,
Sentencias
Una sentencia representa una acción o una secuencia de acciones. Cada sentencia
termina con un punto y coma (; ). Ejemplos de sentencias son:
20 Java 2. Manual de programación
z = 15;
z = z+10u;
//esta sentencia asigna 15 la
//a variable z
//esta sentencia añade 130
//ai valor de z
printlr.("Bienvenido Sr. Mackoy") ; //sentencia de visualización
Bloques
Un bloque es una estructura que agrupa sentencias. Los bloques comienzan con una
llave de apertura ( { ) y terminan con una llave se cierre ( } ). Un bloque puede estar
dentro de otro bloque y se dice que el bloque interior está anidado dentro del exte-
rior o que ambos bloques están anidados:
z = 15;
z = 2+100;
if (z > 225)
!
z = 2-5;
Clases
La clase es la construcción fundamental de Java y, como ya se ha comentado,
constituye una plantilla o modelo para fabricar objetos. Un programa consta de
una o más clases y cada una de ellas puede contener declaraciones de datos y
métodos.
Métodos
Un método es una colección de sentencias que realizan una serie de operaciones
determinadas. Por ejemplo:
System.out.println("Bienvenido a Carchelejo") ;
es un método que visualiza un mensaje en el monitor o consola.
Método ma i n ( I
Cada aplicación Java debe tener un método main declarado por el programador
que define dónde comienza el flujo del programa. El método m a i n tendrá siempre
una sintaxis similar a ésta:
Introducción a Java 21
public static void ma;? (Str-nq;: aras)
1.9. HERRAMIENTAS DE DESARROLLO JAVA
El JDK viene con un conjunto de herramientas tal como se comentó anteriormente:
un compilador Java íjavac), una Máquina Virtual Java íjava),una herramienta para
visualizar applets (appletViewer),un depurador elemental íjdb) y una herramienta
de documentación íjavadoc). Estas herramientas se utilizan para crear, depurar,
documentar y usar programas Java. Dependiendo de su entorno y su plataforma, los
detalles reales de cómo instalar JDK o cualquier conjunto de herramientas Java,
difieren de unos fabricantes a otros y lo más recomendable será seguir las instnic-
ciones que nos ofrezcan ellos.
Las herramientas de desarrollo más importantes se pueden encontrar en los sitios
de Internet declarados en el apartado ((Especificaciones del lenguaje Java)). Estas
herramientas proporcionan un entorno integrado de desarrollo, EID (IDE,
Integrated Development Environment) y sirven para proporcionar un desarrollo
rápido de programas de modo eficiente y productivo.
1.9.1. El entorno de desarrollo JDK
La creación de un programa en Java, ya sean applets o aplicaciones convenciona-
les, necesita la instalación de las herramientas de desarrollo de Java. El Kit de
Desarrollo de Java (JDK) es una donación de Sun Mycrosystem a la que podemos
acceder visitando el sitio que posee Sun en la Red. Como JDK es gratuito y las ver-
siones que se pueden bajar de la Red están actualizadas, es muy frecuente su uso
por los programadores, no obstante la existencia de los entornos de desarrollo inte-
grados que pretenden facilitar las tareas de edición, compilación, ejecución y depu-
ración, haciendo todas ellas directamente accesibles desde los mismos.
Para trabajar con JDK en Windows 95/98/NT, resulta cómodo y eficaz abrir
varias ventanas, y usarlas de la forma siguiente:
En una ventana abrirá un editor, como Edit o Notepad, donde se irá escribien-
do el código.
Otra ventana le será necesaria para tener acceso al indicador (prompt)del siste-
ma y poder invocar desde allí al compilador y a las demás herramientas del JDK.
En una tercera puede tener abierto un archivo con documentación sobre el API
de Java.
22 Java 2. Manual de programación
Puede usar una cuarta ventana para abrir un navegador con soporte Java, por
ejemplo 2ilicrosoft Explorer en versión 4.0 o superior, o el appletviewer para la
verificación del correcto funcionamiento de los applets.
1.lo. UNA APLICACIÓN PRÁCTICA DE JAVA
Inicialmente se expondrá la creación de programas convencionales, y para ver su
estructura básica así como las fases a las que antes aludíamos, necesarias para su
ejecución, seguiremos el siguiente ejemplo: Considere que trabaja con el JDK ins-
talado en un PC bajo Windows 9x y cree la carpeta libro en el directorio raíz de su
disco de arranque. Después, situándose dentro de libro, cree otra denominada
T2ri7aOl.
Abra una ventana DOS, trasládese a la carpeta Terna01 y llame al editor (Edit):
'L.-.  I d i ~ . d c w s > c0 C:;ibrotemaOl
i:libroTema31> e d i t
Una vez dentro de Edit copie el texto incluido en la Figura 1.5 fijándose atenta-
mente para no omitir en su copia ninguno de los caracteres ni signos de puntuación
que aparecen en él. AI terminar, guárdelo con el nombre E] emplol .java y salga
del editor.
iport j atJ3.ii3 .f< ;
' L u i s Joyaner &giJi 1ar Jl1a;s E j e r n p l c i f
n u t i l i t s t a t i c w i d main ( s t r i n g [ ] arg] {
) a programar en JAVA");
Figura 1.5.
El archivo creado es el archivo fuente, al que en Java también se le llama unidad
de cornpiltrcicín. Dicho archivo debe ser almacenado con el nombre E] emplol,ya
que en Java el código siempre ha de estar dentro de una clase y el nombre del archi-
vo debe coincidir con el de la clase que tiene el método m a i n ( ) . En el caso del
ejemplo no sería necesario considerar esta situación, ya que sólo hay una clase. El
archivo fuente debe escribirse dividido en secciones bien definidas, separadas por
Introducción a Java 23
líneas en blanco y precedidas por un comentario identificativo de las misinas. Es
importante guardar dicho archivo con la extensiónjava. Con estos pasos habrá ter-
minado la fase de edición del programa.
A continuación, el programa debe ser compilado, es decir, traducido a bytecode
(código byte), que es el lenguaje que entiende el intérprete de Java. Para compilar
un programa con el JDK hay que invocar ajavac y especificar el nombre del pro-
grama a compilar sin olvidar reflejar su extensión íjava).Ahora debe tener en cuen-
ta que para efectuar la compilación y ejecución de sus programas tal y como se
indica a continuación debe modificar la variable de entorno path, añadiendo al
p a t h anterior el subdirectorio o carpeta donde se encuentran los programas para
compilar, ejecutar depurar y documentar las aplicaciones (javac,,java,,jdhy,jaw-
doc respectivamente). Esta modificación deben introducirse en el archivo
C: au t oexec.ba t,para que los nuevos valores se establezcan cada vez que se
arranque la computadora.
SET PATH=%PATHL&;C:jdkl.3.1bin
o bien
SET PATH=OEATHcc;C:~dkl.4bin(para trabajar Con la 1.4 Beta)
Así mismo, es conveniente adaptar el contenido de c l a s s p a t h para que .lava
pueda localizar siempre lais claseis creadais.
SET CLASSEATH=.;C:
El valor asignado a CLASSPATH hace que Java busque las clases en la carpeta
actual y el directorio raíz. Suponiendo establecidos los anteriores valores para com-
pilar E jemplol .j ava bastaría la siguiente orden:
C:libroTemaOl> javac Ejernplol.java
Por último, será necesario llamar al intérprete de Java para que el programa con
extensión c l a s s surgido en la operación de compilación y que contiene el código
byte pueda ser ejecutado. Para ello, cuando se dispone del JDK, en la línea de órde-
nes o ventana de mandatos del sistema se escribirá la palabra j ava seguida por el
nombre del programa a ejecutar, sin especificar la extensión del mismo y teniendo
en cuenta que, si la clase pertenece a un paquete, el nombre de la misma debe ir pre-
cedido por el del paquete de la forma siguiente:
C:libroTemaOl> java libr=.TemaOl.ijemFlol
o bien.
C:WINDOWS> java libro.TemaOl.Ejemplo1
24 Java 2. Manual de programación
dado el valor establecido para la variable CLASSPATH,que hace que el intér-
prete de Java busque en el directorio raíz y a partir de ahí en aquellos cuyo nom-
bre coincida con los elementos del paquete C : libroTemaO1.Es decir, se
pasa como paráinetro ajava el nombre de la clase especificando el paquete al que
pertenece, sin incluir la extensión y distinguiendo entre mayúsculas y minúscu-
las. La salida obtenida con la ejecución del programa es la impresión en pantalla
de la línea
Ccrnienzo a programar en JAVA
Una breve explicación del código fuente escrito es la siguiente:
La primera instrucción sirve para indicar el paquete al que pertenecerá la clase
que está siendo definida. Los paquetes son un mecanismo para organizar las
clases. y cuando se declara que una clase pertenece a un paquete, dicha clase
deberá ser almacenada en un subdirectorio o carpeta cuyo nombre coincida con
lo especificado como nombre del paquete. En nuestro caso, como el paquete se
denomina 1ib ro .TemaO1,la clase E jemp1o1 deberá ser almacenada en la
carpeta 1ibroTemaO1.
La sentencia import va seguida por el nombre de un paquete y se utiliza para
poder referirse más adelante a clases pertenecientes a dicho paquete sin nece-
sidad de cualificarlas con un nombre de jerarquía de paquetes. En el ejemplo,
no existe aplicación posterior.
La tercera línea es un comentario (comentario de una línea)
La palabra reservada class permite especificar que se va a definir una
clase, una palabra clave o reservada es una palabra especial con un signifi-
cado preestablecido en el lenguaje Java. Para delimitar la clase, se emplean
llaves, { } .
Para ejecutar el programa, el intérprete de Java comienza llamando al méto-
do main ( ) ; como este método se llama antes de la creación de un objeto,
ha de declararse como static y así se le podrá llamar sin tener que refe-
rirse a una instancia particular de la clase; como además se llama por código
fuera de su clase también tiene que ser declarado como public,que es la
forma de permitir que un miembro de una clase pueda ser utilizado por códi-
go que está fuera de la misma. La palabra reservada void indica que main
no devuelve nada. String [ ] args es la declaración de un array de cade-
nas, mediante el que la clase podría tomar un número variable de parámetros
en la línea de comandos, aunque no se use es necesario incluir este paráme-
tro cuando se define el método main ( ). Se emplean llaves, { } ,para delimi-
tar cI nietodo.
* 0 !I .!>I ;I. la pantalla de la coinputadora es un objeto predefinido cuya referen-
1 . t. La clase System pertenece al paquete j ava.lang que" % , : , .
--se importa automáticamente y, por tanto, no necesita cualificación. El método
p r i n t I n ( ) toma la cadena que se le pasa como argumento y la escribe en la
salida estándar. Todas las sentencias en Java deben terminar en ;. Tenga en cuen-
ta que Java es sensible a las mayúsculas, por lo que considera distintos los identi-
ficadores si se cambian mayúsculas por minúsculas o viceversa, es decir, s y st e m
y System son identificadores diferentes.
. Cir,5*’
I .I I. ESTRUCTURA DE UN PROGRAMA APLICACI~N
EN JAVA
Para crear programas en Java hay que tener en cuenta que toda implementación
que se realice se efectuará encapsulada en una clase. Un programa aplicación fuen-
te en Java se podría considerar formado por las siguientes partes:
Una sentencia de paquete (package) que también puede ser omitida.
Una, ninguna o varias sentencias de importación (import).
Una serie de comentarios opcionales colocados en diversos lugares del pro-
Declaraciones de las clases privadas deseadas; puede no haber ninguna.
Una declaración de clase pública.
grama.
A su vez una declaración de clase comenzará con la sentencia c l a s s y podrá
contener:
Declaraciones de variables de la clase (estáticas).
Declaraciones de variables de instancia.
Definiciones de constructores.
Definiciones de métodos.
Dado que una clase es un modelo y las instancias son los objetos de esa clase, a
las variables de instancia se las denomina así porque cada objeto contendrá una
copia propia de dichas variables, de forma que los datos de un objeto se encontra-
rán separados de los de otro objeto, utilizándose los métodos para la modificación
de los valores de las variables de instancia. En consecuencia, un programa muy sen-
cillo que se puede crear en Java es:
public class EJ ernplo2
public static void main (Szring[l args)
26 Java 2. Manual de programación
formado exclusivamente por una declaración de clase pública
Compilación; javac Ejemplo2.java
Ejecución: java Ejemplo2
Las clases de un programa contienen métodos, interactúan entre sí y no necesi-
tan contener un método main ( ) ,pero éste sí será necesario en la clase que consti-
tuya el punto de partida del programa. Tenga también en cuenta que las applets no
utilizan el método main ( ) .
La declaración de métodos en una clase se puede efectuar en cualquier orden y
cada una de ellas se compone por una cabecera y un cuerpo. La cabecera del méto-
do debe contener su nombre, una lista de parámetros y el tipo de resultado. Se espe-
cificará void cuando el método no devuelva resultados. En la implementación del
método, cuando éste no haya sido declarado void, se utilizará la instrucción
return para devolver un valor al punto de llamada del método. La lista de pará-
metros consistirá en cero o más parámetros formales cada uno de ellos precedido
por su tipo y separados por comas. Cuando se llama a un método los parámetros
actuales se asignan a los parámetros formales correspondientes. Entre los paráme-
tros actuales (los de la llamada) y formales (los de la declaración) debe existir con-
cordancia en cuanto a número, tipo y orden. Formatos de métodos pueden ser los
siguientes:
Ejemplo
tipol nombre-funcion (lista de parámetros)
/ / declaración de variables
/ / sentencias ejecutables
/ / sentencia return con el valor a devolver
I
Ejemplo
void nombre-procedimien to (tipo4 nombre-par3, t i p o 5 nombre-par4)
i
/ / declaración de variables
/ / sentencias ejecutablec
I
En el primer ejemplo, t i p o1representa el tipo de dato devuelto por 'el méto-
do; cuando el método no devuelve ningún valor se especificará void como tipo
Introducción a Java 27
devuelto. La lista de parámetros es una secuencia de parejas tipo-identificador sepa-
radas por comas. Observe el formato expuesto en el segundo ejemplo.
En Java es posible agrupar sentencias simples, encerrándolas entre una pareja de
llaves para formar un bloque o sentencia compuesta; las variables declaradas den-
tro de un bloque sólo son válidas en dicho bloque y, si éste tuviera otros anidados,
en los interiores a él. En un programa Java se podrán declarar variables tanto den-
tro como fuera de los métodos. Las variables declaradas dentro del cuerpo de un
método se crean cuando se ejecuta el cuerpo del método y desaparecen después. Las
variables que se declaran fuera del cuerpo de un método son globales a la clase. Las
que se declaran como final y static son, en realidad, constantes.
1.1 1.I. Referencia a miembros de una clase
En los programas escritos en Java se hará referencia a los miembros de una clase,
métodos y variables de instancia, desde otras distintas de aquellas en las que fueron
definidos, para lo que generalmente será necesario declarar un objeto de la clase
adecuada y a continuación escribir nombreObje t o .nombreComponente.No
obstante, hay ocasiones en las que se utilizan métodos y variables de instancia sin
necesidad de efectuar la declaración de ningún tipo de objeto, especificando para su
llamada nombreclase.nombreComponente.Para que esto pueda ocurrir y a
un miembro de una clase sea posible llamarlo con el nombre de la clase en la que
ha sido declarado, sin tener que referirse a una instancia particular de la misma,
dicho miembro debe haber sido declarado static (estático).
1.I2. ERRORES DE PROGRAMACIÓN
Los errores de programación son inevitables, incluso para programadores experi-
mentados. El proceso de corregir un error (bug en inglés) se denomina depuración
(debugging)del programa. Cuando se detecta un error en Java, se visualiza un men-
saje de error que devuelve la posible causa del error. Desgraciadamente los errores
a veces no se detectan y los mensajes de error no son siempre fáciles de interpretar.
Existen tres tipos de errores: errores de compilación (sintaxis), errores de ejecución
y errores lógicos.
1.I2.1. Errores de compilación (sintaxis)
Los errores de sintaxis ocurren cuando el código viola una o más reglas gra-
maticales de Java. Los errores de sintaxis se detectan y visualizan por el com-
pilador cuando se intenta traducir el programa, por esta razón se denominan
28 Java 2. Manual de programación
también errores de compilación. Los errores de compilación provienen de erro-
res en la construcción del código tales como escribir mal una palabra reserva-
da, omitir algún signo de puntuación o bien utilizar, por ejemplo, una llave de
apertura sin su correspondiente llave de cierre. Estos errores suelen ser fáciles
de detectar ya que el compilador suele indicar dónde se producen las posibles
causas.
Ejemplo
La compilación del siguiente programa produce errores de sintaxis:
//este prograrra contiene errores de sintaxis
public class Demo
public static void main (String[] args)
z=50;
Cysten.out.println(z+lO) ;
La ejecución de este programa produce un error detectado por el compilador del
entorno JDK.
Figura 1.6. El compilador del JDK detecta un error de sintaxis.
El error de sintaxis es la no declaración previa de la variable z,que se utiliza en
dos sentencias.
Introducción a Java 29
Nota: Error de sintaxis:Es una violación de las reglas de gramática de Java,
detectada durante la traducción del programa.
1.I 2.2. Errores de ejecución
Los errores de ejecución son errores que producen una terminación anormal y que
se detectan y visualizan durante la ejecución del programa. Un error de ejecución
se produce cuando el usuario instruye a la computadora para que ejecute una ope-
ración no válida, tal como dividir un número por cero o manipular datos indefini-
dos o no válidos en la entrada.
Un error de entrcrdu ocurre cuando el usuario introduce un valor de entrada
imprevisto que el programa no puede manejar. Por ejemplo, si el programa espera
leer un número, pero el usuario introduce una cadena de caracteres. En Java, los
errores de entrada hay que declararlos en una cláusula throws o bien capturarlos
y tratarlos directamente dentro del método en el que se pueden producir (véase el
Capítulo 13, ((Manejo de excepciones))).
Ejemplo
public class ErrorDeE~ecucion
i
private static int z;
static void prueba0 ,
i
1
public static void rnain(Ctring[] args)
i
z=lO/z;
prueba ( ) ;
Figura 1.7. Error de ejecución.
30 Java 2. Manual de programación
AI invocar al método prueba ( ) , se produce un error en tiempo de ejecución:
java.1ang.ArithmeticException: / by zero
que indica un intento de dividir por cero (valor de z),operación no válida.
r I
Nota: Error de ejecución: Se intentó ejecutar una operación no válida que fue
detectada durante la ejecución del programa.
1.12.3. Errores lógicos
Los errores lógicos ocurren cuando un programa realiza un algoritmo incorrecto
y no ejecuta la operación que estaba prevista. Existen muchos tipos de razones
para que se produzcan errores lógicos. Normalmente los errores lógicos son difí-
ciles de detectar, ya que no producen errores en tiempo de ejecución y no visua-
lizan mensajes de error. El único síntoma de que se ha producido un error lógico
puede ser la salida incorrecta del programa. Se pueden detectar errores lógicos
comprobando el programa en su totalidad y comparando su salida con los resul-
tados calculados. La prevención de errores lógicos se puede realizar verificando
el algoritmo y el programa correspondiente antes de comenzar el proceso de eje-
cución.
Nota: Error lógico: Es un error producido por un algoritmo incorrecto.
Por ejemplo, la instrucción
System.out.println("Sie de Cazorla");
no muestra la frase que se deseaba, pues no se ha escrito bien:
System.out.println ("Sierra de Cazorla");
pero el compilador no puede encontrar el error ya que la primera sentencia es sin-
tácticamente correcta.
CAPITU
Características del
lenguaje Java
CONTENIDO
2.1. Palabras reservadas.
2.2. Identificadores.
2.3. Tipos de datos.
2.4. Tipos simples (primitivos).
2.5. Variables.
2.6. Constantes.
2.7. La biblioteca de clases de Java.
2.8. Conceptos básicos sobre excepciones.
2.9. La clase Number y sus subclases.
2.10. Las Clases Character y Boolean.
2.1I. Entrada y salida básicas.
2.12. Operadores.
2.13. La sentencia de asignación.
2.14. Expresiones.
2.15. Class Math.
2.16. Paquete java.math.
2.17. Conversiones de tipos. Operadores molde.
2.18. Operadores aritméticos.
2.19. Operadores relacionales.
2.20. Operadores lógicos.
2.21. Operadores de manipulación de bits.
2.22. Operadores de asignación adicionales.
2.23. Operador condicional.
2.24. Prioridad de los operadores
31
32 Java 2. Manual de programación
Este capítulo expone los tipos de datos simples que ofrece Java,
explica los conceptos de constantes y variables, y enseña como
efectuar su declaración. Se tratan también en el capítulo las ope-
raciones básicas de entradakalida y los distintos tipos de opera-
dores y expresiones, comentándose además algunas clases de
gran utilidad.
2.1. PALABRAS RESERVADAS
Las palabras reservadas son palabras con un significado especial dentro del lengua-
je. En Java 2 las palabras reservadas se listan en la Tabla 2.1:
Tabla 2.1. Palabras reservadas Java 2
abstract
boolean
break
byte
byva1ue
case
cast
catch
char
class
const'
continue
default
do
double
else
extends
false
final
finally
float
for
future'
generic'
got0
if
implements
import
inner
instanceof
int
interface
l o n g
native
new
null
operator'
outer'
package
private
protected
public
rest'
return
short
static
super
switch
synchronized
this
threadsafe
throw
throws
transient
true'
try
var'
void
volatille
while
No son auténticas palabras reservadas,
No se utilizan en las últimas versiones de Java.
'Los métodos nativos están implementados en otros Icnguajes corno C o C++.
En Java se declara un método nativo con la palabra reservada native y el
cuerpo de método vacío.
Características del lenguaje Java 33
2.2. IDENTIFICADORES
Al igual que sucede con cualquier entidad o elemento del mundo real que se iden-
tifica con un nombre, los elementos de un lenguaje de programación utilizan sím-
bolos especiales, denominados ident$caúores. Son identificadores, por tanto, los
nombres que reciben las clases, interfaces, paquetes, métodos, variables o instancias
en un programa. Un identificador en Java debe cumplir las siguientes reglas:
Puede tener cualquier longitud (uno o más caracteres).
No puede contener operadores tales como +, -, . ..
No puede coincidir con una palabra reservada, por tanto no puede ser true,
false o null.
El primer carácter sólo puede ser una letra, el carácter $ o el carácter de subra-
yado.
Después del primer carácter pueden aparecer cualquier combinación de letras,
dígitos, $ y - .
Las letras podrán ser mayúsculas y minúsculas incluyendo, en ambos casos, las
acentuadas y la ñ.
Debe ser referenciado siempre de la misma manera, sin cambiar mayúsculas
por minúsculas ni viceversa. AI cambiar mayúsculas por minúsculas o al con-
trario, Java lo interpreta como un identificador diferente.
Ejemplo
Identijicadores validos Iúentificudores no validos
$5 5B
Nombre Z - t l
Char char
a true
false
nullApe11idos
Superficie -signo
P
El compilador Java detecta los identificadores válidos e informa de los errores
de sintaxis que existan en el programa fuente.
Nota: Java emplea la especificación Unicode para utilizar caracteres. Así se
pueden emplear letras del alfabeto inglés y de otros idiomas internacionales
recogidos en Unicode. Ésta es la razón por la que a , b, g, ..., ñ son
caracteres legales.
34 Java 2. Manual de programación
2.3. TIPOS DE DATOS
Java es un lenguaje fuertemente tipeado; esto implica que constantes, variables y
expresiones tienen un tipo asociado y toda variable que interviene en un programa
debe ser declarada antes de poder ser utilizada. Además, Java comprueba las ope-
raciones de asignación, el paso de parámetros y las expresiones para asegurarse
sobre la compatibilidad entre los tipos de datos que intervienen en ellas.
Una primera clasificación de los tipos de datos en Java nos obligaría a distinguir
entre tipos simples y definidos por el usuario, debido a que tienen características
muy diferentes, constituyendo los tipos simples la base sobre la que se crearán los
tipos definidos por el usuario.
2.4. TIPOS SIMPLES (PRIMITIVOS)
Los tipos simples @/*irnitivos)no están orientados a objetos y pueden subdividirse
en enteros, reales, datos de tipo carácter y lógicos o booleanos, caracterizándose
cada uno de estos grupos por el conjunto de valores que pueden tomar y las opera-
ciones que se pueden realizar sobre ellos. Cada tipo de dato tiene un dominio
(rango) de valores. El compilador asigna espacio de memoria para almacenar cada
variable o constante con arreglo a su tipo.
Enteros
Java ofrece cuatro tipos de enteros: byte,short,int y long.Todos ellos ad-
miten valores tanto positivos como negativos, y cada uno permite almacenar valo-
res en un determinado rango, definiéndose como valores con signo de 8, 16, 32 y
64 bits.
Tabla 2.2. Tipos primitivos enteros
Nombre. Tamaño Rango de valores
en bits
Declaración
byte 8 -128 a 127 b y t e varl;
short 1 6 -32768 a 32767 s h o r t var2 ;
int 32 -2141483648 a 2147483647 i n t var3;
long 64 -9223372036854715808 a long var4;
9223372036a54175801
Es posible escribir constantes enteros en otras bases distintas a la decimal:
octal, hexadecimal. Una constante octal es cualquier número que comienza con
Caracteristicas del lenguaje Java 35
un O y contiene dígitos en el rango 1 a 7 ( O 123 4 ) . Una constante hexadeci-
mal comienza con Ox y va seguida de los dígitos O a 9 o las letras A a F
(OxF10).
Reales
Los tipos de datos de coma flotante permiten almacenar números muy grandes, muy
pequeños o que contienen coma decimal. Java soporta dos formatos de coma flo-
tante float y double.El tipo float utiliza 32 bits para el almacenamiento y
guarda los valores con precisión simple (6 Ó 7 dígitos). El tipo double utiliza 64
bits para el almacenamiento y guarda los valores con mucha mayor precisión (14 ó 15
dígitos); suele ser el tipo devuelto por muchas funciones matemáticas y suele ser el
más empleado.
Tabla 2.3. Tipos primitivos de coma flotante
~ ~~
Nombre Tamaño
en bits
~~ ~~ ~~ -
Rango de valores Declaración
e inicialización
f l o a t 32 (precisión simple) 3,4E-38 a 3,4E38 f l o a t numl=2.7182f;
double 64 (precisión doble) 1,7E-308 a 1,7E308 double num2=2.7182d;
Carácter
El tipo de datos char de Java se utiliza para representar un carácter, éste tipo
emplea 16 bits para el almacenamiento de un carácter y lo efectúa en formato
Unicode. Unicode presenta dos ventajas: (1) permite a Java trabajar con los carac-
teres de todos los idiomas; (2) sus primeros 127 caracteres coinciden con los del
código ASCII.
Tabla 2.4. Tipo primitivo para representar un carácter
Nombre Tamaño Rango de valores Declaración
en bits e inicialización
char 1 6 caracteres alfanuméricos char l e t r a = ’a’ ;
Un literal carácter representa un carácter o una secuencia de escape encerrada
entre comillas simples. Por ejemplo, ‘c’ , ‘D‘.Una cadena de caracteres (string),
es un conjunto de cero o más caracteres (incluyendo las secuencias de escape) ence-
rrados entre dobles comillas.
36 Java 2. Manual de programación
Ejemplo
Ejemplos de cadenas
"Cr,a caaena"
"Cierra Ue Aracena"
"C;erra de C a z o r l a "
"Primera linea rn Segunda linea"
"Prir?era página f Segunda página"
,,P
,ol>;mna ;t Columna 2"
,,1 ,
Regla: En Java, el tipo char representa un carácter.
En Java, para representar una cadena de caracteres se utiliza una estructura de
datos denominada S t r i n g . El concepto de string se explica con detenimiento en
el Capítulo 8, ((Cadenasy fechas)).
Regla: Una cadena se debe encerrar entre dobles comillas. Un tipo carácter es
un Único carácter encerrado entre simples comillas.
Los caracteres Java utilizan Unicode, que es un esquema universal para codifíca-
ción de caracteres en 16 bits establecido por el consorcio Unicode para soportar el
intercambio, proceso y presentación de los textos escritos en los diferentes idiomas
del mundo (véase el sitio Web de Unicode en www .Unicode.org). Unicode toma
dos bytes, expresados en cuatro números hexadecimales que corren de 'uO OO O ' a
'uFFFF'. La mayoría de las computadoras utilizan el código ASCII (Unicode
incluye los códigosASCI1 de 'uOOOO' a 'uOOFF'). En Java se utiliza el códi-
go ASCII, así como Unicode y las secuencias de escape como caracteres especiales.
Tabla 2.5. Secuencias de escape
~ ~ ~ ~ ~~~~~
Secuencia Significado
b
t
 n
f
r
 "
 '
 
uxxxx
Retroceso
Tabulacih
Nueva línea
Avance de página
Retorno de carro sin avance de línea
Dobles comillas
Comillas simples
Barra inclinada inversa
Carácter Unicode
Características del lenguaje Java 37
Ejemplo
Ejemplos de secuencias de escape:
'  k '
'n'
't'
'u015Ef
Tabla 2.6. Ejemplos de caracteres especiales
Carácter ASCII Unicode
Retroceso de espacio
Tabulación
Avance de línea
Retorno de carro
b
t
 n
r
u008
u009
uOOA
uOOD
Precaución: 
Una cadena debe encerrarse entre dobles comillas.
Un carácter es un Único carácter encerrado entre simples comillas.
Un carácter Unicode se debe representar mediante el código ' uXXXX '.
Para almacenar un carácter, se almacena el código numérico que lo representa;
por tanto, internamente los caracteres son números y esto capacita a Java para rea-
lizar algunas operaciones numéricas con datos de tipo char.
Ejemplo
class CocMayuccu;ac
i
public static void main (String argci])
char c;
c='a' -32;
Cystem.out.print ("El carácter es " ) ;
Cystex.out .println(c);
c t t ;
System.cut .print("Siguiente carácter " ) ;
Sycten.out . p r i n t l n (c);
38 Java 2. Manual de programación
Lógico (boolean)
Un dato de tipo lógico puede tomar exclusivamente uno entre los dos siguientes
posibles valores: t r u e , f a l s e (verdadero falso).
Tabla 2.7. Tipo primitivo para representar datos lógicos
Nombre Rango de valores Declaración e inicialización
boolean t r u e , f a l s e boolean bandera = f a l s e ;
Las variables booleanas almacenan el resultado de una expresión lógica, tenien-
do en cuenta que ésta puede estar formada por una Única constante o variable de tipo
lógico. Su contenido puede ser directamente mostrado por pantalla mediante el
método p r i n t l n ( ) .
Ejemplo
package libro.Tema02;
class Ejemplo2
t
public static void main (String[] arg)
{ byte dia;
boolean correcto;
dia = -3;
correcto = dia > O;
Systern.out .print ( " Dia " ) ;
System.out.print(dia);
System.out.print ( " correcto = " ) ;
Cystem.out.println(correcto);
2.5. VARIABLES
Las variables almacenan datos cuyo valor puede verse modificado durante la eje-
cución de un programa. Las variables se utilizan para representar tipos de datos muy
diferentes. En Java hay que distinguir entre variables por valor y objetos o variables
por referencia; las variables de tipo simple son variables por valor.
Declaración de variables. Para utilizar una variable se necesita declararla e
indicar al compilador el nombres de la variable, así como el tipo de dato que repre-
Características del lenguaje Java 39
senta. Esta operación se denomina declaración de variables. Toda variable debe ser
declarada antes de poder ser utilizada. Para declarar variables de tipo simple se
especifica su nombre y su tipo, que define tanto los datos que la variable va a poder
almacenar como las operaciones que tendrá permitidas. La sintaxis es, por tanto:
tipollato nombrevariable;
Ejemplo
Declaración
int z; //declara z como una variable entera
double base; //declara base como variable double
char b; //declara b como variable char
Nota: Las variables permiten almacenar datos, de entrada, salida o datos inter-
medios.
Consejo: Los identificadores se utilizan para nombrar variables, constantes,
métodos, clases y paquetes. Los identificadores descriptivos son los más utili-
zados, ya que hacen los programas más fáciles de leer. Java es sensible a las
mayúsculas, por consiguiente Z y z son identificadores diferentes.
Sentencias de asignación. Después que una variable se declara, se puede asignar
un valor a esa variable utilizando una sentencia de asignación. La sintaxis de la
asignación tiene el siguiente formato:
variable = expresión;
Es preciso tener en cuenta que una expresión es un conjunto de operadores y
operandos, pero una única constante o variable también constituye una expresión.
Ejemplo
2 = 5; //asigna 5 a z
longitud = 1.0 //asigna 7.0 a longitud
b =  B f ; //asigna 'B' a b
Regla: El nombre de la variable debe estar a la izquierda 5 = z; es ilegal.
40 Java 2. Manual de programación
Como ya se indicó anteriormente, una expresión representa un cálculo que
implica valores, variables y operadores.
superficie = 3.141592 * radio * radio;
z = z t i; //el valor de z t 1 se d s i y n d a. la variable z
Precaución: La sentencia de asignación utiliza el signo igual (=).Tenga cui-
dado, no utilizar := que se utiliza con frecuencia en otros lenguajes de pro-
gramación.
tipoDato nombrevariable = valor-inicial;
Declaración e inicializucióri de variables en un solo puso. Se puede declarar e
inicializar una variable en un solo paso en lugar de en dos pasos como se ha mos-
trado en las operaciones.
Ejemplo
Declaración con asignación del valor inicial Declaración y asignación de un valor
char respuesta = ‘S‘
i n t contador = 1;
f l o a t peso = 156.45f;
char respuesta;
respuesta=’C ’ ;
i n t contador;
contador=l;
f l o a t peco;
peso=156.45f;
Precaución:Una variable se debe declarar antes de que se le pueda asignar un
valor. A una variable se le debe asignar un valor antes de que se pueda leer en
un método.
Consejo: Siempre que sea posible, es conveniente declarar una variable y
asignarle su valor inicial en un solo paso, ya que esta acción facilita la inter-
pretación del programa.
Características de/ lenguaje Java 41
Ámbito. Es importante el lugar donde se efectúa la declaración de las variables,
pues éste determina su ámbito. En Java es posible agrupar sentencias simples, ence-
rrándolas entre una pareja de llaves para formar bloques o sentencias compuestas y
efectuar declaraciones de variables dentro de dichos bloques, al principio de los
métodos o fuera de ellos. Una sentencia compuesta nula es aquella que no contiene
ninguna sentencia entre las llaves { } .
Ejemplo
i n t i=25;
double j=Math.sqrt (20);
i++;
j += 5;
System.out.println(i+" "tj);
{ i n t aux = i;
i = ( i n t )( j ) ;
j= aux;
/ / A continuación comienza un bloque
1 //Fin del bloque
System.out .println(i+""tj); / / aux aquí no está definida
Es decir, en Java es posible declarar variables en el punto de utilización de las
mismas dentro del programa, pero habrá de tener en cuenta que su ámbito será el
bloque en el que han sido declaradas. Como ya se ha indicado, un bloque de sen-
tencias se delimita entre dos llaves y las variables declaradas dentro de un bloque
sólo son válidas en dicho bloque. Si un bloque tuviera otros anidados, en los inte-
riores a él. No se pueden declarar variables en bloques interiores con el nombre de
otras de ámbito exterior.
Las variables declaradas dentro del cuerpo de un método son variables locales,
y sólo existirán y se podrá hacer referencia a ellas dentro del cuerpo del método. Las
variables que se declaran fuera del cuerpo de un método son variables de instancia
y cada instancia de la clase tendrá una copia de dichas variables. Las variables
declaradas fuera del cuerpo de los métodos y en cuya declaración se especifique la
palabra static son variables de clase, esto quiere decir que no se hará una copia
de ellas para cada uno de los objetos de la clase y, por tanto, su valor será compar-
tido por todas las instancias de la misma.
2.6. CONSTANTES
Las constantes son datos cuyo valor no puede variar durante la ejecución de un pro-
grama. En un programa pueden aparecer constantes de dos tipos: literales y simbó-
licas. Las constantes simbólicas o con nombre representan datos permanentes que
42 Java 2. Manual de programación
nunca cambian y se declaran como las variables, pero inicializándose en el momento
de la declaración y comenzando dicha declaración con la palabra reservada final,
que sirve para que el valor asignado no pueda ser modificado. Las constantes de clase
se declaran en el cuerpo de la clase y fuera de todos los métodos, siendo necesario
comenzar su declaración con las palabras reservadas fina1y c tatic.La palabra
clave final es obligatoria en la declaración de constantes, mientras que static
consigue que sólo exista una copia de la constante para todos los objetos que se decla-
ren de esa clase. La sintaxis para declarar una constante de clase es:
s t a t i c f i n a l tipoDato NOMBRECONSTANTE = valor;
Ejemplo
1. s t a t i c f i n a l double PI = 3.141592;
superficie = radio * radio * PI;
2. class Prueba
i
s t a t i c f i n a l i n t MAX = 700;
void Método ( )
/ / . . .
I
/ / .
1
Precaución: El nombre de las constantes se suele escribir en mayúsculas.
Antes de utilizar una constante debe ser declarada. Una vez que se ha declara-
do una constante no se puede modificar su valor.
Las constantes literales son valores de un determinado tipo escritos directamen-
te en un programa. Dichas constantes podrán ser enteras, reales, lógicas, carácter,
cadena de caracteres, o el valor null.
Constantes enteras
Las constantes enteras representan números enteros y siempre tienen signo. La
escritura de constantes enteras en un programa debe seguir unas determinadas
reglas:
No utilizar comas ni signos de puntuación en números enteros.
123456 en lugar de 123.456.
Características del lenguaje Java 43
Puede añadirse una L o 1a1,finaldel número para especificar que se trata de
Si se trata de un número en base decimal no podrá comenzar por cero.
un long 123456L.
0123 es una constante entera en base octal
0x123 es una constante entera en hexadecimal
cimal mediante la colocación de Ox o bien OX delante del número.
La notación octal se indica poniendo un cero delante del número y la hexade-
Constantes reales
Una constante flotante representa un número real, siempre tiene signo y repre-
senta aproximaciones en lugar de valores exactos. Las constantes reales tienen el
tipo double por defecto, aunque también pueden ir seguidas por una d o D que
especifique su pertenencia a dicho tipo. Cuando se les añade una f o F se obli-
ga a que sean de tipo float.Para escribir una constante real se puede especifi-
car su parte entera seguida por un punto y su parte fraccionaria, o bien utilizar la
notación científica, en cuyo caso se añade la letra e o E seguida por un expo-
nente.
82.341 equivale a 82.347d 2.5e4 equivale a 25OOOd
4E-3F equivalea O. 004f 5.435E-3 equivalea O. 005435d
Constantes íógicas
Las constantes literales de tipo lógico disponibles en Java son true y false,que
significan verdadero y falso respectivamente.
Constantes de tipo carácter
Una constante de tipo carácter es un carácter válido encerrado entre comillas sim-
ples. Los caracteres que pueden considerarse válidos son:
Las letras mayúsculas y minúsculas, incluyendo en ambos casos las acentuadas y la ñ.
Los dígitos.
Los caracteres $, - y todos los caracteres Unicode por encima del OOCO .
Existen, además, ciertas secuencias especiales, denominadas secuencias de esca-
pe, que se usan para representar constantes de tipo carácter.
44 Java 2. Manual de programación
Tabla 2.8. Ejemplos de constantes de tipo carácter representadas
mediante secuencias de escape
~ ~ ~ ~~ ~~ ~~
Secuencia Significado Secuencia Significado
n' Nueva línea I  I I 
I t' Tabulación I  I l l I,
' b' Retroceso I u0007' Pitido
' r' Retorno de carro sin avance de línea ' uOOIB1 Esc
I   ' 
Constantes de tipo cadena
Una constante literal de tipo cadena en Java está constituida por una serie de carac-
teres, entre los que pueden aparecer secuencias de escape, encerrados entre comi-
llas dobles. Para cada constante literal de tipo carácter usada en un programa Java
crea automáticamente un objeto de tipo String con dicho valor.
Ejemplo
/ / Secuencias de escape
class TresNumeros
11La salida de estei
public s t a t i c void main (String args[])
i
1
System.out .print ( "  t1 n t2 n t3" ) ;
2.7. LA BIBLIOTECA DE CLASES DE JAVA
La potencia del lenguaje Java radica en su biblioteca de clases. Java posee una
biblioteca de clases organizada en paquetes, que son un conjunto de clases lógi-
camente relacionado, y, por tanto, para referenciar una de estas clases en un pro-
grama es necesario escribir su nombre completo, es decir, incluir en el mismo el
paquete al que pertenece, o bien importar el paquete. Una excepción la constitu-
yen las clases pertenecientes al paquete java .lang,que se importa automáti-
camente.
Entre los paquetes de Java que más destacan se podrían mencionar los
siguientes:
Características del lenguaje Java 45
1ar.g Funciones del lenguaje n e t Para redes
uti1 Utilidades adicionales ' awt Gráficos 2 interfaz gráfica de usuario
io Entrada/Salida
text Formateo especializado applet Para crear programas que se ejecuten en la Web
awt .ever.t Sucesos desde el teclado. ratón. etc.
La sentencia import sólo indica a Java dónde buscar las clases utilizadas en un
programa.
2.8. C ~ N C E P T ~ SBÁSICOS SOBRE EXCEPCIONES
Cuando en la ejecución de un programa se produce un error, Java lanza una
excepción', que será necesario capturar para que el programa no se detenga. La
clase Exception,con sus subclases IOException y RuntimeException
contiene las excepciones que una aplicación necesita manejar habitualmente.
En el paquete java .io se define la excepción denominada IOException
para excepciones originadas por errores de entradaisalida. Estas excepciones se
han de manejar de forma que el método donde se puedan producir debe capturar-
las o bien declarar que se lanzan mediante una claúsula throws,en cuyo caso el
método invocador está obligado a capturarlas. Para capturar una excepción en ope-
raciones de entrada/salida el programa deberá incluir la sentencia import
j ava .io y además habrá que poner a prueba el código capaz de lanzar la excep-
ción en un bloque try y manejar la excepción en un bloque catch,el manejo la
excepción se puede reducir a la presentación de un mensaje de error.
//captura de excepciones de entrada y caliia
t=Y
//operaciones de entrada y salida
I
catch (IOException e)
!
Cystem.out .println("Error");
Las operaciones aritméticas también pueden dar origen a excepciones; por ejemplo,
la división por cero. Estas excepciones pertenecen la clase RuntimeException del
paquete java .lang y son lanzadas automáticamente por Java y el compilador no
obliga a su manejo.
' Una excepciónesun tipo especialde error (objetoerror)que se crea cuandosucedealgo impreisto en un prtr
grama. En el Capítulo 13se estudia con más detalle el conceptoy manipulaciónde excepciones.
46 Java 2. Manual de programación
/ k a - t u r a generica de excepciones de la clase Exception
t r y
//operaciones de entrada y salida
catch (Exception e)
i
C ystern. out.printIn ( "Error " tej ;
2.9. LA CLASE Number Y SUS SUBCLASES
Java utiliza los tipos simples byte,int,long,float y double,que no están
orientados a objetos, por razones de rendimiento. Si lo que se necesita es un objeto
de alguno de estos tipos, será necesario recurrir a las clases Byte, Integer,
Long, Float y Double,que son subclases de Number.Number pertenece al
paquete java .lang y proporciona métodos que devuelven el valor del objeto
como el correspondiente tipo simple. Métodos de Number con dicha finalidad son:
public
public
public
public
public
byte bytevalue ( )
a b s t r a c t double doublevalue ( )
a b s t r a c t f l o a t floatvalue ( )
a b s t r a c t i n t intValue(j
a b s t r a c t long longvalue ( j
Number es una clase abstracta, concepto que se explicara con detalle más ade-
lante, y sus métodos abstractos han de ser definidos en cada una de las subclases
comentadas. Por otra parte, las clases Byte, Integer, Long, Float y
Double permiten construir objetos de la clase correspondiente mediante los
métodos:
public
public
public
public
public
public
public
public
public
public
public
Byte (byte pl)
Byze(java.lang.Ctring pl)
Integer ( i n t p1)
Ir,teger(java.lang.String pl)
Long (long pl)
LorLg(java.lang.String pl)
Float (double pl)
Float ( f l o a t pl)
Float ( java.lang .String pl)
Double (double pl)
Double (java.lang.String pl)
Características del lenguaje Java 47
Es decir, se pueden construir objetos de estos tipos a partir de los valores numé-
ricos adecuados o a partir de cadenas con valores válidos para el tipo. La construc-
ción ha de efectuarse con la ayuda del operador new, que también aparece
comentado con posterioridad.
Double d = new Double("2.71828");
double real = d.doubleValue ( ) ;
Integer ent = new Integer(34);
int 1 = ent .intValue( ) ;
Las clases Integer y Long proporcionan dos métodos muy utilizados para
convertir una cadena en un número, parseInt y parselong. Estos métodos
lanzan una NumberFormatException, que es una RuntimeException,
cuando surge algún problema.
public static int parseInt (java.lang.String pi)
//el segundo parámetro permte especificar la base
public static int parseInt (lava.lang.String p:, int 02)
public static long parseLong (lava.lang.String pi)
//el segundo parámetro permite especificar la base
public static long p a r s e L o n g ( j a v a . 1 a n g . C t r i n g pi, int 0 2 )
Ejemplo
int 1 = 1nteger.parseInt ("20C1");
int j = 1nteger.parseInt ("101",2);
System.out.println("i = " + 1 + " j = " + 1);
La salida sería
1 = 2001 j = 5
Otros métodos interesantes de las clases Integer y Long son:
class Inteqer
public static java.lang.String toString(int p)
public static lava.lang.String toBinaryS:r:-,g (int p )
public static java.lang.String toHexString(int p)
public static java.lang.String to0ctalStripg(int p )
48 Java 2. Manual de programación
class Long
public static java.lang.String toString(1ong p)
public static java.lang.String toBinaryString(1ong p)
public static java.lang.String toHexString(1ong p)
public static java.lang.String toOctalString(1ong p)
Estos métodos permiten respectivamente convertir números ( int o long) en
una cadena decimal, binaria, octal o hexadecimal.
2.10. LAS CLASES Character Y Boolean
La clase Character se utiliza para crear objetos a partir de un parametro char.
El constructor es:
public Character (char p)
y posee el método public char charvalue ( ) que devuelve el valor char
Correspondiente.
Otros métodos interesantes de esta clase son:
public static char touppercase (char p)
public static char toLowerCase (char p )
que devuelven el carácter que reciben como argumento transformado a mayúsculas
en el caso del primer método y a minúsculas en el caso del segundo.
La clase Boolean permite crear objetos a partir de un dato de tipo boolean.
Sus constructores son:
public Boclean (boolean p)
public Boolean(java.lang.String p)
y para obtener el correspondiente valor boolean se usa
public boolean booleanvalue0
Ejemplo
boolean rnayor = 3 + 1 > 5;
Soolean ob = new Boolean(mayor);
boolean b = ob,booleaiValue ( ) ;
Características del lenguaje Java 49
2.11. ENTRADA Y SALIDA BÁSICAS
En Java la entrada y salida de información se realiza mediante flujos; es decir,
secuencias de datos que provienen de una fuente. Estos flujos son objetos que
actúan de intermediarios entre el programa y el origen o destino de la información,
de forma que éste lee o escribe en el flujo y puede hacer abstracción sobre la natu-
raleza de la fuente. Como las clases relacionadas con flujos pertenecen a un paque-
te denominado j ava .io, los programas que utilizan flujos necesitan la inclusión
en los mismos de la instrucción
import java.io.*;
En Java existen unos flujos estándar, manipulados por la clase System del
paquete java .lang,que permiten realizar operaciones de entradaisalida:
'system.in. representa la entrada estándar y es del tipo java.io.InpLtSzream
*System.out,del tipo java.io.PrintStream,referencia ia pantalla
*system.err,de tipo java.10. Printstream,referencia la salida de errores
public s t a t i c f i n a l java.io.InputCtream ;I:
public s t a t i c f i n a l lava.io.Printstream out
public s t a t i c f i n a l java.io.PrintStream err
La salida básica por pantalla se lleva a cabo mediante los métodos print y
println, pertenecientes a la clase Printstream.A estos métodos se les puede
llamar mediante System.out,que hace referencia a la salida estándar. El mecanis-
mo básico para salida con formato utiliza el tipo String.En la salida, el signo +com-
bina dos valores de tipo String y si el segundo argumento no es un valor de tipo
String,pero es un tipo primitivo, se crea un valor temporal para él de tipo String.
Estas conversiones al tipo String se pueden definir también para objetos.
Ejemplo
/ *
Ejemplo 1" sobre operaciones básicas de entrada y salida.
Ejecute el siguiente programa y analice los resultados
* /
import java.io.*;
public c l a s s Er.tradaCa1iaa1
t
public s t a t i c void main (String[] args)
i n t 1;
char c;
50 Java 2. Manual de programación
Sys;err.out .println("Escriba un número natural con" +
;=Cysterr.in.read ( ) ;
System.in.skip (2);
/ *
"un único dígito y pulse RETURN");
saita dos caracteres en el f l u j o de entrada:
rn
Caracteres originados al pulsar la tecla RETURN
* /
Cyster,.out.println(i);
System.out.println("Escriba un número natural con" +
"un Único dígito y pulse RETURN");
c=(char)Systern.in.read();
Cystern.out.println (c);
catch ( IOException e)
Cystem.out .println("Error");
La entrada de datos por consola se efectúa en Java leyendo bytes de un flujo de
entrada y almacenándolos en objetos de distinto tipo, como se hizo mediante
System.in.read ( ) en el ejemplo anterior. La instrucción System.i n .
s k i p (2); que también aparece en dicho ejemplo puede sustituirse por esta
otra System.in.skip(System.in.available()); paraqueelpro-
grama determine automáticamente el número de caracteres que quedan en el
flujo de entrada y se desean saltar.
No obstante, la entrada básica en Java suele realizarse mediante el método
readLine ( ) de la clase BufferedReader, que lee una secuencia de caracte-
res de un flujo de entrada y devuelve una cadena y, además, mejora el rendimiento
mediante la utilización de un búfer. Para efectuar este tipo de entrada debe cons-
truirse un objeto de la clase BufferedReader sobre otro de la clase
InputStreamReader asociado a System.in, que se encarga de convertir en
caracteres los bytes leídos desde teclado. Según este planteamiento, la lectura de
valores numéricos conllevaría dos fases: lectura de una cadena y conversión de la
cadena en nzímero. Cuando s i trata de valores de tipo int o long los métodos
Integer.parseint e Integer.parseLong proporcionan un mecanismo
de conversión adecuado, mientras que para valores de tipo real se recurre a efec-
tuar la construcción de objetos de tipo Float o Double a partir de la representa-
ción en forma de cadena del número en coma flotante, para después, mediante
f loatvalue o doubleValue,obtener el valor float o double que encap-
sula dicho objeto. Como ya se ha visto, Integer,Long,Float y Doble son
Características de/ lenguaje Java 51
clases pertenecientes al paquete java .lang que representan como objetos los
tipos simples de su mismo nombre.
Ejemplo
/ *
Elemplo 2" sobre operaciones de entrada y salida.
Ejecute el siguiente programa y analice los resultaccs
* /
import java .io.* ;
public class Entradasalida2
i
public static void main (String[] args)
InputCtreamReader isr = new InputCtreamReader (System.in);
BufferedReader br = new BufferedReader(;sr);
String cadena;
try
Cystem.out .println("Escriba su nombre y pulse RETU;IN");
cadena=br.readLine();
System.out.println("Hola" +cadena+
", escribe un número entero y pulsa RETCW") ;
int entero=Integer.parseInt(br.readLine()1 ;
Cystem.out .println("El número introducido fue el "+er.terc);
Cystem.out.println("Amigo/a" +cadena+
", introduzca ahora un real y p¿ilseXFTLJS>J") ;
System.out.println( " (utilice el punto corno separador" +
cadena=br.readline();
Double d=new Double (cadena);
double real= d.doublevalue ( ) ;
System.out .println("El real es "+real);
"ej 3.45)");
1
i
1
catch ( TOException e)
System.out.println("Error");
1
AI realizar este tipo de operaciones de entrada/salida hay que tener en cuenta la
posible generación de excepciones; por ejemplo, aquellas que son lanzadas por
readLine ante un error de lectura, y estas excepciones deben ser recogidas o
bien listadas en una cláusula t h r o w s que las devuelva al método llamador.
52 Java 2. Manual de programación
2.12. OPERADORES
Los operadores de un lenguaje se pueden utilizar para combinar o modificar los
valores de un programa. Java posee un gran conjunto de operadores. La lista com-
pleta de los operadores Java se muestra en la Tabla 2.9.
Tabla 2.9. Lista completa de operadores Java
> < !
-__ _ <= >= I =
~
-~
? :
& &
-
+=
_ -++
/ &
*= / =
<< >>
t
>>>
& =
>>>= (tipo) new instanceof or .
1 1
2.12.1. Operadores sobre enteros
Los operadores que trabajan sobre enteros pueden ser binurios o unarios (unita-
rios). Los operadores binarios son aquellos que requieren dos operandos (Tabla
2.1 1). Los operadores unarios son aquellos que requieren un único operando
(Tabla 2.10). En ambas tablas se proporciona un ejemplo de la utilización de cada
operador.
La Tabla 2.12 muestra un tipo especial de operadores de asignación que se basan
en los otros operadores. Estos operadores actúan sobre un operando y almacenan el
valor resultante de nuevo en el mismo operando.
Ejemplo
z += 5; equivale a z = z + 5 ;
Tabla 2.1O. Operadores unitarios sobre enteros
Operador Operación Ejemplo
- Negación unitaria -a
++ Incremento ++a o bien a ++
_ _ Decremento --a o bien a--
- Negación lógica bit a bit -a
Características del lenguaje Java 53
Tabla 2.11. Operadores binarios sobre enteros
~
Operador Operación Ejemplo
-- Asignación
____ Igualdad
I = Desigualdad
< Menor que
a = b
a ! = b
a < b
a == b
<= Menor o igual que a <= b
>= Mayor o igual que a >= b
> Mayor que a > b
+ Suma a + b
- Diferencia a - b
Producto a * b
/ División a / b
, Módulo a % b
<< Desplazamiento a izquierdas a << b
>> Desplazamiento a derechas a >> b
>>> Desplazamiento a derechas con rellenado de ceros a >>> b
& AND bit a bit a & b
I OR bit a bit a l b
XOR bit a bit a ^ b
*
Tabla 2.12. Operadores de asignación enteros
t =
/=
--
>>=
---
&=
9-
>>>=
0 -
*=
I =
<<=
2.12.2. Operadores sobre valores de coma flotante
Los operadores sobre valores de coma flotante son un subconjunto de los disponi-
bles para tipos enteros. La Tabla 2.13 muestra los operadores que pueden operar
sobre operandos de tipo f l o a t y double.
54 Java 2. Manual de programación
Tabla 2.13. Operadores sobre valores de coma flotante
Operador OperJción Ejemplo
__
_ __ _
I =
<
<=
>=
>
+
/
,
++
_ _
Asignación
Igualdad
Desigualdad
Menor que
Menor o igual que
Mayor o igual que
Mayor que
Suma
Resta
Multiplicación
División
Módulo
Negación unitaria
lncrernento
Decremento
a = b
b
a ! = b
a < b
a <= b
a >= b
a > b
a + b
a - b
a * b
a / b
-a
++a o bien a++
--a o bien a--
a ==
a % b
2.13. LA SENTENCIA DE ASIGNACIÓN
La sentencia de asignación se usa para dar valor a una variable o a un objeto en el
interior de un programa, aunque hay que tener en cuenta que las variables de tipo
objeto se comportan de forma diferente a como lo hacen las de tipo simple cuando
se realiza una asignación. El operador de asignación es el signo de igualdad y en
este tipo de sentencias la variable se colocará siempre a la izquierda y la expresión
a la derecha del operador.
Los objetos de una determinada clase se crean utilizando el operador new que
devuelve una referencia al objeto, la cual se almacenará en una variable del tipo
objeto mediante una sentencia de asignación. Las sentencias de asignación tam-
bién se podrán aplicar entre dos variables de tipo objeto. A las variables de tipo
objeto se las denomina variables por referencia, debido a que cuando se asigna
una variable de tipo objeto a otra (a diferencia de lo que ocurre con las variables
de tipo simple) no se efectúa una copia del objeto, sino que sólo se hace una
copia de la referencia, es decir, de la dirección de memoria donde se encuentra
el objeto.
Double d, d2;
d = new Double("3") ;
d2 = d;
Características del lenguaje Java 55
En cuanto a las variables de tipo simple, tras efectuar su declaración, podrá usar-
se el operador de asignación, para adjudicarles el valor de una expresión.
int x,y;
x=5;
y=x;
Este operador es asociativo por la derecha, lo que permite realizar asignaciones
múltiples. Así,
adjudica a las tres variables el valor 5.
2.14. EXPRESIONES
En general, las expresiones se definen como un conjunto de operadores y operan-
dos, pero hay que tener en cuenta que dicho conjunto puede estar formado exclusi-
vamente por un operando. Es decir, que las expresiones pueden ser una constante,
una variable o una combinación de constantes, variables y/o funciones con opera-
dores, tanto binarios como unitarios.
Como ya se comentó, en Java las variables declaradas static y fina1 son
en realidad constantes y los métodos cuyo tipo de resultado no es void y que
se declaran como public y static pueden ser considerados funciones glo-
bales.
2.15. CLASE Math
La clase java .lang .Math proporciona una serie de constantes y funciones de
uso muy común en expresiones aritméticas.
Math es una clase en el paquete fundamental java .lang. Los métodos está-
ticos de la clase Math realizan cálculos matemáticos básicos tales como máximo,
mínimo, valor absoluto y operaciones numéricas que incluyen funciones exponen-
ciales, logarítmicas, raíz cuadrada y trigonométricas. Los cálculos en coma flotan-
te se realizan utilizando double y algoritmos estándar.
56 Java 2. Manual de programación
Métodos sobre tipos numéricos
Invocación Significado Estructurade la cabecerade la declaración del miembro
Math.abs (exp) valor absoluto public s t a t i c double abs (double pl)
de e.rp public s t a t i c f l o a t abs ( f l o a t pi)
public s t a t i c i n t abs ( i n t pl)
public s t a t i c long abs (long pl)
Math.max(expl,expZ)mayorentre public static double max (doublep l , double p2)
explyexp2 public static float max (float pi, float p2)
public s t a t i c i n t rnax ( i n t p i , i n t p2)
public s t a t i c long rnax (long p l , long p2)
Math.min(expl,expZ)menorentre public static double rnin (double pi, double p2)
expl.vexp2 public static float min (float pi, float p2)
public s t a t i c i n t min ( i n t pi, i n t p2)
public s t a t i c long rnin (long pl, long p2)
Como se puede apreciar a través de las cabeceras de los métodos, éstos están
redefínidos para que puedan trabajar con diferentes tipos de datos.
Métodos de coma flotante
~ ~
Invocación Significado Estructurade la cabecera de la declaración del miembro
Math.pow(a,b) ah palicstatic&aep <*pi,chhlep?)
Math.exp(a) ea public static double exp (double pi)
Math.cei1 (a) r.1 public static double ceil (double pi)
Math.floor(a) Lul public static double floor (-le pi)
Math.log(a) 'n (4 public static double long (double pl)
Math.sqrt (x) 6 public static double sqrt (double pi)
Math.round ( n ) redondeo al entero public s t a t i c long round (double pi)
(longo int) public s t a t i c i n t round ( f l o a t pi)
más cercano
log natural
Math.random ( ) número aleatorio' public s t a t i c synchronized double random ( )
Constantes de coma flotante
Invocación Significado
Math .E base del logaritmo natural public s t a t i c f i n a l double E
Math.PI p public s t a t i c f i n a l double P I
Estructurade la cabecerade la declaración del miembro
' La clase Random pertenecienteal paquete j ava.uti1ofrece un mayor número de posibilidadespara la gene-
ración de números aleatonos.Puede generar número aleatonos incluso siguiendo diferentes tipos de distribución.
j
Características del lenguaje Java 57
Funciones trigonométricas
Invocación Significado Estructura de la cabecera de la declaracióndel miembro
~
Math.sin (19) sen (19) public static double sin (double pi)
Math.cos (8) CUJ (8) public static double cos (double pi)
Math.tan (8) tg (8) public static double tan (double pl)
Math.asin(x) -u <arcsen(x)<u public static double asin (double pi)
Math.acos(x) O < urcm(x)<8 public static double acoc (double pi)
Math.atan (x) -yhrcfg(x)<D public static double atan (double pi)
2
Math.atan2 (a,b)-IIhrcrg(a)<Fl
2 - 2
public static double atan2 (doublepl, double p2)
b
Ejemplo
...
/ / Calculo del área de un círculo de radio 10
int r = 10;
double c = Math.pow(r,2)*Math.PI;
System.out.println(c);
...
2.16. PAQUETE java.math
El paquete java.math tiene las clases BigDecimal y BigInteger y sopor-
ta operaciones de coma flotante y enteros de precisión ampliada.
2.17. CONVERSIONES DE TIPOS. OPERADORES MOLDE
Con frecuencia se necesita convertir un dato de un tipo a otro sin cambiar el valor
que representa. Las conversiones de tipo pueden ser automáticas o explícitas, es
decir, solicitadas específicamente por el programador.
Conversiones automáticas
En las expresiones pueden intervenir operandos de diferentes tipos y, cuando esto
ocurre, para efectuar las operaciones Java intenta realizar conversiones automáticas
de tipo. Las conversiones automáticas que podrá efectuar son:
58 Java 2. Manual de programación
char
in long float double
byte short
Figura 2.1. Conversiones automáticas.
En la operación de asignación convierte el valor a la derecha del signo igual al
tipo de la variable, siempre que los tipos sean compatibles y esta operación no oca-
sione una pérdida de información, es decir, cuando se trate de conversiones como
las mostradas en la Figura 2.1.
Conversiones explícitas
Este tipo de conversiones utiliza los denominados operadores de conversión, molde
o cast, y puede ser necesario cuando se precisa un estrechamiento de tipo, conver-
sión en el sentido tipo más alto a tipo más bajo, o en casos como el siguiente para
generar una entidad temporal de un nuevo tipo.
. . .
int a = 5;
byte b = 5;
b = (byte)(b * 2);
/*si no se pone el molde da error ya que el
2 es entero y avisa que no se puede
convertir automáticamente int a byte * /
float c = a / b;
/*división entera. El operador división
funciona a dos niveles: entero y real * /
. . .
int a = 5;
byte b = 5;
b (byte)(b * 2);
float c = (floatla / b;
//división real
S a l i d a :
@.O 5 10
Salida:
0.5 5 10
El operador molde tiene la misma prioridad que los operadores unarios.
Mediante los operadores molde cualquier valor de un tipo entero o real puede ser
convertido a o desde cualquier tipo numérico, pero no se pueden efectuar conver-
siones entre los tipos enteros o reales y el tipo boolean.
2.18. OPERADORES ARITMÉTICOS
Los operadores aritméticos permiten realizar operaciones aritméticas básicas,
actúan sobre operandos numéricos y devuelven un resultado de tipo numérico. Los
Características de/ lenguaje Java 59
operadores aritméticos en Java pueden también actuar sobre operandos de tipo
char, ya que Java considera este tipo prácticamente como un subconjunto de los
i n t . Los operadores aritméticos de Java se muestran en la Tabla 2.14.
Tabla 2.14. Operadores aritméticos
- -~
Operador Significado Operador Significado
+ Operador unario + /
o Suma
División entera si los operandos son de
tipo entero
- Operador unario - / División real con operandos de tipo real
o Resta
* Mu1tip1icación % Módúlo, es decir, resto de la división
entera. No es necesario que los
operandos sean enteros
Ejercicio
Convertir un número de metros leídos desde teclado en un complejo de pies y pulgadas
sabiendoque 1 metro = 39.27 p u l g a d a s y 1 pie = 12 pulgadas.
package libro.Tema02;
import java.io.*;
public class Conversion
i
public static void main (String[] args)
I
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br= new BufferedReader(isr);
String cadena;
try
I
System.out.println ("Indique el número de metros y" +
cadena = br.readLine();
Double d = new Double(cadena);
double metros = d.doubleValue ( ) ;
double pulgadas = metros * 39.27;
double pies = pulgadas / 12;
pulgadas = pulgadas % 12; / / es posible aplicar % a reales
pies = pies - pulgadas / 12;
System.out .println("Conversión de metros en un complejo" +
System.out.println(metros + " metros son " + pies +
" pulse RETURN");
" de pies y pulgadas");
" pies y " + pulgadas + " pulgadas");
i
Manual Programaciòn
Características de/ lenguaje Java 61
2.19. OPERADORES RELACIONALES
Los operadores relacionales o de comparación permiten comparar valores para
determinar su igualdad u ordenación y el resultado de las expresiones en las que
intervienen es de tipo lógico. En cuanto a los operandos hay que tener en cuenta que
sólo los tipos numéricos se pueden comparar utilizando operadores de ordenación,
mientras que los de igualdad y desigualdad pueden actuar sobre cualquier tipo de
dato. La Tabla 2.15 lista los operadores relacionales.
Tabla 2.15. Operadores relacionales
Operador Nombre Ejempio Respuesta
_ __ _ Igual (operador formado por dos signos = consecutivos) 1 == 2 f a l s e
I = Distinto 1 ! = 2 t r u e
> Mayor que 1 > 2 f a l s e
< Menor que 1 < 2 t r u e
>= Mayor o igual 1 >= 2 f a l s e
<= Menor o igual 1 <= 2 t r u e
2.20. OPERADORES LÓGICOS
Los operadores lógicos o booleanos actúan sobre operandos de tipo lógico para
devolver un resultado también de tipo lógico. La Tabla 2.16 contiene la lista de los
operadores lógicos existentes en Java.
Tabla 2.16. Operadores lógicos
Operador Significado Operador Significado
& AND lógico 1 1 OR en cortocircuito
I OR lógico XOR
& & AND en cortocircuito I NOT unario lógico
h
Las reglas de funcionamiento son las siguientes:
El operador & da como resultado t r u e si al evaluar cada uno de los operandos
el resultado es t r u e . Si alguno de ellos es false, el resultado es false.
& & es análogo a &, pero si el primer operando es f a l s e , el segundo no es eva-
luado. Esta propiedad se denomina evaluación en cortocircuito. Por ejemplo,
la siguiente expresión evitaría calcular la raíz cuadrada de números negativos:
(X >= O) & & (Math.sqrt(x) >= 2 )
62 Java 2. Manual de programación
Tabla 2.17. Tabla de verdad del operador & &
~~~~
Operandol Operando2 Operandol 6h Operando2
f a l s e f a l s e f a l s e
f a l s e t r u e f a l s e
t r u e f a l s e f a l s e
t r u e t r u e t r u e
El operador 1 da como resultado f a l s e si al evaluar cada uno de los operan-
dos el resultado es f a l s e . Si uno de ellos es t r u e , el resultado es t r u e .
1 I es análogo a I , pero, cuando se usa, si el primer operando es t r u e , el
segundo no se evalúa.
Por ejemplo, en la siguiente expresión:
(10 > 4) 1 1 (num == O)
la sentencia num == O nunca se ejecutará.
Tabla 2.18. Tabla de verdad del operador I I
Operando 1 Operando 2 Operando 1 I I Operando 2
f a l s e f a l s e f a l s e
f a l s e t r u e t r u e
t r u e f a l s e t r u e
t r u e t r u e t r u e
El operador ! da como resultado f a l s e si al evaluar su único operando el re-
sultado es t r u e , y devuelve t r u e en caso contrario.
Tabla 2.19. Tabla de verdad del operador !
Operando !Operando
f a l s e
t r u e
t r u e
f a l s e
El operador ,,
da como resultado t r u e si al evaluar sus operandos uno de
ellos es true y el otro f a l s e , y devuelve f a l s e cuando ambos son t r u e y
también cuando ambos son f a l s e .
Características del lenguaje Java 63
Tabla 2.20. Tabla de verdad del operador A
Operando 1 Operando 2 Operando 1 Operando 2
f a l s e f a l s e f a l s e
f a l s e t r u e t r u e
t r u e f a l s e t r u e
t r u e t r u e f a l s e
2.21. OPERADORES DE MANIPULACIÓN DE BITS
Actúan sobre operandos de tipo entero modificando los bits de sus operandos
Tabla 2.21. Operadores de manipulación de bits
Operador Nombre
&
I
-
<< Desplazamiento a la izquierda
>>>
>> Desplazamiento a la derecha
AND a nivel de bit
OR a nivel de bit
NOT unario a nivel de bit
XOR
Desplazamiento a la derecha rellenando con ceros
A
Para trabajar con estos operadores es necesario tener presente que:
Java:
- Almacena los enteros como números binarios.
- Todos sus enteros, excepto los char, son enteros con signo, es decir,
- Los números negativos se almacenan en complemento a dos, es decir,
pueden ser positivos o negativos.
cambiando por ceros los unos del número y viceversa y sumando un
uno al resultado.
La Tabla 2.22, que describe las acciones que realizan los operadores & I A
y - sobre los diversos patrones de bits de un dato de tipo entero.
64 Java 2.Manual de programación
& sobre bits
A B A & B
O 0 O
o 1 O
1 0 O
1 1 1
I sobre bits * sobre bits -sobre bits
A B A I B A B A A B A - A
O 0 O O 0 O 1 O
o 1 1 o 1 1 O 1
1 0 1 1 0 1
1 1 1 1 1 O
El desplazamiento a la izquierda tiene el siguiente formato v a l o r << n y
mueve a la izquierda n posiciones los bits del operando, rellenando con ceros
los bits de la derecha.
O O O 1 1 1 O 1 v a l o r e s 2 9
tras v a l o r = valor << 3,el v a l o r es 232
o -24 si el primer 1 por la izquierda es el signo (complemento a dos)
1 1 1 0 1 0 O 0
. . .
byte c = 29;
int d = c << 3;
System.out.print1n (d);
byte e = (byte) (c << 3);
Systern.out.print1n (e);
S a l i d a :
232
-24
El desplazamiento a la derecha, valor >> n, mueve a la derecha n posi-
ciones los bits del operando, perdiéndose los bits de la derecha y rellenándose
los de la izquierda con el contenido del bit superior inicial, lo que permite con-
servar el signo.
Ibyte b = - 2;
int c = b >> 1;
//equivale a dividir por 2
int c = - 2;
c = c >> 1;
//equivale a dividir p o r 2
Systern.out.println(c); I systern.out.println(c);
I
S a l i d a -1 S a l i d a -1
Para efectuar desplazamientos a la derecha en datos de tipo i n t sin conservar el
signo el operador adecuado es >>>, que rellena con un cero el bit superior.
Características del lenguaje Java 65
System.out .print111(b);
...
byte b = - 2;
b = (byte) (b >>> 1 ) ;
System.out.println(c) ;
I . . .
b i t e b = - 2;
i n t c = b >>> 1;
i n t c = - 2;
c = c >>> 1;
System.out.println(c);
Sa 1i d a 2 147483647
2.22. OPERADORES DE ASIGNACI~NADICIONALES
Además del operador de asignación ya comentado, Java proporciona operadores de
asignación adicionales (Tabla 2.23). Estos operadores actúan sobre variables de
tipos simples como una notación abreviada para expresiones utilizadas con fre-
cuencia. Por ejemplo, el operador ++ permite la sustitución de la expresión a=a+l
por a+t. Los operadores ++ y -- necesitan una explicación adicional. Dichos
operadores se denominan de autoincremento y autodecremento respectivamente y
admiten su aplicación en dos formas, preJja y posGja, que adquieren importancia
cuando los mismos se usan dentro de una expresión mayor.
Prefija ++a
Postfíja a++
Ejemplo
...
i n t a,b, c;
a = b = 5 ;
c = a++ + ++b;
/ * c es el resultado de la suma del valor original de a
System.out .println(c+" "+a+" "+b);
con el nuevo valor de b * /
. . .
La s a l i d a es
11 6 6
Los operadores &=, 1 = y A = , cuando actúan sobre valores lógicos, son ope-
radores lógicos; si los operandos son enteros, son operadores de manipulación de bits.
66 Java 2.Manual de programación
Ejemplo
package libro.Tema02;
public class Operadores
I
Public static void main (String[] args)
boolean a=true;
a&=true;
System.out.println("true & true = "+a);
a&=false;
System.out.println
a&=false;
System.out.println
a&=true;
System.out.println
Tabla 2.23.
"true & false = "+a);
"false & false = "+a);
"false & true = "+a);
Operadores de asignación
Operador Nombre Ejemplo
-- Asignación simple int a = 5;
/ / a toma el valor 5
++ Incremento y asignación a++
/ / a vale 6
-- Decremento y asignación a--; / / equiva;e a a=a-1
/ / a vale 5
*= Multiplicación y asignación a*=4; / / a = a"4
//a toma el valor 20
/= División y asignación a/=2; //a = a/2
//a torna el valor de 10
*= Módulo y asignación a"--0-6; //a = a%6
//a vale 4
T = Suma y asignación a+=8; //a = a+8
/ / a vale 12
//a vale -11
<<= Desplazamiento a la, a<<=2; //a = a<<2
izquierda y asignacion //a vale - 4 4
>>= Desplazamiento a la a>>=6; / / a = a>>6
derecha y asignación //a vale -1
>>>= Desplazamiento a la derecha a>>>=24; / / a = a>>>24
y asignación rellenando con ceros //a vale 255
-_- Resta y asignación a-=23; //a = a-23
&=
I =
a=3;
Asignación AND o a&=6; //equivalen a a=3&6
AND sobre bits y asignación / / a vale 2
a=3;
Asignación OR o a 1 =6; //equivalen a a=3l6
OR sobre bits y asiganción //a vale I
a=3;
-- Asignación XOR o a^=6; //equivalen a a= 3 - 6
XOR sobre bits y asiganción //a vale 5
Características de/ lenguaje Java 67
2.23. OPERADOR CONDICIONAL
El operador condicional, ? : , es un operador ternario, es decir, requiere tres ope-
randos, y se utiliza en expresiones condicionales, devolviendo un resultado cuyo
valor depende de si la condición ha sido o no aprobada. El formato del operador
condicional es:
c o n d i c i o n ? operandol : operando2;
y conlleva la ejecución de las siguientes operaciones: se evalúa la condición; si
la condición es t r u e , el resultado es operandol, y si es f a l s e , es operando2.
Por ejemplo:
double comisión = ( v e n t a s > 150000)? 0.10 : 0.05;
si las ventas son superiores a 15OOOO, se adjudica el valor O .1O a comisión; en
caso contrario, se le adjudica O .05.
2.24. PRIORIDAD DE LOS OPERADORES
Las expresiones se evalúan siguiendo el orden de prioridad de los distintos opera-
dores que intervienen en ellas, atendiendo primero a los de mayor prioridad. A
igualdad de prioridad se evalúan de izquierda a derecha. Los paréntesis se pueden
utilizar con la finalidad de cambiar el orden preestablecido, ya que las operaciones
encerradas entre paréntesis siempre se evalúan primero. Cuando hay varios parén-
tesis anidados se calcula primero el resultado de las operaciones encerradas en los
más internos.
La prioridad, de mayor a menor, de los distintos operadores en Java aparece
reflejada en la Tabla 2.24, los operadores situados en la misma línea tienen igual
prioridad. En Java todos los operadores binarios, excepto los de asignación, se eva-
lúan de izquierda a derecha (asociatividad).
Consejo: Se pueden utilizar paréntesis para forzar un orden de evaluación, así
como facilitarla lectura de un programa.
68 Java 2. Manual de programación
Ejemplo
;Cuál es el valor de la siguiente expresión, teniendo en cuenta que i vale l?
5 + 4 * 4 > 5 * ( 5 + 4 ) - i t t
Recult a d 0
false
Ejercicio
Determinar si un ario leído desde teclado es o no bisiesto, teniendo en cuenta que
un año es bisiesto cuando es múltiplo de 4 y no lo es de 1 0 0 o si es múltiplo de
4 0 0 .
import java.io.*;
public class Prioridad
public static void main (String[] args)
I
InputStreamReader isr=new InputCtrearnReader(Systern.in);
BufferedReader br= new BufferedReader í -..) ;
String cadena;
try
i
System.out .print("Escriba el año co', 4 dígitos " ) ;
cadena = br .readLine ( ) ;
int año = Integer.parseInt(cadena);
boolean bisiesto = año % 400 == O 1 1
System.out.println(bisiesto);
I
catch(Exception e)
i
año % 100 ! = O & & año % 4 == O;
Cystern.out.println("Cualquier tipo de error");
Características de/ lenguaje Java 69
Tabla 2.24. Prioridad de los operadores
Operador Asociatividad
0 [I I - D
++ -- D- I
new ( t i p o ) D- I
/ % I - D
+ I - D
>> >>> << I - D
> >= < <= i n s t a n c e of I - D
__ ! = I - D
& I - D
I - D
I I - D
& & I-D
I 1 I - D
? : D- I
/= %= += -= >>= >>>= <<= &= ^ = / = D- I
- I
*
-
__
-- *=
3
Decisiones y bucles
CONTENIDO
3.1. La sentencia if.
3.2. La sentencia if-else.
3.3.
3.4. La sentencia switch.
3.5. La sentencia for.
3.6. La sentencia break.
3.7. La sentencia continue.
3.8.
3.9. La sentencia while.
Las sentencias if e if-else anidadas
Diferencias entre continue y break.
3.10. La Sentencia do-while.
71
72 Java 2. Manual de programación
En todos los lenguajes de programación existen construcciones
que permiten tomar decisiones basadas en una condición. Para
efectuar esta tarea Java dispone de las sentencias if,if-else y
switch. Un bucle es una sección de código que se ejecuta
muchas veces hasta que se cumple una condición de terminación.
Las sentencias disponibles en Java para la creación de bucles son
for,while y do-while.Este capítulo pretende introducirle en el
manejo de ambos tipos de sentencias.
Las sentencias selectivas controlan el flujo de ejecución en los
programas basándose en el valor de una expresión sólo conocida
en tiempo de ejecución. En Java existen sólo dos tipos de senten-
cias selectivas, if y switch,en las que la primera se puede con-
siderar a su vez dividida en dos clases, if e if-else.
Las sentencias repetitivas permiten repetir una acción o grupo
de acciones mientras o hasta que se cumple una determinada
condición. Java dispone de tres sentencias de este tipo: for,
whileydo-while.
3.1. LA SENTENCIA if
La sentencia i f permite en un programa tomar la decisión sobre la ejecuciódno ejecu-
ción de una acción o de un grupo de acciones, mediante la evaluación de una expresión
lógica o booleana. La acción o grupo de accionesse ejecutancuando la condiciónes cier-
ta y en caso contrario no se ejecutany se saltan.Los formatos para una sentencia if son:
i f ( condición)
sent encia;
if (condición)
i
//secuencia de sentencias
Ejemplo
. . .
double porcentaje = 0;
/ * Si las ventas son iguales o superiores a 300000 pts.
percibe un 12% de comisión, en caso contrario
no cobra comisión * /
porcentaje = 0.12;
i f (ventas >= 300000)
i n t prima = ( i n t ) (ventas * porcentaje);
Decisiones y bucles 73
Nota: La colocación de un signo de punto y coma después de la condición de
una estructura if constituye un error en la lógica del programa:
if (condición);
/ / si se cumple la condición no se ejecuta ninguna acción
sen tencia;
3.2. LA SENTENCIA if-else
Esta clase de sentencia i f ofrece dos alternativas a seguir, basadas en la conipro-
bación de la condición. La palabra reservada e l s e separa las sentencias utili/adas
para ejecutar cada alternativa. La sintaxis de la sentencia if-else es:
if ( c o n d i c i o n )
else
sen t e n c i a 1 ;
sen t e n c i a2;
if (condicicn)
Si la evaluación de la condición es verdadera, se ejecuta la scnteilc.ic// o la
secuencia de sentenciasl, mientras que si la evaluación es falsa se ejecuta la sew-
tencia2 o la secuencia de sentencias2. Es decir, que las sentencias a realbar tanto
cuando se cumple como cuando no se cumple la condición podrán ser simples o
compuestas. Posibles errores de sintaxis serían:
if ( condi cion) ;
s e n t e n c i a 1;
else
sen t e n c i a 2 ;
Nota: Es necesario recordar que Java proporciona un operador, el condicional,
capaz de reemplazar instrucciones if -e1se.
Ejercicio
Adivinar un número pensado por la computadora.
74 Java 2. Manual de programación
if más cercana, es cierir
zorzepor.de a1 seg.indo * /
import 4 a ~ a . i o . ~ ;
public c l a s s Juego
/ * a pesar de la sangría, este
e l s e corresponde al
primer if * /
public s t a t i c void main (String args[])
{ InpdtStrearrReader isr = new InputStrearnReader(Cystem.1n);
BcfferedReader br = new BufferedReader(isr);
Czr-ng cadena;
t r y .
Syste-;.o~t.pr;n:("Ir.troduzca un número entero entre 1 y 3 " ) ;
cader,a = ir.reaciline ( ) ;
i n t n = ( i n t ) (Math.random()*3)+1;
/ / Moz?..randrmO devuelve un cioubie aleatorio entre O.C y 1.0
i n t I= Integer.parseInt(cadeca);
i f (i == n)
else
Cystem.o¿it . p r i n t l n ("Acertó");
Cystem.out.prictln("No acertó, el número era "+n);
catch(Exceptivn e)
Cys:ei.ozt .print;n ( " C . ~ d l q u i e rtipo de error") ;

La estructura i f -e1se anterior podría haber sido sustituida por:
Cys:e?.c'~t .pr-~niln(i == n ? "Acertó" : "No acertó, era "+n);
3.3. LAS SENTENCIAS if E if- else ANIDADAS
Es posible que alguna de las sentencias a ejecutar especificadas en una instrucción
i f sea a su vez otra sentencia i f .
i f ( c o ~ d i z i ó c l )
i f (condlci6n2)
e l s e
ce.?te;:cla:;
seíi teEci a2;
i f ( c o n d i c i ó n l )
t
i f ( condi ción2)
sent e n c i a 1 ;
else
/ * la calabra reservada else se
corresponde cor la sentencia
sen t e n c i a 2 ;
Decisiones y bucles 75
if ( c o n d i c i ó n lj
if
else
( condi ci6n2j
sentencial;
cen t e ncia2;
if ( C o n d i i l c n 3 )
senten cia 3 ;
else
s e n t e n c i a d ;
else
/ / puede e x i s t i r a n i í i a c i ó n
/ / en ambas ramas
if ( c o n d i c i ó n i )
sen t e n c i a l ;
else
if ( c o n d i ción2j
sen t e n c i a 2 ;
/ / l a anidación en l a rama e l s e
/ / puede s e r u;: i f
if ( r o n d i c i ó c l j
seri t e n cia; ;
else
/ x E l 15 r, :?-else ari:3adz
pUede s e r i n a mks de i a
secuencia de s e z t e r e i a s
que s e pueder. C G ~ O Z ~ ~en
cualq,iera de l a c ZaTas * /
if ( c o n d i ci5,: )
sente:: iia1 ;
else
if ( c o c d i ~ i ó ~ ~ 2 )
else
ser tencia2;
sec r e,?ci5; 3;
/ * la an:íiac:ón e n la r a x ~
e l s e puede s e r czrz
if-eLse * /
La construcción i f - e ls e - if múltiple, también denominada de a/ternatiiu~
múltiples i f - e l s e , es muy habitual en programación y se suele escribir de la
forma siguiente:
if ( c o n d i c i ó n lj
s e n t e n c i a l ;
else if ( c o n d i c i o n 2 )
sen t e n c i a2;
else if ( c o n d i c i ó n 3 j
sen t e n c i a 3 ;
. . .
else if ( c o n d i c i ó n N )
else
sen t e n c i a N ;
sentenciax; //opcional
La sentencia anterior realiza una serie de test en cascada hasta que se produce
una de las siguientes condiciones:
Una de las cláusulas especificadas en las sentencias i f se cumple; en ese caso
la sentencia asociada se ejecuta y no se tiene en cuenta el resto.
76 Java 2. Manual de programación
Yinguna de las cláusulas especificadas se cumple y entonces, si existe, se eje-
cuta la últiiiia sentencia else.
Ejercicio
Programa que ordena de mayor a menor tres números leídos desde teclado.
import a: 2 . - 3 . * ;
public c l a s s Oruiena3
public s t a t i c void rnair, (String(: aryc)
l . , p ~ ~ t s t r c J m " e a d e ri c r = new I n p u t s t rearnxeader (S!ystem. i n ) ;
I-,ifieredReader hi = new BufferedReader ( i c r );
sr1-ing zzciena;
double a , 12, c;
t = Y
? y c t e T . c i t . p r i r a t ("2F.tr-oduzia ' ~ 3número " ) ;
.-acier,^ = b r .reaciLine ( ) ;
i b l e cil = new Cio¿ibie (cadena);
~ m . o i i t . p r i n t("Intoduzca otro iúnierc " ) ;
cdcienz = lar. reaaLine ( 1 ;
I ? c ~ b l e62 = new X & l e (caaer,a);
Sycterri.out . p r i n r ("In~roautcae; tercer nú?,ero " ) ;
iaciena = hr.readLii.e ( ) ;
Prxble ci3 = new 3c¿ble (caCena) ;
b = d2.dsubleValue ( ) ;
~ - d 3 . dsubleValue ( 1 ;
i f ( a > b)
. -
i f (o > c )
else
Systeri.out, .prlr?tir,( a f " "tbT" "Cc);
i f (c > a )
else
Sycte?.cct .println( c ~ ""tat" " A -- ) ;
Syctem.~u;.~rictln(a+" "Act" "+b);
else
i f ( a -,c )
else
3--iem.ou~.orir,tln( b t " "*;;,t" "+c);
i f ( c > I=)
else
s y c t e i . o c t . p r i n t i r . ( i t " "+b+" "+a);
Systerr,.out . p r i r l t l n (b+" " ~ c t ""ra);
1
catch(2xcecr:on e )
' I
Decisiones y bucles 77
Ejercicio
Obtener las soluciones, reales e imaginarias, de una ecuación de segundo grado.
import java.io.*;
public Class Ecuacion
i
public static void main (String[] args)
{
InputStreamReader isr = n e w InputStreamReader(Systern.in);
BufferedReader br = n e w BufferedReader(isr);
String cadena;
double a, b, c, xl, x2;
System.out .println("Introduzca los coeficientes") ;
Cystem.out.print ("a ? " ) ;
cadena = br .readLine ( ) ;
Double dl = n e w Double (cadena);
System.out.print ("b ? " ) ;
cadena = br.readLine();
Double d2 = n e w Double(cadena);
System.out.print ("c ? " ) ;
cadena = br.readLine ( ) ;
Double d3 = n e w Double (cadena);
a = dl .doublevalue ( ) ;
b = d2 .doublevalue( ) ;
c = d3.doublevalue ( ) ;
if (a==O)
System.out.println ("No es ecuación de segundo grado");
else
i
double d = (b*b-4*a*c);
if (d>O)
i
xl = (-btMath.sqrt(d)) / (2*a);
x2 = (-b-Math.sqrt (d)) / (2*a);
System.out.print1n ("xl = "txl);
Systern.out.println("x2 = "tx2);
1
else if (d==O)
(
x1=x2= (-b)/ (2*a);

else
i
'
Cystern.out.println("x1 = x2 = "txl);
d=Math.abs (d);
System.out.println("x1 = "+-b/ (2*a)t" +" +
Math.sqrt(d) / (2*a)t" i " ) ;
78 Java 2. Manual de programación
System.out.println("x2 = "t-b/ (2*a)+" - " f
Math.sqrt(d) / (2*a)t" i " ) ;
I
i
catch(Exception e)
i
System.out .println("Excepción "te);
//Exception es superclase
l
I
I
3.4. LA SENTENCIA switch
Cuando se tienen muchas alternativas posibles a elegir, el uso de sentencias if-
else-if puede resultar bastante complicado, siendo en general más adecuado en
estos casos el empleo de la sentencia switch. La sintaxis de una sentencia
switch es la siguiente:
switch ( e x p r e s i o n )
I
case c o n s t a n t e l :
sen t e ncias1;
//si se trata de múltiples acciones no es necesario
//encerrarlas entre llaves
break;
case constante2:
s e n t encias2;
break;
. . .
case constanteN:
' s e n tencia sN;
break;
sen t e nc i a sX;
default
i
Importante: En la sentencia s w i t c h la expresión ha de devolver un resulta-
do de tipo entero o carácter. La sentencia break se utiliza con la sentencia
s w i t c h para abandonar dicha sentencia tras la ejecución de las sentencias
asociadas a una determinada cláusula case,
El funcionamiento de la sentencia switch es el siguiente:
Decisiones y bucles 79
Cuando el valor de la expresión coincide con una constante de case, se
ejecutan el grupo de sentencias asociadas y si la Última sentencia de un grupo
es break, tras llegar a ella, el programa sale de la estructura switch. Si la
sentencia break se omite, la ejecución sigue en el siguiente grupo de senten-
cias, con independencia del valor de la constante case. Generalmente la pala-
bra reservada break se omite cuando se desea ejecutar la misma acción para
dos o más constantes de case.
La cláusula d e f a u l t es un caso especial de case. Las sentencias que vie-
nen a continuación de ella se ejecutan si ninguna de las constantes que siguen
a las diferentes sentencias case coincide con el valor de la expresión de
switch.
Para comprender mejor cómo utilizar la sentencia switch consideremos un
programa que muestra un menú de opciones (una de sus aplicaciones más típicas).
Ejemplo
Menú de opciones:
import java.io.*;
public class CelectMult
i
public static void main (String[] args)
t
try
( System.out.println ( i i ~ ~ ~ ú i i );
System.out .println("C. Cargar archivo");
System.out.println ("G. Grabar archivo") ;
System.out .println("I. Imprimir archivo");
System.out.println ("S. Salir del programa");
System.out.print ("Elija opción (C, G, I, S) " ) ;
char opcion =(char)Cystem.in.read() ;
System.in.skip(System.in.available());
switch (opcion)
t
case 'C' .. case 'c' :
Cystem.out.println("Ha seleccionado Cargar archivo");
break;
case 'G' : case 'g':
System.out.println("Ha seleccionado Grabar archivo");
break;
case '1'.. case 'i' :
System.out.println("Ha seleccionado Imprimir archivo");
break;
System.out.println("Ha seleccionado Salir de programa");
break;
case ' S I : case 's':
80 Java 2. Manual de programación
default:
System.out.println("Opción no válida") ;
1
1
catch (Exception e)
i )
En el programa anterior, cuando se pulsa la tecla s, se visualiza el mensaje Ha
seleccionado Salir de programa,y si pulsa la tecla Z, aparece el de
Opción no válida.Observe que se utilizan dos cláusulas case para permitir
al usuario introducir letras mayúsculas o minúsculas. Es decir, los múltiples case
se utilizan para permitir que una serie de condiciones proporcionen la misma res-
puesta.
Nota: En una sentencia switch no pueden aparecer constantes case iguales,
pero las sentencias a ejecutar en una sentencia switch pueden ser a su vez
sentencias switch y las sentencias switch anidadas sí pueden tener cons-
tantes case iguales.
3.5. LA SENTENCIA for
El bucle for está diseñado para ejecutar una secuencia de sentencias un número
fijo de veces. La sintaxis de la sentencia for es:
for ( i n i c i a l i z a c i ó n ; condición de terminación; incremento)
sentencias; //desde O a un bloque delimitado por { I
Las sentencias podrán ser cero, una única sentencia o un bloque, y serán lo
que se repita durante el proceso del bucle.
La i n i c i a l i z a c i ó n fija los valores iniciales de la variable o variables de
control antes de que el bucle for se procese y ejecute solo una vez. Si se desea ini-
cializar más de un valor, se puede utilizar un operador especial de los bucles for
en Java, el operador coma, para pegar sentencias. Cuando no se tiene que iniciali-
zar, se omite este apartado; sin embargo, nunca se debe omitir el punto y coma que
actúa como separador.
La condición d e termina ción se comprueba antes de cada iteración del
bucle y éste se repite mientras que dicha condición se evalúe a un valor verdadero.
Si se omite no se realiza ninguna prueba y se ejecuta siempre la sentencia for.
Decisiones y bucles 81
El i ncrement o se ejecuta después de que se ejecuten las sen tencias y antes de
que serealice la siguienteprueba de la condición d e terminación.Normalmente
esta parte se utiliza para incrementar o decrementarel valor de Mas variables de control
y, al igual que en la inicialización, se puede usar en ella el operadorcoma para pegar sen-
tencias.Cuando no se tienen valores a incrementar se puede suprimir este apartado.
En esencia, el bucle for comprueba si la condición de terminación es
verdadera. Si la condición es Verdadera, se ejecutan las sentencias del interior del
bucle, y si la condición es,fulsa, se saltan todas las sentencias del interior del bucle, es
decir, no se ejecutan. Cuando la condición es verdadera, el bucle ejecuta una iteración
(todas sus sentencias) y a continuación la variable de control del bucle se incrementa.
Nota:
Cada parte del bucle f o r es opcional.
Es frecuente que 14s variables de control de un f o r sólo se necesiten en el
bucle, en cuyo caso pueden declararse en la zona de inicialización.
Por ejemplo, para ejecutar una sentencia 1O veces se puede utilizar cualquiera
de los dos siguientes bucles for:
f o r ( i n t i=l; i<=lO;i++) i n t i;
System.out.println(i); for(i=l; i<=lO;i++j
System.out .println(i);
//Systern.out.println(ij; System.out.println(i);
/ / i no está definida //i vale 11
En estos ejemplos, la sentencia for inicializa i a 1,comprueba que i es menor
o igual a 1O y ejecuta la siguiente sentencia que muestra el valor de i.A continua-
ción se incrementa i y se compara con lO, como todavía es menor, se repite el
bucle hasta que se cumpla la condición de terminación (i = 11).
Si en lugar de una sola sentencia se desea ejecutar un grupo de sentencias, éstas
se encierran entre llaves.
for (i=l; i<=10;i++)
{
Systern.out.println(i);
System.out.println("i * 10 = "+i*lOj;

El siguiente bucle f o r , sin embargo, no ejecuta ninguna sentencia, sólo la ini-
cialización y los sucesivos incrementos de la variable de control hasta alcanzar la
condición de terminación:
for ( i n t i=l; i<=2000000000; i+t);
82 Java 2.Manual de programación
Los ejemplos anteriores muestran un incremento de la variable de control del
bucle, con lo que la cuenta, realmente, era siempre ascendente. Un bucle for puede
también decrementar su variable de control produciendo un bucle que cuente en
sentido descendente.
for(int 1=10; i>=l;i-)
System.out.println(i);
Nota: La variable de control de una sentencia f o r puede ser de cualquier tipo
simple.
for (dxble i=10; i>=l;i-0.5) for (&ar i='a' ; i<='z' ;i++)
System.out.println(i); System.out.print(i);
La expresión de incremento de un bucle for no siempre serán sumas o restas sim-
ples. Se puede utilizar cualquier expresión que tenga sentido en el problema que se está
resolviendo.Así por ejemplo, para visualizar los valores 1I 2 I 4I 8I 16 32I 64I 1 28
se puede utilizar la expresión i*2 para realizar el incremento.
for( i=l; i< 200; i*=2)
System.out.println (i);
Es posible usar el operador coma en las cláusulas de inicialización e incremento
for( i=O, j=14; (i+j>= O); i++, j - = 2 )
i
System.out.print (i+" + "+j+" = " ) ;
System.out.println(i+j);
1
Cada parte del bucle for es opcional, de forma que se pueden omitir las sec-
ciones de control si ese tratamiento es el adecuado para el problema a resolver. Por
ejemplo, el siguiente bucle for incrementa la variable de control del bucle, con
independencia del mecanismo de iteración:
for(i=l; i< 10;) it+;
O bien se puede omitir la sección de inicialización:
int i=O;
for(; i< 10; i++)
System.out.println (i);
Decisiones y bucles 83
Es posible poner como condición en un bucle for cualquier expresión de tipo
boolean,incluso expresiones no relacionadas con la variable de control.
Ejercicio
Determinar si un número entero leído desde teclado es o no primo.
import java.io.*;
public class NumPrimo
public static void main (String args [I )
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String cadena;
try
i
System.out.print ("Deme un número entero " ) ;
cadena = br .readLine ( ) ;
int i= 1nteger.parseInt (cadena);
boolean primo = true;
int raiz2 = (int)Math.sqrt(i);
for (int d=2; primo & & d <= raiz2; d++)
if (i % d == O)
primo = false;
if (i == O 1 1 !primo)
else
System.out.print("El "+i+" es compuesto") ;
System.out .print("El "+i+" es primo") ;
i
catch(Exception e)
i
1
System.out .println("Cualquier tipo de error");
3.6. LA SENTENCIA break
En apartados anteriores se usó la sentencia break con la sentencia switch para
abandonar dicha sentencia tras la ejecución de las sentencias asociadas a una deter-
minada cláusula case.La sentencia break se puede utilizar también con las sen-
tencias repetitivas, while, do-while y for para romper o salir de un bucle
cuando se produce alguna situación especial.
84 Java 2. Manual de programación
public class Brl
public s t a t i c void main (String[] args)
1
i n t n;
for (n=O; n<100; n++)
t
System.out.print (n+" " ) ;
i f ( n == 5 0 ) break;
I
1
I
Si hay bucles anidados, una sentencia break colocada en el bucle interno sus-
pende únicamente la ejecución de dicho bucle interior.
public class Br2
public s t a t i c void main (String[] args)
i
i n t n, m;
for (m =O; m<10; m++)
i
f o r (n=O; n<100; n++)
i
System.out.print (n+" " ) ;
i f (n == 5 0 ) break;
I
System.out.println();
1
Para abandonar una serie de estructuras anidadas puede utilizarse break et i -
quet a ; ,donde la etiqueta puede ser cualquier identificador válido. Cuando se eje-
cuta esta sentencia, el control se transfiere a la sentencia siguiente a un bloque
etiquetado con dicho nombre de e t i q u e t a seguido por el signo de dos puntos,
que, además, debe ser el que contenga la sentencia break et i q u e t a .
public class Br3
I
public s t a t i c void main (String[] a r g s )
i
i n t n, m;
parar:
t
for (m = O ; m < 10; mtt)
Decisiones y bucles 85
f o r ( n = O; n < 1 3 3 ; n--1
if (rn = y - 2 ) break p a r a r ;
Sylitern.o;t .print( n i " " ) ;
i f ( n 53) break;
S y s t e n i . o u : . p r i n t l n ( ) ;
} / / f ; n del bloque ccn la etiqueta
Syctern.out.println0;
S y c t e r n . o u t . p r i n t l n ( " F I N " );
3.7. LA SENTENCIA continue
La sentencia continue es similar a break,pero sólo se puede usar en bucles,
y, además, continue no salta fuera del bucle, simplemente salta sobre las sen-
tencias restantes del bucle y transfiere el control al final del bucle ejecutándose la
siguiente iteración del mismo. En consecuencia, una sentencia continue se uti-
liza para comenzar inmediatamente la siguiente iteración de un bucle. Se puede
utilizar continue con bucles for,while y do-while.El formato de CCR-
tinue es:
continue ;
Una sentencia continue en cualquier bucle f o r salta inmediatamente a la
expresión de control del bucle. En otras palabras, dado este bucle:
f o r ( s e n t e n c i a ; expresióni; expresión2)
i
i f ( e x p r e s i j n 3 ) continue;
sen tencia ;
i
si expresión3 es verdadera, la sentencia continue hace que se evalUe inme-
diatamente expresión2,saltándose todas la/s sentencia/s a ejecutar que viene/n
después de ella. Java permite el uso de etiquetas en la sentencia continue
continue e tiquet a ;
86 Java 2. Manual de programación
con las que especificar el bloque al que se aplica.
p u b l i c class Ccrti
public s t a t i c void rnair: (c;tr:ncj[ 1 clrcq:;)
i n t n , rn;
uno :
f o r (rn = O ; r r < l O ; m t t )
f o r (n=O; n i l O C ; n++)
System.out .prir.t(ni" " ) ;
i f (r. == 59) continue uno;
Cyster.oct.print..n( ) ;
Systen.oct.println0 ;
Cystem.c¿it .println ( " F I N " );
3.8. DIFERENCIAS ENTRE continue Y break
La sentencia continue fuerza una nueva iteración, mientras quc break fuerza la
salida del bucle. En el siguiente ejemplo, se muestra la diferencia entre ambas sen-
tencias. En el se observa como el mensaje " E l bucle" nunca se visualiza, pero
en cada bucle por una causa diferente (break en el primero y continue en el
segundo).
t
break;
Sys:ern.out .prin~ln("21 bucle");
f o r (1 =C; -<=;o;1 j t t )
continue ;
Cystern.out.prlntin( " E l bucle");
Otro ejemplo más completo para observar la diferencia de funcionamiento entre
break y continue es el que se muestra a continuación:
L
i
Decisiones y bucles 87
p u b l i c c l a s s B r y C
i
p u b l i c s t a t i c void mal-, ( Y t - i n j [ ] .,LJL)
i f ( c u e n t a > 5 ) continue;
Cystem.out.jrint (ciier.t,i.+" " 1 ;
I
Cyctem.o?it . p r ~ n t l r ,( ) ;
System.out .printin("Después del b i c l e : c i e n t a = ' I - -"-2cT.:<) ;
Cystem.out.print1n ( " C o m i e r i z c b e l bucle 'co?,r r c k " ) ;
f o r ( c ; i e n t a , 7 1; c1uent.a 1 1 2 ; (,Lientat+)
{
i f ( c u e n t a > 5) break;
Cystem.out .print (cue::t.ci+" " ) ;
I
System.out.pr;r,t 1 n ( ) ;
System.out . p r i n t l n ("3espués del s u c l e : c u e n t a 1 "~cuer.:a);
I
AI ejecutar el programa se observa que los bucles f o r cuentan hasta 5 y se
detienen. Después del primer bucle, sin embargo, el valor de c u e n t a es 11, y
después del segundo es 6. La razón es que en el segundo bucle b r e a k fuerza la
terminación y salida del bucle. Sin embargo, la sentencia c o n t i n u e , al igual
que b r e a k , sólo debe utilizarse cuando no existe otra alternativa. Por ejeniplo.
el listado
p u b l i c class Cont2
p u b l i c s t a t i c void main (Ctrinq:; arqc)
i
f o r ( i n t 2 = O ; i < 10; it+)
t
if ( i ! = 2 ) continue;
~ystem.out.println("; = "-1);
88 Java 2. Manual de programación
muestra sólo una línea, i 2. Si i es igual a O I 1, 3 I 4,5,6,7I 8,9,
continue salta sobre la sentencia System.o u t .println.Este caso es un mal
ejemplo de aplicación de continue,ya que se puede evitar reescribiendo el códi-
go de esta manera:
=
public class SinCont
public s t a t i c void r a i n (String[] a r T s )
f o r ( i n t : = O ; I < 13; ;tt)
if (: == 2 )
C y s t em.o1t.printIri ( " i = " t i );
3.9. LA SENTENCIA while
El bucle while ejecuta una sentencia o bloque de sentencias mientrus se cumple
una determinada condición; es decir, la acción o acciones se repiten mientras la con-
dición es verdadera. La sintaxis general de la sentencia while es:
while ( expresión) while (expresi Ón)
sen tencia; {
/ / s e c u e n c i a de sentencia-.

Si expresión es verdad, la sentencia o grupo de sentencias se ejecutan.
Cuando la expresión es falsa, el bucle while se termina y el programa reanu-
da su qjecución en la primera sentencia después del bucle.
i n t i=l;
while (1 <= 100)
Cyctem.out.println ("i = "+I);
:++:
iiiilc ejectitd la primera iteración ya que 1 tiene un valor menor que 100.
t incrementa su valor en 1a cada iteración, cuando I sea igual a 1O 1,lai
I 1 ~ <=IO O será falsa y el bucle se terinina.Un ejeniplo de su aplicación es
i 1 < . ;-)I ogiaina:
Decisiones y bucles 89
import java.io.*;
public class While1
i
public static void main (String args [I )
i
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String cadena;
int n=O ;
try
i
System.out.print ("Deme un número entero " ) ;
cadena = br .readLine ( ) ;
n = Integer .parseInt(cadena);
1
catch (Exception e)
i 1
int i=l;
while (i <= n)
i
System.out .println("Iteración: "+i);
i++;
1
1
1
La sentencia while es adecuada para muchas tareas. Un uso típico de while
en programación es asegurar entradas de usuario válidas. El programa solicita al
usuario si desea o no continuar con el programa mediante mensajes adecuados y
mientras el usuario no indica expresamente una respuesta negativa, no (por ejem-
plo, mediante la pulsación de la letra n o N), se sigue ejecutando el bucle.
import java.io.*;
public class While2
i
public static void main (String[] args)
i
try
i
System.out .print(";Desea continuar? ( C / N ) " ) ;
char resp =(char)System.in.read();
int num = Syctem.in.available~);
System.in.skip (num);
while (resp ! = 'n' & & resp ! = 'N' 1 1 num ! = 2)
Cyctem.out.println("Pulse n o N y RETERN para salir");
Cystem.out.print ( " ¿ D e s e a cont;nuar? ( S I " ) " ) ;
resp =(char)System.in.readO;
90 Java 2. Manual de programación
catchii ., I II 1
Al e-jecutar el prograiiia se solicita tina rcspiicstn al iisiiario y. iiiicntras el carác-
ter tecleado iio sea i i i i a letra N o n.el bucle se i-cpetiri iiideliriid~iiiiciitc.Otro tiso típi-
co de wh: le es procesar entradas de teclado. 1;ii i i i i i c h x aplicacioiies se cuele
so1icitar aI tisiiario qLie introduzca datos repetidaiiieiite h;i sta qiie dicho tisiiario intro-
diizca iin .alar que se coiisiciera de /c./.ini/itrc,iti/i. t;l lisíndo qiie se iiiuestra a conti-
nuación suiixi una secuencia arb¡traria de iiiiiiictos iiitroclucidos por teclado hasta qiie
se produce uii valor concreto (cii niicstro c:iso cl cero) qiic tcriiiina el bucle.
import ir* 3 . 1 .';
public c l a s s 15 11-
public s t a t i c void I I ( 1 1 7 ~ 1 1 I )
Decisiones y bucles 91
La sentencia while ejecuta el bloque de sentencias, mientras que num no sea
igual a cero. Cuando el usuario introduce un valor de entrada cero se termina el
bucle y se presenta en consola la suma resultante. Si el usuario comienza por intro-
ducir un cero, el bucle no se ejecutará y la suma será cero. Otro uso común de la
sentencia while es procesar dalos desde un archivo en disco. Esta operación es
similar a la entrada de datos por teclado con la diferencia de que los valores de
entrada se leen desde el archivo.
Un problema frecuente en programacion se produce cuando aparecen bucles
infinitos. Un bucle infinito es aquel que nunca termina. Los bucles while infinitos
se producen debido a que la condición que se comprueba nunca se hace falsa, de
modo que el bucle while ejecuta repetidamente sus sentencias una y otra vez. Si
se entra en un bucle infinito se podrá salir de él mediante la pulsación conjunta de
las teclas GYRI, y BRFAK ( r x i , t r i i ? m i < )
3.10. LA SENTENCIA do-while
La sentencia do-while es similar a la sentencia while,excepto que la expre-
sión se comprueba después de que el bloque de sentencias se ejecute (mientras
que la sentencia while realiza la prueba antes de que se ejecute el bloque de sen-
tencias). La sintaxis de la sentencia do-while es:
do
while (expresión);
sentencia;
do
sentencias;
while (expresión);
La/s s e n t e n c i a / s se ejecutan y, a continuación, se evalúa la expresión.
Si la expresión se evalúa a un valor verdadero, las sentencias se ejecutan de nuevo.
Este proceso se repite hasta que expresión se evalúa a un valor falso, en cuyo
momento se sale de la sentencia do-while.Dado que el test condicional se rea-
liza al final del bucle la sentencia o bloque de sentencias se ejecuta al menos una
vez.
Ejemplo
public class DoWhilel
i
public static void main (String[] a r g s )
i
int i = 1;
while ( i < 6)
i
92 Java 2. Manual de programación
Cystem.out .println("Bucle while "ti);
it+;
i
i = 1;
do
i
System.out.println ("Bucle d o - W ~ LLc " + i );
it+;
while (i < 6);
Cuando se ejecuta este programa, se visualiza:
Si se modifica el archivo anterior de modo que la expresión sea falsa la primera
vez que se ejecutan los bucles se puede observar la diferencia entre las sentencias
while y do-while.
Ejemplo
public class DoWhile2
public static void main (String/] args)
int i = 6;
while (i < 6)
t
System.out .println("Bucle while "ti);
i+t;
}
i = 6;
do
i
System.out.println ("Bucle do-while "ti);
it+;
while (i < 6);
1
Decisiones y bucles 93
Al ejecutar el programa anterior, se visualiza:
Bucle do-while 6
Ejemplo
Calcular el número de años que ha de estar invertido un capital para que se dupli-
que. Se proporcionarán desde teclado el tanto por ciento de interés y el capital
inicial.
import java.io.*;
public class Interes
i
public static void main (String[] args)
t
InputCtreamRedder isr = new InputStreamReader(System.inj;
BufferedReader br = new BufferedReader(isrj;
String cadena;
double capitalInicia1 = O;
double capitalFina1 = O;
double interes=O;
try
(
Cystern.out.print("Indique el capital inicial " ) ;
cadena = br .readLine ( ) ;
Double dl = new Double(cadena);
capitalInicia1 = dl.doubleValue();
capitalFina1 = CapitalInicial;
System.out.print ("Indique el % de interés " ) ;
cadena = br.readLine();
dl = new Double(cadena);
interes = dl .doublevalue ( ) ;
int años = 0;
do
I
años = años + 1;
capitalFina1 = capitalFina1 + capitalFinal*interes/lGO;
1
while (capitalFina1 < 2 * capitalInicial) ;
System.out.println("El número de años que ha de "+
"estar invertido para poder "+
"duplicarse es "+ años);
I
catch(Exception e)
(
1
1
1
Importante: En un bucle do-whi 1e si la expresión se evalúa a un valor ver-
dadero, las sentencias se ejecutan de nuevo.
4.3.
4.4.
4.5.
4.6.
4.7.
4.8.
4.9.
4.1O.
4.1I .
4.12.
4.13.
Acceso a Datos y Métodos.
Utilización de métodos.
Paso de parámetros.
Paso de parámetros por valor.
Paso de parámetros por referencia.
Constructores.
Modificadores de acceso.
private.
protected.
public.
Recursividad.
95
96 Java 2. Manual de programación
La programación en lenguajes procedimentales -tales como
BASIC, C, Pascal, Ada y COBOL- implica estructura de datos,
diseño de algoritmos y traducción de algoritmos en código. La pro-
gramación orientada a objetos es un tipo de programación que
introduce construcciones específicas llamadas objetos, que a su
vez contienen datos y procedimientos. Los objetos hacen la pro-
gramación más fácil y menos propensa a errores. Un programa en
Java implica un conjunto o colección de objetos que cooperan
entre sí. En este capítulo se introducen los fundamentos de pro-
gramación orientada a objetos: conceptos de clases y objetos,
declaración de clases, creación de objetos, manipulación de obje-
fosy cómo trabajan los objetos entre sí.
4.1. OBJETOS Y CLASES
Un objeto es una colección de datos y las subrutinas o métodos que operan sobre ellos.
Los objetos representan cosas físicas o abstractas, pero que tienen un estado y un com-
portamiento. Por ejemplo, una mesa, un estudiante, un círculo, una cuenta corriente, un
préstamo, un automóvil,...se consideran objetos. Así, ciertas propiedades definen a un
objeto y ciertas propiedades definen lo que hace. Las que definen el objeto se conocen
como campos de datos y el comportamiento de los objetos se define como métodos.
La Figura 4.1 muestra un diagrama de un objeto con sus campos de datos y métodos.
I campodato
1 I
campo dato
E L I
I método2 1Objeto
Figura 4.1. Un objeto contiene datos y métodos
Clases, objetos y métodos 97
Un objeto C i r c u l o contiene un campo de dato r a d i o que es la propiedad que
caracteriza un círculo. El comportamiento de un círculo permite calcular su super-
ficie y su longitud. Así, un objeto C i r c u l o se muestra en la Figura 4.2.
campo dato: radio
objeto C i r c u l o
método: calcularsuperficie
Figura 4.2.
Las clases son estructuras o plantillas que sirven para definir un objeto. En
una clase Java, se pueden utilizar datos para describir propiedades y métodos
que definen su comportamiento. Una clase de un objeto contiene una colección
de métodos y definiciones de datos. Si se diseña una clase que representa a un
cliente, no se ha creado un objeto. Un objeto es una instancia (ejemplar, caso) de
la clase C1i e n t e y, por consiguiente, puede, naturalmente, haber muchos obje-
tos de la clase C l i e n t e . La creación de una variable específica de un tipo par-
ticular de clase se conoce como instanciación (creación de instancias) de esa
clase.
Una clase describe la constitución de un objeto y sirve como plantilla para
construir objetos, especificando la interfaz pública de un objeto. Una clase tiene
un nombre y especifica los miembros que pertenecen a la clase, que pueden ser
campos (datos) y métodos (procedimientos). Una vez que se define una clase, el
nombre de la clase se convierte en un nuevo tipo de dato y se utiliza para:
Declarar variables de ese tipo.
Crear objetos de ese tipo.
El siguiente ejemplo representa una clase C i r c u l o que se utilizara para cons-
truir objetos del tipo C i r c u l o :
class Circulo
{
double radio =5.0;
double calcularsuperficie0
i
return radio*radio*3.141592;
98 Java 2. Manual de programación
objeto 1 de Circulo
Esta clase Circulo es, simplemente, una definición que se utiliza para decla-
rar y crear objetos Circulo.La clase Circulo no tiene un método main y por
consiguiente no se puede ejecutar. Corno estilo de escritura, en este libro se utiliza-
rán nombres que comienzan por mayúsculas para las clases. La clase se declara con
el siguiente formato:
objeto 2 de C i r c u l o
class Kcmbre
i
/ / cLerpo de la c l a s e
El cuerpo de la clase define los miembros úuto, mietnbro.s m¿todo o ambos.
Excepto en el caso de sohrecurgu, todos los miembros deben tener nombres
distintos.
4.2. DECLARACIÓN Y CREACIÓN DE UN OBJETO
Una clase es una plantilla que define los datos y los métodos del objeto. Un objeto
es una instancia de una clase. Se pueden crear muchas instancias de una clase. La
creación de una instancia se conoce como insluncicrcicjn.
clase Circulo

Figura 4.3. Una clase puede tener muchos objetos diferentes
Como ya se ha comentado, una vez que se define una clase, el nombre de la
clase se convierte en un nuevo tipo de dato y se utiliza tanto para declarar varia-
bles de ese tipo, como para crear objetos del inisino. La sintaxis para declarar un
objeto es:
NcrnbreClase combreObje to;
Ejemplo
C i r c ¿ i l o m i c i r c u l o ; / / declara l a variable micirculo
Clases, objetos y métodos 99
La variable micirculo es una instancia de la clase Circulo.La creación de
un objeto de una clase se llama creacirjn de una instancia de la clase. Un objeto es
similar a una variable que tiene un tipo clase. La creación de variables de un tipo de
dato primitivo se realiza simplemente declarándolas, esta operación crea la variable
y le asigna espacio en memoria:
i n t j;
I . Creución de la clase.
2. Declarar los objetos.
3. Crear los objetos.
Una vuriuhle de tipo c h s e es una vuriable referencia, que puede contener la direc-
ción de en memoria (o referencia) de un objeto de la clase o n u l l para una referen-
cia no válida. La declaración de un objeto simplemente asocia el objeto con una clase,
haciendo al objeto una instancia de esa clase. Lu declaración no crea el objeto. Para
crear realmente micirculo (objeto de la clase Circulo)se necesita utilizar el ope-
rador new con el objeto de indicar a la computadora que cree un objeto micirculo
y asigne espacio de memoria para ella. La sintaxis para crear un objeto es:
nombreobjeto = n e w Nombreclase 0 ;
Ejemplo
La siguiente sentencia crea un objeto, micirculo,y le asigna memoria:
micirculo = n e w Circulo O ;
Declaración e Instanciación
Se pueden combinar la declaración y la instanciacibn en una sola sentencia con la
siguiente sintaxis:
NombreClace nombreobjeto = n e w NombreClaseO;
Ejemplo
Creación e instanciación de micirculo en una etapa:
Circulo m i c i r c u l o = n e w Circulo ( ) ;
100 Java 2. Manual de programación
4.3. ACCESO A DATOSY MÉTODOS
Después de que se ha creado un objeto, se puede acceder a sus datos y métodos uti-
lizando la notación siguiente:
nombre0bjeto.datos
nombreObjeto.metodo()
Referencia a un dato de un objeto
Referencia a un método de un objeto
Ejemplo
miCirculo.radio radio de micirculo
miCirculo.calcularCuperficie() devuelve la superficie de micirculo
4.4. UTILIZACIÓN DE MÉTODOS
Los miembros de un objeto son los elementos dato, a los que también se puede
denominar variables de instancia, y los métodos. Los métodos son accioncs que se
realizan por un objeto de una clase. Una invocación a un método es una petición al
método para que ejecute su acción y lo haga con el objeto mencionado. La invoca-
ción de un método se denominaría también llamar a un método y pasar un mensa-
je a un objeto.
Existen dos tipos de métodos, aquellos que devuelven un valor Único y aquellos
que ejecutan alguna acción distinta de devolver un Único valor. El método
readInt es un ejemplo de un método que devuelve un Único valor de tipo i n t .
El método p r i n t l n es un ejemplo de un método que realiza alguna acción distin-
ta de devolver un valor único.
Nota: Existen dos tipos de métodos: aquellos que devuelven un Único valor y
aquellos que realizan alguna acción distinta de devolver un valor. Los méto-
dos que realizan alguna acción distinta de devolver un valor se denominan
métodos void.
La implementación de los métodos podría ser como ésta:
public class Cuentacorriente
i
private double saldo;
public void depositar (double cantidad)
saldo = saldo + cantidad;
saldo = saldo - cantidad;
public double ot>t.c:rierS~i1do ( )
’.
return caldo;
La ilumudu o invocución a un método se puede realizar de dos formas, depen-
diendo de que el método devuelva o no un valor.
1. Si el método devuelve un valor, la llamada al método se trata normalmente
como un valor. Por ejemplo,
int mayor -- m x ( 3 , 4 ) ;
llama al método max ( 3 , 4 ) y asigna el resultado del método a la variable
mayor.Otro ejemplo puede ser la llamada
System.out.println(max(3,4));
que imprime el valor devuelto por la llamada al método max ( 3, 4) .
2. Si el método devuelve void, una llamada al método debe ser una sentencia.
Por ejemplo, el método println ( ) devuelve void.La siguiente llamada
es una sentencia
System.out .println( “ C i e r r a de Cazorla”);
Si se considera ahora un objeto micuenta de la clase Cuentacorriente
Cuentacorriente micuenta;
una invocación al método depositar tendrá el formato
miCuenta.depositar(2400);
Cuando un programa llama a un método, el control del programa se trans-
fiere al método llamado. Un método llamado devuelve el control al llamador
cuando se ejecute su sentencia return o cuando se alcance la llave de cie-
rre 0).
102 Java 2. Manual de programación
4.5. PASO DE PARÁMETROS
La cabecera de un método especifica el número y tipo de parámetros formales
requeridos. Java no soporta parámetros opcionales o de longitud variable. En el
interior de una clase, un método se identifica no sOlo por SLI nombre, sino también
por su lista de parámetros formales. Por consiguiente, el mismo nombre de método
se puede definir mús de una vez con diferentes parámetros formales para conseguir
la sobrecarga de métodos.
Cuando se llama a un método, se deben proporcionar un número y tipo
correctos de argumentos. Los argumentos incluidos en la llamada a un método se
conocen como argumentos (parámetros) reales o simplemente argumentos. La
llamada a un método exige proporcionarle parámetros reales (actuales) que se
deben dar en el mismo orden que la lista de parámetros formales en la especifi-
cación del método. Esta regla se conoce como asociocicíii tiel orden de 10s pur&
metr'os .
Ejemplo
El método imprimirN imprime un mensaje n veces:
void irnprirnirN(String mensaje, int n)
i
for (int i=O; i<n; i + + )
Systern.out . p r i n t l n (mensaje);
1
1. Invocación correcta
Una invocación imprimirN( "Carchelejo", 4) imprime la palabra Carchelejo
cuatro veces. El proceso es el siguiente.
La invocación a imprimirN pasa el parametro real cadena,
"Carchelejo " , al parametro formal mensaje y el parametro real
4 a la variable n.
Se imprime 4 veces la frase Carchelejo.
2. Invocación incorrecta
La sentencia imprimirN(4, "Carchelejo") es incorrecta, ya que el tipo de
dato 4 no coincide con el tipo del parámetro mensaje y, de igual modo, el
segundo parámetro "Carchelejo''tampoco coincide con el tipo del segundo
parámetro formal n.
Clases, objetos y métodos 103
La operación de enlazar (hitiding) los argumentos reales a los argumentos for-
males se denomina puso de urgumetitos. Cuando se llama a un método con más de
un argumento, dichos argumentos se evalúan de modo secuencial, de izquierda a
derecha. Existen dos tipos de paso de parámetros: por valor y por referencia.
4.6. PASO DE PARÁMETROS POR VALOR
Todos los tipos de datos priinitivos ( i n t , long, float,boolean) se pasan en
los métodos por valor. En otras palabras, sus valores se copian en nuevas posicio-
nes, que se pasan a la subrutina (método); como consecuencia de esto, si un argu-
mento se cambia dentro de un método, no se cambiará en el programa llamador
original. El siguiente método no producirá un cambio en x:
void cambiarünidades ( f l o a t x, f l o a t f a c t o r )
. . .
t
x = x * fí.,ctor; / / x no se pUede mcdificar ec e- --a;acior
El único método sencillo para obtener un valor que se calcula dentro de una clase
es utilizar un método cuyo tipo no sea void que específicamente devuelva un valor.
f l o a t cay-oiar ( f l o a t x, f l o a t factor)
r e t u r n ( x * f a c t - o r ) ; / / el nuevc x se aev;lelve ai Llamaaor
I
4.7. PASO DE PARÁMETROS POR REFERENCIA
Los objetos, incluyendo arrays, se llaman tipos referencia, ya que se pasan en los
métodos por referencia en lugar de por valor. AI igual que se pueden pasar tipos pri-
mitivos, se pueden también pasar objetos a métodos como parámetros reales.
Existe una diferencia importante entre el paso de un valor de variables de tipos
de datos primitivos y el paso de objetos. El paso de una variable de un tipo primiti-
vo significa, como ya se ha comentado, que el valor de la variable se pasa a un pará-
metro formal. El cambio del valor del parámetro local en el interior del método no
afecta al valor de la variable en el exterior del método.
El paso de un objeto significa que la referencia del objeto se pasa a un paráme-
tro formal. Cualquier cambio al objeto local que suceda dentro del cuerpo del méto-
do afectará al objeto original que se pasa como argumento. Este tipo de paso de
parámetros se denomina paso por refkrencia.
104 Java 2. Manual de programación
Ejemplo
El objeto micirculo de la clase Circulo se pasa como argumento al método
imprimircirculo ( ) ;
C i r c u l o m i c i r c u l o = new C i r c u l o ( 1 0 . O ) ;
i r n p r i m i r C i r c u l o ( m i C i r c u 1 o ) ;
4.8. CONSTRUCTORES
Un constructor es un tipo especial de método que permite que un objeto se inicia-
lice a valores definidos para sus datos. El constructor tiene exactamente el mismo
nombre que la clase a la cual pertenece; es un método public,es decir, un méto-
do al que puede accederse desde cualquier parte de un programa.
Ejemplo
class MiClase
int micampo ;
public MiClase (int v a l o r ) //constructor
i
1
micampo = v a l o r ;
1
El constructor de una clase comienza con la palabra reservada public y después de
la palabra reservada pub1i c viene el nombre del constructor seguido por sus argumen-
tos entre paréntesis. Cuando se crea un objeto de la clase se deben proporcionartambién
los argumentos requeridos por el constructor. Los constructores se pueden sobrecargar,
lo que permite construirobjetos con diferentestipos de valores inicialesde datos.
Ejemplo
En la clase Circulo se pueden añadir los siguientes constructores:
C i r c u l o (double r )
i
r a d i o = r ;
C i r c u l o ( )
i
r a d i o = 4 . 0
Clases, objetos y métodos 105
Para crear un nuevo objeto Circulo de radio 6.O se puede utilizar la siguien-
te sentencia que asigna un valor 6 . O a micirculo.radio:
micirculo = new Circulo (6.O) ;
Si se crea un círculo utilizando la sentencia siguiente, se utiliza el segundo cons-
tructor que asigna el radio por defecto 4 . O a micirculo.radio:
micirculo = new Circulo ( ) ;
Advertencia: Los constructores son métodos especiales que no requieren un
tipo de retorno, ni incluso void.
Si una clase no tiene constructores, se utiliza un constructorpor defecto que no
inicializará los datos del objeto. Si no se utilizan constructores, todos los objetos
serán el mismo.
Ejemplo
Dada la clase
c l a s s MiClace
{
i n t micampo;
public Miclase( i n t valor)
t
1
micampo = valor;
1
Si se desea crear un objeto de una clase Miclase, se debe proporcionar un
valor entero que la clase utiliza para inicializar el campo dato micampo.Este ente-
ro es el único argumento del constructor de MiClase.Se creará un objeto de la
clase con una sentencia como ésta:
Esta línea de programa no sólo crea un objeto de la clase MiClase,sino que
inicializa el campo micampo al valor 5.
Ejercicio
El siguiente programa crea dos objetos Cir cu1o,de radios 1O y 2, y visualiza sus
superficies.
106 Java 2. Manual de programación
class T e s t C o n s t r u c t o r e s C i r - u l o
i
public static void main (String [ ! args)
i
//Circulo de radio 10.C
Circulo micirculo y new C i r c i i i l o (1:).ti) ;
Cystem.out.println("La superficie del r i rculo de radio ''A
miCirculo.rddiot" es "t
miCirculo.calc,JlarSuperficie( ) ) ;
//Circulo con radio por defecto
Circulo suCirculo = new C i r c i i l o ( ) ;
System.out .println( " L a superficie del circulo de radio " f
suCirculo.radio+" es " +
suCirculo.calcularCuperficie());
1
1
class Circulo
I
double radio;
Circulo (double r )
radio = r;
1
Circulo ( )
radio = 2.0;
i
double calcularsuperficie0
return radio*radio*3.14?592;
I
S a l i d a
La superficie del círculo de radio 10.0 es 314.1592
La superficie del círculo de radio 2.0 es 12.566368
Notas: La clase C i r c u l o tiene dos constructores. Se puede especificar un
radio o utilizar el radio por defecto para crear un objeto C i r c u l o . Así:
1. ElconstmctorCirculo (10. O ) seutilizaparacrearuncírculoconunradio 10.0.
2. El constructor C i r c u l o ( ) se utiliza para crear un círculo con un radio por
defecto de 2.0.
Los dos objetos creados m i c i r c u l o y s u c i r c u l o comparten los mismos
métodos y por consiguiente se pueden calcular sus superficies utilizando el
método c a l c u l a r s u p e r f i c i e .
Clases, objetos y métodos 107
4.9. MODIFICADORES DE ACCESO
Java proporciona modificadores para controlar el acceso a datos, métodos y cla-
ses, con lo que se consigue proteger a las variables y los métodos del acceso de
otros objetos. En Java, se pueden utilizar especificadores de acceso para prote-
ger a variables y métodos de una clase cuando ésta se declara. Existen cuatro
diferentes niveles de acceso: p r i v a t e , p r o t e c t e d , public y, si se deja sin
especificar, package. La Tabla 4.1 proporciona un resumen de los modifica-
dores.
Tabla 4.1. Modificadores de acceso
__ ~~ - ~
Modificador Clase Método Datos Comentario
(por defecto) -I 4 4 Una clase, método o dato es visible en este paquete
p u b l i c < v’ v’ Una clase, método o dato es visible a todos los programas
de cualquier paquete
p r i v a t e  t Un método o dato es sólo visible en esta clase
p r o t e c t e d v  Un método o datos es visible en este paquete y en las
subclases de esta clase en cualquier paquete
Nota: Un modificador que se puede aplicar a una clase se llama modificador
de clase. Un modificador que se aplica a un método se llama modificador de
método. Un modificador que se puede aplicar a un campo dato se llama modi-
ficador de datos.
Nota: El modificador p r i v a t e sólo se aplica a variables o a métodos. Si
public o p r i v a t e no se utilizan, por defecto, las clases, métodos y datos
son accesibles por cualquier clase del mismo paquete.
Precaución: Las variables asociadas con los modificadores son los miembros
de la clase, no variables locales interiores a los métodos. Utilizando modífica-
dores en el interior del cuerpo de un método producirá un error de compila-
ción.
1O8 Java 2. Manual de programación
4.10. private
El nivel de acceso más restrictivo es private.Un miembro privado sólo es acce-
sible en la clase en que está definido. Se utiliza este nivel de acceso para declarar
los miembros que se deben utilizar sólo en la clase. En realidad define los métodos
y los datos a los que sólo se puede acceder dentro de la clase en que están defini-
dos, pero no por las subclases.
El objetivo de private es proteger la información contenida en variables para
evitar que al ser accedido por un ((extraño))pongan al objeto en estado inconsisten-
te o bien para proteger a métodos que si se invocan desde el exterior puedan cam-
biar el estado del objeto o el programa en que se está ejecutando. De hecho, los
miembros privados son como secretos que no se difunden a ((extraños)).
Para declarar un miembro privado, se utiliza la palabra reservada private en
su declaración. La clase DemoPrivado contiene dos miembros privados: una
variable y un método.
public class DemoPrivado
private i n t datoprivado;
private void metodoPrivado ( 1
i
Syctem.out .println("Es un método privado") ;
Funcionamiento
1. El código del interior de la clase DemoPrivado puede inspeccionar o modi-
ficar la variable datoprivado y puede invocar al método
metodoPrivado,pero no lo puede hacer ningún código perteneciente a
otra clase.
2. Otra clase externa, ExternaDemo, no puede acceder a los miembros de
DemoPrivado.
class ExternaDemo
i
void rnetodoAcceco( )
i
DemoPrivado d = new DemoPrivado ( ) ;
d.datoprivado =loo; //no legal
d.metodoPrivado ( 1 ; //no legal
1
Clases, objetos y métodos 109
3. Cuando una clase intenta acceder a una variable a la que no tiene acceso el
compilador imprime un mensaje de error similar al mostrado en la Figura 4.4
y no compila el programa.
Figura 4.4. Error.
4. Sucede igual acción si se trata de acceder a un método privado.
4.11. protected
El especificador p r o t e c t e d permite que la propia clase, las subclases y las cla-
ses del mismo paquete, accedan a los miembros. Los miembros protegidos son
como los ((secretos familiares))compartidos por familiares, e incluso por amigos,
pero no por ((extraños)).Los miembros protegidos se declaran con la palabra re-
servada p r o t e c t e d . Consideremos la clase DemoProtegido que se declara
dentro de un paquete denominado Demo y que tiene una variable y un método pro-
tegidos.
package :~cro.TernzC4.Üeno;
public c l a s s CemsProtegido
I
protected i n t d a t c P r o t e q x i o ;
protected void m e t a d c 2 r o t e g i c i c O
S y c t e m . o ' i t . p r i n t ; n ("Es un Tétodo p r o t e g i u a " ) ;
1
Compilación
C:libroTernaG4Derno>javac DemoFrozeg;do.]ava
110 Java 2. Manual de programación
Funcionamiento
1. La clase OtraDemo es del paquete Demo, pero no es subclase de
DemoProtegido. La clase OtraDemo puede acceder legalmente a la
variable datoprotegido e invocar al método metodoProtegido:
package libro.Tema04.Demo;
class OCraDemo
void VetodoAcceso ( )
DemoProtegido d = new DemoProtegido ( ) ;
d.datoFrotegido = 100; //legal
d.metodoProtegido(); //legal
No produce problemas en la compilación
¿ :  ~ ~ b r o ~ ~ e m a C 4  D e m o > ~ a v a cOtraDemo.lava
2. Si OtraDemo fuera una subclase de DemoProtegido este código sería tam-
bién legal, ya que la clase esta en el mismo paquete que DemoProtegido .
3. Las subclases externas del paquete de la superclase también tienen acceso a
los miembros protegidos pero a través de una referencia al objeto:
package libro.Terna34.DemoBic;
import libro.Tema04.Demo.";
c l a s s NLeva extends CemoProtegido
void ?,etodoAcceco (DemoProtegido d, Nueva n )
t
d.datoprotegido = 100; //no legal
nAatcFrotegido = 100; //legal
d.metodoProteqido ( ) ; //no legal
n.metouoProteg;do(); //legal
1
Se puede acceder a los miembros protegidos a través de un objeto de la clase
Nueva,pero no a través de un objeto de la clase DemoProtegido que no seria
válido.
AI compilar el programa se producen errores (Fig. 4.5).
Clases, objetos y métodos 111
Figura 4.5. Errores
Aunque en algunos ejercicios ya se han usado paquetes y se ha visto de forma
práctica como trabajar con ellos, los conceptos sobre paquetes se explican con deta-
lle en el Capítulo 6.
4.12. public
El especificador de acceso public es aquel que define las clases, métodos y datos
de modo tal que todos los programas pueden acceder a ellos. Los miembros se
declaran públicos sólo si este acceso no puede producir resultados no deseables si
un ((extraño))a ellos los utiliza. Se declara a un miembro público utilizando la pala-
bra reservada public.Por ejemplo:
package NegocLos;
public class EBusinesc
public - i n t cantidad;
void operar 0
System.out .println(“Es .n método púbilcr”) ;
4.13. RECURSIVIDAD
Un método es recur.sivo cuando directa o indirectamente se llama a sí mismo. La
utilización de la recursividad es apropiada cuando el problema a resolver o los datos
a tratar han sido definidos de forma recursiva, aunque esto no garantiza que la mejor
forma de resolver el problema sea la recursiva. La recursión es una alternativa a la
iteración y las soluciones iterativas están más cercanas a la estructura de la compu-
tadora. La definición de factorial de un número (n! = n * (n - 1)!) para todo
número n mayor que O,teniendo en cuenta que 0! = 2 , es recursiva. La imple-
112 Java 2. Manual de programación
mentación se realiza de forma recursiva mediante un método f a c to r ia 1que se
llama sucesivamente a sí mismo.
p u b l i c class Funcion
//factorial recursivo
p u b l i c static long factorial ( i n t n)
!
i f ( n < O )
r e t u r n -1;
i f (n == O )
r e t u r n 1;
else
r e t u r n n * factorial (n-1);
p u b l i c class Prueba
t
p u b l i c s t a t i c void maic (String'] args)
Funcion f = new Funcion ( ) ;
Cysterk.out.println(f.factorial(4));
La función factorial también podría haber sido resuelta de forma iterativa
de la siguiente forma:
p u b l i c c l a s s Funcior.2
//factorial iterativo
p u b l i c s t a t i c long factorial (i;nt n)
i f (7.< O )
r e t u r n -1;
long fact = 1;
while (n > O)
fact = fact * n;
n--;
r e t u r n fact;
Todo algoritmo recursivo puede ser transformado en iterativo, para esta trans-
formación, en ocasiones, resulta necesario utilizar una pila. En el diseño de una
algoritmo recursivo es preciso tener en cuenta que:
Clases, objetos y métodos 113
La recursividad puede ser directa o indirecta.
El instrumento necesario para expresar los algoritmos recursivamente es el
método.
Un método presenta recursividad directa cuando se llama a sí mismo dentro
de su definición.
La recursividad indirecta consiste en que un método llame a otro que, a su vez,
contenga una referencia directa o indirecta al primero.
Un método recursivo debe disponer de una o varias instrucciones selectivas
donde establecer la condición o condiciones de salida.
Cada llamada recursiva debe aproximar hacia el cumplimiento de la o las con-
diciones de salida.
Cada vez que se llame al método los valores de los parámetros y variables
locales serán almacenados en una pila.
Durante la ejecución de dicho método, parámetros y variables tomarán nuevos
valores, con los que trabajará el procedimiento o función.
Cuando termine de ejecutarse el método, se retornará al nivel anterior, recupe-
rándose de la pila los valores tanto de parámetros por valor como de variables
locales y continuándose la ejecución con la instrucción siguiente a la llamada
recursiva. Hay que tener en cuenta que la recuperación de los datos almacena-
dos en una pila se efectúa siempre en orden inverso a como se introdujeron.
Los algoritmos recursivos en los que distintas llamadas recursivas producen
los mismos cálculos es conveniente convertirlos en iterativos. Un ejemplo de
esta situación es el cálculo de los números de Fibonacci,que se definen por
la relación de recurrencia f i b o n a c c i . . = f i b o n a c c i - i fibonac-
ci?.:,es decir, cada término se obtiene sumando los dos anteriores excepto
f i b o n a c c i = O y f i b o n a c c i = 1.La definición dada es recursiva y
su implementación se muestra a continuación tanto de forma recursiva como
iterativa. Obsérvense los diferentes tiempos de ejecución según se utilice uno
u otro algoritmo.
public class Fibcriacci
/ / F i b o n a c c i r e c u r s i v o
public s t a t i c long f i b o r . a c ¿ i r ( i n t n)
i f (n < O )
i f (n == O )
else
r e t u r n -1;
r e t u r n ( O ) ;
i f (I: := 1)
else
r e t u r n (11 ;
r e t u r n ( f i b T n a c c i r ( r i - 1 ) -fibonacc;r (ri-2) ) ;
1
114 Java 2. Manual de programación
//Fibsnacci i z e r a z i v o
public s t a t i c long f i b o n a c c i i ( i n t n )
long f = 3 , fsig = 1;
f o r ( i n t 1 = C ; i < n ; i t + )
long a u x = f s i g ;
f s i g += f;
f = a u x ;
r e t u r n ( f) ;
i
public s t a t i c void main (Str;-,g [ ] a r g s ) throws E x c e p t i o n
S y s z e ~ ~ . o u t . p r i n t l n( " V e r s i ó n I t e r a t i v a : " ) ;
f o r ( i n t i = O ; i <= 38 ; i t + )
S y s t e r n . o u i . p r ; r t l n ( " F i b o n a c c i-i t e r a t i v o ("+;+") "+
f i b o n a c c i i (i)) ;
C$'stem.cYt .print:?. ( "  r , P u l s e RETURN p a r a c o n t i ? , ' J a r  n " ) ;
Syszer;. ir.. r e a d ( ) ;
C y s ~ e m . i n . s k i s ( S y c ~ e m . ; ~ . . a v a i l a b l e0 ) ;
System.ouz.pr:ntln ( " V e r s i ó n r e c u r s i v a : " ) ;
f o r ( i n t i = U; i <= 38 ;I++)
System.out . p r i r . t l n ( " F i b o n a c c ; - r e c u r s i v o ("+i+")= "+
,
f i b o n a c c i r (i)) ;
En general, la recursividad debe ser evitada cuando el problema se pueda
resolver mediante una estructura repetitiva con un tiempo de ejecución signi-
ficativamente más bajo o similar. Teniendo en cuenta esta afirmación, la recur-
si idad debiera evitarse siempre en subprogramas con recursión en extremo
final que calculen valores definidos en forma de relaciones de recurrencia
siinples.
Ejercicio
Diseñar una clase Funcion3 con un método que permita calcular el máximo
común divisor de dos números enteros y positivos por el algoritmo de Euclides.
Para obtener el máximo común divisor de dos números enteros y positivos, a y b
por el algoritmo de Euclides, debe dividirse a ente b y, si el resto es distinto de cero,
repetir la división tras dar a a el valor de b y a b el resto. La condición de termi-
nación o de salida será cuando el resto sea cero.
public class Funcion3
Clases, objetos y métodos 115
//Máximo común divisor
p u b l i c s t a t i c i n t m c d ( i n t a , i n t b)
i f ( a < O I 1 b < O )
r e t u r n -1;
i f ( a '? b == O )
r e t u r n b;
else
r e t u r n mcd (b, a b);
1
//Programa para probar la clase creaaa
import java.io.*;
p u b l i c class Prueba3
i
Funcion3 f = new Funcion? ( ) ;
InputStreamReader i s r = new InputCtreamReacler(System.in);
BufferedReader br = new BufferedReacier(isr);
i n t nl = O , n2 = O;
t r y
i
System.out.print( " D e m e un número " ) ;
nl = Integer .parseInt(br.readLir.e( ) ) ;
System.out.print( " D e m e otro r.,Amero " ) ;
 n2 = Integer.parseInE (br.readline ( ) ) ;
Cystem.out.prict (f.mca(nl,n2)) ;
Cystem.out .print( " es el máximo común divisor e n t z e " ) ;
System.out.println(p1 + " y " + n2);
IOException e )
em.err .println ("Error de lectura");
Existen una serie de técnicas para el diseño de algoritmos que usan recursivi-
dad, entre las que destacan la estrategia de dividey vencerás y la de retroceso o
backtracking. La técnica divide y vencerás consiste en dividir un problema en dos
o más subproblemas, cada uno de los cuales es similar al original pero más peque-
ño en tamaño. Con las soluciones a los subproblemas se debe poder construir de
manera sencilla una solución del problema general. Para resolver cada subpro-
blema generado existen dos opciones, o el problema es suficientemente pequeño
o sencillo como para resolverse fácilmente de manera cómoda o si los subproble-
mas son todavía de gran tamaño, se aplica de forma recursiva la técnica de divide
y vencerás.
116 Java 2. Manual de programación
Hay un gran número de problemas cuya solución requiere la aplicación de méto-
dos de tanteo de forma sistemática, es decir, ir probando todas las opciones posi-
bles. La técnica de backtracking divide la solución del problema en pasos y define
la solución del paso i-L;simoen función de la solución del paso i-&.sirno+ 1. Si no
es posible llegar a una solución se retrocede para probar con otra posible opción.
I 5
Herencia
CONTENIDO
5.1. Descripción de herencia.
5.2. La clase base Object.
5.3. El método clone.
5.4. El método equals.
5.5. El método finalize.
5.6. El método tostring.
5.7. El método getclass.
5.8. Ventajas de la herencia.
5.9. Superclases y subclases.
5.1O. Modificadores y herencia.
5.11. Clases abstractas.
5.12. Métodos abstractos.
5.13. Interfaces.
5.14. Definición de una interfaz.
117
118 Java 2. Manual de programación
~~~~~
Una de las propiedades más sobresalientes de la programación
orientada a objetos es la herencia, un mecanismo que sirve para
definir objetos basados en otros existentes. Java soporta herencia
con extensión de clases, que permite definir una nueva clase
basada en otra clase ya existente sin modificarla. Tal nueva clase,
llamada subclase o clase extendida, hereda los miembros de una
superclase existente y añade otros miembros propios.
Java soporta herencia simple a través de extensión de clases.
En herencia simple una clase se extiende a partir de una única
superclase. Por ejemplo, una subclase Cuentacorriente se
puede extender (ampliar) de una superclase Cuenta o bien
Gerente de Empleado. Algunos lenguajes orientados a objetos,
como C++, soportan herencia múltiple, que es aquella en que una
subclase puede tener varias superclases. Java, por el contrario, no
soporta herencia múltiple aunque su funcionalidad puede ser con-
seguida mediante interfaces.
Este capítulo introduce al concepto de herencia. Específica-
mente examina superclases y subclases, el uso de palabras reser-
vadas, super y t h i s , 10s modificadores p r o t e c t e d , f i n a l y
a b s t r a c t , diferentes clases Útiles y el diseño de interfaces.
5.1. DESCRIPCIÓN DE HERENCIA
En terminología Java, la clase existente se denomina superclase. La clase derivada de
la superclase se denomina la subclase. También se conoce a la superclase como clase
padre y una subclase se conoce como clase hija, clase extendida o clase derivada.
La Figura 5.1 contiene la definición de una clase para estudiantes. Un estudian-
te es una persona, por lo que se puede definir la clase E s tudiante que se deriva
de la clase Persona.Una clase derivada es una clase que se define añadiendo
variables de instancia y métodos a una clase existente. En el ejemplo de la Figura
5.1, la clase Persona es la clase base y la clase Estudiante es la clase deriva-
da, Las clases derivadas tienen todas las variables de instancia y los métodos de la
clase base, más las variables de instancia y métodos que se necesiten añadir.
Persona 7
Figura 5.1. Jerarquía de clases.
Herencia 119
La definición de una subclase tiene la sintaxis siguiente:
public class nombrecldre extends C l a c e B a c e
Un ejemplo puede ser:
public class Estu=-ante extends Percoza
Nota: La herencia es siempre trunsitiva, de modo que una clase puede here-
dar características de superclases de muchos niveles.
Si la clase Perro es una subclase de la clase Mamífero y la clase
Mamífero es una subclase de la clase Animal,entonces Perro heredará atri-
butos tanto de Mamífero como de Animal.Se pueden reutilizar o cambiar los
métodos de las superclases y se pueden añadir nuevos datos y nuevos métodos de
las subclases. Las subclases pueden anular (redefinir) el comportamiento hereda-
do de la clase padre. Por ejemplo, la clase Ornitorrinco redefine el compor-
tamiento heredado de la clase Mamifero, ya que los ornitorrincos ponen
huevos.
/,---
Animal y
--.
+
-<- Mamífero
I
1 Perro y
A----- -.
%
-_I’ i.
Ornitorrinco
~~ ~
-_
Figura 5.2. Herencia y redefinición de comportamientos.
5.2. LA CLASE BASE Object
En Java todas las clases utilizan herencia. A menos que se especifique lo contrario,
todas las clases se derivan de una clase raíz, denominada Ob] ect.Si no se pro-
porciona explícitamente ninguna clase padre, se supone implícitamente la clase
Object.Así, la definición de la clase MiPrimerPrograma:
120 Java 2. Manual de programación
public class MiPrimerPrograma
!
public static void main (String [ I argsj
!
i
System.out .println("Mi primer programa Java" j ;
es igual que la siguiente declaración:
import java.lang.*;
public class MiPrimerPrograma extends Object
t
public static void main (String [ I argsj
I
Cystem.out .println("Mi primer programa Java");
1
i
La clase Ob] ect' proporciona la funcionalidad mínima garantizada que es
común a todos los objetos (Fig. 5.3).
Figura 5.3. Todas las clases son descendientes de la clase Object
' http://java.sun.com/products/jdk/I .3/docs/api/java/lanE/Object.htrnl
Herencia 121
La clase Obje c t define e implementa el comportamiento que cada clase del sis-
tema necesita. La clase Object esta en el nivel mas alto de la jerarquía y se
encuentra definida en la biblioteca java .l a n g . Cada clase del sistema Java es un
descendiente, directo o indirecto de la clase O bject.Esta clase define el estado
básico y el comportamiento que todos los objetos deben tener, tal como comparar
un objeto con otro objeto, convertir a una cadena, esperar una variable condición,
notificar a otros objetos que ha cambiado una variable condición o devolver la clase
del objeto. La clase Object proporciona una funcionalidad mínima que garantiza
un comportamiento común a todos los objetos. Estos objetos incluyen los métodos
siguientes:
public boolean equals ( J ava .lang.Object obj) Determina si el objeto del
argumento es el mismo que el
receptor. Este método se puede
anular para cambiar el test de
igualdad de clases diferentes.
Devuelve la clase del receptor,
un objeto de tipo Class.
Devuelve un kalor aleatorio
para este objeto. Este método
debe también ser anulado cuando
public final java.lang.Class getClacs0
public int hashcode ( )
public 1ava.lang.String tostring0
el método equals se cambia.
Convierte el objeto a un valor
de cadena. Este método se
anula también con frecuencia.
Regla: Los métodos de la clase O bject que se pueden anular o redefinir son:
clone
equals
finalize
tostring
Regla: Los métodos que no se pueden anular en la clase O bj ect,ya que son
final, son:
getclass
notify2
notifyAll
wait
Los métodos wa; t y notify se tratarán en el capítulo destinado a la programación multihilo.
122 Java 2. Manual de programación
5.3. EL MÉTODO clone
Se puede utilizar el método clone para crear objetos de otros objetos del mismo tipo.
Por defecto, los objetos no son clónicos, de modo que la implementación de este
método del objeto lanza una excepción CloneNotCupportedException . Si se
desea que la clase sea clónica, se debe impleinentar la interfaz Cloneable y anular
este método.
protected C'bjert c l o r . e ( ) throws CloneKotCupportedYxceptlon;
5.4. EL MÉTODO equals
Se utiliza para determinar la igualdad de dos objetos. Este método devuelve true
si los objetos son iguales y false en caso contrario. El siguiente código com-
prueba la igualdad de dos enteros (Integer):
Inieger Primero = new Integer(i);
Inieger CeguEdc = new Integer(i);
i f (iri~ero.eqLals(Cegunas))
Cystem.ouz.prinZln ( "L o s O b j e t o s son iguales");
Este programa indicaría que los objetos son iguales aunque referencian a obje-
tos distintos.
5.5. EL MÉTODO finalize
El método finalize no hace nada. Se redefine finalize para ejecutar opera-
ciones especiales de limpieza antes de que se recoleccione la basura correspon-
diente al objeto o cuando el programa termina.
protected void finalize ( )
La llamada
Syster.rxnFinalizercOnExit(true);
solicita la ejecución de los métodos finalize cuando un programa termina. Sin
la petición los métodos finalize no se invocan cuando termina un programa.
I En el Capítulo 13 e estudia el concepto de excepciones.
Herencia 123
Nota: Cuando se utiliza el operador new se reserva memoria, esta memoria no
es necesario liberarla, pues Java realiza una recolección de basura automática
mediante un hilo de baja prioridad, en realidad un demonio,proporcionado por
la máquina virtual de Java.
5.6. EL MÉTODO t o s t r i n g
El método tostring de Object devuelve una representación String del obje-
to. Se puede utilizar tostring junto con System.out .printlnpara visuali-
zar una representación de texto de un objeto, tal como el hilo (thread actual.
Syctern.out .println(Thread.current-hread() .toltr:ng ( ) ) ;
La representación String de un objeto depende totalmente del objeto. La
representación String de un objeto Integer es el valor entero visualizado como
texto. La representación String de un objeto Thread contiene diversos atribu-
tos sobre el hilo tal como su nombre y prioridad. Por ejemplo la salida de la ins-
trucción anterior podría ser:
Thread[main,5,mainl
5.7. EL MÉTODO getclass
El método getCl a ss es un método final que devuelve una representación en tiem-
po de ejecución de la clase del objeto. Este método devuelve un objeto Class.Se
puede consultar el objeto Class para obtener diversas informaciones sobre la
clase, tal como su nombre, su superclase y los nombres de los interfaces que im-
plementa.
public final java.lang.Clacs getclass0
Ejemplo
void imprimirNombreOb~eto(0bJectob])
Cystem.out.println ("La clase del o b j e t o e s "+
obj .getclass ( ) .getName ( ) ) ;
124 Java 2. Manual de programación
Si el objeto ob) pasado como parámetro fuera de tipo Integer,la llamada a
este método devolvería:
La clase del obleto es java.lang.Integer
5.8. VENTAJAS DE LA HERENCIA
El mecanismo de herencia presenta importantes ventajas:
Facilidad en la modificación de clases. Evita la modificación del código exis-
tente al utilizar la herencia para añadir nuevas características o cambiar carac-
terísticas existentes.
Extracción de commalidad de clases difirentes. Evita la duplicación de
estructuras/código idéntico o similar en clases diferentes. Sencillamente, se
extraen las partes comunes para formar otra clase y se permite que ésta sea
heredada por las demás.
Organización de objetos enjerarquía. Se forman grupos de objetos que con-
servan entre sí una relación ((es un tipo de)) (is u king oJ>. Por ejemplo, un
coche (carro) es un tipo de automóvil, un deportivo es un tipo de coche
(carro), una cuenta corriente es un tipo de cuenta, un ingeniero de sistemas
es un tipo de empleado, una matriz cuadrada es un tipo de matriz, manzana
reineta es un tipo de manzana.
9 Adaptación de programas para trabajur en situaciones similares pero dife-
rentes. Evita la escritura de grandes programas, si la aplicación, sistema
informático, formato de datos o modo de operación es sólo ligeramente
diferente, pues se debe utilizar la herencia para modificar el código exis-
tente.
5.9. SUPERCLASES Y SUBCLASES
Una clase extendida hereda todos los miembros de sus superclases, excepto
constructores y finalize,y afiade nuevos miembros específicos. En esencia,
una subclase hereda las variables y métodos de su superclase y de todos sus
ascendientes. La subclase puede utilizar estos miembros, puede ocultar las varia-
bles miembro o anular (redefinir) los métodos. La palabra reservada this.per-
mite hacer referencia a la propia clase, mientras que super se utiliza para
referenciar a la superclase y poder llamar a métodos de la misma (aunque esten
redefinidos).
Herencia 125
Regla: Una subclase hereda todos los miembros de su superclase, que son
accesibles en esa subclase a menos que la subclase oculte explícitamente una
variable miembro o anule un método.
Regla: Los constructores no se heredan por la subclase.
Una clase extendida es una clase compuesta con miembros de la superclase
(miembros heredados) y miembros adicionales definidos en las subclases (miem-
, bros añadidos). Los miembros que se heredan por una subclase son:
Las subclases heredan de las superclases los miembros declarados como
p u b l i c o p r o t e c t e d .
Las subclases heredan aquellos miembros declarados sin especificador de
acceso mientras que la subclase está en el mismo paquete que la superclase.
Las subclases no heredan un miembro de la superclase si la subclase declara un
miembro con el mismo nombre. En el caso de las variables miembros, la varia-
ble miembro de la subclase oculta (hides)la correspondiente de la superclase.
En el caso de métodos, el método de la subclase anula el de la superclase.
Las subclases no heredan los miembros privados de la superclase.
Nota: El término subclase se refiere simplemente a los mecanismos de cons-
trucción de una clase utilizando herencia y, es fácil de reconocer, a partir de la
descripción del código fuente por la presencia de la palabra clave extends.
5.1O. MODIFICADORES Y HERENCIA
El lenguaje Java proporciona diversos modificadores que se pueden utilizar para
modificar aspectos del proceso de herencia. Los modificadores que controlan el
acceso o visibilidad en la clase son: p u b l i c , p r o t e c t e d y p r i v a t e .
A m a característica p u b l i c , método o campo (dato público) puede acceder-
se desde el exterior de la definición de la clase. A una clase pública se puede
acceder fuera del paquete en el que está declarada.
A una característica p r o t e c t e d sólo se puede acceder dentro de la definición
de la clase en la que aparece, dentro de otras clases del mismo paquete o den-
tro de la definición de subclases.
126 Java 2. Manual de programación
A una característica private se puede acceder sólo dentro de la definición
de la clase en que aparece.
Otros componentes posibles de una declaración de clase son static,abs-
tract y final.Los campos dato y métodos se pueden declarar como static.
Un campo estático se comparte por todas las instancias de una clase. Un método
estático se puede invocar incluso aunque no se haya creado ninguna instancia de la
clase. Los campos de datos y métodos estáticos se heredan de igual modo que los
no estáticos, excepto que los métodos estáticos no se pueden anular (redefinir).
Regla:
static Define datos y métodos. Representa amplia información de la
clase que se comparte por todas las instancias de las clases.
public Define clases, métodos y datos de tal modo que todos los pro-
gramas puedan acceder a ellos.
private Define métodos y datos de tal modo que se puede acceder a ellos
por la declaración de la clase, pero no por sus subclases.
Nota: Los modificadores static y private se aplican aisladamente a
variables o a métodos. Si los modificadores public o private no se utili-
zan, por defecto las clases, métodos y datos son accesibles por cualquier clase
del mismo paquete.
Precaución:Las variables asociadas con modificadores son los miembros de
la clase, no variables locales dentro de los métodos. Utilizando modificadores
dentro del cuerpo de un método se producirá un error de compilación.
Los métodos y las clases se pueden declarar abstractas (abstract).Una clase
abstracta no puede ser ((instanciada)).Es decir no se puede crear una instancia de
una clase abstracta utilizando el operador new. Tal clase sólo se puede utilizar como
una clase padre para crear un nuevo tipo de objeto. De modo similar un método
abstract debe ser anulado (redefinido) por una subclase.
Un modificador alternativo, final,es el opuesto de abstract.Cuando se
aplica a una clase, la palabra reservada indica que la clase no se puede atender: es
decir, que no puede ser una clase padre. De modo similar, cuando se aplique a un
método la palabra reservada indica que el método no se puede anular y, en conse-
cuencia, el usuario tiene garantizado que el comportamiento de una clase no puede
ser modificado por una clase posterior.
Herencia 127
Nota: Se puede utilizar el modificador final para indicar que UT clase es
final y no puede ser una clase padre.
Regla:
abstract
final
static
La clase no puede ser instanciada.
Las clases no pueden ser subclasificadas.
Los campos static son compartidos por todas las instancias de
una clase.
Nota: Los modificadores se utilizan en clases y miembros de la clase (datos y
métodos). El modificador final puede utilizarse también en variables locales
en un método. Una variable local final es una constante interna al método.
5.11. CLASES ABSTRACTAS
En ocasiones, una clase definida puede representar un concepto abstracto y como
tal no se puede instanciar. Consideremos, por ejemplo, la comida en el mundo real.
;Se puede tener una instancia (un ejemplar) de comida? No, aunque sí se pueden
tener instancias de manzanas, chocolates, naranjas o peras. La comida representa el
concepto abstracto de cosas que se pueden comer y no tiene sentido que tenga ins-
tancias ya que no es un objeto concreto. Otro ejemplo puede ser la clase abstracta
FiguraTresDimensiones;de ella se pueden definir clases concretas (especí-
ficas), tales como Esfera,Cilindro,Cono,...
Las clases abstractas son Útiles para definir otras clases que sirvan para instan-
ciar objetos, pero de ellas no se pueden crear instancias utilizando el operador new.
El propósito de una clase abstracta es proporcionar una superclase a partir de la cual
otras clases pueden heredar interfaces e implementaciones. Las clases a partir de las
cuales se pueden crear instancias (objetos), se denominan clases concretas. Todas
las clases vistas hasta este momento son clases concretas, significando que es posi-
ble crear instancias de la clase.
Importante: Una clase abstracta es una clase que contiene los nombres de los
comportamientos sin las implementaciones que ejecutan esos comportamien-
tos. Los objetos no sepueden instanciar de una clase abstracta.
I
128 Java 2. Manual de programación
Uno de los objetivos de la programación orientada a objetos es reconocer los ele-
mentos que son comunes y agrupar esos elementos en abstracciones generales. Por
ejemplo, si se desea construir un marco de trabajo íJi-ameti?ork)de clases para figu-
ras geométricas, se puede comenzar con la noción general de «una figuran como
clase base. A partir de esta clase base se pueden derivar las clases de figuras espe-
cíficas, tales como Círculo o Rectángulo.
- -
Figura >-
-
c,/------- ---
/ -.
/
Rectángulo I

1’
- --
/’ Círculo
it__/
Figura 5.4. Herencia y jerarquía de clases.
Una clase se declara abstracta con la palabra reservada abstract.Una jerarquía
de clases no necesita contener clases abstractas, sin embargo, muchos sistemas orien-
tados a objetos tienen jerarquías de clases encabezadas por superclases abstractas. La
Figura 5.5 representa una jerarquía de figura de la que a su vez se derivan otras dos
clases abstractas, FiguraDos Dimensiones y FiguraTresDimensiones.
_ - -
Figura
--* -~~
,,’
,-/ - ~ - --.Figura 2 Dimensiones 3
-----7-
I /
__
’Figura 3 Dimension&
I - * - - %
Figura 5.5. Jerarquía de herencia de clases Figura.
Las clases abstractas son como las clases ordinarias con datos y métodos, pero
no se pueden crear instancias de clases abstractas usando el operador new.Las cla-
ses abstractas normalmente contienen métodos abstractos. Un método abstracto es
una signatura de un método sin implementación. Su implementación se proporcio-
na en sus subclases. Para declarar una clase abstracta tal como Figura se puede
hacer con la siguiente sintaxis:
abstract class Figura
I
Si se trata de instanciar una clase abstracta, el compilador visualiza un error
similar al mostrado en la Figura 5.6 y rechaza compilar el programa.
Herencia 129
1 4 1 I
Figura 5.6.
5.12. MÉTODOS ABSTRACTOS
Una clase abstracta es una clase definida con el modificador abstract que puede
contener métodos abstractos (métodos sin implementación) y definir una interfaz
completa de programación. Los métodos abstractos se implementan en las subclases.
Regla:
No todos los métodos se pueden declarar abstractos. Los siguientes métodos
no se pueden declarar como abstractos:
Métodos privados.
Métodos estáticos.
Ejemplo
Definir una clase abstracta ObjetoGeometrico. Esta clase debe contener entre
otros métodos, los de cálculo del área y perímetro de objetos geométricos. Dado que
no se conoce cómo calcular áreas y perímetros de objetos geométricos abstractos,
los métodos calcularArea y CalcularPerimetro se definen como méto-
dos abstractos. Estos métodos deben implementarse en las subclases. Suponiendo
una clase concreta Circulo como subclase de ObjetoGeometrico.
La posible implementación de la clase Circulo es como sigue:
public c l a s s C i r c ~ l oextends ObletoGeomeLrico
t
private double r a d i o ;
public C i r r u l c (double Y , String nom)
super (ncn?);
radio = z;
I
130 Java 2. Manual de programación
public Circslc ( )
/
t h i s (1.O, "Blanco");
public double devolverRadio ( )
t
return radio;
I
public double calcularArea ( )
return radio * radic * Math.FI;
public double caicularPerimetro ( )
return 2 * Math.PI * radio;
I
public String tostring ( )
return "Nombre = " t cuper.tcStrinq() t " radio = " t radio;
i
y la definición de la clase abstracta ObjetoGeometrico es:
a b s t r a c t c l a s s ObjetoGeometrico
private String nombre;
public ObjetoGeometrico(Strinq nom)
r.ombre = rom;
a b s t r a c t public double calcularkrea();
a b s t r a c t public double calcularPerimetro();
public String tostring ( )
r e t u r n norbre;
I
Como clase de prueba, se puede utilizar la siguiente clase Prueba:
import ]ava.io.*;
public c l a s s Prueua
public s t a t i c void mair (String'] argc)
Herencia 131
InputStreamReader isr = new InputStreamReader(Cystem.;n);
BufferedReader br = n e w BufferedReader(icr);
t=Y
i
Circulo uncirculo n e w Circulo ( ) ;
Systern.o u t .r>rin t1ri ( iinC ircu1o .tostring ( ) ) ;
Cystem.out.prlnt.ln("Area d e l circulo = " +
System.out .println("Longitud de la circunferencla = " +
Systern.out.println ("Introduzca el nomire y pulse RESiJRN") ;
String cadena = br.readLine ( ) ;
System.out .printin("Introduzca el radio y p u l s e RETURN") ;
String numero = br.readLine ( ) ;
Double d = n e w Double(nuner0) ;
double real y d.doubleValEe ( ) ;
Circulo otroCirc'Jlo = n e w Circulo (real, cadei.a);
Systern.out.println(otrcCirculo.toString() 1 ;
System.out.println ("Area del circulo = " +
Cystem.out.println ("Longitud de la rircunfereccia = " +
unCircuio.calcularArea());
unCirculo.calcularPerimetro());
otroCirculo.calcxlarArea()1 ;
otrocirculo.ca1cularPerírne:ro ( ) ) ;
1
catch(Exception e )
Cystem.out .println("Error");
Naturalmente se podrá crear también una subclase Cilindro que se extien-
de Círculo.
1..
._--_-~_ -
Objeto Geométrico ,
-_ _ ~- - -
A
1
Círculo /
4
- _
CiIindro /
Figura 5.7. Cilindro es una subclase de Circulo y Circulc
es una subclase de ObjetoGeometrico.
132 Java 2. Manual de programación
Consejo: Utilice clases abstractas para generalizar propiedades comunes y
métodos de subclases y utilice métodos abstractos para definir los métodos
comunes que deben ser implementados en subclases.
Precaución: Un método abstracto no puede estar contenido en una clase no
abstracta. En una subclase no abstracta extendida de una clase abstracta todos
los métodos abstractos deben ser implementados, incluso si no se utilizan en
la subclase.
Ejemplo
, Rectangulo
- _ .
ObjetoGráfico
Línea Círculo Cuadrado
Figura 5.8. Las clases heredan cierto estado y comportamiento
de su clase padre común O b ~ e t o ~ < r a f i c o .
abstract class SbjetoGrdfix
i n t x, y;
/ / . . .
void moveTo ( i n t nuevaX, i n t r i i ~ c ~ w Y )
t
1
/ / . . .
abstract void d i b cj a r ( 1 ;
c l a s s C i r c u l o extends Objetosrafico
void d;bu j a r ( )
i
/ / . . .
class Reerangulc! extends C b j e t o ( ; r , i f i c c
void dibujár ( )
i
}
/ / . . .
Herencia 133
Advertencia: Java vs. C++
Una diferencia fundamental entre métodos C++ y métodos Java es que los
métodos Java son virtuales por defecto. En otras palabras, Java proporciona el
mecanismo de envío virtual con cada jerarquía de clases, de modo que un
objeto, basado en su tipo y posición en la jerarquía, podrá invocar la imple-
mentación correcta de un método.
Cuando una clase derivada anula un método abstracto y proporciona una
implementación, debe hacerlo con el mismo nombre de método, lista de argu-
mentos y tipo de retorno.
Reglas:
Java utiliza la palabra reservada abstract
abstract public double calcularArea0;
que sirve como un modificador al método calcularArea ( ) . Cuando una
clase contiene al menos un método abstracto, el modificador abstract debe
aplicarse también a la declaración de clases
abstract class ObjetoGeometrico
No se pueden crear instancias de clases abstractas. Por ejemplo, la senten-
cia siguiente es ilegal:
ObjetoGeometricoalgunaFigura = new ObjetoGeometico("Blanco");
//Error
Ejemplo
Definamos la superclase E s tudiante y sus dos subclases, clases derivadas,
EstudiantePregrado y Estudiantepostgrado.En principio no parece
que tenga sentido crear instancias de la clase Estudiante,ya que un estudiante
puede ser de pregrado, de postgrado o puede ser otro tipo de estudiante (de forma-
ción profesional, idiomas, bachiller, etc.), por tanto, declararemos la clase estudian-
te como abstracta.
abstract c l a s s Estudiante
i
protected f i n a l s t a t i c i n t NUM-DE-PRUEBAS = 3 ;
protected String nombre;
134 Java 2. Manual de programación
/ / vea el capítulo sobre arrays
protected i n t [ ] prueba;
protected String calificacion;
public Estudiante ( )
t h i s ("Ningun nombre") ;
1
public Sstudiante(Ctrlny nornbreEstudiante)
nombre = nombreEstudiante;
prueba = new i n t [NUM-DE-PRUEBAS];
calific-cion = "*****".
I
/ / rretodo abstracto
abstract public void ~alcularCdlificdcion();
public String 1eerNombre ( )
i
r e t u r n nombre;
I
public i n t 1eerNotacPruebas ( i n t riumPriicha)
r e t u r n prneba [ numPrueba - 1I ;
1
public void ponerNombre (String niievoNombre)
t
1
nombre = nuevoNombre;
public void fijarNotacPruebas ( i n t numPrueba, i n t notaprueba)
t
1
prueba [numPrueba - 11 = notaprueba;

5.13. INTERFACES
El lenguaje Java soporta interfaces que se utilizan para definir un protocolo de com-
portamiento que se puede implementar por cualquier clase en cualquier parte de la
jerarquía de clases.
Definición: Una interfaz (intersace)en Java es una descripción de comporta-
miento.
Herencia 135
En esencia, una interfaz es un sistema o dispositivo que utiliza entidades no rela-
cionadas que interactúan. Ejemplos de interfaces son un mando a distancia para
televisión, que es una interfaz entre el espectador y un aparato de televisión, un
navegador de Internet, que es una interfaz entre el internauta y la red Internet.
Las interfaces en Java tienen la propiedad de poder obtener un efecto similar a
la herencia múltiple que soportan otros lenguajes como C++. Si se utiliza la palabra
reservada extends para definir una subclase, las subclases sólo pueden tener una
clase padre. Con interfaces se puede obtener el efecto de la herencia múltiple. Una
interfaz se considera como una clase especial en Java. Cada interfaz se compila en
un archivo independiente bytecode tal como una clase ordinaria. No se pueden crear
instancias de una interfaz. En la mayoría de los casos, sin embargo, se puede utili-
zar una interfaz de un modo similar a como se utiliza una clase abstracta. Una inter-
faz Java define un conjunto de métodos, pero no las implementaciones, así como
datos. Los datos, sin embargo, deben ser constantes y los métodos, como se acaba
de indicar, sólo pueden tener declaraciones sin implementación.
,
Sintaxis
m o d i f i c a d o r interface Nombre Int e r f a z
t
//decldraciones de constantes
//declaraciones de los métodos
Definición: Una interfaz es una colección con nombre de definiciones de mé-
todos (sin implementaciones) que puede incluir también declaraciones de
constantes.
Una interfaz se puede considerar una clase abstracta totalmente y en ella hay que
tener en cuenta que:
Todos los miembros son públicos (no hay necesidad de declararlos piblicos).
Todos los métodos son abstractos (se especifica el descriptor del método y no
Todos los campos son staticy final(proporcionan valores constantes Útiles).
hay ninguna necesidad de declararlos abstract).
5.14. DEFINICIÓN DE UNA INTERFAZ
Una definición de interfaz consta de dos componentes (Fig. 5.9): la declaración de
la inteyfaz y el cuerpo de la intwfaz.
136 Java 2.Manual de programación
declaración
de interfaz + public interface Compararobjetos
i
public static final int MENOR ~ 1;
de public static final int I CIJA1 O ;
public static final int MAYOR - 1;
cuerpo de constantes
la interíaz
public int comparar (CompararObjetos otroOb1eto);
1
de métodos
Figura 5.9. Definición de una interfaz.
La declaración de la interfaz declara diversos atributos acerca de la interfaz, tal
como su nombre y si se extiende a otra interfaz. El cuerpo de la interfaz contiene
las declaraciones de métodos y constantes dentro de la interfaz.
Consejo: Las clases abstractas y los interfaces se pueden utilizar para conse-
guir programación genérica. Se deben utilizar interfaces si se necesita heren-
cia múltiple. Si la herencia que se necesita es simple, es suficiente el uso de
clases abstractas. Normalmente el uso de una clase abstracta es mayor que el
uso de una interfaz.
Ejemplo
Diseñar un método de ordenación genérico para ordenar elementos. Los elemen-
tos pueden ser un array de objetos tales como estudiantes, círculos y cilindros.
En este caso se necesita un método genérico comparar para definir el orden de
los objetos. Este método deberá adaptarse para que pueda comparar estudiantes,
círculos o cilindros. Por ejemplo, se puede hacer uso del número de expediente
como clave para la comparación de estudiantes, del radio como clave para la com-
paración de círculos y del volumen como clave para la comparación de cilindros.
Se puede utilizar una interfaz para definir el método genérico comparar del modo
siguiente:
public interface CompararObleto
public static final int MENOS = -1;
public static final int IGUAL = O;
public static final int MAYOR = 1;
public int comparar(Comparar0bjeto unobjeto);
Herencia 137
El método comparar determina el orden de los objetos a y b del tipo
CompararObjeto.La instrucción a.comparar (b)devuelve un valor -1 si a
es menor que b,un valor de O si a es igual a b o un valor de 1si a es mayor que
b. Un método genérico de ordenación para un array de objetos CompararObje t o
se puede declarar en una clase denominada Ordenar:
public class Ordenar
public void ordenar (CompararObjeto[ ] x)
t
/ / vea el capítulo sobre arrays
CompararObjeto maxActual;
int indiceMaxActua1;
for (int i = x.length-1; i >= 1; i--)
i
maxActua1 = x[11;
indiceMaxActua1 = i;
for (int 7 = i-1; j >= O; I--)
if (maxActua1.comparar (x[ 7 ] j ==-1)
í
rnaxActua1 = x[]I;
indiceMaxActua1 = 1 ;
/ * intercambiar x [i] ron x[indiceMaxActua:;
si fuera necesario * /
if (indiceMaxActua1 ! = ij
x [ indiceMaxActua1 I = x [ il ;
x[i] = maxActual;
I
I
Nota: La clase Ordenar contiene el método ordenar. Este método se basa
en algoritmos de ordenación.
138 Java 2. Manual de programación
Precaución: La definición de una interfaz es similar a la definición de una
clase abstracta. Existen, sin embargo, unas pocas diferencias:
En una interfaz los datos deben ser constantes; una clase abstracta puede
tener todo tipo de datos.
Cada método de una interfaz tiene sólo una signatura sin implementación;
una clase abstracta puede tener métodos concretos.
Ningún modificador abstracto aparece en una interfaz; se debe poner el
modificador abstract antes de un método abstracto en una clase abstracta.
Un método genérico de búsqueda de un determinado objeto en un array de obje-
tos CompararObje t o ordenado ascendentemente se puede declarar en una clase
denominada Buscar como la que se expone a continuación. Los métodos de orde-
nación y búsqueda se explican en el capítulo destinado a arrays,
public class Bcscar
private int Busqueja-binaria (CompararObjeto [ 1 x, int iz,
int de, CompararCbjeto unobjeto)
int central = (iz+de)/2;
if (de < iz)
í / devuelve un r.ú.eroRegativo cuando no encuentra el elemento
if ( i n O b J e t o .comparar (x[central]) == CompararObjeto.MEN0S)
else if (ur.3bjeto.cornparar(x[central]) == CompararObjeto.MAYOR)
else
return(-iz) ;
return(Busqceda-binaria (x,iz,central-1,unobjeto)) ;
return(E.Jsqueda-Dinaria (x,centrait 1,de,.dnObjeto)) ;
//devuelve la posición donde se encuentra el elemento
return(centra1);
i
public int bbin (CompararCb]etc[] x, CompararObjeto unobjeto)
return(BLsqJeda-tinaria (x, O, x.,ength, un0bjeto)) ;
Regla: Una vez que se ha definido una interfaz, el nombre de la interfaz se
convierte en el nombre de un tipo. Cualquier clase que implemente la interfaz
se convierte en un subtipo de ella. Una interfaz es un contrato entre proveedo-
res y clientes de un servicio particular. El diseño de una interfaz afecta a las
funcionalidades y capacidad en el lado proveedor y las complejidades y con-
veniencias en el lado cliente.
Herencia 139
Ejemplo
Considerar una interfaz Ordenable.
public interface Ordenable
i
/ * Comparar elementos i y J
para el elemento~ i >, == , < elemento-j devuelve
>O, O, <O si la dirección esta CRECIENDO
<O, O, >O si la dirección esta DECRECTENDO
* /
int comparar(int i, int j);
/ / Intercambia elementos i y j
void intercambio( int i, int j);
/ / Indice del primer elemento
int primero ( ) ;
/ / Indice del Último elemento
int ultimo ( ) ;
/ / Bandera para indicar dirección de order.ación
boolean ordenado ( ) ;
void ordenado (boolean b) ;
/ * Indicador de dirección para
CRECIENDO o DECRECIENDO
* /
void direccion (int dir);
int direccion ( ) ;
/ / Valores de indicadores de direcciones posibles
static final int CRECIENTE = 1;
static final int DECRECIENTE = -1;
6
Encapsulamiento
y poiimortismo
CONTENIDO
6.1. Encapsulamiento.
6.2. Modificadores de clases.
6.3. Modificadores de variables.
6.4. Modificadores de métodos.
6.5. Clases internas.
6.6. Paquetes.
6.7. Declaración de un paquete.
6.8. Paquetes incorporados.
6.9. Acceso a los elementos de un paquete.
6.10. Importación de paquetes.
6.1I . Control de acceso a paquetes.
6.12. Polimorfismo.
6.13. Ligadura.
6.14. Ligadura dinámica.
141
142 Java 2.Manual de programación
Este capítulo examina las importantes propiedades de Java en-
capsulamiento y polimorfismo.La programación orientada a objetos
encapsula datos (atributos) y métodos (comportamientos) en
paquetes denominados objetos. La ocultación de la información y
abstracción,como términos sinónimos, gestiona la visibilidad de los
elementos de un programa.
Encapsulamiento es un término muy utilizado para significar
que los datos y las acciones se combinan en un Único elemento (un
objeto de las clases) y que los detalles de la implementación se
ocultan. El término polimorfismo significa <<múltiplesformas,, (poly
= muchos, morphos = forma). En lenguajes orientados a objetos, el
polimorfismo es un resultado natural de la relación es-un y los
mecanismosdel paso de mensajes, herencia y el concepto de sus-
titución. El polimorfismo es una de las propiedades clave de un tipo
de programaciónconocida Comoprogramación orientadaa objetos.
El polimorfismo permite a los programadores enviar el mismo men-
saje a objetos de diferentes clases. Existen muchas formas de poli-
morfismo en Java. Por ejemplo, dos clases diferentes pueden tener
métodos con el mismo nombre.
6.1. ENCAPSULAMIENTO
Encapsulamiento es un término que se utiliza en las modernas técnicas de programa-
ción. Encapsulamiento significa que los datos y las acciones se combinan en una sola
entidad (es decir, un objeto de la clase) y se ocultan los detalles de la implementa-
ción. La programación orientada a objetos (POO) encapsula datos (atributos) y
métodos (comportamientos)en objetos. Los objetos tienen la propiedad de ocultación
de la información. Esta propiedad significa que aunque los objetos pueden conocer
cómo comunicarse unos con otros a través de interfaces bien definidas, no pueden
conocer cómo están implementados otros objetos (los detalles de la implementación
están ocultos dentro de los propios objetos). Ésta es una situación muy frecuente del
mundo real. Es posible conducir con eficacia un automóvil sin conocer los detalles
internos de cómo funciona el motor, el tren de engranajes o el sistema de frenos.
En Java se tiene un gran control sobre el encapsulamiento de una clase y un objeto.
Se consigueaplicandomodificadoresa clases,variables de instanciay de clases,y méto-
dos. Algunos de éstos modificadores se refieren al concepto de paquete, que se puede
considerar básicamente como un grupo de clases asociadas.
6.2. MODIFICADORES DE CLASES
Se puede cambiar la visibilidad de una clase utilizando una palabra reservada, modifi-
cador, antes de la palabra reservada class en la definición de la clase, por ejemplo:
Encapsulamiento y polimorfismo 143
public class P e r s o n a
I
...
i
Una clase pública se define dentro de su propio archivo y es visible en cualquier
parte. Una clase que es local a un paquete específico no tiene modificador y se
puede definir dentro de un archivo que contiene otras clases. Como máximo, una de
las clases de un archivo puede ser una clase pública.
6.3. MODIFICADORES DE VARIABLES
La cantidad de encapsulamiento impuesta por una clase se establece a discreción del
programador. Puede permitirse el acceso completo a todo el interior dentro de la
clase o se pueden imponer diversos niveles de restricciones. En particular, se puede
controlar cuánto es el acceso a otra clase que tiene la instancia y las variables de
clase de una clase. Se consigue esta acción utilizando un modificador, palabra reser-
vada, antes del tipo de la variable. Por ejemplo:
public static i n t VALOR-MAX =65;
protected S t r i n g n o m b r e ="Pepe Mackoy";
private i n t c u e n t a = O ;
La Tabla 6.1 lista los modificadores y sus significados. Normalmente es una
buena idea imponer tanto encapsulamiento como sea posible. En consecuencia,
debe ocultarse todo lo que se pueda, excepto lo que se desea hacer visible a otras
clases, en cuyo caso se debe permitir la cantidad mínima de visibilidad.
Tabla 6.1. El efecto de un modificador de método o variable
Modificador Significado
public
ningún modificador Visible en el paquete actual
protected
private
Visible en cualquier parte (la clase también debe ser pública)
Visible en el paquete actual y en las subclases de esta c!ase en otros paquetes
Visible sólo en la clase actual
Observación: El modificadorp r o t e c t ed es más débil que el uso de ningún
modificador. No se debe utilizar ningún modificador con preferencia a
protected.
144 Java 2. Manual de programación
6.4. MODIFICADORES DE MÉTODOS
Se puede limitar también el acceso de otras clases a métodos. Esta acción se reali-
za utilizando una palabra reservada (modificador),antes del tipo de retorno del
método. Los modificadores son los mismos que para las variables.
public void leerNombre (String nombre)
i
1
. . .
private s t a t i c i n t contarObjetos0
i
1
protected f i n a l Object encontrarllave0
t
1
* . .
. . .
6.5. CLASES INTERNAS
Java permite definir clases e interfaces dentro de otras clases e interfaces. Una clase
que no se anida dentro de otra se denomina clase de nivel superior. Esto significa
que prácticamente todas las clases iitilizadas hasta ahora son clases de nivel supe-
rior. Las clases internas se definen dentro del ámbito de una clase externa (o de
nivel superior). Estas clases internas se pueden definir dentro de un bloque de sen-
tencias o (anónimamente) dentro de una expresión. La clase Empleado tiene dos
clases internas que representan una dirección y un sueldo (Fig. 6.I), El código fuen-
te de la clase Empleado y sus dos clases internas D i r e c c i o n y Sueldo es:
Ejemplo
public class Empleado
t
i n t edad = 0 ;
public String nombre = "Mackoy";
double tasa = 1 6 . 0 0 ;
Direccion direccion;
Sueldo sueldo;
public Empleado (String unNombre, i n t numero,
String unacalle, String unaciudad,
double tasaHora, i n t horas)
t
Encapsulamiento y polimorfismo 145
nombre = unNombre;
tasa = tasaHora;
direccion = new Direccion (numero, unalalle, unaciudad) ;
sueldo = new Sueldo (horas);
I
/ / clase interna
class Direccion
i
int numero = O;
String calle = "";
String ciudad = "";
Direccion(int num, String unalalle, String unaciudad)
I
numero = nun;
calle = unacalle;
ciudad = unaciudad;
I
void visualizarDeta1
i
Cystem.out.println
I
1
es 0
numero+" "+calle+", "t ciudad);
//clase interna
class Sueldo
t
int horasTrabajadas = O;
Sueldo (int horas)
I
horasTrabajadas = horas;
1
void VisualizarDetalles ( )
i
1
Cystem.out .println("Salario = "t horasTrabajadas * tasa);
public static void main (String args[])
i
Empleado e = new Empleado ("Mackoy", 45, "Calle Real",
e.imprimirDatos ( ) ;
"Cazorla", 15.25, 35);
public void irnprimirDatos( )
i
System.out .println("nFicha Empleado: "tnombre);
direccion.visualizarDetalles();
sueldo.visualizarDetalles 0 ;
146 Java 2. Manual de programación
El resultado de la ejecución de esta aplicación es:
Ficha Empleado: Mackoy
45 Calle Real, Cazorla
Salario = 533.75
Empleado
Variables de instancia
edad, nombre,dirección, tasa, sueldo.
I
1 ;
I
I
I I Clase interna Dirección
I1
I I 1
I I Clase internaSueldo
I
I ¡
I
1
11"::Y 1Imprimir Datos ( )
Figura 6.1. Estructura de la clase Empleado.
Las clases internas no se pueden utilizar fuera del ámbito. Por consiguiente, las
clases externas de la clase Empleado no pueden acceder a la clase interna (a
menos que sean subclases o estén en el mismo paquete, dependiendo de la visibili-
dad en la definición de la clase).
En la práctica, la clase de nivel superior actúa como un paquete de objetos
que contienen cero o más clases internas. Esto es particularmente útil en desa-
rrollo de software orientado a objetos. Por otra parte, la capacidad para definir
un código determinado que se puede crear y pasar donde se necesite es muy
importante.
Sintaxis: C posee punteros a funciones. El lenguaje Smalltalk utiliza objetos
que representancódigo (objetos bloque). Java posee clases internas.
Encapsulamiento y polimorfismo 147
Ejemplo
class A
I
int longitud;
float valor;
//variables durante la ejecucibn
public A() //constructor de A
i
1
public float leerValor0 //devuelve valor de una clase
i
1
return valor;
class B
i
public B O
I
1
//definición de B
//constructor de B
public int leercuenta ( )
i
//accede a longitud de la clase externa
return 5*longitud;
1
1 / / f i n de la clase B
1 //fin de la clase A
Una clase anónima es aquella que no tiene nombre y, cuando se va a crear un
objeto de la misma, en lugar del nombre se coloca directamente la definición.
I Regla: Estas clases se utilizan principalmenteen el manejo de sucesos. I
Ejemplo
Programa que permite la e!ección de una opción de un componente Choice y pre-
senta en pantalla la opción seleccionada (vea los Capítulos 9 y 1O). Para el cierre de
ventana, en lugar de crear la clase Cierre:
class Cierre extends WindowAdapter
t
public void windowClosing(WindowEvent e)
i
}
System.exit (O);
1
148 Java 2. Manual de programación
utiliza una clase anónima; es decir, coloca, donde es necesario, directamente la defi-
nición.
Así, en lugar de
addWindowListener(new Cierre0 ) ;
se utiliza
addWindowListener(new WindowAdapterO
I
public void windowClosing(WinciowEvenz e)
i
1
1 ) ;
System.exit (O);
La implementación del ejemplo propuesto es:
import java.awt.*;
import java.awt.event.*;
public class EjAnonima extends Frame implements ItemListener
i
private Choice selección;
String elemento = " ' I ;
public E]Anonima ( )
t
//empleo de una clase anónima para efectuar el cierre de la ventana
addWindowListener(new WindowAdapterO
i
public void windowClosing(WindowEvent e)
i
System.exit (O);
} ) ;
selección = new Choice ( ) ;
selección.addItem ( "Windows 95" ) ;
selección.addItem ( "Windows 98" ) ;
selección.addItem ( "Windows NT" ) ;
//Opción preseleccionada
selección.select (1);
selección.addItemListener(this);
add (selección);
I
public static void main ( String args [ ] )
I
Encapsu/arniento y poiirnorfismo 149
EjAnonima veritana = new EjAnonima() ;
ventana.cetLayout(new Flow;ayqLt());
ventaiia.cetTitle ( "El AWT" ) ;
ventana.cetCize( 400,150 ) ;
ventana.setVisible(true);
public void pair,t(Graphics g)
I
elemento = selección.getSelectedItem();
g.drawstring ("Elemento seieccionado "+elemento,20,i30);
public void itemCtateChanged(1temEvent e)
i
1
repaint ( ) ;
Compilación
C :libroTemaO6>J avac E] Anonima .java
Ejecución
C:libroTemaOG>java EjAnonima
Elemento seleccionado Windows 98
Figura 6.2. Resultado de la ejecución del ejemplo de clase anónima.
6.6. PAQUETES
Un paquete es una colección de clases que se compilan en una unidad de compila-
ción. Los paquetes proporcionan un medio adecuado para organizar dichas clases.
Se pueden poner las clases que se desarrollan en paquetes y distribuir los paquetes
a otras personas, por tanto, se puede pensar en los paquetes como bibliotecas que se
pueden compartir por muchos usuarios.
150 Java 2. Manual de programación
Es posible llevar un conjunto de clases relacionadas juntas a una única unidad
de compilación definiéndolas todas dentro de un archivo. Por defecto, se crea un
paquete implícito (sin nombre); las clases pueden acceder a variables y métodos que
sólo son visibles en el paquete actual y sólo una de las clases puede ser visible
públicamente (la clase con el mismo nombre que el archivo). Un enfoque mejor
sería agrupar las clases en un paquete explícito con nombre.
El lenguaje Java viene con un conjunto rico de paquetes que se pueden utilizar
para construir aplicaciones. Por ejemplo, el paquete j ava .io agrega las clases de
entrada y salida de datos en un programa. Un paquete puede contener a otros paque-
tes. Los paquetes sirven para organizar las clases en grupos para facilitar el acceso
a las mismas cuando sean necesarias en un programa.
La referencia a una clase de un paquete se hace utilizando un nombre completo,
excepto cuando el paquete haya sido importado implícita o explícitamente. Por
ejemplo java.awt .Button indica que Button es una clase del paquete awt y
que awt es un paquete dentro del paquete java.
Los paquetes son unidades encapsuladas que pueden poseer clases, interfaces y
subpaquetes. Los paquetes son muy útiles:
Permiten asociar clases relacionadas e interfaces.
Resuelven conflictos de nombres que pueden producir confusión.
Permiten privacidad para clases, métodos y variables que no serán visibles
fuera del paquete. Se puede poner un nivel de encapsulamiento tal que sólo
aquellos elementos que están concebidos para ser públicos puedan ser accedi-
dos desde el exterior del paquete.
6.7. DECLARACIÓN DE UN PAQUETE
Cada clase de Java pertenece a un paquete. La clase se añade al paquete cuando se
coinpila.
Un paquete explícito se define por la palabra reservada package en el comien-
zo del archivo en el que se definen una o más clases o interfaces. Para poner una
clase en un paquete específico se necesita añadir la siguiente línea como la prime-
ra sentencia no comentario:
package nombrepaqcete;
Por ejemplo:
package dibujos;
incapsuiamiento y poiimorfismo 151
Los nombres de los paquetes deben ser Únicos para asegurar que no hay con-
flictos de nombres. Java impone un convenio de nombres por el que un nombre de
paquete se construye por un número de componentes separados por un punto (sepa-
rador .). Estos componentes corresponden a la posición de los archivos. En el caso
siguiente, los archivos del paquete
package pruebac.dibujos;
están en un directorio llamado dibujos dentro de un directorio llamado p r u e -
bas. Por otra parte, si los archivos de un paquete específico están en un directorio
llamado concurso,dentro de un directorio llamado pruebas,el nombre del
paquete es
package pruebas.concurso;
Observe que esto supone que todos los archivos asociados con un único paque-
te están en el mismo directorio. Cualquier número de archivos se puede convertir
en parte de un paquete, sin embargo, un archivo sólo se puede especificar en un
único paquete.
Nota: Un paquetp,es una colección de clases relacionadas e interfaces que pro-
porcionan protección de acceso y gestión de espacio de nombres.
-1
6.8. PAQUETES INCORPORADOS
Java proporciona miichos paquetes útiles:
Paquete java .applet:permite la creación de upp1rt.s a traves de la clase Applet,propor-
ciona interfaces pars conectar un applet a un documento Web y para audición de audio.
Paquete java.awt:proporciona un Abstract Window T o o i k i t para programación CUI
independiente de la plataforma, gráficos y manipulación de imágenes.
Paquete j ava.io:soporta flujos de entrada y salida Java.
Paquete j ava .lang:contiene clases esenciales para el lenguaje Java.
- Para programación: String,Object,Math,Class,Thread,System,type
Wrapper classes y los interfaces Copiable (Cloneable)y
Ejecutable(Runnab1e).
- Para operaciones de lenguaje: Compiler,Runtime y Sec~JrityManager.
- Para errores y excepciones: Exception,Throwable y muchas otras clases.
El paquete j ava .lang es el único que se importa automáticamente en cada programa Java.
Paquete j ava .math:proporciona cálculos en entero grande y real grande (big,flout).
152 Java 2. Manual de programación
Paquete j ava.net:soporta facilidades de red (URL, sockets TCP, sockets UDP, direcciones IP,
Paquete lava.rmi:soporta invocación de métodos remotos para programas Java.
Paquete j ava.util:contiene diversas clases de utilidad (conjuntos de bits, enumeración, con-
tenedores genéricos. Vector y Hashtable,fecha, hora, separación de «token)),generación de
números aleatorios, propiedades del sistema).
conversión binario a texto).
6.9. ACCESO A LOS ELEMENTOS DE UN PAQUETE
Existen dos medios para acceder a un elemento de un paquete: 1) nombrar total-
mente ill elemento, inchyelido elpaquete, 2) utilizar sentencias import.Por ejem-
plo, cuando se elige nombrar totalmente al elemento, se puede especificar la clase
Panel proporcionando su definición completa
1ava.awt .Panel
como ocurre en la siguiente cabecera:
public abstract class Boton extends java.awt.Pane1
I
Esta sentencia indica al compilador dónde buscar exactamente la definición de
la clase Panel.Sin embargo, este sistema es un poco complicado para referirse a
la clase Panel un número dado de veces, la alternativa es importar la clase
java .awt .Panel:
import java.awt.Pane1;
public abstract class Boton extends Panel
(
. . .
Hay ocasiones en que se desea importar un número grande de elementos de otro
paquete. En este caso, en lugar de colocar una larga lista de sentencias de importa-
ción (import),se pueden importar todos los elementos de un paquete en una sola
acción utilizando el carácter (comodín)) *. Por ejemplo:
import 2 21;s.awt .* ;
iiiipoitn todos los elementos del paquete java .awt al paquete actual.
Encapsu/arnientoy poiirnorfisrno 153
6.10. IMPORTACIÓN DE PAQUETES
Como se acaba de comentar, para utilizar una clase de un paquete en un programa, se
puede recurrir a añadir una sentencia import en la cabecera del mismo. Por ejemplo,
import rnipaquete.MiPrueba;
Las declaraciones import indican ai compilador Java dónde buscar ciertas cla-
ses y nombres de interfaces, de forma que, una vez importado, el nombre de la clase
se puede utilizar directamente sin el prefijo del nombre del paquete.
Si se tienen muchas clases para utilizar del mismo paquete, se puede emplear el
caracter asterisco (*) para indicar el uso de todas las clases del paquete. Por ejemplo,
import mipaquete.*;
importa todas las clases del paquete mipaquete.
Existen dos formatos de import
1. import paqueteDestino.UnTipo; importa la clase o interfaz
2. import paqueteDestino.*; Importa todas las clases e interfaces del paquete
6.11. CONTROL DE ACCESO A PAQUETES
Java proporciona dos niveles de control de acceso: nivel de clase y nivel de paque-
te. Las reglas de acceso a nivel de clase se resumen en la Figura 6.3.
Figura 6.3. Control de acceso a nivel de clase.
154 Java 2. Manual de programación
Un paquete consta de tipos (clases e inlerjuces) definidos en todos sus archivos.
El acceso a nivel de paquete para un tipo es public o package. Sólo los tipos
públicos son accesibles desde otros paquetes (Fig. 6.4). Por consiguiente, la colec-
ción de todos los formatos de tipos públicos de las interfaces externas de un paque-
te a los restantes paquetes. En otras palabras, una clase puede acceder a tipos
públicos y sus miembros públicos en otro paquete. Una subclase puede también
acceder a los miembros públicos y protegidos de sus superclases en otro paquete.
Los códigos interiores de un paquete pueden acceder a todos los nombres de tipo y
todos los métodos, campos no declarados p r i v a t e , en el mismo paquete.
/ Un paquete
tipos públicos
~
,/’ Tipos ‘‘‘‘-I
, package ,i’
_ - /
/
,
l-- _ - - -
Figura 6.4. Control d e acceso a nivel de paquete
6.12. POLIMORFISMO
Polimorfismo es una palabra que significa ((múltiplesformas))y es una de las carac-
terísticas más importantes de la programación orientada a objetos. En realidad, poli-
morfismo es la propiedad por la que a la misma palabra se le asignan múltiples
definiciones. Existen muchas formas de polimorfismo en Java. Por ejemplo, dos
clases diferentes pueden tener dos o mas métodos con el mismo nombre.
En esencia, polimorfismo es la capacidad para enviar el mismo mensaje a obje-
tos totalmente diferentes, cada uno de los cuales responde a ese mensaje de un
modo específico. Las aptitudes polimórficas de Java se derivan de su uso como liga-
dura dinámica. Además, el mismo nombre de método se puede utilizar con pará-
metros diferentes y se permite que áparentemente el mismo método sea declarado
un cierto número de veces dentro de la misma clase.
Polimorfismo puro‘,se produce cuando una única función se puede aplicar a ar-
gumentos de una variedad de tipos. En polimorfismo puro hay una función (el cuer-
po del código) y un número de interpretaciones (significados diferentes). El otro
’ Éste es el término utilizado pot Timoty Budd en la segunda edición de su libro Understanding Ohject-
Oriented Programming with Java, Addison-Wesley, 2000, p. 195.
Encapsulamiento y polimorfismo 155
enfoque se produce cuando se dispone de un número de funciones diferentes (cuer-
po del código) todas representadas por el mismo nombre. Esta propiedad también
se conoce como sobrecarga y, en ocasiones, polimor-smo ad hoc. El polimorfismo
permite a los programadores enviar el mismo mensaje a objetos de clases diferen-
tes. Considérese la sentencia
cuenta.calcularInteresesMensual0;
donde cuenta se puede referir a un objeto Cuentacorriente o a uno
CuentaAhorros. Si cuenta es un objeto de Cuentacorriente,enton-
ces se ejecuta el método calcularInteresesMensua1 definido en
Cuentacorriente.De igual modo, si cuenta es un objeto CuentaAhorros,
entonces se ejecuta el método calcular InteresesMensual definido en
CuentaAhorros. Esto quiere decir que enviando el mismo mensaje se pueden
ejecutar dos métodos diferentes. El mensaje calcularInteresesMensual se
denomina un mensaje polimórfico, ya que dependiendo del objeto receptor se eje-
cutan métodos diferentes. El polimorfismo ayuda al programador a escribir código
más fácil de modificar y ampliar.
Polimor-smo es, pues, la capacidad de un objeto para responder a un mensa-
je basado en su tipo y posición en la jerarquía de clases. Una respuesta apropiada
implica la capacidad del objeto para elegir la implementación del método que mejor
se adapte a sus características. En C++ el polimorfismo se debe diseñar en las cla-
ses, mientras que en Java el polimorfismo es una característica por omisión de las
clases. El término polimorfismo se utiliza para describir como objetos de clases
diferentes se pueden manipular de modo diferente. Mediante técnicas polimórficas
es posible escribir código que manipule objetos de muchas clases diferentes de un
modo uniforme y consistente con independencia de su tipo exacto. La flexibilidad
y generalidad de las estructuras polimórficas es una de las ventajas más significati-
vas de la programación orientada a objetos.
La estrategia para desarrollar una estructura polimórfica comienza con la identi-
ficación de los métodos comunes a través de un grupo de tipos de objetos similares
pero no idénticos y organizando una jerarquía de clases donde los métodos comu-
nes se sitúan en la clase base, mientras que los restantes se organizan en clases deri-
vadas, deducidas de esta clase base. La interfaz de la clase base define una interfaz
a través de la cual un objeto de cualquiera de las subclases especificadas se puede
manipular. Es importante considerar que los métodos de la interfaz compartida se
deben declarar en la clase base.
Un método abstracto es aquel que se declara en la clase base utilizando la pala-
ra reservada abstract y termina con un punto y coma en lugar del cuerpo del
método. Como ya se indicó en el capítulo anterior, una clase es abstracta si contie-
ne uno o más métodos abstractos o no proporciona una implementación de un méto-
do abstracto heredado. Un método se considera implementado si tiene el cuerpo de
156 Java 2. Manual de programación
un método. Si una clase derivada no implementa todos los métodos abstractos que
hereda de una clase abstracta, entonces esta clase se considera también una clase
abstracta. En contraste, el término clase concreta se utiliza para referirse a una clase
en la que no se definen métodos abstractos y tiene implementaciones para todos los
métodos abstractos heredados. Una clase concreta representa un tipo de objeto espe-
cífico, prefijado. Dado que una clase abstracta no está totalmente especificada, sus
métodos abstractos están definidos pero no implementados, no es posible crear
objetos de las clases abstractas. En consecuencia, si la clase Animal es una clase
abstracta:
public abstract class Animal
I
public abstract void mover 0 ;
I
el siguiente código no es válido:
Animal = new Animal ( . . .) ;
Regla: No es posible crear un objeto de una clase abstracta, pero sí es posible
tener una referencia a clases bases abstractas que se refieren a un objeto de una
clase concreta, derivada.
6.13. LIGADURA
El término ligadura se refiere al acto de seleccionar cuál es el método que se eje-
cutará en respuesta a una invocación específica. En algunos lenguajes, tales como
C, la ligadura se realiza totalmente en tiempo de compilación, incluso si están impli-
cados métodos sobrecargados. La ligadura que se realiza en tiempo de compilación
se denomina ligadura estática ya que una vez que se establece la ligadura, ésta no
cambia durante la ejecución del programa. Sin embargo, cuando la conversión de
tipos (casting)y la herencia están implicadas, la ligadura no se puede hacer total-
mente en tiempo de compilación ya que el cuerpo real del código que se ejecuta
cuando se invoca un método puede depender de la clase real del objeto, algo que no
puede ser conocido en tiempo de compilación. La ligadura dinúmica se refiere a la
ligadura que se lleva a cabo en tiempo de ejecución. El caso de ligadura dinámica
se produce cuando se combinan la conversión de tipos, herencia y anulación de
métodos.
Encapsulamiento y polimorfismo 157
6.14. LIGADURA DINÁMICA
La ligadura dinámica se ilustra mediante los siguientes dos ejemplos, que utilizan
la jerarquía de clases.
public c l a s s Base
t
public void operacion ( )
public c l a s s Derivadal extends Base
i
/ / no se ancla el método operacion
1
public c l a s s Derivada2 extends Base
public void operacion ( )
En esta jerarquía de clases, se derivan dos clases de la misma clase base. La
clase Base y la clase Derivada2 contienen una definición de un método llama-
do operación.La clase Derivadal no anula la definición de operacion.El
siguiente segmento de código ilustra la propiedad de ligadura dinámica.
Derivadal primero = new Derivadal ( . . .) ;
Derivada2 segundo = new Derivada2 ( . . .) ;
Base generica;
generica = (Base) primero;
generica.operacion0;
generica = (Base) segundo;
generica.operacion0;
En la primera invocación de operacion el objeto real es de la clase
Derivadal.Ya que la clase Derivadal no anula el método operacion,la
invocación producirá la ejecución del método operacion de la clase Base.En
la segunda invocación de operacion el objeto real es de la clase Derivada2
que anula el método operacion definido en Base.La pregunta que podemos
hacer es: jcuál de los dos métodos operaciorise invoca? Es decir, en el caso del
método anulado (sustituido) operación,cual de los dos métodos se ejecuta bajo
las diferentes condiciones que implica conversión de tipos. En Java, la ligadura
dinámica ejecuta siempre un método basado en el tipo real del objeto. Por consi-
guiente, en el segmento de código anterior la segunda invocación del método ope-
ración se enlaza al método operación de la clase Derivada2.Ya que el tipo
real del objeto puede no ser conocido hasta el tiempo de ejecución, la ligadura se
158 Java 2. Manual de programación
conoce como dinámica para diferenciarlo de las ligaduras que pueden determinarse
en tiempo de compilación. Por ejemplo, considere las clases siguientes:
public c l a s s Automovil
I
public void conducir ( )
I
System.out.println("Conducir un automóvil") ;
1
I
public c l a s s Carro extends Automovil
i
public void conducir ( )
i
1
System.out.println("Conducir un carro");
Estas dos clases se pueden utilizar en otra clase:
public c l a s s Ejemplo
i
public s t a t i c void main (String argc [ ] )
(
Automovil a = new Automovil ( ) ;
Carro c = new Carro();
a.conducir ( ) ;
c.conducir ( ) ;
a = c;
a.conducir ( ) ;
1
I
Compilación
C:libroTemaGG>javac Automovil.java
C:libroTemaGG>javac Carro.java
C:libroTemaGG>javac Ejemplo.java
Cuando se ejecuta esta aplicación, la versión conducir se define en la clase
Carro dos veces, mientras que la versión de la superclase se llama sólo una vez.
Así, la ejecución producirá:
C:libroTemaGG>java Ejemplo
Conducir un automóvil
Conducir un carro
Conducir un carro
Encapsu/amienío y po/imorfismo 159
La variable a se declaró de tipo Automovi1.Cuando se asignó a la instancia de
Carro y se recibió el mensaje conducir,se responde con la versión conducir
de Carro,que se eligió en tiempo de ejecución. La ligadura dinámica o posterga-
da se refiere, pues, al modo en el que Java decide cuál es el método que debe eje-
cutarse. En lugar de determinar el método en tiempo de compilación (como sucede
en un lenguaje procedimental), se determina en tiempo de ejecución. Es decir, se
busca cuál es la clase del objeto que ha recibido el mensaje y entonces decide cuál
es el método que se ejecuta. Ya que esta decisión se realiza en tiempo de ejecución,
se consume un tiempo de ejecución suplementario, pero, por el contrario, presenta
flexibilidad. Cuando Java selecciona un método en respuesta a un mensaje, lo hace
utilizando tres cosas:
La clase del objeto receptor.
El nombre del método.
El tipo y orden de los parámetros.
Es decir, se pueden definir varios métodos en la misma con el mismo nombre
pero con parámetros diferentes. El sistema selecciona el método que desea llamar
en tiempo de ejecución examinando los parámetros.
public class Golf extends Automovil
i
public void cargar(int i)
i
i
System.out .println("Cargando datos "+ i);
public void cargar (String s )
I
1
System.out .println("Cargando cadenas "+ s ) ;

La clase Golf tiene dos métodos denominados cargar,cada uno con un pará-
metro de tipo diferente. Este código significa que Java puede diferenciar entre los
dos métodos y no se producen conflictos.
A 7
Arrays
CONTENIDO
7.1. Concepto de array.
7.2. Proceso de arrays.
7.3. Arrays de objetos.
7.4. Copia de arrays.
7.5. Arrays muItidimensionales.
7.6. Ordenación de arrays.
7.7. Selección.
7.8. Burbuja.
7.9. Inserción.
7.10. Shell.
7.11. Ordenación rápida.
7.12. Búsqueda.
7.13. Implementación genérica de los métodos
de ordenación.
161
162 Java 2.Manual de programación
7.1.
En capítulos anteriores se han utilizado variables para hacer los
programas más flexibles. Gracias a las variables se pueden alma-
cenar, convenientemente, datos en los programas y recuperarlos
por su nombre.Se pueden también obtener entradasdel usuario del
programa. Las variables pueden cambiar constantemente su valor.
Sin embargo, en algunos casos se han de almacenar un gran
número de valores en memoria durante la ejecución de un progra-
ma. Por ejemplo, suponga que desea ordenar un grupo de núme-
ros,éstos se deben almacenaren memoriaya que se han de utilizar
posteriormente para comparar cada número con los restantes.
Almacenar los números requiere declarar variables en el programa
y es prácticamente imposible declarar variables para miembros
individuales,se necesita un enfoque organizado y eficiente.
Todos los lenguajes de programación, incluyendo Java, propor-
cionan una estructura de datos, array (<matriz,vector,,) capaz de
almacenar una colección de datos del mismo tipo. Java trata estos
arrays como objetos.
CONCEPTO DE ARRAY
Un army (((matriz,vector, lista))) es un tipo especial de objeto compuesto por una
colección de elementos del mismo tipo de datos que se almacenan consecutiva-
mente en memoria. I,a Figura 7.1 es un array de 10 elementos de tipo double y se
representa por un nombre, 1i sta, con índices o subíndices.
lista [O]
lista [l]
lista [ Z ]
lista [3]
lista [4]
lista [51
lista [6]
lista [71
lista [81
lista [91
I I
lista -nombre
[ i ] -índice
F
Figura 7.1. El array lista de 10 elementos, con índices de O a 9.
Arrays 163
Otra forma de representar gráficamente un array es en forma de lista horizontal.
lista [ O ] lista [l] lista [ 2 ] lista [31 lista [4] . . .
Figura 7.2. Array lista de 10 elementos.
Los arrays pueden ser unidimensionales (Figs. 7.1 y 7.2), conocidos también
como listas o vectores, y multidimensionales, conocidos también como tablas o
matrices, que pueden tener dos o más dimensiones.
Ejemplo
El array temperaturas de ocho elementos consta de los siguientes componentes:
temperaturas
temperaturas
temperaturas
temperaturas
temperaturas
temperaturas
temperaturas
temperaturas
Regla: Un array tiene un nombre o identificador, un índice que es un entero
encerradoentre corchetes,un tamaño o longitud,que es Úmerode elemen-
tos que se pueden almacenaren el array cuando se le asignaespacioen memo-
ria. Un array se representa por una variable array y se debe declarar, crear,
iniciar y utilizar.
7.2. PROCESO DE ARRAYS
El proceso que se puede realizar con arrays abarca las siguientes operaciones:
declaración, creación, inicialización y utilización. Las operaciones de declaración,
creación e inicialización son necesarias para poder utilizar un array.
164 Java 2. Manual de programación
7.2.1. Declaración
La declaración de un array es la operación mediante la cual se define su nombre con
un identificador válido y el tipo de los elementos del array. La sintaxis para decla-
rar un array puede adoptar dos formatos:
tipoDato [ 1 nombreArray
zipo3ato nombreArray[]
Ejemplo
double [ j miLista;
double miLista[];
} Se declara un array rrilista de tipo double
f l o a t temperatura[j;
f l o a t [ ] temperatura;
} Se declara un array temperatura de tipo float
Las declaraciones no especifican el tamaño del array que se especificará cuando
se cree el mismo.
7.2.2. Creación
Un array Java es un objeto y la declaración no asigna espacio en memoria para el
array. No se pueden asignar elementos al array a menos que el array esté ya creado.
Después que se ha declarado un array se puede utilizar el operador new para crear
el array con la sintaxis siguiente:
nombreArray = new tipoDato [ tarnafio];
nombreArray es el nombre del array declarado previamente, tipoDa to es el
tipo de dato de los elementos del array y tamaño es la longitud o tamaño del array
y es una expresión entera cuyo valor es el número de elementos del array.
Ejemplo
miLista = new double [8!; / / array miLista de 8 elementos
temperatura = new float 1301; / / array temperatura de 30 elementos
Consejo: El formato más conveniente es tipoDato[ ] nornbreArray. El forma-
to tipoDato nornbreArray[ ] se suele utilizar si se desea seguir el estilo de
escritura C/C++.
Arrays 165
Regla: Se pueden combinar la declaración y la creación de un array con una
sola sentencia.
tipoDa to[ ] nombreArray = new tipoDa to[ tamaño];
tipoDato nombreArray[] = new tipoDa t o [ tamaño];
-
Ejemplo
double;] miLicta = new aoub;e[8];
float temperaturalj = new float.3CI;
Precaución: Una vez que un array se ha creado su tamaño no se puede modi-
ficar.
7.2.3. Inicialización y utilización
Cuando se crea un array, a los elementos se les asigna por defecto el valor cero para
las variables numéricas de tipos de datos primitivos, ’uO O O para variables de
tipo carácter, char,false para variables lógicas, boolean, y null para varia-
bles objetos. A los elementos del array se accede a través del índice. Los índices del
array están en el rango de O a tamaño-l.Así, miLista contiene 8 elementos y
sus índices son O , 1,2 , . . .,7.
Cada elemento del array se representa con la siguiente sintaxis:
nombreArray[índice];
Ejemplo
milista [ 7 ; representa el último elemento del array
Regla: En Java, un índice del array es siempre un entero que comienza en cero
y termina en tamaño-i.
Precaución: Al contrario que en otros lenguajes de programación, los índices
siempre se encierran entre corchetes:
temperaturas [is];
166 Java 2.Manual de programación
Un array completo se puede inicializar con una sintaxis similar a
double[] miLista = { 1.5, 2.45, 3.15, 7.25, 8.4 } ;
esta sentencia crea el array miLista que consta de cinco elementos.
Cálculo del tamaño
El tamaño de un array se obtiene con una variable instancia length.Así, por ejem-
plo, si se crea un array milista,la sentencia miLista.length devuelve el
tamaño del array miLista (10, por ejemplo).
Utilización de los elementos del array
Las variables que reperesentan elementos de un array se utilizan de igual forma que
cualquier otra variable. Por ejemplo:
int[l = new int[50];
int 1 = O, j = O;
/ / . . .
j = n[l] + n[10];
Algunas sentencias permitidas en Java:
1. temperatura[5] = 45;
temperatura [8] = temperatura [5] + 10;
System.out.println(temperatura[8]);
2. int punto = 5;
temperatura [punto+31 = 55;
System.out .println("La temperatura 8 es 'I +
temperatura[punto+3] ) ;
3. System.out.print1n ("La segunda entrada es 'I +
entrada[2]);
Reglas:
temperatura í n+3 I = 45;
valor de la variable de índice
índicei - (elementodel array)
+
nombredel array
Arrays 167
Se pueden procesar elementos de un array mediante bucles (por ejemplo, f o r )
por las siguientes razones:
Todos los elementos del array son del mismo tipo y tienen las mismas propie-
dades; por esta razón, se procesan de igual forma y repetidamente' utilizando
un bucle.
El tamaño de un array se conoce, por lo que el bucle mas idóneo es f o r .
Ejemplo
1. El bucle for siguiente introduce valores en los elementos del array. El tama-
ño del array se obtiene en milista.length.
for (int i = O; i < miLista.iength; i + + )
miLista[il = (double) i;
2.int[l cuenta = new ~ ~ ~ [ I o c I ;
int i;
for (1 = O; i < cuenta.length; i++)
a[i] = O;
7.3. ARRAYS DE OBJETOS
Los ejemplos anteriores han creado arrays de elementos de tipos primitivos. Es
posible también crear arrays de cualquier tipo de objeto, aunque el proceso es un
poco más complicado. Por ejemplo, la siguiente sentencia declara un array de 10
objetos Circulo ( C i r c u l o es una clase definida previamente):
Circulo [ ] arraycirculo = new Circulo [ IO];
El array de objetos se inicializa de modo similar a un array ordinario:
for (int i = O; i < arrayCirculo.1ength; i+t)
arraycirculo [i] = new Circulo ( ) ;
Representacióngráfica
Crear un array de objetos Persona (clase Persona).
Persona[] p = new PersonaL51;
168 Java 2.Manual de programación
2 def:ne LX array de obletos
de tipo Persona , q u e puede conrener 5 o~:etos
Se crea UII array de oojetos 1
Persoza
~
I new Persona ( ) 1 i
Se neceSAta crear los
ob-etos de. array
.- - - A
Figura 7.3. Creación de un array de objetos.
1 Persona

Figura 7.4. Estructura completa del array.
Crear un array de 50 objetos pertenecientes a la clase Racional.
La clase Racional representa los números racionales. Un número racional es
un número con un numerador y un denominador de la forma n/d;por ejemplo,
1/ 5,2/ 7 y 3/ 4. Un número racional no puede tener un denominador de valor O.
Los enteros son equivalentes a números racionales de denominador 1, es decir,
n/l.El siguiente programa crea un arrayRaciona1,que se compone de 50
objetos Racional,lo inicializa con valores aleatorios y a continuación invoca al
método suma ( ) para sumar todos los números racionales de la lista.
public class PruebaArrayDeObjetos
public s t a t i c void main (String[] args)
/ / crear e inicializar arrayRaciona1
Arrays 169
Racional [ ] arrayRaciona1 = new Racional [ 501 ;
//inicializar arrayRaciona1
System.out.println("Los números racionales son " ) ;
for ( i n t i = O; i < arrayRacional.length; it+)
i
arrayRaciona1 [ i] = new Racional ( ( i n t ) (Math.random ( ) *50),
System.out.print (arrayRacional[i]+" " ) ;
l + ( i n t )(Math.random()*lO));
}
System.out.println ( " " ) ;
/ / calcular y visualizar el resultado
System.out .println("La suma de los números racionales es "+
suma (arrayRaciona1)) ;
1
public s t a t i c Racional suma(Racional[] arrayRaciona1)
t
Racional suma = new Racional (O,1);
for ( i n t i = O; i < arrayRacional.length; i++)
return suma;
suma = sama.add (arrayRaciona1[ i] ) ;
Observaciones
1. El programa crea un array de 50 objetos Racional y pasa el array al méto-
do suma ( ) ,que suma todos los números racionales del array y devuelve su
suma.
2. Los números racionales se generan aleatoriamente utilizando el método
Math.random ( ) .
3.Precaución. Se ha de evitar un denominador O; para ello se puede añadir al
denominador un 1.
7.4. COPIA DE ARRAYS
Con frecuencia se necesita duplicar un array o bien una parte de un array. Existen
dos métodos para copiar arrays: copiar elementos individuales utilizando un bucle
y utilizar el método arraycopy.
Método 1
Un método para copiar arrays es escribir un bucle que copia cada elemento desde
el array origen al elemento correspondiente del array destino.
170 Java 2. Manual de programación
Ejemplo
El siguiente código copia arrayFuente en arrayDestino:
for (int i = O; i < arrayFuente.lengtn; l i t )
arrayDectino[il = arrayFuente[i];
Este método plantea problemas si los elementos del array son objetos.
Método 2
Los inconvenientes anteriores se resuelven usando el método Syctern. array-
copy ( ) que copia arrays en lugar de utilizar un bucle y que tiene el siguiente for-
mato:
public static void arraycopy(java.iang.0bject
a r r a y r u e n t e , int pos-in;, lava.lang.0bject arrayCesti,?o,
int p o s - f i n , int l e n g t h )
, .
La sintaxis del método arraycopy ( ) es:
arraycopy (arrayFuente, pos-ini, arrayDest.ino, 90s-f:I-., l o n g i t , ~ d );
intl] arrayFuente = {4, 5, 1, 25, iC0);
int[l arrayDestiro = new int[arrayFuente.length];
Syctern.arraycopy(arrayFuente, 0, arrayDectino, 3, arrayFuente.length);
~ ~ ~
Notas:
1. El método arraycopy ( ) puede copiar cualquier tipo (tipo primitivo o
tipo Ob] ect) de elementos del array.
2. En Java, se pueden copiar tipos de datos primitivos utilizando sentencias de
asignación, pero no objetos ni arrays completos. La asignación de un obje-
to a otro objeto hace que ambos objetos apunten a la misma posición de
memoria.
Arrays 171
7.5. ARRAYS MULTIDIMENSIONALES
Las tablas o matrices se representan mediante arrays bidimensionales. Un array
hidimensional en Java se declara como un array de objetos array.
tipo nombre [ ] [ 3 ;
Las tablas de valores constan de información dispuesta enfilas y columnas. Para
identificar un elemento de una tabla concreta se deben especificar los dos subíndi-
ces (por convenio, el primero identifica la fila del elemento y el segundo identifica
la columna del elemento).
o 1 2 3 4 5
(a)Array de una dimensión
(b)Array bidimensional
Figura 7.5. Arrays: (a) Una dimensión; (b) Dos dimensiones (bidimensional).
La Figura 7.6 ilustra un array de doble subíndice, a, que contiene tres filas y cua-
tro columnas (un array de 3 x 4). Un array con rn filas y n columnas se denomina
arra-t’ mgor-n.
ColumnaO Columna 1 Columna2 Columna3
-+ Subíndice columna
-* Nombre del array
-- ---- Subíndice fila
-~_ _ _ ~
Figura 7.6. Un array de dos dimensiones con tres filas y cuatro columnas.
172 Java 2. Manual de programación
Cada elemento del array a se identifica como tal elemento mediante el formato
a [ i 3 I.j] ; a es el nombre del array, e i,j son los subíndices que identifican uní-
vocamente la fila y la columna de cada elemento de a, observése que todos los ele-
mentos de la primera fila comienzan por un primer subíndice de O y los de la
columna cuarta tienen un segundo subíndice de 3 (4-1).
7.5.1. Declaración de arrays multidimensionales
Los arrays multidimensionales se declaran de la misma forma que los bidimensio-
nales, es decir, con un par de corchetes para cada dimensión del array.
t i p o nombre [ I [I [ I . . .;
Ejemplo
1. Un array b de 2x2 dimensiones se puede declarar e inicializar con:
2. La declaración
crea un array de dos filas y tres columnas, en el que la primera fila contiene
4,5,6.
Los arrays con múltiples subíndices con el mismo número de columnas en cada
fila se pueden asignar dinámicamente. Por ejemplo, un array de 3x3 se asigna
como sigue:
int b[l [I;
b = new int[3][3];
Los arrays con subíndices múltiples en los que cada fila contiene un número
diferente de columnas se pueden asignar dinámicamente, como sigue:
int b [ ][ ; ;
b = new int[3][ j ; //asigna filas
b[O] = new int[5]; //asigna 5 columnas a la f;la O
b [ l ] = new int[4]; //asigna 4 columnas a :a fila 1
b [ 2 ] = new int[3]; //asigna 3 columnas a ;a fila 2
La expresión b .length devuelve el número de filas del array, mientras
b [ 1] .length devuelve el número de columnas de la fila 1 del array.
Ejemplo
Declarar y crear una matriz de 5x5
intr; [I ma:riz = new int[5][ 5 1 ;
O bien
int matriz[] [I = new int[5:[5];
Se puede utilizar también una notación abreviada para declarar e inicializar un
array de dos dimensiones:
int[][I matriz =
I
I
La asignación de valores a un elemento específico se puede hacer con sentencias
similares a:
matriz[2] [O] = 3;
Un medio rápido para inicializar un array de dos dimensiones es utilizar bucles f o r :
tabla[x] [ y ] = 5;
1
174 Java 2. Manual de programación
Los hiicles crnidudos funcionan del modo siguiente. El bucle externo, el bucle x,
arranca estableciendo x a O. Como el cuerpo del bucle x es otro bucle, a continua-
ción arranca dicho bucle interior, bucle y, fijando y a O . Todo esto lleva al progra-
ma a la línea que inicializa el elemento del array t a b l a [ O ] [ O ] al valor 5. A
continuación el bucle interior establece y a 1,y con ello t a b l a [ O I [ 1] toma el
valor 5. Cuando termina el bucle interno el programa bifurca de nuevo al bucle
externo y establece x a 1.El bucle interno se repite de nuevo, pero esta vez con x
igual a 1,y tomando y valores que van de O a 2. Por Último, cuando ambos bucles
terminan el array completo se habrá inicializado.
Ejemplo
1. Inicialización de los elementos del array.
O
OO
1 4
2 ' 8
3 12
~~
t
1 2 3
5 ~ 6 -1 7
1 13 14 15
~~ 1 1 2 3
9 10 1' 1
Tras crear y declarar el array t a b l a
i n t ¿ a b - a r ; [ = new i n t [ ? 131;
El listado siguiente inicializa el array:
f o r ( i n t x = 9; x < 3 ; I-x)
f o r ( i n t y = C ; y < 3; i + y )
:auls[x] :y1 xx4 + y ;
2. Declarar. crear e inicializar un array de 8 filas y 10 columnas con 80 enteros
de ~ a l o rcero
i n t ?uneras I I 1 ; / / d e c l a r a r e l a r r a y
-,uneras = new i n t [ 8 1 :lo]; / / c r e a r e l a r r a y e n memoria
f o r ( i n t x = 3; x < 8 ; t + x )
rirrercc[xI [y1 = U;
f o r ( i n t y = C; y < 13; - + y )
Normalmente, la asignación de valores a arrays bidimensionales se realiza median-
te bucles anidados, por ejemplo anidando bucles f o r . Es decir que, supuesto un array
a de dos dimensimes, mediante dos bucles f o r , uno externo y otro interno, es
posible leer y asignar valores a cada uno de los elementos del array. El recorrido de
un array, por ejemplo para mostrar la información almacenada en él, también se rea-
liza utilizando bucles for anidados, ya que los bucles facilitan la manipulación de
cada uno de los elementos de un array. Como se comentó con anterioridad, dado un
array, denominado por ejemplo a, la expresión a . length determina su número de
filas y, si se usa una estructura for con una variable de control, i, que recorra
dichas filas a [ i ].length devolverá el número de columnas en cada fila.
Ejemplo
1 . La siguiente estructura declara, crea, inicializa y muestra el contenido del
array a, en el que cada fila contiene un número diferente de columnas:
int a[] [ I ;
a = new int[3] [I; //as:gna filas
a [ O ] = new int[5:; //asigna 5 r o l u i . r a s a la fila C
a [ l ; = new int[7]; //asigna 7 cclxLzac a la fils 1
a[21 = new int[3]; //asigna 3 columnas a ICfila 2
f o r (int 1 = O; < a.length; i+-)
f o r (int j = 3; J < a[:] .length; j++>
a[:] [j] = j + 1;
/ / presexta por consola el conteniac =el array
f o r (int I = C; i < a.lengt;i; ;++)
t
f o r (int j = 3; 7 < a!:] . l e n g t h ; j-+)
System.out.orintln0;
Cyctem.out.print(o[i] [j:-" " 1 ;
1
2. Declarar, crear e inicializar un array de 8 filas y 10 columnas con 80 enteros
de valor cero.
int numeroc [ j 1 1 ;
numeroc = new int;8][ l o ; ;
f o r (int x = 3; x < numeros.length; + + X I
f o r (int y = 3; y < numeroc[x;.length; ++y)
nunieroc[x] [y] = 3;
Ejercicio (aplicación)
La siguiente aplicación crea e inicializa un array de dos dimensiones con 10 colum-
nas y 15 filas. A continuación presenta en pantalla el contenido del array.
public class Tabla1
176 Java 2. Manual de programación
s t a t i c i n t tabla [ 3 [I ;
s t a t i c void llenar ( )
tabla = new i n t [ l 5 1 [lo];
f o r ( i n t x = O ; x < 15; x++)
f o r ( i n t y = O ; y < 10; y++)
tabla[x][y] = x * 10 t y;
s t a t i c void mostrar 0
f o r ( i n t x = O ; x < 15; x++)
I
f o r ( i n t y = O ; y < 10; y++)
System.out.println0;
System.out.print (tabla[x][y]+"t");
public s t a t i c void main (String[] args)
llenar ( ) ;
mostrar ( ) ;
Ejercicio (applet)
El AppletTablal,se comporta de forma similar a la aplicación anterior, también
crea e inicializa un array de dos dimensiones con 1O columnas y 15 filas.A continua-
ción imprime el contenido del array en el área de visualización del upplet, de modo que
se puede ver que el array contiene realmente los valores a los que se ha inicializado.
package libro.Tema07;
import java.awt.*;
import java.applet.*;
public class AppletTablal extends Applet
t
i n t tabla [ ] [ ] ;
public void init ( )
tabla = new i n t [ l 5 1 [ i o ] ;
f o r ( i n t x = O ; x < 15; x++)
f o r ( i n t y = O ; y < 10; y++)
tabla[x][y] = x * 10 + y;
1
public void paint (Graphics g)
f o r ( i n t x = 3 ; x < 15; xt+)
for (int y = O; y < 10; y++)
i
String c = String.valueOf (tabla[XI[y]) ;
g.drawString(s, 50+y*25, 50+x*15);
I
Para ejecutar el applet (vea el Capítulo 11, ((Appletw), será necesario:
1. Su compilación
Mediante una instrucción como la siguiente:
C:libroTema07>]avac AppletTabla1.java
cuando se trabaja con eljdkl.3
Usando el modificador target durante la compilación para generar un archivo
class específico para una determinada máquina virtual, ya que no siempre es
seguro que el navegador utilizado para ejecutar el código HTML con la marca
APPLET soporte todas las características incorporadas a la versión del JDK
con la que el applet ha sido compilado. Así, con eljdkl.4se emplea
C:libroTema07>javac -target 1.1 AppletTablal.java
con la finalidad de que el applet pueda ser ejecutado por los navegadores
(browsers)habituales.
Otra forma más adecuada para que un applet complilado en la versión 1.4 del
jdk pueda ser ejecutado por los browsers habituales consiste en utilizar Plug-in
(veáse el Apéndice F, ((Contenido del CDD)
2. Crear un archivo A t 1.h t m l con el siguiente contenido:
Archivo HTML (Atl.html)
<HTML>
<APPLET
WIDTH=350
HEIGHT=300
code=libro.Tema07.AppletTablal.class>
</APPLES>
</FITML>
Al abrir la página, usando por ejemplo Microsoft Internet Explorer, el applct se
carga y ejecuta automáticamente. La salida obtenida se muestra en la Figura 7.7.
178 Java 2. Manual de programación
O 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99
100 101 102 103 104 105 106 107 108 109
110 111 112 113 114 115 116 117 118 119
120 121 122 123 124 125 126 127 128 129
130 131 132 133 134 135 136 137 138 139
140 141 142 143 144 145 146 147 148 149
Figura 7.7. Ejecución del applet en Microsoft Internet Explorer
7.6. ORDENACIÓN DE ARRAYS
La clasificación de datos es una de las operaciones más usuales en programación y
podrá considerarse de dos tipos:
Interna, es decir, con los datos almacenados en memoria.
Externa, con la mayor parte de los datos situados en un dispositivo de almace-
namiento externo.
Dentro de la ordenación interna habría que considerar la ordenación tanto de
arrays como de listas(vea el capítulo sobre estructuras de datos), pero para explicar los
métodos de ordenación se estudiará exclusivamente la ordencrcidnde arrays. Además,
los métodos de ordenación interna se aplicarán a arrays unidimensionales, aunque su
uso puede extenderse a otro tipo de arrays, bidimensionales, tridimensionales, etc.,
considerando el proceso de ordenación con respecto a filas, columnas, páginas, etc.
El concepto de ordenación se puede definir de la siguiente hrma: dado un array
unidimensional X y dos índices i y j que permiten recorrerlo, se dirá que está orde-
nado ascendentemente si para todo i < j se cumple siempre que X [ i ] <= X [ j] .
El array estará ordenado en orden descendente si cuando i < j se cumple siempre,
para todos sus elementos, que X [ i I >= X [ jI .
Los métodos de clasificación interna más usuales son: Selección, Burbuja,
Inserción, Inserción binaria, Shell, Ordenación rúpida (Quick Sort).
Arrays 179
7.7. SELECCI~N
El algoritmo de ordenación por selección de un array con n elementos tiene los
siguientes pasos:
1. Encontrar el elemento menor del array.
2. Intercambiar el elemento menor con el elemento de subíndice 1.
3. A continuación, buscar el elemento menor en la sublista de subíndices 2 . .n,
e intercambiarlo con el elemento de subíndice 2. Situándose, por tanto, el
segundo elemento menor en la posición 2.
4. Después, buscar el elemento menor en la sublista 3 . .n, y así sucesivamente.
Por ejemplo, dada la siguiente lista 7 4 8 1 1 2 .
Se compara a [ i ] con los siguientes elementos:
-7 4 8 1 12
-4 I 8 1 12
-4 7 8 12
-1 I 8 4 12
con lo que el elemento menor queda seleccionado en a [ i ]
Se compara a [ 2j con los siguientes elementos:
-7 8 4 12
-I 8 4 12
-4 8 7 12
con los que el elemento menor queda.seleccionado en a [ 2 ] .
Se compara el elemento a 13] con los siguientes:
-8 7 i2
-7 8 12
con lo que el elemento menor queda en a[3].
Se compara el elemento a[4] con los siguientes:
-8 1 2
con lo que el array quedaría 1 4 l a 12.
También se podría buscar el elemento mayor y efectuar la clasificación en orden descendente.
Codificación
p u b l i c class Pruebas
p u b l i c s t a t i c void main (String[ 1 args)
r
i n t a[]= {7,4,8,1,12};
i n t menor;
f o r ( i n t i = O; i < a.length-1; I++)
I
menor = 1;
for ( i n t j = i + l ; 1 < a.lergth; j++)
180 Java 2. Manual de programación
if (a[:] < a[rnenorJ)
menor = 7;
i n t auxi = a[iJ;
a;iJ=a[menor];
a [menor]=auxi;
1
/ / Presentación de los resultados
f o r ( i n t i = O ; i < 5; i++)
Cystem.out.println(a[i]);
1
7.8. BURBUJA
La ordenación por burbuja (buble sort) se basa en comparar elementos adyacentes
del array e intercambiar sus valores si están desordenados. De este modo se dice que
los valores más pequeños burbujean hacia la parte superior de la lista (hacia el pri-
mer elemento), mientras que los valores más grandes se hunden hacia el fondo de
la lista.
Si se parte de la misma lista que en el método anterior, 7 4 8 1 12:
7 4 8 1 12
4 7- a 1 12
4 7 8- 1 12
4 7 i 8- 12
4- I 1 8 -12
4 7- 1 8
4 1 7- 8
4- 1 7 -8
1 4- 7
quedando el 7 en tercera posición:
1- 4 -
quedando el cuatro en la segunda posición:
quedando el 12 al final de la lista:
quedando el 8 en penúltima posición:
7
1 -4-
con lo que la lista resultante sería 1 4 7 8 12.
Codificación
public c l a s s PruebaB
t
public s t a t i c void main (String[ ] args)
i n t a[;= {7,4,8,1,12};
f o r ( i n t i = 1; 1 < a.length; i++)
Arrays 181
f o r ( i n t j = O; j < a.length-i; j++)
i f (a[j+il < a[jl)
t
i n t auxi = a[jI ;
a[j] = a[j+l];
a[j+l] = auxi;
/ / Presentación de los resultados
f o r ( i n t i = O; i < 5; I++)
System.out .println(a[i]) ;
I
Una optimización del método anterior que aprovecha posibles ordenaciones ini-
ciales en el array es:
public c l a s s PruebaBOp
t
public s t a t i c void main (String[ ] args)
I
i n t a[] = {7,4,8,1,12};
i n t i = 1;
boolean ordenado;
do
i
ordenado = true;
f o r ( i n t j = O; j < a.length-i; j++)
if (a[j+ll < a[jl)
t
ordenado = false;
i n t auxi = a[jl;
a[jl = a[j+ll;
a[j+l] = auxi;
1
i++;
1
while (ordenado == false);
/ / Presentación de los resultados
for (i = O; i < 5; i++)
System.out.println(a[i] ) ;
7.9. INSERCI~N
El método está basado en la técnica utilizada por los jugadores de cartas para clasi-
ficar sus cartas, donde eljugador va colocando, insertando cada carta en su posición
correcta. Por tanto, el método se basa en considerar una parte del array ya ordena-
182 Java 2. Manual de programación
do y situar cada uno de los elementos restantes en el lugar que le corresponda por
su valor. Inicialmente la parte ordenada consta de un Único elemento, ya que un
único elemento que se podrá considerar siempre ordenado.
El lugar de inserción se puede averiguar mediante búsqueda secuencia1 en la parte
del array ya ordenada, método de inserción directa, o efectuando una búsqueda bina-
ria (la búsqueda binaria se comentará más adelante en este mismo capítulo), con lo
que el método pasará a denominarse de ordenación por inserción binaria.
Los elementos de la lista, 7 , 4 , 8 , 1, 1 2 , van tomando los siguientes valores:
7.4 8 1 12 seguarda en a u x i a [ i , , s e c o m p a r a a u x i con a[Gl y,
como a [ O ] es mayor, se desplaza hasta a [ 1] y en a [ C ] se
pone a u x i
-1
4 ' a u x i
~
4 7 8 1 12 no hay desplazamiento. pues a u x i (donde se ha guardado
a [2])es mayor que a [ 11
--,8 a u x i
I__.
4 7 8,.1 12 s e g u a r d a e n a u x i c o n a i 3 1 ysecomparacona[21
Hay desplazamiento de a [ 2 ] a a [ 3 I
',-1
1 a u x i
L A
4 7,+ 8 8 12 e compara a u x l con a [ 1] y. como e mayor a .1 ] que
a u x i , hay deiplazamiento de a L 11 a a [ 2 I
-1
4,-7 8 12 e compara a u x i con a : O 1 . Se deplaza a [OI a a [ 11
4 4 7 8 12 s e c o l o c a e l l e n a [ O ]
1 4 7 8 12 a [ 4 ] se guarda en a u x i , se compara con a [ 3 ] y no hay
desplazamientos.
Codificación
/ / i n s e r c i ó n direcEa
public c l a s s P r u e b a I D
public s t a t i c void mair. ( S t r i n g [ 3 a r g s )
I
i n t a [ ] = {7,4,8,1,12!;
i n t i , j , a u x i ;
boolean e n c o n t r a d o s i t i o ;
for (i = 1; i < a . l e n g t h ; i+i)
Arrays 183
auxi = a[i:;
er.contradositio = false;
while ( 2 >= C & & !eccontradositio)
j = 1-1;
if (a[]] > a.Jxi)
else
encontrados:tio = t r ü e ;
a [ j+1]= a u x i ;
i
/ / Prese-tarióc de los resultados
for (i = O; i < 5; it+)
Systen.out.pr;ntln(a[i]);
I
7.10. Shell
Este método se basa en realizar comparaciones entre elementos no consecutivos,
separados por saltos o intervalos mayores que 1. Estos saltos sufrirán sucesivos
decrementos. Es un método elaborado que resulta más eficiente cuando las listas
son grandes.
Considere el siguiente array: 6 1 4 7 2 (5 elementos). En una primera pasa-
da, las comparaciones se realizarán entre elementos separados por un intervalo de
5/2.
El primer intercambio se produce entre a [ O 1 y a [ 2 ] y luego entre a [ 2 ] y a [ 4] .
Puesto que ha habido intercambio entre a [ 21 y a [ 4 I hay que comprobar que
dicho intercambio no ha estropeado la ordenación efectuada anteriormente, por
tanto, se retrocede y se comparan de nuevo a [ O ] con a [ 2 3 . Como resultado se
obtendrá ahora 2 1 4 7 6. Los elementos a [ O ] , a [ 2 ] y a [ 4 ] se encuentran
ahora ordenados y por otra parte también a [ 1] y a [ 3 3 . Se repite el proceso con
salto o intervalo la mitad del anterior.
184 Java 2.Manual de programación
Como hay intercambio entre a [ 3] y a [ 4] se retrocede para comprobar que no se ha estropeado la orde-
nación entre a [ 2 3 y a [ 3] y como esté bien no se retrocede más.
1 1 2 ! 4 ; 6 ( 7 (
Resultado final
El proceso termina, pues se han comparado todos los elementos con un salto o intervalo de uno y el salto
ya no puede ser menor.
Codificación
public c l a s s PruebaCh
public s t a t i c void main (String[ ] args)
i
i n t a[] = (7,4,8,1,12};
i n t i, j, k , salto;
salto = a.length / 2;
while (salto > O)
t
for (i = salto; i < a.length; i++)
i
j = i - salto;
while ( j >= O)
i
k = j t salto;
i f ( a [ j ] <= a[kl)
else
I
j = -1;
i n t auxi = a[jl;
a[jl = a[kl;
a[k] = auxi;
j -= salto;
}
salto /= 2;
1
/ / Presentación de los resultados
for (i = O; i < 5; i++)
Cystem.out.println(a[il) ;
!
!
Arrays 185
7.11. ORDENACI~NRÁPIDA
El método consiste en:
Dividir el array en dos particiones, una con todos los elementos menores a un
cierto valor específico y otra con todos los mayores que él. Dicho valor es uno
cualquiera, tomado arbitrariamente, del vector, y recibe la denominación de
pivote.
Tratar, análogamente a como se expuso en el primer apartado cada una de las
particiones, lo que conduce a un algoritmo recursivo.
Codificación
public class PruebaQS
i
public static void quicksort (int a [I, int iz, int de)
(
int i = iz;
int J = de;
int pivote = a [ (iz+de)/2];
do
i
while(a[i] < pivote) {i++;1
whiie(a[j] > pivote) {I--;1
if (i <= j)
i
int auxi = a[il;
a[i] = a[j];
a [ j ] = auxi;
i++;
j--;
1
1
while (i <= j);
if (j > iz) {quickSort(a, iz, j);}
if (1 < de) {quickCort(a, i, d e ) ; }
1
public static void main (String[ ] args)
t
int[] a = {6,1,4,7,2,5,3};
quicksort (a, O, a.length-1);
for (int i = O; i < a.length; i++)
Systen.out.println(a[i]) ;
!
186 Java 2. Manual de programación
7.12. B~SQUEDA
La biísc-/i/edaes una de las operaciones más importantes en el procesamiento de la
información, y permite la recuperación de datos previamente almacenados. Cuando
el almacenamiento se encuentra en memoria principal, la búsqueda se califica de
interna. Existen diversas formas de efectuar búsquedas en un array.
del array hasta alcanzar el final del mismo y, si en algún lugar del array se encuen-
tra el elemento buscado, el programa deberá informar sobre lailas posicióniposicio-
nes donde ha sido localizado. El algoritmo se puede optimizar utilizando una
variable lógica que evite seguir buscando una bez que el dato se ha encontrado si
únicamente se desea obtener la posición donde se localiza por primera vez al ele-
mento buscado.
array de forma ordenada. Consiste en comparar el elemento buscado con el ele-
mento que ocupa la posición central y, según sea mayor o menor que el central y el
array se encuentre clasificado en orden ascendente o descendente, se repite la ope-
ración considerando un siihar~.a~~formado por los elementos situados entre el que
ocupa la posición central+l y el último, ambos inclusive, o por los que se
encuentran entre el primero y el situado en central-1,también ambos inclusive.
El proceso finalizará cuando se encuentre el dato o el sz/hcrrra.v de hzísqz/edu se
quede sin elementos.
La bzisqz/eúcrlined consiste en recorrer y examinar cada uno de los elementos
La biisqiieda hinrrria requiere que los elementos se encuentren colocados en el
Codificación recursiva
La implementación que se efectúa es recursiva (una operación se llama a sí misma).
AI encontrar el elemento buscado se devuelve su posición y, si no se encuentra,
devuelve un número negativo, cuyo valor absoluto representa la posición donde
dicho elemento debiera ser situado si se quisiera añadir a la lista sin que ésta per-
diera su ordenación.
public class Bbin
private int bucquedaB;nar;a(int[: a, int iz, int de, int c)
int central = (iz + de)/2;
if (de < ir)
return(-iz);
return(bucque3aBinaria (a, iz, central-1, 2 )) ;
if (a[central] < c)
if (c < arcectral:)
else
return(%usquedaEinaria (a, centzal+l, de, c)) ;
Arrays 187
else
return(cectra1) ;
i
public int búsqüedaB(int[] a, int c)
return(b~squecaB1:iar;a (a,3,a.leng~h,c)) ;
i
1
public class Class1
i
public static void mair.(Str-n.g [ ] a r g s )
/ / er. el array a los elemenLos están colocados ae forma ordenada
int[] a = !?,2,5,7,8,9,11,123;
//muestra el array
for (int I = O; I < a.length; :-+)
Cystem.o'dt.println(a[i:);
System.out.println();
Bbin buscador = new Bbin ( ) ;
//Busca el 1
int p = buscador.búsqaedaB(a, 1);
/*Interpreta la i n f o r m a c i j n devuelta por el
if (p >= O)
proceso de búsqueda * I
Cysten.out.pr:nt ("El elemento 1 esta en " ) ;
System.out .println("la posición "+ pj ;
else
Cystem.out . p r i n t ("El eiemento no esza.");
System.out .print("Su l u g a r deberia ser " j ;
Cystem.out.println("la posición " + Math.abs ( p )) ;
Importante: La búsqueda binaria es mucho más eficiente que la lineal, pero
requiere que los elementos se encuentren colocados en el array de forma orde-
nada.
188 Java 2. Manual de programación
7.13. IMPLEMENTACIÓNGENÉRICA DE LOS MÉTODOS
DE ORDENACIÓN
Antes de presentar una implementación genérica de los distintos métodos de orde-
nación hay que tener en cuenta que cuando los elementos de un array se declaran
a partir de la superclase Object,dicho array se podrá utilizar para almacenar
objetos de distinta clase. Los métodos de ordenación y búsqueda deben imple-
mentarse de forma que respectivamente puedan ordenar y buscar información en
arrays con cualquier tipo de contenido; para ello, se define una interfaz,
Comparable y se declara la información almacenada en el array, en lugar de
Object,como Comparable. La interfaz Comparable tendrá la siguiente
estructura:
/ * Interfaz básico estándar de comparación, concebido para admitir
varios criterios de ordenación en este caso el campo criterio
no será usado*/
interface Comparable
boolean menorque(Comparab1e c, i n t criterio) throws Exception;

El objeto a almacenar en el array implementará la interfaz Comparable;por
ejemplo:
//objeto Comparable
public c l a s s Entero implements Comparable
i n t valor;
Entero ( i n t valor)
this.valor = valor;
public boolean menorque (Comparable c, i n t criterio) throws
Exception
i f ( ! (c instanceof Entero))
//Lanza una excepción (vea el capítulo sobre excepciones)
throw new Exception ("Tipo de comparación inválido");
Entero e = (Entero)c;
return (valor < e .valor);
1
I
Arrays 189
Los métodos de ordenación deben codificarse ahora de la siguiente forma:
public class Metord
i
public void celeccion (Comparable[ ] a, int criterio) throws
Exception
t
int mesor;
for (int 1 = O; 1 < a.length-í; i++)
menor = 1;
for (int j = 1+l; j < a.length; I++)
if (a[ j] .mezorque(a[r;e>.or],crizerio)
menor = j;
Comparable auxi=a [ i I ;
a[i]=a[menor];
a [menor]=auxi;
}
public void incercion (Comparable[ ] a, int cr;rer-c) throws
Exception
Comparable dux;
int 1 ;
boolean encoctradocitio;
for (int i = 1; i < a.length; I++)
i
aux = a [ i ] ;
encontrados;tio = false;
while (j >= O & & !encontradositio)
(aux.mencrque(a[II , criterio))
1 = i-1;
if
a[j+l]=a[jl;
j--;
else
encontradositio = true;
a [ jtl]=aux;
public void burbula (Comparable[ ] a, int criterio) throws
Exception
Comparable auxi = a[] I ;
a[j] = a [ ] + l ] ;
a [ j + i ] = auxi;
190 Java 2. Manual de programación
public void burbulaMelorada (Comparable[I a, i n t criterio)
throws Exception
boolean ordenado;
i n t i = 1;
do
ordenaao = true;
for ( i n t 3 = O; < < a.length-1; I++)
(a:j + 1 ].menorque (a[ J! ,crizerio))i f
ordemdo = f a l s e ;
Comparable aux: = a[]';
a[]; = a [ j L l 1 ;
a [ : t l ] = aux:;
i-t;
while (ordenado == f a l s e ) ;
public void gC (Comparable a [ 1 , i n t c r i t e r i o ) throws Exception
i
ql-iciCort (a, criter-o, O, a.LengLh-1) ;
public void quicksort(Comparable a[], i n t criterio, i n t i z , i n t de)
i
throws Exception
i n t : = :z;
i n t j = de;
Ccinparable pivote = a [ (iz+de)/2];
do
w h i l e ( a [ i ; .menorque(pivote,criteric) {it+;1
while ( p i v o t e . r n e n o r q u e (a[ J I , criterio) ) {I--; 1
i f (i <= j)
Comparable aux: = a [i! ;
a i i ; = a[];;
a[:] = auxi;
i-+;
- - _ .> I
while (i <= 1) ;
if (j > iz) { q c i c k S o r t ( a , criterio, iz, 3);)
if (: < ae) { q u i c k C o r t ( a , criterio, i, de);}
Arrays 191
El programa de prueba podría ser:
public c l a s s PruebaT
I
public s t a t i c void r i d i n (String[I args) throws Excepticr
i
Encero[: a = new Zntero[7];
a[u] = new Entero(6);
a[:] = new Entero(1);
a[2] = new Entero(4);
a[3] = new Entero(7);
a[4] = new Entero(?);
a[5] = new Entero([>);
a[61 = new Ertero(3);
Metcrd ordenadcr = new Yetordo ;
orderador.seleccior (a,3 ) ;
for ( i n t 1 = O; 1 < a.,~qgth; I++)
System.out.printlnía[i].valor);
1
Cadenas y fechas
CONTENIDO
8.1. Creación de cadenas.
8.2. Comparación de cadenas.
8.3. Concatenación.
8.4.
8.5. La clase StringTokenizer.
8.6. La clase StringBuffer.
8.7.
8.8. La clase Date.
8.9. Los formatos de fechas.
Otros métodos de la clase String.
Métodos de la clase StringBuffer.
8.10. La Clase Calendar.
193
194 Java 2. Manual de programación
Una cadena (string)es una secuencia de caracteres. Los arrays y
las cadenas se basan en conceptos similares. En la mayoría de los
lenguajes de programación, las cadenas se tratan como arrays de
caracteres, pero en Java, una cadena (string)se utiliza de modo
diferente a partir de un objeto array.
Java proporciona la clase incorporada string para manejar
cadenas de caracteres.En el caso de que se desee modificarcon fre-
cuencia estas cadenas, es conveniente usar la clase StringBuffer
en lugar de String con objeto de consumir menos memoria.
En algunas ocasiones es, necesario efectuar un análisis gra-
matical básico de una cadena y, para ello, se emplea la clase
CtringTokenizer,que permite dividir una cadena en subcade-
nas en aquellos lugares donde aparezcan en la cadena inicial
unos determinados símbolos denominados delimitadores.
Los programas también necesitan manejar frecuentemente la
fecha del sistema. Para trabajar con fechas en los programas se
utiliza la clase GregorianCalendar,mientras que la clase Date
se puede utilizar para medir el tiempo que una determinada tarea
tarda en ejecutarse.
En este capítulo se comentan las características de cada una
de las clases, de uso frecuente, anteriormente citadas.
8.1. C R E A C I ~ NDE CADENAS
Una de las clases más frecuentemente utilizadas en los programas Java es la clase
S t r i n g perteneciente al paquete Java.l a n g . Las cadenas S t r i n g de Java no
son, simplemente, un conjunto de caracteres contiguos en memoria, como ocurre en
otros lenguajes, sino que son objetos con propiedades y comportamientos. La clase
S t r i n g se declara en Java como clase f i n a l como medida de seguridad y, por
tanto, no puede tener subclasec.
public final class Strinq extends Oblect implements Cerializable,
Cciiparable
Existen dos formas de crear una cadena en Java, mediante un literal y mediante
el empleo de un constructor explícito. Cada vez que en un programa Java se utiliza
una constante de cadena, automáticamente se crea un objeto de la clase S t r i n g .
Para crear una cadena con un literal y asignarle una referencia, puede emplearse una
sentencia como la siguiente:
String saludo = “Hcla”;
Cadenas y fechas 195
La cadena así creada se coloca en un lugar especial reservado para las mismas y,
si posteriormente se crea otra cadena con el mismo literal, no se añade un nuevo
objeto a dicho espacio, sino que utiliza el objeto existente, al que añade una nueva
referencia.
Ejemplo
Las siguientes líneas de código producen el resultado que se muestra en la Figura 8.1:
String ciudad = "Madrid" ;
String miciudad = "Madrid" :
_.- Ambas referencias amputan al
mismo literal físico en el
espacio reservado para el
~~ _ _ ~ almacenamiento de literales
String
ciudad 7:Madrid
miciudad
Figura 8.1. Creación de cadenas con el mismo literal.
Otra forma de crear cadenas es usar un constructor explícito, por ejemplo:
char arr [ ] = { 'H' , 'o', '1', 'a' } ;
String saludo = new C;ring(arr) ;
Esta última sentencia coloca un objeto String en el montíczdo (heap),en lugar de
situarlo en el espacio reservado para las cadenas anteriormente comentado. Entre los
diversos constructores que posee la clase S t r i n g pueden destacarse los siguientes:
public String ( )
public Str,cg(char[ ] arr)
public Ctring(java.lang.String cad)
public Strir.g(java .la=g.Stringsuffer buffer)
Crea un objeto Strinq sin
caracteres.
Crea un objeto srring a
partir de un array de
caracteres.
Crea un String con los
mismos caracteres que otro
objeto String,es decir.
realiza una copia.
Crea un objeto String con
una copia de los caracteres
existentes en un
CtringBuffer,que es una
cadena dinámicamente
redimensionable.
196 Java 2. Manual de programación
Nota: La sentencia cad2 = new String(cad1); permite efectuar la copia
de la cadena, en este caso cadl,que se pasa como argumento.
La sentencia cad2 = cadl;copia la referencia cadl en cad2 y consigue
que ambas variables permitan acceder al mismo objeto.
La sentencia cad2 = cadl .tostring ( ) produce unos resultados
análogos a la anterior, puesto que cadl .tostring ( ) devuelve el propio
objeto String.
Ejemplo
Tras la siguiente sentencia:
String ciudad2 = new String (“Madrid”);
ciudad2 no tiene un valor literal colocado en el espacio reservado para el almace-
namiento de literales String,sino que es parte de un objeto separado String.
ciudad2 -Madrid
ciudad -Madrid
miciudad f
Figura 8.2. Diferencias entre la creación de cadenas con el mismo literal
y mediante el uso de un constructor explícito.
AI elegir entre uno u otro método es importante recordar posteriormente cuál se
ha usado, pues esto afecta a la forma en la que las cadenas Strings se pueden
comparar.
Las cadenas de caracteres también se pueden leer desde teclado y el método
habitualmente utilizado para ello es readLine de la clase BufferedReader
que lee una secuencia de caracteres de un flujo de entrada y crea un objeto de
tipo String devolviendo una referencia al mismo. Se ha de tener en cuenta que
para efectuar este tipo de entrada debe construirse previamente un objeto de la
clase Buf feredReader sobre otro de la clase InputStreamReader aso-
ciado a System.in.
Otro aspecto importante de los objetos de tipo String es que no pueden ser
modificados en memoria. En realidad, lo que esto quiere decir es que para modifi-
car una cadena existente Java crea un nuevo objeto String con las modificacio-
nes y deja la cadena inicial, sin utilidad, disponible para la recolección de basura.
Cadenas y fechas 197
Por tanto, un programa que necesite efectuar muchas manipulaciones de cadenas
String puede consumir grandes cantidades de memoria y, para evitarlo, en dichos
casos deben reemplazarse los objetos S t r i n g por objetos de la clase
StringBuffer.
8.2. COMPARACIÓN DE CADENAS
La comparación de cadenas se basa en el orden numérico del código de caracteres;
es decir, que, al comparar cadenas, Java va comparando sucesivamente los códigos
Unicode de los caracteres correspondientes en ambas cadenas y si encuentra un
carácter diferente o una de las cadenas termina detiene la comparación. Para que
dos cadenas sean iguales, han de tener el mismo número de caracteres y cada carác-
ter de una ser igual al correspondiente carácter de la otra. Al comparar cadenas la
presencia de un carácter, aunque sea el blanco, se considera mayor que su ausencia.
Además, la comparación de cadenas distingue entre mayúsculas y minúsculas pues-
to que su código no es el mismo, las letras mayúsculas tienen un número de código
menor que las minúsculas.
A la hora de comparar cadenas hay que tener en cuenta que el operador == com-
para solamente las referencias de objeto, mientras que el método equals compa-
ra los contenidos de los objetos.
public boolean equals (java.lang.Object un0bject)
Así, cuando se crean cadenas mediante literales, éstas podrán ser comparadas
tanto con el operador == como con el método equals.
Ejemplo
Comparar dos cadenas usando primero el método equals y a continuación el ope-
rador ==.
import java.io.*;
public class Cornpararcadenas
i
public static void main (String[] args)
t
String nornbrel, ciudadl, nornbre2, ciudad2;
nombre1 = "Ana";
ciudadl = "Madrid";
nombre2 = "Pedro";
198 Java 2. Manual de programación
ciudad2 = "Madrid";
System.oiit.println("Comparacihn con equals");
i f (ciuaacil. e q ~ a l s(ci>~dad2))
System..cut.println(nombrel + " y "+ ncmbre2~
" son de ;a misaa ciudad");
else
Syscen.cuz.pristln (nor?brel + " y "t nombre2+
" son de distinta ciudad");
Sycter.o ~ t.println("Cciparacicc con ==" j ;
i f (c:¿idadl == ciudad2)
Systerr,.out.println(nombre1 t " y " + nor?,bre2-
'' scn de la rnis.3 c1~1aad");
else
Syszem.out .prir.tln(?,cr.brel+ " y " + ncmbre2+
" son de distinta ciudad");
t
Si se desea comparar cadenas creadas usando un constructor explícito. será nece-
sario emplear el método equals.
Importante:Para comparar cadenas, lo más seguro es usar siempre el método
equals, aunque en algunas ocasiones esta operación nos devolvería un resul-
tado análogo al empleo del operador ==.
Ejemplo
Comparar dos cadenas leídas desde teclado usando primero el método e q u a l s y a
continuación el operador == .
import java.ic.*;
public class Compararcadenas2
public s t a t i c Szring leer ( )
IrputStreamRea&r i c r = new 1nputStrear.Reader(Syccern.in);
BufferedReader br = new BufferedReader (isrj;
String cadena = " " ;
t r y
/ "
readL:ne: public java.lang.Ctring readL;ne(),
es an rietodo de java.ic.BufferedReader
* /
cadera = br.read¿ir.e ( j ;
Cadenas y fechas 1%
i
catch(Excepticr e)
: i
return cadena;
String n o i b z e l , v i - d a d l , noY.bre2, ciuaad2;
Syszem.out.printlr- ("IndlqJe el nombre y pu
no-crel = l e e r ( ) ;
Byste~.oit.prir_ln("~-diquela ciuaad y pci
ciudad1 r leer();
se R E T C W " ) ;
Cystem.cut .priritlr.("InC;q,e el nombre y pulse RETCZL");
nomcre2 = l e e r ( ) ;
Systei.out . p r i r . t l n ("Indique la ci-dad y pulse R5;'JRN") ;
ciuaad2 = leer ( ) ;
Cystem.cu:.printlz ("Comparación con eqiials") ;
if (ciudad1.equals(ciuaad2))
System.out.println(nombre1 + " y "+ nombre2 +
" sor' de la misma ci¿idad");
System.out.println(ncmbre1 - " y "t nombre2 t
" cor de distinta ciudad");
else
Cyscem.out .printlr.("Conparaciór, ccn = = " ) ;
if (ciudaal == ciudad2)
Cyste~.out.printl-(nomhLel + " y "- ncmbre2 +
" san de la misma ciudad");
C y s t e m . o u t . p r i n t l r ( n o m b r e l + " y ''& n o i b r e 2 t
" son de d i s t i r t a ciuaad");
else
I
Si el método leer del programa anterior se sustituye por este otro:
public static Ctrinq l e e r ( )
InputStreamReader :sr = new 1np~~tStreaaReaderjSystern.ir.);
BufferedReader br = new B u f f e r e d R e a c e r ( i s r j ;
S t r i n g cadena = " " ;
try
i
cadena = Icr .readLine ( ) .intern ( ) ;
i
catch(Exceptior, e )
t i
return cadena;
200 Java 2. Manual de programación
el resultado obtenido al comparar con el operador == será diferente, ya que el méto-
do intern ( ) obliga a las cadenas a colocarse en el espacio reservado por Java
para el almacenamiento de literales String.
emplearse el método
Cuando se desean ignorar las diferencias entre mayúsculas y minúsculas, debe
public boolean equalsIgnoreCase (java.1ang.String o t r a c a d )
y, por tanto, la ejecución de las siguientes líneas de programa
if ("ANA".equalsIgnoreCase ("Ana"))
System.out .println("son iguales");
mostraría que las cadenas son iguales.
Nota: compareToy compareToIgnoreCaseson métodos habitualmen-
te utilizados en los programas que necesitan ordenar arrays de cadenas.
Otra forma de comparar cadenas es utilizar el método compareTo,cuyo for-
mato es el siguiente:
public int compareTo (java.lang.String o t r a C a d )
Este método devuelve O cuando las cadenas son iguales, un número negativo si el
objeto String que invoca a compareTo es menor que el objeto String que se le
pasa como argumento y un número positivo cuando es el argumento el que es mayor.
Ejemplos
I . String cadl = new String("Ana");
String cad2 = new String ("Anastasia");
System.out .print ("La cadena " ) ;
if (cadl.compareTo (cad2) < O)
else if (cadl.compareTo (cad2) == O)
else
System.out.println(cad1 t " es menor que " + cad2);
Cystem.out.println(cad1 t " es igual que "t cad2);
System.out.println(cad1 + " es mayor que " + cad2);
el resultado es
La cadena Ana es menor que Anastasia
Cadenas y fechas 201
2. if ("Ana".CGmpareTG ("ANASTASIA")< O)
Systern.out.println ("es menor") ;
Systern.out .println("no es menor") ;
else
el resultado es
no es menor
3. System.out.println("Juan".cornpareTo("Javier")< o ) ;
el re.sultado es
false
Para no diferenciar entre mayúsculas y minúsculas, en lugar de compareTo se
emplea compareT o IgnoreCace.
8.3. coNCATENACIóN
Concatenar cadenas significa unir varias cadenas en una sola conservando el
orden de los caracteres en cada una de ellas. En Java es posible concatenar
cadenas usando tanto el operador + como el método concat.
El operador t en Java tiene un significado especial de concatenación de cadenas
y se puede utilizar con objetos de la clase String.
Ejemplo
String cadl = n e w String("4 + 2");
String cad2 = n e w String(" = " ) ;
String operacion = cadl + cad2;
//imprime 4 + 2 =
Cystern.out.println(operacion);
En el caso de que uno de los operandos que intervienen en una expresión sea de
cadena, el operador t convierte a cadena los valores de otros tipos que intervienen
en la expresión y efectúa concatenación.
Ejemplo
S y S t e m . o u t . p r i n t l n ( o p e r a c i o n t 4 t 2); //Salida 4 + 2 = 42
En el estudio de la concatenación de cadenas y teniendo en cuenta la imposibi-
lidad de modificar los objetos String,es importante comprender el funciona-
miento de las siguientes instrucciones:
202 Java 2. Manual de programación
S:r:.ig av;co = new S t r i n g ("Ura c a d e r a " ) ;
aviso = ob-co - " puede z c n t e n e r caracteres n u m é r i c o s " ;
Estas sentencias no cambian el objeto String original, sino que Java adquiere
una nueva zona de memoria para un nuevo objeto String,donde quepa la nueva
cadena, copia el antiguo en el nuevo objeto y añade la nueva parte. La referencia
aviso apunta ahora hacia la nueva cadena. La vieja versión del String queda
disponible para la recolección de basura.
Estas sentencias se podrían haber escrito de la siguiente forma:
S t r i n g a v i s o = new S t r i n g ( " J n a c a d e n a " ) ;
aT~7:r.o t = 1' puede c o n z e n er c a ract ere s n , m e r 1coc " ;
es decir, es posible también usar el operador += en operaciones de concatena-
ción.
Otra forma de efectuar la concatenación de cadenas es utilizar el método con-
cat.Este inétodo devuelve un nuevo objeto, resultado de añadir los caracteres del
objeto String especificado como parámetro a continuación de los del objeto
String que invoca concat.
Ejemplo
S t r i r . g r a d 1 = new S t r i n g ( " 4 t 2 " ) ;
Stri7.g cae2 = new C:rinq ( " = " ) ;
Srr:ng o p e r a c i o r . = cacil. c o n c a t (cad21;
//i:1,prime 4 t 2 =
C ~ s t e ~ . c ; t . p r : n t l i ( o p e r a r i o n ) ;
8.4. OTROS MÉTODOS DE LA CLASE String
Entre los restantes métodos de la clase String se pueden destacar:
I . , public i n t l e n g t h ( ) )
El método length devuelve la longitud de la cadena
Ejemplo
C-ririg cad1 = new C t r i n q (" ANA" ) ;
Cys:em. out.pr:r.tln (cad:. l e r , g t h ( ) ) ;
Cadenas y fechas 203
Nota: Referencia un carácter fuera de los límites de una cadena S t r i n g , es
decir, con índice negativo o mayor o igual al tamaño del String,produce
una StringIndexOutOfBoundsException.
2. /public char c h a r A t ( i n t indice)l
Devuelve el carácter de la cadena que se encuentra en la posición
especificada mediante el parámetro i n d i c e , lo mismo que en el
caso de los arrays se considera que el primer carácter de una
cadena se encuentra situado en la posición cero y el último en
length ( ) -1.
Ejemplo
public class EjcharAt
public s t a t i c void rnair. ( S t r - n g [ ] args)
I
String cad1 = new String (" ANA" ) ;
for ( i n t i = O ; I < cadl.;engtk. ( ) ; i t t )
C y s t e m . o u t . p r i n t i n ( c a S l . c h a r A t ( l ) ) ;
i
1
h p r i t w e t i priritcillci
A
N
A
3U. /public java.lang.String substring ( i n t i ' i c i ü , i n t Z : R ) ~
36. public java.iang.Strinq substring ( i n t i n i c i o ) 1
El método substring permite extraer una subcadena de una cadena
y puede ser invocado con el paso de uno o de dos parámetros a
elección del programador. Si se especifica un parámetro el método
devuelve una nueva cadena que comienza donde indica inicio
y se extiende hasta el final de la misma; si se especifican dos. la
nueva cadena estará formada por los caracteres existentes en la cadena
original entre la posición inicio y la fi n - 1 , ambas inclusive.
public class Ejsubstrir,gs
I
204 Java 2. Manual de programación
public s t a t i c void main (String[] args)
i
String cadl = new String (" ANA" ) ;
for ( i n t i = O ; i < cadl.length(); I++)
Cystem.out.println(cadl.substring(i,itl));
-rime en pantalla
A
N
A
4. lpublic cnar [ ] toCharArray ( ) 1
Devuelve un array de caracteres creado a partir del objeto S t r i n g .
Ejemplo
public c l a s s EjtoCharArray
{
public s t a t i c void main (String[] a r g s )
Ctrinq sal>Jdo = new String ("hola");
/ / Crea un array de caracteres a partir de la cadena
c h a r [ ; arr = s a l u c i o . t o C k a r A r r a y ( ) ;
/ / Eodifica e l array de caracteres pasando cada
for ( i n t i=O; i<arr.length; i t t )
Cyscerr.out.println(arr);
/ / La cadera no se ha modificado
Systen.o';t .println(saludo);
'Jno de sus caracteres a mayúsculas
a r r [ i ] = ( c h a r )(arr[i]-('a'-'A'));
iinprime en pantalla
HOLA
hola
Observación: El método length() devuelve la longitud de una cadena
mientras que la variable length de un array informa sobre la longitud del
mismo:
cadl .length ( ) ;
arr.length;
Cadenas y fechas 205
5. public boolean regionMatches (boolean i g n o r a D i f , int i n i c i o l ,’
java.lang.String o t r a c a d , int i n i c i o 2 , int c u a n t o s )
Compara una parte de una cadena con parte de otra y devuelve un resultado
b o o l e a n . Si el primer parámetro es t r u e , no distingue entre mayúsculas y
minúsculas. El significado de los restantes parámetros es:
i n i c i o l , posición en la que comienza la comparación para la cadena que
invoca al método.
o t r aCad, la segunda cadena. i n icio2 posición de la segunda cadena en
la que empieza la comparación.
c u a n t o s número de caracteres a comparar.
6.[public boolean endcWith(java.1ang.String s u f i j o ) I
Devuelve t r u e cuando la cadena termina con los caracteres
especificados como argumento.
7.lpublic boolean startsWith(java.lang.String p r e f i j o ) l
Devuelve t r u e cuando la cadena comienza con los caracteres
especificados como argumento.
8U.l public int indexof (int car)]
8b.l public int indexof (java.lang.String cad)I
Estos métodos buscan la cadena o carácter especificados como parámetros
en la cadena fuente; y cuando los encuentran, interrumpen la búsqueda,
devolviendo la posición donde aparece el carácter o donde comienza la cade-
na buscada en la cadena fuente. Si no encuentran el carácter o cadena bus-
cados, devuelven - 1,
indexof podría utilizarse para comprobar si la opción elegida en un menú
de opciones es válida.
import java.io.*;
public class VerificaOpcion
i
public static void main (String[] args)
i
206 Java 2. Manual de programación
//Cadena con el conjunto de opciones válidas
String opciones = "ABCS";
char opcion;
int n;
try
i
System.out .println("MENÚ");
System.out .println("A. Altas") ;
System.out.println ("B. Bajas") ;
System.out.println ("C. Consultas") ;
System.out.println ("S. Salir");
do
t
System.out.print("Elija opción (A, B, C, S) " ) ;
opcion =(char)System.in.read() ;
n = System.in.available();
System.in.skip (n);
)while (opciones.index0f(opcion) == -1 1 I n!=2);
switch (opcion)
i
case 'A':
//Altas
break;
case 'B' :
break;
case 'C':
//Consultas
break:
case ' S I :
//Salir
//Bajas
1
1
catch (Exception e)
t }
9.lpublic java.lanq.Strinq replace (char oldchar, char newChar)l
Devuelve una nueva cadena resultante de reemplazar todas las apariciones
del oldchar con el newchar.
1O.Ipubiic java.lang.string trim0 I
Elimina los espacios en blanco que pudieran existir al principio o final de
una cadena.
11.lpubiic java.iang.string toLowerCase 0 1
Convierte a minúsculas las mayúsculas de la cadena.
Cadenas y fechas 207
13d.
12./public java.lang.string touppercase 01
public static java.lang.String valueof (char[ ] datos,
int desplazamiento, int cont)
Convierte a mayúsculas las minúsculas de la cadena.
13a.lpublic static java.lang.String valueOf(boo1ean b)l
~~
13b.Ipublic static java.lang.String valueOf(char .>I
13~.bublic static java.lang.String valueof (char[ ] datos)]
13e.publicstatic java.lang.String valueof (double d)l
13f. lpubiic static java.1ang.String valueof(fioat f);
13g.lp~biicstatic java.lang.String valueOf(int i)]
13h. lpubiic static java.lang.String valueof (long
13i.lpublic static java.lang.String valueof (java.lang.Object obj)1
Todos estos métodos crean cadenas a partir del correspondiente parámetro y
devuelven dichas cadenas.
~ -
Recuerde: Para convertir una cadena de caracteres que representa un número
al valor correspondiente se utilizan métodos de las clases Double,Float,
Integer,como doublevalue,floatvalue o parseint.En el caso
de doubley floatel primer paso seráconstruir un objeto Doubleo Float,
mientras que en el caso de los tipos enteros no es necesario.
int entero = Integer.parseInt(cadena);
Double d = n e w Double(cadena);
double real = d.doubleValue ( ) ;
208 Java 2. Manual de programación
8.5. LA CLASE StringTokenizer
StringTokenizer pertenece al paquete java .uti1 y actúa sobre String.
Proporciona capacidades para efectuar un análisis gramatical básico de cadenas, efec-
tuando su división en subcadenas por aquellos lugares donde aparecen en la cadena
inicial unos determinados símbolos denominados delimitadores. El primer paso para
efectuar el análisis consiste en la creación de un objeto StringTokenizer
mediante alguno de los siguientes métodos:
la. public StringTokenizer (java.lang.String cad)
lb. public StringTokenizer(java.1ang.String cad, java.lang.Ctring
delim)
IC. public StringTokenizer(java.1ang.String c a d , java.lang.String
delim, boolean devol verTokens)
El parámetro cad representa la cadena que se desea analizar y el parámetro,
delim representa los delimitadores; si no se especifica ningún parámetro se con-
sideran delimitadores por defecto, el espacio en blanco, tabulador, avance de línea
y retorno de carro ( I '  t n rI ! ) , El parámetro que aparece en el tercer construc-
tor devolverTokens,de tipo booleano, permite establecer si se deben devolver
o no los delimitadores cuando se analiza una cadena. Otros métodos interesantes de
la clase en estudio son los siguientes:
public java.lang.String nextToken0
Devuelve el siguiente token (unidad lexicográfica) y cuando no lo encuentra lanza
una excepción,
NoSuchElementException
public java.lang.String nextToken(java.lang.String delim)
Devuelve el siguiente token y permite cambiar la cadena delimitadora.
public boolean hasMoreTokens ( )
Devuelve true o false según queden o no tokens en la cadena.
public int countTokens ( )
Devuelve el número de tokens que aun no se han analizado.
Ejemplo
El siguiente ejemplo muestra el funcionamiento de StringTokenizer a traves
del método divide que recibe como parámetro una cadena con una expresión y
devuelve en un array de cadenas los operandos y operadores de la misma.
Cadenas y fechas 209
Cadena a analizar en el ejemplo
" (31.4+5^2)* 7 . 3 "
Cadena delimitadora que se establece
I l + - * / A ( ) I 1
Salida en pantalla
(
31.4
5
2
+
A
I
*
7 . 3
import java.util.*;
public c l a s s EjStringTokenizer
t
private s t a t i c String[] expresionDividida;
private static String [ ] divide (String cad)
t
StringTokenizer st2 = new StringTokenizer (cad,
i n t cont = O;
while (st2.hasMoreTokens ( ) )
i
"+- * / " ( ) ' I , true) ;
cont++;
st2.nextTokenO;
1
StringTokenizer st = new StringTokenizer (cad,
String[] aux = new String[cont];
for ( i n t i=O; i<aux.length; i++)
return dux;
" +- * / " ( ) " , t r u e ) ;
aux[i] = st.nextToken();
1
public s t a t i c void main (String[] args)
{
String cad = " (31.4+5^2)* 7 . 3 " ;
expresionDividida = divide (cad);
for ( i n t i=O; i < expresionDividida.length; it+)
System.out.println(expresionDividida[i]);
8.6. LA CLASE StringBuffer
AI igual que S t r i n g , la clase StringBuff er también pertenece al paquete
j ava. l a n g y ha sido declarada como f i n a l ; pero a diferencia de los objetos
S t r i n g , con los que se necesita reservar una nueva área en memoria para crear una
nueva versión, los objetos Str ingBu f f er son modificables, tanto en contenido
como en tamaño.
public finai class StringBuffer extends Object iqlements Serializable
210 Java 2. Manual de programación
A la hora de elegir entre usar objetos String o StringBuffer hay que
tener en cuenta que los String mejoran el rendimiento cuando el objeto no se
modifica, mientras StringBuffer es la clase recomendada si el objeto va a
sufrir muchas modificaciones. Los objetos StringBuffer tienen una determi-
nada capacidad y, cuando ésta se excede por la adición de caracteres, crecen auto-
máticamente. En realidad Java utiliza objetos de la clase Str ingBuffer por su
cuenta cuando se utilizan los operadores + o += para concatenar cadenas.
Constructores
public StringBufferO
public StringBuffer (int longitud)
Construye un CtringBuffer
sin caracteres, con capacidad
inicial para 16.
Construye un CtringBuffer
sin caracteres, con capacidad
inicial para longitud carac-
teres.
public StringBuffer (java.lang.Ctring cad)Construye un StringBuffer
con la misma secuencia de ca-
racteres que la cadena recibida
como parámetro. La capacidad
inicial del StringBuffer es
para 16 caracteres más de los
almacenados en dicha cadena.
8.7. MÉTODOS DE LA CLASE StringBuffer
Los métodos importantes de la clase Str ingBuffer son:
public int length()
Devuelve el número de caracteres actuales.
public int capacity
Devuelve la capacidad.
public synchronized void encurecapacity (int minimacapacidad)
Establece una capacidad minima.
public synchronized void setLength (int nuevaLongi tud)
Establece la longitud, si es menor que el número de caracteres actuales se trunca a la
longitud especificada.
public synchronized java.1ang.CtringBuffer append(boo1ean b)
Cadenas y fechas 211
public synchronized java.1ang.StringBuffer append(char c)
public synchronized java.1ang.StringBuffer append(char[] cad)
public synchronized java.1ang.StringBuffer append(char[]
cad, int desplazamiento, int longitud)
public java.1ang.StringBuffer append(doub1e d)
public java.1ang.StringBuffer append(f1oat f)
public java.1ang.CtringBuffer append(int i)
public synchronized java.1ang.CtringBuffer append(1ong 1)
public java.lang.StringBuffer append(java.lang.0bject o b j )
public java.1ang.StringBuffer append(java.lang.String cad)
Los métodos append añaden al final del StringBuffer la cadena resultante de la
transformación del correspondiente argumento.
public java.1ang.StringBuffer insert(int desplazamiento,
boolean b)
public synchronized java.lang.StringBuffer insert(int
desplazamiento, char c)
public synchronized java.lang.StringBuffer insert(int
desplazamiento, char [ ] cad)
public synchronized java.1ang.StringBuffer insert(int index,
char[] cad, int desplazamiento, int longitud)
public java.lang.StringBuffer insert (int desplazamiento, double d)
public java.1ang.StringBuffer insert(int desplazamiento, float f)
public java.1ang.StringBuffer insert(int desplazamiento, int i)
public java.1ang.StringBuffer insert (int desplazamiento, long 1)
public synchronized java.lang.StringBuffer insert(int
desplazamiento, java.lang .Object o b j )
public synchronized java.1ang.StringBuffer insert(int
desplazamiento, java.1ang.String cad)
Los métodos insert colocan distintos tipos de datos, previamente transformados a
cadena, en una determinada posición del StringBuffer.
public synchronized java.1ang.StringBuffer delete(int inicio,
int fin)
212 Java 2. Manual de programación
Elimina del objeto StringBuffer los caracteres exitentes entre las posiciones inicio
y fin-1.
public synchronized java.lang.StringBuffer replace (int i n i c i o ,
Sustituye los caracteres existentes entre las posiciones inicio y fin-i por los especifi-
cados mediante cad.
int f i n , String c a d )
public synchronized java.1ang.StringBuffer reverse0
Invierte la cadena almacenada en el StringBuffer.
public java.lang.String substring(int i n i c i o )
public java.lang.String substring (int i n i c i o , int f i n )
Permite extraer un String de un StringBuffer y puede ser invocado pasándole dos
o bien un único parámetro. Cuando sólo se le especifica un parámetro el método devuelve
una nueva cadena que comienza donde indica inicio y se extiende hasta el final de la mis-
ma, si los parámetros son dos la nueva cadena estará formada por los caracteres existentes
en la original entre la posición inicio y la fin-1,ambos inclusive.
public java.lang.String tostring()
Copia el StringBuffer en un String y devuelve dicha copia.
public synchronized char charAt(int i n d i c e )
Devuelve el carácter existente en una determinada posición.
public synchronized void setCharAt (int i n d i c e , char car)
Coloca el carácter car en una determinada posición, sobreescibiendo el allí existente con
el nuevo.
public synchronized void getchars (int fuenteInicio, int fuenteFin,
char [ I d e s t , int d e s t l n i c i o )
Copia en un array los caracteres del StringBuffer,devolviendo dicho array.
8.8. LA CLASE Date
En Java 2 la clase Date representa fechas y horas y tiene dos constructores:
public Date0
public Date (long num)
Crea un nuevo objeto Date y coloca en e1
la fecha y hora actuales
Crea un nuevo objeto Date y coloca en el
la fecha obtenida al interpretar el paráme-
tro como el número de milisegundos en
que debe incrementarse una fecha arbitra-
ria,] de enero de 1970.
Cadenas y fechas 213
Entre los métodos de esta clase destacan:
public java.lang.S t r i n g tostring ( ) Convierte el objeto Date en una cadena
de caracteres.
public long getTirne ( ) Devuelve el número de milisegundos
transcurridos desde una fecha arbitraria. 1
de enero de 1970.
import java.util.*;
Date actual = new Date();
S y s t e r n . o u t . p r i n t l n ( a c t u a l ) ;
8.9. LOS FORMATOS DE FECHAS
Los formatos especiales para las fechas se establecen mediante la clase DateFormat
del paquete java .text y se crea un objeto,formateador. Format es la clase base
en el formate0 de información sensible a la localidad, como fechas y números.
public abstract class Format extends Object implements
Serializable, Cloneable
y DateFormat extiende Format.
public abstract class DateFormat extends Format
Los métodos
public s t a t i c f i n a l java.text.DateFormat getDateInstance0
Y
public s t a t i c f i n a l java.text.DateForrnat getTirneInstance0
sin parámetros permiten crear unformateador con el estilo de formato local.
Ejemplo
import java.util.*;
import 1ava.text.DateForrnat;
214 Java 2. Manual de programación
. . .
Date actial = new Date 0;
DaieFormat forrateador = DateFormat.getDateInstance0;
C y s t e r . o ü t . p r i n t l n ( f o r n a t e a d o r . f o r . f o r m a c ( a c t u a 1 ) ) ;
También es posible establecer un estilo específico, utilizando el método
public s t a t i c f i n a l java.text.3ateForrat get3ateInctance(int
e s t i l o )
y pasándole alguno de los siguientes valores como parámetro:
public s t a t i c f i n a l i n t DEFAULT
public s t a t i c f i n a l i n t FULL
public s t a t i c f i n a l i n t LONG
public s t a t i c f i n a l i n t MEDIUM
e incluso establecer la localidad
public static f i n a l java.text.DateFormat getDateInctanc
( i n t e s t i l o , java.util.Locale unalocalidad)
Observe que el segundo parámetro es de la clase Locale,algunas de cuyas
constantes son:
public s t a t i c f i n a l java.ut;l.Locale ENGLISH
public s t a t i c f i n a l java.ut:l.Locale GERMAN
Ejemplo
import lava.util.*;
import lava.text.*;
. . .
DaLe actual = new Date 0 ;
DateFormat formateadcr = CateLormat.getDate1nstance
CycteI-.oct.pri?tln(formateador.format(actual));
(>ateFcrnat.LC!dG, Locale.ENGLISH);
8.10. LA CLASE Calendar
La clase Calendar y su subciase GregorianCalendar representan datos de
tipo calendario. La clase Calendar permite crear fechas específicas, establecien-
do el día, mes y año, incluyendo la zona y los ajustes horarios y también permite
obtener todos ellos, así cdmo el día de la semana.
Cadenas y fechas 215
p u b l i c a b s t r a c t c l a s s Calendar extends Object implements
C e r i a l i z a b l e , Cloneable
p u b l i c c l a s s GregorianCalendar extends Calezdar
Entre los métodos de la clase Calenciar se pueden citar:
p u b l i c s t a t i c synchronized j a v a . u t i l . C a l e n d a r g e t I n s t a n c e 0
Devuelve un objeto de tipo Gregoriar!Calendar inicializado con la fecha y hora
actuales y huso horario y sitio por omisión.
p u b l i c f i n a l i n t g e t ( i n t campo)
Devuelve parte de una fecha.
p u b l i c f i n a l Date getTime0
Devuelve el tiempo actual del calendario.
p u b l i c f i n a l void s e t ( i n t año, i n t mes, i n t d i a )
p u b l i c f i n a l void s e t ( i n t año, i n t mes, i n t d i a , i n t h o r a , i n t
minutos)
public f i n a l void s e t ( i n t año, i n t mes, i n t d i a , i n t h o r a , i n t
minutos, i n t segundos)
Establecen partes de una fecha.
p u b l i c f i n a l void cetTime (Date unDatej
Establece el tiempo para el calendario con la fecha dada.
Constantes
p u b l i c static f i n a l i n t JANUARY
p u b l i c s t a t i c f i n a l i n t FEBRUARY
p u b l i c s t a t i c f i n a l i n t MON3AY
p u b l i c s t a t i c f i n a l i n t TUESDAY
. . .
Campos
p u b l i c s t a t i c f i n a l i n t DAYP -OF WEZK
p u b l i c s t a t i c f i n a l i n t DAY OF-YEAR
p u b l i c static f i n a l i n t HOUE-OF~~AY
Ejercicio
El programa FechaCumpl determina cuantos días faltan para un cumpleaños.
216 Java 2. Manual de programación
import java.io.*;
import java.util.*;
public class FechaCumpl
public static void main (String[] argc)
I
InputStreamReader isr = new InputStreamReader(System.in);
BafferedReader br = new BufferedReader(isr);
String nombre;
try
System.out.println ("Escriba su nombre y pulse RETURN") ;
nombre = br .readLine ( ) ;
System.out .print111("indique el día de su cumpleaños"+
int dia = Integer.parseInt(br.readLine0);
System.out.println ("indique el número de mes en que"+
int mes = Integer.parseInt(br.readLine ( ) ) ;
Calendar call = Calendar.getinstance();
Calendar cal2 = Calendar.getInstance();
ca12.set (call.get (Calendar.YEAR),mes -
int diferencia = ca12.get(Calendar.DAY-OF-YEAR) -
if (diferencia > O)
else
"y pulse RETURN") ;
"nació y pulse RETURN");
1,dia);
call.get(Calendar.DAY-OF-YEAR);
System.out .println("Faltan "+diferencia+" dias");
if (diferencia == O)
else
System.out.println("FELICIDADES");
System.out.println("Su cumpleaños fué hace " t
Math.abs (diferencia)+" dias");
1
catch (IOException e)
I
System.out .println("Error");
1
CAPlT 9
InterfacesI gráficasI
de usuario
CONTENIDO
9.1. El AWT.
9.2.
9.3. La clase Component.
9.4. La clase Container.
9.5. Ventanas.
9.6. Clase Panel.
9.7. Clase Label.
9.8. Clase Button.
9.9. Clase Textcomponent.
9.10. Clase Canvas.
9.11. Clase Choice.
9.12. Clase Checkbox.
9.13. Listas.
9.14. Clase Scrollbar.
9.15. Menús.
9.16. Administradores de diseño.
9.17. Swing.
Realización de dibujos: clase Graphics.
217
218 Java 2. Manual de programación
~~
Las interfaces Gráficas de Usuario (IGU)' ofrecen objetos visuales
sobre los cuales pueden los usuarios actuar y de esta forma comu-
nicarse con un programa. En la versión 2 de Java, la biblioteca
denominada Java Foundation Classes proporciona un conjunto de
clases destinadas al diseño de interfaces gráficas, entre las que,
conjuntamente con las de j ava .awt,destacan las pertenecientes
al paquete j avax.swing. Los componentes Swing se ejecutan
uniformemente en cualquier plataforma y constituyen una mejora
sobre los del awt aunque no siempre los reemplazan. Los compo-
nentes de las IGU (botones, campos de texto, etc.) esperan a que
el usuario ejecute alguna acción sobre ellos; es decir, esperan un
evento (o suceso). Por eso se dice que la programación con IGU
es una programación dirigida por eventos. La gestión de eventos
se verá con mayor profundidad en el capítulo diez.
AWT (Abstract Window>Toolkit) es un paquete en el que se encuentran clases capa-
ces de crear componentes de la IGU (GUI); es decir, clases capaces de crear obje-
tos visuales sobre los cuales pueden los usuarios actuar, mediante el empleo del
ratón o el teclado, para comunicarse con el programa, sustituyendo, por tanto,
dichos objetos la entradahalida clásicas. El aspecto de estos componentes puede
variar de una plataforma a otra, ya que existe una vinculación con la IGU local.
Los componentes de la IGU (botones, campos de texto, etc.) se organizan en
contenedores y esperan hasta que el usuario ejecute alguna acción sobre ellos, es
decir, esperan un evento (suceso).Por eso se dice que la programación IGU es una
programación dirigida por eventos. Para el diseño de este tipo de programas es
necesario considerar, como se acaba de indicar, que las interfaces gráficas están
construidas por elementos gráficos denominados componentes agrupados dentro de
otros que se denominan contenedores, pero además hay que tener en cuenta que los
contenedores son a su vez componentes y pueden volver a ser agrupados en otros
contenedores. Habitualmente en un contenedor habrá varios componentes y para
situarlos de forma conveniente pueden usarse los administradores de diseño.
' En ingles, Grupízicul U.yerInrerfuce (CUI)
Interfaces gráficas de usuario 219
p u b l i c abstract void copyArea(int pl, i n t p2, i n t p 3 , i n t p4,
i n t p5, i n t p6)
Copia un área rectangular de la pantalla y la coloca en otro lugar; p1,p2 representan la
esquina superior izquierda del área a copiar; p3 y p4 la anchura y altura de la misma y p5
y p6 un desplazamiento relativo con respecto a los dos primeros valores, a través del cual
se obtiene el lugar donde se situará la esquina superior izquierda de la copia.
p u b l i c abstract java.awt.Graphics c r e a t e 0
Crea una nueva referencia para un contexto gráfico.
Es interesante también conocer que los métodos gráficos de Java se encuentran en
la clase Graphics,que permite dibujar rectángulos, arcos, polígonos, etc., y, median-
te el método drawstring ( ), puede mostrar cadenas en una determinada posición.
En resumen, las clases del paquete AWT pueden clasificarse en: gráficos, com-
ponentes, administradores de diseño, manipuladores de sucesos y manipuladores de
imágenes y, para poder hacer uso de las mismas y gestionar los eventos que se pro-
duzcan, los programas deben incluir las siguientes sentencias:
import j a v a . a w t . * ;
import j a v a . a w t . e v e n t . * ;
9.2. REALIZACIÓN DE DIBUJOS: CLASE Graphics
Graphics es una clase abstracta que proporciona un conjunto de métodos para dibu-
jar en pantalla -incluido uno para el dibujo de cadenas-y permite escribir programas
que usan gráficos independientemente de la plataforma sobre la que van a ser ejecuta-
dos. Para efectuar dichos dibujos se necesita un objeto Graphics que no puede ser
instunciado, pero se puede obtener a través de los métodos paint y update que lo
reciben como parámetro; por tanto, para dibujar, se redefinen los métodos paint y
update de componentes que soportan el dibujo (pintura) o visualización de imáge-
nes. Los métodos paint y update se explicarán al hablar de la clase Component;
por ahora sólo diremos que reciben como parámetro un objeto Graphics, que repre-
senta el contexto gráfico del objeto al que pertenecen, y no hacen nada por omisión.
Dentro de los métodos pertenecientes a la clase Graphics mencionaremos los
siguientes:
p u b l i c abstract void clearRect ( i n t pl, i n t p2, i n t p3, i n t p4)
Dibuja un rectángulo cuya esquina superior izquierda es pl,p2 y cuyas dimensiones son p3
y p4 (ancho y alto respectivamente) en el color actual del segundo plano.
public abstract void c i i p R e c t ( i n t pl, i n t p2, i n t p3, i n t p4)
Establece una subzona en el contexto gráfico donde se van a realizar las modificaciones con
las siguientes operaciones de dibujo; esta subzona será la intersección entre el rectángulo
formado por los parámetros pasados al procedimiento y el rectángulo anteriormente consi-
derado.
220 Java 2. Manual de programación
p u b l i c abstract void drawArc(int p l , i n t p2, i n t p3, i n t p4,
i n t p 5 , i n t pó)
Dibuja un arco de modo que pl y p2 son las coordenadas de la esquina superior izquierda de
un rectángulo que contuviera dicho arco; p3 y p4 especitican la altura y anchura de dicho rec-
tángulo y p5 y p6 son un ángulo de inicio y un ángulo de barrido, ambos expresados en gra-
dos. El arco se dibuja desde la posición que indica el ángulo de inicio, recorriendo en sentido
contrario a las agujas del reloj los grados especificadas como ángulo de barrido.
p u b l i c abstract void drawLine(int pl, i n t p2, i n t p 3 , i n t p4)
Dibuja una línea del color seleccionado que comienza en pi,p2y termina en p3,p4.
p u b l i c abstract void drawOval(int pl, i n t p2, i n t p3, i n t p4)
Dibuja una elipse o un círculo. En el caso de la elipse, pl y p2 son las coordenadas para la
esquina superior izquierda de un rectángulo que contuviera a la elipse; p3 y p4 especifican la
altura y anchura de dicho rectángulo. Se obtiene un círculo cuando se enmarca en un cuadrado.
p u b l i c abstract void drawPoiygon ( i n t pl [ 1 , i n t p2[ 1 , i n t p3)
Dibuja una serie de líneas conectadas. Para que la figura esté conectada el primer punto debe
ser igual al último. El primer y segundo parámetro son las matrices que contienen las coor-
denadas y el tercero especifica el número de puntos.
p u b l i c void drawRect(int pl, i n t p2, i n t p 3 , i n t p4)
Dibuja un rectángulo cuya esquina superior izquierda es pl,p2y cuyas dimensiones son p3
y p4 (ancho y alto respectivamente).
public void draw3DRect ( i n t pl, i n t p2, i n t p3, i n t p4, boolean p5)
Dibuja un rectángulo tridimensional en el color actual; pl y p2 son las coordenadas de la
esquina superior izquierda; p3 y p4 la anchura y altura del rectángulo, y p5 un valor boo-
leano que especifica si el rectángulo debe dibujarse hundido ( f a l s e )o realzado (true).
public abstract void drawstring (java.lang. String pl, i n t p2, i n t p3)
Dibuja una cadena empleando la fuente y color actuales a situando el primer carácter de la
misma arriba y a la derecha del pixel especificado por los parámetros p2 y p3.
p u b l i c abstract void f i l l A r c ( i n t p l , i n t p2, i n t p3, i n t p4,
i n t p5, i n t p6)
Dibuja un arco relleno.
p u b l i c abstract void f i l l O v a l ( i n t pl, i n t p2, i n t p 3 , i n t p4)
Dibuja una elipse o un círculo rellenos.
p u b l i c abstract void f i l l R e c t ( i n t pl, i n t p2, i n t p3, i n t p4)
Dibuja un rectángulo relleno cuya esquina superior izquierda es pl,p2 y cuyas dimensio-
nes son p3 y p4 (ancho y alto respectivamente).
p u b l i c abstract java.awt.Color g e t l o l o r ( )
Permite obtener el color actual en el que se realizarán los dibujos.
p u b l i c abstract Font getFont ( )
Devuelve un objeto Font que representa la fuente actual.
Interfaces gráficas de usuario 221
public abstract void setColor(java.awt.Color pl)
Establece el color actual para dibujar en el contexto gráfico. Las constantes y métodos de
color se definen en la clase Color.Constantes de color predefinidas son:
Color.black, Color.white,Color.gray,Color.lightGray,
Color.darkGray,Color.red, Color.pink,Color.orange,
Color.yellow,Color.green, Color.blue, Color.cyan,
Color .magenta.
public abstract void cetFont (java.awt .Font pl)
Establece como fuente actual la especificada en el objeto Font.Para crear un objeto
Font con una determinada fuente, estilo y tamaño se utiliza:
public Font(java.lang.String pl, int p2, int p3)
El primer parámetro es el nombre de la fuente, el segundo el estilo y el tercero el tamaño
en puntos. La fuente puede ser cualquiera de las reconocidas por el sistema; si la elegida
no está disponible en el sistema donde luego se ejecuta el programa será sustituida por la
fuente por omisión en dicho sistema. Constantes predefinidas en cuanto al estilo de fuen-
te son Font.PLAIN (normal), Font.ITALIC (cursiva), Font .BOLD (negrita).
Otra herramienta muy útil de la clase Font es
public int getsize ( )
que devuelve el tamaño de la fuente actual en puntos.
public java.awt.FontMetrics getFontMetrics0
Devuelve los siguientes datos sobre la fuente actual: línea de base (posición del renglón
sobre el que se escribe), parte ascendente, parte descendente, anchura de los caracteres,
interlineado, altura de la fuente. Se utiliza en combinación con otros métodos:
public int getAscent 0
public int getDescent 0
public int getHeight ( )
public int getleadingo
public int [ ] getwidths ( )
para obtener información sobre una determinada característica de la fuente. Un ejemplo es:
int alto = g .getFontMetrics ( ) .getHeight ( 1 ;
public abstract void setXORMode(java.awt.Color pl)
Establece el modo de pintura XOR,que consigue que las figuras se transparenten y permitan
ver la que está debajo cuando se dibujan una encima de otra.
En los métodos descritos se observa que para dibujar la primera acción que se
realiza es un posicionamiento; por tanto, es necesario conocer que la posición 0,O
corresponde a la esquina superior izquierda de la superficie de dibujo, y además,
como se verá más adelante, que algunos contenedores tienen bordes, y el área ocu-
pada por estos bordes se considera como parte integrante de la zona de dibujo, de
modo que, en estos casos, la posición 0,O queda oculta por los bordes.
Otro aspecto interesante a tener en cuenta es que el modo de pintura por omisión
es el de sobrescritura y, así, cuando una figura se dibuja sobre otra la tapa, es posible
222 Java 2. Manual de programación
modificar esta situación y permitir que se vean ambas figuras estableciendo el
modo de pintura XOR. Para volver al modo sobrescritura se utiliza public
abstract void setPaintMode0.
Las aplicaciones que se diseñan pueden crear un gran número de objetos Graphics,
pero los recursos consumidos por los objetos Graphics obtenidos a través de los
métodos paint y update son liberados automáticamente por el sistema cuando
finaliza la ejecución del método; por esta razón, en estos casos, no es necesaria una
llamada a dispose.
Recuerde: Graphics proporciona, entre otros, el método drawstring
que permite el dibujo de cadenas y constituye una forma muy fácil de presen-
tar mensajes.
Nota: Para efectuar dibujos se redefinen los métodos paint y update de
componentes que soportan la pintura o visualización de imágenes; ésta es una
forma de obtener el objeto Graphics necesario.
9.3. LA CLASE Component
Component es una clase abstracta situada en la parte superior de la jerarquía de
clases del paquete AWT y que representa todo aquello que tiene una posición, un
tamaño, puede dibujarse en pantalla y además recibir eventos. En esta clase se
definen métodos para la gestión de los eventos producidos por el ratón o el tecla-
do, otros destinados a especificar el tamaño, el color o tipo de fuente y otros que
permiten obtener el contexto gráfico. Entre todos esos métodos, de momento, se
destacarán los siguientes:
public void paint(java.awt.Graphicc pl)
El método paint proporcionado por el componente debe ser redefinido por el progra-
mador; este método recibe como parámetro el contexto gráfico del objeto al que perte-
nece el método y no tiene que ser invocado. La llamada a un método paint se efectúa
de dos formas:
Directamente por el sistema, por ejemplo cuando el componente se muestra por pri-
mera vez en pantalla, deja de estar tapado por otro o cambia de tamaño. En este tipo
de llamadas el AWT determina si el componente debe ser repintado en su totalidad o
sólo en parte.
Interfaces gráficas de usuario 223
Por la aplicación, que invoca al método repaint,considerando que éste, indirecta-
mente, a través de update llama a paint.
public void repaint ( )
Es el método que permite a las aplicaciones, mediante invocaciones a dicho método sobre
los componentes, ordenar la repintura de los mismos. Este método hace que el intérprete eje-
cute una llamada al método update,que en su implementación por defecto llama al méto-
do paint.El formato mostrado es el básico.
Figura 9.1. Jerarquía de clases.
224 Java 2. Manual de programación
public void repaint(int pl, int p2, int p3, int p4)
Formato del método comentado anteriormente en el que se especifica la región a repintar,
para que el proceso sea más rápido cuando no se necesita vover a pintar todo el área.
public void repaint (long pl)
El parámetro especifica el máximo de milisegundos que pueden pasar antes de llamar al
método update.
public void repaint (long pl, int p2, int p3, int p4, int p5)
Formato de repaint en el que se especifica tanto el tiempo como las dimensiones del área
a repintar; pi y p2 son las coordenadas de la esquina superior izquierda, p3 la anchura y
p4 la altura.
public void update(java.awt.Graphics pl)
Este método posibilita repinturas incrementales. AI igual que paint recibe como paráme-
tro el contexto gráfico del objeto al que pertenece y se invoca automáticamente cuando una
aplicación llama al método repaint.Cuando no se sobreescribe, el método update
borra el contexto gráfico rellenando el fondo con el color de fondo por defecto y llama a
continuación a paint para que dibuje de nuevo; estas operaciones hacen que se origine un
parpadeo. Una forma de evitar esto es sobrescribir update para que no borre el contexto
gráfico; por ejemplo, escribiendo en él una simple llamada a paint.
Todos los elementos de la interfaz de usuario que aparecen en pantalla e inte-
ractúan con el usuario son subclases de Component (Fig. 9.1).
9.4. LA CLASE Container
Container es una subclase abstracta de Component que contiene métodos adi-
cionales que van a permitir a los contenedores almacenar objetos Component.
Nota: Los objetos Container también son Component y, por consiguiente,
resulta posible anidar Container.
Los componentes se colocan en los contenedores empleando el método add de
la clase Container y los administradores de diseño acomodan los componentes
en el contenedor e intentan reajustarlos cuando el usuario redimensiona dicho con-
tenedor. Los administradores de diseño se asocian al contenedor mediante el méto-
do setLayout.El formato de los métodos citados es:
public java.awt.Component add(java.awt.Cornponent pl)
public void add(java.awt.Cornponent pl, java.lang.0bject p 2 )
public java.awt.Component add(java.lang.Ctring pl,
public void setLayout(java.awt.LayoutManager pl)
java.awt.Component p2)
Interfaces gráficas de usuario 225
Los principales administradores de diseño son: FlowLayout, BorderLayout
y GridLayout.
9.5. VENTANAS
La clase Window hereda de Container y contiene métodos para manejar venta-
nas. Frame y Dialog extienden Window y FileDialog extiende Dialog,
pudiéndose obtener así cuatro tipos básicos de ventanas:
Window
Frame
Dialog
FileDialog
Ventana de nivel superior, sin barra de título ni borde.
Marco, es decir, ventana con borde, título y una barra de menús asociada.
Ventana de diálogo con borde y título.
Ventana de diálogo especializada en mostrar la lista de archivos de un directorio.
9.5.1. Clase Frame
En las aplicaciones IGU se emplea Frame como contenedor más externo, siendo
BorderLayout su administrador de diseño por defecto. La clase Frame tiene los
siguientes constructores:
public Frame ( ) Crea una ventana estándar sin titulo.
public Frame ( java.lang .String p i ) Crea una ventana con el titulo especificado.
El método publicsynchronizedvoidsetTitle (java.lang.Stringpl)
permite cambiar el título de un marco.
IIFigura 9.2. Marcos sin y con barra de menús.
Las dimensiones de una ventana tienen que ser establecidas después de que ésta
ha sido creada, y para ello se utiliza el método public void setSize (int
pl, int p2) de java .awt .Component. Además, las ventanas Frame
necesitan que se las haga visibles, para lo que se emplea el método public void
setvisible (boolean pl) de java.awt .Component.
226 Java 2. Manual de programación
Cierre de la ventana de una aplicación
Para cerrar una ventana, el método usualmente aceptado es que el usuario efectúe
clic sobre el botón de cierre de la misma m.La pulsación de este botón genera un
suceso que puede ser detectado por el oyente WindowListener del paquete
java .awt .event,para ello se instancia y registra un objeto receptor de even-
tos de ventana.
addWindowListener(new ReceptorEventoO)
y luego se define el receptor de eventos de forma que suplante y redefina el méto-
do windowClosing de WindowAdapter realizando la acción adecuada, que,
para el contenedor más externo, es salir al sistema.
class ReceptorEvento extends WindowAdapter
public void windowClosing(WindowEvent e)
System.exit(O);
WindowAdapter es una clase que proporciona implementaciones vacías de
los métodos presentes en WindowListener y que resulta conveniente utilizar,
pues evita tener que codificar los muchos métodos que requiere el uso de dicha
interfaz.
WindowListener
public abstract void windowActivated(java.awt.event.WindowEvent pl)
public abstract void windowClosed(]ava.awt.event.WindowEvent pl)
public abstract void windowClosing(~ava.awt.event.WindowEventpi)
public abstract void windowDeactivated(java.awt.event.WindowEvent pl)
public abstract void windowDeiconified(java.awt.event.WindowEvent pl)
public abstract void windowIconified(java.awt.event.WindowEvent pl)
public abstract void windowOpened(java.awt.event.WindowEvent pl)
lnterfaces gráficas de usuario 227
Los tipos WindowEvent se generan cuando una ventana cambia de estado y se
procesan por los objetos que implementa la interfaz WindowListener.
Ejemplo
Un ejemplo de Frame que utiliza Graphics y permite el cierre de la ventana de
la aplicación usando WindowAdapter es EjMarco.
IBienvenido ai AWT
I
Figura 9.3. Escribir en un marco.
import java.awt.*;
import java.awt.event.*;
public c l a s s EjMarco extends Frame
i
public s t a t i c void main( String args[] )
t
new EjMarco ( ) ;
public EjMarco ( )
t
addWindowListener (new Cierre ( ) ) ;
setTitle ("Marco");
setsize (200,100);
setvisible (true) ;
1
public void paint (Graphics g)
t
Font letrero = new Font ("CancCerif", Font.ITALIC, 14);
g.setFont (letrero);
g.drawString("Bienvenido al AWT", 42,60);
1
c l a s s Cierre extends WindowAdapter
I
public void windowClosing (WindowEvent e)
i
I
Cystem.exit (O);
1
228 Java 2. Manual de programación
El ejemplo anterior sin la utilización de WindowAdapter es:
import java.awt.*;
import java.awt.event.*;
public class EjMarco2 extends Frame implements WindowListener
t
public static void main( String args[] )
I
new EjMarco2 ( ) ;
i
public EjMarco2 ( )
addWindowListener (this);
setTitle ("Marco");
setsize (200,100);
setvisible (true);
public void paint (Graphics g)
i
Font letrero = new Font ("SansSerif", Font.ITALIC, 14);
g.setFont (letrero);
g.drawString ("Bienvenido al AWT",42,60);
public void windowClosing(WindowEvent e)
i
System.exit (0);
i
public void windowActivatediWindowEvent e)
i }
public void windowClosed(WindowEvent e)
t i
public void windowDeactivated(W1ndowEvent e)
I!
public void windowDeiconified(Wind0wEvent e)
t i
public void windowIconified(WindowEvent e)
i!
public void windowOpened(WindowEvent e)
t i
hterfaces gráficas de usuario 229
9.5.2. Clase Dialog
Los cuadros de diálogo son parecidos a las ventanas Frame, excepto porque no son
el contenedor más externo, sino ventanas hijas de otras de nivel superior, y además no
tienen barra de ineiiús. Estos objetos pueden ser redimensionados, desplazados y
colocados en cualquier lugar de la pantalla, no estando su posición restringida al inte-
rior de la ventana padre, pero no pueden ser maximizados ni minimizados.
Figura 9.4. Cuadro de diálogo.
A veces, cuando se muestra un cuadro de diálogo, lo que se persigue es que el
usuario introduzca o tome alguna información y cierre dicho cuadro de diálogo
antes de continuar, no se debe permitir el acceso a ninguna otra parte de la aplica-
ción mientras tanto. Para conseguir esto, habrá que utilizar un cuadro de diálogo
modal. En contraposición, los cuadros de diálogo sin modo dejan acceder a otras
ventanas mientras se exhibe el cuadro de diálogo. Los constructores son:
public Dialog (1ava.awt .Frame pl)
El paráinetro pl es la ventana de nivel superior padre del cuadro de diálogo.
public Dialog (java.awt .Frame p i , boolean pZ)
El priiner paráinetro sigue siendo la ventana de nivel superior, mientras que p2 permite
especificar si va a ser o no un cuadro de diálogo modal.
public Dialog(]ava.awt.Frame pl, java.lang.Ctring p2)
Este formato permite especificar el titulo del cuadro de diálogo que se está creando
public Dialog(:ava.awt.Fraxe pl, java.lang.String p2, boolean p 3 )
Incluye el título y si es modal o no.
Después de la creación, se puede establecer el tipo de cuadro de diálogo (modal
o no modal) mediante el método
public void setModal (boolean pl)
Ejemplo
Muestra el funcionamiento de Dialog.
230 Java 2. Manual de programación
import java.awt.*;
import java.awt.event.*;
public class Dialogos
public static void main( String args[])
t
Marco elMarc0 = new Marco();
elMarco.setTitle ("Marco");
elMarco.setCize( 400,200 ) ;
elMarco.setVisible( true ) ;
elMarco.addWindowListener(new Cerrar());
Dialogo dialogoNoModa1 = new Dialogo(elMarco,
dialogoNoModal.setBackground(Color.yel10~);
dialogoNoModal.getGraphics0;
/ * setBounds coloca la esquina superior de: diálogo en la
posición 100, 100 con
respecto a su contenedor y establece su anchura en 300
pixels y su altura en 100 * /
"Dialogo no modal", false);
dialogoNoModal.setBounds(100,100,300,100);
dialogoNoModal.addWindowListener(new Cerrar(dialogoNoModa1));
dialogoNoModal.setVisible(true);
Dialogo dialogoModa1 = new aialogo (elklarco,
diaiogoModal.setSize(300,iOO);
dialogoModal.addWindowListener(new Cerrar(dialogoModa1));
dialogoModal.setVisible(true);
"Dialogo modal", true);
1
class Marco extends Frame
i
public void paint (Graphics g )
Font letrero = new Font ("Courier", Font.BOLD, 12);
g.setFont (letrero);
g.drawString("Bienvenid0 ai AWT",24,70);
!
class Dialogo extends Dialog
Dialogo (Frame ventana, String titulo, boolean modo)
super (ventana, titulo, modo) ;
1
public void paint (Graphics g)
interfaces gráficas de usuario 231
i f (super.icModal ( ) )
g.drawstring ("Ciérreme para poder acceder" +
"a otras ventanas", 10,40);
else
g.drawCtring ("Desde este cuadro puede acceder" +
"a otras Ventanas", 10,40);
}
J
c l a s s Cerrar extends WindowAdapter
I
Dialogo otroDialogo;
Cerrar( Dialogo unDialogo )
i
otroDialogo = unDialogo;
I
Cerrar ( )
otroDiaiogo = null;
i
public void windowclosing( WindowEvent evt )
t
i f (otro3iaiogo ! = n u l l )
otroDialogo.dispose();
else
System.exit (O);
Llr;S@ 0'1n í u m u 11i ~ d 8dcceú~i3 01t.35 irF<nlarid:
- J
Figura 9.5. Cuadros de diálogo modales y no modales.
232 Java 2. Manual de programación
Nota: Un cuadro de diálogo modal, mientras no se cierra, no permite el acce-
so a ninguna otra parte de la aplicación. Los cuadros de diálogo sin modo
dejan acceder a otras ventanas mientras se exhibe el cuadro de diálogo.
9.5.3. Clase FileDialog
Estos cuadros de diálogo heredan de la clase Dialog,son modales por omisión y
tienen ciertas capacidades incorporadas, como la de recorrer el árbol de directorios.
El aspecto que presentan depende del sistema de manejo de ventanas, así como del
subtipo de cuadro del que se trate: abrir archivos o guardar archivos, especificado
en el constructor.
Ejemplo
El programa DialogoA permite seleccionar un archivo mediante un cuadro
FileDialog (Fig. 9.6) y, si se selecciona alguno, muestra a continuación un diá-
logo informativo con el nombre completo del archivo seleccionado (Fig. 9.7).
3Cei
dDie
tiDit
2Ve,
alventanas1
Dialogos d
larclal Mi PC Archivo CLASS
Iioga4 & Disco de 3%[A 1 Archivo CLASS
Archivo CLASS
Archivo CLASS 1E
Archivo CMCC 2:
lulo CI libro
Archivo CLASS
-J ,.,,a Y Y l U l l l l l l l V I
Ttana a m
ID 1
Figura 9.6. Elección del archivo FileDialog.LOAD.
Archivo P6tt@tC¡ondd
Figura 9.7. Diálogo informativo.
Interfaces gráficas de usuario 233
import java .awt .* ;
import java.awt.event.*;
public class DialogoA
{
public static void main ( String args [ ] )
i
}
Ventana ventanas = new Ventana ( ) ;
1
class Ventana
i
String msg="";
public Ventana ( )
t
Frame elMarco = new Frame ( ) ;
FileDialog dialogoArchivos = new FileDialog(elMarco,
dialogoArchivos.setVisible(true);
String nombre = dialogoArchivos.getFile();
String directorio = dialogoArchivos.getDirectory0;
if (nombre != null)
{
"Elija archivo", FileDialog.LOAD);
msg ="Archivo seleccionado: "t directorio t nombre;
Dialogo2 dialogoModa1 = new Dialogo2(elMarco,
dialogoModal.setSize(msg.length()*5+24,lOO);
dialogoModal.addWindowListener(new Cerrar2(dialogoModal));
dialogoModal.setVisible(true);
"Diálogo modal", true, msg) ;
System.exit (O);
1
class Dialogo2 extends Dialog
I
String mensaje;
Dialogo2 (Frame ventana, String titulo, boolean modo, String msg)
{
super (ventana, titulo, modo) ;
mensaje = msg;
1
public void paint (Graphics g)
I
Font letrero = new Font ("Helvetica", Font.PLAIN, 10);
g.setFont (letrero);
g.drawString (mensaje,12,4O);
}
234 Java 2. Manual de programación
class Cerrar2 extends WindowAdapter
{
Dialogo2 otroDialogo;
Cerrar2( Dialogo2 unDialogo )
otroDialogo = unDialogo;
i
public void windowClosing( WindowEvent evt )
I
)
otroDialogo.dispose0;
9.6. CLASE Panel
Los objetos de la clase Panel carecen de barra de título, barra de menús y borde,
se emplean para almacenar una colección de objetos a los que de esta forma se
organiza en unidades, no generan eventos y adquieren el tamaño necesario para
que quepan los componentes que contienen. Esta clase es la superclase de Applet
y su administrador de diseño por defecto es FlowLayout.
Constructores
public Panel ( ) Crea un nuevo panel.
public Panel ( java .awt .LayoutManager pi ) Crea un nuevo panel y
establece un determinado
administrador de diseño para
él. Por ejemplo:
Panel pX = new Panel
(new GridLayout ( ) ) ;
Para destacar un panel se establece un determinado color de fondo para él. El panel
se coloca en un contenedor mediante el método add y, como él también es un conte-
nedor, se le pueden agregar componentes, incluidos otros paneles, mediante el
método add.
9.7. CLASE Label
Label extiende la clase Component y permite mostrar texto estático, es decir,
texto que no puede ser modificado por el usuario, en una IGU. Para crear un rótulo
con la clase Label es necesario declarar una referencia y llamar al constructor.
interfaces gráficas de usuario 235
Constructores
public Label ( ) Crea una etiqueta sin texto.
public Label (java.lang.String p i ) Creaunaetiquetacuyotextoeslacadena
pasada como parámetro.
La cadena de caracteres que presenta la etiqueta puede modificarse con el
método
public synchronized void setText(java.lang.String p l )
y se devuelve mediante
public java.lang.String getText()
El procedimiento
public synchronized void setAlignment (int pi)
permite establecer la alineación del texto. El parámetro p l puede ser cualquiera de
las siguientes constantes predefinidas:
public static final int CENTER
public static final ant LEFT
public static final int RIGHT
Como todos los componentes, las etiquetas se colocan en los contenedores median-
te el método add de la clase Container.
add (referencia-etiqueta)
I
Figura 9.8. Etiquetas, paneles. Empleo de colores de fondo
para destacar los paneles.
236 Java 2. Manual de programación
El siguiente ejemplo muestra cómo crear etiquetas y paneles y establecer colores de
fondo.
import java.awt.*;
import java.awt.event.*;
public class Paneles extends Frame
i
public Paneles ( )
t
addWindowListener(new Cierre30 ) ;
Panel pX = new Panel();
pX.setBackground(Color.black);
Panel pY =new Panel ( ) ;
pY.setBackground(Co1or.red);
Label etiqueta1 = new Label ("Los paneles se adaptan") ;
Label etiqueta2 = new Label ("a nuestro tamaño");
etiquetal.setBackground(Co1or.white);
pY.add(etiqueta1) ;
pY.add(etiqueta2);
pX.add(pY);
add (pX);
public static void main( String args[l )
i
Paneles ventana = new Paneles 0 ;
ventana.setLayout(new FlowLayoutO);
ventana.setTitle ( "El AWT" ) ;
ventana.setSize( 300,120 ) ;
ventana.setVisible(true);
I
1
class Cierre3 extends WindowAdapter
t
public void windowClosing(WindowEvent e)
t
I
System.exit (O) ;
1
9.8. CLASE Button
Esta clase produce botones con etiqueta que provocan la ejecución de una acción
cuando se efectúa clic en ellos con el ratón. La clase Button define los siguientes
constructores:
Interfaces gráficas de usuario 237
public Button ( ) Crea un botón sin etiqueta.
public Button (java.lang .String p i ) Crea un botón cuya etiqueta es la cadena
pasada como parámetro.
y pone a disposición del programador una colección de métodos entre los que des-
tacan
public synchronized void
addActionListener(java.awt.event.ActionListener pi)
Añade un receptor de eventos semánticos
public synchronized void
removeActionListener(]ava.awt.event.ActionListener p i )
Elimina el receptor de eventos
public java.lang.String getlabel()
Devuelve la etiqueta del botón
public synchronized void setLabel(java.1ang.String pi)
Establece la etiqueta del botón
Ejemplo
Colocación de botones en un contenedor (Fig. 9.9).
Los botones de este ejemplo no ejecutan ninguna acción.
import java .awt .* ;
import java.awt.event.*;
public class Prueba extends Frame
i
public Prueba ( )
I
addWindowListener(new Cierre30);
Panel panelBotones = new Panel ( ) ;
for (int i = 1; i < 8 ; i++)
panelBotones.add (new Button ("Botón "+i ) ) ;
/* Se utiliza el administrador de diseño por defecto en la
clase Frame para colocar el panel en el área Sur * /
add ( "South", panelBotones ) ;
public static void main( String args[J )
i
Prueba ventana = new Prueba ( ) ;
238 Java 2. Manual de programación
ventana.setTitle ( "El AWT" ) ;
ventana.setSize( 400,250 ) ;
ventana.setVisible(true);
1
La clase Cierre3 ya fue implementada en el Apartado 9.7.
Figura 9.9. Botones.
Aunque la gestión de eventos se tratará en el Capítulo 10, es necesario advertir
que, cuando se colocan botones en un contenedor, tienen como objetivo reaccionar
ante su pulsación. Para que se pueda reaccionar ante la pulsación de un botón hay
que enlazarlo a ActionListener, interfaz definida en awt .event con un
único método a implementar denominado actionperformed, por lo que no
necesita adaptadores. Este método tiene un parámetro del tipo ActionEvent,que
puede informar a través del método getsource sobre el botón que ha sido pulsa-
do, y deberá ser redefinido para establecer la reacción adecuada ante la pulsación
de un determinado botón. El marco en uso será el responsable de la redefinición del
método actionperformed.
9.9. CLASE Textcomponent
La clase Textcomponent dispone de ina gran colección de métodos para fa ili-
tar la presentación de texto en un programa IGU, pero no dispone de constructores
públicos, por lo que no puede ser instanciada. Posee dos subclases, TextField y
TextArea.TextField permite mostrar al usuario un area de una Única línea,
mientras que TextArea presenta varias líneas. El texto mostrado, tanto en uno
como en otro caso, puede ser editable o no.
Interfaces gráficas de usuario 239
Los constructores de TextField son:
public TextField ( )
Crea un campo de texto por defecto.
public TextField (int pl)
Crea un campo de texto con p 1 caracteres de ancho, este número de caracteres no define la
anchura del campo, pues esto depende del tipo de letra y del administrador de diseño que se
empleen.
public TextField(java.1ang.String pi)
Crea un campo de texto y lo inicializa con la cadena pl
public TextField (java,lang.String pi, int p2)
Crea un campo de texto, inicializándolo con la cadena p i y estableciendo su ancho a p2
caracteres.
Otros métodos interesantes en el trabajo con campos de texto son:
public synchronized java.lang.String getText0
Método de lectura. Obtiene la cadena contenida en un campo de texto.
public synchronized void setText(java.lang.Ctring pi)
Método de escritura. Establece el contenido de un campo de texto.
public synchronized void select(int pl, int p2)
Selecciona una serie de caracteres comenzando en pi y terminando en p2.
public synchronized void selectAl1 ( )
Método para seleccionar todos los caracteres pertenecientes a Textcomponent.
public synchronized java.lang.String getSelectedText0
Obtiene el texto previamente seleccionado. La selección previa pudo realizarse por la orden
select o directamente por el usuario.
public synchronized void setEditable (boolean pl)
Controla la editabilidad del campo.
public void setEchoChar (char pl)
Sirve para introducir contraseñas, pues inhabilita el eco de los caracteres, exhibiendo en su
lugar el carácter especificado como parámetro.
En los cuadros de texto será necesario tratar el evento que se produce al pulsar
la tecla RETURN. Este tratamiento consistirá en enlazar el campo de texto a la inter-
faz ActionListener,y redefinir su método actionperformed,que tiene
un parámetro capaz de informar sobre el campo de texto en el que ha sido pulsada
la tecla RETURN (INTRO).
240 Java 2.Manual de programación
Ejemplo
Solicita el nombre y la edad del usuario mediante cuadros de texto. La edad se soli-
cita con un cuadro «sin eco)),de forma que no se vea lo que se está tecleando. Tras
la pulsación de RETURN en el cuadro edad, el programa transforma la cadena leída
en un número, muestra dicha edad, y se disculpa por su falta de confidencialidad
mediante la adición al mensaje de la palabra Joven".El ejemplo pretende resal-
tar que los cuadros de texto no permiten la lectura directa de números. Utiliza
repaint y responde a eventos.
Intoduzca su nombre 5'
lntoduzca la edad en añosy pulse <RETURN>a continuación
Figura 9.10. Cuadros de texto.
lntoduzca la edad en añosy pulse <RETURN>a continuación
Joven de 86 años
Figura 9.11. Salida mostrada por el programa
lnterfaces gráficas de usuario 241
import java.awt.*;
import java.awt.event.*;
public class CTexto extends Frame implements ActionListener
t
int edad = 0;
TextField texto2;
public CTexto ( )
t
addWindowListener(new Cierre30);
Label etiqueta1 = new Label ("Introduzca su nombre");
add(etiqueta1);
TextField texto1 = new TextField ( " " , 35);
add(texto1);
Label etiqueta2 = new Label ("Introduzcala edad en años" +
add (etiqueta2);
texto2 = new TextField("",2);
textoZ.setEchoChar('*');
add (texto2);
textoZ.addActionListener(this);
"y pulse <RETURN> a continuación");
1
public void paint (Graphics g)
i
try
i
edad = Integer.parseInt(texto2.getText( ) ) ;
g.drawCtring ("Joven de "+edad+" años",24,150);
1
catch (Exception ex)
t }
1
public void actionperformed (ActionEvent e)
i
if (e.getsource ( ) ==texto2)
repaint ( ) ;
i
public static void main( String args[] )
I
CTexto vt = new CTexto ( ) ;
vt.setLayout (new FlowLayout 0 ) ;
vt.setTitle( "El AWT" ) ;
vt.setSize( 400,250 1 ;
vt.setVisible(true);
I
i
La clase TextArea efectúa la presentación de areas de texto en pantalla. Sus
constructores y algunos otros métodos destacables son:
242 Java 2. Manual de programación
public TextArea ( )
Crea un área de texto por defecto.
public TextArea (int pl, int p 2 )
Crea un área de texto con p i filas y p2 columnas.
public TextArea(java.1ang.String pl)
Crea un área de texto y la inicializa con la cadena p i .
public TextArea (lava.lang.String pi, int p2, int p 3 )
Crea un área de texto y la inicializa con la cadena p 1, estableciendo como número de filas
p2 y como número de columnas p3.
public synchronized java.lang.String getText0
Método de lectura. Obtiene el texto.
public synchronized void setText(java.1ang.String pi)
Método de escritura. Establece el contenido del área.
public synchronized void append(j’ava.1ang.String pi)
Añade cadenas a un área de texto.
public synchronized void setEditable (boolean pi)
Controla la editabilidad del campo.
public synchronized java.lang.String getSelectedText()
Obtiene el texto seleccionado. Pertenece a j ava .awt .TextComponent.
Si el texto a mostrar no cabe en el número de filas o columnas visibles aparecen
automáticamente barras de desplazamiento en la dirección adecuada para que se
pueda acceder cómoda y rápidamente a toda la información.
Figura 9.12. TextArea,el texto a mostrar no cabe en el número
de filas ni de columnas visibles.
Para capturar sus eventos, el objeto TextArea se enlaza a la interfaz
TextListener y se sobrescibe el método textValueChanged.
9.10. CLASE Canvas
La clase Canvas hereda de Component,encapsulando una ventana vacía o lien-
zo, sobre el que se puede dibujar y que es capaz de recibir información por parte
lnterfaces gráficas de usuario 243
del usuario en forma de eventos producidos por el ratón o el teclado. Los lienzos
no generan eventos, sólo los reconocen. El constructor de Canvas no tiene pará-
metros
public Canvas ( )
Los lienzos no tienen un tamaño por omisión y es necesario adjudicárselo; si no
se le adjudica, éste dependerá del administrador de diseño que se esté utilizando y
podría llegar a ser demasiado pequeño o incluso invisible. El método empleado con
esta finalidad pertenece a la clase Component y es
public void setSize(int pl, int p2)
import java.awt.*;
import java.awt.event.*;
public class VLienzo extends Frame
i
public VLienzo ( )
i
addWindowListener (new Cierre3 ( ) ) ;
Canvas 1 = new Canvas ( 1 ;
1.setsize (300,150);
l.setBackground(Color.yel1ow);
add(1);
/ / se establece un color de fondo para hacer resaltar el lienzo
1
public static void main ( String args [ ] )
VLienzo ventana = new VLienzo ( ) ;
ventana.setLayout(new FlowLayoutO 1 ;
ventana.setTitle ( "El AWT" ) ;
ventana.setSize( 400,250 ) ;
ventana.setVisible(true);
Se puede observar tras la ejecución del ejemplo que en el lienzo creado no apa-
rece ningún dibujo, sólo un fondo amarillo. Los Canvas heredan de Component
el método paint,pero como ya se comentó anteriormente, para que este método
haga algo es preciso redefinirlo y para ello es necesario crear una subclase de
Canvas.Un ejemplo más completo sobre Canvas aparece en el apartado dedica-
do a los administradores de diseño.
244 Java 2. Manual de programación
9.11. CLASE Choice
Este tipo de componentes permite seleccionar una Única opción de entre una lista des-
plegable de ellas (Fig. 9.13). Cuando se agregan a un contenedor, sólo muestran una
determinada opción y una flecha que será la que permita escoger las restantes opcio-
nes al efectuar clic sobre ella. El ancho que ocupan se establece automáticamente
como el suficiente para mostrar las opciones incluidas en la lista. El constructor no
tiene parámetros y crea una lista vacía:
public Choice ( )
Las opciones son cadenas de caracteres y aparecen en el orden en que se añaden
mediante el método
public synchronized void addItem(java.1ang.String pi)
A cada una de estas opciones le corresponderá un índice, de forma que el primer
elemento añadido tiene índice O, el siguiente 1 y así sucesivamente. Los índices se
pueden obtener con el método
public int getSelectedIndex ( )
y estos números se utilizan frecuentemente como subíndices de vectores que con-,
tienen información relativa a cada una de las opciones.
Figura 9.13. La clase Choice antes y después de desplegar sus opciones.
Otros métodos destacables son:
public synchronized java.lang.String getSelectedItem()
Devuelve una cadena con el nombre del elemento seleccionado.
public synchronized void select (int pi)
Permite especificar la elección por defecto.
El evento de selección de una opción se tratará de la forma siguiente: se enlaza
el objeto Choice a la interfaz ItemListener y se redefine su método
itemstatelhanged,que tiene un parametro de tipo ItemEvent.
lnterfaces gráficas de usuario 245
Ejemplo
Construir un menú de opciones con el componente Choice, a continuación el
usuario selecciona una opción y se presenta en la pantalla la opción seleccionada.
i
1 ElementoseleccionadoDos
Figura 9.14. Presentaciónde la opción seleccionada.
import java.awt.*;
import java.awt.event.*;
public class EjChoice extends Frame implements ItemListener
{
private Choice selección;
String elemento = "";
public EjChoice ( )
I
addWindowListener(new Cierre30);
selección = new Choice ( ) ;
selección.addItem ( "Uno" ) ;
selección.addItem ( "DOS" ) ;
/ * La Última opción se denomina Tercero en vez de Tres,
para que se vea con mayor facilidad la anchura que
adquieren los objetos Choice automáticamente * /
selección.addItem ( "Tercero" ) ;
//Opción preseleccionada
selección.select (1);
selección.add1temListener( t h i s ) ;
add (selección);
}
public s t a t i c void main ( String args [ ] )
t
EjChoice ventana = new EjChoice 0 ;
ventana.setLayout(new FlowLayoutO ) ;
ventana.setTitle ( "El AWT" ) ;
246 Java 2. Manual de programación
ventana.setSize( 400,250 ) ;
ventana.setVicible(true);
1
public void paint (Graphics g)
I
elemento = selección.getSelectedItern();
g.drawString ("Elemento seleccionado " + elemento, 20, 230);
public void iternStateChanged(1temEvent e)
i
1
repaint ( ) ;
9.12. CLASE Checkbox
Las casillas de verificación son componentes IGU con dos estados posibles: activa-
do (true) y desactivado (false). Están formadas por un pequeño cuadro que
puede presentar o no una marca de verificación y una etiqueta descriptora de la
opción (Fig. 9.15).
r Casilla Verificación
Figura 9.15. Casilla de verificación desactivada.
Las casillas de verificación pueden utilizarse individualmente y también pueden
agruparse en un CheckboxGroup. Los CheckboxGroup agrupan de 1 a n
casillas de verificación de forma que no podrá haber varias activadas al mismo
tiempo. El constructor de un grupo CheckboxGroup crea un grupo vacío y la
forma de conseguir que las distintas casillas de verificación se añadan al grupo será
especificar el nombre del grupo cuando se creen las casillas de verificación. La
clase CheckboxGroup hereda de Object y no es un Component,por lo que
los objetos CheckboxGroup no pueden agregarse a un contenedor, lo que se hará
es añadir individualmente cada una de las casillas que constituyen el grupo. Dentro
de los métodos para manejar este tipo de objetos citaremos.
Constructor de un conjunto de un CheckboxGroup.
public CheckboxGroup ( )
public Checkbox(java.lang.String p l , java.awt.CheckboxGroup p2,
boolean p 3 )
Construye un Checkbox cuya etiqueta será la cadena especificada como pnmer parámetro, su
estado (activado o desactivado) el tercer parámetro y lo agrega al CheckboxGroupespecifica-
do como segundo parámetro, que debe haber sido previamente creado. El formato de las casi-
llas de verificación cambia y se convierten en circulares.
Interfaces gráficas de usuario 247
public Checkbox ( )
Crea un Checkbox vacío y no seleccionado.
public Checkbox(java.lang.String pl)
Crea un Chekbox no seleccionado cuya etiqueta es la cadena pasada como parametro.
public Checkbox (java.lang.String pl, boolean p2)
Crea un Chekbox cuyo estado inicial, seleccionado o no seleccionado, dependerá de lo
especificado como segundo parámetro y cuya etiqueta es la cadena pasada como primer
parámetro.
public java.awt.Checkbox getSelectedCheckbox0
Determina dentro de un grupo el objeto Checkbox seleccionado.
public boolean getstate0
Obtiene el estado del Checkbox.
public java.lang.String getlabelo
Obtiene la etiqueta de un Checkbox.
Para tratar el evento de selección de una opción, se siguen lo mismos pasos que
se expusieron en el caso de Choice.
Ejemplo
Creación de un CheckboxGroup que trata el evento de selección de una opción.
...............................................
C Primera opción 6 !se.ci!.nd.a..oP.c!4!;
r Tercera opción C Cuarta opción
Elemento seleccionado Segunda opción
Figura 9.16. CheckboxGroup,el formato de las casillas de verificación
cambia y se convierten en circulares.
248 Java 2. Manual de programación
import java.awt.*;
import java.awt.event.*;
public class EjCheckboxGroup extends Frame implements ItemListener
i
private Checkbox opl, op2, Op3, Op4;
private CheckboxGroup menu;
public EjCheckboxGroup ( )
i
addWindowListener(new Cierre30);
menu = new CheckboxGroup ( ) ;
opl = new Checkbox ("Primera opción", menu, false);
op2 = new Checkbox ("Segunda opción", menu, false);
op3 = new Checkbox ("Tercera opción", menu, false);
op4 = new Checkbox ("Cuarta opción", menu, false);
add(op1);
add (op2);
add (Op3);
add(op4);
opl.addItemListener(this);
op2.addItemListener(this);
op3.addItemListener(this);
op4.addItemListener(this);
I
public static void main( String args[] )
I
EjCheckboxGroup ventana = new EjCheckboxGroup ( ) ;
ventana.setLayout (new GridLayout (3,2)) ;
ventana.setTitle ( "El AWT" ) ;
ventana.setSize( 400,250 ) ;
ventana.setResizable(fa1se);
ventana.setVisible(true);
/ * Redefinir el método getInsets de la clase Container es una
forma de conseguir que los componentes que situemos en un
contenedor queden ligeramente separados del borde del mismo.
Los valores que especifiquemos en getinsets los utilizarán
los administradores de diseño a la hora de colocar compo-
nentes en el contenedor * /
public insets getInsets ( )
i
1
return new Insets(20,20,20,20);
public void paint (Graphics g )
I
if (menu.getSelectedCheckbox ( ) ! = null)
g.drawstring ("Elemento seleccionado 'I+
menu.getSelectedCheckbox().getLabel(),20,230);
Interfaces gráficas de usuario 249
public void itemStateChanged(1temEvent e)
I
1
repaint ( ) ;
1
Compilación
C:libroTema09>javac EjCheckboxGroup.java
Ejecución
C:libroTema09>java EjCheckboxGroup
9.13. LISTAS
La clase L i s t proporciona listas donde se pueden realizar selecciones múltiples. Si
todos los elementos de una lista no caben en el número de filas visibles, aparece
automáticamente una barra de desplazamiento para que se pueda acceder a los res-
tantes elementos de la lista; sucede, de modo análogo, si el número de caracteres
de alguna de las opciones supera el número de columnas visibles.
Enero
1Febrero
Agosto
Octubre
INoviembre
Figura 9.17. Lista cuyos elementos no caben en el número de filas visibles
y con varias opciones seleccionadas: Marzo, Abril, Julio.
Los constructores de una lista son:
public List ( )
Crea una lista que no permite selecciones múltiples.
public List(int pi)
Crea una lista con tantas filas visibles como especifique el parámetro pl y que no admite
selecciones múltiples.
250 Java 2. Manual de programación
public List (int pl, boolean p2)
Crea una lista con tantas filas visibles como indique el parámetro p i y que admitirá o no
selecciones múltiples según sea true o falseel valor que le pasemos como parámetro p2.
Para añadir nuevas opciones a una lista se emplea:
public void add(java.lang.String pl)
Otros métodos útiles son:
public synchronized java.lang.String getSelectedItem()
Devuelve una cadena con el nombre del elemento seleccionado, si no se selecciona ningún
elernento o se selecciona más de uno devuelve nu11.
public synchronized int getSelectedIndex0
Devuelve el índice del elemento seleccionado.AI primer elemento de la lista le corresponde
un cero, al siguiente un uno y así sucesivamente. Si hay más de un elemento seleccionado o
aún no se ha seleccionado ninguno, devuelve -1.
public synchronized void select (int p l )
Permite especificar la elección por defecto.
public synchronized java.lang.String[] getSelectedItems0
Se emplea para tratar selecciones múltiples, devolviendo un vector de cadenas que contiene
los nombres de los elementos seleccionados.
public synchronized int[] getSelectedIndexes0
Se utiliza para tratar selecciones múltiples, devolviendo un vector de enteros con los índices
de los elementos seleccionados.
En una lista se han de considerar dos tipos de eventos; si se efectúa doble clic
con el ratón sobre un elemento de la lista se produce un ActionEvent; si se efec-
túa un único clic sobre los elementos de la lista, se produce un ItemEvent.Para
tratar el suceso ActionEvent se necesita enlazar el ,objeto List a la interfaz
ActionListener y sobreescribir actionperformed,y para tratar el suceso
ItemEvent es necesario enlazarlo a ItemLictener y sobreescribir
itemStateChanged.
Ejemplo
Este programa permite efectuar selecciones múltiples en una lista con las siguien-
tes características:
Efectuando clic con el botón izquierdo del ratón sobre elementos no seleccio-
Si efectúa clic sobre un elemento seleccionado, lo elimina de la selección.
nados, los selecciona.
Interfaces gráficas de usuario 251
Selección.
Elemento 1
Elemento 4
Figura 9.18. Resultado de la ejecución del programa ejemplo de listas.
El marcado y desmarcado de los elementos podrá efectuarse tantas veces como
se quiera (Fig. 9.18). Para terminar el proceso de selección múltiple, deberá efec-
tuar doble clic sobre un elemento aún no seleccionado de la lista, el cual, con ésta
operación, también se añadirá a la selección. Si efectúa doble clic sobre un elemento
previamente seleccionado, también terminará el proceso de selección, pero este
último elemento no se añadirá a la misma.
import java.awt.*;
import java.awt.event.*;
public class EjLista extends Frame implements ItemListener,
ActionListener
i
private List lista;
public EjListaO
addwindowlistener (new Cierre3 ( ) ) ;
lista = new List(5,true);
for (int i = 1; i < 8; i++)
lista.add("Elemento "+i);
lista.addActionListener(this);
1icta.addItemListener (this);
add(1ista) ;
1
public static void main ( String args [ ] )
EjLista ventana = new EjListaO;
ventana.setLayout (new FlowLayout ( ) ) ;
ventana.setTitle ( "El AWT" ) ;
ventana.setCize( 400,250 ) ;
ventana.setVisible(true);
252 Java 2. Manual de programación
public void paint (Graphics g)
I
String arr [I = 1ista.getSelectedIterns( ) ;
int alto = g.getFontMetrics ( ) .getHeight( ) ;
if (arr.length ! = O)
{ g.drawString ("Selección: ' I , 20,250-alto*8);
for (int i = O; i < arr.length; i++)
g.drawString(arr[i],20,250-alto* (7-i)) ;
1
1
public void actionPerformed(ActionEvent e)
{
if (e.getSource0 == lista)
repaint ( ) ;
1
public void iternStateChanged(1ternEvent e)
t 1
9.14. CLASE Scrollbar
Las barras de desplazamiento son componentes que recorren valores enteros y pue-
den estar orientadas horizontal o verticalmente (Fig. 9.19).
Figura 9.19. Barra de desplazamiento.
Constructores
public Scrollbar ( )
Crea una barra de desplazamiento vertical.
public Scrollbar (int pi)
Crea una barra de desplazamiento en la dirección indicada por el parámetro p1:
Scrollbar.HORIZONTALoScrollbar.VERT1CAL.
Interfaces gráficas de usuario 253
public Scrollbar (int pl , int p2, int p 3 , int p 4 , int p5)
Crea una barra de desplazamiento en la dirección que se le indique mediante el parámetro
p l , con el valor inicial especificado en p2 (el cuadro de desplazamiento aparecerá inicial-
mente en esta posición), cuyo tamaño para el cuadro de desplazamiento es el tercer paráme-
tro y con los valores mínimo y máximo que contengan los parámetros p4 y p5. Si el valor
inicial es menor que el mínimo o mayor que el máximo, el valor inicial se hará igual al míni-
mo o máximo respectivamente.
Otros métodos necesarios para trabajar con barras de desplazamiento son:
public synchronized void setvalues(intpl, int p2, int p3, int p 4 )
Establece los parámetros para una barra de desplazamiento.
public int getMaximum()
Devuelve el valor máximo.
public int getMinimum ( )
Devuelve el valor mínimo.
public int getvalue ( )
Obtiene el valor actual de la barra.
public synchronized void setvalue (int pl)
Establece el valor actual.
Ejemplo
Crea una barra de desplazamiento horizontal (Fig. 9.20).
import java.awt.*;
import java.awt.event.*;
class EjBarra extends Frame
{
public EjBarra ( ) '
(
Scrollbar barra = new Scrollbarí Scrollbar.HORIZONTAL,
100,o, o, 200);
Frame v = new Frame( "El AWT" ) ;
v.add ("North", barra ) ;
v.setSize( 200,200 ) ;
v.setVisible( true ) ;
v.addWindowListener( new Cierre3 (
1
public static void main( String args
(
}
new E] Barra ( ) ;
1 '
254 Java 2. Manual de programación
La salida del programa anterior es la mostrada en la Figura 9.20.
I
Figura 9.20. Resultado de la ejecución del ejemplo.
Cada vez que se mueve el cuadro de desplazamiento se genera un evento del
tipo AdjusmentEvent, que debe ser recogido por el receptor
AdjustmentListener,por lo que se enlazará el objeto a la interfaz corres-
pondiente y se sobreescibirá el método adjustrnentvaluechanged.
9.15. MENÚS
Menucomponent es la superclase de todos los elementos relacionados con los
menús, siendo subclases suyas tanto MenuItem como MenuBar. MenuItern
contiene los métodos para crear los elementos de un menú. La clase MenuBar con-
tiene el constructor de barras de menú. Las barras de menú actúan como contene-
dores de menús. La clase Menu es una subclase de MenuItem y proporciona
métodos para la administracción de los menús. Los menús contienen elementos de
menú y se agregan a barras de menú.
Cuando se selecciona un elemento de un menú se genera un evento del tipo
ActionEvent,que se tratará de forma análoga a como se ha explicado en otras
ocasiones.
Los elementos se añaden al menú mediante el método add y los menús a la
barra de menús de la misma forma, pero la adición del menú a un marco se efectúa con:
public synchronized void setMenuBar(java.awt.MenuBar pl)
Constructores
public MenuBar ( )
Construye la barra de menús.
lnferfaces gráficas de usuario 255
public Menu (Java.lang.String pl)
Construye el menú, recibe como parámetro el nombre del menú.
Crea un elemento de menú, recibe como parámetro el nombre de la opción
public MenuItem(java.1ang.String pl)
Ejemplo
Pasos a seguir para la creación de un menú que responda a eventos:
Figura 9.21. Menús.
/ / Frame con barra de menú.
import java.awt.*;
import java.awt.event.*;
public class EjMenu extends Frame implements ActionListener
i
public EjMenu ( )
t
addWindowListener (new Cierre3 ( ) ) ;
setTitle ("Marco");
MenuBar mb = new MenuBar ( ) ;
Menu m = new Menu ("Archivo");
MenuItem abrir = new MenuItem("Abrir archivo");
MenuItem cerrar = new MenuItem ("Cerrar archivo");
abrir.addActionListener(this);
cerrar.addActionListener(this);
m.add(abrir) ;
m.add(cerrar) ;
mb.add (m);
setMenuBar (mb);
setsize (200,100);
setVisible(true);
1
public void actionPerformed(ActionEvent e)
t
System.out.println(e.getSource());
256 Java 2. Manual de programación
public static void main ( String args [ ] )
I
new EjMenu ( ) ;
9.16. ADMINISTRADORES DE DISEÑO
Java tiene cinco administradores de diseño que controlan la ubicación de los
componentes añadidos a un contenedor y, cuando el usuario redimensiona el
contenedor, estos administradores intentan reajustar dichos componentes en
la nueva área. Los más importantes son: FlowLayout, BorderLayout y
GridLayout.Para incorporar un administrador de diseño se utiliza la siguiente
sentencia:
setLayout (new NombreGestor(parámetros)) ;
y cuando se desee no usar un administrador se pasa null al método setlayout;
en este caso habrá que colocar y dimensionar los componentes de forma manual,
para lo que se puede utilizar el método
public void setBounds(int p l , int p2, int p 3 , int p4)
en el que los parámetros p l y p2 representan la posición, en pixels, del extremo
superior izquierdo del componente con respecto a su contenedor, mientras p 3 y p4
son la anchura y altura del objeto respectivamente.
Cuando se quiere dejar un pequeño borde entre un contenedor y los componen-
tes que situamos en él se puede recurrir a redefinir el método getinsets de la
clase Container,especificando en él la cantidad de espacio que se desea reser-
var para dicho borde. Estos valores serán tenidos en cuenta por el administrador de
diseño correspondiente cuando vaya a colocar los componentes en el contenedor.
Un ejemplo de getinsets aparece en el apartado que comenta la clase
Checkbox.
Las características de los administradores de diseño fundamentales se detallan a
continuación.
9.16.1. FlowLayout
Utiliza la interfaz LayoutManager y es el administrador de diseño que usan por
omisión los paneles y las applets. Cuando se utiliza FlowLayout los componentes
se colocan en el contenedor de izquierda a derecha en el orden en el que van siendo
agregados y, cuando no caben más en una fila, continúan colocándose en la siguiente.
lnterfaces gráficas de usuario 257
Los constructores son:
public FlowLayout ( )
public FlowLayout ( i n t pi)
Construye un FlowLayout
por defecto, que centra los
componentes, dejando 5 pixeles
de espacio entre cada uno de
ellos.
Construye un FlowLayout y
mediante el parámetro permite
especificar el alineamiento. Son
valores válidos para dicho pa-
rámetro.
FlowLayout.LEFT
FlowLayout.CENTER
FlowLayout.RIGTH
public FlowLayout ( i n t pl, i n t p 2 , i n t p 3 ) Construyeun FlowLayout de
forma que se pueden especifi-
car tanto el alineamiento como
el espacio horizontal y vertical
a dejar entre los componentes.
El diseño se establece mediante s e t l a y o u t . Por ejemplo:
setLayout (new FlowLayout (FlowLayout.LEFT))
La adición de componentes se efectúa empleando el método add.
9.16.2. BorderLayout
Es el administrador de diseños por defecto para los cuadros de diálogo y los mar-
cos y se caracteriza por acomodar a los componentes en cinco areas: North,
South, E a s t , West y C e n t e r , especificadas en el orden en el que dichas áreas
son dimensionadas.
I South I
Figura 9.22. BorderLayout: áreas.
Es posible usar, por tanto, de uno a cinco componentes con BorderLayout,
uno para cada posición, y, excepto en el caso de Center, cuando alguna posición
no es usada la zona correspondiente será ocupada por los otros componentes.
258 Java 2. Manual de programación
Si no se usa North ni south,quedaría así. Si no se usa North,ni south,ni East.
Figura 9.23. BorderLayout cuando no se usan algunas posiciones.
Sus constructores son:
public BorderLayout ( ) Construye un BorderLayout.
public BorderLayout (int pl, int p2) Construye un BorderLayout
separando cada área horizontal
y verticalmente el número de pi-
xeles indicados como argumento.
Estableciéndose el diseño de la siguiente forma:
setLayout (new BorderLayout ( ) 1
setLayout (new BorderLayout (pi, p2) )
para situar un componente en una determinada posición se incluye la posición o
área en el método add :
public java.awt.Component add(java.lang.String pl,
java.awt.Component p2)
el primer parámetro es la posición, cuyo nombre (North, South, East,
West o Center) debe comenzar siempre por mayúscula y, puesto que el área ha
de especificarse, los componentes podrán agregarse en cualquier orden.
9.16.3. GridLayout
Divide el contenedor en una cuadrícula que permite colocar los componentes en filas
y columnas, concediendo el mismo tamaño a todos ellos. Dichos componentes se
agregan a la cuadrícula ocupando la primera fila de izquierda a derecha y pasando a
continuación a ocupar, en el mismo sentido, la fila siguiente y así sucesivamente.
Los constructores de GridLayout son:
public GridLayout(int pi, int p2)
Construye un GridLayout con el número de filas especificado como primer parámetro y
el número de columnas especificado como segundo parámetro.
public GridLayout (int pl, int p2, int p3, int p4)
Construye un GridLayout con el número de filas especificado como primer parámetro y
el número de columnas especificado como segundo parámetro y cada componente separado
horizontalmente por p 3 pixeles y verticalmente por p4.
Interfaces gráficas de usuario 259
El diseño se establece mediante:
setLayout (new GridLayout (pl, p2) )
setLayout (new GridLayout (pl, p2, p3, p4) )
y la adición de componentes se realiza con add:
public java.awt.Cornponent add(java.awt.Cornponent p l )
Nota: Redeñnir cl =¿todo getinsets de la clase Container sirve para
$esque secdoquenea uncontenedorquedenlige-
íi8lmisrrns.
€jemplo
En este ejemplo se muestra el comportamiento de los administradores de diseño y dis-
tintos componentes del AWT. Pero no incluye la gestión de eventos, excepto la del even-
to de cierre que se produce cuando se hace clic en el icono de salida de la ventana.
Figura 9.24. Ejemplo sobre el comportamiento de los administradores de diseño.
260 Java 2. Manual de programación
import java .awt .* ;
import java.awt.event.*;
public class Ventanas extends Frame
t
public Ventanas ( )
I
addWindowListener (new Cierre3 ( ) ) ;
Panel panelBotones = new Panel ( ) ;
Panel panelcentral = new Panel ( ) ;
MenuBar mb = new MenuBar ( ) ;
Menu m = new Menu ( "Menú" ) ;
m.add( new MenuItem( "Opción 1" ) ) ;
m.add( new MenuItem( "Opción 2" ) ) ;
m.add( new MenuItem( "Opción 3" ) ) ;
mb.add( m ) ;
setMenuBar( mb ) ;
panelBotones.add ( new TextField ( "Campo de Texto" ) ) ;
panelBotones.add ( new Button ( "Botón" ) ) ;
panelBotones.add( new Checkbox ( "Casilla Verificación" ) ) ;
Choice selección = new Choice ( ) ;
selección.addItem ( "1" ) ;
selección.addItem ( "2" ) ;
selección.addItem ( "3" ) ;
panelBotones.add( selección ) ;
//Se utiliza GridLayout para dividir el contenedor
panelcentral.setLayout ( new GridLayout ( 2 , l ) ) ;
//se coloca el dibujo
Dibujo d = new Dibujo ( ) ;
d.setBackground(Color.yel1ow);
panelCentral.add(d);
/ / se colocan la etiqueta y el área de texto
Panel p = new Panel ( ) ;
p.setLayout ( new BorderLayout ( ) ) ;
p.add ( "North",new Label ( "Etiqueta",Label.CENTER ) ) ;
TextArea Texto= new TextArea ("Puede escribir aquí +
for ( i n t i=l; i<=12; it+)
Texto.append (i+"n");
p.add ( "Center",Texto ) ;
panelCentral.add( p ) ;
"el texto que deseen") ;
Interfaces gráficas de usuario 261
/*se utiliza BorderLayout para acomodar los componentes en
las distintas áreas * /
setLayout ( new BorderLayout ( ) ) ;
add ( "South",panelBotones ) ;
add ( "Center",panelcentral ) ;
List lista = new List();
lista.add( "Mercurio");
1ista .add ( "Venus" ) ;
lista.add ( "Tierra");
lista.add ( "Marte");
lista.add( "JÚpiter");
lista.add ( "Saturno");
lista.add ( "Urano");
lista.add ( "Neptuno");
lista.add( "Plutón");
add( "East",lista ) ;
1
public s t a t i c void main( String args[] )
i
Ventanas ventana = new Ventanas ( ) ;
ventana.setTitle ( "El AWT" ) ;
ventana.setSize( 400,250 ) ;
ventana.setVisible(true);
1
1
//Subclase de Canvas
class Dibujo extends Canvas
I
public void paint( Graphics g )
{
i n t ancho = getsize0 .width;
i n t alto = getsize0 .height;
Font fuente = g.getFont ( ) ;
i n t tamañoletra = fuente.getsize ( ) ;
g.drawString ( "Los planetas", (ancho-g.getFontMetrics ( ) .
g.drawOval(l,l+tamañoLetra,ancho-2,alto-tamañoLetra-2 ) ;
g.fill0val(ancho/4,tamañoLetra+alto/6,ancho/2, (alto-
stringWidth("Los planetas") ) /2,10 ) ;
tamañoletra)/ 2 ) ;
1
1
Otros administradores de diseño son: GridBagLayout,parecido a GridLayout
pero admitiendo que los componentes ocupen varias celdas, y CardLayout,que crea
una organización con tarjetas.
262 Java 2. Manual de programación
java . awt .
9.17. swing
Component
java.awt.Container
El paquete swing extiende el awt,añade nuevos componentes e incorpora dos
administradores de diseño más. La superclase de los componentes swing es la
clase JComponent,que deriva de la clase estándar Container y, por tanto, des-
ciende también de la clase Component del awt,de esta jerarquía se deduce que
todos los componentes swing son contenedores (Fig. 9.25). Entre las novedades
aportadas por j avax .swing destacan las ventanas con pestañas, el hecho de
poder añadir bordes así como asociar un texto de ayuda a cualquier componente.
Además, los componentes swing se ejecutan uniformemente en cualquier plata-
forma. Hay que tener en cuenta que, en muchas ocasiones, los nombres de los com-
ponentes en ambos paquetes casi coinciden, diferenciándose únicamente en que los
de swing anteponen una J,y la forma de trabajo también, facilitándose así el paso
de awt a swing.
Figura 9.25. Jerarquía de clases: la clase JComponent.
-
10
Gestión de eventos
CONTENIDO
10.1. Tipos de eventos.
10.2. Los componentes del AWT como fuente
de eventos.
10.3. Receptores de eventos.
10.4. Procesamiento de eventos.
10.5. Clases adaptadoras.
10.6. Clases receptoras anónimas.
10.7. Problemascomunes en el tratamiento de eventos.
263
264 Java 2. Manual de programación
Los usuarios pueden comunicarse con los programas a través de
los objetos visuales que ofrecen las InterfacesGráficasde Usuario
(IGU). Cuando se trata del paquete awt la comunicación se pro-
duce de la siguiente forma, los distintos componentes del AWT son
capaces de detectar eventos de una determinada clase y notificar
esta acción a un objeto receptor. Si el receptor recibe el aviso de
que ha ocurrido determinado suceso, llama a un método, redefini-
do por el programador, que ejecuta las acciones deseadas. Por
otra parte, Swing proporciona nuevostipos de eventos pero el pro-
cesamiento de los mismos es análogo al comentado anteriormen-
te. En este capítulo se comentan los diferentes tipos de eventos
del AWT,así como los problemas que se presentan en el procesa-
miento de los mismos.
10.1. TIPOS DE EVENTOS
La programación GUI es una programación dirigida por eventos que implica la
necesidad de procesar los mismos y, por tanto, la utilización de las clases propor-
cionadas por el paquete j ava .awt .event que definen los tipos de eventos del
AWT.
Jerarquía de clases
Figura 10.1. Clases proporcionadas por el paquete j ava .awt .event
Lajerarquía de clases conduce a una división de los eventos en dos categorías fun-
damentales, de bajo nivel, subclase de ComponentEvent,y semánticos, colegas de
Gestión de eventos 265
ComponentEvent.No obstante, la programación de los eventos de ambas cate-
gorías es similar y su principal diferencia reside en la naturaleza del objeto evento y
la información que es capaz de proporcionar.
Los eventos de bajo nivel ofrecen acceso al componente que ha generado el
evento y, con él, acceso a los métodos de la clase Component mediante el
método:
public java.awt.Component getComponent0
Los eventos semánticos proporcionan diferentes métodos para obtener una refe-
rencia al objeto que ha generado el evento. Por ejemplo, en ActionEvent se
puede obtener la etiqueta identificativa del objeto fuente mediante
public java.lang.Ctring getActionCommand0
mientras que en ItemEvent debiera utilizarse
public java.awt.ItemCelectable getItemSelectable0
Nota: Si no se desea recordar métodos específicos es posible recurrir al
método
public java.lang.0bject getsource0
perteneciente a la clase java.uti1.Eventobject,situada muy arriba
en la jerarquía; como consecuencia, este método puede ser utilizado con todo
tipo de eventos,
10.2. LOS COMPONENTES DEL AWT COMO FUENTE
DE EVENTOS
Los distintos componentes del AWT son capaces de actuar como fuente de even-
tos, es decir, como objetos capaces de detectar eventos de una determinada
clase y, para conocer los eventos que pueden ser detectados por cada uno de
ellos, hay que tener en cuenta tanto la siguiente tabla como la jerarquía de cla-
ses del AWT.
266 Java 2. Manual de programación
Tabla 10.1. Fuentes de eventos
Fuente Clase de evento
B u t t on
L l S t
Y e r.u I ten
T e x t F i e l d
A c t i o n E v e n t
A c t i o n E v e n t
A c t i o n E v e n t
A c t i o n E v e n t
S c r o l l B a r AdjustrnentEvent
Cornpor.e nt CornponentEvent
C o n z a i n e r C o n t a i n e r E v e n t
Conponent FocucEvent
Checkbox
CheckboxMen~dItern
Choice
L;ct
I ternEvent
I ternEven t
IternEvent
I ternEvent
Corrponenr K e y0ver,t
Cunponent MouseEvent
T e x t A r e a
T e x t F i e l d
T e x t E v e n t
T e x t E v e n t
D;alog WindowEvent
Frame WindowEvent
10.3. RECEPTORES DE EVENTOS
Las clases de nivel más bajo dentro de los distintos subárboles a considerar en
lajerarquía de eventos tienen una interfaz ((oyente))asociada, excepto MouseEvent
que tiene dos, con un único método o bien un conjunto de métodos declarados en ellas
para tratar los eventos de las mismas y los receptores de eventos son clases que imple-
mentan interfaces oyentes específicas.
Clase de evento Interfaz
I A r t i o n E v e n t I A c t 1 onLi s tener
~ct i o n L i st e n e r , métodos:
public abstract void actionPerformed(java.awt.event.ActionEvent pl)
Gestión de eventos 267
ItemEvent
Clase de evento Interfaz
ItemListener 1
1 AdjustmentEvent 1 Ad] ustmentlistener 1
A d j ustmentListener, métodos:
public abstract void
adjustment~a:ueChanged(~ava.awt.event.Adjustme~~tEventpl)
Clase de evento Interfaz
1 ComponentEvent 1 ComponentListener
ComponentListener, métodos:
public abstract void
componentHidden(~ava.awt.event.ComponentEvent pl)
public abstract void
componentMoved(java.awt.event.ComponentEvent pl)
public abstract void
componentResized(]ava.awt.event.ComponentEVent p i )
public abstract void
componentShown(]ava.awt.event.ComponentEvent pZ)
Clase de evento Interfaz
ContainerEvent 1 ContainerListener
ContainerListener, rne'todos:
public abstract void
cornponentAdded(java.awt.event.ContainerEvent pl)
public abstract void
componentRemoved(java.awt.event.ContainerEvenc pl)
Clase de evento Interfaz
1 FocusEvent 1 FocusListener I
FocusList ener,
public abstract void focusGained(java.awt.event.FocdsEve~tpi)
public abstract void f o c u s L o s t ( ~ a v a . a w t . e v e n t . F o c ; s E v e n t pl)
métodos:
ItemListener, métodos:
public abstract void itemCtateChanged(java.awt.event.1temEvent pl)
268 Java 2. Manual de programación
MoxseEvenc
i
Clase de evento Interfaz
MouceLictener
MouceMotionLictener
1 KeyEvenr. 1 KeyListener I
TextEvent
KeyLis t e n e r , métoclos:
public a b s t r a c t void keyPressed(java.awt.event.KeyEvent pl)
public abstract void keyReleased(;ava.awt.event.KeyEvent pl)
public abstract void keyTyped(java.awt.event.KeyEvent pl)
TextListener
~
MouceLic tener , métodos:
public a b s t r a c t void
public a b s t r a c t void
public abstract void
public a b s t r a c t void
public abstract void
MoLIseMot ioI:Li s t ener ,
public abstract void
public abstract void
Clase de evento
mouseClicked(java.awt.event.MouseEvent pl)
mouseEntered(java.awt.event.MouseEvent pl)
mouseExited(java.awt.event.MouseEvent pl)
mousePressed(~ava.awt.event.MouseEventpl)
mouseReleased(java.awt.event.MouseEvent pl)
métodos:
mOuSeDragged (1ava.awt .event.MouseEvent pi)
mouceMoved(java.awt.event.MouseEvent pl)
Interfaz
Text Lis tener ,
public abstract void textValueChanged(java.awt.event.TextEvent pl)
WlétOdOS:
Clase de evento Interfaz
WindowEvent1 I WindowListener
WinciowLi s tener , métodos:
public abstract void windowActivated(java.awt.event.WindowEvent pl)
public abstract void windowClosed(java.awt.event.WindowEvent pl)
public abstract void windowClosing(java.awt.event.WindowEvent pl)
public abstract void windcwDeactivated(java.awt.event.WindowEvent p l )
public abstract void windowDeiconified(~ava.awt.event.WindowEventpl)
public abstract void windowIconified(java.awt.event.WindowEvent pl)
public a b s t r a c t void windowCpened(java.awt.event.WindowEvent pl)
Gestión de eventos 269
10.4. PROCESAMIENTO DE EVENTOS
Para el procesamiento de eventos, hace falta que un objetofuente capaz de detectar
eventos de una determinada clase, notifique a un objeto receptor que se ha produ-
cido un evento de la clase que dicho receptor es capaz de interpretar y, para ello,
dicho receptor debe implementar una interfaz «oyente», asociada a un determinado
tipo de suceso, sobreescribiendo cada uno de sus métodos, y registrarse con la fuen-
te. Cuando el receptor recibe el aviso de que ha ocurrido un suceso llama al méto-
do correspondiente al evento particular generado, sobreescrito por el programador,
que ejecuta las acciones deseadas.
Ejemplo
Presentar las coordenadas de la posición donde se pulse el ratón dentro del área de
un marco. El programa termina cuando se cierra la ventana.
Pnsicidn del ratdn: 60, 40
Figura 10.2. MousseEvent.
-
import java.awt.*;
import java.awt.event.*;
public class Marco extends Frame
{ int x = O, y = O;
public static void main( String args[] )
t
Marco fuente = new Marco
fuente.setTitle ("Marco");
fuente.setCize(250,lOO);
fuente.setVisible(true);
//se instancian y regist.
1 ;
in los receptores
fuente.addWindowListener(new ReceptorCierreO);
fuente.addMouseListener(new ReceptorRaton(fuente));
public void paint (Graphics g)
t
g.drawString ("Posición del ratón: "ixt", "+y,60,40);
270 Java 2.Manual de programación
/ * Las clases receptoras implementan oyentes y sobreescriben
* / sus métodos
class Receptorcierre implements WindowListener
public void windowClosing(WindowEvent e)
i
i
1
System.exit (O);
public void windowActivated(WindowEvent e)
t i
public void windowClosed(WindowEvent e)
0
public void windowDeactivated(WindowEvent e)
i 1
public void windowDeiconified(WindowEvent e)
i }
public void windowIconified(Wind0wEvent e)
i 1
public void windowOpened(WindowEvent e)
i }
class ReceptorRaton implements MouseListener
1
Marco laventana;
ReceptorRaton(Marco fuente)
i
laventana = fuente;
1
public void mousepressed (MouseEvent e)
laventana.x = e.getX ( ) ;
laventana.y = e.getY ( ) ;
laventana.repaint0;
1
public void rnouseReleased(MouseEvent e)
o
public void rnouseEntered(M0useEvent e)
i 1
public void mouseExited (MouseEvent e)
t )
public void mouseClicked(MouseEvent e)
i }
1
Gestión de eventos 271
Otra forma de implernentación podría haber sido:
import java.awt.*;
import java.awt.event.*;
public class Marco2 extends Frame implements WindowListener,
MouseListener
{ int x = O, y = O;
Marco2 ( )
(
setTitle ("Marco");
setsize (250,100);
setvisible (true);
//se registra el receptor
addWindowListener(this);
addMouseListener(this) ;
1
public static void main ( String args [I )
i
1
i
1
Marco2 fuente = new Marco2 ( ) ;
public void paint (Graphics g )
g.drawCtring ("Posición del ratón: "tx+", "+y,60,40);
public void windowClosing (WindowEvent e)
t
System.exit (O);
public void windowActivated (WindowEvent e)
i l
public void windowClosed(WindowEvent e)
{ I
public void windowDeactivated(WindowEvent e)
{ I
public void windowDeiconified(WindowEvent e)
{ I
public void windowIconified(WindowEvent e)
i }
public void windowOpened(WindowEvent e)
i )
public void mousePressed(MouseEvent e)
i
x = e.getX();
y = e.getY();
repaint ( ) ;
I
272 Java 2. Manual de programación
public void mouseReleased(MouseEvent e)
public void mouseEntered (MouseEvent e)
public void mouseExited(MouseEvent e)
public void mouseClicked(MouseEvent e)
i }
{ I
i }
1
En cuanto a swing,hay que destacar que aunque proporciona nuevos tipos de
eventos el procesamiento de los mismos es análogo al estudiado. Los programas
que utilicen swing deberán incorporar las siguientes sentencias:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swinq.event.*;
En versiones anteriores, swing ha usado otros nombres de paquetes:
corn.sun.java.swing
java.awt.swing +
10.5. CLASES ADAPTADORAS
Dado que existen interfaces ((oyentes))con un gran número de métodos y que un
receptor que implementa una de estas clases se ve obligado a sobreescribir todos
ellos, cuando se requiere una interfaz de este tipo se utilizan clases adaptadoras, que
implementan las interfaces oyentes con métodos vacíos y se definen las clases
receptoras para que extiendan las adaptadoras.
Ejemplo
Implementación de un programa que presenta las coordenadas de la posición donde
se pulsa el ratón dentro del área de un marco usando clases adaptadoras.
import java.awt.*;
import java.awt.event.*;
public class Marco3 extends Frame
i
int x = 0 , y = O;
public static void main( String args[] )
i
Gestión de eventos 273
Marco3 fuente = new Marco3 0 ;
fuente.setTitle ("Marco");
fuente.setSize(250,lOO);
fuente.setVisible(true);
//se instancian y registran los receptores
fuente.addWindowListener(new ReceptorCierre20);
fuente.addMouseListener(new ReceptorRaton2(fuente));
1
public void paint (Graphics g)
i
g.drawString("Posición del ratón: "txt", "+y,60,4O);
//Las clases receptoras extienden adaptadoras
class ReceptorCierre2 extends WindowAdapter
public void windowClosing (WindowEvent e)
t
I
System.exit (O);
1
class ReceptorRaton2 extends MouseAdapter
t
Marco3 laventana;
ReceptorRaton2(Marco3 fuente)
t
laventana = fuente;
1
public void mousePressed (MouseEvent e)
I
laventana.x = e.getX ( )
laventana.y = e.getY ( ) ;
laventana.repaint0;
I
1
Nota: Las clases adaptadoras hacen innecesario redefinir aquellos métodos,
declarados en la interfaz, no Útiles para el programa que se está diseñando.
Las clases adaptadoras disponibles en j ava .awt .event son:
Class CornponentAdapter Class ContainerAdapter
Class FocucAdapter Class KeyAdapter
274 Java 2. Manual de programación
Class MouseAdapter Class MouseMotionAdapter
Class WindowAdapter
10.6. CLASES RECEPTORAS ANÓNIMAS
Una clase anónima es aquella que no tiene nombre y, cuando se va a crear un obje-
to de la misma, en lugar del nombre se coloca directamente la definición. Las cla-
ses receptoras pueden ser definidas como clases anónimas.
Ejemplo
Construir un menú de opciones con el componente Choice,elegir una opción, pre-
sentarla en pantalla y realizar el cierre de la ventana mediante una clase anónima
(Fig. 10.3).
Elemento seleccionado Tercero
Figura 10.3. Ejemplo de Choice y clase anónima para el cierre de ventana.
import java.awt.*;
import java.awt.event.*;
public class EjAnonima extends Frame implements ItemListener
i
private Choice selección;
String elemento = " " ;
public EjAnonima ( )
t
/*empleo de una clase anónima para efectuar el cierre de la
* /
addWindowListener(new WindowListenerO
ventana
Gestión de eventos 275
t
public void windowclosing (WindowEvent e)
I
I
public void windowActivated (WindowEvent e)
t }
public void windowClosed(WindowEvent e)
t }
public void windowDeactivated(Wind0wEvent e)
t l
public void windowDeiconified(WindowEvent e)
t l
public void windowIconified(WindowEvent e)
I }
public void windowopened (WindowEvent e)
I I
System.exit (O);
1 )
selección = new Choice ( ) ;
selección.addItem ( "Uno" ) ;
selección.addItem ( "Dos" ) ;
selección.addItem ( "Tercero" ) ;
//Opción preseleccionada
selección.select (1);
selección.addItemListener(thís);
add (selección);
I
public static void main( String args[] )
i
EjAnonima ventana = new EjAnonima ( ) ;
ventana.setLayout(new FlowLayoutO ) ;
ventana.setTitle ( "El AWT" ) ;
ventana.setSize( 400,250 ) ;
ventana.setVisible(true);
1
public void paint (Graphics g)
I
elemento = selección.getSelectedItem();
g.drawstring ("Elemento seleccionado"+elemento,
20,230);
I
public void itemStateChanged(1temEvent e)
t
I
repaint ( ) ;
1
276 Java 2. Manual de programación
Resulta práctico definir como anónimas las clases receptoras que extienden
adaptadoras. Por ejemplo, en el caso anterior se podría definir la siguiente clase
anónima:
//empleo de una clase anónima
addWindowListener(new WindowAdapter
I
public void windowClosing
i
System.exit (O) ;
)
WindowEvent e)
10.7. PROBLEMASCOMUNES EN ELTRATAMIENTO DE EVENTOS
Un problema frecuente en el tratamiento de eventos se origina por los «titubeos» del
usuario ante la realización de una determinada elección y la medida a tomar suele
ser ignorar las selecciones realizadas por el mismo hasta que éste confirme su deci-
sión; para ello se añade un botón de confirmación y se ignoran los eventos genera-
dos hasta que el usuario pulse dicho botón.
Ejemplo
Crear un CheckboxGroup que agrupe 4 casillas de verificación. Sólo se acepta
la selección de la opción cuando se pulsa el botón de confirmación (Fig. 10.4).
import java.awt.*;
import java.awt.event.*;
public class EjCheckboxGroup extends Frame implements ActionLictener
i
private Checkbox opl, op2, op3, op4;
private CheckboxGroup menu;
private Button confirmacion;
private Label 1;
String elemento = "Elija opción y pulse Aceptar";
public EjCheckboxGroup()
i
addWindowListener (new Cierre ( ) ) ;
menu = new CheckboxGroup ( ) ;
opl = new Checkbox ("Primera opción", menu, false
op2 = new Checkbox ("Segunda opción", menu, false
op3 = new Checkbox ("Tercera opción", menu, false
op4 = new Checkbox ("Cuarta opción", menu, false)
Gestión de eventos 277
add(op1);
acid(op2);
add(op3);
add(op4);
Panel p = new Panel ( ) ;
p.setLayout (new GridLayout (2,l)) ;
1 = new Label (elemento);
confirmacion = new Button ( "Aceptar" ) ;
p.add(confirmacion) ; .
confirmacion.addActionListener(this);
p.add(1);
add(p);
public static void main( String args[] )
i
EjCheckboxGroup ventana = new EjCheckboxGroup() ;
ventana.setLayout (new GridLayout (3,2)) ;
ventana.setTitle ( "El AWT" ) ;
ventana.setSize( 500,250);
ventana.setVisible(true);
public void paint (Graphics g)
I
if (menu.getSelectedCheckbox ( ) ! = null)
elemento = "Elemento seleccionado:" t
menu.getCelectedCheckbox() .getLabel();
1.setText (elemento);
1
public Insets getInsets ( )
i
1
return new insets (20,20,20,20);
public void actionPerformed(ActionEvent e)
i
1
repaint ( ) ;
1
class Cierre extends WindowAdapter
I
public void windowClosing (WindowEvent e)
System.exit (0);
1
1
278 Java 2. Manual de programación
~ r Ptimera opción C Sewnda aotión
r Tercera opcl6n @ Cualta opcldn
,-____.. ___
Aceptar
L ..--..........<..I ~ .............---,.,.._I_<._~ _._._._._,_,..__;
Elementoseleccionada: Cuarta opclón
Figura 10.4. Confirmación de la selección de una opción.
Por otra parte, en algunos programas las acciones a realizar ante un determinado
evento deben depender de eventos anteriores y, en estos casos, lo habitual es recu-
rrir a variables booleanas que reflejen lo que ha sucedido antes y programar las
acciones a realizar en relación con el valor de dichas variables.
Ejercicio
Diseño de una calculadora sencilla (Fig. 10.5).
Figura 10.5. Calculadora.
En un programa que efectúe la creación de una calculadora será preciso en pri-
mer lugar distinguir entre la parte correspondiente al diseño de la pantalla y la de
Gestión de eventos 279
manejo de los sucesos; dentro de esta última, es necesario resaltar que las acciones
a realizar ante la pulsación de un botón van a depender sobre todo de si dicho botón
es un dígito o un operador. Considerando operadores binarios y las operaciones
como series de operando operador operando operador para evaluar según el orden
de introducción, cuando el botón pulsado sea un operador marcará el fin de la ope-
ración anterior, pero la actual no se podrá realizar hasta que no se introduzca un
segundo operando y se marque su fin con un nuevo operador. Cuando el botón pul-
sado sea un dígito la acción dependerá de la selección anterior y de si esta fue un
dígito, la coma decimal o un operador. Por tanto, la ejecución de unas acciones u
otras requerirá la consulta de los valores de variables booleanas ( o troNumero,
esDecimal) que informen sobre dicha selección anterior.
import java.awt.*;
import java.awt.event.*;
public class Calculadora extends Frame
TextField resultado;
boolean otroNumero = true, esDecirnal = false;
double total =O. O;
char operador='x' ; / / sin operador
/ * Diseña la pantalla utilizando 2 paneles auxiliares que se
colocan con BorderLayout.
Uno de estos paneles auxiliares contiene a su vez otros dos,
uno de operandos y otro de operadores, q u e se colocan .,t-li-
zando GridLayout. Los paneles de operandos y operadores con-
tienen los botones y vuelven a hacer uso de GriaLayout * /
public Calculadora ( j
Botones cero, uno, dos, tres, cuatro, cinco, seis, s ~ e t e ,
ocho, nueve, coma;
Botones suma, resta, multiplica, divide, obtiene, borra;
setFont (new Font ("Arial",Font.PLAIN,14)) ;
setBackground(Color.1ightGray);
setTitle ("Calculadora"j ;
setsize (200,140);
addWindowListener(new Cierre0 ) ;
Panel paneloperandos = new Panel ( ) ;
panelOperandos.setLayout(new GridLayout(3,4) ) ;
cero = new Botones("O", 'x', 'O', this);
/ * el segundo parametro que se pasa al constructor indica
panelOperandos.add(ceroj;
cero.addActionListener(cero);
que no es un operador, el tercer parámetro es el valor * /
280 Java 2. Manual de programación
c
uno = n e w Botones ("l", 'x' , '1' t h i s ) ;
paneloperandos.add (uno);
uno.addActionListener(un0);
doc = n e w Botones ( "2", 'x', '2', t h i s ) ;
paneloperandos.add (dos);
dos.addActionListener(dos);
tres = n e w Botones ( " 3 " , 'x' , ' 3 ' , t h i s ) ;
panel@perandos.add(tres);
tres.addActionListener(tres);
cuatro = n e w Botones ("4", 'x' , '4', t h i s ) ;
panelOperandos.add(cuatro);
cuatro.addActionListener(cuatro);
c i n c o = n e w B O t O n e S ( " 5 " , 'x'' '5', t h i s ) :
panelOperandos.add( cinco ) ;
cinco.addActionListener(cinco);
seis = n e w Botones ("6", 'x' , '6', t h i s ) ;
panelOperandos.add(seis);
ceis.addActionListener(seis);
s i e r e = n e w Botones ("7", 'x', 'If, t h i s ) ;
panelOperandos.add(siete);
ciete.addActionLictener(siete);
ocho = n e w Botones ("8", 'x' , '8', t h i s ) ;
panelOperandos.add( ocho ) ;
ocho.addkctionListener(ocho);
n'Jeve = n e w Botones ("9", 'x' , '9', t h i s ) ;
panelOperandos.add(nueve);
nueve.addActionLictener(nueve);
coma = n e w Botones(",", 'x', ' . ' , t h i s ) A
panelOperandos.add(coma);
coma.addActionListener(coma);
Panel paneloperadores = n e w Panel ( ) ;
paneloperadores .cetLayout( n e w GridLayout ( 2 , 3 )) ;
/ / borra pasa como operador el espacio en blanco
borra = n e w Botones ("C", ' ', ' O ' , t h i s ) ;
/ * el segundo parametro que se pasa al constructor indica el
operador, el tercer parámetro es el valor y para los opera-
dores es cero * /
panel@peradores.add(borra);
borra.addActionListener(borra);
suma = n e w Botones ( ' I + " , ' + r , 'O', t h i s ) ;
panelOperadores.add(suma);
sJma.addActionListener (suma);
resta = n e w Botones ( " - ' I , I - ' , 'O', t h i s ) ;
panelGperadores.add(resta);
recra.addA-zionLictener(resta);
multiplica = n e w Botcnec ( " * ' I , ' * I , 'O', t h i s ) ;
panelCperadcres .add (multiplica);
-.ultiplica.addActionListener(multiplica);
diviSe = n e w Bo:onec ( " / ' I , ' / r , 'O', t h i s ) ;
Gestión de eventos 281
panelOperadores.add(divide);
divide.addActionListener(divide);
obtiene = new Botones ("=", ' = I , 'O', this ) ;
panelOperadores.add(obtiene);
obtiene.addActionListener(obtiene);
Panel panelcentral = new Panel();
panelcentral.setLayout (new GridLayout (1,2,10,10)) ;
panelCentral.add(panel0perandos);
panelCentral.add(panel0peradores);
Panel panelResultado = new Panel();
panelResultado.setLayout(new FlowLayout 0);
resultado = new TextField( "O",15);
resultado.setEditable(false);
panelResultado.add(resultad0);
add ("North", panelResultado) ;
add ("center", panelcentral) ;
setVisible(true);
1
public static void main ( String args [I )
i
1
new Calculadora ( ) ;
/ / no se trata de un operador
void coloca(char valor )
I
String .digit0 = " " ;
if( valor == I . ' )
if( !esDecirnal )
{
I
if( otroNumero )
i
resultado.setText ( "O");
otroNumero = false;
1
esDecirna1 = true;
digito = " .";
1
I
else
if( otroNurnero )
digito = ""tvalor;
282 Java 2. Manual de programación
resultado.setText( digito ) ;
if ( valor ! = 'O' )
otroNumero = false;
else
repaint ( ) ;
resultado.setText(resultado.getText() + digito ) ;
//es un operador
void calcula(char otrooperador)
i
double numero;
ncmero = (new Double (resultado.getText ( ) ) ) .doublevalue ( ) ;
if ( (!otroNumero 1 1 operador == '=' ) & & otrooperador ! = ' ' 1
t
switch( operador )
i
case '+' :
total += numero;
break;
case I - ' :
total -= numero;
break;
case ' * I :
total *= numero;
break;
case ' / ' :
total / = numero;
break;
case 'x' :
case ' ' :
total = numero;
break;
resultado.setText ( ( new Double (total) ) .tostring ( ) ) ;
1
operador = otrooperador;
otroNumero = true;
esDecima1 = false;
if (otrooperador == ' ' )
t
resultado.setText ( "O" ) ;
operador = ' ';
total = 0.0;
1
Gestión de eventos 283
c l a s s Botones extends Button implements ActionListener
I
char unoperador, unvalor;
Calculadora calc;
Botones(Ctring texto, char oper, char valor, Calculadora c )
t
super( texto ) ;
unoperador = oper;
u n v a l o r = v a l o r ;
calc = c;
1
public void actionPerformed(ActionEvent e)
i
i f ( unoperador == 'x' )
/ / no es un operador
calc.coloca (unvalor);
calc.calcula(unoperador);
else
1
i
c l a s s Cierre extends WindowAdapter
i
public void windowclosing (WindowEvent e)
t
1
Cystem.exit (O);
I 11
Applets
CONTENIDO
11.1. Introducción a HTML.
11.2. Incorporación de applets a páginas Web.
11.3. Estructura de un applet.
11.4. Transformación de aplicaciones en applets.
11.5. Incorporación de sonido.
11.6. Incorporación de imágenes.
285
286 Java 2. Manual de programación
~~ ~ ~~ ~ ~~~ ~~ ~
Los applets son pequeños programas Java que se incluyen en
páginas Web y cuyo código se descarga desde el sevidor para ser
ejecutado localmentepor un navegador. Por tanto, para trabajar con
applets es necesario conocer algunas de las características de las
páginas Web y del lenguaje en que éstas están escritas, y el capí-
tulo comienza exponiendo conocimientos básicos sobre HTML.
También se explicará la estructura fundamental de un applet. Te-
niendo en cuenta que las applets trabajan con IGU y están guia-
das por eventos, el capítulo se apoya en los conocimientos
aportados por otros anteriores para la creación de las primeras
applets.
11.1. INTRODUCCIÓN A HTML
Internet es útil para el intercambio de información y la comunicación multiperso-
nal gracias a su organización en servidores, que disponen de la información y los
recursos, y clientes, que acceden a ellos. Dentro de los servicios proporcionados
por Internet, la Web ocupa un lugar destacado, constituyendo las páginas Web,
archivos guardados en servidores repartidos por todo el mundo y los navegadores
programas cuya misión es conectarse a un servidor Web para recibir sus datos y
presentar las páginas en pantalla. Las paginas Web se escriben en lenguaje HTML
(lenguaje de marcas de hipertexto). En un documento HTML existe texto normal y
marcas encerradas entre llaves angulares que indican al navegador cómo mostrar el
contenido del documento en pantalla.
Existen marcas básicas que necesitan otra de cierre, como las mostradas en la
Tabla 11.1.
Tabla 11.I.Marcas básicas de un documento HTML
~~ ~ __
Marca Significado
<HTML> . . . </HTML> Comienzo y fin del documento HTML
<HEAD> . . . </HEAD> Comienzo y fin de cabecera
<BODY> . . . </BODY> Comienzo y fin del cuerpo
Applets 287
Las marcas <HTML> y </HTML> señalan el principio y fin del documento y
<HEAD> </HEAD> y <BODY> </BODY> dividen el documento en sus dos par-
tes fundamentales: cabecera y cuerpo.
PARTES EN UN DOCUMENTO HTML
<HTML> -Comienzo del documento
<HEAD>
</HEAD>
<BODY>
</BODY>
Cabezera
Cuerpo
1
1
...
...
</HTML> -Fin del documento
Otras marcas que necesitan cierre se muestran en la Tabla 11.2.
Tabla 11.2. Marcas en las que se exige cierre
Marca Significado
<TITLE> título-de-fagágina </TITLE>
<Hn> ...</Hn>
<UL>
<UL>
<OL>
<OL>
< L I > ...</OL>
<B> ...</B>
< I > ...</I>
entradas-de-la-lista
entradas-de-la-lista
Irá dentro de la cabecera y permitirá poner título
al documento.
Cabeceras cuyo nivel viene representado por el
número n que las acompaña. El tamaño de texto
más grande es para las de nivel 1
Comienzo y fin de una lista no numerada
Comienzo y fin de una lista numerada
Entrada de la lista
Negrita
Cursiva
Existen también en HTML otras marcas que no necesitan cierre (Tabla 11.3).
288 Java 2. Manual de programación
Tabla 11.3. Marcas en las que se requiere cierre
Marca Significado
<BR>
<P>
<HR>
Salto al principio de la siguiente línea sin introducir una línea en
blanco para separar el texto anterior.
Nuevo párrafo, introduciendo una línea en blanco para separar el
siguiente texto del anterior.
Línea horizontal gráfica como separador de bloques de texto.
Es preciso tener presente que la escritura de saltos de línea en una página HTML
Así mismo, existe otra clase de marcas que requieren atributos con especifica-
se trata como si fuera una escritura de espacios en blanco.
ción de la información adicional necesaria para completar la acción.
Tabla 11.4. Marcas que requieren atributos
Marca Significado
~ ~ ~~~ ~~~~ ~
<FONT SIZE=nÚmero> Cambia el tamaño de las fuentes.
<IMG SRC=nombre-imagen> Permite incluir en una página
Web la imagen con el nombre
especificado.
La marca para la inclusión de una
imagen se puede complementar
con el atributo ALT que permite
la sustitución de la imagen por
una descripción de la misma
cuando dicha página se visite con
el navegador en modo texto.
<IMG SRC=nombre-imagen ALT=descripción>
Los enlaces en las páginas Web se indican a traves de la marca <A>. ..</A>,
que se denomina ((ancla))(anchors)y que necesita como atributo la referencia al
documento con el cual se enlaza (URL), de la siguiente forma:
<A HREF= ref-a1- docurnento- con-e1- cua1- se-en1az a>
texto- que-se-rno strara- en-panta11a </ A>
Además de las marcas citadas, existen caracteres que tienen un significado espe-
cial en lenguaje HTML. Estos caracteres especiales sirven para representar en el
dispositivo de salida (pantalla, impresora,...) a otros caracteres normales de escritu-
ra que no pueden escribirse directamente, dado que tienen un significado especial
en HTML. Es decir, por ejemplo, para representar en pantalla el símbolo es pre-
ciso escribir en el documento HTML el carácter (( & 1t;D.
Applets 289
Tabla 11.5. Representación de caracteres especiales
Carácterque se desea presentar
< &It;
> &gt;
11 & q u o t ;
Carácterpor el que debe sustituirse
& &amp;
. . . ...
HTML también tiene códigos especiales para los caracteres que no forman parte
de conjunto ASCII estándar (Tabla 11.6).
Tabla 11.6. Códigos especiales para representar caracteres no ASCII
Carácterque se desea presentar Carácterpor el que debe sustituirse
ó
ñ
Ñ
...
&oacute;
&ntilde;
&Ntilde;
...
11.2. INCORPORACIÓN DE APPLETS A PÁGINAS WEB
Los applets permiten vincular código Java con páginas Web. Esta acción permite
construirpáginas Web dinámicas. Además, hay que tener en cuenta que el código Java
se ((descarga))desde el servidor para ser ejecutado en el navegador, de forma que se
aprovecha la potencia del sistema local y se evita la sobrecarga del servidor. Un applet
se incorpora en una página Web usando las siguientes órdenes (comandos) html:
<APPLET
CODEBASE= U R L - d e - l a - c l a s e
CODE=nombre- de-1a- c1ase
NAME=nornbre
WIDTH=núrnero H E I G H T = n Ú m e r o
ALT= t e x t o
ALIGN=?’ ust i f i c a c i ó n
V S P A C E = e s p a c i o - vert i cal
<PARAM
H S P A C E = e s p a c i o - h o r i zon t a l
>
NAME=n o m b r e - a rgurnen t o VALUE= va1or-a rgumen to>
. . . (parametros, puede haber varios)
(códigosHTML alternativos para clientes que no soportan Java)
< / A P P L E T >
290 Java 2. Manual de programación
Los distintos elementos y su responsabiiicLd se describen a continuación:
CODEBASE:Necesario cuando el upplet no se encuentra en el mismo lugar que
la página Web y representa el directorio, relativo al directorio en donde se
encuentra la página Web, que contiene la clase del upplet.
CODE:Obligatorio; nombre del archivo que contiene el código byte de la clase
ya compilada.
NAME:Opcional. Nombre de la instancia del applet. Este nombre permite a los
upplets de una misma página encontrarse y comunicarse entre sí.
WIDTH y HEIGHT:Obligatorios; representan el tamaño del rectángulo que
ocupará el applet en la página Web.
ALT: Opcional; sirve para especificar el texto alternativo que presentará un
navegador cuando comprenda la etiqueta APPLET, pero no pueda ejecutar el
applet.
ALIGN:Opcional; establece la alineación del upplet con respecto a los otros
elementos de la pagina. Como justificación, se podrá indicar LEFT,RIGHT,
TOP, TEXTTOP,MIDDLE,ABSMIDDLE,BASELINE,BOTTOM y ABSBOT-
TOM.
tal que separará al upplet del texto que le rodea.
VSPACE y HSPACE:Opcionales, permiten fijar el espacio vertical y horizon-
Entre las órdenes APPLET y /APPLET se pueden colocar parámetros para el
upplet con la sintaxis:
<PARAM NAME=nornbre-argumento V A L U E = v a l o r - a r g u m e n t o >
- NAME: Nombre del parametro que se desea pasar al applet. El nom-
bre a r g u m e n t o puede escribirse encerrado o no entre comillas y no se
hacedistinción entre mayúsculas y minúsculas.
- VALUE:Valor que se desea enviar al upplet mediante el parametro. El
valor que se envía también puede escribirse encerrado o no entre comillas.
Es importante tener presente que los parámetros pasados a un upplet pueden ser
varios, resultando necesario especificar para cada uno de ellos un nombre
(NAME)y un valor (VALUE). Otro factor a considerar es que si se desea que las
applets que trabajan con parámetros puedan ejecutarse siempre, conviene que en las
mismas se proporcionen valores por omisión para dichos parámetros. Por último,
diremos que los parámetros se reciben en el upplet siempre como cadenas median-
te el método getparameter:
public java.lang.Ctring getParameter(java.1ang.String pl)
Applefs 291
La sentencia necesaria sería, pues:
String argumento= getParameter ( "nombre-argumento" ) ;
donde las comillas son obligatorias. Esta sentencia devuelve el valor-argumento
del parámetro cuyo nombre (NAME) es nombre-argumento; si no lo encuentra,
devuelve nu 11.
11.2.1. Edición de un documento HTML y-ejecución de applefs
La edición de una página HTML se realiza con un editor de texto. Una vez escrito
el código en el editor, se debe almacenar con la extensión HTML.
La visualización de la página Web que incorpora un applet se podrá efectuar
usando un navegador o el visor de applets, appletviewer;de ambas formas el applet
se carga y ejecuta automáticamente.
FORMATO BÁSICO DE UNA PÁGINA WEB QUE INCORPORA UN APPLET
<HTML>
<HEAD>
</HEAD>
<BODY>
<APPLET
CODE= nombre-de-la-clase
WIDTH= número
height= número >
</APPLET>
</BODY>
</ HTML>
Ejemplo
Una página HTML que incorpora un applet al que se le pasan parámetros podría ser
la mostrada en la Figura 11.1.
292 Java 2. Manual de programación
<HEAD>
;/HEAD,
<RODY>
<HI .EjernpIo</Hl>
<UL>
~TlTLE>T&iacute,iulocírlTLE>
<Ll> Lino
<LI> Dos </Liz
</UL>
<I-- Colocacion del codiaa HTML aue interese - - >
4PFLET
CODE = libro Tenia11 El4pplet class
WIDTH = 220
HEIGHT = ion>
~ P A R A MNAME = "Colar" VALJE = 'w5,1nn,inn":
cPARAM NAME = "Nombre" VALUE = "Cadena">
aAPFLET>
</BODY,
:/HTML>
Figura 11.1. Página T.html.
Es conveniente observar el código HTML y, sobre todo, cómo se especifica en
CODE el nombre del archivo que contiene el código byte (bytecode)de la clase com-
pilada.
CODE=libro.Temall.EjApplet.class
El applet de la Figura 11.2 recibe como cadenas los parámetros Nombre y
Col or. Dicho upplet no adjudica valores por omisión para los parámetros, ya que
el ejemplo pretende ser una demostración sobre el paso de los mismos y, si se pro-
dujeran errores basta con que éstos se visualicen. Es importante destacar trata-
miento del parámetro Color que en el mencionado upplet se efectúa. Es necesario
tener en cuenta que en Java el color está encapsulado en la clase Color,que defi-
ne algunas constantes para especificar un conjunto de colores comunes, pero ade-
más es posible definir colores utilizando constructores de color. De esta forma es
posible especificar cualquier color y después Java busca el más cercano al solici-
tado en función de las limitaciones del sistema donde se esté ejecutando el pro-
grama o applet. El tratamiento efectuado es debido a que applet exige recibir
cadenas como parámetros y el constructor de color empleado requiere tres núme-
ros enteros.
public Color (int p l , int p 2 , int p3) Los parámetros son valores del
O al 255 que se corresponden
con la cantidad de colores puros,
rojo, verde y azul, utilizados en
la mezcla para obtener el color
deseado.
Applets 293
package libro Tema11,
import java awt *,
import Java applet *,
public class EjApplet extends Applet
String nombre,
String color,
public void init0
i
nombre = getParameter(1'Nombre"),
coIot = yetParameter("CoIoI"),
int cl = Integer parselnt(co1or substring(0,3)),
int c2 = Integer parselnt(co1or subctring(4,6)),
int c3 = Integer parselnt(co1or substringp,lO)),
setBackground(new Color(c1 ,c2, c3)),
I
1
i
public void paint(Graphics g)
g setFont(new Font("Arial", Font BOLD, 14)),
y drawString(nombre ,20,2O),
Figura 11.2. Applet: EjApplet.java.
El método init ( ) es proporcionado por la clase Applet e inicializa el upplet
cada vez que se carga (posteriormente se ampliará el concepto de init). El upplet
puede hacer uso de paint debido a que la clase Applet hereda de Panel,que a
su vez lo hace de Container y ésta de Component.
Tanto la página como el upplet se almacenan en C : 1ibro Tema11 .
Una vez creados el applet y la pagina, la única operación necesaria será compi-
lar el upplet, para lo que se utiliza la siguiente instrucción:
C:libroTemall>javac EjApplet .Java
Al abrir la página, usando por ejemplo Microsoft Internet Explorer, el upplet se
Otra forma de ejecutar un upplet es utilizando uppletviewer; éste simula un
carga y ejecuta automáticamente. El resultado se muestra en la Figura 11.3.
navegador elemental y necesita que se le pase como parámetro el nombre del archi-
vo HTML donde se incorpora el upplet. Es decir, ejecutar la orden:
C:libroTemall>appletviewer T.html
294 Java 2. Manual de programación
.uti0
m Dos 
Parámetro: Parámetro:
rnelGI Nombre y
lugar
donde se
encuentra
la página
Figura 11.3. Resultado de la ejecución del applet E] Applet .class.
El uso de uppletviewer requiere añadir al archivo HTML la orden:
CODECASE = ..  . .
11.3. ESTRUCTURA DE UN APPLET
La clase Applet extiende la clase Panel del AWT y Panel extiende
Container que, a su vez, extiende Component, proporcionándose así a las
upplets todas las herramientas necesarias en la programación IGU (Znterfuz Gráfica
de Usuario) y, al igual que todos los programas que trabajan con IGU, las upplets
están guiadas por eventos.
Las upplets disponen de cinco métodos que pueden sobreescribir, aunque no es
obligatorio que lo hagan, pues tienen implementaciones por defecto que se invoca-
rán automáticamente durante la ejecución de la misma. Cuatro de estos métodos son
proporcionados por la clase App1et:
public void init ( ) Inicializa el applet y es invocado por el
Appletviexlev o el navegador cuando se carga el
applet.
Applets 295
public void s t a r t ( ) Se ejecuta a continuación de init y también cada
vez que el usuario del navegador regresa a la
página HTML donde reside el upplet y debe contener
las tareas que deban llevarse a cabo en estas
ocasiones.
public void stop() Se ejecuta cuando el usuario abandona la página
HTML en la que reside el applet.
public void destroy ( ) Libera todos los recursos que el applet está utilizando
y se ejecuta antes de que el applet se descargue
cuando el usuario sale de la sesión de navegación.
El quinto método es paint perteneciente a la clase Container,que se invo-
ca para dibujar en el applet al iniciar su ejecución, así como cada vez que el mismo
necesita redibujarse. Un ejemplo se presenta cuando el applet se oculta por una ven-
tana y luego esta ventana se mueve o se cierra.
ESTRUCTURA BÁSICA DE UN APPLET
import java.awt.*;
import java.applet.*;
public class NombreApplet extends Applet
/ / métodos que se pueden sobreescribir
public void init ( )
{ / I . ..i
public void start O
{ / / .. . I
public void stop0
{ / I . ..I
public void destroy O
{ / / . . . I
public void paint (Graphics g)
{ / / .. . I
I
Otros métodos de interés cuando se trabaja con upplets son:
public void recize(int pl, int p2)
Redimensionar el applet.
296 Java 2. Manual de programación
public void repaint ( )
Repintar el upplet a petición del programa.
public void update(java.awt.Graphics pl)
Es llamado por repaint y, como paint,se utiliza para dibujar en el upplet, ofreciendo la
posibilidad de efectuar repintados incrementales.
public void showstatus (java.lang.Ctring pi)
Muestra un mensaje en la barra de estado del navegador o visor de applets.
public java.awt.Image getImage (java.net.URL pl,
java.lang.String p 2 ) .
Devuelve un objeto image que encapsula la imagen encontrada en la dirección especifica-
da mediante el parámetro p l y cuyo nombre es el especificado como segundo parámetro.
public java.applet.AudioClip getAudioClip (java.net.URL p l ,
java.lang.String p 2 ) .
Devuelve un objeto Audioclip que encapsula el fragmento de audio encontrado en la
dirección especificada mediante el parámetro pl y cuyo nombre es p2.
public java.applet.App1etContext getAppletContext0
Obtiene el contexto del upplet.
public java.net.URL getCodeBase0
Obtiene el URL del upplet.
public java.net.URL getDocumentBase0
Devuelve el URL del archivo HTML que inició el upplet.
public abstract void showDocument (java.net.URL pi)
Muestra, desde el contexto de un upplet, el documento especificado mediante el parámetro
pl.Es un método definido en la interfaz
java.app1et.AppletContext
public abstract java.util.Enumeration getApplets ( )
Método que permite obtener las applets que se encuentran en el contexto de la actual.
Definido en la interfaz
java.applet.App1etContext
public abstract java.applet.Applet getApplet(java.lang.String pl)
Devuelve el upplet de nombre pl,si dicha upplet se encuentra en el contexto actual, en otro
caso devuelve null Definido en la interfaz
java.applet.App1etContext
Applets 297
Además de AppletContext que permite acceder al entorno de ejecución del
applet, la clase Applet dispone de otras dos interfaces mas: 1) AppletStub,
proporciona mecanismos para la comunicación entre el applet y el navegador; 2)
Audioclip,reproduce archivos de sonido. La incorporación de imágenes y soni-
do a un applet se verá más adelante.
Ejemplo
Applet que calcula el volumen de una esfera y lo muestra en la barra de estado.
package libro.Ternal1;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Esferavol extends Applet implements ActionListener
i
Label mensaje;
TextField valor;
public void init ( )
i
mensaje = new Label("Introduzca el radio y pulse <RTM>: " ) ;
valor = new TextField(l0);
add (mensaje);
add (valor);
valor.addActionListener(this);
public void actionPerformed(ActionEvent e)
i
Couble val = new Double (valor.getText( 1 ) ;
double radio = val.doublevalue ( ) ;
showstatus ("El volumen es "
+ Double.toString(volumenEsfera(radio)));
public double volumenEsfera( double radio)
double volumen;
volumen = (double)4/3*Math.PI*Math.pow (radio,3);
return volumen;
I
298 Java 2.Manual de programación
Figura 11.4. Resultado de la ejecución del applet Esferavol.class.
Archivo HTML (Pagina.HTML)
<HTML>
<HEAC>
</HEAD>
<BODY>
<APPLET
CODE=libro.Temall.EsferaVol.class
NAME=EsferaVol
WIDTH=32O
HE;GHT=lOO >
</APP¿ET>
</BODY>
</HTML>
11.4. TRANSFORMACIÓN DE APLICACIONES EN APPLETS
Las técnicas generales a seguir para transformar en upplets las aplicaciones con
IGU desarrolladas en Java son:
Añadir a las importaciones del programa la del paquete java .applet .*.
Hacer que la clase que define el applet extienda Applet.La sustitución de
Frame por Applet obliga a eliminar las posibles llamadas a setTitle y a
cambiar dispose por destoy.
Reemplazar el constructor de la clase por el método init.
Eliminar el método main.
Eliminar las llamadas a System.exit.
Hacer que la entrada y salida de datos se efectúe siempre a través del AWT.
Appleis 299
Tener en cuenta que el administrador de diseño por defecto para las applets es
Crear un archivo HTML que incorpore el applet.
FlowLayout.
Se requiere, además, tener presente las siguientes consideraciones:
Los applets, por razones de seguridad, no pueden efectuar todos los trabajos
que realizan las aplicaciones. Por ejemplo, no pueden ejecutar un programa de
la computadora del usuario, ni listar directorios, ni borrar, ni leer, ni escribir, ni
renombrar archivos en el sistema local.
Cuando se efectúa programación multihilo, deben detenerse los hilos de un
applet cuando se sale de la página Web en la que el mismo reside. Para ello, se
sobreescribe el método s t o p del applet. Los hilos se reinician en el método
start del applet que se invoca automáticamente cuando el usuario retorna a
la página Web.
Los applets sólo pueden crear conexiones por red con la computadora de la que
proceden.
Ejemplo
Transformar en applet la aplicación de la calculadora vista en el capítulo anterior.
package libro.Temal1;
import java.awt.*;
import java.awt.event.*;
/ / se añade la importación del paquete applet
import java.applet.*;
/ / En la aplicación la clase Calculadora extendía Frame
public class Calculadora extends Applet
i
TextField resultado;
boolean otroNumero = true, esDecima1 = false;
double total = 0.0;
char operador = 'x';
/ / init reemplaza al constructor de la clase, Calculadora0
public void init 0
this.setLayout (new BorderLayout ( ) ) ;
Botones cero, uno, dos, tres, cuatro, cinco, seis,
siete, ocho, nueve, coma;
Botones suma, resta, multiplica, divide, obtiene, borra;
300 Java 2. Manual de programación
setFont (new Font ("Arial",Font.PLAIN,14)) ;
setBackground(Color.1ightGray);
Panel paneloperandos = new Panel();
paneloperandos.setLayout (new GridLayout (3,4)) ;
cero = new Botones ("O", 'x', 'O', t h i s ) ;
panelOperandos.add(cero);
cero.addActionListener(cero);
uno = new Botones ("l", 'x' , '1' , t h i s ) ;
panelOperandos.add(uno);
uno.addActionListener(uno);
dos = new Botones( "2", 'x', '2', t h i s ) ;
paneloperandos .add(dos);
dos.addActionListener(dos);
tres = new Botones ( " 3 " , 'x' , ' 3 ' , t h i s ) ;
panelOperandos.add(tres);
tres.addActionListener (tres);
cuatro = new Botones ("4", 'x' , '4', t h i s ) ;
panelOperandos.add(cuatro);
cuatro.addActionListener(cuatro);
cinco = new Botones ( " 5 " , 'x' , '5', t h i s ) ;
panelOperandos.add( cinco ) ;
cinco.addActionListener(cinco) ;
seis = new Botones ("6", 'x' , '6', t h i s ) ;
panelOperandos.add(seis);
seis.addActionListener(seis);
siete = new Botones ("7", 'x' , 'I!, t h i s ) ;
panelOperandos.add(siete);
siete.addActionListener(siete);
ocho = new Botones ("8", 'x', '8', t h i s ) ;
panelOperandos.add( ocho 1 ;
ocho.addActionListener(och0);
nueve = new Botones ("9", 'x', '9', t h i s
panelOperandos.add(nueve);
nueve.addActionListener(nueve);
coma = new Botones ( " , ' I , 'x' , ' .' , t h i s
panelOperandos.add(coma);
coma.addActionListener(coma);
Panel paneloperadores = new Panel ( ) ;
panelOperadores.setLayout(new GridLayout(2,3));
borra = new Botones("C", ' ', 'O', t h i s ) ;
panelOperadores.add(borra);
borra.addActionListener(borra);
suma = new Botones ( " + " , 't' , 'O', t h i s ) ;
panelOperadores.add(suma);
suma.addActionListener(suma);
resta = new Botones ( ' I - " , '-', ' O ' , t h i s ) ;
panelOperadores.add(resta);
resta.addActionListener(resta);
multiplica = new Botones ( " * " , ' * ' , ' O ' , t h i s ) ;
panelOperadores.add(mu1tiplica);
nultiplica.addActionListener(multip1icaj;
divide = new Botones ( " / ' I , ' / ' , 'O', this);
panelOperadores.add(divide);
aivide.addActionListener(dividej;
obtiene = new Botones ( " = ' I , I = ', 'O', this j;
panelOperadores.add(obtiene);
obtiene.addActionListener(obtienej;
Applets
Panel panelcentral = new Panel ( ) ;
p a n e l C e n t r a l . s e t L a y o U t ( n e w GridLayout(l,2,:0,13));
panelCentrai.add(panelCperandos);
panelCentral.add(panel0peradcre.s);
Panel panelResultado = new Panel();
panelResultado. setLayout (new FlowLayout ( j j ;
resultado = new TextField( "O",15);
resultado.setEditable(false);
panelResultado.add(resultadoj;
add ("North", panelResuitadoj ;
add("Center", panelcentral) ;
/ / Desaparece el método main()
void coloca (char valor )
i
String digito = " ' I ;
if( valor == ' . )'
I
if ( !ecDecimal )
if ( otroNumero )
i
resultado.setText ( "O") ;
otroNumero = false;
I
esDecimal = true;
digit0 ' f . I' l .
I
I
else
if ( otroNumero )
i
d i g i t o = ""+valor;
resultado.setText( digito 1 ;
if ( valor ! = 'O' )
otroNumero = false;
1
else
repaint ( ) ;
resultado.setText(resultado.getText() + digit0 1;
302 Java 2. Manual de programación
void calcula (char otrooperador)
i
double numero;
numero = (new Double (resultado.getText ( ) ) ) .doublevalue ( ) ;
i f ( ( !otroNumero 1 1 operador == '=' ) & & otrocperador != ' ' )
switch( operador )
i
case I t ' :
total t= numero;
break;
case I - ' :
total -= numero;
break;
case ' * I :
total *= numero;
break ;
case ' / I :
total /= numero;
break;
case 'x' :
case ' ' :
total = numero;
break:
1
resultado.setText ( ( new Double (total) ) .tostring()) ;
1
operador = GtroOperadGr;
otroNumero = true;
esDecimal = false;
i f (otrocperador == ' ' 1
i
resultado.setText ( "0" ) ;
operador = ' ';
total = 0.0;
1
class Botones extends Button implements ActionListener
i
char unoperador;
char unvalor;
Calculadora calc;
Botones(Str1ng texto, char oper, char valor, Calculadora c )
i
super( texto ) ;
unoperador = oper;
unvalor = valor;
calc = c;
I
Applets 303
p u b l i c void actionPerformed (ActionEvent e )
if ( .;noperador == ‘x’ )
else
caic.coloca (unvalor);
calc.calcula(unoperado=);
/ / No es necesaria la clase Cierre
Archivo HTML (PagCalc.HFML)
<HTML>
<HEAD>
< T I T T E , C a l c u i a d o r a < / T I T = E >
</ HEAC>
<BODY>
<APPLE,
C03Y=libro.Teia;l.Ca~cui~d~~a.class
NAME=Ca1cuiadora
WIDTH=2 OC
HEIGHT=14@ >
</ APPLET>
</B03Y>
</HTML>
Cuando un programa no trabaja con interfaz gráfica de usuario, su transforma-
ción en applet conlleva modificaciones más profundas, ya que se requiere pasar a
una programación dirigida por eventos.
Ejemplo
Transformar en applet una aplicación que rellena un vector con 1O números enteros
aleatorios, muestra los números generados y la media de los mismos.
/ / Aplicación
class LLenaArr
p u b l i c s t a t i c void main (String[ j args)
f i n a l i n t n5iems=lG;
i n t arr [ ] = new int[nElerns] ;
i n t j ;
i n t suma = O ;
for(j = 0; j < nElems; j + + )
i
arr[j] = 1 + ( i n t ) (Math.randorn() * 1 0 ) ;
suma += arr[jl;
304 Java 2. Manual de programación
double media = (double)(suma) / nElems;
for(j = O; 1 < nElems; j++)
System.out.println ( " ' I ) ;
System.out .println("La media es "+ media) ;
system.out.print( arr[j] + " ' I ) ;
i
Compilación
C:libroTemal:>]avac LLenaArr.java
Ejecución y resultado de la misma
C:libroTemall>]ava LLenaArr
8 9 3 4 9 10 7 7 3 6
La necia es 6.6
/ / applet
import ]ava.awt.*;
import ]ava.applet.*;
public class LLenaArr2 extends Applet
final int nElems = 10;
int arr[] = new int[nElemsl;
double media = 0.0;
public void init ( )
int suma = O;
t
for(int j = O; j < nElems; 1 ++)
arr[j] = 1 + (int) (Math.random0 * 10);
suma += arr [j];
media = (double)(suma)/ nE1ern.s;
public void paint (Graphics g )
int x = O;
for(int j = O; j < nElems; j++)
I
x += 35;
g.drawString(String.valueOf (arr[j]), x, 35);
Applets 305
g.drawString("La media es "+ media,35,70);
1
Compilación
C:librotema ll>javac LLenaArr2.java
Archivo HTML (Numeros.html)
IHTMLZ
<HEAD>
</HEAD>
<BODY>
<APPLET
CODE= LLenaArr2.class
WIDTH= 400
HEIGHT= loo>
</APPLET>
</BODY>
</ HTML>
Ejecución
C:libroTemall>appletviewer numeros.htm1
El resultado se muestra en la Figura 11.5.
7 2 9 6 8 6 1 8 1 3
Lamediaes 51
Figura 11.5. Resultado de la ejecución del applet LLenaArr .class
306 Java 2. Manual de programación
11.5. INCORPORACIÓN DE SONIDO
Para reproducir sonidos desde un applet, se comienza por cargar el archivo de soni-
do mediante
public java.applet.AudioC1ip getAudioCl;p(;ava.net.URL pi,
lava.lang.String p2)
y posteriormente se controla la reproducción mediante los métodos proporcionados
por Audioclip.
Ejemplo
Audioclip audiocl;
audiocl = getAudioClip (getCodeBase( ) , "Sonido.au");
audiocl .play( ) ;
. . .
. . .
De esta forma los datos de audio se cargan cuando se construye el audio clip.
La interfaz Audioclip del paquete java .applet define los siguientes
métodos:
public abstract void l o o p ( ) Reproduce el archivo de forma continua.
public abstract void play() Reproduce el archivo.
public abstract void stop() Detiene la reproducción.
La versión 1.3 de la Plataforma 2 de Java incluye una nueva y poderosa
A P I ( javax .sound) que permite capturar, procesar y reproducir audio y MIDI.
Este A P I permite una flexible configuración del audio y del sistema M I D I , inclu-
yendo métodos para que las aplicaciones puedan preguntar al sistema cuáles son los
recursos que están instalados y disponibles. Los archivos de audio pueden ser de los
formatos AIF, AU y WAV y los de música M I D I Tipo O, M I D I Tipo 1y RMF.
11.6. INCORPORACIÓN DE IMÁGENES
El método a seguirpara la incorporaciónde imágenes a un applet es similar al anterior-
mente descritopara la incorporaciónde sonido. La imagen se carga mediante el método
public java.awt.Image getImage(java.net.URL pi,
java.lang.String p2)
Applets 307
en el que pi representa el lugar de ubicación de la imagen, mientras que p2 es el
nombre del archivo que la contiene, que puede ser de tipo j pg o gif,y se puede
mostrar utilizando
p u b l i c abstract boolean drawImage(java.awt.1mage p l , i n t p2,
i n t p3, java.awt.image.ImageObserver p4)
El primer parámetro p l es la imagen, el segundo, p2,y tercero, p3, representan
el lugar donde debe situarse la imagen en el applet (en realidad son las coordena-
das para la esquina superior izquierda de la misma) y el cuarto, p4, es una refe-
rencia a un objeto Imageobserver,que puede ser cualquiera que implemente la
interfaz Imageobserver y normalmente es el objeto en el que se muestra la ima-
gen. También se puede utilizar para mostrar la imagen
p u b l i c abstract boolean drawImage(java.awt.1mage p l , i n t p2,
i n t p3, i n t p4, i n t p 5 , java.awt.image.Irnage0bserver p6)
Este segundo método permite establecer una anchura y altura determinadas para
Imageobserver es una interfaz implementada por la clase Component que
la misma mediante los parámetros p5 y p6.
define el método
public abstract boolean imageupdate (java.awt .Image pl, i n t p2,
i n t p3, i n t p4, i n t p5, i n t p6)
el cual puede redefinirse para cambiar su comportamiento por defecto, que es pin-
tar las imágenes mientras se cargan. El método imageupdate devolverá
false cuando se haya completado la carga de una imagen y true en caso con-
trario.
Ejemplo
Modificación del ejercicio que calcula el volumen de una esfera y lo presenta en la
barra de estado, para que muestre la imagen de un altavoz y haga sonar un pitido
especial tras la introducción de los datos.
package libro.Ternal1;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
308 Java 2. Manual de programación
public class EsferaVol2 extends Applet implements ActionListener
label mensale;
TextField valor;
Audioclip pita;
Image audio;
public void init ( )
/ * Se supone qae los archivos, tanto de imagen como de
sonido, se encuentran almacenados en el mismo lugar
que el applet, por eso se obtiene su dirección con
getCodeBase " /
audio = getImage (getCodeBace( ) , "Audio.gif");
pi=a = getAudioClip (getCodeBase( ) , "Sonido.au");
mensaje = new Label("1ntroduzca el radio y pulse <RTM>: " ) ;
valor = new TexLField(l0) ;
add(mensaje1 ;
ada (valor);
valor.addActionlistener(this);
public void actionPerformed(Acti0nEvent e)
t
Couble val = new Double (valor.getText ( ) ) ;
double radio = val.doublevalue ( ) ;
showCtatus ("El volumen es " +
pita.play() ;
Double.toString(volumenEsfera(radio)));
1
public double volumenFsfera ( double radio)
i
double volumen;
volumen = (double)4/3* Math.PI * Math.pow(radio,3);
return volumen;
public void paint (Graphics g)
i
i
g.drawImage (audio, O, O, this);
Archivo HTML (Pagina2.HTML)
<HTML>
<HEAD>
</HEAD>
<BODY>
<APPLET
CGDE=iibro.Temall.EsferaVol2.class
NAME=EsferaVol2
WIDTH=320
HEIGHT=100 >
</APPLES>.
</BODY >
</HTML>
I I
Figura 11.6. Resultado de la ejecución de EsferaVol2. class.
Si se requiere cargar varias imágenes simultáneamente en lugar de la interfaz
Imageobserver y su método imageupdate, es mejor utilizar la clase
MediaTracker de java.awt, con la cual se puede comprobar el estado de
diversas imágenes en paralelo.
Métodos
public MediaTracker (java.awt..Component p l )
Permite crear la instancia.
public void addImage (java.awt.Image pl, int p 2 )
Añade una nueva imagen sobre la que controlar el estado de carga. El primer parámetro es la
referencia a la imagen que está siendo cargada y el segundo es un número identificativo del
misma.
public boolean Image checkID (int pl)
Verifica el estado de la imagen.
public void waitForID(int pi)
Obliga al programa a esperar hasta que la imagen cuyo identificador se especifica como pará-
metro se haya cargado por completo.
public void waitForAll ( )
Obliga al programa a esperar hasta que todas las imágenes registradas se hayan terminado de
cargar.
A 12
rrogramacion
concurrente:
Hilos de ejecución
CONTENIDO
12.1. La programación multihilo en Java.
12.2. Estados de un hilo.
12.3. Creación de hilos.
12.4. Planificación y prioridades.
12.5. Hilos de tipo demonio.
12.6. Grupos de hilos.
12.7. Sincronización.
12.8. Animaciones.
12.9. Doble buffer.
311
312 Java 2. Manual de programación
Java permite la creación de programas con múltiples hilos de eje-
cución (multithreading); es decir, programas con varias partes,
denominadas hilos, que realizan sus actividades en paralelo. Hay
que tener en cuenta que la mayor parte de las computadoras per-
sonales disponibles hoy día cuentan con un Único procesador, lo
que hace imposible la ejecución simultánea de los diferentes hilos,
dado Io cual se utiliza un sistema de planificación que permite
compartir el uso del procesador según unas prioridades previa-
mente establecidas.
La creación de programas con varios hilos de ejecución resul-
ta muy útil en algunas ocasiones; por ejemplo, para imprimir un
documento largo mientras el usuario continúa con el uso de la
IGU, o para conseguir una eficiente implementación de las anima-
ciones. No obstante, también puede dar origen a multitud de pro-
blemas y, en la mayor parte de los casos, los hilos habrá que
coordinarlos, por ejemplo, para impedir que uno lea datos de una
estructura antes de que otro los escriba en ella.
12.1. LA PROGRAMACIÓN MULTlHlLO EN JAVA
Los hilos de ejecución en Java están implementados en la clase Thread, que forma
parte del paquete j ava .l a n g . Cada hilo (thread) tiene un principio, unflujo de
ejecución y un,fin definidos, pero no es una entidad independiente sino que debe
ejecutarse en el contexto de un programa. La clase Thread implementa el con-
cepto de ejecución multihilo de una forma independiente de la plataforma donde se
va a producir dicha ejecución. El intérprete de la máquina virtual específica donde
se rueda (se ejecuta) el programa es el encargado de conseguir que los hilos se eje-
cuten de forma concurrente, esto es, alternada en el tiempo, dando la apariencia de
una ejecución simultánea. Por esta razón, la alternancia de código se efectúa de
forma muy diferente en distintas computadoras.
Imp~rtante:Los sistemas operativos tienen diferentes formas de planificar la
concreta de la concurrencia de ope-
.Cuando varios hilos con la misma
ede predecirse durante cuánto tiempo se
ido en un sistema específico.
Programación concurrente: Hilos de ejecución 313
12.2. ESTADOS DE UN HILO
Los objetos hilo de Java tienen cuatro posibles estados: nuevo, ejecutable, bloqueado,
muerto (Tabla 12.1).
Tabla 12.1 Estados de objetos hilo
~~~ ~ ~ ~ ~ ~ ~~ ~~~
Nuevo A este estado se accede mediante la llamada a un constructor de la clase hilo, y
durante el mismo el hilo aún no tiene asignados recursos.
Ejecutable Se accede con una llamada al método start.éste método asigna los recursos
necesarios para ejecutar el hilo, planifica su ejecución y realiza una llamada a su
método r u n , que es el que contiene el código con las acciones que debe realizar
el hilo y habitualmente es un bucle.Como los hilos se alternan, un hilo en estado
ejecutable no tiene por qué ser el que, en un determinado momento, se encuentra
ejecutándose.
Bloqueado Un hilo puede estar bloqueado como consecuencia de:
Una llamada al método sleep,se tendrá así un hilo dormido que, al cabo de
un cierto tiempo, despertará y pasará al estadoEjecutable.El método i n t e r r u p t
consigue que un hilo dormido se despierte inmediatamente, producién-
dose una excepción.
Esperando la terminación de una operación de entradaisalida.
Llamadas a otros métodos como wait, y i e l d o j o i n .
Muerto A este estado se llega tanto tras completar el método r u n . El método s t o p de
versiones anteriores ya no se usa en Java2, debido a que ocasionaba problemas por
ejemplo por no limpiar, antes de finalizar la ejecución de un hilo, el estado de los
objetos con los que el mismo se encontraba trabajando.
Es preciso tener en cuenta que un hilo puede pasar fácilmente del estado
Bloqueado al estado Ejecutable, y la forma de paso estará estrechamente relaciona-
da con la causa que provocó la detención del hilo.
Para obtener información sobre el estado de un hilo, se puede recurrir al méto-
do isAlive, que devuelve true siempre que el hilo no se encuentre en los esta-
dos Nuevo, ni Muerto. Otro método que indirectamente proporciona también
información sobre el estado de un hilo es jo i n , que obliga al hilo llamador a espe-
rar hasta que finalice el hilo al que se llama. El método j oin permite, además,
especificar el límite de tiempo que se esperará a que el otro hilo termine su trabajo.
Un hilo Muerto no puede volver al estado Ejecutable.
Importante: Los métodos stop, suspendedy resumepertenecen a ver-
siones anteriores y ya no se usan en Java2.
314 Java 2. Manual de programación
12.3. CREACIÓN DE HILOS
La creación de hilos en Java se puede efectuar de dos formas:
1 . Usando una instancia de una clase que implemente la interfaz Runnable.
Esta interfaz sólo tiene el método run, que es el método donde habrá que
colocar el código que debe ejecutar el hilo y su implementación constituye la
mejor elección desde una perspectiva orientada a objetos.
2. Creando una subclase de la clase Thread para obtener un objeto que here de
de ella. Hay que tener en cuenta que Java no admite la herencia múltiple, por
lo que cuando se utiliza este método y se hereda de Thread, dicha subcla-
se ya no podrá serlo de ninguna otra.
En ambos casos, para que el hilo comience su ejecución es necesario: I ) crear el
El siguiente es un ejemplo de creación de un hilo implementando la interfaz
hilo, 2) llamar al método start.
Runn ab1e:
public class Principal
public static void main (String[] args)
I
Encuentra bcl = new Encuentra ("0012R");
1
public class Encuentra implements Runnable
I
Thread t;
String claveb;
public Encuentra (String clave)
i
claveb = clave;
t = new Thread (this);
t.start0;
public void run ( )
i
Cystem.out.println("Esta es la tarea a realizar por el hilo");
t=Y
Thread.currentThread().cleep(2000);
1
catch ( InterruptedException e)
Programación concurrente: Hilos de ejecución 315
t
I
System.out .println("Fin");
I
Después de compilar el programa, ejecute C : libroTemal2>java
Principal. En este ejemplo, una clase llamada Encuentra implementa la
interfaz Runnable,lo que obliga a Encuentra a implementar el método run.
A continuación se construye un hilo con el constructor
public Thread (lava.iang.Runnabie PI)
cuyo parámetru es una instancia de la clase que implementa la interfaz Runnable,
y después se llama al método start,cuyo formato es
public synchronized void start ( )
para que comience la ejecución del hilo.
El código a ejecutar por el hilo será el definido en el método run, aunque éste
3uede llamar a otros métodos. Para que se pueda observar mejor el funcionamiento
ie run, se han colocado en él las instrucciones System.out.println y el
método sleep.
El método sleep se utiliza cuando se pretende retrasar la ejecución de un hilo;
-ecibe como parámetro un número de milisegundos y hace dormir al hilo dicho
iúmero de milisegundos como mínimo. Debe colocarse en un bloque
:ry/catch,ya que puede lanzar una excepción si algún otro hilo intenta inte-
rumpirlo mientras está dormido. Cuando el hilo completa el método run se con-
iierte en muerto y finaliza. El hilo actual puede obtenerse mediante el método
Chread.currentThread ( ) .
La creación de hilos podría efectuarse también de la siguiente forma:
public class Principal2
I
public static void main ( S t r i n g [ ] argc)
t
Encuentra2 bcl = new Encuentra2 ("@@12R");
bcl.start ( ) ;
1
public class Encuentra2 extends Thread
i
String claveb;
316 Java 2. Manual de programación
public E n c u e n t r a 2 ( S t r i n g c l a v e )
I
claveb = c l a v e ;
public void r u n ( )
i
Cystem.out . p r i n ~ l n("Esta es l a tarea a r e a l i z a r por e l hilo");
t=Y
{
s ; e e p ( 2 0 0 0 ) ;
i
catch ( I n t e r r u p t e d E x c e p t i o n e )
S y s t e m . o i i t . p r i n t 1 1 1 ( " F i n " );
En este caso, el método r u n se coloca en una subclase de Thread. Esta clase,
en vez de implementar la interfaz R u n a b l e , extiende T h r e a d y redefine su
método r u n . El hilo se crea instanciando la clase E n c u e n t r a 2 y, como en el caso
anterior, para que comience su ejecución se recurre también a start.
12.4. PLANIFICACIÓN Y PRIORIDADES
Los sistemas operativos difieren en la forma de planificar la ejecución de los hilos.
Solaris 7 , por ejemplo, usa multitarea por derecho de prioridad (preemptive) esto
quiere decir que ejecuta un hilo de cierta prioridad hasta completarlo o hasta que
está listo otro hilo de más alta prioridad que lo desaloja. Windows utiliza reparti-
ción de tiempo por turno circular (round-robin),esto implica la concesión a cada
hilo de una cantidad limitada de tiempo, transcurrida la cual el hilo puede ser desa-
lojado por otro que esté listo con su misma prioridad; los hilos con mayor prioridad
siguen ejecutándose los primeros y desalojando, como siempre, a los de menor prio-
ridad. Además, hay que tener en cuenta que Windows NT es capaz de utilizar
máquinas con más de una unidad central de proceso (UCP). En un sistema con múl-
tiples UCP los hilos del programa podrían ser planificados en UCP separadas.
Como Java puede rodar en diferentes sistemas, cada uno de los cuales tiene su
propia forma de manejar hilos, no se puede predecir durante cuánto tiempo se eje-
cutará un hilo antes de que sea interrumpido en un sistema específico. Si en un
determinado momento existen varios hilos en estado Ejecutable, se ejecutará pri-
mero el que tenga mayor prioridad y, sólo cuando finalice o se detenga dicho hilo,
se iniciará la ejecución de otro con menor prioridad; por otra parte, si un hilo con
Programación concurrente: Hilos de ejecución 317
mayor prioridad que el que está en ese momento ejecutándose pasa al estado
Ejecutable, <<arrebataránla UCP al que se encuentra en ejecución. El problema
exige tener cuidado con los algoritmos para que resulten independientes de la pla-
taforma y sólo se presenta ante hilos de idéntica prioridad, y métodos que pueden
ayudar a resolverlo son sleep y y i e l d .
El método sleep quita el control de la UCP a un hilo con cualquier prioridad,
ofreciendo oportunidad para que otros se ejecuten. Además, un hilo puede ceder su
derecho de ejecución efectuando una llamada al método yield,pero sólo a hilos
adecuados y disponibles; es decir, a hilos ejecutables con igual prioridad que el
mismo, por lo que éste método no asegura que el hilo actual detenga su ejecución.
Es redundante en los sistemas con repartición de tiempo por turno circular. Los
métodos suspend y resume pertenecen a versiones anteriores y ya no se usan en
En Java la prioridad de los hilos por omisión es 5 y, cuando se crea uno nuevo,
hereda la prioridad del que lo creó. La prioridad podrá ser modificada mediante el
método
' Java2.
public final void secpricrity (int pl)
al que se le pasa como parámetro valores numéricos enteros comprendidos entre
M I N PRIORITY (constante que vale i ) y MAX P R I O R I T Y (constante que vale
IO), definidas en la clase Thread. Cuanto mayor sea el valor entero, mayor será
el nivel de prioridad que indica. Para obtener la prioridad de un hilo se utiliza el
método
public final int getPriority()
12.5. HILOS DE TIPO DEMONIO
Un demonio es un hilo cuyo propósito es ofrecer servicios a otros hilos de ejecu-
ción existentes dentro del mismo proceso. El intérprete de Java permanece en eje-
cución hasta que todos los hilos de un programa finalizan su ejecución, pero no
espera a que terminen cuando éstos han sido establecidos como demonios. Para
especificar que un hilo de ejecución es de tipo demonio, se deberá realizar una lla-
mada al método
public final void setDaernon (boolean pl)
pasándole como argumento true.Para determinar si un hilo es de este tipo, se
deberá llamar al método
public final boolean isDaernon ( )
318 Java 2. Manual de programación
12.6. GRUPOS DE HILOS
Los hilos en Java siempre pertenecen a un grupo, lo cual va a permitir que se pue-
dan manipular y gestionar de forma colectiva. Cuando se crea un hilo Java lo colo-
ca por defecto en el grupo del hilo bajo el cual se crea y para colocarlo en otro hay
que especificarlo en el constructor, no siendo posible cambiar a un hilo de grupo
tras su creación. Los constructores proporcionados por Thread que permiten aso-
ciar un nuevo hilo a un grupo específico son:
public Thread(java.1ang.ThreadGroup pl,java.lang.Runnable p2)
public Thread(java.lang.ThreadGroup pl, java.lang.Runnable
p2, java.lang.String p 3 )
El grupo de un hilo actual puede obtenerse mediante el método
public final java.1ang.ThreadGroup getThreadGroup0
y el del hilo actual lo podría proporcionar la siguiente instrucción:
Thread.currentThread0 .getThreadGroup();
Es necesario tener en cuenta que los grupos no sólo pueden contener hilos de eje-
cución, sino también otros grupos. La clase ThreadGroup implementa las carac-
terísticas y posibilidades de los grupos de hilos y dentro de ella es posible destacar
los siguientes métodos:
public ThreadGroup ( java.lang.String pi)
Crea un grupo de hilos, el parámetro pl es el nombre para el grupo.
public ThreadGroup java.1ang.ThreadGroup pl, java.lang.String p2)
Crea un grupo hijo del grupo pasado como argumento, el parámetro p2 es el nombre para el
grupo hijo.
public int activecount ( )
Número de hilos Ejecutahles de un grupo de hilos
public final void destroy()
Destruye un grupo de hilos y sus subgrupos.
public int enumerate (java.iang.Thread p1[ 1 )
Devuelve en el array una referencia a todos los hilos activos del grupo.
public int enumeraze (java.1ang.ThreadGroup pi[ 1 )
Devuelve en el array una referencia a todos los grupos activos del grupo.
Programación concurrente: Hilos de ejecución 319
public final int ';'.' ','../ I , ' , ' I
Devuelbe la prioridad máxima que puedc tcricr tin hilo dc u n grupo
public final - J - . J . ' , f ,
Devuelve el nombre del grupo
public final javc.lanq.Thre,~Jr2r,&L ~ J Ct I 0
Devuelve el grupo padre de un grupo de hilos
public final Boolean isüaemon ( )
Indica si el grupo es un demonio.
public final void setMaxpriority (int pl)
Establece la prioridad máxima para un grupo.
public final void setDaemon (boolean pl)
Establece si el grupo actual es o no un demonio.
12.7. SINCRONIZACI~N
Cuando hay muchos hilos rodando en una máquina virtual de Java, es posible que
varios de ellos deseen modificar la misma fuente al mismo tiempo; en estas cir-
cunstancias, se hace necesario sincronizarlos de alguna forma y que cada uno de
ellos conozca de algún modo el estado y las actividades de los demás. La forma más
sencilla de explicar la sincronización es recurrir al clásico problema de produc-
tor/consumidor, en el que existe un productor que genera datos y los almacena en
una estructura de tamaño limitado, por ejemplo un array, desde donde se extraen por
un consumidor. El productor será un hilo que añade los datos a la estructura tan
rápido como puede, mientras que el consumidor va a ser otro hilo que extrae esos
mismos datos también tan rápido como puede. En esta situación es evidente que
será necesario un contador para saber el número de elementos almacenados en el
array en un instante determinado e impedir que, de momento, siga trabajando el
productor cuando el array esté lleno o el consumidor si se queda vacío, como se
muestra en el siguiente programa.
320 Java 2. Manual de programación
public class Principals
t
public static void main (String[ ] args)
Datos d = new Datos ( ) ;
Productor p = new Productor (d);
Consumidor c = new Consumidor (d);
I
i
public class Datos
double[! ad;
int contador = -1;
public Datos ( )
ad = new double [ 41 ;
1
public void poner(doub1e d)
while (contador < ad.length - 1)
contador++;
ad[contador] = d * 1000 + contador;
public void quitar0
while (conEador >= O)
double d = ad[contador];
ad[contador] = O;
contador--;
System.out .println("Consume "+d);
public class Productor implements Runnable
Thread hilol;
Datos dtos;
int num = 0;
Programación concurrente: Hilos de ejecución 321
public Productor (Datos d)
t
dtos = d;
hilol = new Thread(th1.s);
hilol.start ( ) ;
public void r u n 0
i
for (int i = O ; i < 5; i++)
dtos .poner (i);
t=Y
Thread.currentThread0 .sleep(100);
1
catch ( InterruptedException e)
t }
public class Consumidor implements Runnable
i
Thread h i l o 2 ;
Datos dtos;
public Consumidor (Datos d)
dtos = d;
h i 1 0 2 = new Thread(this);
hilo2.start ( 1 ;

public void run()
t
for (int i = O; 1 < 5; i++)
dtos.quitar ( ) ;
try
i
Thread.currentThread ( ) .sleep(100);
322 Java 2. Manual de programación
El problema que surge ahora es debido a que puede ocurrir que, tras un incre-
mento del contador por parte del hilol, y antes de que éste coloque un nuevo
dato en la estructura, el planificador decida dejar de ejecutar el productor y comen-
zar a ejecutar consirmidor y pase a ejecutarse el h i 1 0 2 , que quita un dato de la
posición indicada por el contador, donde aún no hay un dato válido, y decrementa
el contador; si ahora vuelve a ejecutarse el hilol como ya tenía efectuado su
incremento de contador no lo realiza de nuevo y coloca el dato actual sobrescri-
biendo uno anterior. Java soluciona este tipo de problemas mediante la sincroniza-
ción, usando variables de condición y monitores.
. Los monitores son objetos especiales asociados a datos que controlan el acceso a
los mismos. Por otra parte, se denominan secciones críticas a aquellos bloques de
código de un programa que acceden a datos compartidos por hilos de ejecución dis-
tintos y concurrentes. Cuando, en Java, se marcan secciones críticas con la palabra
reservada synchronized se asocia un Único monitor a los datos contenidos en
ellas; de esta forma, durante el tiempo que un hilo permanece dentro de uno de estos
bloques sincronizado, los demás hilos que quieran acceder ai mismo o a cualquier
otro sincronizado sobre la misma instancia tienen que esperar hasta que el monitor
esté libre, pues sólo un hilo puede obtener el monitor sobre los datos en un instante
dado y los hilos que no poseen el monitor no pueden tener ningún tipo de acceso a
los datos con él asociados. Para aplicar todo esto al ejemplo anterior bastaría marcar
con synchronized los métodos poner y quitar, impidiendo su interrupción:
public synchronized void poner (double d)
i
while (contador < a d . lenqth-1)
{
contador++;
ad[contador] = d * 1030 + contador;
public synchronized void qu;tar í )
I
while (contador >= O)
i
double d = ad[contador];
ad[contador] = 3;
contador--;
Cyctem.out .println("Consume "+d);
Para que la sincronización sea efectiva, todos los bloques que acceden a los
recursos compartidos deben estar sincronizados. También hay que tener en cuenta
que, aunque los bloques sincronizados pueden no ser métodos completos, en gene-
Programación concurrente: Hilos de ejecución 323
ral, la mejor opción es que lo sean. No hay problema en que un hilo llame a un
método que accede a datos para los que ya tiene el monitor.
La sincronización es necesaria en programas donde hay varios hilos que de-
sean modificar las mismas fuentes al mismo tiempo; no obstante, puede dar ori-
gen a algunos problemas. Imagine que dos hilos de ejecución necesitan el mo-
nitor sobre dos estructuras y cada uno coge el monitor para una de ellas, pero
como cada hilo necesita los dos monitores y ninguno puede obtener el que tiene
cogido el otro, ambos se paran. La solución consiste en que alguno de estos hilos
ceda voluntariamente el monitor al otro, estas cesiones voluntarias se efec-
túan a través de los métodos wait, notify y notifyAll de la clase
Ob] ect.
En el problema productor/consumidoK citado como ejemplo, si uno de los pro-
cedimientos de monitor descubre que no puede continuar, situación que correspon-
dería a los casos array lleno para productor y vacío para consumidor, mejor que
dormirse por un cierto periodo de tiempo es que dicho procedimiento se bloquee
(wait) hasta que el otro le indique que se debe despertar y volver a competir por
el monitor (notify).
Métodos
public final void wait ( ) Cuando un hilo en ejecución invoca el método
wait pasa a una cola asociada al objeto y su
ejecución se detiene hasta que otro hilo active
el método notify de ese mismo objeto.
public final void notify() Es el método por el que un hilo que está ejecu-
tando un método sincronizado puede despertar
al primero de la cola asociada ai objeto.
public final void notifyAll() Convierte en Ejecutables todos los hilos que
esperaban en la cola del objeto, aunque sólo
uno de ellos podrá obtener el monitor.
Resumen: Se denominan secciones críticas a aquellos bloques de código de un
programa que acceden a datos compartidos por hilos de ejecución distintosy con-
currentes; si las secciones criticas se marcan con la palabra s y n c h r o n i z e d
se asocia un único monitor a los datos contenidos en ellas.
Losmonitores son objetos especiales asociadosa datos que controlan el acce-
so a los mismos, ya que sóloun hilo puede obtener el monitor sobre los datos en
un instante dado. Un hilo puede ceder voluntariamente el monitor al otro a tra-
vésdelosmétodos w a i t , n o t i f y y n o t i f y A l 1 delaclaseObject.
324 Java 2. Manual de programación
Ejemplo
public class Principals2
'L
public static void pain (String[ ] a r g s )
Datos2 d = new Datos20;
Proauctor2 p = new Productor2(d);
Consumidor2 c = new Consumidor2 (d);
1
public class Datos2
double[: ad;
int conzador = -1;
public Datos2 ( )
t
ad = new double [ 4;;
public synchronized void poner( double d)
while (cor.tador >= ad.length-1)
/ * debe estar en un bucle w h i l e , no en un if,
por si en la ciguienze llamada se repite el problema,
por ejexplo a causa de un notifyAll() * /
W a l t ( ) ;
catch (InterruptedException e)
t }
while (contador < aa.1eng:h-1)
contador+*;
ad[contadorl = d*1000 + contador;
i
notify ( ) ;
public synchronized void quitar()
!
while (contador < O)
t
t=Y
t
wait ( ) ;
Programación concurrente: Hilos de ejecución 325
i
catch ( InterruptedCxception e)
t i
i
while (contaacr >= 3)
double d=ad [contadorj ;
contador--;
Cystem.o,t .pri?,tln( “ C c ~ c - m e“+d);
notify ( ) ;
I
public class Productor2 implements Runnable
I
Thread hilol;
Datos2 dtos;
int Rum = O;
public Produc~or2(Datos2 d)
t
dtos = d;
hilol = new Thread(this);
hilol.start ( ) ;
public void r u n 0
t
for (int : = O ; i < 3 ; i t + )
dtcc.poner (i);
public class Consumidor2 implements Runnable
i
Thread hilo2;
Datos2 dtcs;
public Consumidor2 (Datos2 d)
dtos = d;
hilo2 = new Thread(this);
hilo2.star: ( 1 ;
public void run()
for (int i = O; 1 < 3 ; i++)
I
326 Java 2. Manual de programación
citos.quitar();
1
12.8. ANIMAClONES
Un upplet trabaja con animaciones cuando efectúa una presentación sucesiva de
imágenes, cada una con pequeñas diferencias con respecto a la anterior, dando así
la apariencia de movimiento. Estas applets, además de dibujar las imágenes,
deben poder responder a las acciones del usuario, por lo que las animaciones
deben ejecutarse como hilos independientes que no obstaculicen otras tareas y los
hilos deben detenerse cuando se sale de la página Web en la que reside el applet.
Para todas estas tareas:
El upplet implementará la interfaz Runnable, que se encargara de reali-
zar las tareas de dibujo. Por ejemplo:
public class Rebota extends Applet implements Runnable,
MouseListener
public void run ( )
i
. . .
. . .
repaint ( ) ;
. . .
Se sobreescribirán los métodos s t a r t y s t o p del applet con el código ade-
cuado para convertir en Ejecutables y Muertos los hilos que hayan podido
crearse. Por ejemplo:
public void start0
{
if (hilo == null)
i
hilo = new Thread( this ) ;
hilo.start 0;
En s t o p se asigna n u l l al/los hilo/s para que se puedan recolectar sus
recursos cuando se abandone la página Web en la que el applet reside.
Programación concurrente: Hilos de ejecución 327
Por ejemplo:
public void stop()
hiloctop ( ) ;
public void hiloctop ( )
ejecutable = false;
hilo = null;
Lógicamente, las animaciones pueden ser efectuadas por cualquier programa
Java con GUI, no es necesario que se trate de un applet.
Nota: No confunda los métodos start y stop de los hilos y de las upplets.
El método stop para hilos está obsoleto.
Recuerde: Las animaciones deben ejecutarse como hilos independientes para
que no obstaculicen la simultánea realización de otras tareas.
12.9. DOBLE BUFFER
Una técnica muy empleada en las animaciones con la finalidad de reducir el parpa-
deo es el doble buffer. Esta técnica permite que, mientras se presenta un imagen en
pantalla (primer bqfler), también puede tratarse de texto o gráficos, se pueda ir ela-
borando en memoria la imagen siguiente (segundo bqffer).El doble buffer requiere:
La creación de un objeto Image vacío, que actúa como buffer. El método a
emplear pertenece a la clase java .awt .Component:
public java,awt .Image createImage (int pl, int p2)
donde pi y p2 son la anchura y altura de la misma. Por ejemplo
imagen = createhage (ANCH0,ALTO ) ;
Obtener un contexto gráfico para dibujar la imagen en segundo plano, con el
siguiente método de la clase java .awt .Image:
public abstract java.awt.Graphice getGraphics0
328 Java 2. Manual de programación
Por ejemplo,
contextoGraf = imagen.getGraphicc0;
Mostrar el contenidodel buffer mediante drawImagede j ava.awt.Graphics
public abstract boolean drawImage(~ava.awt.Imagep l , i n t p2,
i n t p3, java.awt.image.Image0bserver p4)
en donde el primer parámetro es la imagen a dibujar, los dos siguientes son las
coordenadas para la esquina superior izquierda de la misma y el cuarto es el
observador. Por ejemplo,
g .arawimage ( imagen,O, O,t h i s ) ;
Pero tenga presente que drawImage tiene otros muchos formatos mediante
los cuales puede ser invocado.
Ejercicio
Pelota que rebota en los bordes de un upplet; su movimiento se puede detener y
reactivar efectuando clics con el ratón sobre en cualquier posición del mismo
(Fig. 12.1).
/ / Ejemplo de animación y doble buffer.
import ;ava.awt.*;
import java.awt.event.*;
import java.appiet.*;
p u b l i c class Rebota extends Applet implements Runnable,
MouceListener
{
public f i n a l i n t ANCHO = 2 0 0 ;
public f i n a l i n t ALTO = 100;
f i n a l i n t TMIN = 25;
i n t actual = TMIN;
i n t px = O ;
i n t p y = O ;
i n t dx = 1;
i n t dy = 1;
boolean e2ecutable = t r u e ;
Tsread hiio = n u l l ;
Image imagen;
Graphics contextoGraf;
public void init ( )
Programación concurrente: Hilos de ejecución 329
I
resize ( ANCH0,ALTO ) ;
/ * La pelota sale de una posición aleatoria e?. ;a p a r z e
superior del applet * /
int rango = ANCHO - TMIN;
px = (int) (Math.random0 * rango);
try
i
imagen = createImage (ANCH0,ALTO ) ;
contextoGraf = imagen.getSraphics0;
I
catch (Exception e)
t
contextoGraf = null;
1
addMouseListener(this);

public void start()
i
if (hilo == null)
i
hilo = new Thread( this ) ;
hilo.start ( ) ;
public void stop()
I
hilostop ( ) ;
I
public void run()
i
while (hilo ! = null)
I
if (ejecutable)
t
if ( px + actual > ANCHO I I px < 0)
if ( py + actual > ALTO 1 1 py < O)
dx *= -1;
dy *= -1;
px = px + dx;
PY = PY + dy;
t=Y
hilo.sleep( 10 ) ;
1
catch( Exception e )
i }
330 Java 2. Manual de programación
regaint ( 1 ;
niic = null;
public void hiloct.op ( )
ejecutable = false;
hilc = null;
public void hilosuspend()
elecutable = false;
public void hiloresume ( )
eJ ecurable = true;
public void update(Graghics g )
pairt( g ) ;
public void paint(Graphics g )
if ( ccptextosraf ! = null )
t
dibuja (contextcGraf ) ;
g.cirawIrnage(imagen,O, O, this ) ;
else
d i b u j a ( g ) ;
public void diCu 1a (Graphics g )
y.setColor (Color.gray);
g.filLRect (O,O,ANCEG,ALTG ) ;
g.setcoior ( C o l o r .red) ;
y.fil,Oval(px, py, acz,al, actua-);
public void mousePrecced (YouseEvent e)
if (ejecutable )
else
e ~ e c u ~ a b l e= !ejecutable;
hiloresume ( ) ;
hiloslspend ( 1 ;
Programación concurrente: Hilos de ejecución 331
1
public void rnouceReleaced(MouceEvent e)
{ I
public void mouseEntered (MonseEvent e)
1 1
public void rnouseExited (MouceEvent e)
t i
public void mouseclicked (MouseEvent e)
I }
Unas Últimas aclaraciones: en el ejemplo expuesto, el método run se encarga de
obtener la posición donde la pelota ha de ser dibujada, de forma que se consiga su
rebote en los bordes del applet, y manda que se redibuje. Cuando se presiona el
ratón, mousepressed detiene o activa alternativamente la ejecución del hilo.
El archivo Rebota.h t m creado es el siguiente:
Archivo HTML (Rebota.htm)
<HTML>
<HEAD>
</HEAD>
<BODY>
<applet
code=Rebota.clasc
name=Rebota
width=200
height=100 >
</ applet>
</BODY>
</HTML>
Applet started 1 Applet started I Applet started I~~ ____
Figura 12.1. Applet Viewer muestra Rebota,class.
Compilación
C:libroTemal2>javac Rebota.3 ava
332 Java 2. Manual de programación
Ejecucion con appietviewer
C:iibroTe~a12>appletviewerRebota.htm
Ejercicio
El siguiente applet que muestra el funcionamiento del método de ordenación deno-
minado método de la burbuja. Este applet presenta dos botones; uno permite la
generación de un nuevo array aleatorio de números enteros y el otro lanza un hilo
que efectúa la ordenación del mismo (Fig. 12.2). Cada número entero contenido en
el array se representa en su correspondiente posición mediante un gráfico de barras,
donde la altura de la barra se corresponde con el valor del número. El proceso de
ordenación aparece paso a paso, pudiéndose apreciar en cada momento los inter-
cambios que se van efectuando (Figs. 12.3 y 12.4).
Figura 12.2. Situación inicial
El applet diseñado es:
import java.awt.*;
import lava.awt.event.*;
import java.applet.*;
import java.util.*;
/ * Se utiliza la clase Random, perteneciente a java.uti1, para
la generación de números aleatorios * /
/ * Clase que permite la ordenación gráfica de un array de
enteros por el método de Burbuja * /
public class OrdenacionGrafica extends Applet implements
Act:onLis tener, RLInnab1e
Programación concurrente: Hilos de ejecución 333
/ / Variables generales
private s t a t i c i n t nurnelems = 100; //No de enteros
private s t a t i c i n t rango = 160; //Rango
private i n t [ ] arr0rd; //Array de ordenación
private Thread t = null; //Hilo de ordenación
private final i n t ANCHO = 640;
private final i n t ALTO = 400;
/ / Variables de proceso
private boolean ejecutable = true;
/ / Variables de gráfico
private static Color colordeBarra = Color.blue; //Color de barra
private static int AnchuradeBarra = 3; //Anchura
private static i n t yIni = 100 t rango; //Ordenada inicial
private static i n t xIni = 20; //Abscisa inicial
private static i n t xSep = AnchuradeBarra*2; //Ceparación x entre barras
private image imagen;
private Graphics contextoGraf;
/ / Paneles
Panel pl;
/ / Botones
Button nuevoArr;
Button nueva0rd;
/ / Constructor
public OrdenacionGrafica ( )
(
setLayout (new BorderLayout ( ) ) ;
pl = new Panel ( ) ;
/ / Configuración de panel
pl .setLayout (new FlowLayout ( ) ) ;
nuevoArr = new Button ("Nuevo array") ;
nuevaOrd = new Button ("Ordenar");
nuevoArr.addActionListener(this);
nuevaOrd.addActionListener(this);
pl .add (nuevoArr);
pl .add(nuevaOrd);
add ( " South",pl ) ;
/ / Generación inicial de array aleatorio
arrOrd = randomEntArray(nume1erns);
public void init ( )
I
resize ( ANCH0,ALTO ) ;
334 Java 2. Manual de programación
imagen = createImage(ANCH0,ALTO ) ;
contextoGraf = imagen.getGraphicc();
catch(Exception e)
contex2oGraf = null;
public void stop()
i
1
hilostop ( ) ;
public void paint(Graphics g )
if( contextoGraf ! = null )
t
dibuja (contextoGraf ) ;
g .drawImage (imagen,O O, this ) ;
else
. dibuja( g ) ;
public void update(Graphics g )
paint( g ) ;
1
public void dibuja (Graphics g)
g.setcolor (Color.gray);
g.fillRect (O,O,ANCHG,ALTO ) ;
for (int i = O; 1 < arrGrd.length; it+)
dibujaEnt(g, arrGrd[i], i);
/ * Control de Eventos.
Al pulsar el botón nuevoArr se genera un nuevo array y se
interrumpe cualquier ordenación que se estuviera llevando
a cabo.
Al pulsar el botón nuevaOrd comienza el proceso de ordena-
ción tras la creación de un nuevo array y no ocurre nada
si el array ya se estaba ordenando.
Una vez empezado el proceso de ordenación o se genera un
nuevo array o hay que esperar a que dicho proceso termine */
public void actionPerformed(ActionEvent e)
i
if (e.getCource0 == nuevoArr)
Programación concurrente: Hilos de ejecución 335
4,
if (t ! = null )
tilostop ( ) ;
arrOrd = r a n a o r n E n t A r r a y ( n u w e 1 e m s ) ;
repaint ( 1 ;
1
if (e.netsourre ( ) == nieva0rd)
if (t == null )
ejecutable = true;
t.start0;
t = new Thread( this 1 ;
I
public void hilostop ( )
ejecutable = false;
t = null;
/ / Birbuja
public void run ( )
i
while (t ! = null)
i
for (int i = 1; i < arr0rd.length & & ejecutable; it-)
for (int j = O; j < arr0rd.length-i & & ejecutable; J + + )
if (arrOrd[:+l] < arrOrd[jj & & e<ecutable)
int tr?p = arrOrd[jj ;
arr0rd [ j] = arrOrd:j+1];
arr3rd[J+l] = =nip;
repaint ( ) ;
t*Y
t
t.sleep (100);
i
catch(Exception e )
t }
}
t = null;
/ / Método para :a construcción de un array aleatorio de entezcs
public int[ ] randomEntArray (int N)
Random gen = new Random() ;
int[] a = new int:N] ;
for (int 1 = C; i < a.lenqth; i++)
a[i]=Math.abs (gen.nextInz():rango);
336 Java 2. Manual de programación
r e t u r n (a);
I
/ / Método para la representación de un entero en su posición i
public void dibujaEnt(Graphics g, i n t h, i n t i)
i n t x = xIni + i * xSep;
i n t y = yIni - h;
i n t w = AnchuradeBarra;
g.setColor(co1ordeBarra);
g.fillRect(x,y,w,h);
AOOlet starfeu I
Figura 12.3. Fase intermedia del proceso de ordenación, se observa cada intercambio.
Figura 12.4. Array ordenado.
Programación concurrente:Hilos de ejecución 337
El archivo Ord .h t m tiene el siguiente contenido:
Archivo HTML (Ord.htm)
<HTML>
<HEAD>
<TITLE>Proceso de ordenación en el método de la Burbuja</TITLE>
</HEAD>
<BODY>
<applet
code=OrdenacionGrafica.class
name=OrdenacionGrafica
width=640
height=400 >
</applet>
</BODY>
</HTML>
I
I
Maneio
de excepciones
CONTENIDO
13.1. Conceptos generales.
13.2. Manejo de excepciones.
13.3. Captura y tratamiento de excepciones.
13.4. Lanzar la excepción.
13.5. Declarar la excepción.
13.6. El bloque finally.
13.7. Creación de excepciones.
13.8. Métodos de la clase Throwable.
L 339
340 Java 2. Manual de programación
Las excepciones son objetos que describen y permiten controlar
errores y problemas inesperados en el funcionamiento de un pro-
grama sin oscurecer el diseño del mismo, y se manejan por un
código especial que no sigue el flujo normal de ejecución de dicho
programa. El compiladorobliga al manejode algunas excepciones,
mientras que para otras esto será potestativo del programa.Java,
además de proporcionar múltiples clases de excepciones, permite
crear nuevos tipos para que respondan a una anomalía en el fun-
cionamiento de un programa sobre la que los usuarios deban ser
informados. En este capítulo se explica la captura, tratamiento,
declaración, creación y lanzamiento de excepciones y se comen-
tará su importancia e inexcusable uso en algunas ocasiones, por
ejemplo en operaciones con archivos.
13.1. CONCEPTOS GENERALES
Todos los tipos de excepción son subclases de Throwable y, como se puede
observar en el esquema de la jerarquía de clases (Fig. 13.1), por debajo de
Throwable hay dos clases, Error y Exception,que dividen las excepcio-
nes en dos ramas distintas.
Las excepciones de la clase Error abarcan fallos graves de los que los pro-
gramas no pueden recuperarse y, por tanto, no suelen ser capturadas por los
mismos.
La clase Exception abarca las excepciones que los programas suelen captu-
rar; tiene varias subclases, entre las que destacan RuntimeException,
IOException e InterruptedException.
- RuntimeException comprende errores en tiempo de ejecución que se
producen al efectuar operaciones sobre datos que se encuentran en la memo-
ria de la computadora, se subdivide en diversas subclases entre las que
destacan ArithmeticException y NullPointerException,
ambas pertenecientes al paquete j ava .lang,como casi todas las
RuntimeException, y disponibles en todos los programas ya que este
paquete se importa automáticamente.
- IOException comprende los errores de entrada/salida y pertenece al
paquete j ava .io.
- InterruptedException,de cuyo tipo son los errores debidos a la
interrupción de un hilo de ejecución por otro,pertenece también a j ava.lang.
Manejo de excepciones 341
Además de disponer de todas estas clases, es posible extender la clase
Exception o sus subclases y crear nuevos tipos de excepciones que respondan a
una anomalía en el funcionamiento de un programa sobre la cual deben ser infor-
mados los usuarios, aunque hay que tener en cuenta que no es conveniente utilizar
las excepciones como un método alternativo para especificar flujo de control.
Importante: Todos los errores que se pueden originar en un método, excepto los
de tipo Error y RuntimeException,hay que declararlos en una cláusula
throws o bien capturarlos y tratarlos dentro de ese mismo método. Los proga-
mas no están obligados a capturar ni declarar las excepciones del tipo
RuntimeException.
Throwable
Error
Exception
InterruptedException
RuntimeException
ArithmeticException
IlLegalArgumentException
r--NumberFormatException
1- ~~ IndexOutOfBoundsException
I
StringlndexOutOfBoundsException ArraylndexOutOfBoundsException
...
NullPointerException
ILegalMonitorStateException
...-
- IOException
FileNotFoundException
, ...
EOFException
- AWTException
Figura 13.I . Excepciones,
342 Java 2. Manual de programación
Dada la obligatoriedad impuesta por el compilador con respecto a la captura
de algunas excepciones, hace ya tiempo que se viene utilizando código para la gestión
de las mismas y se ha visto ya que para capturar excepciones basta con escribir el códi-
-go que se quiere controlar en un bloque try y especificar la excepción que se desea
capturar en una cláusula catch.Así, si escribe el siguiente programa, el compilador
le obligará a modificarlo y capturar, de la forma especificada, la excepción
IOException que por la operación de lectura pudiera haber sido generada.
Ejemplo
El programa siguiente pide la introducción por teclado de un número entero, n,
comprendido entre 1y 2 O; a continuación, muestra las sucesivas potencias de 2
desde 2 elevado a 1 hasta 2 elevado a n .
import java.io.*;
public c l a s s E:emplo
//E:enplo 1.
public s t a t i c void main (String args [ ] )
InputStreamReader icr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(1sr);
String cadena;
i n t n = O ;
Syctem.out.print("Deme un numero entero entre 1 y 20 ' I ) ;
cadena = br.readLine();
n = Integer .parseInt(cadena);
i n t 1 = 1;
while (1 <= n)
System.out.println ("2""+i+" = "+Math.pow(2,i)) ;
it+;
Si lo modifica de la siguiente forma, el compilador lo aceptará y funcionará
correctamente cuando introduzca números enteros en el rango indicado, pero dará
una excepción si teclea una letra en lugar de un número o pulsa RETURN (INTRO) sin
introducir nada.
Ejemplo
import 3 ava .IC.* ;
public c l a s s Ejemplo2
Manejo de excepciones 343
public static void r a i n (CrrLrg args [ ] )
!
InputStreamReader isr = new InputStreamReaser(Cys=em.;n);
BufferedReader br = new BufferedReader(icr);
/ * se hace necesaria la inicialización de la cadena,
debido a que las instrucciones en el CLoque try pasria?.
no ser ejecutadas,pero seria igual in2cializarla a " I '
* /
String cadena = "C";
int n;
System.out .print("Deme un número entero entre 1 y 2C " ) ;
t=Y
I
cadena = br .readLine ( ) ;
1
catch (IOException e)
t }
n = 1nteger.parseInt (cadena);
int i = 1;
while (i <= n)
System.out.println("2^"+i+" = "+Math.pow(2,i)) ;
Iff;
I
I
I
importante: No se puede garantizar que las sentencias siguientes a un deter-
minado catch vayan a ser ejecutadas.
13.2. MANEJO DE EXCEPCIONES
Las operaciones que se pueden realizar con excepciones son: captura y tratamiento
(manejo), lanzamiento y declaración.
13.3. CAPTURA Y TRATAMIENTO DE EXCEPCIONES
Para capturar una excepción, se escribe el código que se quiere controlar en un blo-
que t r y ; se especifica la excepción que se desea capturar en una cláusula catch y
se coloca el tratamiento para la misma en el bloque catch. La cláusula catch con-
siste en la palabra reservada catch, seguida por el tipo de excepción que se desea
capturar y un nombre de parámetro encerrados entre paréntesis. El conjunto
try/catch no se puede separar con sentencias intermedias.
344 Java 2. Manual de programación
No se debe colocar una estructura try/catch para cada una de las instruccio-
nes de un programa que pueda lanzar una excepción, sino agrupar las que estén rela-
cionadas en un único bloque try.En estos casos, es decir, cuando las sentencias
encerradas en un bloque try pueden producir más de una excepción, es posible
poner varias cláusulas catch consecutivas; permite efectuar un tratamiento distin-
to para cada una de las excepciones. La búsqueda de la excepción originada se efec-
tuará secuencialmente en cada una de las claúsulas catch,por tanto no se debe
colocar una claúsula catch que capture excepciones de una superclase antes de
otra que capture las de una de sus subclases.
Ejemplo
Modificar el ejercicio de las potencias de modo que no se produzca una interrupción
si se teclea una letra en lugar de un número o se pulsa RETURN (INTRO) sin introdu-
cir nada.
import java.io.*;
public class E j emplo3
public s t a t i c void main (String args[])
InputCtreamReader icr = new InputStreamReader(System.in);
BcfferedReader b r = new BufferedReader (isr);
i n t n = O ;
System.out.print("Deme un número entero entre 1 y 20 " ) ;
t r y
i
String cadena = br.readLine ( ) ;
n = Integer .parseInt(cadena);
catch ( IOException e)
{//tratamiento 1
1
catch (NurnberFormatException e)
{//tratamiento 2
i n t i = 1;
while (i <= n)
System.out .println( " 2 ^ " + 1 + " = "tMath.pow(2,i)) ;
it+;
Otra posibilidad para resolver este problema de las múltiples excepciones gene-
radas en un bloque try,es utilizar una claúsula catch que capture excepciones de
Manejo de excepciones 345
una superclase que englobe todos los tipos de excepciones que, por las instruccio-
nes incluidas en try,pueden ser generadas y utilizar instanceof para determi-
nar el tipo de excepción.
Ejemplo
Dado que la clase Exception engloba las excepciones a considerar en los ejem-
plos I a 3 ya explicados, para capturar las citadas excepciones IOException y
NumberFormatException podría escribirse el código de la siguiente manera:
import java.io.*;
public c l a s s Ejemplo4
t
public s t a t i c void main (String args [I )
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader (isr);
String cadena;
i n t n = O;
System.out.print("Deme un número entero entre 1 y 20 " ) ;
t=Y
t
cadena = br .readLine ( ) ;
n = Integer.parseInt(cadena);
1
catch (Exception e)
i
if (e instanceof IOException)
else if (e instanceof NumberFormatException)
System.out .printin("Error de entrada/calida") ;
System.out .println("No tecleó un número entero");
1
i n t i = 1;
while (i <= n)
i
System.out.printin("2^"+i+" = "+Math.pow (2,i)) ;
i++;
1
13.4. LANZAR LA EXCEPCIÓN
Una claúsula catch puede recibir una excepción y, en lugar de tratarla o después
de hacerlo, volver a lanzarla mediante una instrucción throw.
346 Java 2. Manual de programación
Ejemplo
Modificando levemente el ejemplo anterior, puede utilizarse también en el presen-
te caso. La modificación consiste en la creación de un método de lectura que, des-
pues de su tratamiento, lanza la excepción NumberFormatException.
import java.io.*;
public class Ejemplo5
t
public static int leer ( )
i
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(1sr);
String cadena = I"';
int n = O;
try
i
cadena = br.readLine ( ) ;
n = 1nteger.parseInt (cadena);
1
catch (IOException e)
{ )
catch(NumberFormatException e)
i
System.out.println("1) ¿Tecleó solo return?");
throw (e);
1
return n;
1
public static void main (String args [ ] )
i
int n = O;
System.out.print("Deme un número entero entre 1 y 20 ' I ) ;
try
{
n = leer ( ) ;
catch(NumberFormatException e)
System.out.println( " 2 ) ¿Tecleó una letra o un real?");
1
int i = 1;
while (i <= n)
i
System.out .println("2A"+it"= "+Math.pow(2,i)) ;
i++;
1
1
1
Manejo de excepciones 347
13.5. DECLARAR LA EXCEPCIÓN
Las excepciones pueden no ser tratadas (manejadas), posponiendo su tratamiento
para que sea efectuado por el método llamador, pero cuando no pertenecen a la clase
RuntimeExcepti o n , es necesario listar los tipos de excepciones que se pasan en
la cabecera del método. En general las excepciones R u n t imeExcept ion deben
capturarse en el método donde se han producido; en caso contrario serán tratadas
por el bloque t r y del método invocador más próximo que capture dicha excepción
y sin necesidad de ser listadas en la cabecera del método.
Ejemplo
En este caso leer no efectúa ningún tratamiento y, como se puede observar, se
hace necesario listar la IOExceptionen la cabecera del método.
import java.io.*;
public class Ejemplo6
public static int leer ( ) throws IOException
I
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String cadena = "";
try
t
cadena = br .readLine ( ) ;
return Integer.parseInt(cadena);
1
finally
t i
1
public static void main (String argstl)
i
int n = O;
System.out.print("Deme un número entero entre 1 y 20 ' I ) ;
I
try
n = leer ( ) ;
1
catch (IOException e)
i }
catch (NumberFormatException e)
i
1
int i=l;
while (i <= n)
System.out .println("¿Tecleó solo return?");
348 Java 2.Manual de programación
SyStem.out.println ("2""+i+" = "+Math.pow(2,i)) ;
i++;
Hay que tener en cuenta que el bloque try no puede aparecer sólo, por lo que,
al no ser necesario ninguna claúsula catch,se ha de colocar una cláusula y bloque
finally.
f i n a l l y
I }
13.6. EL BLOQUE finally
Cuando no se produce ninguna excepción en un método y también cuando se pro-
duce pero es capturada, la ejecución continúa en la sentencia siguiente a catch,
excepto si se fuerza a otro tipo de abandono mediante instrucciones como return,
break o continue.Cuando la excepción no se captura, la búsqueda de la claúsu-
la catch adecuada para la captura de la excepción lanzada continúa por los restan-
tes métodos en orden inverso a como fueron efectuadas las llamadas. Por tanto, no
se puede garantizar que las sentencias siguientes a un determinado catch vayan a
ser ejecutadas.
Ejemplo
Compare los siguientes códigos. En el primer caso, las instrucciones Siguientes a los
catch se ejecutan Únicamente si ocurre una excepción. En el segundo caso, por las
instrucciones siguientes a los catch en el método leer no pasa ni cuando todo es
correcto ni cuando se produce una NumberFormatException.
import java.io.*;
public c l a s s Ejemplo7
t
public s t a t i c i n t leer ( )
i
InputStreamReader isr = new InputCtreamReader(System.in);
BufferedReader br = new BufferedReader(1sr);
String cadena = " ' I ;
try
cadena = br .readLine ( ) ;
return Integer.parseInt(cadena);
Manejo de excepciones 349
//cuando todo es correcto sale
1
catch (IOException e)
o
catch (NumberFormatException e)
i i
/ / Instrucción siguiente a catch
System.out .println("Pasa solo cuando ocurre excepción") ;
return O;
public s t a t i c void main (String args [ I )
i
i n t n = 0;
System.out.print ("Deme un número entero entre 1 y 20 ' I ) ;
n = leer ( ) ;
i n t i=l;
while (i <= n)
f
System.out.println ("2""+i+" = "+Math.pow(2,i));
it+;
1
import java.io.*;
public c l a s s Ejemplo8
t
public s t a t i c i n t leer()
i
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader (isr);
String cadena = "";
try
I
cadena = br.readLine ( ) ;
return Integer.parseInt(cadena);
1
catch (IOException e)
I 1
/ / Instrucción siguiente a catch
System.out.println("No pasa cuando no hay error ni" +
return O;
"cuando seproduceunNumberFormatException");
public s t a t i c void main (String args[])
I
350 Java 2. Manual de programación
int n = O;
System.out.print("Deme un número entero entre 1 y 20 " ) ;
t=Y
i
1
catch(NumberFormatException e)
I }
int i = 1;
while (i <= n)
i
n = leer ( ) ;
S y s t e m . o u t . p r i n t l n ( " 2 ^ " + i + " = "+Math.pow(2,i)) ;
i++;
1
1
I
Nota: El bloque finally sirvepara colocar en él instruccionesque se desea
se realicen siempre que se sale de un bloque t r y y es opcional, pero pasa a
ser obligatorio cuando un bloque t r y no va seguido por ninguna claúsula
catch ya que, como se dijo, el bloque t r y no puede aparecer solo.
El formato general es:
try
1
}
catch(Tipo-de-excepcion identificador)
i
1
//otros catch si los hubiera
finally
{
1
...
. . .
...
Las instrucciones colocadas en el bloque f i n a l l y se realizan siempre que se
sale del bloque t r y : tanto si se ha producido una excepción y se ha capturado,
como si no se ha capturado, como si no se ha producido la excepción, como si se
ha salido del bloque t r y con r e t u r n , b r e a k o c o n t i n u e . No resulta, pues,
adecuado poner en un bloque f i n a l l y sentencias que a su vez puedan produ-
cir nuevas excepciones.
Manejo de excepciones 351
Ejemplo
Aunque el tratamiento de archivos se verá en el capítulo siguiente, dado que el
tnanejo de excepciones es muy importante en el trabajo con archivos, se muestra a
continuación el control de excepciones en un programa diseñado para comparar dos
archivos especificados mediante la línea de órdenes. Para comprender la imple-
mentación efectuada se necesita conocer que los argumentos pasados en la línea de
órdenes a un programa se reciben por el método main y se almacenan en el array
unidimensional de tipo string que dicho método especifica siempre como pará-
metro.
public static void main (String args [ I )
Los argumentos escritos a continuación del nombre del programa se separan
unos de otros por un espacio en blanco y Java almacenará el primero de ellos en
args [ O ] ,el segundo en args [ 1] ,y así sucesivamente. El programa compara los
archivos, efectuando una lectura secuencia1 de ambos y comprobando la igualdad
entre lo que va leyendo de cada uno de ellos. Se detiene cuando encuentra alguna
diferencia o uno de los archivos termina.
La claúsula t r y inicial prueba de forma agrupada diversas excepciones que se
pueden producir en el programa. No obstante, en el caso de que la excepción sea
generada por no encontrarse el archivo, conviene identificar cuál de los dos archi-
vos pasados como parámetros es el que no ha sido encontrado, por tanto se colo-
can dentro del try anterior otros dos bloques t r y que permitan identificar cuál
de ellos ha sido la causa. La instrucción de cierre de archivo debe aparecer en el
boque finallypara que siempre sea ejecutada y como lanza una IOException
ésta vuelve a ser capturada. La llamada al programa debe efectuarse de la siguien-
te forma:
C:libroTemal3>java CompArch a.txt b.txt
Una llamada sin parámetros produce la salida siguiente:
C:libroTemal3>java CompArch
La llamada debe ser: java CompArch archivo1 archivo2
Otros casos considerados son aquellos en los que alguno o ambos archivos no
existen.
import java.io.*;
class CompArch
I
352 Java 2. Manual de programación
public static void main (String args [ ] )
l
int i = O, j = O;
FileInputStream fl = nuii;
FileInputCtream f2 = null;
try
t
/ / Abre el primer archivo
try
i
//Excepción por apertura del archivo
fl = new FileInputCtream(args [O]) ;
1
c a t c h ( F i 1 e N o t F o u n d E x c e p t i o n e)
t
1
Cystem.out.println(args[O] + 'I Archivo no encontrado") ;
/ / Abre el segundo archivo
try
I
f2 = new FileInputCtream(argc[11) ;
catch(Fi1eNotFoundException e)
I
System.out.println (args[l] + " Archivo no encontrado");
i
/ / Compara los archivos
do
t
/*Las excepciones generadas en la lectura se capturan
i = fl.read0;
j = f2.readO;
if (i ! = j) break;
por el try externo * /
I
while(i ! = -1 & & j ! = -1); / / fin de archivo
if(i ! = j)
else
System.out.print1n ("Los archivos son diferentes.") ;
System.out.println("Los archivos son iguales.' I ) ;
i
catch (IOException e)
t
System.out.println("Error");
Manejo de excepciones 353
I
c a t c h ( A r r a y I n d e x O u t 0 f B o u n d s E x c e p t i o n e)
i
Cystem.out.println ("La llamada debe ser: "+
"java CompArch archivo1 archivo2");
1
catch(Exception e)
I
}
finally
i
/ / ]ava.lang.NullPointerException
try
i
/ * el cierre de a r c h i v o no debe colocarse en el
anterior bloque try pues pudiera no ejecutarse.
La operación de cierre lanza una excepción que hay
que tratar * /
if (fl ! = null)
fl .close0;
catch ( IOException e)
i
1
try
t
if (f2 ! = null)
f2.closeO;
1
catch ( IOException e)
t }
I
Nota: Los argumentos pasados en línea de comandos a un programa se reci-
ben por el método main y se almacenan en el array unidimensional de tipo
String que dicho método especifica siempre como parámetro. Cuando se
llama al programa sin parámetros, la posterior referencia a losmismos origina
una excepción del tipo Array IndexOutOfBoundsException.
13.7. CREACIÓN DE EXCEPCIONES
En Java es posible definir nuevas excepciones específicas para una determinada situa-
ción, que se usarán para detectar anomalías en el funcionamiento de una aplicación.
354 Java 2. Manual de programación
Para crear una excepción se define una subclase de Exception que implemente
un constructor con un parámetro de tipo String y sobreescriba el método
getMecsage ( ) de la clase Throwable. Hay que tener en cuenta que la clase
Exception no define ningún método, sólo hereda los definidos por Throwable.
Ejemplo
Creación de una nueva excepción.
c l a s s NuevaExcp extends Exception
!
String mensaje;
public NuevaExcp (String causa)
i
I
mensaje = causa;
public String getMessage ( )
return mensaje;
Para usar la nueva excepción la aplicación creará y lanzará un objeto de ese tipo
cuando se cumpla una determinada condición. Como en cualquier otro caso, la
excepción deberá ser capturada o declarada escribiendo su tipo en la cabecera del
método que la lanza precedido por la palabra reservada throws.Si se lanza desde
main el tratamiento no se podrá posponer y habrá que capturarla.
Ejemplo
Esta aplicación que usa la nueva excepción (NuevaExcp).La excepción se lanza
y captura en main.El ejemplo lanza la excepción siempre, aunque lo normal sería
que ésta sólo se lanzara cuando ocurriera algún motivo.
public c l a s s Ejemplo9
i
public s t a t i c void main (String[ I argc)
i
try
i
/ / se lanza siempre
throw new NuevaExcp("C1n motivo");
I
catch (NuevaExcp e)
Manejo de excepciones 355
System.out.println(e.getMessage0);
El programa siguiente solicita la edad y, si no está en el rango adecuado, lanza
una excepción.
import java.io.*;
public c l a s s Ejemplo10
public s t a t i c void main (String args[])
i
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String cadena;
i n t edad = O;
System.out.print ("Introduzca la edad " ) ;
try
I
cadena = br .readLine ( ) ;
edad = Integer.parseInt(cadena);
i f (edad < 18 1 1 edad > 65)
throw new FueraDeRango("ExcepciÓn: valor fuera de rango");
System.out .println("Edad: " + edad);
catch (Exception e)
i f (e instanceof IOException)
else i f (e instanceof NumberFormatException)
else
System.out .println("Error de entrada/salida") ;
System.out .println("No tecleó un número entero");
System.out.println(e.getMessage()) ;
c l a s s FueraDeRango extends Exception
I
String mensaje;
public FueraDeRango (String causa)
i
1
public String getMessage ( )
i
I
mensaje = causa;
return mensaje;
i
356 Java 2. Manual de programación
Ejemplo
El problema de las Torres de Hanoi es un problema clásico de recursión. Se tienen tres
torres y un conjunto de discos de diferentes tamaños. Cada disco tiene una perfora-
ción en el centro que le permite ensartarse en cualquiera de las torres. Los discos
han de encontrarse siempre situados en alguna de las torres. Inicialmente todos
están en la misma torre, ordenados de mayor a menor, como se muestra en el dibu-
jo. Se debe averiguar los movimientos necesarios para pasar todos los discos a otra
torre, utilizando la tercera como auxiliar y cumpliendo las siguientes reglas:
En cada movimiento sólo puede intervenir un disco. Origen Destino Auxiliar
2 3No puede quedar un disco sobre otro de menor tamaño. ’
El problema se puede resolver considerando que para pasar, por ejemplo, tres
discos del pivote origen al destino, han de pasar dos discos al pivote auxiliar, mover
uno al destino y mover dos discos del auxiliar al destino.
Paso 7
1 Orinen Destino Auxiliar
Paso 3-~
Paso 2
-~~
Oriqen Destino AuxGr-T Oriqen Destino Auxiliar
El paso 1, vulnera la primera regla, pero para solucionarlo, podemos recurrir a
la misma mecánica: movemos un disco de origen a destino, movemos el siguiente
al auxiliar y, por último movemos el disco de destino a auxiliar.
Fases del Paso 1
1 Origen Destino Auxiliar 1 Origen Destino Auxiliar ~ Origen Destino Auxiliar
Lo mismo ocurriría con el paso 3 y se solucionaría de la misma forma.
Se creara la clase Hanoi para resolver el problema. En esta clase el método
movsTorre lanza una NuevaExcp si el número de discos es negativo. El método
Manejo de excepciones 357
m a i n de la clase PruebaH captura y trata las excepciones; vuelve a pedir el núme-
ro de discos cuando éste fue negativo y ante cualquier otro tipo de excepción, como
introducir una letra en lugar de un número, el programa termina.
public class Hanoi
private s t a t i c void movsTorre ( i n t ndiscos, i n t origen, i n t
destino, i n t auxiliar) throws NuevaExcp
i
//Control Excepciones
i f (ndiscos < O)
i f (ndiscos == O)
i f (ndiscos == 1)
else
throw new NuevaExcp ("Numero de discos incorrecto") ;
return ;
System.out.println("Paso disco de "+origen+" a "tuestino);
movsTorre(ndiscos-1, origen, auxiliar, destino);
Cystem.out.println("Paso disco de " + origen t " a 'I +
destino) ;
movsTorre(ndiscos-1, auxiliar, destino, origen);
public Hanoi ( i n t n)throws NuevaExcp
i
System.out.println("Bienvenidoa las torres del fin del munao");
Cystem.out .println("Movimientos: "+ ( i n t )(Math.pow(2,n)-1)) ;
Cystem.out .println("Listado: " ) ;
movsTorre(n, 1, 2, 3);
/ / esta clase ya ha sido comentada
c l a s s NuevaExcp extends Exception
i
String mensaje;
public NuevaExcp (String causa)
I
mensaje = causa;
i
public String getMecsage ( )
I
return mensaje;
358 Java 2. Manual de programación
import java.io.*;
public class PruebaH
I
public static void main (String[] args)
i
int n = O;
boolean repetir = false;
do
t
try
I
repetir = false;
System.out.println("Introduzca número de discos:") ;
InputStreamReader isr = new
InputCtreamReader(System.in);
BufferedReader br = new BufferedReader (isr);
n = Integer .parseInt(br.readLine ( ) ) ;
Hanoi h = new Hanoi(n);
1
catch (NuevaExcp el)
t
System.out .println("tEl número de discos no puede "+
"ser negativo") ;
repetir = true;
1
catch (IOException e2)
{
1
catch (Exception e3)
i
1
System.err.println ("Error de lectura");
System.err.println (e3);
1
while (repetir);
1
13.8. MÉTODOS DE LA CLASE Throwable
public java.lang.Throwable fillInCtackTrace()
Devuelve un objeto con los métodos en ejecución en el momento de lanzarse la excepción.
public java.lang.String getMessage0
Devuelve el mensaje descriptivo almacenado en una excepción.
Manejo de excepciones 359
public void printCtackTrace()
Muestra por consola un mensaje con la clase de excepción, el mensaje descriptivo de la
misma y una lista con los métodos en ejecución en el momento de lanzarse la excepción.
public void printStackTrace(java.io.PrintStream p l )
Envía el mensaje anteriormente especificado al flujo que se le especifique como parámetro.
public java.lang.String tostring()
Devuelve una cadena descriptora de la excepción.
D I iI I i l l 111
I
I
Arch¡vos
CONTENIDO
14.1. La clase File.
14.2. Flujos.
14.3. Apertura de archivos.
14.4. Encadenamiento de flujos
14.5. Excepciones en archivos.
14.6. Métodos de Inputstream.
14.7. Métodos de Outputstream.
14.8. Métodos de Reader.
14.9. Métodos de Writer.
14.10.
14.11.
14.12.
14.13.
14.14.
14.15.
14.16.
14.17.
14.18.
Métodos de DataInputstream.
Métodos de Dataoutputstream.
Métodos de RandomAccessFile.
Serialización de objetos.
StringTokenizer y StreamTokenizer.
Operaciones con archivos y mantenimiento
de los mismos.
Archivos secuenciales.
Archivos directos.
Funciones de transformación de clave
y tratamiento de colisiones.
361
362 Java 2. Manual de programación
Como estructura de datos, los archivos permiten el almacena-
miento permanente y la manipulación de un gran número de
datos. Los archivos de datos son un conjunto de datos estructura-
dos que se tratan como una unidad y se encuentran almacenados
en un dispositivo de almacenamiento externo. Un archivo se con-
sidera formado por una colección de datos lógicamente relaciona-
dos, a los que denominaremos registros, cada registro agrupa
datos también con una relación lógica entre sí a los que se deno-
mina campos y es el programador el encargado de estructurar los
archivos de tal forma que se adapten a las necesidades del pro-
grama ya que, en realidad, Java considera los archivos simple-
mente como flujos secuenciales de bytes.
En los archivos de datos se pueden destacar dos organizaciones
fundamentales: secuencia/y la directa o aleatoria, siendo posible
trabajar en Java con ambos tipos de organizaciones. La organi-
zación secuencia/implica que los datos se almacenan consecu-
tivamente en el soporte externo, no siendo posible acceder
directamente a un determinado dato si no se recorren todos los
anteriores. La organización directa permite el posicionamiento
directo en un determinado lugar de un archivo para leer la informa-
ción allí almacenada y no obliga al almacenamientode la misma en
forma secuencial.Además, a diferencia de la secuencial, la organi-
zación directa permite modificar un dato previamente almacenado,
eliminarlo o insertar uno nuevo en cualquier posicióndel archivo sin
que sea necesario efectuar una copia de todo el archivo cada vez
que se realizauna de estas operaciones.En el presentecapítulo, se
explicará el concepto de fhjo y se mostrará cómo estructurar los
datos e implementar en Java ambos tipos de organizaciones.
14.1. LA CLASE F i l e
Los objetos de la clase File no especifican cómo se almacena o recupera la infor-
mación en un archivo, sólo describen las propiedades del mismo y permiten obte-
ner información sobre él.
Nota: Un objeto de la clase File posibilita la obtención de información sobre
las propiedades tanto de un archivo como de un subdirectorio y permite la
modificación de algunos de sus atributos. Los métodos delete y
renameTo de la clase File permiten borrar y renombrar archivos.
Los objetos File se crean mediante los siguientes constructores:
Archivos 363
public File (java.io.Fiie dir, java.lang.Ctring nombre)
Donde el primer parámetro es un objeto File que referencia un directorio y el segundo el
nombre del archivo.
public File ( 7 ava .lang .String path)
El parámetro es el nombre de un directorio o bien el nombre completo, incluyendo ruta de
acceso, de un archivo.
public Fiie(java.lang.String path, java.1ang.Ctring nombre)
Donde el primer parámetro es el nombre del directorio y el segundo el nombre del archivo.
Ejemplos
//ruta relativa, el directorio actual
File arch = new File ("ejemplo.dat");
/ * ruta absoluta, en ei siguiente caso especifica el directo-
rio raiz en Windows que utiliza un separador (  ) distir.-
to de ünix ( / ) * /
File arch = new File ( "   ' I , "ejemplo.dat");
/ * es posible utilizar en una versión Windows de Java el ca-
File arch = new File("/","e]emplo.dat") ;
rácter/ como separador * /
Métodos y campos a destacar dentro de la clase son:
public static final char separatorchar
public java.lang.String getName0
public 1ava.lang.Ctring getparento
public java.lang.String getAbsolutePath()
public java.lang.String getpath()
public boolean canwrite 0
Variable inicializada co'n el
separador indicado en el archi-
vo de propiedades del sistema
que permite especificar rutas
independientes de la plataforma.
Devuelve el nombre del archivo
referenciado por el objeto.
Devuelve el nombre del direc-
torio padre.
Devuelve la ruta absoluta del
archivo.
Devuelve la ruta relativa.
Devuelve true si se puede
escribir en el archivo o directo-
rio.
public boolean canRead() Devuelve true si se puede leer
desde el archivo o directorio.
364 Java 2. Manual de Programación
public boolean i s F i l e ( 1
public boolean : s D i r e c t o r y ( )
public ;ava.lang.String[] l i s t ( )
public boolean m k d i r ( )
public boolean d e l e r e ( )
I>euclvetrue si el archivo re-
presentado por el objeto F i l e es
un archivo normal.
Devuelve t r u e si el archibo
representado por el objeto ?i 10
es un directorio.
Devuelve un array con los nom-
bres de los archivos y directo-
rios existentes en el directorio
especificado por el objeto F i l e .
Esta lista no incluye el directo-
rio actual ni el padre del actual.
Crea el directorio especificado
por el objeto F i l e .
Borra el objeto 0 1 ~ ecspecifica-
do, cuando se trate de un direc-
torio cste ha de estar vacio
public boolean renar?eTo (java.i o . F i l e dect) lienombra el archivo especifi-
cado por el objcto F i l e con el
nombre del archivo File pasado
como parámctro y devuelve
t r u e cuando la operación se
efectúa con éxito y f a l c e si se
intenta renoinbrar un archivo
cambiándolo de directorio.
public boolean e x i s t s ( )
Ejercicio
Mostrar el contenido de un subdirectorio.
Detielbe t r u e si existe el
ob.jeto F i l e especificado y
f a l c e en caso contrario.
Figura 14.1. Listado del contenido de un subdirectorio
7
Archivos 365
import java.io.*;
public class Listado
t
public static String l e e r ( )
InputStrearnReader isr = new I n p u t C t r e a m R e a d e r ( S y 3 t e - . - n ) ;
BufferedReader br = new EufferedReader(1sr);
try
return br.readLine0;
i
catch(Excepticn e)
t i
return I"';
1
public static void main (Strin,-[] a r g s j
Systern.out.println("Indique nombre de cubdirecEoris");
System.out .println("Trayectoria absoluta, ej : C::.icrcj") ;
String nomdir = leer();
File arch = new File(norndir);
if (arch.exictc( 1 j
if (arch.isnirectory ( ) )
{
Systern.out.println ("iontenibo de "Tnom5:r) ;
String arr[j = arch.list0;
for(int J = 3; j < arr.length; I++)
I
File otro = new File(nomdir + ""+arr[]]);
if ( o t r o . isDirectory ( 1 )
else
System.out .println(arr[j] + " < f i R > " j ;
Systen.out.printic(arr[jl);
else
System.out .println(r~omdirA"no es un directorio") ;
else
Cyster..out.println("No existe");
1
Ejercicio
i
I
Utilice AWT para efectuar la misma tarea que el ejercicio anterior y defina una clase
anónima para el cierre de la ventana.
366 Java 2. Mar ual de Programación
-i-i
LEkr LE
Figura 14.2. Listado del contenido de un subdirectorio. Pantalla inicial.
Contenidci de c libro A
Temaül qCilR5
Tema1 1 <[)IR-
_.
1
Figura 14.3. Listado del contenido de un subdirectorio.
import java.awt.*;
import java.awt.even:.*;
import java.io.*;
public class EjFile extends Frame implements ActionListener
TextField textoi;
TextArea texto2;
public EjFile ( )
cet¿ayoct (new BorderLayout ( ) ) ;
//empleo de Ena clase anónima
Archivos 367
aadWindow;istep.er (new WindowAdopter ( )
t
public void windowclosing (WinCc,dEver.te)
System.exit (3);
I
1 ) ;
textol = new TextField ("Introduzca en esze -,gar"-
textol.selectAll ( 1 ;
add ("North",textolj ;
textol.addActionListener(this);
texto2 = new TextArea 0;
add ("Center", texto2) ;
"el novbre ae un sundirectorio", 55);
public void actionPerformed(ActionEveKt e )
I
File arch = new File (textol.getText( ) ) ;
if (arch.exists( ) )
if (arch.isDirectory ( ) )
texto2.append ("Contenido de " + arch t "n");
String arr [ ] = arch.list ( ) ;
for(int J = O; j < arr.length; jc+)
i
File otro = new File,(arch+ "   " f arr [j]j ;
if (otro.2sDirectory ( ) 1
texto2 .append(arr[ j1 + 'I <CIX>" - "F.");
else
texto2.append (arr[ J ] + "n");
I
I
else
texto2.append (e.tostring ( ) - " nc es cc direitsri3");
else
texto2.append (e.tostring (j + " n3 existe");
public static void main( String args[] )
EjFile vt = new EjFileO;
vt.setTitle ( "Ejemplo FILS" ) ;
vt.setSize( 400,250 ) ;
vt.setVisibie(truej;
368 Java 2. Manual de Programación
14.2. FLUJOS
Los programas en Java realizan las operaciones de entrada/salida a través de,flu-
jos; así se consigue gestionar de forma similar la entrada/salida sobre dispositi-
vos muy diferentes, como teclado, pantalla, impresora, una conexión a red, un
bz@r en memoria o un archivo en el disco. A diferencia de la pantalla, la impre-
sora no tiene definido en Java un flujo de salida estándar y para sacar por impre-
sora los resultados de un programa hay que asociar un flujo al puerto (LPT1, ...)
donde esté conectada. Las diferentes clases de flujos se encuentran agrupadas en
el paquete java .io y en la parte superior de esta jerarquía destacan las clases:
Inputstream,Outputstream, Reader, Writery RandomAccessFile.
Figura 14.4. Clases de flujos que heredan de Object.
inputstream es una clase abstracta, superclase de otras concretas que tratan
con flujos de entrada de bytes, mientras que Outputstream es la clase abstracta
superclase de otras que representan un flujo de salida de bytes. Estas clases definen,
pues, la funcionalidad básica común a todas las clases de flujo de bytes. Vea la
Figura 14.5. Writer es una clase abstracta para escribir caracteres en flujos y
Reader la clase abstracta cuyas subclases podrán leerlos (Fig. 14.6.).
Cuando se trabaja con Reader o Writer el flujo se orienta a Unicode (16 bits)
y con Stream a bytes (8 bits). Las clases Stream,en gran parte, se consideran
obsoletas, ya que Java usa Unicodey tiene más sentido usar Reader/Writer que
trabajar con byres, donde Java tiene que traducir los bytes en Unicode para impri-
mirlos y de vuelta en Unicode cuando los lee.
Por otra parte, en adición a Stream,Reader y Writer,el paquete java.io
define la clase RandomAccessFile que permite implementar archivos de acce-
so directo.
Archivos 369
Figura 14.5. Inputstream y Outputstream,jerarquía de clases.
370 Java 2. Manual de Programación
Reader
I
Figura 14.6. Reader y Writer, jerarquía de clases.
14.3. APERTURA DE ARCHIVOS
Para crear, escribir o leer un archivo se requiere establecer un flujo a/desde él; las
clases capaces de crear un flujo aidesde un archivo requieren una referencia a un
objeto File o un nombre de archivo como argumento. Estas clases son:
La subclase FileOutputCtream hereda de OutputCtream y permite
crear un flujo de salida para escribir bytes en un archivo. Los constructores
son:
public FileOurputCtream(java.lang.String nombre).
public FileOctputCtream (java.io.File file)
/ / f i l e es un objeto F i l e
public FiLeCutputCtream (java.lang.Ctr;ng nombre, boolean
a ñ a d i r ) .
Archivos 371
Los tres constructores lanzan excepción. Con los dos primeros si el archivo
existe y se abre de esta forma, se destruye. El último constructor permite aña-
dir datos a un archivo existente, cuyo nombre viene especificado por nombre.
Ejemplo
Fileoutputstream f1 = n e w FileOutputCtream ("info.txt");
o bien
File arch = n e w File("ejemplo.da~"j;
Fileoutputstream f2 = n e w FileOutputStream (arch);
Un flujo debe cerrarse cuando ya no vaya a utilizarse con las sentencias sufi-
cientes:
fl.close0;
f 2 .close ( j ;
La subclase FileInputStream hereda de Inputstream y permite crear
un flujo para lectura de bytes desde un archivo. La lectura comienza desde el
principio del archivo y cuando se leen datos del mismo, para que se puedan
volver a leer los datos del principio es necesario cerrar el flujo y volverlo a
abrir. Los constructores son:
public FileInputStream(]ava.ic.File f i l e )
public FileInputCtream(java.lang.String nombre)
Ambos constructores lanzan una FileNotFoundException
Ejemplo
FileInputStream fl = n e w FileInputStream("notas. txt");
o bien
File arch = n e w File ("e]emplo.txt"j ;
FileInputStream f2 = n e w FiLeInputStream(arch);
El flujo se cierra de modo similar al caso anterior.
Filewriter hereda de Writer y proporciona la posibilidad de crear un
flujo para escritura de caracteres en un archivo. Los constructores son:
372 Java 2. Manual de Programación
public FiieWriter(java.1o.F
public FileWriter (]ava.lang
public F-leWr-ter (7ava.lar.g
le f i l e )
String nombre)
String nombre, boolean añadir)
y lanzan una IOException.Los dos primeros constructores destruyen una
archivo existente; el último permite añadir datos al final del mismo.
Ejemplo
FlieWrlter fe new FileWriter ("info.txt");
fe.:lose ( ) ;
. . .
FileReader permite crear un flujo para la lectura de caracteres desde un
archivo. Análogamente a lo que ocurre con FileInputStream,la lectura
comienza desde el principio del archivo y cuando se leen datos del mismo, para
una nueva lectura desde el principio es necesario cerrar el flujo y volverlo a
abrir. Los constructores son:
public FileReader (lava.io.F i i e f i l e )
public FileReader(java.lang.String nombre)
y lanzan una excepción FileNotFoundException.
Ejemplo
FileReader fl = new FileReader ("info.txt");
fl.close ( ) ;
. . .
La clase RandomAccess File permite el acceso directo (también llamado
ucceso aleatorio) a una determinada posición dentro de un archivo, así como
la lectura y escritura de datos en dicho archivo. Esta clase no deriva de
Inputstream ni de Outputstream,sino que implementa las interfaces
DataInput y Dataoutput que definen los métodos de entradahalida bási-
cos. El flujo se crea mediante:
public RandcmAccessFile(java.io.File f i l e , java.lang.Ctring m)
throws FileNotFoundException
public RandorrSiccessFile(java.lang.Ctring nombre,]ava.iang.String m)
throws IOException
El parámetro m representa el modo en el que se creará el flujo y en la llamada
se le podrá pasar: r (lectura) o rw (lectura/escritura).
Archivos 373
Ejemplo
RanaomAcceccFile :le = new RaidomAcceccFile ("datos.=a-", "rw");
f le.close ( 1 ;
Nota: En Java RandomAccessFilees la clase que permite el acceso directo
y FileReader,FileInputStream, FileWritery FileOutputStream
ofrecen tratamiento secuencial.
14.4. ENCADENAMIENTO DE FLUJOS
Para conseguir flujos personalizados,que se adapten a los requisitos de transferencia de
datos en Java se utiliza la composición de flujos. Este sistema sirve no sólo para archi-
vos, si no que se aplica también a los flujos de red y de conector (socket).Existen una
serie de flujos que efectúan tratamientos especiales de la información; son, por ejemplo:
InputStreamReader
OutputCtreamWriter
BufferedReader
BufferedWriter
BufferedInputStream
BufferedOutputStream
Printstream
PriztWrLter
DataInputCtream
DataoutputCtream
Convierten bytes a caracteres.
Establecen un buffer para caracteres
I
Establecen un buffer para bytes
Escribe valores y objetos en un flujo de bytes.
Escribe valores y objetos en un flujo de caracteres.
Permiten leer y escribir tipos de datos primitivos,
efectuando conversiones desde un flujo de bytes a
dichos tipos de datos primitivos.
Estos flujos pueden asociarse unos con otros y con los de apertura de archivos para
obtener el flujo deseado ai escribir o leer de un archivo. Por ejemplo, la clase
FileOutputStreamconsidera el flujo como una colección de bytes, pero no como
unidades más grandes; cuando se desea imprimir unidades más grandes, se le puede
asociar un objeto Printstream.Los objetos PrinStream admiten los métodos
print y println para valores y objetos. Cuando se trata de objetos, estos métodos
374 Java 2. Manual de Programación
llaman al método tostring del objeto e imprimen el resultado. Prinstream
almacena los datos a imprimir en un bufer con la finalidad de trabajar de la forma más
eficiente posible y disminuir el número de operaciones de transferencia, así los datos
sólo se escriben cuando se llena el buffer o termina el programa. Esto resulta muy con-
veniente para los archivos, pero no para la pantalla. Systern. out es una instancia de
PrinStream y por eso print y print1n son los métodos que se vienen utilizan-
do para mostrar información por pantalla. La clase posee el método
public void flush ( )
que se utiliza para asegurar que los buffers de datos se escriben físicamente en el
flujo de salida.
Ejemplos
1. System.out.print ("Deme una cadena " ) ;
System.out .println("y a continuación pulse RETURN");
/ * Habitualmente Java vacía el buffer cuando, este se
llena, cuando termina el programa y cuando se efectúa
una lectura desde teclado, por lo que la siguiente
instrucción no suele ser necesaria * /
System.out.flush0 ;
2. File f = n e w File ("texto.txt");
//la siguiente instrucción abre el archivo para escritura
Fileoutputstream fe = n e w FileOutputStream(f) ;
Printstream salida = n e w PrinStream (fe);
/ * Después se utilizarían los métodos println o print de
salida.println ("Los f l u j o s proporcionan canales "+
Printstream * /
"de comunicación") ;
/ * P o r último seria conveniente cerrar los f l u j o s con el
método close * /
Otro encadenamiento se puede utilizar para leer cadenas desde un archivo abierto
con FileInputStream.El programa que lee llama a un BufferReader que
utiliza un InputStreamReader,que a su vez utiliza un FileInputStream
para leer del File.
Ejemplo
/ / Objeto File
File f = n e w File ("texto.txt");
//Apertura del archivo para lectura. F l u l o de bytes
FileInputStream fl = n e w FileInputStream(f);
Archivos 375
//Conversión a f l u j o de caracteres
InputCtreamReader entrada = n e w InputStreamReader(f1j;
/ * Buffer para caracteres y objeto que permite leer una línea
BufferedReader lectorcad = n e w BufferedReader(entrada);
/ / Lectura
String cadena = lectorCad.readLine0; //lanza una IOException
completa * /
El método readLine ( ) de la clase BufferedReader permite leer una
secuencia de caracteres de un flujo de entrada y devuelve una cadena; además, uti-
liza un byffeer para mejorar el rendimiento. Para efectuar lectura desde teclado, se
utiliza system.in,que es una instancia de java.i o . Inputstream;por esta
razón, las lecturas de una cadena desde teclado se han efectuado con un método
análogo ai anteriormente expuesto.
Ejemplo
InputCtreamReader entrada = n e w InputCtreamReader(System.in);
BufferedReader lectorcad = n e w BufferedReader(entradaj;
String cadena = lectorcad.readLine ( ) ;
DataInputStream y DataOutputStream se utilizan respectivamente para
leer o escribir en un flujo FileOutputStream o FileOutputStream datos
de tipos primitivos y recuperarlos como tales y también en este caso se aplica enca-
denamiento.
Ejemplo
FileInputCtream fe = n e w FileInputCtream
DataInputCtream de = n e w DataInputStream
cad = de.readUTF(j;
de.close ( ) ; //método heredado de Filter
"datos.dat");
fe);
nputstream
14.5. EXCEPCIONES EN ARCHIVOS
Cuando se trabaja con archivos se pueden producir errores de entrada/salida y Java
obliga a prever este tipo de errores y recoger las excepciones que pueda lanzar el
sistema. Las excepciones del paquete java .io se muestran en la Figura 14.7.
Cuando el programador diseña un método tiene dos opciones con este tipo de
excepciones: listarías en la cabecera del mismo o bien recogerlas y tratarlas. Si está
sobrescribiendo un método del que no puede modificar la interfaz, se verá obligado
a recoger estas excepciones y tratarlas en el propio método.
Las excepciones en el trabajo con archivos pueden ser lanzadas por los métodos
de escritura y lectura, pero además hay que tener en cuenta que la apertura de un
376 Java 2. Manual de Programación
archivo puede producir una excepción IOException cuando falla la operación; por
ejemplo, si se intenta abrir para lectura un archivo que no existe, y el cierre de un
archivo con el método close también puede producir una IOException.Por otra
parte, los archivos en Java terminan con una marca de fin de archivo y cuando en la
lectura de un archivo se llega a dicha marca se puede lanzar una EOFException.
Capturar y tratar las excepciones en la apertura y cierre de un archivo.
public class ControlExcepciones
t
public static void main (String[] args)
i
AbreYCierra arch = new AbreYCierra ( ) ;
arch.leer ( ) ;
import java.io.*;
public class AbreYCierra
I
FileInputStream fl = null;
public void leer0
File f = new File("texto.txt");
fl = new FileInputCtream(f);
1
catch(I0Exception e)
I
Cystem.out .println(e);
1
finally
t
try
i
/ * no debe colocarse en el primer bloque try ya que
if (fl ! = null)
fl.close0;
1
catch(I0Exception e)
pudiera no ejecutarse * /
Cyctern.o.dt.println(e);
Systerr..out.println("Fin");
:t
1
Archivos 377
Figura 14.7. Excepciones del paquete 1ava. 10
Nota: Al trabajar con archivos, las excepciones pueden ser lanzadas por los
métodos de lectura y escritura y también por las operaciones de apertura y cie-
rre del archivo. El compilador obliga a tratar dichas excepciones.
378 Java 2. Manual de Programación
Nota: Cuando se detecta el fin de flujo:
.El método read de inputstream devuelve - 1.
El método readLine devuelve null.
Los métodos que se exponen en DataInputStream generan una
EOFException.
14.6. MÉTODOS DE inputstream
public int available ( )
Deuelve el número de bytes actualmente disponibles para su lectura en el flujo de entrada.
public void close 0
Cierra el flujo de entrada. Genera una IOException si se produce un error.
public synchronized void mark(int num)
Coloca una marca en el flujo de entrada, válida hasta que se lea el número de bytes especi-
ficado como parámetro.
public boolean marksupported0
Comprueba si el flujo de entrada soporta los métodos mark y reset.
public abstract int read0
Devuelve como entero el siguiente byte disponible de la entrada.
public int read(byte b [ I )
Intenta leer desde el flujo de entrada el número de bytes necesarios para llenar el array b
pasado como parámetro y devuelve el número real leído.
public int read(byte b [ 1 , int d e s d e , int c u a n t o s )
Intenta leer desde el flujo de entrada el número de bytes especificados corno tercer paráme-
tro y los introduce en el array b empezando en b [decde] .
public synchronized void reset ( )
Coloca el puntero de entrada en la marca establecida con mark.
public long skip(1ong n)
Salta y descarta n bytes del flujo de entrada, devolviendo el número real de bytes saltados.
Excepto m a r k , todos los métodos restantes lanzan una IOException.
Archivos 379
14.7. MÉTODOS DE Outputstream
public void close()
Cierra el flujo de salida. Genera una IOException si se produce un error
public void flush()
Vacía y limpia el buffer.
public void writ-e (byte b [ I )
Escribe b . length bytes del array b en el flujo de salida.
public void write(byte b [ 3 , int d e s d e , int cuantos)
Escribe b . cuantos bytes del array b en el flujo de salida comenzando desde b [doczel.
public abstract void writeíint 5)
Escribe un Único byte en el flujo de salida.
Todos estos métodos lanzan una excepción IOException.
14.8. MÉTODOS DE Reader
La clase Reader es una clase abstracta, superclase de todos los flujos de entrada
orientados a carácter que proporciona un conjunto de métodos similar al que la clase
inputStream proporciona para los flujos de entrada orientados a byte. Todos sus
métodos lanzan una excepción IOException.
public
public
public
public
public
public
public
public
public
abstract void close ( )
void mark (int n u m l a r a c t e r e s )
boolean markSupported()
int read()
int read (char c [ ] )
abstract int readíchar c[ I , int d e s d e , int cuantos)
boolean ready ( )
void reset 0
long skip(1ong n)
14.9. MÉTODOS DE Writer
La clase Writer es una clase abstracta superclase de todos los flujos de salida
orientados a carácter que proporciona un conjunto de métodos similar al que la clase
Outputstream proporciona para los flujos de entrada orientados a byte. Todos
sus métodos lanzan una IOException.
380 Java 2. Manual de Programación
public abstract void close ( )
public abstract void flush ( )
public void write (char c [ I )
public abstract void write (char c[ 1 , int d e s d e , int
public void write (int c)
public void write (lava.lang.Ctring c a d e n a )
public void write (java.lang.Ctring c a d e n a , int d e s d e , int
c u a n tos)
c u a n t o s )
14.10. MÉTODOS DE DataInputStream
Esta clase actúa como filtro envolviendo un flujo de entrada para así permitir la
lectura desde un archivo de datos de tipos primitivos. Métodos de
DataIripu t Stream son:
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
final int read (byte b u f f e r [ ] )
final int read(byte b u f f e r [ 1 , int d e s d e , int c u a n t o s )
final boolean readBoolean0
final byte readByte( )
final char readchar( )
final double readDoubie( )
final float readFloat( )
final void readFully(byte b u f f e r [ 1 )
final int skipBytes(int n)
final void readFully(byte b u f f e r [ 1 , int d e s d e , int
c u a n tos)
final int readInt ( )
final long readLong ( )
final short readshort( )
final int readUnsignedByte( )
final int readUnsignedChort( )
final java.lang.Ctring readUTF()
static final java.lang.Ctring readUTF(java.io.DataInput
e n t r a d a )
Todos estos métodos lanzan una IOException y casi todos ellos están defini-
dos en la interfaz DataInput implementada por la misma. Los métodos readUTF
devuelven una cadena de caracteres Unicode y generan una excepción del tipo
UTFDataFormatException si los bytes no representan una codificación UTF-
8 válida de una cadena Unicode. En el formato UTF-8' los dos primeros bytes indi-
can el número de bytes que han de ser leídos a continuación para formar la cadena.
El nombre de los restantes métodos realizan las tareas que dicho nombre sugiere.
' Las siglas UTF-8 significan Formato de Transformación Universal 8; es un formato de transmisión para
Unicode válido para los archivos de sistemas Unix.
Archivos 381
14.11. MÉTODOS DE DataOutputStream
Esta clase actúa como filtro envolviendo un flujo de salida para así permitir la
escritura en un archivo de datos de tipos primitivos. Todos los métodos de
DataOutputStream,excepto size ( ) lanzan una IOException.Métodos
de DataOutputStream son:
public void flush()
public final int size()
public synchronized void write (byte b u f f e r [ i , int desde, int c u a c t s c )
public synchronized void write (int v a l o r )
public final void writeBoolean(boo1ean b o o l e a n o )
public final void writeByte (int v a l o r )
public final void writeBytec (]ava.lang.Ctring c a d e n a )
public final void writechar (int c a r á c t e r )
public final void writechars (java.lang.Stringc a d e n a )
public final void writeDoubie (double v a l o r )
public final void writeFloat:(float v a l o r )
public final void writeInt(int v )
public final void writeLong (long v)
public final void writeshort (int v )
public final void writeUTF(]ava.lang.String c a d e n a )
El método s i z e ( ) devuelve el número de bytes escritos y, por su nombre y lo
comentado en otras ocasiones, puede deducirse el significado de los restantes. Casi
todos los métodos de esta clase están definidos en la interfaz Dataoutput imple-
mentada por la misma.
Nota: DataInputStream y DataOutputStream se utilizan respec-
tivamente para leer o escribir en un flujo FileOutputCtream o
FileOutputStream datos de tipos primitivos y recuperarlos como tales
aplicando encadenamiento.
14.12. MÉTODOS DE RandomAccessFile
Esta clase implementa las interfaces DataInput y Dataoutput y además de los
métodos de ambas interfaces ofrece también los siguientes:
public long getFilePointer ( ) Devuelve, en bytes, la posición
actual en el archivo.
public long length0 Devuelve, expresada en bytes,
la longitud del archivo.
382 Java 2. Manual de Programación
publice void ceek(1ong pl) Coloca en una posición especí-
fica relativa al principio del
archivo, de forma que las ope-
raciones de lectura o escritura
puedan realizarse directamente
en dicha posición.
14.13. SERIALIZACIÓN DE OBJETOS
En Java un registro de un archivo se puede corresponder con una clase y los cam-
pos del registro coincidirían con las variables de instancia; por consiguiente, en
lugar de leer y escribir series de datos agrupadas en los archivos, puede resultar más
adecuado leer y escribir objetos. La serialización de objetos es la forma de guardar
objetos en archivos o enviarlos a través de la red, ya que permite escribir o leer obje-
tos en flujos. El mecanismo de serialización mantiene el control sobre los tipos de
objetos y las relaciones entre ellos.
Para que se pueda serializar un objeto, basta con establecer que implemen-
te la interfaz S e r i a l i z a b l e . Esta interfaz no tiene métodos, por lo que no habrá
que añadir implementaciones a la clase, pero obliga a que todos los campos de datos
del objeto sean serializables; como los tipos predefinidos son todos serializables,
en realidad lo único que habrá que considerar es que si desde ese objeto se refe-
rencian otros, estos también hayan sido declarados serializables. La clase que
permite escribir los objetos en el flujo de salida es O b j e c t O u t p u t S t r e a m y
C b j e c t I n p u t C t r e a m la que permite leerlos.
O b j e c t O u t p u t S t r e a m implementa la interfaz O b j e c t c u t p u t que a su
vez implementa D a t a c u t p u t que le añade la capacidad de escribir, además de
objetos, tipos básicos de datos. Las operaciones con archivos se harán encade-
nando un O b j e c t c u t p u t s t r e a m a un F i l e C u t p u t C t r e a m y el método
w r i t e o b j e c t ( o b j e t o ) es el que se utiliza para escribir objetos en el flujo
abierto hacia el archivo:
public final void writeObject(java.iang.0bject o b j )
Los métodos f l u s h ( ) y c l o s e ( ) se emplearán para obligar a volcar el con-
tenido del bgfer y cerrar el flujo respectivamente.
C b j e c t I n p u t C t r e a m implementa la interfaz C b j e c t I n p u t que a su vez
implementa D a t a I n p u t que le añade la capacidad de leer, además de objetos, tipos
básicos de datos. Las operaciones con archivos se harán encadenando un
C b j e c t I n p u t S t r e a m a un F i l e I n p u t S t r e a m y el método readobject ( ) .
public final java.lang.Object readobject0
es el método que se utiliza para leer objetos en el flujo abierto hacia el archivo.
Archivos 383
I I
Nota: La serialización de objetos permite guardar en archivos objetos que
implementan la interfaz Ser ia1iz ab1e.
14.14. StringTokenizer Y StreamTokenizer
StringTokenizer pertenece al paquete java. util;trabaja sobre cadenas y
se puede utilizar como herramienta para efectuar el análisis de las líneas leídas de
un archivo de texto. La clase StreamTokenizer es miembro del paquete
j a v a . io y realiza un trabajo muy similar a StringTokenizer,permitiendo
dividir un flujo de entrada en fragmentos significativos mediante el empleo de unos
delimitadores. El constructor es:
public StreamTokenizer (java.io.Reader r)
La constante TT EOF indica que se ha leído el final del flujo; de modo análogo
TT EOL y TT WORD indican el fin de línea y el fin de palabra. Para inicializar los
del&itadores,se emplea resetsyntax ( ) y después con el método wordchars
se puede establecer la serie de caracteres que pueden constituir una palabra. El
método eolIsSignificant determina que los caracteres de línea nueva sean
tratados como tokens, de forma que nextToken devuelva TT-EOL cuando se lea
el fin de línea.
14.15. OPERACIONES CON ARCHIVOS Y MANTENIMIENTO
DE LOS MISMOS
Las operaciones con archivos son aquellas que tratan con su propia estructura, tales
como la creación, apertura o cierre de los mismos y que son proporcionadas por el
lenguaje, en este caso Java. Además de utilizar este tipo de operaciones al trabajar
con archivos, será necesario diseñar métodos que efectúen tareas de mantenimien-
to. El mantenimiento de un archivo incluye las siguientes operaciones:
9 Actualización
Altas. Operación de incorporar al archivo un nuevo registro.
Bajas. Acción de eliminar un registro de un archivo. Las bajas pueden ser
de dos tipos:
Ldgicu. Se efectúa colocando en el registro que se desea borrar una bandera o
indicador que lo marque como borrado. Admite la posterior recuperación de la
información.
384 Java 2. Manual de Programación
Fkica. implica la desaparición de esa información del archivo de forma que no
pueda ser recuperada por operaciones posteriores. Puede efectuarse mediante la
sobreescritura del registro o bien creando un nuevo archivo que no incluya dicho
registro.
Modificaciones. Proceso de modificar la información almacenada en un
determinado registro de un archivo.
Consulta
De un Único registro.
De todos los registros del archivo.
14.16. ARCHIVOS SECUENCIALES
En los archivos secuenciales los registros se almacenan unos al lado de otros sobre
el soporte externo y se pueden designar por números enteros consecutivos; sin
embargo, estos números de orden no se pueden utilizar como funciones de acceso
y para realizar el acceso a un registro resulta obligatorio pasar por los que le prece-
den. Además, este tipo de archivos no pueden abrirse simultáneamente para lectura
y escritura y terminan con una marca de final de archivo.
Los archivos secuenciales en Java se pueden abrir para lectura con
Fi1eInputStream o Fi1eReaderypara escritura con Fi1eOutputStream
o Filewriter.
Cuando un archivo secuencial se abre para lectura, un puntero de datos imagi-
nario se coloca al principio del archivo, de forma que la lectura siempre comen-
zará por el principio. Cuando un archivo secuencial se abre para escritura, el
puntero de datos imaginario puede colocarse al principio del archivo, con lo que
si éste existía se perderá cualquier información almacenada en el mismo, o bien
al final:
public FileOutputCtream(java.lang.String nombre, boolean a ñ a d i r )
public Filewriter (Java.lang.String nombre, boolean aríadir)
para así poder añadirle nueva información por el final.
Un caso particular de archivos secuenciales son los archivos de texto, que están
formados por una serie de líneas cada una de las cuales se encuentra constituida por
una serie de caracteres y separadas por una marca de final de línea.
Ejercicio
Diseñar Ún programa con interfaz gráfica que muestre el contenido de los archivos
de texto que se le indiquen a través de un campo de texto (Fig. 14.8).
Archivos 305
!-
mode con codepage prepate=((850) C iWINDüWSCOMMANDega I
mode con codepage select=850
keyb sp,,C iWINDOWSiCOMMANDkeyboard SYS
set path=%path%,C h i p
Fin
f
Figura 14.8. Ejecución: muestra el contenido del archivo c : autoexec.bak.
import java.io.*;
import java.awt.*;
import java.awt.event.*;
public class LeeTexto extends Frame implements Actioniistener
TextArea contenido;
T e x t F i e l d nombre;
File arch = null;
public LeeTexto ( )
cetLayout (new BorderLayout ( ) ) ;
addWindowListener (new W indowAdapter ( )
public void windowClosing (WindowEvent e)
Cystem.exit (O) ;
1
1 ) ;
nombre = new TextField();
nombre.addActionLictener(this);
add ("North",nombre) ;
contenido = new TextArec3( ) ;
add ("Center",contenido) ;
1
public void actionPerformed (ActionEvent e)
nombre.selectAll ( ) ;
arch = new File (nombre.qetText ( 1 ) ;
CargarArchivo ( ) ;
386 Java 2. Manual de Programación
public static void main( String args[] )
I
LeeTexto v e n t a n a = new LeeTexto ( ) ;
ventana.cetCize( 400,250 ) ;
v e n t a n a . cet-it-e ("Zlemplo de Lectura desde Archivo") ;
ver.tana.cetV-sible(true);
void CargarArc?.ivo ( 1
i
File3eader f = null;
SufferedReader br = null;
String cadena = null;
try
f = new FiieReader (arch);
br = new Suf feredReader (f);
do
cadena = br.reasLine0;
if (rader,a ! = null)
cor.tenido.append(cadena + "  n " ) ;
i
while (cadena ! = null);
catch (FileNozFoundExceptisn e)
!
contenido.apFend("Ei arch;vo no existen");
I
catch (IOException e)
ccntenido.append("Errorn");
finally
t=Y
t
if (br ! = null)
{
Dr.close(); //basta con cerrar el oDjeto nac exterior
i
catch ( IOException e)
!
contenido.append ("Errorn");
i
coxtenido.appexd ("F:nnn") ;
Archivos 387
Ejercicio
Un ejemplo de serialización. El programa debe permitir efectuar altas y bajas y con-
sultas de los datos de los empleados de una empresa.
En la implementación expuesta a continuación, las operaciones se efectúan en
un array en memoria; este array es el campo de datos de un objeto de tipo
Personal.El objeto Personal se recupera y escribe desdeien un archivo en el
disco empleando serialización. Como los elementos del array son objetos de tipo
Empleado,la clase Empleado también ha de ser serializable. El método main
de la clase Ejemplo llama a: 1) leer,método que cuando el archivo existe lee el
objeto, 2) operaciones,que a través de un menú de opciones permite elegir la
operación a realizar, 3) escribir,que escribe el objeto en el archivo cuando
dicho objeto ha sufrido cambios.
La clase Empleado representa los registros y sus campos son: código,
edad, nombre, domicilio y telSfono.El código es el campo clave que
identifica al empleado y se supone que no se van a introducir en ningún momento
códigos repetidos.
Las altas se efectúan simplemente añadiendo nuevos elementos al final del array.
El array se crea de nuevo, para aumentar su tamaño, en cada adición y se utiliza otro
array auxiliar copiaDeLista para conservar la información anterior. Tras crear
el nuevo array arrEmpleados, se copian en e1 los elementos del array
copiaDeLista y se coloca al final el nuevo empleado (unEmpleado). Esta
forma de trabajar imita el funcionamiento de la clase Vector del paquete
java .util,que inicialmente crea un array de objetos de un tamaño determinado
y, si más adelante se necesita, crea otro de mayor tamaño, mueve todos los objetos
al nuevo y borra el antiguo; la clase Vector proporciona así arrays dinámicos, que
aumentan o disminuyen de tamaiio en tiempo de ejecución.
La baja de un empleado (método eliLminar de la clase Personal)disminu-
ye el tamaño del array.
La consulta pide un código y efectúa un recorrido secuencia1 del array hasta
que éste se acaba o encuentra un empleado cuyo código sea igual al introducido
desde teclado. En el caso de que encuentre a dicho empleado, muestra la informa-
ción almacenada sobre dicho empleado.
import java.io.*;
public c l a s s Ejemplo
static Personal lista = n u l l ;
//si ?a lista s-ifre cambios se escribe en el disco
s t a t i c boolean carcbios;
388 Java 2. Manual de Programación
public static void maip(String[] args)
leer ( ) ;
operaciones ( ) ;
escribir ( ) ;
public s t a t i c void leer ( )
/ * Creación considera dos casos si el archivo existe
Lile fichero = new File("empresa.dat") ;
i f
i
previamente o no * /
( ! fichero.exists ( ) )
lista = new Personal ( 1 ;
System.out.printlr! ("Nuevo archivo");
else
ois = new ObjecticputStream(new Fileinputstream
lista = (Personal)ois.readoblect 0 ;
System.out .printin("Archivo existente") ;
("empresa.dat"));
1
catch (ClassNotFoundExceptisn e)
System.out .printir.("Error: " + e.tostring ( ) ) ;
catch (IOException e)
I
System.out .println("Error: " + e.tostring ( ) ) ;
1
f i n a l l y
I
i f ( o i s ! = null)
ois .close ( ) ;
1
catch ( IOException e)
t j
public s t a t i c void operaciones ( )
t
short opción = O ;
InpuZCtreamReader isr = new :nputStreamReader(System.in);
BufferedReader br = new BLfferedReader(1sr);
Archivos 389
int posi = -1;
short código = 3;
short edac = O;
Ctrinq Rornbre, dorniciiio, teléfono;
boolean eliminado = false;
boolean error;
/ / Mantenimiento
try
t
do
Systern.out.println("MENC");
Systern.out.printin("?. Altas") ;
Systern.oUt.println("2. Bajas") ;
Systern.out.println("3. Consultas");
Systern.out.println ("4. Fin");
Systern.out.printin();
Systern.cGt.print ( " E l i j a opción: " ) ;
do
opción = Short .parseShort (new BufferedReacer (new
inputCtrearnReader(System.in)).readLineO);
while (opcL6n < 1 ' 1 opción > 4);
switch (opciór.)
/ * Con el fin de simplificar el ejemplo, se supone
case 1: / / altas
q u e no se inti-od~cencódigos repetidos * /
/ * se trata la excepcihn para que vrelva a pedir
el dato en el caso de que se ;ntroduzca un
valor no n,xiérico * /
do
error = false;
try
System.out.print ("código: " 1 ;
código = Short .parseshort(br.readLine ( ) ) ;
catch (NumcerFormatExcepti o n ne)
System.out.println ("Vaior no vál;do "+
error = true;
"(ha de ser un número)");
I
while (error);
System.out .prini: ( " nombr e :
nombre = br.reaiLine ( ) ;
do
{
" ) ;
390 Java 2. Manual de Programación
error = false;
try
System.out.print ("edad: ' I ) ;
edad = Short.parseShort(br.readLlne0);
catch (NumberFormatException ne)
t
System.out.println("Valor no váildo " f
error = true;
"(ha de ser UI número)");
while (error);
System. o u t . print ( "domicilio : " ) ;
domicilio = br.readLine ( ) ;
System.out.print("teléfono: ' I ) ;
teléfono = br .readLine ( ) ;
1ista.añadir (new Empleado (código, nombre, edad,
domicillo, teléfono));
cambios = true;
break;
do
case 2: / / bajas
t
error = false;
try
t
System.out .print("Código a borra::: " ) ;
código = Short .parseshort (br.reatlLine ( ) ) ;
1
i
catch (NumberFormatException ne)
System.out .println("Vaior no válido " f
error = true;
"(ha de ser un número)");
!
i
while (error);
eliminado = licta.elimlnar(código);
if (eliminado)
Sys tem.out .pr1nt1n ( "RegIc tro e1imiriado" ) ;
cambios = true;
1
else
if (licta.longitud() ! = O)
else
break;
System.out.println ("No esta");
System.out .println("Lista vacía") ;
Archivos 391
case 3: / / consultas
do
error = false;
try
I
System.out .print("Código a buscar: " ) ;
código = L h o r t . p a r s e C h o r t ( b r . r e a d l i n e 0 ) ;
catch (NumberFormatYxception re)
t
Cystem.out .pri~tln("Valor no válido " +
error = true;
"(ha de ser UT. n , h e r o ) " ) ;
while (error);
posi = lista.biiscar (código);
if (posi == -1)
if (lista.lo.igitud0 ! = O)
else
Cystem.out .print13("Registro no encoctzado") ;
Cystem.out .println("Lista vacia") ;
else
lista.e:emento(posi) .mostrar 0;
break ;
case 4:
while (opci6n ! = 4);
catch ( IOException e)
public static void escrib;r ( )
t
ObjectOutputStream ous =: null;
//si hubo cambios l o s i':;cribe en el a r c h i v o
try
if (cambios)
t
out = new ObjectOutputCtream( new
ous.write0bject (lista);
FileOntputCtzean("empresa.dat")) ;
i
lista = null;
catch ( IOException e)
392 Java 2. Manual de Programación
t
Cystem.out.printin("Error: " + e.toString()) ;
finally
t
if (ous ! = null)
ous.close ( ) ;
catch ( IOException e)
t i
/ * Clase Personal de la empresa. Objeto que representa un
array de Empleado * /
import lava.io.*;
public class Personal implements Serializable
private Empleado[] arrEmpleados;
private int nElementos;
public Personal ( )
/ / Crea'el array
nElementos = O;
arrEmpleados = inicializar(nE1ementos);
private Empleado[] inicializar(int nElementos)
t
return new Empleado [nElementos];
catch (OutOfMemoryError e)
I
System.out.println(e.toString());
return arrEmpleados;
public Empleado elemento(int i )
if ( i >= O & & i < nElementos)
else
return arrEmpleados [ i1 ;
I
Archivos 393
System.out .println('"3 hay elementos en esa poSici6Z");
return null;
I
1
public int longitud()
i
1
return arrEmpleados.lencjth;
public void añadir (Empleado unEmpleado)
i
Empleado [ ] copiaDeLista;
/ / el array crece conform se le van añadiendo nuevos eiementoc
copiaDeLista = arrEmpleados;
nElementos = copiaDeLisia.length;
arrEmpleados = inicializar (nElernentoc t 1);
for ( int i = O; i < nElernentos; i++ j
arrErnpleados [i] = copLaDeLista[i] ;
arrEmpleados[nElementos] = unEmpleado;
nElementos++;
public boolean eliminar(short cod)
{
Empleado[] copiaDeLista;
int posi = buscar(cod);
if (posi ! = -1)
i
/ / el array disminuye cuando se eliminan elementos
arrEmpleados [posil = null;
cop1aDeLista = arrEmp:.eados ;
if (copiaDeLista.lengLh ! = O)
i
int k = O;
nElementos = copiaDeLista.length;
arrEmpleadoc = inic ializar (nElementos - 1j ;
for (int i = O; i < nElementos; I++)
if (copiaDeLista[ i] ! = null)
arrEmpleados [ k + t ] = copiaDeLista [i];
nElementos--;
return true;
1
1
return false;
}
public int buscar(short cod)
i
int posi = O;
394 Java 2. Manual de Programación
if (pos1 < nElementoc)
for (int 1 = posi; I < nElementos; I++)
if (arrEmpleadcc [ i] .devolvercodigo ( ) == cc d)
return 1;
return -1;
/ / Clase Empleado. Objeto que representa un registro.
import ;ava._o.*;
public class Enpleado implements Serlaiizable
private short codigo;
private short edad:
private Strirg nombre, domicilio, telefono;
public Empleado ( )
public nmpleado(short cod, Strinq zom, short annos, String
=om, String tfno)
I
código = cod;
noxbre = corn;
edad = annos;
domicilio = dcm;
teléforo = tfno;
public void establecerCódigo(short cod)
i
cócigo = cod;
i
public short devolvercódigo ( )
return código;
i
public void estabiecerNombre (String nom)
I '
nombre = nori;
public String devolverNombre0
return nombre;
Archivos 395
public void establecerEdad ( s h o r t annos)
t
I
edad = annos;
public s h o r t devolverEdad ( )
t
r e t u r n edad;
public void ectablecerDomicilio(String dom)
i
domicilio = dom;
public String devolverDomicilio()
I
r e t u r n domic i 1io;
i
public void establecerTelSfono (String tfno)
I
teléfono = tfno;
1
public String devolverlel'ifono( )
i
ret u r n teiéf ono ;
I
public void mostrar ( )
i
System.out .println(devolverCodigo( ) ) ;
System.out .println(devoLverNombre ( ) ) ;
Cystem.out .println(devo.LverEdad( ) ) ;
System.out .println(devo..verDomicilio( ) ) ;
System.out .println(devo1-verTeléfono( ) ) ;
I
14.17. ARCHIVOS DIRECTOS
Los registros en un archivo de acceso directo han de ser de longitud fija. En un
archivo directo, el orden físico de los registros no tiene por qué corresponderse con
aquel en el que han sido introducidos, y los registros son accesibles directamente
mediante la especificación de un número que indica la posición del registro con res-
pecto al origen del archivo. Los archivos directos, también denominados aleatorios,
396 Java 2. Manual de Programación
se abren para lectura y escritura al mismo tiempo. En Java RandomllccessFile
es la clase que permite la apertura de archivos de acceso directo y ofrece el método
seek ( p o s i c i ó n ) para el posicionamiento sobre un determinado registro del
srchivo.
Nota: A diferencia de los secuenciales:
Los archivos directos se abren para lectura y escritura al mismo tiempo.
Permiten el posicionamiento sobre un determinado registro, sin que sea
necesario recorrer los anteriores.
14.18. FUNCIONES DE TRANSFORMACIÓN DE CLAVE
Y TRATAMIENTO DE COLISIONES
Aunque la información en un archivo directo puede colocarse simplemente de
forma secuencial, normalmente esto no se hace así, dado que la utilidad fundamen-
tal de los archivos directos es proporcionar un rápido acceso a la información. Con
esta finalidad los datos deben situarse de tal manera que puedan ser localizados
rápidamente y, como éste tipo de archivos permite el posicionamiento directo en un
determinado lugar del archivo y el acceso a la información en los archivos se suele
efectuar utilizando una clave, la solución consiste en crear una relación perfecta-
mente definida entre la clave identificativa de cada registro y la posición donde se
colocan dichos datos. La clave es un campo del propio registro que lo identifica de
modo único, por ejemplo el número de matrícula de un alumno en el caso de un
archivo que almacenara datos de alumnos o el NIF, número de identificación fiscal,
en el caso de querer guardar información sobre los clientes de una empresa. Es pre-
ciso tener en cuenta que, aunque en ocasiones la clave (x)podrá ser utilizada para
obtener la posición empleando simplemente la fórmula mostrada en la Tabla 14.1,
otras veces esto no es posible.
Tabla 14.1. Fórmula que en algunas ocasiones se puede aplicar
para transformar la clave en una posición
Fórmula Clave Posición relativa al
comienzo del Archivo
O
5*tamaño registro
Posicior. = (long) (x-1)* tamaño registro;
Archivos 397
La citada fórmula no se puede utilizar cuando el porcentaje de claves a almace-
nar en el archivo es reducido en comparación al rango en el que pueden oscilar los
valores de las mismas o cuando las claves son alfanuméricas. La solución en estos
casos es aplicar funciones que transformen las claves a números en el rango conve-
niente, a estas funciones se las denomina funciones de conversión (hash),y luego
usar dichos números en la fórmula expuesta. El resultado de dicha fórmula hay que
convertirlo a un tipo l o n g dado que el argumento de s e e k es de tipo long.
Cuando se aplica una función de conversión puede ocurrir que dos registros con
claves diferentes produzcan la misma dirección física en el soporte. Se dice enton-
ces que se ha producido una colisión y habrá que situar ese registro en una posición
diferente a la indicada por el algoritmo de conversión. Si esto ocurre, el acceso se
hace más lento, por lo que resulta importante encontrar una función de conversión
que produzca pocas colisiones.
Ejemplo
Imagine que las claves identificativas de los registros que desea almacenar oscilan
entre los valores 1a 1O O OO O O, pero la cantidad de registros sobre los cuales se va
tener que guardar información sólo es 5O. Según la fórmula de la Tabla 14.1,habría
que disponer de un archivo de tamaño
(1000000-1)* tamañoRegistro
para así poder situar en la posición adecuada cualquier registro que fuera necesario
almacenar. Este archivo sería demasiado grande y estaría en su mayor parte deso-
cupado. Puesto que se sabe que no va a ser necesario guardar más de 50 registros,
se podría aplicar una función de conversión como la siguiente:
x = clave % 50; / * dividir por un número primo da origen
a un menor número de colisiones, es
decir de restos repetidos * /
que convertiría cualquier clave entre 1 y 1 0 0 0 0 0 0 en números entre O y 49.
Lógicamente con esta función a registros con diferentes claves les puede corres-
ponder el mismo x y, por tanto, la misma posición.
posición = x * tamañoRegistro; / * la función hash aplicada
hace innecesario restar
l a x * /
Existen muchos tipos de funciones de conversión. La eficiencia de la función hush
y el método de resolución de colisiones se mide por el número de comparaciones
de claves necesarias para determinar la posición en la que se encuentra por fin un
398 Java 2.Manual de Programación
determinado registro. El tratamiento de las colisiones también se puede efectuar de
muy diferentes formas:
Creando una zona especial, denominada zona de excedentes, a la cual se lle-
van exclusivamente esos registros. La zona de desbordamiento, excedentes o
sinónimos podría encontrarse a continuación de la zona de datos o ser incluso
otro archivo.
Buscando una nueva dirección libre en el mismo espacio donde se están intro-
duciendo todos los registros, zona de datos, para el registro colisionado. Lo que
se puede hacer mediante diferentes técnicas, por ejemplo, direccionamiento
abierto y encadenamiento.
- El direccionamiento abierto resuelve las colisiones mediante la búsqueda, en
el mismo espacio donde se están introduciendo todos los registros (zona de
datos) de la primera posición libre que siga a aquella donde debiera haber
sido colocado el registro y en la que no se pudo situar por encontrarse ya
ocupada. El archivo se considera circular y cuando se busca sitio para un
registro las primeras posiciones siguen a las últimas.
- El encadenamiento se basa en la utilización de tablas hash que permitan
localizar rápidamente por la clave la posición donde se ha escrito el archivo
en el disco. Los registros se colocan en el archivo de forma secuencia1
excepto cuando se deseen aprovechar los huecos dejados por las operaciones
de baja.
Ejercicio
Presentar un menú de opciones que permita efectuar altas, bajas y consultas en un
archivo directo mediante el método de transformación de claves. El archivo,
otrosempleados.dat,almacenará código, nombre, edad, domici-
lio y teléfono de los empleados de una empresa. El campo clave es el código.
El método de transformación de claves consiste en introducir los registros en el
soporte que los va a contener en la dirección que proporciona el algoritmo de con-
versión. Su utilización obliga al almacenamiento del código en el propio registro,
ya que éste no se podrá deducir de la posición, y hace conveniente la inclusión en
el registro de un campo auxiliar, ocupado,en que se marque si el registro está ocu-
pado o no. Se requiere tener en cuenta que códigos distintos, sometidos al algorit-
mo de conversión pueden proporcionar una misma dirección, por lo que se tendrá
previsto un espacio en el disco para el almacenamiento de los registros que han
colisionado. Aunque se puede hacer de diferentes maneras, en este caso se reser-
vará espacio para las colisiones en el propio archivo a continuación de la zona de
datos. Se supondrá que la dirección más alta capaz de proporcionar el algoritmo de
Archivos 399
conversión es FINDATOS y se colocaran las colisiones que se produzcan a partir de
allí en posiciones consecutivas del archivo. La zona de colisiones será la compren-
dida entre FINDATOS y MAX; siendo MAX una constante establecida por el progra-
mador que determina el tamaño total del archivo y cuyo valor, lógicamente, será
mayor que FINDATOS.
Creación. Cuando se abre el archivo por primera vez se debe realizar un reco-
rrido de todo el archivo inicializando el campo ocupado a un valor vacío, por
ejemplo, a espacio en blanco. La inicialización a espacio en blanco del campo
ocupado se realiza hasta MAX.
Altas. Para introducir un nuevo registro se aplica al campo código de dicho
nuevo registro el algoritmo de conversión, obteniendo así la posición donde
debe situarse. Se lee la información almacenada en el archivo en dicha posi-
ción y si el campo ocupado indica que dicho lugar está libre el nuevo registro
se sitúa allí; cuando la mencionada posición no esta libre el nuevo registro se sitúa
en la primera posición libre existente en la zona de colisiones.
Consultus. Para localizar un registro se aplicará al código a buscar la función
de transformación de claves y, si no se encuentra en la dirección devuelta por
la función, se examinará registro a registro la zona de colisiones. Para decidir
que se ha encontrado habrá que comprobar que el registro no está de baja y que
su código coincide con el que se está buscando, en cuyo caso se interrumpi-
rá la búsqueda y se mostrará el registro por pantalla.
Bajas. La eliminación de un registro se efectuará mediante baja lógica y con-
sistirá en:
- Localizar el registro buscándolo por su código, primero en la zona direc-
ta y, si allí no se encuentra, en la zona de colisiones.
- Una vez localizado eliminar la marca existente en su campo ocupado,
asignando a dicho campo el valor que se interpreta como vacío, y escribir
nuevamente la información en el archivo en la posición donde se encontró.
import java.io.*;
public class Ejemplo2
i
public s t a t i c f i n a l i n t MAX = 1 0 0 ;
/ / Número máximo de registros
public static f i n a l i n t FINDATOS = 15;
//Fin de la zona de datos
static InputCtrearnReader isr = new InputCtreamReader
s t a t i c BufferedReader br = new BufferedReader (isr);
s t a t i c Personal2 archivo = n u l l ;
(System.in);
400 Java 2. Manual de Programación
public s t a t i c void main (String[ ] args)
i
try
I
abrir ( ) ;
operaciones ( ) ;
1
catch (IOException e)
i:
1
finally
i
try
i
archivo.cerrar ( ) ;
1
catch ( IOException e)
i }
System.out.println("Error: " t e.toString()) ;
}
public s t a t i c void abrir ( ) throws IOException
1
Empleado2 unEmpleado = null;
archivo = new Personal2 ( ) ;
i f (archivo.longitud()== O)
I
System.out.println("Operación de inicialización") ;
unEmpleado = new Empleado2 ( ) ;
unEmpleado.establecerOcupado(' I ) ;
for ( i n t i = O; i < MAX; it+)
archivo.añadir(unEmpleado);
1
else
System.out .println("Archivo ya existe");
public s t a t i c void operaciones() throws IOException
i:
short opción = O;
boolean error;
do
i
System.out.println("MENÚ") ;
System.out .println("1. Altas") ;
System.out.println ("2. Bajas");
System.out.println ("3. Consultas") ;
System.out.print1n ("4. Fin");
System.out.println();
System.out.print ("ELja opción: " ) ;
do
{
error = false;
try
i
opción = Short.parseShort(new BufferedReader(new
InputStreamReader(Systern.in)).readLine());
1
catch (NumberFormatException ne)
{
System.out .println("Valor no válido "+
error = true;
"(ha de ser un número)");
)
)
while (opción < 1 1 1 opción > 4 1 I error);
switch (opción)
I
case 1: / / altas
altas ( ) ;
break;
bajas ( ) ;
break;
consultas ( ) ;
break;
case 2: / / bajas
case 3: / / consultas
case 4:
1
1
while(opción ! = 4);
)
public static int hash(int código)
{
}
return código % FINDATOS;
public static void altas ( ) throws IOException
{
Empleado2 unEmpleado = null;
int posi = -1;
short código = O;
short edad = O;
String nombre, domicilio, teléfono;
boolean error, encontradoHueco;
char ocupado;
402 Java 2. Manual de Programación
/ * se trata la excepción para que vuelva a pecir el dato
do
i
en caso de error * /
error = false;
try
System.out.print ("código: ' I ) ;
código = Short .parseshort(br.readLine ( ) ) ;
I
catch (NumberFormatException ne)
i
System.out.println ("Valor no válido "+
error = true;
"(ha de ser un número)");
1
while (error);
/ * se comprueba si está libre la posición correspondiente
posi = hash (código);
unEmpleado = archivo.elemento(posi);
encontradoHueco = false;
//si no está libre se busca hueco en la zona dc? colisiones
if (unEmpleado.devolverOcupado ( ) == ' * ' )
en la zona de datos * /
t
posi = FINDATOS - 1;
while (posi < MAX-1 & & !encontradoHueco)
I
posi = posi + 1;
unEmpleado = archivo.elemento (posi);
if (unEmpleado.devolverOcupado ( ) ! = ' * ' )
encontradoHueco = true;
1
i
else
if (encontradoHueco)
i
encontradoHueco = true;
/ / Leer otros campos
System.out.print ("nombre: ' I ) ;
nombre = br.readLine ( ) ;
do
i
error = false;
try
I
System.out.print("edad: ' I ) ;
edad = Short.parseShort(br.readLine());
1
Archivos 403
catch (NumberFormzltException ne)
!
System.out .print:ln("Valor no válido "+
error = true;
" (ha de ser un número)" ) ;
1
i
while (error);
System.out .print("domicilio: " ) ;
domicilio = br .read1,ine( ) ;
System.out .print("teléfono: " ) ;
teléfono = br.readLine0 ;
ocupado = I * ' ; / / s e marca como ocupado
/ * se escribe en la posición posi que puede pertenecer
archivo.ponerelemento(posi, new Empleado2 (código, nombre,
edad, domicilio, teléfono, ocupado)) ;
a la zona de dat'3.s o a la de colisiones * /
1
1
public static void bajas ( ) throws IOException
Empleado2 unEmpleado = null;
int posi = -1;
short código = O;
boolean error, eliminado, encontrado;
do
i
error = false;
try
!
System.out.print ("Código a borrar: " ) ;
código = Short .parseshort(br.readLine ( ) ) ;
i
catch (NumberF0rmatE:xception ne)
i
System.out .printlri("Valor no válido "+
error = true;
"(ha de ser un número)" ) ;
1
i
while (error);
/ / se busca en la zona de datos
posi = hash (código);
unEmpleado = archivo.elemento (posi);
encontrado = false;
if (unEmpleado.devolverOcupado()=='*'
& & unEmpleado.devolverCÓdigo ( ) == código)
else
i
encontrado = true;
404 Java 2. Manual de Programación
/ * si no se encontró en la zona de datos se recorre
secuencialmente la de colisiones para intentar
encontrarlo * /
posi = FINDATOC - 1 ;
while (posi < MAX-1 & & ! encontrado)
t
posi = posi + 1;
unEmpleado = archivo.elemento (posi);
if (unEmpleado.devolverOcupado ( ) == * '
& & unEmpleado .devolverCÓdigo( ) == código)
encontrado = true;
1
1
if ( !encontrado)
else
i
System.out.println ("No esta");
//se marca como libre
unEmpleado.establecerOcupado(' I ) ;
//se escribe en la posición adecuada
archivo.ponerelemento(posi, unEmpleado);
1
public static void consultas ( ) throws IOException
{
Empleado2 unEmpleado = null;
int posi = -1;
short código = O ;
boolean encontrado, error;
do
(
error = false;
try
(
Cystem.out .print ("Introduzca el código a buscar " ) ;
código = Short.parseShort(br.readLine());
}
catch (NumberFormatException ne)
I
Cystem.out.println("Valor no válido "t
error = true;
"(ha de ser un número)");
1
1
while (error);
//se busca el código en la zona de datos
posi = hash (código);
unEmpleado = archivo.elemento (posi);
encontrado = false;
Archivos 405
i f (ünEmpleado.devolver OcJpado ( ) == ' * '
& & unEmpleado.devolverCodigo ( 1 == codigo)
else
encontrado = true;
t
/ * si n3 se encuentri en la zorAa ce datos se recorre
encontrado = f a l s e ;
while (POSI < MAX-1 & & !encontrado)
la de colisiones para inteptar 1ocal;zarlo " /
pos1 = FINDATOS - 1;
I
posi = posi t I;
UnEmpleado = archi.io.eiemento(posi);
i f (unEmpleado.devolverOcupado ( ) == ' * '
& & unEmpleado.devo..verCódigo ( ) == código)
encontrado = true;
1
1
i f ( !encontrado)
else
System.out.println("No está") ;
unEmpleado.mostrar0;
I
/ / Clase Personal2, personal de la empresa.
import java.io.*;
public c l a s s Personal2
i
private RandomAccessFile raf = n u l l ;
private i n t nElementos;
private i n t longReg = 102;
//registros de longitud fija, no se permite que excedan longReg
public Personal2 ( ) throws IOException
i
File arch = new File ("ctrosempleados.dat");
//se abre para lectura/escritura
raf = new RandomAccessFile (arch, "rw");
nElementos = t h i s . longitud ( ) ;
i
public void añadir (Empleado2 obj) throws IOException
i
/ * se utiliza para inicializar el archivo, escribiendo un
determinado número de registros con el campo ocupado a
espacio en blanco.
El archivo crece corforme se le van añadiendo nuevos
elementos.
406 Java 2. Manual de Programación
x /
nZ1emeP. tost + ;
ponere;emento(nElementos, obj);
public void ponerelemento ( i n t 1, Empleado2 unEmp .eado )
throws ICException
i f (1-I>= O & & 1-1 < nElementos)
/ * En el formato UTF-8 los dos primeros bytes indican
el numero de bytes que han de ser leídos a conti-
nuar-on para formar la cadena, como se escriben 3
cadenas en este formato se suman 6 bytes al tamaño
de los campos de datos de unEmpleado * /
//posicionamiento en el lugar adecuado
raf.seeK( (long) (1-1) * longReg);
raf.writeShort(unEmpleado.devolverCódigo() ) ;
raf.writeUTF(unEmpleado.devolverNombre() ) ;
raf.writeShort(unEmpleado.devolverEdad());
raf.writeUTF(unEmpleado.devolverDomicilio0 ) ;
raf.writeUTF(jnEmpleado.devolverTeléfono()i;
raf.writeChar(unEmpleado.devolverOcupado() i ;
1
else
System.out .println("unEmpleado demasiado grande");
Cystem.out .println("No se puede poner e n esa posición");
else
public Empleado2 elemento ( i n t i ) throws IOExcept Lon
lL
i f (i-1 >= O & & i-1 < nElementoc)
t
//posicionamiento de nuevo
raf.seek ( (long) (1-1) * longReg);
s h o r t codigo = raf .readshort ( ) ;
String nombre = raf.readUTF0;
short edad = raf.readShort();
S t r i n g domicilio = raf.readUTF0;
String teléfono = raf.readUTF0;
char ocupado = raf.readChar0;
r e t u r n new Empleado2 (codigo, nombre, edad, domicilio,
teléfono, ocupado);
1
else
i
System.out .println("No hay elementos en esa posición") ;
r e t u r n n u l l ;
Archivos 407
public i n t longitud ( ) throws IOException
return ( i n t )Math.ceil( (double)raf .length ( ) / 1orgReg);
public void cerrar ( ) throws IOException
if (raf ! = n u l l )
raf .close ( ) ;
I
i
/ / Clase Empleado2. Objeto que representa un registro
import java.io.*;
public c l a s s Empleado2
i
/ / campo clave
p r i v a t e short código;
p r i v a t e short edad;
p r i v a t e String nombre, domici1io, teléfono ;
/ / campo para efectuar b31as lógicas, por marca
p r i v a t e char ocupado;
public Empleado2 ( )
i
código = O;
edad = O;
nombre = " " ;
domicilio = " " ;
teléfono = " ' I ;
oc;ipado = ' ' ;
//cadena nula
/*espacio en blanco marca e-
registro como vacio * /
public Empleado2 ( s h o r t cod, String nom, s h o r t annos, Str1r.g
dom, String tfno, char m3rca)
I
código = cod;
nombre = nom;
edad = annos;
domicilio = dom;
teléfono = tfno;
ocupado = marca;
i
public long tamaño ( )
i
/ * tamaño que ocupan los campos de datos. Un short ocspa 2
bytes.
Se utiliza para ver si el tamaño es permitido y no se
excede la 1ongReg establecida * /
return 2 + nombre.length() * 2 + 2 + domicilio.length()*Z
+ teléfono.lengtk,() * 2 + 2;
1
408 Java 2. Manual de Programación
public void establecerOcupado (char marca)
ocupado = marca;
public char devolverocupado ( )
return ocupado;
public void establecerCódigo(short cod)
código = cod;
public short devolvercódigo ( )
return código;
I
public void establecerNombre(Str1ng nom)
nombre = nom;
1
public String devolverNombre()
return nombre;
1
public void establecerEdad(sh0rt annos)
I
edad = annos;
public short devolverEdad0
return edad;
public void estab?ecerDomicilio(String dorn)
1
domicilio = dom;
1
public String devolverDomicilio()
i
return dorn;cillo;
public void establecerTelefono(Ctring tfno)
telkfonc = t f n o ;
Archivos 409
public String devolverTelefono()
I
return teléfono;
I
public void mostrar ( )
I
System.out.println(devolverCódigo());
System.out.println(devolverNombre());
System.out.println devolverEdad0);
System.out.println devolverDomicilio());
System.out.println devolverTelefono());
1
CA 15
Estructuras de datos
definidas por
el programador
CONTENIDO
15.1. Listas.
15.2. Implementación de una lista.
15.3. Lista ordenada.
15.4. Listas genéricas y uso de interfaces.
15.5. Listas doblemente enlazadas.
15.6. Pilas.
15.7. Colas.
15.8. Colas circulares.
rn 411
412 Java 2. Manual de programación
Java, como los restantes lenguajes de programación, suministra
una serie de ti’pos de datos básicos y una serie de operaciones
para su manipulación. En ocasiones, estos tipos de datos no son
los adecuados para resolver un problema y es necesario crear
nuevos tipos de datos, que será preciso definir especificando tanto
sus datos componentes como las operaciones que los manipulan.
Estos tipos de datos se definen mediante clases y proporcionan
una de las características más importantes de la PO0 (Pro-
gramación Orientada a Objetos), la reutilización de componentes.
Las colecciones de datos organizados y a las que se accede de
forma perfectamente definida constituyen una estructura de datos.
Existe un cierto número de estructuras de datos de reconocida uti-
lidad, cuyo uso se repite frecuentemente en los programas, y que
pueden llegar a considerarse como una extensión de los tipos
básicos del lenguaje; estas estructuras tienen un nombre y unas
características establecidas y entre ellas destacan: listas, pilas,
colas, árboles y grabs. Las tres primeras son estructurasde datos
lineales,puesto que en ellas cada elemento tiene un único prede-
cesor y un Único sucesor, mientras que las dos Últimas son estruc-
turas no lineales. En este capítulo se describen estructuras de
datos lineales, ya que las estructuras de datos no lineales quedan
fuera de los objetivos de este libro.
Dada la importancia de las estructuras de datos, Java ofrece
clases que implementan algunas de ellas: java.u t i 1 .vector,
java.util.Stack, java.util.Hastable, java.util.BitSet.
15.1. LISTAS
Una lista es una secuencia de elementos del mismo tipo o clase almacenados en me-
moria. Las listas son estructuras lineales, donde cada elemento de la lista, excepto el
primero, tiene un único predecesor y cada elemento de la lista, excepto el último, tiene
un único sucesor. El número de elementos de una lista se denomina longitud. En una
lista es posible añadir nuevos elementos o suprimirlos en cualquier posición.
Existen dos tipos de listas: contiguas y enlazadas. En una lista contigua los ele-
mentos son adyacentes en la memoria de la computadora y tienen unos límites,
izquierdo y derecho, que no pueden ser rebasados cuando se añade un nuevo ele-
mento. Se implementan a través de arrays. En este tipo de listas la inserción o eli-
minación de un elemento, excepto en la cabecera o final de la lista necesitará una
traslación de parte de los elementos de la misma (Fig. 15.1). Una lista enlazada se
caracteriza porque los elementos se almacenan en posiciones de memoria que no
son contiguas (adyacentes), por lo que cada elemento necesita almacenar la refe-
rencia al siguiente elemento de la lista.
Estructuras de datos definidas por el programador 413
Las listas enlazadas son mucho más flexibles y potentes que las listas contiguas
y, en ellas, la inserción o eliminación (supresión) de un elemento no requiere el des-
plazamiento de otros elementos de la misma.
Las listas enlazadas (Fig. 15.3) se suelen construir vinculando nodos (objetos
que contienen al menos un miembro que es una referencia a otro objeto de su mismo
tipo, Fig. 15.2). Esta forma de organización resulta la más adecuada si el número de
elementos a almacenar en un momento dado es impredecible. Si se utiliza un array
para almacenar una serie o colección de elementos; en el caso de que el número de
elementos exceda el tamaño establecido para el citado array en el momento de su
creación, los nuevos elementos no se podrán almacenar en dicho array y la posible
solución será la creación de un nuevo array de las dimensiones adecuadas y el tras-
paso de la información del viejo al nuevo array. Se ha de tener en cuenta que la clase
Vector de Java permite crear estructuras de datos de tipo array de objetos redi-
mensionables durante la ejecución de un programa. En el caso de utilizar nodos vin-
culados para almacenar la información, éstos se crean y destruyen conforme se
requieran, de esta manera la lista aumenta o disminuye de tamaño dinámicamente y
sólo se llena cuando se agota la memoria disponible. El acceso a la lista se realiza
mediante una referencia al primer nodo de la misma y, para marcar su fin, se esta-
blece la referencia de enlace del último nodo a n u l l .
LLongitud Vacíos Límite
de la lista superior
Límite
inferior
Figura 15.1. Lista contigua.
public clas Nodo
I
Object info;
Nodo sig;
Nodo (Object información, Nodo siguiente)
(
1
info = información;
sig = siguiente;
I
Figura 15.2. Nodo.
414 Java 2. Manual de programación
info sig
I
-+ info sig -+
I
Figura 15.3. Lista enlazada.
xi
Las listas enlazadas se clasifican a su vez en tres tipos: circulares, doblemente
enlazadas y doblemente enlazadas circulares.
xi
Circulares. El Último elemento referencia al primero de la lista (Fig. 15.4).
f i n
Figura 15.4. Lista enlazada circular.
Doblemente enlazadas. Su recorrido puede realizarse tanto desde frente a
final como desde final a frente.Cada nodo de dichas listas consta de un
miembro con información y otros dos que referencian objetos de su mismo tipo
( a n t y sig),uno para referenciar al nodo sucesor y otro al predecesor (Fig. 15.5).
7~~
tina1
frente
I I
xrl
Figura 15.5. Lista doblemente enlazada.
Listas doblemente enlazadas circulares. En este tipo de listas el miembro a n t
del primer nodo de la lista referencia, o apunta, al último nodo y el miembro sig
del último nodo al primero (Fig. 15.6).
Estructuras de datos definidas por el programador 415
inicio
Figura 15.6. Lista doblemente enlazada circular.
Resumen: Una lista enlazada se caracteriza porque los elementos se almace-
nan en posiciones de memoria que no son contiguas o adyacentes. Cada ele-
mento necesita almacenar al menos una referencia al siguiente elemento de la
lista. En una lista enlazada la inserción o eliminación (supresión) de un ele-
mento no requiere el desplazamiento de otros elementos de la misma.
Importante: Una lista enlazada que se implementa vinculando nodos aumen-
ta y disminuye de tamaño dinámicamente.
I
15.2. IMPLEMENTACIÓN DE UNA LISTA
Los métodos básicos que necesitaría implementar una lista son los especificados en
la clase Lista:
El constructor Lista crea una lista vacía asignando el valor n u l 1al miem-
bro privado inicio que contiene la referencia al primer nodo de la lista.
El método vacia determina si la lista esta vacía comprobando si la referen-
cia al primer nodo de la lista es null.Devuelve true cuando la lista está
vacía y f a1se en caso contrario.
El método insertarprincipio crea un nuevo nodo donde almacena una
referencia al objeto que recibe como parámetro y otra al inicio de la lista,
por último asigna a inicio el nuevo nodo y convirtiéndolo así en el primer
elemento de la lista.
El método borrarprincipio guarda en auxi la referencia al primer nodo
de la lista, y quita éste nodo de la lista, asignando a inicio la referencia al
siguiente nodo de la lista, contenida en inicio.sig;por Último, devuelve
la referencia al nodo que se ha quitado (auxi).
416 Java 2. Manual de programación
public class Lista
i
private Nodo inicio;
Lista ( )
i
inicio = null;
public boolean vacía ( )
(
1
return (inicio == null);
public void insertarPrincipio(0bject elemento)
Nodo nuevoNodo = new Nodo (elemento, inicio);
inicio = nuevoNodo;
}
public Nodo borrarPrincipio0
(
if (vacía( ) )
t
return null;
1
else
I
Nodo auxi = inicio;
inicio = inicio.sig;
return (auxi);
I
1
public void mostrarLista ( )
i
Nodo actual = inicio;
while (actual != null)
(
actual.rnostrarNodo0;
actual = actual.sig;
1
I
public class Nodo
i
public Object info;
public Nodo sig;
Estructuras de datos definidas por el programador 417
public Nodo (Object información, Nodo siguiente)
I
info = información;
sig = siguiente;
1
public void mostrarNodo ( )
t
1
System.out.println(info);
}
public class Prueba
I
public static void main (String[] args)
t
Lista unaLista = new Lista ( ) ;
unaLista.insertarPrincipio(new Integer(1));
unaLista.insertarPrincipio(new Integer(2));
unaLista.mostrarLista();
while (!unaLista.vacía())
I
Nodo unNodo = unaLista.borrarPrincipio0;
unNodo.mostrarNodo0;
1
unaLista.mostrarLista();
1
En la implementación expuesta, la inserción de un nuevo elemento se efectúa
siempre por el principio de la lista y la supresión también. En muchas ocasiones
esta situación no es la deseada, y lo que se desea es buscar o suprimir un ele-
mento determinado. Estas acciones requieren añadir métodos que permitan la
búsqueda y el borrado de elementos con un determinado valor en un campo de
datos clave.
15.3. LISTA ORDENADA
Una lista está ordenada cuando sus elementos están organizados, en orden cre-
ciente o decreciente, por el contenido de uno de sus campos de datos. Para que
una lista resulte ordenada es probable que la inserción de nuevos elementos
requiera colocarlos en posiciones intermedias de la misma (Fig. 15.7). Las listas
enlazadas realizan este tipo de inserciones más eficientemente que las contiguas,
al no ser necesario para insertar un nuevo elemento desplazar ningún otro de la
lista. También resultan más rápidas las operaciones de supresión de elementos en
posiciones intermedias mediante el empleo de este tipo de listas (Fig. 15.8).
418 Java 2.Manual de programación
i n f o s i g
I
i n i c i o
...... *
........--c i n f o s i g --+ i n f o s i g -+
I I
x
I
i n f o s i g
i
L .t
........
I I
-+ i n f o s i g -+ i n f o s i g --+
I x2 I
xi
I
Xi X3
nullI xn I
Figura 15.7. Inserción de un nuevo elemento en una posición intermedia de la lista.
i n i c i o ............................................
Figura 15.8. Supresión de un elemento en una posición intermedia de la lista.
< . ,
l n l C l O .................. ~
I
- 1 I / I r I
Figura 15.9. Supresión del primer elemento de la lista en una lista
con varios elementos.
Estructuras de datos definidas por el programador 419
, . .
lnlCIO .........................
Figura 15.10. Supresión del primer elemento de la lista
en una lista con un único elemento.
La clase Listaordenada muestra las operaciones básicas para necesarias para
trabajar con una lista encadenada ordenada construida mediante vinculación de
nodos. Estas operaciones san:
El constructor Listaordenada crea una lista vacía, asignando el valor
null al miembro privado inicio que contiene la referencia al primer
nodo de la lista.
El método vacia comprueba el valor de inicio y devuelve true cuando
la lista está vacía, es decir, cuando la referencia al primer nodo es null.y
false en caso contrario.
El método insertarcrea un nuevo nodo de la clase Nodo2,capaz de alma-
cenar un entero, una cadena y la referencia a otro objeto de su misma clase, y
almacena en dicho nodo la clave y el nombre a insertar.El método utili-
za una variable de la clase Nodo2 para recorrer la lista hasta que esta se acabe
o encontrar un elemento con clave menor o igual al que se desea insertar. En
otra variable, anterior,de la clase Nodo2 guarda en todo momento la refe-
rencia al elemento anterior al que en ese momento está siendo visitado. Cuando
termina el recorrido inserta el nuevo nodo a contiuación del anterior.Si el
anterior es null,puede significar que la lista está vacía o que la clave del
primer elemento de la misma es menor o igual a la del nuevo y, en ambos casos,
dicho nuevo elemento ha de situarse al comienzo de la lista.
El método borrar intenta suprimir de la lista un elemento cuyo campo
clave almacena un determinado valor. Para ello, recorre la lista buscando el
elemento, de forma análoga a la indicada para la inserción,empleando
también las variables actual y anterior.Si encuentra el elemento y es el
primero, hace que inicio referencie al siguiente nodo de la lista, mientras
que si lo encuentra en cualquier otra posición, lo que hace es que el campo
sigdel elemento anterior referencie al elemento siguiente (actual.cig).
El método mostrarLista utiliza la variable actual para efectuar un recorri-
do de la lista y presentar la información almacenada en cada uno de sus nodos.
420 Java 2. Manual de programación
//lista ordenada descendentemente
public class Listaordenada
i
private Nodo2 inicio;
Listaordenada ( )
i
1
inicio = null;
public boolean vacía ( )
return (inicio == null);
1
public void insertar (int clave, String nombre)
i
Nodo2 nuevoNodo = new Nodo2 (clave, nombre);
Nodo2 anterior = null;
Nodo2 actual = inicio;
boolean pasado = false;
/ * recorre la lista hasta encontrar un elemento con clave menor
while (actual ! = null & & ! pasado)
i
o igual al que se desea insertar * /
if (clave < actual.clave)
i
anterior = actual;
actual = actual.sig;
1
else
pasado = true;
I
/ * inserta el nuevo elemento a continuación de anterior,
si el anterior era null significa que ha de insertarse
al comienzo de la lista * /
if (anterior == null)
inicio = nuevoNodo;
else
anterior.sig = nuevoNodo;
nuevoNodo.sig = actual;
i
public Nodo2 borrar (int clave)
i
Nodo2 anterior = null;
Nodo2 actual = inicio;
boolean encontrado = false;
/ / se recorre la lista buscando el elemento
while (actual ! = null & & !encontrado)
i
Estructuras de datos definidas por el programador 421
if (clave == actual.clave)
else
encontrado = true;
I
anterior = actual;
actual = actual.sig;
I
1
/ / si se encuentra se borra
if (encontrado)
/ * si es el primero se hace que inicio referencie al
siguiente elemento de la lista, si no lo que se
hace es que el campo sig del elemento anterior
referencie al elemento siguiente * /
if (anterior == null)
else
return (actual);
inicio = actual.sig;
anterior.sig = actual.sig;
i
return null;
public void buscar (int clave)
1
Nodo2 anterior = null;
Nodo2 actual = inicio;
boolean er.contrado = false;
//se recorre la
while (actual !
i
if (clave ==
encontrado
else
!
anterior =
lista buscando el elemento con dicha clave
= nuii & & !encontrado)
actual.clave)
= true;
actual;
actual = actual.sig;
1
/ / si se encuentra se muestra
if (encontrado)
else
actual.mostrarNodo0 ;
System.out.println (“No esta”);
1
public void mostrarlista 0
i
Nodo2 actual = iniCi0;
while (actual ! = null)
422 Java 2. Manual de programación
actual.mostrarNoao();
actual = actual.sig;
public class Nodo2
public int clave;
public String nomlsre;
public n'odo2 sig;
public Nodo2(int cl, String n)
clave = cl;
nombre = n;
slg = null;
public void mostrarNodo ( )
Cyster.out .println ("Clave: "- clave+" Nombre "+nombre);
I
public class P r ~ e b a 2
i
public static void main (CtrinqI ] args)
Listaordenada u n a i i s t a = new ListaOrdenadaO;
ur.aLista.insertar (4, "Pedro");
unaUicta.insertar (1, "Luis");
unaLista.insertar (8, "Tomas");
;naLista.mostrarLista();
/ / . * .
15.4. LISTAS GENÉRICASY USO DE INTERFACES
A diferencia de la clase Lista,la clase Listaordenada creada en el apartado
anterior es demasiado específica, ya que sólo puede almacenar un tipo entero y una
cadena. Para arreglar situaciones como ésta y que una lista pueda almacenar datos
de cualquier clase, los métodos de la lista deberán trabajar con la superclase
Ob] ect.Esta estructura permitirá, siempre que se efectúen las conversiones ade-
cuadas, utilizar la lista para almacenar objetos de distinta clase. Se ha de tener pre-
Estructuras de datos definidas por el programador 423
sente que Java convierte implícitamente una referencia a un objeto de una subclase
en una referencia a su superclase y también que es conveniente que en un objeto
listu sólo se almacenen datos homogéneos, de una misma clase.
En la clase L i s taordenada,se requiere en ocasiones efectuar comparaciones;
por ejemplo, para encontrar un determinado elemento en una lista, dado que las lis-
tas genéricas pueden almacenar toda clase de objetos, debe dejarse a los tipos de
datos la iinpleinentación de los métodos de comparación. Como ya se ha comenta-
do en ocasiones anteriores, esta característica se consigue definiendo una interfaz,
Comparable y declarando la información almacenada en el nodo, en lugar de per-
teneciente a la clase Object,como perteneciente a la interfaz Comparable.Así,
para construir una L i s taOdenadaGenerica y utilizarla para almacenar en ella
una serie de libros ordenados por el ISBN se requiere:
Definir la interfaz de comparación; en este caso, concebida para admitir varios
criterios de ordenación.
interface ComFarabLe
{
boolean mencrque (Co-,parablec, int cr:teric) throws Exceptiun;
Declarar Comparable el campo de datos del nodo, i n f .
/ / Ncdo comparable
public class Nodo3
private Comparable inf;
private Ku'ado3 sig;
Nodo3 (comparable información, Ncdo3 sigu-ente)
inf = informacicn;
c i g = siguiente;
. . .
1
Diseñar la lista de forma que sus inétodoc trabajen con Comparable.
//Lista enlazada ordenada estandar para Copparables
public class L-staCdeoadaSenerica
I
private int c r i t e r i o ;
424 Java 2. Manual de programación
private Nod03 primero;
ListaOdenadaGenerica(int criterio)
i
primero = null;
this.criterio = criterio;
i
/ / . ..
public void insertar(Comparab1e elemento) throws Exception
i
1
/ / . . .
public Comparable obtener(Comparab1e elemento) throws Exception
t
/ / . ..
1
/ / . . .
Hacer que los tipos de datos a colocar en la lista implementen los métodos de
comparación. Así, para construir una lista de libros ordenada por ISBN, la
clase Libro debe implementar el método menorque.
class Libro implements Comparable
i
private String autor;
private String titulo;
private long ISBN;
public Libro(String a, String t, long i)
t
autor = a;
titulo = t;
ISBN = i;
1
public booiean menorque(Comparab1e c, int criterio) throws Exception
{
Estructuras de datos definidas por el programador 425
if ( ! (c instanceof Libro) )
t
throw new Exception ("Error de comparación");
i
return( ( (Libro)c ) .ISBN < ISBN);
1
public String devolverAutor ( )
t
return (autor);
I
public String devolverTitulo ( 1
(
return(titu1o) ;
i
public long devolverISBN ( )
I
1
return (ISBN);
íjercicio
Diseñar una clase ListadeLibros, que permita efectuar la gestión de una
biblioteca.
La clase ListadeLibros representa un array unidimensional cuyos elemen-
tos son listas enlazadas ordenadas de la clase ListaOrdenadaGenerica y ten-
drá métodos para efectuar el almacenamiento, recuperación y eliminación de los
libros. Los libros se almacenan por inicial de título e ISBN. La inicial del título
( a - z ) determina la posición en el array unidimensional donde será colocado
el libro. Como cada elemento del array es una ListaOrdenadaGenerica, los
libros que comiencen por la misma inicial serán situados en la correspondiente lista
enlazada ordenados por ISBN.
426 Java 2.Manual de programación
z
Figura 15.11. La clase Lista enlazada.
Los aspectos más importantes en cuanto a genericidad de la clase
ListaOrdenadaGenerica acaban de ser comentados, ya que esta clase ha sido
puesta como ejemplo para exponer las características de las listas genéricas. Por otra
parte, ListaOrdenadaGenerica es una lista ordenada y los métodos
estaliacia,insertar y elimina funcionan de manera similar a los ya expli-
cados (vacia,insertar y borrar)de la clase Listaordenada,excepto por
el empleo del método menorque,en lugar de un operador relacional, para efectuar
las comparaciones entre los elementos de la lista y el elemento a insertar o eliminar.
Otros detalles se especifican en el código como comentarios.
Como ListadeLibros representa un array cuyos elementos pertenecen a la
clase ListaOrdenadaGenerica,su constructor crea e inicializa el array, cre-
ando cada uno de sus objetos, de la clase ListaOrdenadaGenerica.El méto-
do guardar: 1) llama al método 1ista y le pasa como parámetro el título del
libro, para que lista determine por la inicial del título la posición en el array de la
lista donde el libro debe ser insertado; 2) invoca al método insertar de
ListaOrdenadaGenericapara que efectúe la inserción. Los métodos recuperar
y eliminar también recurren a lista para determinar la posición en el array de
la lista donde el libro a consultar o suprimir debe encontrarse situado; la diferen-
cia entre ambos es que recuperar una vez localizada la lista llama a obtener para
que encuentre el elemento dentro de la misma, mientras eliminar llama a eli-
mina para que suprima dicho elemento de la lista.
Estructuras de datos definidas por el programador 427
Otras clases e interfaces implementadas son:
NOd03.Clase de los nodos de la ListaOrdenadaGenerica.
Libro.Clase que implementa la interfaz Comparable.
Comparable.Interfaz de comparación.
NoEsta.Excepción general de búsqueda.
PruebaL.Clase de prueba para comprobar el buen funcionamiento del
ejercicio.
p u b l i c class ListadeLibros
i
/ / Tamaño del array de indexación
f i n a l s t a t i c i n t 1 = 'z'-'a'+l;
/ / Declaración del array de Indexación
p u b l i c ListaOrdenadaGenerica[] libros;
/ * Constructor: Inicialización del array de indexación asi
como de sus elementos lista.
La ordenación en cada una de las listas se efectúa
ascendentemente por el ISBN y carece de valor el
parámetro pasado a ListaOrdenadaGenerica * /
p u b l i c ListadeLibros ( )
I
libros = new ListaOrdenadaGenerica[l];
f o r ( i n t i=O; i<libros.length; it+)
libros [i] = new ListaOrdenadaGenerica ( O ) ;
1
/ / Simple conversión de clave Titulo-->no de lista
i n t lista (String titulo)
i
r e t u r n ( (titulo.toLowerCase( ) ) .charAt(O)-'a');
/ / No de libros
i n t nlibros ( )
!
i n t c = O ;
f o r ( i n t i = 0;i < 1ibros.length; i + + )
420 Java 2. Manual de programación
c += libros [i].nelems( ) ;
return(c) ;
1
/ / Método para el almacenamiento
public void guardar (Libro libro)
{
try
I
1
catch(Exception e) { )
libros[lista(libro.devolverTitulo())].insertar(libro);
/ / Se intercepta la posible excepción de insertar
/ / Método para la recuperación (vea class NoEsta)
public Libro recuperar (String titulo, long ISBN) throws NoEsta
{
Libro nuevo = null;
try
{
nuevo = (Libro)libros [lista(titulo)] .obtener( new
Libro ( " " , titulo,ISBN)) ;
}
catch (Exception e) { )
/ * Nótese la necesidad de 'downcasting' Dado que la lista
es estándar para objetos 'comparables'(vea interface
Comparable) hay que realizar una inevitable conversión
a Libro.
Nótese también que puesto que en este método se conoce
la integridad de la lista que se maneja(todos sus obje-
tos son Librono se realiza comprobación de seguridad
para este downcasting (al contrario que en la clase
Libro) * /
if (nuevo == null)
return(nuev0) ;
throw new NoEsta ( ) ;

/ / Metodo para la elirninaciÓn(vea class NoEsta)
public void eliminar (String titulo, long ISBN
(
try
{
1
libros [lista(titulo)].elimina(new Libro ( " " titulo,ISBN)) ;
Estructuras de datos definidas por el programador 429
catch(Exception e) { }
private int criterio;
private Nodo3 primero;
ListaOrdenadaGenerica(int criterio)
t
prir,ero = null;
this.criterio = criterio;
1
/ / Informa sobre si la lista está o no vacia
public boolean estavacia ( )
t
return (primero == null);
/ / No de elementcs
public int nelemc ( )
int n = C;
~ o d o 3aux = primero;
while (aux ! = null)
I
aux = aux.devolversiguiente ( ) ;
ni+;
return(n);
/ * Método para inserción. Ei hecho de que se permita arrojar
una excepción es debido a que se puede Lntentar incrod>Jc:r
comparables de métodos menorque incompatibles lo qi;e daria
un primer aviso aquí * /
public void insertar(Comparab1e elernentc) throws ExceptLon
Nodo3 nuevo = new Nodo3(eleme~to,null);
Nodo3 a7Jxl = null;
Nodo3 aux2 = primero;
while (aux2 ! = null & & aux2 .?~enorq~.e(nuevo,cr:terio) )
430 Java 2. Manual de programación
acxl = aux2;
a.Gx2 = aux2.devolversiguiente ( ) ;
/ * Obsérvese la importancia del & & en cortocircuito que
eviza problemas dado el posterior acceso al método menorque.
Obsérvese también la peculiar simplificación de la
sirtaxis i2plementando un método menorque en Nodo3
(vea -;ass Nodo3) * /
n.~ev3.asignarCigüiente(aux2);
if (aLxl == null)
else
pri;-.ero= ~ . u e v o ;
a u x l . asignarsigciente (nuevo);
/ / Dletodo para BIuscpeda (ver comentario sobre throws en insertarj
public Corparable obtener(Comparab1e elemento) throws Exception
//* ;Comparanos nodo con nodo o valor con valor? A práctica
iqlialdad s-stemática se opta por lo mas fácil * /
Nodc3 nuevc = new Nodo3(elernento, null);
Ncao3 dux = primero;
while(aJx ! = null & & aux.menorque (nuevo,criterio)j
if (aux ! = null & & !nuevo.menorque (aux,criterio))
aux = acx.devolversiguiente ( ) ;
return(aux.devolverValor());
1 " Si el uno no es menor que el otro y el otro r.o es
/ * Obsfrvese zambiér. la importancia del & & en cortocir-
menor que el uno: son iguales: (a<b & a>b)<=>b=a * /
c ~ i t odado el posterior uso del método menorque
(vea Libro.menor que) que lanzarla una excepcijr. * /
else
return (null);
* Yetodo para eli-inacion (ver comentario sobre throws er.
irsertar) * /
public void eliiina(Comparab1e elemento) throws Exception
N o m ? aeliiinar = new Rod03 (elemento, null);
?&ceo3 auxl = null;
Nodo3 a¿ix2 = primero;
Estructuras de datos definidas por el programador 431
while (aux2 ! = n u l l & & aux2.menorque (aeliminar, criter:~) )
auxl = aux2;
acx2 = aux2.devolverSiguiente();
i f (aux2 ! = n u l l & & !aeliminar.menorque(aux2, criterio))
i f ( a u x 1 == n u l l )
else
primero = n u l l ;
auxl .asignarsiguiente (aux2.devolversiguiente ( 1 ) ;
1
/ * Nodo3 comparable que implementa la facilidad adicicial
de delarce comparar por el mismo sin-plif,randc l a sintaxis * /
p u b l i c class Nodo3
p r i v a t e ComparabLe inf;
p r i v a t e n’odo3 c i g ;
Nodo3 (Comparable información, Nodo3 sig,;iente)
i
:nf = información;
sig = sig¿iiente;
I
p u b l i c Comparable devolvervalor()
i
r e t u r n (inf);
p u b l i c Nodo3 devolverCigaiente ( 1
r e t u r n (cig);
1
p u b l i c void asignarvalor (Comparable ir.formacio~.)
inf = infornación;
p u b l i c void asignarSiguiente(Nodo3 siguiente)
i
s;g = ciguierte;
432 Java 2. Manual de programación
boolean menorque (Nodo3 c, int criterio) throws Exception
t
return(inf.menorque(c.inf, O) ) ;
/ / Objeto comparable Libro
class Libro implements Comparable
private String autor;
private String titulo;
private long ISBN;
public Libro(Ctring a, String t, long i)
I
autor = a;
titulo = t;
ISBN = i;
public String devolverAutor ( )
return (autor);
public String devolverTitulo ( )
I
return(titu1o);
1
public long devolverICBN ( )
t
return (ISBN);
/ * Método obligado para comparables, como se indica en la
interfaz el campo criterio no sera utilizado en este caso * /
public boolean menorque(Comparab1e c, int criterio) throws
Exception
if ( ! (c instanceof Libro))
return ( ( (Libro)c) .ISBN<ISBN);
throw new Exception ("Error de comparación") ;
1
Estructuras de datos definidas por el programador 433
/ * Interfaz básico estándar de comparación. Es la base sobre la
que se implementa cualquier ordenación o búsqJeda. A r n q u e en
principio está concebido para admitir varios cr;terics de
ordenación en este caso el campo criterio no será usado * /
interface Comparable
boolean menorque(Comparab1e c, i n t criterio) throws Excepzion;
1
/ / Excepción estándar general de bjsqueda
c l a s s NoEsta extends Exception
i
public NoEsta ( )
super ("No se encuentra el libro") ;
/ / Una prueba simple para la biblioteca ListadeLibros
public c l a s s PruebaL
i
public s t a t i c void main (String[ ] args)
i
/ / Inicializa un objeto ListadeLibros
ListadeLibros 1 = new ListadeLibros 0;
/ / Crea dos objetos Libro aimacenándolos después
Libro librol = new Libro ("Chesterton",
"El padre Brown",471193089);
Libro libro2 = new Libro ("Froid",
"Die Traumdeutung",1571690956);
1.guardar (librol);
1.guardar (libro2);
/ / ?rr;ieba su recuperación
t = Y
!
Libro nuevo: = i.recuperar ("Si padre Rrcw::", 6711333E9);
Librc r.uevo2 = 1.recuperar("Die :raundeut~~y",15?1CYV93%) ;
434 Java 2. Manual de programación
........................
...... a n t i n f s i g ......................
Sycrerr.out.print ("En Stock: " ) ;
Sycrem.out.printlr (1.nlibrosO ) ;
Sys:em.out.println(nuevol.devolverTitulo()+
" : "+nuevol.devolverAutor ( ) ) ;
System.ouz.prLntln(nuevo2.devolverTitulo()+
" : "+nuevo2.devolverAutor ( ) ) ;
Cycrem.in.read ( ) ;
a n t i n f sig
I
catch (Exception e ) { 1
/ / 3 o r r a ;no de los libras
1.eliainar ("El padre Brown",471193089);
System.olit.print("En Stock: " ) ;
Systern.c;lt. p r i n t l n (1.nlibros( ) ) ;
catch (Exception e) { I
15.5. LISTAS DOBLEMENTE ENLAZADAS
Se caracterizan porque su recorrido puede realizarse tanto desde frente a final
como desde frente a final.Este tipo de listas se suele construir vinculando
nodos. Cada nodo de dichas listas consta de un campo con información y otros dos
campos (ant y s i g ) que referencian el nodo antecesor y el sucesor respectiva-
mente. Además en una lista doblemente enlazada, cada nodo, excepto el primero y
el último, se encuentra referenciado por otros dos, su sucesor y su antecesor.
Figura 15.12. Inserción de un nuevo elemento al principio de una lista doblemente
enlazada.
Estructuras de datos definidas por el programador 435
En la operación de inserción será necesario tener en cuenta si se trata del primer
elemento de la lista; en caso contrario, el nuevo elemento ha de colocarse por delan-
te del primero, en una posición intermedia o al final. La supresión debe contemplar
si se desea eliminar un elemento al principio de la lista, en el medio o ai final, y ade-
más la posibilidad de que la lista conste de un único elemento y quede vacía tras su
eliminación.
15.6. PILAS
Una pila es una lista que tiene establecidas ciertas restricciones en cuanto a la forma
de extraer o colocar en ella nuevos elementos. La pila se utiliza siempre que se
desea recuperar una serie de elementos en orden inverso a como se introdujeron. La
extracción de un elemento de una pila se realiza por la parte superior, de igual forma
que la inserción. Esta propiedad implica que el único elemento accesible de una pila
es el último. Estas estructuras se denominan LIFO (Last Input First Output),
((últimoelemento que se pone en la pila es el primero que se puede extraer)).
Las pilas se pueden implementar vinculando nodoc y también mediante arrays,
utilizando una variable auxiliar, cima,que apunte al Último elemento de la pila.
En realidad, en Java no es necesario definir la clase Pila,ya que en el paquete
java.uti1 viene la clase Stack (pila). La clase Stack hereda de Vector,ya
que una pila se puede implementar con eficiencia mediante una tabla que no tiene
tamaño fijo. Los métodos proporcionados por Stack son:
public boolean empty ( )
Comprueba si la pila está vacía
public synchronized java.lang.Cbject peek()
Consulta el elemento situado en la cima de la pila, sin quitarlo de ésta. Si la pila está vacía,
devuelve una excepción EmptyStackException.
public synchronized java.lang.Object pop ( )
Quita el objeto situado en la cima de la pila y lo devuelve como resultado de la función. Si
la pila está vacía, devuelve la excepción anteriormente mencionada.
public java.lang.Object push(java.lang.0bject obj)
Coloca un nuevo elemento en la cima de la pila.
public synchronized int search(java.lang.0bject obj)
Devuelve la distancia existente desde la cima de la pila hasta la posición donde el objeto,
obj,se encuentra situado o -1 si el objeto no está en la pila.
public Stack ( )
Constructor.
436 Java 2. Manual de programación
vacía se coloca un elemento se coloca otro elemento se quita un elemento
cima = 2.
cima = 1
...
...
...
3
2
1
Figura 15.13. Pila implementada con vector
La implementación de una pila utilizando nodos vinculados requiere el diseño
de los métodos:
.
.
Se
Pila,el constructor. Crea una pila vacía asignando null al miembro pri-
vado cima que contiene la referencia a la cima (tope)de la pila.
vacia.Determina si la pila está o no vacía comprobando el valor de cima;
devuelve true cuando el valor de cima es null y false en caso contra-
rio.
apilar.Añade un nuevo elemento en la cima de la pila, es decir, crea un
nuevo nodo cuyo campo sig referencia la cima de la pila y a continuacitn
asigna a cima el nuevo nodo.
desapilar.Comprueba que la pila no está vacía, suprime el nodo de la cima
haciendo que cima pase a referenciar al siguiente nodo, o a null si la pila se
ha quedado vacía, y devuelve el objeto perteneciente al nodo eliminado.
obtenercima.Devuelve el objeto almacenado en la cima de la pila.
podría efectuar de la siguiente forma:
public class Pila
private Nodo4 cima;
P i l a ( )
I
cima = null;
1
public boolean vacía ( )
return (cima == null);
I
Estructuras de datos definidas por el programador 437
public void apilar(0bject elemento)
{
cima = new Nodo4(elemento, cima);
public Object desapilar ( ) throws Exception
{
i f (vacía( ) )
Object aux = cima.inf;
cima = cima.sig;
return aux);
throw new Exception ("Pila Vacia");
1
public OLject obtenercima ( ) throws Exception
i
i f (vacía( ) )
return (cima.inf);
throw new Exception ("Pila Vacia") ;
1
public c l a s s Nodo4
i
Object inf;
Nod04 sig;
Nodo4 (Object información, Nod04 siguiente)
i
inf = información;
sig = siguiente;
1
//La información se muestra en orden inverso al de introducción
import java.io.*;
public class PruebaP
I
public s t a t i c void main (String args [ ] )
i
String cadenai, cadenaf;
Pila p = new Pila();
System.out .println("Prueba");
System.out.println ("Escriba una palabra:") ;
try
I
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader bf = new BufferedReader (is);
cadenai = bf .readLine ( ) ;
438 Java 2. Manual de programación
for (int i = O; i < cadenai.length(); i+t)
cadenaf = "";
for (int i = O; i ¿ cadenai.length 0 ; it+)
p.apilar (new Character (cadenai.charAt(i)) ) ;
cadenaf = cadenaf + ( (Character)p.desapilar ( ) ) .
charvalue ( ) ;
System.out .println(cadenaf);
1
catch(Exception e) i 1
Cuando un programa llama a un subprograma, se utilizan internamente pilas
para guardar el lugar desde donde se hizo la llamada y el estado de las variables en
ese momento.
Entre las aplicaciones de las pilas destacan: 1) Su uso en la transformación de
expresiones aritméticas de notación injija apostfija' y en la posterior evaluación de
la expresión. 2) Su utilización para la transformación de algoritmos recursivos en
iterativos.
15.7. COLAS
Una cola es una estructura de datos lineal en donde las eliminaciones se realizan por
uno de sus extremos, denominadofrente, y las inserciones por el otro, denominado
final. Se las conoce como estructuras FIFO (First Input First Output). La cola de un
autobús o de un cine son ejemplos de colas que aparecen en la vida diaria. La cola
se podrá implementar mediante un array unidimensional, usando la clase Vector
o utilizando nodos vinculados.
Cuando se implementa con un array (Fig. 15.14) se utilizan dos variables nu-
méricas, primero y último,para marcar el principio yfinal de la cola; como
los elementos se añaden por el final y se quitan por el principio, puede ocurrir que
la variable último llegue al valor máximo del array, aun cuando queden posi-
ciones libres a la izquierda de la posición primero (Fig. 15.15). Existen diver-
sas soluciones:
' Una de las tareas que realiza un compilador es la evaluación de expresiones aritméticas. En la mayo-
ría de los lenguajes de programación las expresiones aritméticas se escriben en notación infiju, que son aque-
llas en las cuales el símbolo de cada operación binaria se sitúa entre los operandos: 4 * (3+5). Muchos
compiladores transforman estas expresiones irzfijas en notación po.s?fij~~,en la cual el operador sigue a los
operandos (oprefija, en la cual el operador procede a los operandos) y a continuación generan instrucciones
máquina para evaluar esta expresión postfija: 4 3 5 + *. Nunca se necesitan paréntesis para escribir expre-
siones en las notaciones posífija y prefija.
Estructuras de datos definidas por el programador 439
Retroceso Consiste en mantener fijo a 1 el valor de primero, realizando un
desplazamiento de una posición para todas las componentes ocu-
padas cada vez que se efectúa una supresión.
Reestructuración Cuando último llega al máximo de elementos se desplazan las
componentes ocupadas hacia atrás las posiciones necesarias para
que el principio coincida con el principio de la tabla.
Un array circular es aquel en el que se considera que la compo-
nente primera sigue a la componente última.
Mediante un array circular
primero último MAX
Figura 15.14. Cola implementada con array.
primero último I
MAX
Figura 15.15. Cola implementada con un array tras una serie de operaciones
de adición y sustracción de elementos.
La clase Vector de Java, así como la creación de una cola utilizando nodos
vinculados evitan los problemas originados por MAX en las implementaciones con
arrays.
Las operaciones típicas en una cola son: crear la cola, comprobar si la cola está
o no vacía, poner elementos en la cola por el,final, quitar elementos por elfrente y
obtener el objeto situado en e1,frente de la misma. En la implementación de una
cola utilizando nodos vinculados que se efectúa a continuación los métodos que
realizan las mencionadas tareas se denominan respectivamente: Cola, vacía,
poner, quitar y obtenerprimero.Los miembros privados primero y
último guardan la información sobre elfrente yJinal de la cola; inicialmente, el
constructor asigna null a ambos.
440 Java 2. Manual de programación
El método vacia comprueba si queda algún elemento que se pueda extraer de
la cola consultando primero y si el valor de primero es null devuelve
truepara indicar que la cola está vacía, en caso contrario devuelve false.
El método poner se encarga de añadir nuevos elementos a la cola por el
final; para ello, comienza por comprobar si la cola está vacía, si esto ocurre,
será necesario que primero referencie al nuevo elemento, en caso contra-
rio será el elemento referenciado por u1t imo,a través de su campo si g ,
quien establezca un vínculo con el nuevo elemento, el método poner termi-
na asignando a u1timo el nuevo elemento.
El método quitar,si la cola no está vacía, asigna a una variable aux el
objeto alamacenado en el campo inf del primer elemento, después hace que
primero referencie al nodo referenciado por el campo si g de dicho primer
elemento, si la cola se ha quedado vacía y primero es null asigna tam-
bién null a ultimo,en cualquier caso, cuando la cola no está vacía,
devuelve aux.
El método obtenerprimero devuelve el objeto referenciado por el campo
info del elemento referenciado por primero.
public class Cola
t
private Nodo4 primero;
private Nodo4 ultimo;
Cola ( )
{
primero = null;
ultimo = null;
1
public boolean vacía ( )
{

return (primero == null) ;
public void poner (Object elemento)
t
Nod04 aux = new NOdO4(elemento, n u l l ) ;
i f (vacía( ) )
else
ultimo = aux;
primero = aux;
u1timo.si.g = aux;
1
public Object quitar ( ) throws Exception
{
i f (vacía( ) )
Object aux = primero.inf;
throw new Exception ("Cola vacía");
Estructuras de datos definidas por el programador 441
primero = primero.sig;
if (primero == n u l l )
ultimo = n u l l ;
return (dux);
)
public Object obtenerprimero0 throws Exception
I
if (vacia( ) )
return (primero.inf);
throw new Exception ("Cola vacía") ;
1
public class Nodo4
i
Object inf;
Nodo4 sig;
Nodo4 (Object información, Nodo4 siguiente)
i
inf = información;
sig = siguiente;
1
1
Una aplicación de las colas es una cola de impresión. En un sistema de tiempo
compartido suele haber un procesador central y una serie de periféricos comparti-
dos: discos, impresoras, etc. Los recursos se comparten por los diferentes usuarios
y se utiliza una cola para almacenar los programas o peticiones de los diferentes
usuarios que esperan su turno de ejecución. El procesador central atiende, normal-
mente, por riguroso orden de llamada del usuario; por tanto, todas las llamadas se
almacenan en una cola. Existe otra aplicación de las colas muy utilizada, la cola de
prioridad; en ella el procesador central no atiende por riguroso orden de llamada,
sino por las prioridades asignadas por el sistema o bien por el usuario, y sólo den-
tro de las peticiones de igual prioridad se producirá una cola.
Resumen: En realidad las pilas y las colas son listas que tienen establecidas
ciertas restricciones en cuanto a la forma de extraer o colocar en ellas nuevos
elementos:
La extracción de un elemento de una pila se reaIiza por la parte superior, lo
mismo que la inserción. Estructura LIFO.
En una cola las eliminaciones se realizan siempre por uno de sus extre-
mos, denominado frente, y las inserciones por el otro, denominado final.
442 Java 2. Manual de programación
15.8. COLAS CIRCULARES
Una cola circular es una variante de las listas circulares. Una cola necesita dos refe-
rencias, una al primer elemento y otra al último; por consiguiente, una cola circular
se toma como referencia de acceso la del Último nodo, de esta forma se tiene implí-
citamente la del primero puesto que en una cola circular el primer elemento sigue
al Último (Fig. 15.16).
último
I 1 L
iprimero
Figura 15.16. Cola circular.
Teniendo en cuenta las consideraciones anteriores y utilizando nodos vincula-
dos, los métodos a implementar tendrán las siguientes características:
El constructor, Colacircular.Crea la cola, asignando null al miembro
privado uitimo.
vacia.Devuelve true si la cola está vacía (ultimoes null) y false en
caso contrario.
poner.Crea un nuevo nodo y comprueba si la cola está vacía; si está vacía,
al campo sig del nuevo nodo le asigna el nuevo nodo; si no está vacía, asig-
na al campo sig del nuevo nodo el primero (ultimo.sig)y a ultimo.sig
el nuevo. Al terminar, en ambos casos, asigna a u1timo el nuevo.
quitar.Tras verificar que la lista no está vacía, el método considera dos
casos: 1) que la lista tenga un único elemento (ultimo.sig será igual a
ultimo), por lo que, al quitarlo, ultimo debe pasar a tomar el valor null;
2) que la lista tenga más de un elemento y, para eliminar el primero, este
primero (que es uitimo.sig) deberá pasar a referenciar a su siguiente
(ultimo.sig.sig).
obtenerprimero devuelve el objeto referenciado por el campo info del
primer elemento.
Estructuras de datos definidas por el programador 443
La implementación de la cola circular es:
public class Colacircular
i
private Nodo4 ultimo;
Colacircular ( )
i
ultimo = null;
public boolean vacía ( )
i
return(u1timo == null);
1
public void poner (Object elemento)
I
Nodo4 aux = new Nodo4(elernento, null);
if (vacia( ) )
else
i
aux.sig = aux;
aux.sig = ultimo
ultimo.sig = aux
1
ultimo = aux;
1
public Object quitar
i
if (vacia( ) )
sig;
) throws Exception
throw new Exception ("Cola vacía") ;
Object aux = ultimo.sig.inf;
if (ultimo.sig == ultimo)
else
return (aux);
ultimo = null;
ultimo.sig = ultimo.sig.sig;
public Object obtenerprimero ( ) throws Exception
if (vacía( ) )
return (u1timo.sig .inf) ;
throw new Exception ("Cola vacía");
1
//La clase Nodo no cambia
public class Nodo4
444 Java 2.Manual de programación
Object inf;
Nodo4 sig;
Nodo4 (Oblect información, Nodo4 siguiente)
I
inf = información;
sig = siguiente;
/ * Cína prueba similar a la que se efectuó con la pila se puede
utilizar ahora para ver el funcionamiento de la cola
circular. La información se muestra en el mismo orden en el
que fue introducida * /
import java.io.*;
public class PruebaCC
public static void main (String args [ ] )
t
String cadenai, cadenaf;
Colacircular cc = new Colacircular ( ) ;
System.out .println("Prueba");
System.out .println("Escriba una palabra:") ;
try
InputCtreamReader is = new InputStreamReader(Systern.in);
BufferedReader bf = new BufferedReader(is);
cadenai = bf .readLine ( ) ;
for (int i = O; i < cadenai.length(); it+)
cadenaf = " " ;
while ( ! cc.vacía ( ) )
System.out.println(cadenaf);
cc.poner (new Character (cadenai.charAt(i)) ) ;
cadenaf = cadenaf t ( (Character)cc.quitar ( ) ) .charvalue ( ) ;
!
catch(Exception e) { }
1
A A
Palabras
reservadas Java
m 445
446 Java 2. Manual de programación
Las siguientes palabras no se pueden utilizar como identificadores:
aDstract
booleai
break
byte
case
catch
char
class
const
contirue
defau-t
aouble
e-se
exter.ds
falce
final
13
finally
float
for
goto
lf
implements
import
instanceof
in:
interface
long
r.atIT,e
rew
n,ll
package
private
protected
public
return
short
szatic
super
switch
synchronized
this
throw
znrows
trar.s ient
true
try
void
volatiie
*..ile..h '
Las siguientes palabras reservadas pueden no tener significado en algunas ver-
siones actuales, pero están reservadas para uso futuro:
byvalue
cast
C0.T s t
f u t u r e
g e n e r i c
got0
i n n e r
operat o r
outer
r e s t
var
APENDICE B
Prioridad
de operadores
447
448 Java 2. Manual de programación
B.1. PRIORIDAD DE OPERACIONES
Los operadores se muestran en orden decreciente de prioridad de arriba a abajo. Los
operadores del mismo grupo tienen la misma prioridad (precedencia)y se ejecutan
de izquierda a derecha (asociatividad).
Operador Tipo Asociatividad
o Paréntesis
o Llamada a función
[I Subíndice
Acceso a miembros de un objeto
Dcha-Izda
Dcha-Izda
Dcha-Izda
Dcha-Izda
++
_ -
Prefij o incremecto
Prefijo aecremer.to
Dcha-Izda
Dcha-Izda
Más unitario
Mei.os unitario
Kegacion 1ógica un1tar1a
Complemento bit a bit Lnitario
(tipo) Modelo unitario
new Creaccion de obletos
Dcha-Izda
Dcha-Izda
Dcha-Izda
Dcha-Izda
Dcha-Izda
Dcha-Izda
+
-
Producto
Division
Resto entero
Surna
Resta
Izda-Dcha
Izda-Dcha
Izda-Dcha
Izda-Dcha
Izda-Dcha
<< Desplazamiento bit a bit a la izquierda Dcha-Izda
>> Desplazamiento bit a bit a la derecha
>>> Desplazamiento bit a bit a la derecha
con extensión de signo Dcha-Izda
rellenando con ceros Dcha-Izda
< Menor que Izda-Dcha
> Mayor que Izda-Dcha
<= Menor o ig;ial qUe Izda-Dcha
>= Mayor o igiial que Izda-Dcha
instanceof Verificación tipo de objeto Izda-Dcha
Izda-DchaI9.Ja1dad-__ _
I = Desigualdad Izda-Dcha
& AND bit a bit Izda-Dcha
OR exclcsive Sit a biz IZCa-DCha
OR inclLs;ve bit a bir Izda-Dcha
Prioridad de operadores 449
Operador Tipo Asociatividad
~
& & AND lógico Izda-Dcha
~~~ ~~
I 1 OR lógico Izda-3cha
? : Condiciona: ternario 3cka-Izda
--
+=
-=
*=
/=
~,-c -
& =
--
I =
<<=
>>=
>>>=
Asignación
Asignación
Asignación
Asignación
Asignación
Asignación
Asignac-ón
Asignación
Asignación
Asignación
de suma
de resta
de producto
de división
de módulo
AND bit a bit
OR exclusive bit a bit
OR inclusive bit a bic
de desplazamiento
3ck. a-Izda
Echa-Izda
Dcha-Izda
Dcna-Izda
Echa-Izda
Dcna-Izda
Dcha-Izsa
Dcha-: zda
Ccha-Izcio
a izquierda bit a bit Echa-Izaa
Desplazamiento derecho bit a bit con
asignación de extensiór. de signo Echa-Izda
Desplazamiento derecho bit a bit con
asignación de extensión a cero Dcha-Izda
Guía de sintaxis
451
452 Java 2. Manual de programación
Este apéndice describe las reglas básicas de sintaxis de Java que cumplen las dife-
rentes versiones existentes en la fecha de publicación de este libro: JDKl .1, 1.2y 1.3,
con el compilador Java 2.0. Gran parte de la sintaxis de Java se basa en C y/o C++.
C.1. ESTRUCTURA DE PROGRAMAS JAVA
Un programa Java consta de una colección de archivos o unidades de compilación.
Cada archivo puede contener un nombre opcional de paquete, una serie de declara-
ciones i m p o r t y por último una secuencia de declaraciones de interfaces o clases.
Una unidad de compilación puede identificar sus paquetes, importar cualquier
número de otros paquetes, clases o interfaces y declarar cualquier número de clases
e interfaces.
C.1.1. Declaración de importaciones
Una declaración de importación (import)nombra un elemento de otro paquete
que se utilizará en las declaraciones posteriores de interfaces o clases. Se puede uti-
lizar un asterisco para incluir todos los elementos de un paquete.
importnombrePaquece.*;
import nombrePaquete.NorrDreC-2se;
importnonbrePaquete.NambreI?terfaz;
Así, import java .io.* ; indica al compilador que importe cualquier clase
del paquete java .io proporcionado por Java a medida que se necesite. Es una
buena idea incluir esta línea al principio de cualquier archivo j ava que realice
operaciones de entradaisalida. Otros ejemplos:
importjava.ut;l.Date;
import.]ava.net.*;
C.1.2. Definición de clases
Una definición de una clase consta de una declaración y un cuerpo. El cuerpo con-
tiene campos de datos y declaraciones de métodos. La declaración de una clase cons-
ta de palabras reservadas e identificadores: una secuencia opcional (en el modelo
sintáctico para indicar que es opcional se encierra entre [ ] ) de modificadores, la
palabra reservada class,el nombre de la clase, un nombre opcional de la clase
padre, una secuencia opcional de interfaces y el cuerpo de la clase con sus miembros.
Guía de sintaxis 453
[modificadoresDeClase] class Nombre [extends P a d r e ]
[implements Inter f az I
[ , I n t e r f a z 2 [ , . . .I:]
{
I
//cuerpo de la clase (miembros)
Los modificadoresDeClase pueden ser: abstract, final,public.
Una clase abstracta es aquella que tiene uno o más métodos abstractos y de la
que el programador no piensa instanciar objetos. Su fin es servir como supercla-
se de la que otras puedan heredar. Las clases que heredan de una clase abstracta
deben implementar los métodos abstractos de su superclase o seguirán siendo abs-
tractas. Una clase final no puede ser superclase y todos sus métodos son implí-
citamente final.Una clase pública debe estar en su propio archivo, denominado
Nombre. java. Los miembros de una clase pueden ser métodos y variables de ins-
tancia (pertenecientes a un tipo base o una clase).
/ / Formato más simple de una definición de clase
class Claseüno
I
} I / Claseüno
/ / campos de datos y declaraciones de métodos
/ / Una clase que extiende otra clase
public class ClaseDos extends Otraclase
I
/ / campos de datos y declaraciones de métodos
} / / ClaseDos
/ / Clase compleja
public abstract class Miobjeto extends Otraclase
iniplaments InterfazUno, InterfazDos
t
} / / MiObjeto
/ / campos de datos y declaraciones de métodos
Ejemplos
1. public class Primerprograma
public s t a t i c void main (String[] args)
I
1
System.out.println("SierraMagina-Carchelejo");
454 Java 2. Manual de programación
2. public abstract c l a s s Numero
t
. . .
1
C.1.3. Declaración de variables
En Java, las variables se pueden declarar: 1) como campos de datos de una clase, 2)
como argumentos de un método, o 3) como variables locales dentro de un bloque.
C.1.4. Declaracionesde campos de datos y variables de métodos
Una variable se declara proporcionando su tipo y su identificador. El tipo puede ser
uno de los tipos primitivos o puede ser una clase. Las declaraciones de las variables
locales y campos de datos pueden incluir la asignación de un valor inicial. Los argu-
mentos obtienen su valor inicial cuando se llama al método.
//Elempios de declaraciones de variables de método o campos de datos
i n t z; / / identificador z es de tipo int
char in;cialNonbre =' M' ; / / inicialNombre es de tipo char
/ / y de valor inicial 'M'
Strir,g saludo = "HolaMackoy"; / / saludo es de tipo String
/ / y de valor inicial "HolaMackoy"
boolean interruptor = false; / / interruptor es de tipo boolean
/ / y valor inicial false
Una declaración de variables de instancia o campos de datos tiene una parte
de modificador opcional, un tipo, un nombre de variable y una inicialización
opcional.
[modificadoresDeVariable] tipo nombre [ = valor] ;
Los modificadoresDeVariable pueden ser: public, protected,
static,final.
Ejemplos
1. public class
protected
protected
protected
/ / . . .
i
Figura
Rectangulo position;
double dx,dy;
Color color;
Guía de sintaxis 455
2. c l a s s Empleado extends Persona
i
protected String nombre = " " ;
protected i n t edad;
protected Empieado unEmpleado;
11...
C.1.5. Visibilidad de campos de datos
Los campos de datos son accesibles desde cualquier método dentro de la clase.
Dependiendo de la visibilidad declarada, otros objetos pueden acceder también a los
campos de datos. A los campos de datos que no se les proporciona un valor inicial
explícito se les asigna un valor por defecto.
C.1.6. Declaración de constantes de clase
Las constantes de una clase se decíaran como variables, siendo necesario comenzar
su declaración con las palabras reservadas f i n a l y s t a t i c y se les asigna un
valor en la declaración. Este valor ya no se podw modificar.
Ejemplo
c l a s s Empleado extends Persona
t
public s t a t i c f i n a l cantidaa = 50;
//declaración de variabies
//declaraciones de métodos
C.l.7. Conversión explícita de tipos
(nombre-t i p o ) expresibn
C.1.8. Creación de objetos
Una instanciación (creación) de objetos crea una instancia de una clase y declara
una variable de ese tipo. Los objetos se crean a partir de una clase utilizando el ope-
rador new. La sintaxis adecuada es:
456 Java 2. Manual de programación
[ tipo] nombrevariable = new tipo( [parámetrol[ , parámetroZ[, ...I I]) ;
Repuesto unapieza = new Repuesto ( ) ;
Automovil micarro = new Automovil (5, "Golf");
La creación de una instancia (un objeto):
Le asigna memoria dinámicamente.
Crea un objeto con el nombre nombrevariable.
inicializa sus variables de instancia a los valores por defecto: n u l 1para los
objetos, false para variables booleanas, O para los otros tipos base.
Llama al constructor con los parámetros especificados.
Por último, devuelve una referencia al objeto creado, es decir, la dirección de
memoria donde se encuentra dicho objeto.
C.1.9. Declaración de métodos
Las declaraciones de métodos simples, denominadas también signuturus, constan
de un tipo de retorno, un identificador, y una lista de argumentos (parámetros). El
tipo de retorno puede ser cualquier tipo válido (incluyendo una clase) o el tipo
void si no se devuelve nada. La lista de argumentos consta de declaraciones de
tipo (sin valores iniciales) separados por comas. La lista de argumentos puede estar
vacía. Los métodos pueden también tener una visibilidad explícita.
[modificadoresDeMetodos] tipoDeResu1tado nombreMé todo
( [ tipoparámetrol parámetrol
[,tipoParámetroZ parámetroZ[, ...I ] ] )
[throws ExcepciÓn1 [ , ExcepciÓn2[ ,.. .I I I
t
//cuerpo del método
i
Los modificadoresDeMetodospueden ser: public, protected,private,
abstract,final,static,synchronized.Como tipoDeResultado se espe-
cificará void cuando el método no devuelva resultados. En la implementación del
método, cuando éste no haya sido declarado void, se utilizará la instrucción
return para devolver un valor al punto de llamada del método. Es decir, en cuan-
to que se ejecuta return,el método termina devolviendo un Único valor como
resultado. Para devolver múltiples valores mediante una función en Java deben com-
binarse todos los ellos en un objeto y devolver la referencia al objeto. A continua-
ción del nombre del método y entre paréntesis se especificará la lista de parámetros,
que constará de cero o más parámetros formales cada uno de ellos precedido por su
tipo y separados por comas.
Guía de sintaxis 457
Cuando se llama a un método, íos parámetros actuales se asignan a los paráme-
tros formales correspondientes. Entre los parámetros actuales, los de la llamada, y
los formales, los de la declaración, debe existir concordancia en cuanto a número,
tipo y orden.
La palabra reservada throws permite listar tipos de excepciones lanzadas por el
método cuyo tratamiento se pospone para que sea efectuado por el método llamador.
Los métodos de una clase están asociados con una instancia específica de la
misma, excepto si son estáticos.
public class Ejemploi {
/ / campos de datos declarados, ninguno
/ * Declaración simple: no se devuelve nada, no se pasa ningún
private void calcularImpuestos(){
1
argumento * /
/ / cuerpo del método
/ * Un método con un argumento de tipo double que devuelve us
public int CalCUlarTotal (double x) [
entero * /
/ / cuerpo del método
1
/ * Un método que devuelve un objeto de tipo Miobjeto con un
protected MiObjeto convertir(int z, String s) {
}
entero y una cadena de entrada * /
/ / cuerpo del método
1 / / clase Ejemplo1
C.l.I O. Llamadas de métodos
Cuando se llama a un método, se deben proporcionar los argumentos del tipo ade-
cuado:
/ / interior de un método
i
calcularZ ( ) ;
int z = calcularZ (16,25);
Miobjeto ob] = convertir(25, " Hola Mackoy" ) ;
C.l .I 1. El método main
Cada aplicación Java (no los appkts) debe tener un método main que es donde
comienza la ejecución de la misma. Es decir, para ejecutar un programa el intérprete
de Java comienza llamando al método main ( ) . Este método se llama antes de la
458 Java 2. Manual de programación
creación de un objeto y ha de declararse como static para que se pueda llamar
sin tener que referirse a una instancia particular de la clase. Como además es Ila-
mado por código fuera de su clase, también tiene que ser declarado como pub1ic,
que es la forma de permitir que un miembro de una clase pueda ser utilizado por
código que está fuera de la misma. La palabra reservada v o i d indica que main no
devuelve nada.
public s t a t i c void ma;?. (String[I args)
String [ ] args es la declaración de un array de String,mediante el cual
la clase podría tomar un número variable de parámetros en la línea de órdenes;
aunque no se use, es necesario incluir este parámetro cuando se define el método
main().
C.1.12. Extensión de clases
[acceso] [ f i n a l : c l a s s Nombreclase extends Superclase
/ / cLerpo de la clase ampliaaa
Constructor de la subclase
2TbreClase (arqll, . . . )
. . .) ;
public
i
super
. . .
1
C.1.I 3. Constructores
La sintaxis de un constructor es similar a la de un método, sin tipoDeResultado
y cuyo nombre debe coincidir con el de la clase. El constructor se invoca automáti-
camente cuando se crea una instancia de la clase.
~ n o d i i i e a c o r e ~ D e C o n s ~ r t i c t o r ]nombreConstructor
( [ tipoParánetrol parámetrol
[ , tipoParámetro2 parámetro2 [ , . . . I 1 1 )
//cuerpo ael constructor
1
Guía de sintaxis 459
Los modificadoresDeConstructor siguen las mismas reglas que en los
Un constructor debe ser invocado con el operador new.
Una clase puede tener múltiples métodos constructores, siempre que éstos se
diferencien unos de otros en el número y/o tipo de parámetros.
métodos normales, pero un constructor abstracto estático final no está permitido.
c l a s s Persona
protected Ctrirg nombre = " " ;
protected i n t edad = O;
public Persona (String nom, int años)
t
nombre = nom;
edad = años;
public s t a t i c void main (String args [ 3 )
Persona p = new Persona ("Luisito Mackoy", 13);
System.out.println("Nombre: 'I + p.nombre + " " + "Eaad: "
t p.edad) ;
1

C.1.14. Los constructores en la extensión de clases
El cuerpo de un constructor comienza con una llamada heredada al constructor de
la superclase de la clase. Esta llamada debe ser la primera sentencia del cuerpo de
un constructor y no puede aparecer en ningún otro lugar. En Java super ( . . .)
es usado en vez del nombre del constructor de la superclase. Si no se usa super
entonces se supone implícitamente que el cuerpo del constructor comienza con la
llamada super ( ) sin parámetros. El resto del cuerpo es como un método normal.
c l a s s Empleado extends Persona
protected String categoria = " ' I ;
protected i n t salario = O;
public Empleado (String nom, i n t años, Ctrizg n:vel, i n t sueldo)
super (nom, años);
categoria = nivel;
salario = sueldo;
public s t a t i c void main (Strinq args [ ] )
460 Java 2. Manual de programación
Empleado e = new Empieado ("Arzurito Mackoy", 13, "medio",
System.out.println("Nombre: " + e.nombre + " '' + "Eaad: I'
+ e.edad) ;
System.out.println("Nive1: " t e.categoria + " "
+ "Salario: " + e.salario);
200000);
C.1.15. Definición e implementación de interfaces
Definiciónde una interfaz
public interface Nornbrein t e r f a z
t
public abstract tipoDeResu1 tado nombreMétodo () ;
//otras declaraciones de métodos vacios.
Se ha de tener en cuenta que:
Todos los miembros de una interfaz son públicos automáticamente.
Todos los métodos son abstractos automáticamente.
Todos los campos deben ser declarados static y final.
La clase que implementa la interfaz debe implementar todos los métodos decla-
rados en ella.
public class Irnplementa [extends Padre] implements NombreInterfaz
public tipoDeResEltado nombreKétodo0
t
/ / . . .
/ / s e inplementan todos los métodos de la interfaz NombreInterfaz
1
Es posible que una clase implemente más de una interfaz.
[ modificadoresDeClase] class Nombre [extends Padre]
[implements I n t e r f a c e ]
i, I n t e r f a c e 2 [, . . .111
//Implementación de todos los métodos de las distintas interfaces
Guía de sintaxis 461
Es posible definir clases que tengan objetos del tipo NombreInterfaz,como
si la interfaz fiera una clase, pudiendo así usarse en ellas, las diversas implementa-
ciones de ésta. La clase E j emplo puede usar, entre otras que hubiera definidas, la
que ofrece la clase Implementa.
public class Ejemplo
{
public Ejemplo ( )
(
1
public tipoDeResult a d o unMetodo(NombreInterfaz elemento)
{
/ / . ..
/ / . ..
C.l.I6. Clases anónimas
Una clase anónima es aquella que no tiene nombre y, cuando se va a crear un obje-
to de la misma, en lugar del nombre se coloca directamente la definición.
n e w SuperNombreO { cuerpo clase ]
Por ejemplo, considerando declarada una clase Implementa que implementa
NombreInterfaz,la siguiente instrucción
e.unMetodo ( n e w Implementa ( ) ) ;
pasa a e.unMetodo una nueva instancia de dicha clase Implementacomo pará-
metro. Si se quisiera emplear una clase anónima no se efectuaría la declaración de
implementa y la instrucción anterior se sustituiría por:
e.unMétodo ( n e w NombreInterfaz ( )
I
public tipoDeResultado nombreMétodo()
(
/ / . ..
1
/ * se implementan todos los métodos de la interfaz
NombreInterfaz * /
1
) ;
462 Java 2. Manual de programación
C.2. SENTENCIAS
C.2.1. Sentencias de declaración
tipo nombreVariab1e;
Ejemplos
int longitud;
double e;
Circulo circulo;
C.2.2. Sentencias de asignación
Una sentencia se asignación asigna el valor de la expresión en el lado derecho a la
variable del lado izquierdo.
nombre = expresiónlegal;
Ejemplos
longitud = 5 + I ;
i += 5;
C.2.3. Sentencias return
Las sentencias return proporcionan una salida de un método con un valor de
retorno no void. Las sentencias de retorno pueden no aparecer en un método con
un tipo de retorno void. Las sentencias return pueden aparecer en cualquier
parte de una estructura de control; producen un retorno inmediato del método. El
valor de la expresión a continuación del retorno debe coincidir con el tipo de retor-
no del método.
Ejemplo
public int calcularResta(int x, int y) {
I
return x- y;
Guía de sintaxis 463
C.2.4. Sentencias compuestas
Las sentencias compuestas se encierran entre llaves { } y se ejecutan secuencial-
mente dentro del bloque.
Ejemplo
i
i n t m = 25;
i n t n = 30;
i n t p = m + n;
/ / asigna el valor 25 a m
/ / asigna el valor 30 a n
/ / asigna el valor 55 (m + n) a p
C.2.5. Sentencia if
Las sentencias de selección proporcionan control sobre dos alternativas basadas en
el valor lógico de una expresión.
i f (expresiónlógica)
bloqueCen t e n c i a s l
//si son varias sentencias se encierran entre { }
bloqueCen tencias21
[else i f (expresiónlógica)
[else
bloqueSen tenciashr]
Ejemplo
i f (i < O )
else
t
System.out .println("Número negativo") ;
System.out.print("Número válido, ' I ) ;
System.out .println("es positivo") ;
1
C.2.6. Sentencia switch
La sentencia switch es la bifurcación múltiple.
switch (expresion-int)
f
464 Java 2. Manual de programación
case constante-expl:
sentenciasl;
entre llaves * /
[break;]
sentencias2;
[break;] ]
/*si se trata de múltiples acciones no es necesario encerrarlas
[case constante-exp2 :
[case constante-expN:
sentenciasN;
[break;] ]
sentenciasX;
[break;] ]
[default
Ejemplos
1. switch ( y / 50)
{
case 2: elemento = new Demo2 (O, O) ; break;
case 3: elemento = new Demo3(0, O, 100); break;
case 4: elemento = new Demo4(0, O, 200); break;
case 5: elemento = new Demo5(O, O); break;
1
2. switch (n)
case 1:
case 2:
i
visualizarResultado
break;
case 3:
case 4:
case 5:
case 6 :
visualizarResultado
visualizarResultado
break;
default:
visualizarResultado
} //fin de switch
C.2.7. Etiquetas
nombreE tiqueta:
break [nombreEtiquetal;
continue [nombreEtiqueta];
"1, 2, Sierra de Cazorla");
"3, 4, Sierra Magina");
"3, 6, Sierra de Jaen");
n + " fuera de rango");
Guía de sintaxis 465
salir:
i
for (i = O; i < 10; i++)
{
for (j = O; j < 20; j++)
I
if (i == 1) break salir;
System.out.print(j + " " ) ;
System.out.println0;
1
} //fin del bloque con la etiqueta
C.2.8. Sentencia while
La sentencia while se utiliza para crear repeticiones de sentencias en el flujo del
programa.
while (expresiónlógica)
bloqueSentencias
//el bloquesentencias puede ejecutarse de O a n veces
Ejemplo
while (cuenta <= numero)
{
System.out .print(cuenta + ' I , " ) ;
cuenta++;
1
C.2.9. Sentencia do-while
La sentencia do-while se utiliza para repetir la ejecución de sentencias y se eje-
cuta al menos una vez.
do
while (expresiónLÓgica);
bloquesentencias //el bloquesentencias se ejecuta al menos una vez
466 Java 2. Manual de programación
Ejemplo
do
S y s t e m . o u t . p r i n t ( c u e n t a + ' I , ' I ) ;
c u e n t a + + ;
I
while ( c u e n t a <= numero)
C.2.1O. Sentencia for
La sentencia f o r se usa para repetir un número fijo de veces la ejecución de una
serie de sentencias.
f o r ( [ i n i c i a c i ó n ]; [ c o n d i c i ó n D e T e s t ] ; [ a c t u a l i z a c i ó n ] )
s e n t e n c i a s
Ejemplo
f o r ( i n t i = O ; i < 1 0 ; it+)
a [ i ] = 5 * i;
C.2.11. Método e x i t y sentencia break
La sentencia b r e a k se puede utilizar en una sentencia swit ch o en cualquier tipo
de sentencia de bucles. Cuando se ejecuta b r e a k el bucle que lo contiene o la sen-
tencia switch terminan y el resto del cuerpo del bucle no se ejecuta. Una invoca-
ción al método e x i t termina una aplicación. El formato normal de una invocación
al método e x i t es
S y s t e m . e x i t ( O ) ;
La captura de excepciones se realiza mediante bloques t r y - c a t c h . La/s senten-
ciais de un bloque se colocarán siempre entre llaves.
try
bloqueAIntentar //aunque sea una ú n i c a s e n t e n c i a ésta i r á e n t r e { }
boqueCen t e nc ias1
catch ( t i p o E x c e p c i o n 1 i d e n t i f i c a d o r l )
Guía de sintaxis 467
[catch (tipoExcepcion2 identificadoz-2)
boqueSentencias2]
. . .
[ f i n a l l y
boqueSentenciashr]
o bien
try
f i n a l l y
bloqueAintent a r
boquesentenciasN
ya que el bloque try no puede aparecer sólo.
import java.io.*;
public class ReturnTryEj
{
public s t a t i c i n t leer ( )
i
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader (isr);
String cadena = ' I " ;
try
{
cadena = br .readLine ( ) ;
return Integer.parseInt(cadena);
1
catch (Exception e)
{
i f (e instanceof IOException)
else i f (e instanceof NumberFormatException)
System.out .print111("Error de entrada/salida") ;
System.out .println("No tecleó un número entero");
1
/ / Instrucción siguiente a catch
System.out .print111("Se devuelve O") ;
return O;
public s t a t i c void main (String args [ ] )
t
i n t n;
do
{
468 Java 2.Manual de programación
System.out.print("Deme un número entero entre 1 y 20 ' I ) ;
n = leer ( ) ;
1
while ((n <= O) I 1 (n > 20)) ;
System.out.println("2A'' + n + " = " + Math.pow(2,n));
1
C.2.13. Sentencia throw
Una sentencia throw lanza una excepción, que puede ser una excepción recibida
o bien una nueva excepción. Una cláusula catch puede recibir una excepción y, en
lugar de tratarla o después de hacerlo, volver a lanzarla mediante una instrucción
throw.
try
bloqueAIntentar
catch ( NumberForma tException i d e nt if icador)
{
/ / . ..
throw ( i d e n t i f i c a d o r );
1
Para lanzar una nueva excepción, se crea un objeto de una subclase de
Exception que implemente un constructor y se lanza con throw cuando ocurra
el hecho que debe provocar la excepción:
if ( e x p r e s i ó n l ó g i c a )
throw new ConstuctorSublclaseException( [parámetroi[ , parámetro2
[ , ...I l l ) ;
Ejemplo
if (edad < 18 I I edad > 65)
throw new FueraDeRango ("Excepción: valor fuera de rango");
class FueraDeRango extends Exception
{
String mensaje;
public FueraDeRango (String causa)
i
mensaje = causa;
Guía de sintaxis 469
public String getMessage ( )
i
1
return mensaje;
C.2.14. Sentencia throws
Lista las excepciones no tratadas y pertenecientes a clases distintas de
RuntimeException.Así, su tratamiento será pospuesto y deberá ser efectuado
por el método llamador o tendrán que volver a ser listadas en la cabecera de éste con
otra cláusula throws.
[ rnodifi cadoresDeMé todos] tipoDeResultado nombreMétodo
( [t i p o p a r á m etrol paráme t r o l
[,tipoParárnetro2 parárnetro2[, ... I , ' ] )
[throws Excepción1 [,
Excepción2 [, . . .I I I
//cuerpo del método que no trata la excepción
C.2.15. Sentencia package
Cada clase pública definida en Java debe ser almacenada en un archivo separado
y si hay varias relacionadas todas ellas se almacenan en el mismo subdirectorio.
Un conjunto de clases relacionadas definidas en un subdirectorio común puede
constituir un paquete Java. Los archivos del paquete deben comenzar con la
siguiente sentencia:
package nombrepaquete;
donde el nombre del paquete refleja el subdirectorio que contiene dichas clases. Se
utiliza el carácter punto ( .) como separador entre nombres de directorios, cuando
es necesario especificar varios para referenciar al que contiene las clases.
Ejemplo
package libro.Tema03;
470 Java 2. Manual de programación
Se puede usar una clase definida en otro paquete especificando, para referirse
a ella, la estructura de directorios del otro paquete seguida por el nombre de la
clase que se desea usar y empleando el carácter punto como separador.
Referenciar clases de esta forma puede resultar molesto y la solución consiste en
utilizar import, que permite incluir clases externas o paquetes enteros en el
archivo actual.
c.3. MISCELÁNEA
C.3.1. Referencia a miembros de una clase
r:arnkre0bj e t o.i?omOreComponen te
Si es static no es necesario referirse a una instancia en particular de la clase
y puede referenciarse como
nombreClase. nombreComponente
Los miembros de una clase están asociados con una instancia específica de la
misma, excepto si son estáticos.
C.3.2. Conversión explícita de tipos
Existen dos tipos fundamentales de conversiones de tipos que pueden ser realizados
en Java, con respecto a tipos numéricos y con respecto a objetos. El formato a apli-
car para efectuar una conversión explícita de tipos es:
(tjpoA'ombre) expresión;
Ejemplo
double resultaao = (double) (4/8); //asigna 0.0 al resultado
double resultado = (double)4/(double)8;//asigna 0.5 al resultado
double reslJltado = (double)4/8; //asigna O. 5 al resultado
double resiiltaao = 4/5; /*conversión implícita, asigna 0.0 al
resultado * /
A1cmr.o unAlumno = (Aluyno)KnaPersona;
Guía de sintaxis 471
C.4. ARRAYS
Un array es un objeto que contiene un número de posiciones de memoria consecu-
tivas, celdas de memoria, cada una de las cuales contiene datos del mismo tipo. Los
arrays en Java pueden se unidimensionales o multidimensionales
C.4.1. Declaración de un array
int arrEnt ] ; //array unidimensional capaz ae alnace-ar enteros
float [ ] arrFloat; //array unidimensional capaz de almacenar floa:
double[]; j arrCodble; //array bidimensional para almacenar datos cioLble
int a [ ][I; //array bidimens-ona- capaz de alrracenar enteros
C.4.2. Creación de un array
arrEnt = new int[100]; /*necesaria su previa dec1araz:ón:
int arrEnt[]; * /
Es posible crear arrays en los que cada fila contiene un número diferente de
columnas:
a = new int[3][I; //asigna filas (supuesta la previa aeclaración)
a [ O ] = new int[7]; //asigna 7 columnas a la f;ia O
a[i] = new int[5]; //asigna 5 columnas a la fila 1
a [ 2 ] = new int[9]; //asigna 9 columnas a la fila 2
C.4.3. Combinar declaración y creación
La declaración y la creación se pueden combinar.
int[] arrEnt = new intiloo];
double[][ I arrDouble = new doubie[8j [lo];
Pelota [ ] arrayPelotas = new Pelota;lC];
C.4.4. Combinar declaración creación e inicialización
int[] arrEnt = 119, 2, 3 , 5, 7, 6, 8, 15, 9, 12);
472 Java 2. Manual de programación
C.4.5. Recorrido de los elementos de un array
Se suele efectuar con ayuda de estructuras repetitivas.
for (int i = O; i < arrayPelotas.1ength; i++)
arrayPelotas [ i] = new Pelota ( ) ;
C.4.6. Acceso a un elemento de un array
Se accede a un elemento de un array mediante un índice que debe ser un valor ente-
ro mayor o igual que cero y menor que el número de elementos del array (almace-
nado en la variable de instancia length)y que especifica la posición del elemento
en el array
arrayPelotas [ 5 ] .moverA(24,15);
a [ O ] [5] = 2 + a[Ol [4];
C.5. CADENAS
Una cadena (string) es una secuencia de caracteres. Java proporciona una clase
incorporada String para manejar cadenas de caracteres:
String msg = "Sierra de Cazorla";
Si cadl y cad2 son variables de tipo cadena
cadl == cad2
comprueba si las dos variables se refieren al mismo objeto. Mientras que
cadl.compareTo(cad2)
devuelve positivo, cero o negativo según cadl sea mayor, igual o menor que cad2.
C.5.1. Concatenación de cadenas
El operador + en Java tiene un significado especial de concatenación de cadenas
y se puede utilizar con objetos de la clase String,que pertenece al paquete
Guía de sintaxis 473
java .lang.Al contrario que C++, Java no soporta sobrecarga de operadores, el
caso del operador +para concatenación de cadenas es una excepción a esta regla de
Java. En cuanto uno de los operandos que intervienen en una expresión es de cade-
na, el operador +convierte a cadena los valores de otros tipos que intervienen en la
expresión y efectúa concatenación:
a + b / / al menos a o b han de ser una cadena
Ejemplos
System.out.println (5+1); //Salida 6
System.out.println (""t5ii); //Salida 51
g.drawString(5+1, 100,100); //Error de sintaxis
g.drawCtring ("5 + 1 = "+5+1,100,100); //Salida 5 + 1 = 51
String h = new String ("Felicidades");
String pm = new String("para Mackoy") ;
String titulo = h + " " + pm;
//imprime Felicidades para Mackoy;
Cystem.out.println(titu1o);
C.6. APPLETS
Los applets son pequeños programas Java que se incluyen en páginas Web y cuyo
código se descarga desde el servidor para ser ejecutado localmente por un navega-
dor. Todas las applets disponen de cinco métodos que pueden sobreescribir, aunque
no resulta obligatorio que lo hagan, pues tienen implementaciones por defecto, y
que se invocarán automáticamente durante la ejecución de la misma. Cuatro de ellos
son proporcionados por la clase Applet y el otro es paint perteneciente a la
clase Container.
import java.awt.*;
import java.applet.*;
public class NombreApplet extends Applet
t
public void init ( )
t
/ * Inicializa el applet y es invocado por el Appletviewer o el
navegador cuando se carga el applet * /
1
public void start ( )
I
474 Java 2. Manual de programación
/ * Se ejeccta a continuacion de init y tambien cada vez que e ;
usuario ael navegador regresa a la pagina HIM¿ donde
reside el applet. Debe contener las tareas a Llevar a cabo
en estas ocasiones * /
public void stop()
/ x Se e;ecLta cuando el usuario abandona la pagina HTML er, la que
reside el apple: * /
public void destroy()
I
/ * Libera todos l o s recursos que el applet est2 Ltilizaxdo y se
ejecuta axtes de q'üe la applet se descargue cuando e l usuario
sale de la sesión de navegación * /
public void pain= (Graphics g)
I
/ * D-bula en el applet al comenzar esta a ejecutarse y tamb;en
cada vez qLe la misma necesita redibujarse * /

Más contenido relacionado

PDF
Modulo herramientas
PDF
Material de trabajo informática i
PDF
Java. curso practico de formacion para la preparación de certificacion iz0 808
PDF
Programacion web aprenda java como si estuviera en primero
PDF
PDF
Aprenda java como si estuviera en primero
PDF
Trabajo de manual Word 2013
PPTX
Como funciona Visual Studio
Modulo herramientas
Material de trabajo informática i
Java. curso practico de formacion para la preparación de certificacion iz0 808
Programacion web aprenda java como si estuviera en primero
Aprenda java como si estuviera en primero
Trabajo de manual Word 2013
Como funciona Visual Studio

Destacado (20)

PDF
Manual Programacion Php
PDF
Manual programacion-javascript-parte1
PDF
Auto cad. guia practica de aprendizaje
DOCX
TrabajoSSI-virus y antivirus
PDF
Ubuntu manual-13-10-es-ubu
PDF
Poo y mvc en php
DOCX
Comandos basicos Linux
PDF
Linux 100
PDF
PDF
redes de seguridad
PDF
Tecnico hardware desde cero
PPT
Tipos de datos en C
DOCX
Manual de Programación c/c++ Ricky Bonilla
PDF
Herramientas para programar en C
PPS
Pilas Pilas
PDF
3899699 manual-de-programacion-con-php-y-my sql
DOCX
MANUAL DE PRACTICAS DE LINUX (Alberto Hdz)
DOCX
Inter p referencia completa
PDF
Manual programacion c++
DOCX
Manual Programacion Php
Manual programacion-javascript-parte1
Auto cad. guia practica de aprendizaje
TrabajoSSI-virus y antivirus
Ubuntu manual-13-10-es-ubu
Poo y mvc en php
Comandos basicos Linux
Linux 100
redes de seguridad
Tecnico hardware desde cero
Tipos de datos en C
Manual de Programación c/c++ Ricky Bonilla
Herramientas para programar en C
Pilas Pilas
3899699 manual-de-programacion-con-php-y-my sql
MANUAL DE PRACTICAS DE LINUX (Alberto Hdz)
Inter p referencia completa
Manual programacion c++
Publicidad

Similar a Manual Programaciòn (20)

PDF
PDF
PDF
Aprenda java-como-si-estuviera-en-primero
PDF
PDF
PDF
PDF
Aprenda java
PDF
PDF
Intro java
PDF
Esquema curso java
PDF
Introduccion poo con_java
PDF
MANUAL DE JAVA
PDF
JAVA
Aprenda java-como-si-estuviera-en-primero
Aprenda java
Intro java
Esquema curso java
Introduccion poo con_java
MANUAL DE JAVA
JAVA
Publicidad

Manual Programaciòn

  • 2. JAVA 2 MANUAL DE PROGRAMACIÓN
  • 3. JAVA 2 MANUAL DE PROGRAMACIÓN Luis Joyanes Aguilar Matilde Fernandez Azuela Departamento de Lenguajes y Sistemas Informáticos e Ingeniería del Software Facultad de Informática / Escuela Universitaria de informática Universidad Pontificia de Salamanca. Campus Madrid Osborne McGraw-Hill MADRID BUENOS AIRES CARACAS GUATEMALA LISBOA MÉXICO NUEVA YORK PANAMA SAN JUAN SANTAFÉ DE BOGOTÁ SANTIAGO SA0 PAUL0 SAN FRANCISCO * SIDNEY SINGAPUR ST. LOUIS TOKIO * TORONTO AUCKLAND HAMBURG0 LONDRES * MILÁN MONTREAL NUEVA DELHI PARiS
  • 4. CONTENIDO ....<.<...........< .............................................< ........ Capítulo I . Introducción a .Java ................ 1. I . La historia de Java .......... ........,...<....,...<.<........<. 1.3.;,Qué es .l¿l¿l? ....<..._......<..<.<...._.....<.<...................................... I .7.I . Java coi110 leiigua.jc de Internet I.7.7. .lava con10 leng~ia.je 1.3.I . Sencillo ... .............I . . . . . . . . . . . . . . . . . . . . . I .3.3. Orientado I .3.3. Distribuido .................................................................. 1 .3. Características de J a ~ a...................... . < .........<.............<. 1.3.6. Seguro ....................................... 1.3.7. ,4rqiiitectur 1 .3.8. Portable .......~ ............................................... 1 .3.9. Alto i-endiiniento .... ..<..........<............<....... I .3.10. Multihilo ...................................................... I .3.1I . r>inón1ico ....... ............<........._....<...<<.<.......< I .4. La programación orientada a objetos como base de Java I .5. Especificacioiies del lengua-je Java ...................................... 1.6,Aplicaciones y u p p / c t ~......................................... Seiiiejanzas y diterencias entre aplicaciones 4 Etapas para crear un programa ................................... Componentes de ~ i n aaplicación ........................................ .‘l. Herrainientas de desarrollo Java ...... .<.............< I .9,I , El entorno de desarrollo JDK ..................................... . I O. Una aplicación práctica de Java ........................... ....... I .h.1, 1 .7.I , 1 .8. xiii 1 2 3 3 4 5 5 6 7 7 8 8 9 9 I O I o 11 1 1 12 13 13 15 15 18 21 71 27 V
  • 5. vi Contenido I,11. Estructura de un programa aplicación en Java ................................................ 1.1 I . 1. Referencia a miembros de una clase ......................................................... I , 17.I Errores de compilaci ............................................... I , 12.2. Errores de e-iecución I . 12.3. Errores Ibgicos ....................................................... 25 27 I . 12. Errores de programación ...................................................... .................................... Capítulo 2. Características del lenguaje Java .......................................................... 31 2.1. Palabras resercadas .. ...................................................... 22. Identiíicadores ..... ................................................. 7.3. Tipos de datos .................................................... .................. 2.6. constantes ................................................. ...................................... 2.7. La biblioteca dc clases de Java .................................................... 7.8. Coiiceptos bisicos sobre excep ................................................... 2.9. 7.10. Las clases Character y Boolean ........................ La clase Nxmber y sus subclases .................................... .......................... .................................. ..................................... 2.13. La sentencia dc asignación ....... 2.14. Expresiones .................. .................................................. ................................................. 2.15. ClaseMath ........... ......................................................... ............................... 2.18. Operadores aritméticos ......................... ..................................... 7.19. Operadores relacionales ................. ......................................... 2.20. Operadores lb&''ICOS ............... .................................................... ..................................................... ................................................... 32 33 34 34 38 41 44 45 46 48 49 52 52 53 54 55 55 57 57 58 61 61 63 65 67 67 71 3.I . La sentencia i f ........... 72 3.3. La sentencia i f - e l s e 73 3.3. Las sentencias i f e I f - e l s e anidadas 74 3.4. La sentencia s w i t c h ..................................................... 78 803.5. La sentencia f o r .................... 3.6. La sentencia break 83 3.7. La sentencia continue ...... 85 Capítulo 3. Decisiones y bucles ................. ............................................ ................................................... .................................................... ............................ ..................................................... ................................. ................................... ...............................................
  • 6. Contenido vi¡ 3.8. Diferencias entre continue y break ......................................................... 3.9. La sentencia while ...................................................................................... 3.10. La sentencia do-while ................................................................................ Capítulo 4.Clases. objetos y mktodos ....................................................................... 4.1. 4.2. 4.3. 4.4. 4.5. 4.6. 4.7. 4.8. 4.9. 4.IO. 4.11. Ob-jetos y clases .. Declaración y crea Acceso a datos y n Utilización de inétodos Paso de paránietros ......................................................................................... Paso de parárnetros por valor . Paso de parámetro Constructores ...... Modificadores dc private ................................. protected .................................................................................................... 4.12. public ........................................................................................................... 4.I3. Recursividad ................................................................................................... . . Capítulo 5.Herencia ................................................................................................... 5.I. 5.3. El inétodo c l o n e ............................................................................................ 5.4. El método equals 5.5. El método f i n a l 1ze ..................................................................................... 5.6. El método tostring 5.7. El método getclass ..................................................................................... Descripción de herencia ................................................................................... 5.2. La clase Object . ............................... 5.8. Ventajas de la herencia .................................................... 5.9. Superclases y subclases ................................................................................... 5.I0. Modificadores y herencia 5.1 I . Clases abstractas ............................................................................................... 5.12. Métodos abstractos 5.13. Interfaces ... ............................................................................................ 5.14. Definición d Capítulo 6.Encapsulamiento y polirnorfisrno .......................................................... 6.1. 6.2. 6.3. 6.4. 6.5. 6.6. 6.7. 6.8. 6.9. Encapsulainiento .. ............................... Modificadores de c Modificadores de bariables ............................... Modificadores de inétodos ............................................................................... Clases internas ..... ............ .......... Paquetes ........................................................................................................... Declaración de un paquete ....... Paquetes incorporados ..................................................................................... Acceso a los elementos de un paquete 86 88 91 95 96 98 I o0 1O0 102 I03 103 104 107 1ox 109 1 1 1 1 1 1 117 118 I19 122 122 127 I73 123 124 124 I25 127 129 134 I35 141 142 142 143 144 144 149 150 151 152
  • 7. vi¡¡ Contenido 6.I 0. Importacióii de pacliietes ............................... 6.I I , Control de acceso a paquetes 6.12. Polimortisino ....................................................... ............................ 6.13. Ligadura .......................... _.........<.............<.<........_._..<................... 6.14, Ligadura diiiiiiiicn ...................................................... ............... ................................ <.. ......................... <............_................... ......<..<......... 7.I . Concepto de array .............................. ........................... <................ 7.2. Proceso de arrays 7.2.I DeclaraciOn ................................ ............................................. 7.2.2. CreaciUn ........ ............................................ <..... 7.3. Arrays de objetos .. .....<.......................<...................... ................................... 7.5. .4rrays mu ItidiniensioiiaIes ._....<.<.<._._._._......<..........._....<.<......... 7.6. Ordenación de arrays .........<..._._..................._.................. 7.X. Burbuja ................ _..........<..._._._....<.<.........._._.............. 7.1 1 . Ordenación ripida ........................................ 7.12. Rúsclueda ........................ ............_......<..............._...........<.... 7.7. Selection ...................<......................... _._..<....<...................<............. 7.9. Inserción ............,................................... 7.10. Shell ,..._._............. _....<...................<.<......................... ......................................... .................................. ...................... Capítulo 8. Cadenas y fechas ....................................... ........................ 8. I . Creación de cadenas _............<...............................<....... 8.2. Comparación de cadenas .................... ........................................ 8.3. Concatenación ...... .......................................... <....... X.4. Otros métod .....<........................... 8.5. Laclase St 8.6. La clase StringBuffer ................................ ......................... 8.7. Métodos de 8.8. La clase Date .........._........<................_.......... 8.9. Los formatos de Fechas ... ._....<....<....................................... 8.10. La clase Calendar .............................................. ................... .............. Capítulo 9. Interfaces grificas de usuario .............................................. 9.I . El AWT.......... ................................................ 9.2. Realización d .......................................... 9.3. La clase Com 9.3. La clase Container ............................. ........<...........................< 9.5. Ventanas .............. ............<.<....................................... 9.5,I . Clase Frame ...................................... ................................... 153 153 154 156 157 161 162 163 164 164 165 167 169 171 172 178 179 I x0 181 1x3 1x5 I X6 1 XX 193 194 197 20 1 202 20X 209 210 212 213 214 217 218 219 222 224 225 225 9.5.2. Clase Dialog ............................................................................................ 229
  • 8. Contenido ¡X 0.5.3. (’lase FileDialog .................................................................................. 9.6. Clase Par?el........................... ......................................... 9.7. Clase Label .................................................................................................... 9.8. C’lasc Button ........................ ........................................ 0.0. Clase T e x t C o r n p o n e n t ................................................................ ~ ................ 0.10. (’lase canvas ........................ 9.1 I . Clase Choice .................................................................................................. 9. 12. Clase Chec kbox ................... ............<......<..................<............. ............................ .............<.............<.....................<......................,,,,....................... ...................... 9.15. Meniis . .................................... <........<.........................,,.,.,...................... 9.16. Adininistradores de diseno ...... .......................................... 9.16.1, FlowLayout ..................................................................................... Capitulo 10. Gestión de eventos ....... 10.2. Los componentes del AWT con ...................... <............... 10.1 . Tipos de eventos ..................... 10.3. Receptores de eventos ............ 10.4. Procesamiento de eventos ................................................................................ 10.5. Clases adaptadoras ...................................................................... 10.6. Clases receptoras anóniinas .............................................................................. 10.7. Problemas comunes en cl tratamiento de eventos ......................................... .... Capitulo 11. Applets ........................... ......<.......... 1 1 , 1 . Introducción a HTML ............. I 1 2. Incorporación de q 7 p / c ~ / . sa páginas Web ......................................................... I 1 2.I . Edición de un documento HTML y ejecución de applets . 1 1.4. Transforinación de aplicaciones en tipplefs ................................ 1 1 .6. Incorporación de imágenes ......................................................... 11.3. Estructura de un tr/~plet 1 I .5. Incorporación de sonido .......... ................................................ .......................................................................... Capitulo 12. Programacih concurrente: Hilos de ejecución ................................. 12.1, La prograinacih niultihilo en Java ................................................................. 12.2. Estados de un hilo ............................................ 12.3. Creación de hilos .......................................................................... 12.4. Planiticaci6n y pri 12.6.Grupos de hilos .......................................................................... 12.7. Sincronizacióii ........................ .............<....<.........................<.<< 12.8. Animaciones ............................................................................... . . 12.5. Hilos de tipo demonio ......................... ........................................... I.... 12.9, Doble hi!fj’¿~/- ............................... .........<.<..................................<. 232 234 234 236 238 242 244 246 249 252 254 256 256 257 258 262 263 264 265 266 269 272 274 276 285 286 289 29 1 294 29X 306 306 311 312 313 3 I4 316 317 318 319 326 327
  • 9. x Contenido Capítulo 13. Rlanejo de excepciones ......................................................................... 13.1. 13.7. I 3.-3. 1.3.4. 13.5. 13.6. 13.7. 13.x. Coiiceptos generales ..,.,.,............................... Mane.jo de excepciones ......... Captura y tiatanliento de exce ,.<..............<..<.... ..........<........ .........<....<................... ....................... <..._...........<.<........ . , Laiizar la cxcepcioii .,...._....,.. Declarar la excepcioii ...................................... .............. El bloque f inaliy .......................... Creacicín de excepciones ................................................ Mitodos de la clase Throwable .......... ..................... . I ._...<..<....._................................ .......................................... Capitulo 14. Archivos ................................................................................................. 14.I . La clase File ........... .................................................. .................................................................... ...................... 14.3. Apertura de archivos .. ......................................... <........... 14.4,Eiicadenaimiento 14.5. Evcepciones en ar .........<...............<................. 14.6. Mitodos de I n p ....................................... 14.7. hldodos de Outputstream ........<.<........<................................ 14.8. [;lbtodos de Reader ............................................... ........................ 14.9. Xlitodos de Writer ........................ ................................................. 14.10. Mitodos de DataInputStream .................................... 14.1I . Mitodos de DataOutputStream .. 13.12.Vitodos de RandomAcces s F i l e .................................. 14,13. Serializacióii de objetos ..................... ........................ <...................... ................................................ 14.13. StringTokenizer y StreamTokenizer ............. 14.15. Operaciones con 13.16.Archibos secuenciales .... 13.17.Archivos directo .......................... 14.I 8. Funciones de transformación de clave y tratamiento de colisiones .......... ...................<...................... Capítulo 15. Estructuras de datos definidas por el programador ......................... 15.1. Lista ...................................... <........ ....................................... 15.3. Lista ordenada ............................................... 15.4, 1.7.5. Listas doblemente enlazadas ......................................... ................ 15.6. Pilas ............................................ ........................................... 15.7. Colas ......................... ............................................. 15.8. Colas circulares ......................................... ....................................... 15.7. Iiiiplementación de una lista ,..............._..<......................... ............................. Listas genéricas y LISO de interfaces 339 340 343 343 345 347 348 353 358 361 362 368 370 373 375 378 379 379 379 380 38 1 38 1 382 3x3 383 384 395 396 411 412 415 417 422 434 435 438 442
  • 10. A. B. C. D. E. F. G. Contenido xi APÉNDICES Palabras reservadas Java ...................................................................................... 445 Prioridad de operadores 447 Guía de sintaxis .............................................................................. Paquetes de la plataforma Java 2. Versiones 1 .3 y 1.4 Beta ............................... Recursos: libros, revistas y WEB ........................................................................ índice analítico ............................................................................................................ 529
  • 11. PRÓLOGO Cinco años después de su lanzamiento, Java se ha convertido en un estándar de la industria, en un lenguaje de programación para desarrollo de aplicaciones tanto de propósito general como de Internet, y también en un lenguaje para comenzar la formación en programación, al tener características excelentes para el aprendi- zaje. Java, desarrollado por Sun Microsystems en 1995, es un mag- nífico y completo lenguaje de programación orientado a objetos diseñado para distribuir contenidos a través de una red. Una de sus principales características es que permite operar de forma inde7 pendiente de la plataforma y del sistema operativo que se esté uti- lizando. Esto quiere decir que permite crear una aplicación que podrá descargarse de la red y funcionar posteriormente en cual- quier tipo de plataforma de hardware o software. Generalmente, y al contrario, todo programa o aplicación queda atado a dos cosas: al hardware y al sistema operativo. Así, por ejemplo, una aplica- ción Windows sólo funcionará en plataforma Wintel (equipada con procesadores Intel y sistema operativo Windows) igual que una versión creada para Mac sólo funciona sobre Power PC o Imac y Mac OS o la misma aplicación desarrollada para Unix, sólo lo hace sobre plataformas Unix y no hay forma de que funcione sobre otra máquina. La idea de Java, por el contrario, es poner una capa sobre cualquier plataforma de hardware y sobre cualquier sistema ope- rativo que permite que cualquier aplicación desarrollada en Java quede ligada únicamente a Java, independizada por lo tanto de la xiii
  • 12. xiv Prólogo plataforma. Esta concepción queda recogida en el concepto de máquina virtual JVM (Java Virtual Machine), un software que interpreta instrucciones para cual- quier máquina sobre la que esté corriendo y que permite, una vez instalado, que una misma aplicación pueda funcionar en un PC o en un Mac sin tener que tocarla. Hoy en día. cualquier sistema operativo moderno (Windows, Macintosh, Linux, Unix, Solaris. etc.) cuenta con una JVM. Así, lo que hace Java en combinación con esta «máquina» es funcionar como hardware y como sistema operativo virtual, emulan- do en software una CPU universal. Al instalar Java, éste actuará como una capa de abstracción entre un programa y el sistema operativo. otorgando una total indepen- dencia de lo que haya por debajo; es decir, cualquier aplicación funcionará en cual- quier máquina e incluso en cualquier dispositivo. Otra gran ventaja es que los programadores no tendrán que desarrollar varias versiones de la misma aplicación, puesto que el modelo de desarrollo es el mismo se trate del dispositivo más pequeño o del más grande de los servidores. Otra gran ventaja es que permite que todas las máquinas. plataformas y aplicaciones se comu- niquen entre sí accediendo desde cualquier equipo, dondequiera que esté situado, a las aplicaciones que residan en una red, ya sea Internet o una intranet o extranet. En definitiva, se puede decir que Java es lo más cercano que existe hoy día a un lenguaje de computación universal, lo que significa que puede correr en cualquier plataforma siempre y cuando una máquina virtual haya sido escrita para ella. LA GENEALOGíA DE JAVA Java es un descendiente de C++ que a su vez es descendiente directo de C. Muchas características de Java se han heredado de estos dos lenguajes. De C, Java ha here- dado su sintaxis y de C++, las características fundamentales de programación orien- tada a objetos. El diseño original de Java fue concebido por James Gosling, Patrick Naughton, Chris Warth, Ed Frank y Mike Sheridan, ingenieros y desarrolladores de Sun Mi- crosystems en 1991, que tardaron 18 meses en terminar la primera versión de tra- bajo. Este lenguaje se llamó inicialmente «Oak», y se le cambió el nombre por Java en la primavera de 1995. Sorprendentemente, la inquietud original para la creación de «Oak» no era Internet. En realidad, se buscaba un lenguaje independiente de la plataforma (es decir, de arquitectura neutra) que se pudiera utilizar para crear software que se incrustara en dispositivos electrónicos diversos tales como controles remotos, auto- móviles u hornos de microondas. Aunque el modelo de lenguaje elegido fue C++, se encontraron con que, si bien se podía compilar un programa C++ en cualquier tipo de CPU (Unidad Central de Proceso), se requería, sin embargo, un compilador C++ completo que corriese en esa CPU. El problema, en consecuencia, se convertía en compiladores caros y en gran consumo de tiempo para crear los programas. Sobre
  • 13. Prólogo XV esas premisas, Gosling y sus colegas comenzaron a pensar en un lenguaje portable, independiente de la plataforma que se pudiera utilizar para producir código que se ejecutara en una amplia variedad de CPU y bajo diferentes entornos. Entonces coinenz6 a aparecer el nuevo proyecto y se decidió llamarle Java. ¿Por qué Java es importante para Internet? Internet ha ayudado considerablemente a «catapultar» a Java al cenit del mundo de la programación de computadoras. y Java. a su vez, ha tenido un profundo impacto en Internet. La razón es muy simple: Java extiende el universo de los objetos que se mueven libremente en el ciberespacio que forma la red Internet. En una red existen dos grandes categorías de ob-jetosque se transmiten entre las computadoras conec- tadas (el servidor y la computadora personal): información pasiva y dinámica, pro- gramas activos. Un ejemplo fácil de datos pasivos son los correos electrónicos que usted recibe en su computadora o una página web que se baja de la red. Incluso si descarga un programa, está recibiendo datos pasivos hasta tanto no ejecute dicho programa. Sin embargo, existewotros tipos de objetos que se transmiten por la red: programas dinámicos autoejecutables que son agentes activos en la computadora cliente. Estos programas dinámicos en red presentan serios problemas de seguridad y portnhilidad. Java ha resuelto gran cantidad de problemas con un nuevo modelo de programa: el upplot. Java se puede utilizar para crear dos tipos de programas: aplicaciones y applets. Una aplicucicín es un programa que se ejecuta en su computadora bajo el sistema operativo de su computadora; en esencia, es un programa similar al creado utili- zando C, C++ o Pascal. Cuando se utiliza para crear aplicaciones, Java es un len- guaje de propósito general similar a cualquier otro y con características que lo hacen idóneo para programación orientada a objetos. Este libro dedica buena parte de su contenido a enseñar a diseñar, escribir y ejecutar aplicaciones, Pero Java tiene una característica notable que no tienen otros lenguajes: la posi- bilidad de crear applets. Un applet es una aplicación diseñada para ser transmitida por Internet y ejecutada por un navegador Web compatible con Java. Un applet es realmente un pequeño programa Java, descargado dinámicamente por la red, tal como una imagen, un archivo de sonido, un archivo musical MP3 o divX, o una secuencia de vídeo: pero con una notable propiedad, es un programa inteligente que puede reaccionar dinámicamente a entradas y cambios del usuario. Java es un lenguaje idóneo para resolver los problemas de seguridad y portabili- dad inherentes a los sistemas que trabajan en red. La razón fundamental de este aser- to reside en el hecho de que la salida de un compilador Java no es un código ejecutable, sino códigos de bytes (bytecode).Un hvtecode es un conjunto de instrucciones muy optimizadas diseñadas para ser ejecutadas por un sistema en tiempo de ejecución
  • 14. xvi Prólogo Java. denominado máquina virtual Java (JUVLIVit+mdMachine, JVM)que actúa como un interprete para los bytecodes. La traducción de un programa en código4 de bytes facilita la ejecución del programa en una amplia variedad de entorna y plataformas. La razón es simple: sólo es preciso implementar JVM en cada plataforma. EVOLUCIÓN DE LAS VERSIONES DE JAVA Java comenzó a desarrollarse en 1991 con el nombre de Proyecto Ouk («roble»en inglés) que era -según cuentan sus inventores- el árbol que veían desde su despa- cho. Tras muchas peripecias, Java salió al mercado en 1995 y el cambio de nombre parece que se debía a que era uno de los tipos de café que servían en una cafetería cercana al lugar en que traba.jaban los desarrolladores y ésa es la razón de que el logotipo de Java sea una humeante taza de café. Una de las primeras aplicaciones que lo soportan con especificaciones comunes para las que se comenzó a diseñar Java fue Internet; su objetivo era poder descar- gar en cualquier tipo de máquina aplicaciones residentes en la Web y ejecutarlas para trabajar con ellas contra la propia máquina del usuario. AI principio se trataba de aplicaciones HTML -páginas de puro contenido estático- y fue evolucionando y adaptándose a Internet y a sus innovaciones tecnológicas; eso significa que Java soporta XML de modo muy eficiente y las nuevas tecnologías inalámbricas, celula- res o móviles. Dos grandes especificaciones existen actualmente en torno a Java: J2EE (Java 2 Enterprise Edition) y J2ME (Java 2 MicroEdition). J2EE, está orientada al desarrollo de aplicaciones de propósito general y son numerosos los grandes fabricantes (IBM. Nokia, Motorola, Hewlett-Packard ....) que lo soportan con especificaciones comunes; J2EM, un nuevo estándar para disposi- tivos inalámbricos (móviles, de bolsillo o de mano (handhrlds))que requieren una integración en dispositivos con poco espacio físico y memoria de trabajo. J2EE es ya un auténtico estándar así reconocido por la industria y J2EM va camino de con- vertirse en otro gran estándar. que en este caso está contribuyendo a la revolución inalátnbrica que está haciendo que Internet llegue a dispositivos electrónicos de todo tipo, como teléfonos móviles (celulares), teléfonos de sobremesa, electrodo- mésticos, decodificadores de TV digital, etc. La versión original de Java que comenzó a comercializarse y expandirse con rapidez fue la 1.O, aunque pronto apareció la versión I . I , que si bien sólo cambió el segundo dígito del número, los cambios fueron más profundos de lo que el número suele indicar en la nomenclatura de los programas de software (modificaciones y pequeñas actualizaciones). De hecho, añadió numerosos elementos a la biblioteca. redefinió los sucesos (eventos) y reconfiguró la citada biblioteca. Posteriormente la versión 2, con sus diferentes kits de desarrollo, ha servido para asentar la eficiencia y calidad Java. Se puede considerar que Sun ha lanzado cinco versiones importan- tes del lenguaje Java:
  • 15. Prólogo xvii Java 1.0. Una pequeña versión centrada en la Web disponible uniformemente para todos los navegadores Web populares y que se lanzó en 1995. J m u 1.1. Una versión lanzada en 1997 con mejoras de la interfaz de usuario, manipulación de sucesos (eventos) reescrita totalmente y una tecnología de componentes denoniinada J uvuBeuns. Juiw 2 cot7 SDK 1.2. Una versión ampliada significativamente y lanzada en I Y98 con características de interfaces gráficas de usuario, conectividad de bases de datos y muchas otras mejoras. Juw 2 COIZSBK 1.3. Una versión lanzada en el 2000 que añade características notables. como multimedia mejorada, más accesibilidad y compilación más rápida. Juvrr 2 ~ 0 1 1SDK 1.3 hetu. Una versión lanzada a primeros del mes de junio de 2001 que, entre otras me.joras. introduce la posibilidad de trabajar con XML. A finales del 200 1 está prevista la salida de la versión definitiva. Además de los kits de desarrollo de Java, existen numerosas herramientas comerciales de desarrollo para los programadores de Java. Las más populares son: Symantec Visual Café. Borland Jbuilder. IBM Visual Age for Java. Sun Forte for Java. Si usted trabaja con alguna herramienta distinta de SDK 1.3y 1.4para crear pro- gramas Java a medida que lea este libro, necesita asegurarse que sus herramientas de desarrollo están actualizadas para soportar Java 2. Los programas de este libro fueron escritos y probados con Java SDK v. 1.3.1, la versión más actual existente durante el proceso de escritura del libro. Sin embargo, durante la fase de pruebas de imprenta de la obra, Sun presentó oficialmente el 29 de mayo de 2001 la versión Java SDK v. 1.4beta con la cual fueron compilados y probados todos los programas de nuevo, por lo que usted no deberá tener ningún problema. Bueno, realmente, sí se le presentará un «problema» como a nosotros, pero que por fortuna nos resolvieron los ingenieros de Sun Microsystems (Andrew Bennett y Bill Shannon), cuya ayuda y apoyo técnico destacamos de forma espe- cial. El «problema» es que al tratar de ejecutar los applets bajo SDK v. 1.4 en el navegador Web no le funcionarán completamente a menos que utilice unos progra- mas plug-in descargados del sitio de Sun. Los navegadores existentes normalmente no soportan -como es lógico- la última versión de Java y sólo cuando ellos realizan la nueva versión es cuando tienen en cuenta esta Última versión de Java. Sun ha resuelto esta situación proporcionando un plug-in (añadido/actualización o «parche»).En realidad, cualquier clase añadida a Java I .2 y posteriores no se encuentra en la implementación de Java proporcionada
  • 16. xviii Prólogo por los navegadores. por lo que se originarán errores al usar las nuevas clases. pero no debiera haber problemas cuando se está escribiendo código que no usa estas nue- vas características. No obstante, en Java 1.4 esto no es así. pues se ha eliminado la opción de coinpilación por defecto del compilador ( j r r i ~ r c . )existente en Java 1.3que iiutotiiáticliiiieiite dirigía el código a la versión I . 1 de la máquina virtual. Para solu- cionar este <<problemanse tienen dos posibilidades: Lisir siempre Jriiw Plug-in, lo cual le permitirá emplear las últiinas rne.joras del producto. o dirigir específicamen- te SLI código a una máquina virtual determinada compatible con el navegador corres- pondiente. mediante el empleo del modificador -tcrr,yet del cornpilador. Las nuevas actualizaciones Sun Microsystems es propietaria de Java; sin embargo, numerosos fabricantes con- tribuyen a la me-jora y desarrollo de las especificaciones del ectándar. Sun propor- ciona las licencias de esta tecnología pero e.jerce siempre un cierto control sobre las implenientaciones que se hacen de la misma, con el ob.jetivo de mantener la inde- pendencia de la plataforma. Ese objetivo se trata de conseguir con procesos contro- lados por el programa JCP ( J m w Coinmimit~Procrss). en los que se determina el proceso formal de estandarización y continuar asegurándose de que las especifica- ciones siguen siendo compatibles. Es decir. que Java siga siendo Java. Las actualizaciones más utilizadas actualmente son la versión Java 2 (J2SE) y los kit de desarrollo JDK 1.2 y 1.3. Sin embargo, ya está disponible (java .sun.corn/ j2 se/1.4 ) la versión más reciente. J2SE 1.4 (kit de desarro- Ilo JDK 1.4).para las plataformas Solaris. Linux y Windows. Java J2SE 1.4 (incluida en el libro y en el CD) Las aportaciones más interesantes se encuentran en la integración en el núcleo de la plataforma de la posibilidad de trabajar con XML. estableciendo así los fundamen- tos básicos para la creación y consumo de servicios Web. Existen mejoras en las JFC (JCIVCIFoundation Cln.w.7) que afectan al rendimiento de las aplicaciones cliente basadas en Si.~.ingy gráficos Java 2D. También contempla el uso de arqui- tecturas de 64 bits y se ha mejorado la seguridad con la integración de una nueva API compatible Kerberos. Direcciones Web de interés profesional Internet está plagada de direcciones de interés y excelentes relativas a Java. No obs- tante. además de los recursos que incluimos en el Apéndice G (que aconsejamos
  • 17. Prólogo xix visite gradualmente) le daremos unas direcciones de gran interés sobre todo para descargar software y documentación actualizada. http://~ava.sur~..com/j~se h t t p : / / l d v a . s u n . c n m / ! Z s e / l . 3 h t t p : / / ! a v a . s u n . _ o m / 7 2 s e / 1 . 4 / h t t p : / / j a v a . c u n . c o r r / j 2 c e / l . 3 / d o c s / . n t t p : / / j a v a . c ~ ~ n . c o - / j ~ s e / l . 4 / d o e s / kttp:/ / j a v a . c ¿ n . - c m / i : r ~ - i * ~ t s / p ~ . ~ g i n / l.3. ir.dex, h t m l h t t p : / / ] a v a . s u n . c o m / j ~ s ~ / l . 4 / ~ ~ ~ ~ / ~ ~ ~ ~ ~ / p l u g i n / i n c i e x . h:il -tto://]ava.sun.com/j2me Platufornici Jnvtr 2, Srundurtl Edition I:I .4 P1rrtufi)rmci Jaiw 2 Micro Ecli- tion, J2ME (.ri.rtemci.r.inaldm- 17rico.r) Como motor de búsqueda le recomendamos Google (www.g o o g l e . corn) , Altavista (www.alt a v i s t a . corn) o Ask (www.ask.corn),aunque si está acostumbrado a otros buscadores (tales como los incluidos en Terra, Ya. StarMedia, Excite...) es recomendable que haga pruebas prácticas para ver si real- mente le puede ser ventajoso realizar el cambio. EL LIBRO COMO HERRAMIENTA DIDÁCTICA La obra J a ~ m2. Mutiid de progrumacicín ha sido diseñada y escrita pensando en personas que desean iniciarse en el mundo de la programación de Java tanto para desarrollo de aplicaciones como para desarrollo de upplets. Tiene como objetivo primordial enseñar a programar en Java para entornos abiertos y entornos de Internet en niveles de iniciación y medios. Si bien es un libro pensado en el profe- sional y en el estudiante autodidacto, la experiencia docente de los autores se ha volcado en el libro tratando de conseguir una obra didáctica que pueda servir no sólo para su uso en cursos profesionales, sino en cursos de enseñanzas regladas tales como los módulos formativos de ciclo superior de la formación profesional y en los primeros semestres de estudios universitarios de ingeniería y ciencias. Se ha buscado que el libro fuera autosuficiente, aunque el rendimiento mayor del libro se
  • 18. xx Prólogo conseguirá cuando el lector tenga una formación mínima de fundamentos de teoría de progranmación. Conocimientos de otros lengua.jes de programación. fundamen- talmente estilo C/C++. ayudará considerablemente al aprendizaje gradual no sólo en el tiempo sino en el avance de contenidos. Por todo ello. pensamos que el libro puede servir. además de aprendimje auto- didacto. para cursos de introducción a la programación/prograninción en Java de un semestre de duración o cursos profesionales de unas 30-40 horas que y a posean experiencia en otros lengua-jesde programación. CONTENIDO Siempre que Sun lanza una nueva versión de Java hace un kit de desarrollo gratis que pone disponible en su Web para soportar a dicha versión. Este libro se ha creado utilizando el kit que se denomina Java 2 Software Development Kit, Standard Edition, Versión 1.3 (JDK 1.3).Tras lanzar Sun la versión 1.4 beta, se han probado todas las aplicaciones y applefs con esta nueva versión (JDK 1.4). Así mismo, se han actualizado los paquetes de la plataforma Java 2 para incluir ambas versiones y el contenido del CD ad.junto al libro que incluye dichas versio- nes para los entornos Windows y Linux. El libro consta de quince capítiilos y siete apéndices (A-G). Un breve contenido de los capítulos y apéndices se reseña a con- tinuación: Capítulo 1. Introducción CI JLiva. En este capítulo se realiza una descripción de la historia de Java junto a una breve descripción de las características más notables. Se describe el concepto de aplicación y de uppler y los métodos para crear un programa Java. Sun tiene disponible en su página Web (www.sun.com) el Kit de Desarrollo necesario para la compilación y ejecución de programas denominado JDK (Jui’u Development Kif)y en este capítulo se explica este entorno de desarro- llo, así como los errores típicos que se producen en la fase depuración y puesta a punto de programas por parte del usuario. Capítulo 2. Caructeri~ricusdel lenguaje Javu. Todo lenguaje de programación. y Java no es una excepción, dispone de un conjunto de elementos básicos que cons- tituyen su núcleo fundamental para la escritura de programas. En el capítulo se des- criben: palabras reservadas. identificadores, tipos de datos. variables, constantes y operadores. así como una breve introducción a las clases y bibliotecas de clases de Java. Capítulo 3. Decisiorzes y bucles. Los programas requieren siempre de sentencias y estructuras de control para seguir la secuencia de e.jecución de sus instrucciones. La ejecución secuencia1 de un programa requiere de modo continuo una toma de decisiones e iteraciones o repeticiones: para ello, se utilizan sentencias de decisión y de iteración para realizar los bucles o repeticiones de acciones. Se describen
  • 19. Prólogo xxi las sentencias básicas: i f , ef-else, f o r , while, do-while, break y continue. Capítulo 4. C1usr.s. ohjrro.s y inPtodos. El concepto de clase y de objeto como instancia o e.jemplar de una clase se analizan con el apoyo de la sintaxis utilizada para SLI escritura. Capítulo 5. Herencicr. Una de las propiedades fundamentales del concepto de orientación a objetos es la herencia. Se explica el concepto, así como el método de implementar en Java dicha propiedad y sus ventajas e inconvenientes. Capítulo 6. Eiic~rrp,sirlcin~ieiitoy polinzorflsmo. Otras dos propiedades fundamen- tales de la orientación a objetos son el encapsulamiento de la información y el con- cepto de polimorfismo. Ambas propiedades. los métodos y sintaxis se describen en este capítulo. Capítulo 7. Arruys. La información básica manejada por los programas se or- ganiza en estructuras de datos. Se describe el array como representante genuino de listas. tablas o vectores. así como métodos para ordenar estas estructuras de infor- mación y realizar búsqueda de información en las mismas. Capítulo 8. Cadenus y,fechus. El concepto de cadena como secuencia o lista de caracteres y las clases específicas necesarias para su manipulación se analizan en este capítulo. También se considera el concepto casi siempre necesario en un programa del tratamiento de las fechas como elementos básicos de medición del tiempo. Capítulo 9. iizterfilces ,qrcíficn.sde usuario. Una de las grandes virtudes de los lenguajes de programación actuales, y Java en particular, es la facilidad que ofrece al usuario para construir interfaces gráficas sencillas y adaptadas al entorno de tra- bajo. Capítulo 10. Gestión cíc eventos. La programación mediante eventos o sucesos es otra de las características sobresalientes que aporta Java al mundo de la progra- mación. El concepto y los tipos de eventos así como métodos para su gestión y manipulación se describen en este capítulo. Capítulo 11. Applers. Los programas conocidos como applets son, sin género de dudas. el puente ideal para la conexión con el mundo Internet y una de las propie- dades de Java que lo han hecho tan popular. Una breve introducción al lenguaje HTML y el modo de realizar applrts son la base del capítulo. Capítulo 12. Programucion concurrente: Hilos de ejecución. Otra propiedad fundamental de Java como lenguaje de tiempo real es la posibilidad de manejar pro- cesos en paralelo. El concepto de hilo (thread),su manipulación e implementación se analizan en este capítulo. Capítulo 13. Manqjo dr excepciones. El concepto de excepciones es vital en la programación moderna. Lenguajes como Ada y C++ lo incorporaron a su sintaxis, y Java, siguiendo los pasos de estos dos potentes lenguajes, ha incluido el trata- miento de excepciones en sus compiladores. Capítulo 14.Archivos. Las estructuras de datos organizados en torno a archivos o ficheros son pieza fundamental en el proceso de información de cualquier orga-
  • 20. xxii Contenido nización. Su organización. diseño y construcción constituyen el contenido funda- mental de este capítulo. Capítulo 15. E.struc~tirrn.sde cirrtos defliiicíti.spor 01 progrtrniudor: Una vez que el programador sabe mane.jar estructuras de datos básicas como arrays y archivos, sen- tirá la necesidad con relativa frecuencia de utilizar estructuras de datos dinámicas tales como listas, pilas y colas. Su concepto y métodos de iinplementación se expli- can en este último capítulo. En los apéndices. se incluyen herramientas de trabajo complementarias para el programador tales como: Lisrndo de pa1cihrci.s r-eservad(is Juvci (A); fiihla de prio- riúud de operadores (B);Guía de sintaxis de JLILYI2, que facilita la consulta al lec- tor en la fase de escritura y depuración de prograinas (C);Paquetes de la platuforma Jain 3 más utilizados e incluidos en las versiones de 1.3.1 y 1.4 de los kit de desa- rrollo JDK (0);Una conzpuracicín eritw l o s 1rnguuje.s de progr-armickjn orientados ci ohjetos mrís p o p l ~ i r e sen la uctucilidd: C++ y Java ( E ) ;Coriteriido del CD como elemento de ayuda en el aprendizaje y formación en Java para el lector y herra- mienta de software complementaria para cursos y seminarios en laboratorios de programación (F);Recursos de Juiu: libros, revistas y sitios Web de interés. CD QUE ACOMPAÑA AL LIBRO El disco compacto que se adjunta en las tapas de este libro contiene la versión Java 2 y el kit de desarrollo JDK de Sun versiones 1.3.1 y 1.4 para entornos Windows y Linux. Así mismo, se han incluido todas las aplicaciones y applets sobresalientes incluidos en el libro con el ob-jetivofundamental de ayudarle en el proceso de compilación y ejecución. AGRADECIMIENTOS Como ya hemos indicado anteriormente, no podemos terminar este prólogo sin expresar nuestra gratitud a todo el equipo de Sun Microsystems en Palo Alto (Ca- lifornia), su disponibilidad y efectividad a la hora de resolver cualquier consulta ha resultado una inestimable ayuda en el desarrollo de esta obra. Evidentemente com- portamientos profesionales como &tos son algunos de los millones de razones para usar Java. Así pues, reiteramos nuestro agradecimiento a Sun Microsystems y en particular a los ingenieros: Andrew Bennett Engineering Manager. Sun Microsystems. Inc.
  • 21. CONTENIDO 1. I . La historia de Java. 1.2. ‘Qué es Java? 1.3. Características de Java. 1.4. 1.5. Especificaciones del lenguaje Java. 1.6. Aplicaciones y applets. 1.7. Creación de programas. 1.8. Componentes de una aplicación. 1.9. Herramientas de desarrollo Java. 1.I O. Una aplicación práctica de Java. 1.I I . Estructura de un programa aplicación en Java. 1.I 2. Errores de programación. La programación orientada a objetos como base de Java. m 1
  • 22. 2 Java 2. Manual de programación Este capítulo introduce al lector en el mundo de Java, su fortaleza y sus debilidades. Describe la programación en Java y por qué es diferente de la programación en cualquier otro lenguaje, así como las ventajas que estas diferencias pueden representar en la crea- ción de aplicaciones nuevas y eficientes. El futuro de la computación está influenciado por Internet y Java es una parte importante de ese futuro. Java es el lenguaje de programación de lnternet y es una plataforma cruzada, orientada a objetos, usada en la Red y preparada para multimedia. Desde su nacimiento real en 1995, Java se ha convertido en un .lenguaje maduro para el desarrollo de aplicaciones críticas y eficientes. Este capítulo comienza con una breve historia de Java y sus carac- terísticas más sobresalientes, así como ejemplos sencillos de apli- caciones y el concepto de applefs Java. 1.1. LA HISTORIA DE JAVA Java no fue creado originalmente para la red internet. Sun Microsystems comenzó a desarrollarlo con el objetivo de crear un lenguaje, independiente de la plataforma y del sistema operativo, para el desarrollo de electrónica de consumo (dispositivos electrónicos inteligentes, como televisores, vídeos, equipos de música, etc.). El proyecto original, denominado Green comenzó apoyándose en C++, pero a medida que se progresaba en su desarrollo el equipo creador de <<Green»comenzó a encontrarse con dificultades, especialmente deportahilidad. Para evitar estas difi- cultades, decidieron desarrollar su propio lenguaje y en agosto de 1991 nació un nuevo lenguaje orientado a objetos. Este lenguaje fue bautizado con el nombre de Oak. En 1993, el proyecto Green se volvió a renombrar y pasó a llamarse First Penon Juc. Sun invirtió un gran presupuesto y esfuerzo humano para intentar ven- der esta tecnología, hardware y software, sin gran éxito. A mitad de 1993, se lanzó Mosaic, el primer navegador para la Web y comenzó a crecer el interés por Internet (y en particular por la World Wide Web). Entonces, se rediseñó el lenguaje para desarrollar aplicaciones para internet y, en enero de 1995, Oak se convirtió en Java. Sun lanzó el entorno JDK 1.O en 1996, primera versión del kit de desarrollo de dominio público, que se convirtió en la primera especificación for- mal de la plataforma Java. Desde entonces se han lanzado diferentes versiones, aun- que la primera comercial se denominó JDK 1.1 y se lanzó a principios de 1997.
  • 23. Introducción a Java 3 En diciembre de 1998 Sun lanzó la plataforma Java 2 (que se conoció como JDK 1.2 durante su fase de pruebas beta). Esta versión de Java ya representó la madurez de la plataforma Java. Sun renombró Java 1.2 como Java 2. El paquete de Java que se utiliza en esta obra, incluye el compilador Java y otras utilidades, se denomina oficialmente Java 2 JDK, versión 1.3. Los programas Java se pueden incluir (((embeber))o ((empotrar)))en páginas HTML y descargarse por navegadores Web para llevar animaciones e interacciones a los clientes Web. Sin embargo, la potencia de Java no se limita a aplicaciones Web, Java es un lenguaje de programación de propósito general que posee carac- terísticas completas para programación de aplicaciones independientes o autóno- mas. Java, como lenguaje, es fundamentalmente orientado a objetos. Se diseñó desde sus orígenes como verdadero lenguaje orientado a objetos, al contrario que otros lenguajes, como C++ y Ada, que tienen propiedades de lenguajes procedi- mentales. La programación orientada a objetos (POO) es también, actualmente, un enfoque de programación muy popular que está reemplazando poco a poco a las téc- nicas tradicionales de programación procedimental o estructurada. La última versión lanzada por Sun es Java 2 JDK 1.4 Beta. En la dirección www .s u n . corn se pueden encontrar todas las versiones para Windows9x, Windows 2000/NT, UNIX, Unix (Solaris), Macintosh,... 1.2. ¿QUÉ ES JAVA? El significado de Java tal y como se le conoce en la actualidad es el de un len- guaje de programación y un entorno para ejecución de programas escritos en el lenguaje Java.AI contrario que los compiladores tradicionales, que convierten el códi- go fuente en instrucciones a nivel de máquina, el compilador Java traduce el código fuente Java en instrucciones que son interpretadas por la Máquina Virtual Java (JVM, Java Virtual Machine). A diferencia de los lenguajes C y C++ en los que está inspirado, Java es un lenguaje interpretado. Aunque hoy en día Java es por excelencia el lenguaje de programación para Internet y la World Wide Web en particular, Java no comenzó como proyecto Internet y por esta circunstancia es idóneo para tareas de programación de pro- pósito general y, de hecho, muchas de las herramientas Java están escritas en Java. 1.2.1. Java como lenguaje de Internet Java es un lenguaje para programar en Internet que trata de resolver dos problemas claves con el contenido de Internet:
  • 24. 4 Java 2. Manual de programación Computadora local Sistema operativo Navegador Java Máquinavirtual Java En la actualidad, el contenido de la WWW es pasivo y estático. La entrega (Deliverry) del contenido WWW es dependiente de la configura- ción de cada navegador Web de usuario. Computadoraservidor (host) Código fuente Java .Código fuente En el mundo de la Web, Java es una tecnología facilitadora que permite a los desarrolladores crear páginas Web que se entregarán de modo consistente a todos los usuarios con un navegador habilitado para Java y con independencia de la pla- taforma hardware y el sistema operativo que se esté utilizando'. Dado que el códi- go fuente se interpreta, si existe un intérprete Java para una plataforma específica hardware o sistema operativo, se pueden escribir programas con el conocimiento de que serán útiles en esa plataforma. La Figura 1.1 muestra cómo el código fuente Java se transfiere en Internet. En la computadora servidor (host)se almacena el código fuente. Cuando un usuario de una computadora local se conecta con el servidor a través de Internet mediante un navegador habilitado para Java, el código fuente se transfiere de la computadora servidor a la computadora local. 1.2.2. Java como lenguaje de propósito general A medida que Java se populariza en desarrollos de Internet, gana también como len- guaje de propósito general. Java es totalmente portable a gran variedad de platafor- mas hardware y sistemas operativos. Java tiene muchos conceptos de sintaxis de C y C++, especialmente de C++, del que es un lenguaje derivado. Añade a C++ propiedades de gestión automática de memoria y soporte a nivel de lenguaje para aplicaciones multihilo. Por otra parte, Java, en principio a nivel medio, es más fácil de aprender y más fácil de utilizar que C++ ya que las características más complejas de C++ han sido eliminadas de Java: herencia múltiple, punteros (apuntadores) y sentencia g o to entre otras. ' En Cohn et al., Java. DeveloperS Reference, Indianapolis: Sams Net. 1996. se describen las caracte- rísticas fundamentales del lenguaje Java original.
  • 25. Introducción a Java 5 Las iinpleinentaciones de la Máquina Virtual Java pueden ser muy eficaces y eso hace posible que los programas Java se ejecuten tan rápidamente como los programas C++. Esta característica clave de Java, unida a sus fortalezas como lenguaje de Internet, lo hacen muy adecuado para desarrollos en sistemas clienteiservidor, soporte masivo de los sistemas informáticos de la mayoría de las empresas y organizaciones. Las propiedades que se verán más adelante hacen a Java doblemente idóneo para desarrollos cliente/servidor y para desarrollos de Internet. 1.3. CARACTERISTICAS DE JAVA Java ha conseguido una enorme popularidad. Su rápida difusión e implantación en el mundo de la programación en Internet y fuera de línea (offline)ha sido posible gra- cias a sus importantes características. Los creadores de Java escribieron un artículo, ya clásico, en el que definían al lenguaje como sencillo, orientado a objetos, distri- buido, interpretado, robusto, seguro, arquitectura neutra, alto rendimiento, multihilo y dinámico. Analicemos más detenidamente cada característica. 1.3.1. Sencillo Los lenguajes de programación orientados a objetos no son sencillos ni fáciles de utilizar, pero Java es un poco más fácil que el popular C++*,lenguaje de desarrollo de software más popular hasta la implantación de Java. Java ha simplificado la programación en C++, añadiendo características funda- mentales de C++ y eliminando alguna de las características que hacen a C++ un len- guaje difícil y complicado. Java es simple porque consta sólo de tres tipos de datos primitivos: números, boolean y arrays. Todo en Java es una clase. Por ejemplo, las cadenas son objetos verdaderos y no arrays de caracteres. Otros conceptos que hacen la programación en C++ más complicada son los punteros y la herencia múltiple. Java elimina los punteros y reemplaza la herencia múltiple de C++ con una estructura única deno- minada interfaz ( i nter face). Java utiliza asignación y recolección automática de basura (garbage collection), aunque C++ requiere al programador la asignación de memoria y recolección de basura. Otra característica importante es que la elegante sintaxis de Java hace más fácil la escritura de programas. En C++. Inicicición y Refereiicia (McCraw-Hill, 1999).de Luis Joyanes y Héctor Castán, podrá encon- trar una guía de iniciación con enfoque similar a esta obra. si usted necesita iniciarse en C++.
  • 26. 6 Java 2. Manual de programación 1.3.2. Orientado a objetos La programación orientada a objetos modela el inundo real, cualquier cosa del inundo puede ser inodelada cotno un ob-jeto.Así una circunferencia es un objeto, un autoiii¿hiI es un &jeto, una ventana es un objeto, un libro cs un ob.jeto e incluso un préstamo o una tarjeta de crédito son objetos. Un prograina Java se denomina oricii- ttrtio LI oi?jc'/o.s debido a que la programación en Java se centra en la creación, mani- pulación y coiistruccih de objetos. Un objeto tiene p i ~ ) p i ~ & ~ i c ~ , s(un estado) y un coniportainieiito. Las propiedades o el estado se detinen iitilinndo datos y el coinportainiento se define utilizando métodos. Los ob-jetos sc detitien utilizando clases en Java. Una clase es similar a una plantilla para construir objetos. Con la excepcicín de los tipos de datos primiti- os. todo en Ja.a es uti ob.jeto. En Java, al contrario de lo que sucede en C++, no hay fuiicioiies globales: todas las iiinciones se in,ocan a tra,Cs de tin objeto. Por e-jeinplo, se puede definir un objeto c u a d r a d o mediante una clase c u a d r a d o (Fig. l.2), con un l a d o (propiedad) y caliularSuperficie como el mt.todo qiie encuentre o calcule la superficie del cuadrado. Clase Instanoar I I d d T í 1 lnstanciar cuadrado de lado 1O cuadrado de lado25 Figura 1.2. Dos objetos , ~ dlrCricde lados 10 y 25 Se crean a partir de la clase r, i a j r ~ i Un objeto es una realización concreta de una descripción de una clase. El pro- ceso de creacicín de objetos se denomina ii~7~f~1~1~.i~rc,iÓi?(crear instancias) de una clase. AI iiufcrwitn. una clase. se crean objetos. Así. es posible crear un objeto c u a - d r a d ~instaiiciando la clase con un lado determinado. por ejemplo se puede crear un cuadrado de lado I O y otro cuadrado de lado 25. Se puede encontrar cl área de los respecti os cuadrados usando el inktodo c a l c u l a r S u p e r fLcie. Uti programa consta de una o más clases que se disponen en una jerarquía en modo árbol, de modo qiie una clase hija puede heredar propiedades y comporta- mientos de su clase padrc (ascendente). Java con un conjunto de clases pre- dctinidas, agrupadas en paquetes que se pueden utilizar en los programas,
  • 27. Introducción a Java 7 La programación orientada a objetos proporciona mayor flexibilidad, modulari- dad y reusabilidad. En la actualidad está ya muy implantado este tipo de programa- ción y Java se convertirá en breve plazo en uno de los lenguajes más usados de propósito general. 1.3.3. Distribuido La computación distribuida implica que varias computadoras trabajan juntas en la red. Java ha sido diseñado para facilitar la construcción de aplicaciones distribuidas mediante una colección de clases para uso en aplicaciones en red. La capacidad de red está incorporada a Java. La escritura de programas en red es similar a enviar y recibir datos a y desde un archivo. La utilización de una URL (Uniform Resource Locator) de Java puede hacer que una aplicación acceda fácilmente a un servidor remoto. 1.3.4. Interpretado Java es interpretado y se necesita un intérprete para ejecutar programas Java. Los programas se compilan en una Máquina Virtual Java generándose un código inter- medio denominado bytecode. El bytecode es independiente de la máquina y se puede ejecutar en cualquier máquina que tenga un intérprete Java. Normalmente, un cornpilador traduce un programa en un lenguaje de alto nivel a código máquina. El código sólo se puede ejecutar en la máquina nativa. Si se eje- cuta el programa en otras máquinas, éste ha de ser recompilado. Así por ejemplo, cuando un programa escrito en C++ se compila en Windows, el código ejecutable generado por el compilador sólo se puede ejecutar en una plataforma Windows. En el caso de Java, se compila el código fuente una sola vez y el bytecode generado por el compilador Java se puede ejecutar en cualquier plataforma. Nota: Los programas Java no necesitan ser recompilados en una máquina des- tino. Se compilan en un lenguaje ensamblador para una máquina imaginaria, denominada máquina virtual. Sin embargo, los intérpretes Java tienen una seria desventaja sobre los sistemas convencionales. Son, normalmente, mucho más lentos en ejecución. Innovaciones recientes en el mundo Java han avanzado sobre las ideas de los intérpretes y han aparecido compiladores JIT (just-in-time) que leen la representación en bytecode independiente de la máquina de un programa Java, e inmediatamente antes de que
  • 28. 8 Java 2. Manual de programación la ejecución traduzca la representación en b-ytecode en instrucciones de la máquina real del sistema en el que el programa Java se está ejecutando. Dado que los progra- mas Java se ejecutan a continuación como instrucciones máquina, pueden ser casi tan rápidos como programas compilados en lenguajes más convencionales para pla- taformas de hardware específicas y mantener la portabilidad de la máquina virtual. 1.3.5. Robusto Robusto significa fiable. Ningún lenguaje puede asegurar fiabilidad completa. Java se ha escrito pensando en la verificación de posibles errores y por ello como un lenguaje fuertementetipificado (con tipos). Java ha eliminado ciertos tipos de construcciones de programación presentes en otros lenguajes que son propensas a errores. No soporta, por ejemplo, punteros (apuntadores) y tiene una característica de manejo de excepcio- nes en tiempo de ejecución para proporcionar robustez en la programación. Regla: Java utiliza recolección de basura en tiempo de ejecución en vez de liberación explícita de memoria. En lenguajes como C++ es necesario borrar o liberar memoria una vez que el programa ha terminado. 1.3.6. Seguro Java, como lenguaje de programación para Internet, se utiliza en un entorno distri- buido y en red. Se puede descargar un applet Java y ejecutarlo en su computadora sin que se produzcan daños en su sistema, ya que Java implementa diversos meca- nismos de seguridad para proteger su sistema de daños provocados por un progra- ma stray. La seguridad se basa en la premisa de que nada debe ser trusted. Naturalmente la seguridad absoluta no existe, pero, aunque se encuentran pro- blemas de seguridad en Java, éstos no son lo suficientemente notables como para producir trastornos apreciables. Nota: Existen numerosos sitios en la Red para información sobre seguridad de computadoras. Este sitio de la universidad de Princeton (allí impartió clase el físico universal Einstein) es excelente para estudiar problemas de seguridad informática, especialmente para Java, ActiveX y JavaScript. www.cs.princeton.edu/sip/.
  • 29. Introducción a Java 9 1.3.7. Arquitectura neutral Una de las características más notables de Java es que es de arquitectura neutral, lo que también se define como independiente de la plataforma. Se puede escribir un programa que se ejecute en cualquier plataforma con una Máquina Virtual Java. Se pueden ejecutar applets de Java en un navegador Web; pero Java es algo más que escribir upplets de Java, ya que se pueden también ejecutar aplicaciones Java autónomas (stand-alone)directamente en sistemas operativos que utilicen un intér- prete Java. I I Importante: Utilizando Java, los desarrolladores necesitan escribir una Única versión para ejecutarse en todas las plataformas, dado que los bytecodes no se corresponden a ninguna máquina específica y trabajan en todas las máquinas. Comentario: Un programa Java es el mismo si se ejecuta en un PC, un Macintosh, o un sistema Unix. Es distinto de los lenguajes convencionales tales como C/C++ 1.3.8. Portable Java es un lenguaje de alto nivel que permite escribir tanto programas convencio- nales como aplicaciones para Internet (applets). Dado que Internet es una red for- mada por equipos muy diferentes interconectados por todo el mundo, resulta fundamental para los programas que rueden en ella su independencia de la plata- forma en la que van a ser ejecutados. Dicha independencia se obtiene en Java gra- cias a que el compilador Java genera un código intermedio, bytecode (código byte), no ejecutable por sí mismo en ninguna plataforma, pero que puede ser ejecutado a gran velocidad mediante un intérprete incorporado en la máquina virtual Java. En las diferentes plataformas existirán máquinas virtuales específicas, y cuando el código byte llegue a esas máquinas virtuales será interpretado pasándolo al código adecuado para la computadora receptor de la aplicación. Las máquinas virtuales Java son programas capaces, entre otras cosas, de interpretar el código byte, que pueden venir incluidos en los navegadores, proporcionados con el sistema operativo, con el entorno Java o bien obtenerse a través de Internet (mediante descarga del corres- pondiente programa). Por tanto, los programas Java pueden ejecutarse en cualquier plataforma sin necesidad de ser recompilados; es decir, son muy portables.
  • 30. 10 Java 2. Manual de programación Pero la portabilidad de Java aún va más allá; Java fue diseñado de modo que pueda ser transferido a nuekas arquitecturas. En Java todos los tipos de datos primitivos son de tamaños definidos con inde- pendencia de la máquina o sistema operativo en el que se ejecute el programa. Esta característica es distinta de C o C++, en los que el tamaño de los tipos dependerá del coinpilador y del sistema operativo. Nota: El tamaño fijo de los números hace el programa portable. I I Regla: El entorno Java es portable a nuevos sistemas operativos y hardware. El compilador Java está escrito en Java. 1 I 1.3.9. Alto rendimiento Los coinpiladores de Java han ido mejorando sus prestaciones en las sucesivas !ersiones. Los nuevos compiladores conocidos como JlT @st-in-tirvze) permiten que prograinas Java independientes de la plataforma se ejecuten con casi el mismo rendimiento en tiempo de ejecución que los lenguajes convencionales coinpi1ados. 1.3.10. Multíhilo Java es uno de los primeros lenguajes que se han diseñado explícitamente para tener la posibilidad de múltiples hilos de ejecución; es decir, Java es multihilo (multith- reudit7g).Multihilo es la capacidad de un programa de ejecutar varias tareas simul- táneamente. Por ejemplo, la descarga de un archivo de vídeo mientras se graba el vídeo. La Programación multihilo está integrada en Java. En otros lenguajes se tiene que llamar a procedimientos específicos de sistemas operativos para permitir mul- tihilo. Los hilos sincronizados son muy Útiles en la creación de aplicaciones distribui- das y en red. Por ejemplo, una aplicación puede comunicarse con un servidor remo- to en un hilo, mientras que interactúa con un usuario en otro hilo diferente. Esta propiedad es muy útil en programación de redes y de interfaces gráficas de usuario. Un usuario de Internet puede oír una emisora de música mientras navega por una página Web y un servidor puede servir a múltiples clientes al mismo tiempo.
  • 31. introducción a Java 11 1.3.11. Dinámico Como Java es interpretado, es un lenguaje muy dinámico. En tiempo de ejecución, el entorno Java puede extenderse (ampliarse) mediante enlace en clases que pueden estar localizadas en servidores remotos o en una red (por ejemplo, Intranet/Intemet). Es una gran ventaja sobre lenguajes tradicionales como C++ que enlaza clases antes del momento de la ejecución. Se pueden añadir libremente nuevos métodos y propiedades a una clase sin afec- tar a sus clientes. Por ejemplo, en la clase Cuadrado se pueden añadir nuevos datos que indiquen el color del polígono y un nuevo método que calcule el períme- tro del cuadrado. El programa cliente original que utiliza la clase Cuadrado per- manece igual. En tiempo de ejecución, Java carga clases a medida que se necesitan. 1.4. LA PROGRAMACIÓN ORIENTADA A OBJETOS COMO BASE DE JAVA La programación orientada a objetos (POO) es la base de Java y constituye una nueva forma de organización del conocimientoen la que las entidades centrales son los objetos. En un objeto se unen una serie de datos con una relación lógica entre ellos, a los que se denomina variables de instancia,con las rutinas necesarias para manipularlos,a las que se denomina métodos. Los objetos se comunican unos con otros mediante interfaces bien definidasa través depuso de mensajes;en PO0 los mensajes están asociados con méto- dos, de forma que cuando un objeto recibe un mensaje, ejecuta el método asociado. Cuando se escribe un programa utilizando programación orientada a objetos, no se definen verdaderos objetos, sino clases; una clase es como una plantilla para construir varios objetos con características similares. Los objetos se crean cuando se define una variable de su clase. En las clases pueden existir unos métodos especiales denominados constructores que se llaman siempre que se crea un objeto de esa clase y cuya misión es iniciar el objeto. Los destructores son otros métodos especiales que pueden existir en las clases y cuya misión es realizar cualquier tarea final que corresponda realizar en el momento de destruir el objeto. Las propiedades fundamentales de los objetos son: El encapsulamiento, que consiste en la combinación de los datos y las opera- ciones que se pueden ejecutar sobre esos datos en un objeto, impidiendo usos indebidos al forzar que el acceso a los datos se efectúe siempre a través de los métodos del objeto. En Java, la base del encapsulamiento es la clase, donde se define la estructura y el comportamiento que serán compartidos por el grupo de objetos pertenecientes a la misma. Para hacer referencia a los componentes accesibles de un objeto será necesario especificar su sintaxis: nombreobjeto.nombreComponente.
  • 32. 12 Java 2. Manual de programación La herencia es la capacidad para crear nuevas clases (descendientes) que se construyen sobre otras existentes, permitiendo que éstas les transmitan sus pro- piedades. En programación orientada a objetos, la reutilización de código se efectúa creando una subclase que constituye una restricción o extensión de la clase base, de la cual hereda sus propiedades. El polimorjismo consigue que un mismo mensaje pueda actuar sobre diferen- tes tipos de objetos y comportarse de modo distinto. El polimorfismo adquiere su máxima expresión en la derivación o extensión de clases; es decir, cuando se obtienen nuevas clases a partir de una ya existente mediante la propiedad de derivación de clases o herencia. 1.5. ESPECIFICACIONES DEL LENGUAJE JAVA Los lenguajes de computadoras tienen reglas estrictas de uso que deben seguirse cuan- do se escriben programas con el objeto de ser comprendidos por la computadora. La referencia completa del estándar Java se encuentra en el libro Java Languaje Specification, de James Gosling, Prill Jorg y Grey Steele (Addison Wesley, 1996). La especificación es una definición técnica del lenguaje que incluye sintaxis, estructura y la interfaz de programación de aplicaciones (API, application pro- gramming interfuce) que contiene clases predefinidas. El lenguaje evoluciona rápi- damente y el mejor lugar para consultar las últimas versiones y actualizaciones del mismo se encuentra en el sitio Web de internet de Sun Las versiones de Java de Sun se incluyen en JDK (Java Deivlupment Kit), que es un conjunto de tierramientas que incluyen un cornpilador, un intérprete, el entor- no de ejecución Java, el lenguaje estándar Java y otras utilidades. En la actualidad existen cuatro versiones JDK. Este libro es compatible con JDK 1.4 Beta, que es una mejora sustancial de las versiones anteriores JDK 1.O y JDK 1.1. La nueva versión JDK 1.3 incluye un compilador JIT (jusf-in-time)para ejecutar el código Java. El entorno JDK está disponible para Windows9Y98, Windows NT/2000 y Solaris, pero existen muchos entornos de desarrollo para Java: JBuilder de Borland, Visual Age Windows de IBM, Visual J++ de Microsoft, Visual Café de Symantec, etc. Nota: Todos los programas de este libro se pueden compilar y ejecutar en los entornos JDK 1.2, JDK 1.3 y JDK 1.4 y deben poder trabajar con cualquier herramienta de desarrollo que soporte las citadas versiones.
  • 33. Introducción a Java 13 JDK consta de un conjunto de programas independientes cada uno de los cuales se invoca desde una línea de órdenes. Las herramientas de desarrollo más impor- tantes se pueden encontrar en los siguientes sitios de Internet: Café de Symantec www.symantec.com Sun Java Workshop www.javasof.com Visual Age for Java by IBM JFactory de Roge Wave www.rogewave.com JBuilder de lmprise www.imprise.com Visual J++ de Microsoft www.microsoft.com Forte de Sun www.sun.com www.ibm.com Estas herramientas proporcionan un EíD (Entorno Integrado de Desarrollo) que permite el rápido desarrollo de programas. Le recomendamos utilice herramientas EID para desarrollo de programas y ejecute las tareas integradas en la interfaz grá- fica de usuario, tales como: edición, compilación, construcción, depuración y ayuda en linea. 1.6. APLICACIONES Y APPLETS Los programas en Java se dividen en dos grandes categorías:aplicaciones y applets. Las aplicaciones son programas autónomos independientes (standalone),tal como cualquier programa escrito utilizando lenguajes de alto nivel, como C++, C, Ada, etc.; las aplicaciones se pueden ejecutar en cualquier computadora con un intérpre- te de Java y son ideales para desarrollo de software. Los applets son un tipo espe- cial de programas Java que se pueden ejecutar directamente en un navegador Web compatible Java; los applets son adecuados para desarrollar proyectos Web. Los applets son programas que están incrustados, ((empotrados))(embedded)en otro lenguaje; así cuando se utiliza Java en una página Web, el código Java se empo- tra dentro del código HTML. Por el contrario, una aplicación es un programa Java que no está incrustado en HTML ni en ningún otro lenguaje y puede ser ejecutado de modo autónomo. Naturalmente, a primera vista parece deducirse que las aplicaciones son más grandes (y en principio más complejas) que los applets. Sin embargo, esto no es necesariamente verdad. 1.6.1 Semejanzas y diferencias entre aplicaciones y applets Una de las primeras preguntas que suele hacerse el programador principiante en Java es: ;Cuándo debo utilizar una aplicación y cuándo un applet? La respuesta no
  • 34. 14 Java 2. Manual de programación siempre es fácil, pero ineludiblemente pasa por conocer las semejanzas y diferen- cias que tienen ambos tipos de programas. Gran parte del código de las aplicacio- nes y los upplets es el mismo, presentándose las diferencias al considerar los entornos de ejecución de los programas. Regla: Las aplicaciones se ejecutan como programas independientes o autónomos, Los upplets deben ejecutarse en un navegador Web. de modo similar a cualquier otro lenguaje de alto nivel. El desarrollo de las aplicaciones Java suele ser algo más rápido de desarrollar que los upplets, debido a que no necesita crear un archivo HTML y cargarlo en un navegador Web para visualizar los resultados. Sugerencia:Si su programa no necesita ejecutarse en un navegador Web, elija crear aplicaciones. Un aspecto muy importante en el desarrollo de programas es la seguridad. Los upplets necesitan unas condiciones de seguridad para evitar daños en el sistema en el que está funcionando el navegador, por tanto, tienen ciertas limitaciones. Algunas limitaciones a considerar son: Los applets no pueden leer o escribir en el sistema de archivos de la computa- dora, pues en caso contrario podrían producir daños en archivos y propagar virus. Los upplets no pueden establecer conexiones entre la computadora de un usua- rio y otra computadora, excepto que sea el servidor donde están almacenados los applets'. Los applets no pueden ejecutar programas de la computadora donde reside el navegador, dado que podrían originar daños al sistema. Por el contrario, las aplicaciones pueden interactuar directamente con la compu- tadora sobre la que se ejecutan, sin las limitaciones anteriormente mencionadas. Esta actividad comienza ya a desarrollarse con las tecnologías Napster creadas por Fanning, un estu- diante norteamericano a primeros del año 2000. Otras tecnologías similares con Gnutella, Scour, etc., y se las conoce de modo genérico como tecnologías P2P (peer-ro-peer).
  • 35. Introducción a Java 15 Notas: En general, se puede convertir un applet Java para ejecutarse como una apli- Una aplicación no siempre se puede convertir para ejecutarse como un cación sin pérdida de funcionalidad. upplet, debido a las limitaciones de seguridad de los applets. En este libro aprenderá fundamentalmente a escribir aplicaciones Java, aunque también dedicaremos atención especial a desarrollar applets. 1.7. CREACIÓN DE PROGRAMAS Antes de que una computadora pueda procesar un programa en un lenguaje de alto nivel, el programador debe introducir el programa fuente en la computadora y la computadora a su vez debe almacenarlo en un formato ejecutable en memoria. Las etapas clásicas en un lenguaje tradicional son: edición, compilación, enlace, ejecu- ción y depuración de un programa. Las herramientas fundamentales empleadas en el proceso de creación de programas son, por tanto: editor, compilador, depurador y, naturalmente, el sistema operativo. El editor es un programa utilizado para crear, guardar (salvar o almacenar) y corregir archivos fuente (escritos en lenguaje Java). El compilador es un programa que traduce un programa escrito en un lenguaje de alto nivel a un lenguaje máqui- na. El depurador es un programa que ayuda a localizar errores en otros programas. El sistema operativo es el programa con el que interactúa el usuario con el objeto de especificar qué programas de aplicación y/u operaciones del sistema debe ejecu- tar la computadora (los sistemas operativos más utilizados son: Windows 9x/NT/2000, Linux, Unix, Solaris y Mac)'. 1.7.1 Etapas para crear un programa La creación de un programa debe comenzar con la escritura del código fuente correspondiente a la aplicación. Cada programa Java debe tener al menos una clase. Un ejemplo de una aplicación Java sencilla que sirva de modelo es el popular ((Hola mundo)) de Stroustrup (el autor de C++), modificado para que visualice un mensaje de bienvenida con el nombre de un pequeño pueblo andaluz. ' Microsoft ha anunciado el lanzamiento de la arquitectura .NETy el sistema operativo Windows XP para el segundo trimestre de 200I .
  • 36. 16 Java 2. Manual de programación //Esta aplicación visualiza: Hola Carchelejo. Bienvenido a Java public class Bienvenido I public static void main (String[] argc) t Cyctem.out.println("Hola Carchelejo. Bienvenido a Java"); Las etapas que preparan un programa para su ejecución son: 1. Crear una carpeta de proyecto en la que se recojan todos los archivos signi- ficativos, incluyendo clases que se desean incluir. 2. Utilizar un programa editor que introduzca cada línea del programa fuente en memoria y lo guarde en la carpeta proyecto como un archivo fuente. 3. Utilizar el programa compilador para traducir el programa fuente en byteco- de (código en bytes). Si existen errores de sintaxis (un error gramatical de una línea en un programa Java), el compilador visualiza esos errores en una ven- tana. 4. Utilizar el programa editor para corregir esos errores, modificando y vol- viendo a guardar el programa fuente. Cuando el programa fuente está libre de errores, el compilador guarda su traducción en bytecode como un archivo. 5 . El intérprete Java (JVM) traduce y ejecuta cada instrucción en bytecode. 6. Si el código no funciona correctamente se puede utilizar el depurador para ejecutar el programa paso a paso y examinar el efecto de las instrucciones individuales. Edición Editar el programa Bienvenido con un editor" escribiendo el texto correspon- diente al programa fuente. Debe darle un nombre al archivo fuente que constituye el programa (Bienvenido.j ava). Por convenio, el archivo del programa fuen- te debe terminar con la extensión java.Almacene el programa en la carpeta C : jdkl.3 . O-02bin. Los editores que se han utilizado en la preparación de este libro son Edit.com y Notepad.exe (se tra- bajó bajo Windows 98).
  • 37. Introducción a Java 17 Error típico: Palabras mal escritas: Java es sensible a las letras mayúsculas y minúsculas y el siguiente programa daría error: I public class Bienvenido I public s t a t i c void Main (String[] args) t System.out .println("Hola Carchelejo. Bienvenido a Java"); pues main debe escribirse sólo en minúsculas. y Los nombres de métodos y variables con una letra minúscula. Los nombres de las clases comienzan normalmente con una letra mayúscula Compilación La orden siguiente compila Bienvenido.java: javac Bienvenido.]ava Si no existen errores de sintaxis, el compilador genera un archivo denominado Bienvenido.class. El archivo no es un archivo objeto tal como se genera en otros compiladores de lenguajes de alto nivel. Este archivo se llama bytecode. El bytecode es similar a las instrucciones máquina, pero su arquitectura es neutral y se puede ejecutar en cualquier plataforma que tenga el entorno en tiempo de ejecución y el intérprete Java. Nota: Una gran ventaja de Java es que el código bykcode puede ejecutarse en diferentes plataformas hardware y sistemas operativos. El cornpilador enlazará el archivo del código fuente en Java y objetos impor- tados.
  • 38. 18 Java 2. Manual de programación Archivo fuente Objetos importados 1 Compilador 1 Figura 1.3. El código fuente de un programa se compila en bytecode. Ejecución Para ejecutar un programa Java, se debe ejecutar el bytecode del programa en cual- quier plataforma que soporte un interprete Java. La siguiente orden ejecuta el códi- go bytecode del programa aplicación Bienvenido.java: java Bienvenido La salida de este programa se muestra en la Figura 1.4. Figura 1.4. La salida del programa Bienvenido. 1.8. COMPONENTES DE UNA APLICACIÓN En un programa aplicación, destacan los siguientes elementos: Comentarios, 4 Palabras reservadas, Sentencias, Bloques, Clases, Métodos, el método main. Comentarios La primera línea del programa Bienvenido es un Comentario. Los Comentarios sirven para documentar los programas y en ellos se escriben anota-
  • 39. Introducción a Java 19 ciones sobre cómo funciona el programa o sobre cómo se ha construido. Los comentarios ayudan a los programadores actuales y futuros o a los usuarios de los mismos a comprender el programa. En Java, como en todos los lenguajes de pro- gramación, los comentarios no son sentencias de programación y son, por consi- guiente, ignorados por el cornpilador. En Java, los comentarios que constan de una única línea están precedidos por dos barras inclinadas (/ /), si se extienden sobre varias líneas están encerrados entre / * y * / . Cuando el compilador encuentra un comentario del tipo / / ignora todo el texto que viene a continua- ción hasta el final de línea, y cuando el compilador se encuentra con un comen- tario de la forma / * y * / ignora todo el texto entre ambos juegos de caracteres. Ejemplos de comentarios: / / Esto es un comentario relativo / * a l a S i e r r a de C a z o r l a , escrito por Mackoy * / Existen también otra clase de comentarios, denominados comentarios de docu- rnentacion, que pueden ser extraídos a archivos HTML utilizandojavadoc. Es nece- sario introducirlos entre los símbolos / ** ...* /. Palabras reservadas Las palabras reservadas o palabras clave (Keywords) son palabras que tienen un determinado significado para el compilador y no pueden ser utilizadas para otros fines. Por ejemplo, la palabra while significa que se habrá de evaluar la expre- sión que viene a continuación y, en función del valor de la misma, se ejecutarán o no se ejecutarán las sentencias siguientes. Otras palabras reservadas son p u b l i c , s t a t i c , p r i v a t e , que representan modificadores. Otro ejemplo es c l a s s , una palabra reservada muy utilizada, que significa que la palabra que viene a continuación es el nombre de la estructura clase. Las palabras reservadas se resaltarán en los códigos fuente que aparecen en el libro escribiéndolas en negrita. Precaución: Java es sensible a las mayúsculas, por consiguiente, w h i l e es una palabra reservada y While no es palabra reservada, Sentencias Una sentencia representa una acción o una secuencia de acciones. Cada sentencia termina con un punto y coma (; ). Ejemplos de sentencias son:
  • 40. 20 Java 2. Manual de programación z = 15; z = z+10u; //esta sentencia asigna 15 la //a variable z //esta sentencia añade 130 //ai valor de z printlr.("Bienvenido Sr. Mackoy") ; //sentencia de visualización Bloques Un bloque es una estructura que agrupa sentencias. Los bloques comienzan con una llave de apertura ( { ) y terminan con una llave se cierre ( } ). Un bloque puede estar dentro de otro bloque y se dice que el bloque interior está anidado dentro del exte- rior o que ambos bloques están anidados: z = 15; z = 2+100; if (z > 225) ! z = 2-5; Clases La clase es la construcción fundamental de Java y, como ya se ha comentado, constituye una plantilla o modelo para fabricar objetos. Un programa consta de una o más clases y cada una de ellas puede contener declaraciones de datos y métodos. Métodos Un método es una colección de sentencias que realizan una serie de operaciones determinadas. Por ejemplo: System.out.println("Bienvenido a Carchelejo") ; es un método que visualiza un mensaje en el monitor o consola. Método ma i n ( I Cada aplicación Java debe tener un método main declarado por el programador que define dónde comienza el flujo del programa. El método m a i n tendrá siempre una sintaxis similar a ésta:
  • 41. Introducción a Java 21 public static void ma;? (Str-nq;: aras) 1.9. HERRAMIENTAS DE DESARROLLO JAVA El JDK viene con un conjunto de herramientas tal como se comentó anteriormente: un compilador Java íjavac), una Máquina Virtual Java íjava),una herramienta para visualizar applets (appletViewer),un depurador elemental íjdb) y una herramienta de documentación íjavadoc). Estas herramientas se utilizan para crear, depurar, documentar y usar programas Java. Dependiendo de su entorno y su plataforma, los detalles reales de cómo instalar JDK o cualquier conjunto de herramientas Java, difieren de unos fabricantes a otros y lo más recomendable será seguir las instnic- ciones que nos ofrezcan ellos. Las herramientas de desarrollo más importantes se pueden encontrar en los sitios de Internet declarados en el apartado ((Especificaciones del lenguaje Java)). Estas herramientas proporcionan un entorno integrado de desarrollo, EID (IDE, Integrated Development Environment) y sirven para proporcionar un desarrollo rápido de programas de modo eficiente y productivo. 1.9.1. El entorno de desarrollo JDK La creación de un programa en Java, ya sean applets o aplicaciones convenciona- les, necesita la instalación de las herramientas de desarrollo de Java. El Kit de Desarrollo de Java (JDK) es una donación de Sun Mycrosystem a la que podemos acceder visitando el sitio que posee Sun en la Red. Como JDK es gratuito y las ver- siones que se pueden bajar de la Red están actualizadas, es muy frecuente su uso por los programadores, no obstante la existencia de los entornos de desarrollo inte- grados que pretenden facilitar las tareas de edición, compilación, ejecución y depu- ración, haciendo todas ellas directamente accesibles desde los mismos. Para trabajar con JDK en Windows 95/98/NT, resulta cómodo y eficaz abrir varias ventanas, y usarlas de la forma siguiente: En una ventana abrirá un editor, como Edit o Notepad, donde se irá escribien- do el código. Otra ventana le será necesaria para tener acceso al indicador (prompt)del siste- ma y poder invocar desde allí al compilador y a las demás herramientas del JDK. En una tercera puede tener abierto un archivo con documentación sobre el API de Java.
  • 42. 22 Java 2. Manual de programación Puede usar una cuarta ventana para abrir un navegador con soporte Java, por ejemplo 2ilicrosoft Explorer en versión 4.0 o superior, o el appletviewer para la verificación del correcto funcionamiento de los applets. 1.lo. UNA APLICACIÓN PRÁCTICA DE JAVA Inicialmente se expondrá la creación de programas convencionales, y para ver su estructura básica así como las fases a las que antes aludíamos, necesarias para su ejecución, seguiremos el siguiente ejemplo: Considere que trabaja con el JDK ins- talado en un PC bajo Windows 9x y cree la carpeta libro en el directorio raíz de su disco de arranque. Después, situándose dentro de libro, cree otra denominada T2ri7aOl. Abra una ventana DOS, trasládese a la carpeta Terna01 y llame al editor (Edit): 'L.-. I d i ~ . d c w s > c0 C:;ibrotemaOl i:libroTema31> e d i t Una vez dentro de Edit copie el texto incluido en la Figura 1.5 fijándose atenta- mente para no omitir en su copia ninguno de los caracteres ni signos de puntuación que aparecen en él. AI terminar, guárdelo con el nombre E] emplol .java y salga del editor. iport j atJ3.ii3 .f< ; ' L u i s Joyaner &giJi 1ar Jl1a;s E j e r n p l c i f n u t i l i t s t a t i c w i d main ( s t r i n g [ ] arg] { ) a programar en JAVA"); Figura 1.5. El archivo creado es el archivo fuente, al que en Java también se le llama unidad de cornpiltrcicín. Dicho archivo debe ser almacenado con el nombre E] emplol,ya que en Java el código siempre ha de estar dentro de una clase y el nombre del archi- vo debe coincidir con el de la clase que tiene el método m a i n ( ) . En el caso del ejemplo no sería necesario considerar esta situación, ya que sólo hay una clase. El archivo fuente debe escribirse dividido en secciones bien definidas, separadas por
  • 43. Introducción a Java 23 líneas en blanco y precedidas por un comentario identificativo de las misinas. Es importante guardar dicho archivo con la extensiónjava. Con estos pasos habrá ter- minado la fase de edición del programa. A continuación, el programa debe ser compilado, es decir, traducido a bytecode (código byte), que es el lenguaje que entiende el intérprete de Java. Para compilar un programa con el JDK hay que invocar ajavac y especificar el nombre del pro- grama a compilar sin olvidar reflejar su extensión íjava).Ahora debe tener en cuen- ta que para efectuar la compilación y ejecución de sus programas tal y como se indica a continuación debe modificar la variable de entorno path, añadiendo al p a t h anterior el subdirectorio o carpeta donde se encuentran los programas para compilar, ejecutar depurar y documentar las aplicaciones (javac,,java,,jdhy,jaw- doc respectivamente). Esta modificación deben introducirse en el archivo C: au t oexec.ba t,para que los nuevos valores se establezcan cada vez que se arranque la computadora. SET PATH=%PATHL&;C:jdkl.3.1bin o bien SET PATH=OEATHcc;C:~dkl.4bin(para trabajar Con la 1.4 Beta) Así mismo, es conveniente adaptar el contenido de c l a s s p a t h para que .lava pueda localizar siempre lais claseis creadais. SET CLASSEATH=.;C: El valor asignado a CLASSPATH hace que Java busque las clases en la carpeta actual y el directorio raíz. Suponiendo establecidos los anteriores valores para com- pilar E jemplol .j ava bastaría la siguiente orden: C:libroTemaOl> javac Ejernplol.java Por último, será necesario llamar al intérprete de Java para que el programa con extensión c l a s s surgido en la operación de compilación y que contiene el código byte pueda ser ejecutado. Para ello, cuando se dispone del JDK, en la línea de órde- nes o ventana de mandatos del sistema se escribirá la palabra j ava seguida por el nombre del programa a ejecutar, sin especificar la extensión del mismo y teniendo en cuenta que, si la clase pertenece a un paquete, el nombre de la misma debe ir pre- cedido por el del paquete de la forma siguiente: C:libroTemaOl> java libr=.TemaOl.ijemFlol o bien. C:WINDOWS> java libro.TemaOl.Ejemplo1
  • 44. 24 Java 2. Manual de programación dado el valor establecido para la variable CLASSPATH,que hace que el intér- prete de Java busque en el directorio raíz y a partir de ahí en aquellos cuyo nom- bre coincida con los elementos del paquete C : libroTemaO1.Es decir, se pasa como paráinetro ajava el nombre de la clase especificando el paquete al que pertenece, sin incluir la extensión y distinguiendo entre mayúsculas y minúscu- las. La salida obtenida con la ejecución del programa es la impresión en pantalla de la línea Ccrnienzo a programar en JAVA Una breve explicación del código fuente escrito es la siguiente: La primera instrucción sirve para indicar el paquete al que pertenecerá la clase que está siendo definida. Los paquetes son un mecanismo para organizar las clases. y cuando se declara que una clase pertenece a un paquete, dicha clase deberá ser almacenada en un subdirectorio o carpeta cuyo nombre coincida con lo especificado como nombre del paquete. En nuestro caso, como el paquete se denomina 1ib ro .TemaO1,la clase E jemp1o1 deberá ser almacenada en la carpeta 1ibroTemaO1. La sentencia import va seguida por el nombre de un paquete y se utiliza para poder referirse más adelante a clases pertenecientes a dicho paquete sin nece- sidad de cualificarlas con un nombre de jerarquía de paquetes. En el ejemplo, no existe aplicación posterior. La tercera línea es un comentario (comentario de una línea) La palabra reservada class permite especificar que se va a definir una clase, una palabra clave o reservada es una palabra especial con un signifi- cado preestablecido en el lenguaje Java. Para delimitar la clase, se emplean llaves, { } . Para ejecutar el programa, el intérprete de Java comienza llamando al méto- do main ( ) ; como este método se llama antes de la creación de un objeto, ha de declararse como static y así se le podrá llamar sin tener que refe- rirse a una instancia particular de la clase; como además se llama por código fuera de su clase también tiene que ser declarado como public,que es la forma de permitir que un miembro de una clase pueda ser utilizado por códi- go que está fuera de la misma. La palabra reservada void indica que main no devuelve nada. String [ ] args es la declaración de un array de cade- nas, mediante el que la clase podría tomar un número variable de parámetros en la línea de comandos, aunque no se use es necesario incluir este paráme- tro cuando se define el método main ( ). Se emplean llaves, { } ,para delimi- tar cI nietodo. * 0 !I .!>I ;I. la pantalla de la coinputadora es un objeto predefinido cuya referen- 1 . t. La clase System pertenece al paquete j ava.lang que" % , : , .
  • 45. --se importa automáticamente y, por tanto, no necesita cualificación. El método p r i n t I n ( ) toma la cadena que se le pasa como argumento y la escribe en la salida estándar. Todas las sentencias en Java deben terminar en ;. Tenga en cuen- ta que Java es sensible a las mayúsculas, por lo que considera distintos los identi- ficadores si se cambian mayúsculas por minúsculas o viceversa, es decir, s y st e m y System son identificadores diferentes. . Cir,5*’ I .I I. ESTRUCTURA DE UN PROGRAMA APLICACI~N EN JAVA Para crear programas en Java hay que tener en cuenta que toda implementación que se realice se efectuará encapsulada en una clase. Un programa aplicación fuen- te en Java se podría considerar formado por las siguientes partes: Una sentencia de paquete (package) que también puede ser omitida. Una, ninguna o varias sentencias de importación (import). Una serie de comentarios opcionales colocados en diversos lugares del pro- Declaraciones de las clases privadas deseadas; puede no haber ninguna. Una declaración de clase pública. grama. A su vez una declaración de clase comenzará con la sentencia c l a s s y podrá contener: Declaraciones de variables de la clase (estáticas). Declaraciones de variables de instancia. Definiciones de constructores. Definiciones de métodos. Dado que una clase es un modelo y las instancias son los objetos de esa clase, a las variables de instancia se las denomina así porque cada objeto contendrá una copia propia de dichas variables, de forma que los datos de un objeto se encontra- rán separados de los de otro objeto, utilizándose los métodos para la modificación de los valores de las variables de instancia. En consecuencia, un programa muy sen- cillo que se puede crear en Java es: public class EJ ernplo2 public static void main (Szring[l args)
  • 46. 26 Java 2. Manual de programación formado exclusivamente por una declaración de clase pública Compilación; javac Ejemplo2.java Ejecución: java Ejemplo2 Las clases de un programa contienen métodos, interactúan entre sí y no necesi- tan contener un método main ( ) ,pero éste sí será necesario en la clase que consti- tuya el punto de partida del programa. Tenga también en cuenta que las applets no utilizan el método main ( ) . La declaración de métodos en una clase se puede efectuar en cualquier orden y cada una de ellas se compone por una cabecera y un cuerpo. La cabecera del méto- do debe contener su nombre, una lista de parámetros y el tipo de resultado. Se espe- cificará void cuando el método no devuelva resultados. En la implementación del método, cuando éste no haya sido declarado void, se utilizará la instrucción return para devolver un valor al punto de llamada del método. La lista de pará- metros consistirá en cero o más parámetros formales cada uno de ellos precedido por su tipo y separados por comas. Cuando se llama a un método los parámetros actuales se asignan a los parámetros formales correspondientes. Entre los paráme- tros actuales (los de la llamada) y formales (los de la declaración) debe existir con- cordancia en cuanto a número, tipo y orden. Formatos de métodos pueden ser los siguientes: Ejemplo tipol nombre-funcion (lista de parámetros) / / declaración de variables / / sentencias ejecutables / / sentencia return con el valor a devolver I Ejemplo void nombre-procedimien to (tipo4 nombre-par3, t i p o 5 nombre-par4) i / / declaración de variables / / sentencias ejecutablec I En el primer ejemplo, t i p o1representa el tipo de dato devuelto por 'el méto- do; cuando el método no devuelve ningún valor se especificará void como tipo
  • 47. Introducción a Java 27 devuelto. La lista de parámetros es una secuencia de parejas tipo-identificador sepa- radas por comas. Observe el formato expuesto en el segundo ejemplo. En Java es posible agrupar sentencias simples, encerrándolas entre una pareja de llaves para formar un bloque o sentencia compuesta; las variables declaradas den- tro de un bloque sólo son válidas en dicho bloque y, si éste tuviera otros anidados, en los interiores a él. En un programa Java se podrán declarar variables tanto den- tro como fuera de los métodos. Las variables declaradas dentro del cuerpo de un método se crean cuando se ejecuta el cuerpo del método y desaparecen después. Las variables que se declaran fuera del cuerpo de un método son globales a la clase. Las que se declaran como final y static son, en realidad, constantes. 1.1 1.I. Referencia a miembros de una clase En los programas escritos en Java se hará referencia a los miembros de una clase, métodos y variables de instancia, desde otras distintas de aquellas en las que fueron definidos, para lo que generalmente será necesario declarar un objeto de la clase adecuada y a continuación escribir nombreObje t o .nombreComponente.No obstante, hay ocasiones en las que se utilizan métodos y variables de instancia sin necesidad de efectuar la declaración de ningún tipo de objeto, especificando para su llamada nombreclase.nombreComponente.Para que esto pueda ocurrir y a un miembro de una clase sea posible llamarlo con el nombre de la clase en la que ha sido declarado, sin tener que referirse a una instancia particular de la misma, dicho miembro debe haber sido declarado static (estático). 1.I2. ERRORES DE PROGRAMACIÓN Los errores de programación son inevitables, incluso para programadores experi- mentados. El proceso de corregir un error (bug en inglés) se denomina depuración (debugging)del programa. Cuando se detecta un error en Java, se visualiza un men- saje de error que devuelve la posible causa del error. Desgraciadamente los errores a veces no se detectan y los mensajes de error no son siempre fáciles de interpretar. Existen tres tipos de errores: errores de compilación (sintaxis), errores de ejecución y errores lógicos. 1.I2.1. Errores de compilación (sintaxis) Los errores de sintaxis ocurren cuando el código viola una o más reglas gra- maticales de Java. Los errores de sintaxis se detectan y visualizan por el com- pilador cuando se intenta traducir el programa, por esta razón se denominan
  • 48. 28 Java 2. Manual de programación también errores de compilación. Los errores de compilación provienen de erro- res en la construcción del código tales como escribir mal una palabra reserva- da, omitir algún signo de puntuación o bien utilizar, por ejemplo, una llave de apertura sin su correspondiente llave de cierre. Estos errores suelen ser fáciles de detectar ya que el compilador suele indicar dónde se producen las posibles causas. Ejemplo La compilación del siguiente programa produce errores de sintaxis: //este prograrra contiene errores de sintaxis public class Demo public static void main (String[] args) z=50; Cysten.out.println(z+lO) ; La ejecución de este programa produce un error detectado por el compilador del entorno JDK. Figura 1.6. El compilador del JDK detecta un error de sintaxis. El error de sintaxis es la no declaración previa de la variable z,que se utiliza en dos sentencias.
  • 49. Introducción a Java 29 Nota: Error de sintaxis:Es una violación de las reglas de gramática de Java, detectada durante la traducción del programa. 1.I 2.2. Errores de ejecución Los errores de ejecución son errores que producen una terminación anormal y que se detectan y visualizan durante la ejecución del programa. Un error de ejecución se produce cuando el usuario instruye a la computadora para que ejecute una ope- ración no válida, tal como dividir un número por cero o manipular datos indefini- dos o no válidos en la entrada. Un error de entrcrdu ocurre cuando el usuario introduce un valor de entrada imprevisto que el programa no puede manejar. Por ejemplo, si el programa espera leer un número, pero el usuario introduce una cadena de caracteres. En Java, los errores de entrada hay que declararlos en una cláusula throws o bien capturarlos y tratarlos directamente dentro del método en el que se pueden producir (véase el Capítulo 13, ((Manejo de excepciones))). Ejemplo public class ErrorDeE~ecucion i private static int z; static void prueba0 , i 1 public static void rnain(Ctring[] args) i z=lO/z; prueba ( ) ; Figura 1.7. Error de ejecución.
  • 50. 30 Java 2. Manual de programación AI invocar al método prueba ( ) , se produce un error en tiempo de ejecución: java.1ang.ArithmeticException: / by zero que indica un intento de dividir por cero (valor de z),operación no válida. r I Nota: Error de ejecución: Se intentó ejecutar una operación no válida que fue detectada durante la ejecución del programa. 1.12.3. Errores lógicos Los errores lógicos ocurren cuando un programa realiza un algoritmo incorrecto y no ejecuta la operación que estaba prevista. Existen muchos tipos de razones para que se produzcan errores lógicos. Normalmente los errores lógicos son difí- ciles de detectar, ya que no producen errores en tiempo de ejecución y no visua- lizan mensajes de error. El único síntoma de que se ha producido un error lógico puede ser la salida incorrecta del programa. Se pueden detectar errores lógicos comprobando el programa en su totalidad y comparando su salida con los resul- tados calculados. La prevención de errores lógicos se puede realizar verificando el algoritmo y el programa correspondiente antes de comenzar el proceso de eje- cución. Nota: Error lógico: Es un error producido por un algoritmo incorrecto. Por ejemplo, la instrucción System.out.println("Sie de Cazorla"); no muestra la frase que se deseaba, pues no se ha escrito bien: System.out.println ("Sierra de Cazorla"); pero el compilador no puede encontrar el error ya que la primera sentencia es sin- tácticamente correcta.
  • 51. CAPITU Características del lenguaje Java CONTENIDO 2.1. Palabras reservadas. 2.2. Identificadores. 2.3. Tipos de datos. 2.4. Tipos simples (primitivos). 2.5. Variables. 2.6. Constantes. 2.7. La biblioteca de clases de Java. 2.8. Conceptos básicos sobre excepciones. 2.9. La clase Number y sus subclases. 2.10. Las Clases Character y Boolean. 2.1I. Entrada y salida básicas. 2.12. Operadores. 2.13. La sentencia de asignación. 2.14. Expresiones. 2.15. Class Math. 2.16. Paquete java.math. 2.17. Conversiones de tipos. Operadores molde. 2.18. Operadores aritméticos. 2.19. Operadores relacionales. 2.20. Operadores lógicos. 2.21. Operadores de manipulación de bits. 2.22. Operadores de asignación adicionales. 2.23. Operador condicional. 2.24. Prioridad de los operadores 31
  • 52. 32 Java 2. Manual de programación Este capítulo expone los tipos de datos simples que ofrece Java, explica los conceptos de constantes y variables, y enseña como efectuar su declaración. Se tratan también en el capítulo las ope- raciones básicas de entradakalida y los distintos tipos de opera- dores y expresiones, comentándose además algunas clases de gran utilidad. 2.1. PALABRAS RESERVADAS Las palabras reservadas son palabras con un significado especial dentro del lengua- je. En Java 2 las palabras reservadas se listan en la Tabla 2.1: Tabla 2.1. Palabras reservadas Java 2 abstract boolean break byte byva1ue case cast catch char class const' continue default do double else extends false final finally float for future' generic' got0 if implements import inner instanceof int interface l o n g native new null operator' outer' package private protected public rest' return short static super switch synchronized this threadsafe throw throws transient true' try var' void volatille while No son auténticas palabras reservadas, No se utilizan en las últimas versiones de Java. 'Los métodos nativos están implementados en otros Icnguajes corno C o C++. En Java se declara un método nativo con la palabra reservada native y el cuerpo de método vacío.
  • 53. Características del lenguaje Java 33 2.2. IDENTIFICADORES Al igual que sucede con cualquier entidad o elemento del mundo real que se iden- tifica con un nombre, los elementos de un lenguaje de programación utilizan sím- bolos especiales, denominados ident$caúores. Son identificadores, por tanto, los nombres que reciben las clases, interfaces, paquetes, métodos, variables o instancias en un programa. Un identificador en Java debe cumplir las siguientes reglas: Puede tener cualquier longitud (uno o más caracteres). No puede contener operadores tales como +, -, . .. No puede coincidir con una palabra reservada, por tanto no puede ser true, false o null. El primer carácter sólo puede ser una letra, el carácter $ o el carácter de subra- yado. Después del primer carácter pueden aparecer cualquier combinación de letras, dígitos, $ y - . Las letras podrán ser mayúsculas y minúsculas incluyendo, en ambos casos, las acentuadas y la ñ. Debe ser referenciado siempre de la misma manera, sin cambiar mayúsculas por minúsculas ni viceversa. AI cambiar mayúsculas por minúsculas o al con- trario, Java lo interpreta como un identificador diferente. Ejemplo Identijicadores validos Iúentificudores no validos $5 5B Nombre Z - t l Char char a true false nullApe11idos Superficie -signo P El compilador Java detecta los identificadores válidos e informa de los errores de sintaxis que existan en el programa fuente. Nota: Java emplea la especificación Unicode para utilizar caracteres. Así se pueden emplear letras del alfabeto inglés y de otros idiomas internacionales recogidos en Unicode. Ésta es la razón por la que a , b, g, ..., ñ son caracteres legales.
  • 54. 34 Java 2. Manual de programación 2.3. TIPOS DE DATOS Java es un lenguaje fuertemente tipeado; esto implica que constantes, variables y expresiones tienen un tipo asociado y toda variable que interviene en un programa debe ser declarada antes de poder ser utilizada. Además, Java comprueba las ope- raciones de asignación, el paso de parámetros y las expresiones para asegurarse sobre la compatibilidad entre los tipos de datos que intervienen en ellas. Una primera clasificación de los tipos de datos en Java nos obligaría a distinguir entre tipos simples y definidos por el usuario, debido a que tienen características muy diferentes, constituyendo los tipos simples la base sobre la que se crearán los tipos definidos por el usuario. 2.4. TIPOS SIMPLES (PRIMITIVOS) Los tipos simples @/*irnitivos)no están orientados a objetos y pueden subdividirse en enteros, reales, datos de tipo carácter y lógicos o booleanos, caracterizándose cada uno de estos grupos por el conjunto de valores que pueden tomar y las opera- ciones que se pueden realizar sobre ellos. Cada tipo de dato tiene un dominio (rango) de valores. El compilador asigna espacio de memoria para almacenar cada variable o constante con arreglo a su tipo. Enteros Java ofrece cuatro tipos de enteros: byte,short,int y long.Todos ellos ad- miten valores tanto positivos como negativos, y cada uno permite almacenar valo- res en un determinado rango, definiéndose como valores con signo de 8, 16, 32 y 64 bits. Tabla 2.2. Tipos primitivos enteros Nombre. Tamaño Rango de valores en bits Declaración byte 8 -128 a 127 b y t e varl; short 1 6 -32768 a 32767 s h o r t var2 ; int 32 -2141483648 a 2147483647 i n t var3; long 64 -9223372036854715808 a long var4; 9223372036a54175801 Es posible escribir constantes enteros en otras bases distintas a la decimal: octal, hexadecimal. Una constante octal es cualquier número que comienza con
  • 55. Caracteristicas del lenguaje Java 35 un O y contiene dígitos en el rango 1 a 7 ( O 123 4 ) . Una constante hexadeci- mal comienza con Ox y va seguida de los dígitos O a 9 o las letras A a F (OxF10). Reales Los tipos de datos de coma flotante permiten almacenar números muy grandes, muy pequeños o que contienen coma decimal. Java soporta dos formatos de coma flo- tante float y double.El tipo float utiliza 32 bits para el almacenamiento y guarda los valores con precisión simple (6 Ó 7 dígitos). El tipo double utiliza 64 bits para el almacenamiento y guarda los valores con mucha mayor precisión (14 ó 15 dígitos); suele ser el tipo devuelto por muchas funciones matemáticas y suele ser el más empleado. Tabla 2.3. Tipos primitivos de coma flotante ~ ~~ Nombre Tamaño en bits ~~ ~~ ~~ - Rango de valores Declaración e inicialización f l o a t 32 (precisión simple) 3,4E-38 a 3,4E38 f l o a t numl=2.7182f; double 64 (precisión doble) 1,7E-308 a 1,7E308 double num2=2.7182d; Carácter El tipo de datos char de Java se utiliza para representar un carácter, éste tipo emplea 16 bits para el almacenamiento de un carácter y lo efectúa en formato Unicode. Unicode presenta dos ventajas: (1) permite a Java trabajar con los carac- teres de todos los idiomas; (2) sus primeros 127 caracteres coinciden con los del código ASCII. Tabla 2.4. Tipo primitivo para representar un carácter Nombre Tamaño Rango de valores Declaración en bits e inicialización char 1 6 caracteres alfanuméricos char l e t r a = ’a’ ; Un literal carácter representa un carácter o una secuencia de escape encerrada entre comillas simples. Por ejemplo, ‘c’ , ‘D‘.Una cadena de caracteres (string), es un conjunto de cero o más caracteres (incluyendo las secuencias de escape) ence- rrados entre dobles comillas.
  • 56. 36 Java 2. Manual de programación Ejemplo Ejemplos de cadenas "Cr,a caaena" "Cierra Ue Aracena" "C;erra de C a z o r l a " "Primera linea rn Segunda linea" "Prir?era página f Segunda página" ,,P ,ol>;mna ;t Columna 2" ,,1 , Regla: En Java, el tipo char representa un carácter. En Java, para representar una cadena de caracteres se utiliza una estructura de datos denominada S t r i n g . El concepto de string se explica con detenimiento en el Capítulo 8, ((Cadenasy fechas)). Regla: Una cadena se debe encerrar entre dobles comillas. Un tipo carácter es un Único carácter encerrado entre simples comillas. Los caracteres Java utilizan Unicode, que es un esquema universal para codifíca- ción de caracteres en 16 bits establecido por el consorcio Unicode para soportar el intercambio, proceso y presentación de los textos escritos en los diferentes idiomas del mundo (véase el sitio Web de Unicode en www .Unicode.org). Unicode toma dos bytes, expresados en cuatro números hexadecimales que corren de 'uO OO O ' a 'uFFFF'. La mayoría de las computadoras utilizan el código ASCII (Unicode incluye los códigosASCI1 de 'uOOOO' a 'uOOFF'). En Java se utiliza el códi- go ASCII, así como Unicode y las secuencias de escape como caracteres especiales. Tabla 2.5. Secuencias de escape ~ ~ ~ ~ ~~~~~ Secuencia Significado b t n f r " ' uxxxx Retroceso Tabulacih Nueva línea Avance de página Retorno de carro sin avance de línea Dobles comillas Comillas simples Barra inclinada inversa Carácter Unicode
  • 57. Características del lenguaje Java 37 Ejemplo Ejemplos de secuencias de escape: ' k ' 'n' 't' 'u015Ef Tabla 2.6. Ejemplos de caracteres especiales Carácter ASCII Unicode Retroceso de espacio Tabulación Avance de línea Retorno de carro b t n r u008 u009 uOOA uOOD Precaución: Una cadena debe encerrarse entre dobles comillas. Un carácter es un Único carácter encerrado entre simples comillas. Un carácter Unicode se debe representar mediante el código ' uXXXX '. Para almacenar un carácter, se almacena el código numérico que lo representa; por tanto, internamente los caracteres son números y esto capacita a Java para rea- lizar algunas operaciones numéricas con datos de tipo char. Ejemplo class CocMayuccu;ac i public static void main (String argci]) char c; c='a' -32; Cystem.out.print ("El carácter es " ) ; Cystex.out .println(c); c t t ; System.cut .print("Siguiente carácter " ) ; Sycten.out . p r i n t l n (c);
  • 58. 38 Java 2. Manual de programación Lógico (boolean) Un dato de tipo lógico puede tomar exclusivamente uno entre los dos siguientes posibles valores: t r u e , f a l s e (verdadero falso). Tabla 2.7. Tipo primitivo para representar datos lógicos Nombre Rango de valores Declaración e inicialización boolean t r u e , f a l s e boolean bandera = f a l s e ; Las variables booleanas almacenan el resultado de una expresión lógica, tenien- do en cuenta que ésta puede estar formada por una Única constante o variable de tipo lógico. Su contenido puede ser directamente mostrado por pantalla mediante el método p r i n t l n ( ) . Ejemplo package libro.Tema02; class Ejemplo2 t public static void main (String[] arg) { byte dia; boolean correcto; dia = -3; correcto = dia > O; Systern.out .print ( " Dia " ) ; System.out.print(dia); System.out.print ( " correcto = " ) ; Cystem.out.println(correcto); 2.5. VARIABLES Las variables almacenan datos cuyo valor puede verse modificado durante la eje- cución de un programa. Las variables se utilizan para representar tipos de datos muy diferentes. En Java hay que distinguir entre variables por valor y objetos o variables por referencia; las variables de tipo simple son variables por valor. Declaración de variables. Para utilizar una variable se necesita declararla e indicar al compilador el nombres de la variable, así como el tipo de dato que repre-
  • 59. Características del lenguaje Java 39 senta. Esta operación se denomina declaración de variables. Toda variable debe ser declarada antes de poder ser utilizada. Para declarar variables de tipo simple se especifica su nombre y su tipo, que define tanto los datos que la variable va a poder almacenar como las operaciones que tendrá permitidas. La sintaxis es, por tanto: tipollato nombrevariable; Ejemplo Declaración int z; //declara z como una variable entera double base; //declara base como variable double char b; //declara b como variable char Nota: Las variables permiten almacenar datos, de entrada, salida o datos inter- medios. Consejo: Los identificadores se utilizan para nombrar variables, constantes, métodos, clases y paquetes. Los identificadores descriptivos son los más utili- zados, ya que hacen los programas más fáciles de leer. Java es sensible a las mayúsculas, por consiguiente Z y z son identificadores diferentes. Sentencias de asignación. Después que una variable se declara, se puede asignar un valor a esa variable utilizando una sentencia de asignación. La sintaxis de la asignación tiene el siguiente formato: variable = expresión; Es preciso tener en cuenta que una expresión es un conjunto de operadores y operandos, pero una única constante o variable también constituye una expresión. Ejemplo 2 = 5; //asigna 5 a z longitud = 1.0 //asigna 7.0 a longitud b = B f ; //asigna 'B' a b Regla: El nombre de la variable debe estar a la izquierda 5 = z; es ilegal.
  • 60. 40 Java 2. Manual de programación Como ya se indicó anteriormente, una expresión representa un cálculo que implica valores, variables y operadores. superficie = 3.141592 * radio * radio; z = z t i; //el valor de z t 1 se d s i y n d a. la variable z Precaución: La sentencia de asignación utiliza el signo igual (=).Tenga cui- dado, no utilizar := que se utiliza con frecuencia en otros lenguajes de pro- gramación. tipoDato nombrevariable = valor-inicial; Declaración e inicializucióri de variables en un solo puso. Se puede declarar e inicializar una variable en un solo paso en lugar de en dos pasos como se ha mos- trado en las operaciones. Ejemplo Declaración con asignación del valor inicial Declaración y asignación de un valor char respuesta = ‘S‘ i n t contador = 1; f l o a t peso = 156.45f; char respuesta; respuesta=’C ’ ; i n t contador; contador=l; f l o a t peco; peso=156.45f; Precaución:Una variable se debe declarar antes de que se le pueda asignar un valor. A una variable se le debe asignar un valor antes de que se pueda leer en un método. Consejo: Siempre que sea posible, es conveniente declarar una variable y asignarle su valor inicial en un solo paso, ya que esta acción facilita la inter- pretación del programa.
  • 61. Características de/ lenguaje Java 41 Ámbito. Es importante el lugar donde se efectúa la declaración de las variables, pues éste determina su ámbito. En Java es posible agrupar sentencias simples, ence- rrándolas entre una pareja de llaves para formar bloques o sentencias compuestas y efectuar declaraciones de variables dentro de dichos bloques, al principio de los métodos o fuera de ellos. Una sentencia compuesta nula es aquella que no contiene ninguna sentencia entre las llaves { } . Ejemplo i n t i=25; double j=Math.sqrt (20); i++; j += 5; System.out.println(i+" "tj); { i n t aux = i; i = ( i n t )( j ) ; j= aux; / / A continuación comienza un bloque 1 //Fin del bloque System.out .println(i+""tj); / / aux aquí no está definida Es decir, en Java es posible declarar variables en el punto de utilización de las mismas dentro del programa, pero habrá de tener en cuenta que su ámbito será el bloque en el que han sido declaradas. Como ya se ha indicado, un bloque de sen- tencias se delimita entre dos llaves y las variables declaradas dentro de un bloque sólo son válidas en dicho bloque. Si un bloque tuviera otros anidados, en los inte- riores a él. No se pueden declarar variables en bloques interiores con el nombre de otras de ámbito exterior. Las variables declaradas dentro del cuerpo de un método son variables locales, y sólo existirán y se podrá hacer referencia a ellas dentro del cuerpo del método. Las variables que se declaran fuera del cuerpo de un método son variables de instancia y cada instancia de la clase tendrá una copia de dichas variables. Las variables declaradas fuera del cuerpo de los métodos y en cuya declaración se especifique la palabra static son variables de clase, esto quiere decir que no se hará una copia de ellas para cada uno de los objetos de la clase y, por tanto, su valor será compar- tido por todas las instancias de la misma. 2.6. CONSTANTES Las constantes son datos cuyo valor no puede variar durante la ejecución de un pro- grama. En un programa pueden aparecer constantes de dos tipos: literales y simbó- licas. Las constantes simbólicas o con nombre representan datos permanentes que
  • 62. 42 Java 2. Manual de programación nunca cambian y se declaran como las variables, pero inicializándose en el momento de la declaración y comenzando dicha declaración con la palabra reservada final, que sirve para que el valor asignado no pueda ser modificado. Las constantes de clase se declaran en el cuerpo de la clase y fuera de todos los métodos, siendo necesario comenzar su declaración con las palabras reservadas fina1y c tatic.La palabra clave final es obligatoria en la declaración de constantes, mientras que static consigue que sólo exista una copia de la constante para todos los objetos que se decla- ren de esa clase. La sintaxis para declarar una constante de clase es: s t a t i c f i n a l tipoDato NOMBRECONSTANTE = valor; Ejemplo 1. s t a t i c f i n a l double PI = 3.141592; superficie = radio * radio * PI; 2. class Prueba i s t a t i c f i n a l i n t MAX = 700; void Método ( ) / / . . . I / / . 1 Precaución: El nombre de las constantes se suele escribir en mayúsculas. Antes de utilizar una constante debe ser declarada. Una vez que se ha declara- do una constante no se puede modificar su valor. Las constantes literales son valores de un determinado tipo escritos directamen- te en un programa. Dichas constantes podrán ser enteras, reales, lógicas, carácter, cadena de caracteres, o el valor null. Constantes enteras Las constantes enteras representan números enteros y siempre tienen signo. La escritura de constantes enteras en un programa debe seguir unas determinadas reglas: No utilizar comas ni signos de puntuación en números enteros. 123456 en lugar de 123.456.
  • 63. Características del lenguaje Java 43 Puede añadirse una L o 1a1,finaldel número para especificar que se trata de Si se trata de un número en base decimal no podrá comenzar por cero. un long 123456L. 0123 es una constante entera en base octal 0x123 es una constante entera en hexadecimal cimal mediante la colocación de Ox o bien OX delante del número. La notación octal se indica poniendo un cero delante del número y la hexade- Constantes reales Una constante flotante representa un número real, siempre tiene signo y repre- senta aproximaciones en lugar de valores exactos. Las constantes reales tienen el tipo double por defecto, aunque también pueden ir seguidas por una d o D que especifique su pertenencia a dicho tipo. Cuando se les añade una f o F se obli- ga a que sean de tipo float.Para escribir una constante real se puede especifi- car su parte entera seguida por un punto y su parte fraccionaria, o bien utilizar la notación científica, en cuyo caso se añade la letra e o E seguida por un expo- nente. 82.341 equivale a 82.347d 2.5e4 equivale a 25OOOd 4E-3F equivalea O. 004f 5.435E-3 equivalea O. 005435d Constantes íógicas Las constantes literales de tipo lógico disponibles en Java son true y false,que significan verdadero y falso respectivamente. Constantes de tipo carácter Una constante de tipo carácter es un carácter válido encerrado entre comillas sim- ples. Los caracteres que pueden considerarse válidos son: Las letras mayúsculas y minúsculas, incluyendo en ambos casos las acentuadas y la ñ. Los dígitos. Los caracteres $, - y todos los caracteres Unicode por encima del OOCO . Existen, además, ciertas secuencias especiales, denominadas secuencias de esca- pe, que se usan para representar constantes de tipo carácter.
  • 64. 44 Java 2. Manual de programación Tabla 2.8. Ejemplos de constantes de tipo carácter representadas mediante secuencias de escape ~ ~ ~ ~~ ~~ ~~ Secuencia Significado Secuencia Significado n' Nueva línea I I I I t' Tabulación I I l l I, ' b' Retroceso I u0007' Pitido ' r' Retorno de carro sin avance de línea ' uOOIB1 Esc I ' Constantes de tipo cadena Una constante literal de tipo cadena en Java está constituida por una serie de carac- teres, entre los que pueden aparecer secuencias de escape, encerrados entre comi- llas dobles. Para cada constante literal de tipo carácter usada en un programa Java crea automáticamente un objeto de tipo String con dicho valor. Ejemplo / / Secuencias de escape class TresNumeros 11La salida de estei public s t a t i c void main (String args[]) i 1 System.out .print ( " t1 n t2 n t3" ) ; 2.7. LA BIBLIOTECA DE CLASES DE JAVA La potencia del lenguaje Java radica en su biblioteca de clases. Java posee una biblioteca de clases organizada en paquetes, que son un conjunto de clases lógi- camente relacionado, y, por tanto, para referenciar una de estas clases en un pro- grama es necesario escribir su nombre completo, es decir, incluir en el mismo el paquete al que pertenece, o bien importar el paquete. Una excepción la constitu- yen las clases pertenecientes al paquete java .lang,que se importa automáti- camente. Entre los paquetes de Java que más destacan se podrían mencionar los siguientes:
  • 65. Características del lenguaje Java 45 1ar.g Funciones del lenguaje n e t Para redes uti1 Utilidades adicionales ' awt Gráficos 2 interfaz gráfica de usuario io Entrada/Salida text Formateo especializado applet Para crear programas que se ejecuten en la Web awt .ever.t Sucesos desde el teclado. ratón. etc. La sentencia import sólo indica a Java dónde buscar las clases utilizadas en un programa. 2.8. C ~ N C E P T ~ SBÁSICOS SOBRE EXCEPCIONES Cuando en la ejecución de un programa se produce un error, Java lanza una excepción', que será necesario capturar para que el programa no se detenga. La clase Exception,con sus subclases IOException y RuntimeException contiene las excepciones que una aplicación necesita manejar habitualmente. En el paquete java .io se define la excepción denominada IOException para excepciones originadas por errores de entradaisalida. Estas excepciones se han de manejar de forma que el método donde se puedan producir debe capturar- las o bien declarar que se lanzan mediante una claúsula throws,en cuyo caso el método invocador está obligado a capturarlas. Para capturar una excepción en ope- raciones de entrada/salida el programa deberá incluir la sentencia import j ava .io y además habrá que poner a prueba el código capaz de lanzar la excep- ción en un bloque try y manejar la excepción en un bloque catch,el manejo la excepción se puede reducir a la presentación de un mensaje de error. //captura de excepciones de entrada y caliia t=Y //operaciones de entrada y salida I catch (IOException e) ! Cystem.out .println("Error"); Las operaciones aritméticas también pueden dar origen a excepciones; por ejemplo, la división por cero. Estas excepciones pertenecen la clase RuntimeException del paquete java .lang y son lanzadas automáticamente por Java y el compilador no obliga a su manejo. ' Una excepciónesun tipo especialde error (objetoerror)que se crea cuandosucedealgo impreisto en un prtr grama. En el Capítulo 13se estudia con más detalle el conceptoy manipulaciónde excepciones.
  • 66. 46 Java 2. Manual de programación / k a - t u r a generica de excepciones de la clase Exception t r y //operaciones de entrada y salida catch (Exception e) i C ystern. out.printIn ( "Error " tej ; 2.9. LA CLASE Number Y SUS SUBCLASES Java utiliza los tipos simples byte,int,long,float y double,que no están orientados a objetos, por razones de rendimiento. Si lo que se necesita es un objeto de alguno de estos tipos, será necesario recurrir a las clases Byte, Integer, Long, Float y Double,que son subclases de Number.Number pertenece al paquete java .lang y proporciona métodos que devuelven el valor del objeto como el correspondiente tipo simple. Métodos de Number con dicha finalidad son: public public public public public byte bytevalue ( ) a b s t r a c t double doublevalue ( ) a b s t r a c t f l o a t floatvalue ( ) a b s t r a c t i n t intValue(j a b s t r a c t long longvalue ( j Number es una clase abstracta, concepto que se explicara con detalle más ade- lante, y sus métodos abstractos han de ser definidos en cada una de las subclases comentadas. Por otra parte, las clases Byte, Integer, Long, Float y Double permiten construir objetos de la clase correspondiente mediante los métodos: public public public public public public public public public public public Byte (byte pl) Byze(java.lang.Ctring pl) Integer ( i n t p1) Ir,teger(java.lang.String pl) Long (long pl) LorLg(java.lang.String pl) Float (double pl) Float ( f l o a t pl) Float ( java.lang .String pl) Double (double pl) Double (java.lang.String pl)
  • 67. Características del lenguaje Java 47 Es decir, se pueden construir objetos de estos tipos a partir de los valores numé- ricos adecuados o a partir de cadenas con valores válidos para el tipo. La construc- ción ha de efectuarse con la ayuda del operador new, que también aparece comentado con posterioridad. Double d = new Double("2.71828"); double real = d.doubleValue ( ) ; Integer ent = new Integer(34); int 1 = ent .intValue( ) ; Las clases Integer y Long proporcionan dos métodos muy utilizados para convertir una cadena en un número, parseInt y parselong. Estos métodos lanzan una NumberFormatException, que es una RuntimeException, cuando surge algún problema. public static int parseInt (java.lang.String pi) //el segundo parámetro permte especificar la base public static int parseInt (lava.lang.String p:, int 02) public static long parseLong (lava.lang.String pi) //el segundo parámetro permite especificar la base public static long p a r s e L o n g ( j a v a . 1 a n g . C t r i n g pi, int 0 2 ) Ejemplo int 1 = 1nteger.parseInt ("20C1"); int j = 1nteger.parseInt ("101",2); System.out.println("i = " + 1 + " j = " + 1); La salida sería 1 = 2001 j = 5 Otros métodos interesantes de las clases Integer y Long son: class Inteqer public static java.lang.String toString(int p) public static lava.lang.String toBinaryS:r:-,g (int p ) public static java.lang.String toHexString(int p) public static java.lang.String to0ctalStripg(int p )
  • 68. 48 Java 2. Manual de programación class Long public static java.lang.String toString(1ong p) public static java.lang.String toBinaryString(1ong p) public static java.lang.String toHexString(1ong p) public static java.lang.String toOctalString(1ong p) Estos métodos permiten respectivamente convertir números ( int o long) en una cadena decimal, binaria, octal o hexadecimal. 2.10. LAS CLASES Character Y Boolean La clase Character se utiliza para crear objetos a partir de un parametro char. El constructor es: public Character (char p) y posee el método public char charvalue ( ) que devuelve el valor char Correspondiente. Otros métodos interesantes de esta clase son: public static char touppercase (char p) public static char toLowerCase (char p ) que devuelven el carácter que reciben como argumento transformado a mayúsculas en el caso del primer método y a minúsculas en el caso del segundo. La clase Boolean permite crear objetos a partir de un dato de tipo boolean. Sus constructores son: public Boclean (boolean p) public Boolean(java.lang.String p) y para obtener el correspondiente valor boolean se usa public boolean booleanvalue0 Ejemplo boolean rnayor = 3 + 1 > 5; Soolean ob = new Boolean(mayor); boolean b = ob,booleaiValue ( ) ;
  • 69. Características del lenguaje Java 49 2.11. ENTRADA Y SALIDA BÁSICAS En Java la entrada y salida de información se realiza mediante flujos; es decir, secuencias de datos que provienen de una fuente. Estos flujos son objetos que actúan de intermediarios entre el programa y el origen o destino de la información, de forma que éste lee o escribe en el flujo y puede hacer abstracción sobre la natu- raleza de la fuente. Como las clases relacionadas con flujos pertenecen a un paque- te denominado j ava .io, los programas que utilizan flujos necesitan la inclusión en los mismos de la instrucción import java.io.*; En Java existen unos flujos estándar, manipulados por la clase System del paquete java .lang,que permiten realizar operaciones de entradaisalida: 'system.in. representa la entrada estándar y es del tipo java.io.InpLtSzream *System.out,del tipo java.io.PrintStream,referencia ia pantalla *system.err,de tipo java.10. Printstream,referencia la salida de errores public s t a t i c f i n a l java.io.InputCtream ;I: public s t a t i c f i n a l lava.io.Printstream out public s t a t i c f i n a l java.io.PrintStream err La salida básica por pantalla se lleva a cabo mediante los métodos print y println, pertenecientes a la clase Printstream.A estos métodos se les puede llamar mediante System.out,que hace referencia a la salida estándar. El mecanis- mo básico para salida con formato utiliza el tipo String.En la salida, el signo +com- bina dos valores de tipo String y si el segundo argumento no es un valor de tipo String,pero es un tipo primitivo, se crea un valor temporal para él de tipo String. Estas conversiones al tipo String se pueden definir también para objetos. Ejemplo / * Ejemplo 1" sobre operaciones básicas de entrada y salida. Ejecute el siguiente programa y analice los resultados * / import java.io.*; public c l a s s Er.tradaCa1iaa1 t public s t a t i c void main (String[] args) i n t 1; char c;
  • 70. 50 Java 2. Manual de programación Sys;err.out .println("Escriba un número natural con" + ;=Cysterr.in.read ( ) ; System.in.skip (2); / * "un único dígito y pulse RETURN"); saita dos caracteres en el f l u j o de entrada: rn Caracteres originados al pulsar la tecla RETURN * / Cyster,.out.println(i); System.out.println("Escriba un número natural con" + "un Único dígito y pulse RETURN"); c=(char)Systern.in.read(); Cystern.out.println (c); catch ( IOException e) Cystem.out .println("Error"); La entrada de datos por consola se efectúa en Java leyendo bytes de un flujo de entrada y almacenándolos en objetos de distinto tipo, como se hizo mediante System.in.read ( ) en el ejemplo anterior. La instrucción System.i n . s k i p (2); que también aparece en dicho ejemplo puede sustituirse por esta otra System.in.skip(System.in.available()); paraqueelpro- grama determine automáticamente el número de caracteres que quedan en el flujo de entrada y se desean saltar. No obstante, la entrada básica en Java suele realizarse mediante el método readLine ( ) de la clase BufferedReader, que lee una secuencia de caracte- res de un flujo de entrada y devuelve una cadena y, además, mejora el rendimiento mediante la utilización de un búfer. Para efectuar este tipo de entrada debe cons- truirse un objeto de la clase BufferedReader sobre otro de la clase InputStreamReader asociado a System.in, que se encarga de convertir en caracteres los bytes leídos desde teclado. Según este planteamiento, la lectura de valores numéricos conllevaría dos fases: lectura de una cadena y conversión de la cadena en nzímero. Cuando s i trata de valores de tipo int o long los métodos Integer.parseint e Integer.parseLong proporcionan un mecanismo de conversión adecuado, mientras que para valores de tipo real se recurre a efec- tuar la construcción de objetos de tipo Float o Double a partir de la representa- ción en forma de cadena del número en coma flotante, para después, mediante f loatvalue o doubleValue,obtener el valor float o double que encap- sula dicho objeto. Como ya se ha visto, Integer,Long,Float y Doble son
  • 71. Características de/ lenguaje Java 51 clases pertenecientes al paquete java .lang que representan como objetos los tipos simples de su mismo nombre. Ejemplo / * Elemplo 2" sobre operaciones de entrada y salida. Ejecute el siguiente programa y analice los resultaccs * / import java .io.* ; public class Entradasalida2 i public static void main (String[] args) InputCtreamReader isr = new InputCtreamReader (System.in); BufferedReader br = new BufferedReader(;sr); String cadena; try Cystem.out .println("Escriba su nombre y pulse RETU;IN"); cadena=br.readLine(); System.out.println("Hola" +cadena+ ", escribe un número entero y pulsa RETCW") ; int entero=Integer.parseInt(br.readLine()1 ; Cystem.out .println("El número introducido fue el "+er.terc); Cystem.out.println("Amigo/a" +cadena+ ", introduzca ahora un real y p¿ilseXFTLJS>J") ; System.out.println( " (utilice el punto corno separador" + cadena=br.readline(); Double d=new Double (cadena); double real= d.doublevalue ( ) ; System.out .println("El real es "+real); "ej 3.45)"); 1 i 1 catch ( TOException e) System.out.println("Error"); 1 AI realizar este tipo de operaciones de entrada/salida hay que tener en cuenta la posible generación de excepciones; por ejemplo, aquellas que son lanzadas por readLine ante un error de lectura, y estas excepciones deben ser recogidas o bien listadas en una cláusula t h r o w s que las devuelva al método llamador.
  • 72. 52 Java 2. Manual de programación 2.12. OPERADORES Los operadores de un lenguaje se pueden utilizar para combinar o modificar los valores de un programa. Java posee un gran conjunto de operadores. La lista com- pleta de los operadores Java se muestra en la Tabla 2.9. Tabla 2.9. Lista completa de operadores Java > < ! -__ _ <= >= I = ~ -~ ? : & & - += _ -++ / & *= / = << >> t >>> & = >>>= (tipo) new instanceof or . 1 1 2.12.1. Operadores sobre enteros Los operadores que trabajan sobre enteros pueden ser binurios o unarios (unita- rios). Los operadores binarios son aquellos que requieren dos operandos (Tabla 2.1 1). Los operadores unarios son aquellos que requieren un único operando (Tabla 2.10). En ambas tablas se proporciona un ejemplo de la utilización de cada operador. La Tabla 2.12 muestra un tipo especial de operadores de asignación que se basan en los otros operadores. Estos operadores actúan sobre un operando y almacenan el valor resultante de nuevo en el mismo operando. Ejemplo z += 5; equivale a z = z + 5 ; Tabla 2.1O. Operadores unitarios sobre enteros Operador Operación Ejemplo - Negación unitaria -a ++ Incremento ++a o bien a ++ _ _ Decremento --a o bien a-- - Negación lógica bit a bit -a
  • 73. Características del lenguaje Java 53 Tabla 2.11. Operadores binarios sobre enteros ~ Operador Operación Ejemplo -- Asignación ____ Igualdad I = Desigualdad < Menor que a = b a ! = b a < b a == b <= Menor o igual que a <= b >= Mayor o igual que a >= b > Mayor que a > b + Suma a + b - Diferencia a - b Producto a * b / División a / b , Módulo a % b << Desplazamiento a izquierdas a << b >> Desplazamiento a derechas a >> b >>> Desplazamiento a derechas con rellenado de ceros a >>> b & AND bit a bit a & b I OR bit a bit a l b XOR bit a bit a ^ b * Tabla 2.12. Operadores de asignación enteros t = /= -- >>= --- &= 9- >>>= 0 - *= I = <<= 2.12.2. Operadores sobre valores de coma flotante Los operadores sobre valores de coma flotante son un subconjunto de los disponi- bles para tipos enteros. La Tabla 2.13 muestra los operadores que pueden operar sobre operandos de tipo f l o a t y double.
  • 74. 54 Java 2. Manual de programación Tabla 2.13. Operadores sobre valores de coma flotante Operador OperJción Ejemplo __ _ __ _ I = < <= >= > + / , ++ _ _ Asignación Igualdad Desigualdad Menor que Menor o igual que Mayor o igual que Mayor que Suma Resta Multiplicación División Módulo Negación unitaria lncrernento Decremento a = b b a ! = b a < b a <= b a >= b a > b a + b a - b a * b a / b -a ++a o bien a++ --a o bien a-- a == a % b 2.13. LA SENTENCIA DE ASIGNACIÓN La sentencia de asignación se usa para dar valor a una variable o a un objeto en el interior de un programa, aunque hay que tener en cuenta que las variables de tipo objeto se comportan de forma diferente a como lo hacen las de tipo simple cuando se realiza una asignación. El operador de asignación es el signo de igualdad y en este tipo de sentencias la variable se colocará siempre a la izquierda y la expresión a la derecha del operador. Los objetos de una determinada clase se crean utilizando el operador new que devuelve una referencia al objeto, la cual se almacenará en una variable del tipo objeto mediante una sentencia de asignación. Las sentencias de asignación tam- bién se podrán aplicar entre dos variables de tipo objeto. A las variables de tipo objeto se las denomina variables por referencia, debido a que cuando se asigna una variable de tipo objeto a otra (a diferencia de lo que ocurre con las variables de tipo simple) no se efectúa una copia del objeto, sino que sólo se hace una copia de la referencia, es decir, de la dirección de memoria donde se encuentra el objeto. Double d, d2; d = new Double("3") ; d2 = d;
  • 75. Características del lenguaje Java 55 En cuanto a las variables de tipo simple, tras efectuar su declaración, podrá usar- se el operador de asignación, para adjudicarles el valor de una expresión. int x,y; x=5; y=x; Este operador es asociativo por la derecha, lo que permite realizar asignaciones múltiples. Así, adjudica a las tres variables el valor 5. 2.14. EXPRESIONES En general, las expresiones se definen como un conjunto de operadores y operan- dos, pero hay que tener en cuenta que dicho conjunto puede estar formado exclusi- vamente por un operando. Es decir, que las expresiones pueden ser una constante, una variable o una combinación de constantes, variables y/o funciones con opera- dores, tanto binarios como unitarios. Como ya se comentó, en Java las variables declaradas static y fina1 son en realidad constantes y los métodos cuyo tipo de resultado no es void y que se declaran como public y static pueden ser considerados funciones glo- bales. 2.15. CLASE Math La clase java .lang .Math proporciona una serie de constantes y funciones de uso muy común en expresiones aritméticas. Math es una clase en el paquete fundamental java .lang. Los métodos está- ticos de la clase Math realizan cálculos matemáticos básicos tales como máximo, mínimo, valor absoluto y operaciones numéricas que incluyen funciones exponen- ciales, logarítmicas, raíz cuadrada y trigonométricas. Los cálculos en coma flotan- te se realizan utilizando double y algoritmos estándar.
  • 76. 56 Java 2. Manual de programación Métodos sobre tipos numéricos Invocación Significado Estructurade la cabecerade la declaración del miembro Math.abs (exp) valor absoluto public s t a t i c double abs (double pl) de e.rp public s t a t i c f l o a t abs ( f l o a t pi) public s t a t i c i n t abs ( i n t pl) public s t a t i c long abs (long pl) Math.max(expl,expZ)mayorentre public static double max (doublep l , double p2) explyexp2 public static float max (float pi, float p2) public s t a t i c i n t rnax ( i n t p i , i n t p2) public s t a t i c long rnax (long p l , long p2) Math.min(expl,expZ)menorentre public static double rnin (double pi, double p2) expl.vexp2 public static float min (float pi, float p2) public s t a t i c i n t min ( i n t pi, i n t p2) public s t a t i c long rnin (long pl, long p2) Como se puede apreciar a través de las cabeceras de los métodos, éstos están redefínidos para que puedan trabajar con diferentes tipos de datos. Métodos de coma flotante ~ ~ Invocación Significado Estructurade la cabecera de la declaración del miembro Math.pow(a,b) ah palicstatic&aep <*pi,chhlep?) Math.exp(a) ea public static double exp (double pi) Math.cei1 (a) r.1 public static double ceil (double pi) Math.floor(a) Lul public static double floor (-le pi) Math.log(a) 'n (4 public static double long (double pl) Math.sqrt (x) 6 public static double sqrt (double pi) Math.round ( n ) redondeo al entero public s t a t i c long round (double pi) (longo int) public s t a t i c i n t round ( f l o a t pi) más cercano log natural Math.random ( ) número aleatorio' public s t a t i c synchronized double random ( ) Constantes de coma flotante Invocación Significado Math .E base del logaritmo natural public s t a t i c f i n a l double E Math.PI p public s t a t i c f i n a l double P I Estructurade la cabecerade la declaración del miembro ' La clase Random pertenecienteal paquete j ava.uti1ofrece un mayor número de posibilidadespara la gene- ración de números aleatonos.Puede generar número aleatonos incluso siguiendo diferentes tipos de distribución. j
  • 77. Características del lenguaje Java 57 Funciones trigonométricas Invocación Significado Estructura de la cabecera de la declaracióndel miembro ~ Math.sin (19) sen (19) public static double sin (double pi) Math.cos (8) CUJ (8) public static double cos (double pi) Math.tan (8) tg (8) public static double tan (double pl) Math.asin(x) -u <arcsen(x)<u public static double asin (double pi) Math.acos(x) O < urcm(x)<8 public static double acoc (double pi) Math.atan (x) -yhrcfg(x)<D public static double atan (double pi) 2 Math.atan2 (a,b)-IIhrcrg(a)<Fl 2 - 2 public static double atan2 (doublepl, double p2) b Ejemplo ... / / Calculo del área de un círculo de radio 10 int r = 10; double c = Math.pow(r,2)*Math.PI; System.out.println(c); ... 2.16. PAQUETE java.math El paquete java.math tiene las clases BigDecimal y BigInteger y sopor- ta operaciones de coma flotante y enteros de precisión ampliada. 2.17. CONVERSIONES DE TIPOS. OPERADORES MOLDE Con frecuencia se necesita convertir un dato de un tipo a otro sin cambiar el valor que representa. Las conversiones de tipo pueden ser automáticas o explícitas, es decir, solicitadas específicamente por el programador. Conversiones automáticas En las expresiones pueden intervenir operandos de diferentes tipos y, cuando esto ocurre, para efectuar las operaciones Java intenta realizar conversiones automáticas de tipo. Las conversiones automáticas que podrá efectuar son:
  • 78. 58 Java 2. Manual de programación char in long float double byte short Figura 2.1. Conversiones automáticas. En la operación de asignación convierte el valor a la derecha del signo igual al tipo de la variable, siempre que los tipos sean compatibles y esta operación no oca- sione una pérdida de información, es decir, cuando se trate de conversiones como las mostradas en la Figura 2.1. Conversiones explícitas Este tipo de conversiones utiliza los denominados operadores de conversión, molde o cast, y puede ser necesario cuando se precisa un estrechamiento de tipo, conver- sión en el sentido tipo más alto a tipo más bajo, o en casos como el siguiente para generar una entidad temporal de un nuevo tipo. . . . int a = 5; byte b = 5; b = (byte)(b * 2); /*si no se pone el molde da error ya que el 2 es entero y avisa que no se puede convertir automáticamente int a byte * / float c = a / b; /*división entera. El operador división funciona a dos niveles: entero y real * / . . . int a = 5; byte b = 5; b (byte)(b * 2); float c = (floatla / b; //división real S a l i d a : @.O 5 10 Salida: 0.5 5 10 El operador molde tiene la misma prioridad que los operadores unarios. Mediante los operadores molde cualquier valor de un tipo entero o real puede ser convertido a o desde cualquier tipo numérico, pero no se pueden efectuar conver- siones entre los tipos enteros o reales y el tipo boolean. 2.18. OPERADORES ARITMÉTICOS Los operadores aritméticos permiten realizar operaciones aritméticas básicas, actúan sobre operandos numéricos y devuelven un resultado de tipo numérico. Los
  • 79. Características de/ lenguaje Java 59 operadores aritméticos en Java pueden también actuar sobre operandos de tipo char, ya que Java considera este tipo prácticamente como un subconjunto de los i n t . Los operadores aritméticos de Java se muestran en la Tabla 2.14. Tabla 2.14. Operadores aritméticos - -~ Operador Significado Operador Significado + Operador unario + / o Suma División entera si los operandos son de tipo entero - Operador unario - / División real con operandos de tipo real o Resta * Mu1tip1icación % Módúlo, es decir, resto de la división entera. No es necesario que los operandos sean enteros Ejercicio Convertir un número de metros leídos desde teclado en un complejo de pies y pulgadas sabiendoque 1 metro = 39.27 p u l g a d a s y 1 pie = 12 pulgadas. package libro.Tema02; import java.io.*; public class Conversion i public static void main (String[] args) I InputStreamReader isr=new InputStreamReader(System.in); BufferedReader br= new BufferedReader(isr); String cadena; try I System.out.println ("Indique el número de metros y" + cadena = br.readLine(); Double d = new Double(cadena); double metros = d.doubleValue ( ) ; double pulgadas = metros * 39.27; double pies = pulgadas / 12; pulgadas = pulgadas % 12; / / es posible aplicar % a reales pies = pies - pulgadas / 12; System.out .println("Conversión de metros en un complejo" + System.out.println(metros + " metros son " + pies + " pulse RETURN"); " de pies y pulgadas"); " pies y " + pulgadas + " pulgadas"); i
  • 81. Características de/ lenguaje Java 61 2.19. OPERADORES RELACIONALES Los operadores relacionales o de comparación permiten comparar valores para determinar su igualdad u ordenación y el resultado de las expresiones en las que intervienen es de tipo lógico. En cuanto a los operandos hay que tener en cuenta que sólo los tipos numéricos se pueden comparar utilizando operadores de ordenación, mientras que los de igualdad y desigualdad pueden actuar sobre cualquier tipo de dato. La Tabla 2.15 lista los operadores relacionales. Tabla 2.15. Operadores relacionales Operador Nombre Ejempio Respuesta _ __ _ Igual (operador formado por dos signos = consecutivos) 1 == 2 f a l s e I = Distinto 1 ! = 2 t r u e > Mayor que 1 > 2 f a l s e < Menor que 1 < 2 t r u e >= Mayor o igual 1 >= 2 f a l s e <= Menor o igual 1 <= 2 t r u e 2.20. OPERADORES LÓGICOS Los operadores lógicos o booleanos actúan sobre operandos de tipo lógico para devolver un resultado también de tipo lógico. La Tabla 2.16 contiene la lista de los operadores lógicos existentes en Java. Tabla 2.16. Operadores lógicos Operador Significado Operador Significado & AND lógico 1 1 OR en cortocircuito I OR lógico XOR & & AND en cortocircuito I NOT unario lógico h Las reglas de funcionamiento son las siguientes: El operador & da como resultado t r u e si al evaluar cada uno de los operandos el resultado es t r u e . Si alguno de ellos es false, el resultado es false. & & es análogo a &, pero si el primer operando es f a l s e , el segundo no es eva- luado. Esta propiedad se denomina evaluación en cortocircuito. Por ejemplo, la siguiente expresión evitaría calcular la raíz cuadrada de números negativos: (X >= O) & & (Math.sqrt(x) >= 2 )
  • 82. 62 Java 2. Manual de programación Tabla 2.17. Tabla de verdad del operador & & ~~~~ Operandol Operando2 Operandol 6h Operando2 f a l s e f a l s e f a l s e f a l s e t r u e f a l s e t r u e f a l s e f a l s e t r u e t r u e t r u e El operador 1 da como resultado f a l s e si al evaluar cada uno de los operan- dos el resultado es f a l s e . Si uno de ellos es t r u e , el resultado es t r u e . 1 I es análogo a I , pero, cuando se usa, si el primer operando es t r u e , el segundo no se evalúa. Por ejemplo, en la siguiente expresión: (10 > 4) 1 1 (num == O) la sentencia num == O nunca se ejecutará. Tabla 2.18. Tabla de verdad del operador I I Operando 1 Operando 2 Operando 1 I I Operando 2 f a l s e f a l s e f a l s e f a l s e t r u e t r u e t r u e f a l s e t r u e t r u e t r u e t r u e El operador ! da como resultado f a l s e si al evaluar su único operando el re- sultado es t r u e , y devuelve t r u e en caso contrario. Tabla 2.19. Tabla de verdad del operador ! Operando !Operando f a l s e t r u e t r u e f a l s e El operador ,, da como resultado t r u e si al evaluar sus operandos uno de ellos es true y el otro f a l s e , y devuelve f a l s e cuando ambos son t r u e y también cuando ambos son f a l s e .
  • 83. Características del lenguaje Java 63 Tabla 2.20. Tabla de verdad del operador A Operando 1 Operando 2 Operando 1 Operando 2 f a l s e f a l s e f a l s e f a l s e t r u e t r u e t r u e f a l s e t r u e t r u e t r u e f a l s e 2.21. OPERADORES DE MANIPULACIÓN DE BITS Actúan sobre operandos de tipo entero modificando los bits de sus operandos Tabla 2.21. Operadores de manipulación de bits Operador Nombre & I - << Desplazamiento a la izquierda >>> >> Desplazamiento a la derecha AND a nivel de bit OR a nivel de bit NOT unario a nivel de bit XOR Desplazamiento a la derecha rellenando con ceros A Para trabajar con estos operadores es necesario tener presente que: Java: - Almacena los enteros como números binarios. - Todos sus enteros, excepto los char, son enteros con signo, es decir, - Los números negativos se almacenan en complemento a dos, es decir, pueden ser positivos o negativos. cambiando por ceros los unos del número y viceversa y sumando un uno al resultado. La Tabla 2.22, que describe las acciones que realizan los operadores & I A y - sobre los diversos patrones de bits de un dato de tipo entero.
  • 84. 64 Java 2.Manual de programación & sobre bits A B A & B O 0 O o 1 O 1 0 O 1 1 1 I sobre bits * sobre bits -sobre bits A B A I B A B A A B A - A O 0 O O 0 O 1 O o 1 1 o 1 1 O 1 1 0 1 1 0 1 1 1 1 1 1 O El desplazamiento a la izquierda tiene el siguiente formato v a l o r << n y mueve a la izquierda n posiciones los bits del operando, rellenando con ceros los bits de la derecha. O O O 1 1 1 O 1 v a l o r e s 2 9 tras v a l o r = valor << 3,el v a l o r es 232 o -24 si el primer 1 por la izquierda es el signo (complemento a dos) 1 1 1 0 1 0 O 0 . . . byte c = 29; int d = c << 3; System.out.print1n (d); byte e = (byte) (c << 3); Systern.out.print1n (e); S a l i d a : 232 -24 El desplazamiento a la derecha, valor >> n, mueve a la derecha n posi- ciones los bits del operando, perdiéndose los bits de la derecha y rellenándose los de la izquierda con el contenido del bit superior inicial, lo que permite con- servar el signo. Ibyte b = - 2; int c = b >> 1; //equivale a dividir por 2 int c = - 2; c = c >> 1; //equivale a dividir p o r 2 Systern.out.println(c); I systern.out.println(c); I S a l i d a -1 S a l i d a -1 Para efectuar desplazamientos a la derecha en datos de tipo i n t sin conservar el signo el operador adecuado es >>>, que rellena con un cero el bit superior.
  • 85. Características del lenguaje Java 65 System.out .print111(b); ... byte b = - 2; b = (byte) (b >>> 1 ) ; System.out.println(c) ; I . . . b i t e b = - 2; i n t c = b >>> 1; i n t c = - 2; c = c >>> 1; System.out.println(c); Sa 1i d a 2 147483647 2.22. OPERADORES DE ASIGNACI~NADICIONALES Además del operador de asignación ya comentado, Java proporciona operadores de asignación adicionales (Tabla 2.23). Estos operadores actúan sobre variables de tipos simples como una notación abreviada para expresiones utilizadas con fre- cuencia. Por ejemplo, el operador ++ permite la sustitución de la expresión a=a+l por a+t. Los operadores ++ y -- necesitan una explicación adicional. Dichos operadores se denominan de autoincremento y autodecremento respectivamente y admiten su aplicación en dos formas, preJja y posGja, que adquieren importancia cuando los mismos se usan dentro de una expresión mayor. Prefija ++a Postfíja a++ Ejemplo ... i n t a,b, c; a = b = 5 ; c = a++ + ++b; / * c es el resultado de la suma del valor original de a System.out .println(c+" "+a+" "+b); con el nuevo valor de b * / . . . La s a l i d a es 11 6 6 Los operadores &=, 1 = y A = , cuando actúan sobre valores lógicos, son ope- radores lógicos; si los operandos son enteros, son operadores de manipulación de bits.
  • 86. 66 Java 2.Manual de programación Ejemplo package libro.Tema02; public class Operadores I Public static void main (String[] args) boolean a=true; a&=true; System.out.println("true & true = "+a); a&=false; System.out.println a&=false; System.out.println a&=true; System.out.println Tabla 2.23. "true & false = "+a); "false & false = "+a); "false & true = "+a); Operadores de asignación Operador Nombre Ejemplo -- Asignación simple int a = 5; / / a toma el valor 5 ++ Incremento y asignación a++ / / a vale 6 -- Decremento y asignación a--; / / equiva;e a a=a-1 / / a vale 5 *= Multiplicación y asignación a*=4; / / a = a"4 //a toma el valor 20 /= División y asignación a/=2; //a = a/2 //a torna el valor de 10 *= Módulo y asignación a"--0-6; //a = a%6 //a vale 4 T = Suma y asignación a+=8; //a = a+8 / / a vale 12 //a vale -11 <<= Desplazamiento a la, a<<=2; //a = a<<2 izquierda y asignacion //a vale - 4 4 >>= Desplazamiento a la a>>=6; / / a = a>>6 derecha y asignación //a vale -1 >>>= Desplazamiento a la derecha a>>>=24; / / a = a>>>24 y asignación rellenando con ceros //a vale 255 -_- Resta y asignación a-=23; //a = a-23 &= I = a=3; Asignación AND o a&=6; //equivalen a a=3&6 AND sobre bits y asignación / / a vale 2 a=3; Asignación OR o a 1 =6; //equivalen a a=3l6 OR sobre bits y asiganción //a vale I a=3; -- Asignación XOR o a^=6; //equivalen a a= 3 - 6 XOR sobre bits y asiganción //a vale 5
  • 87. Características de/ lenguaje Java 67 2.23. OPERADOR CONDICIONAL El operador condicional, ? : , es un operador ternario, es decir, requiere tres ope- randos, y se utiliza en expresiones condicionales, devolviendo un resultado cuyo valor depende de si la condición ha sido o no aprobada. El formato del operador condicional es: c o n d i c i o n ? operandol : operando2; y conlleva la ejecución de las siguientes operaciones: se evalúa la condición; si la condición es t r u e , el resultado es operandol, y si es f a l s e , es operando2. Por ejemplo: double comisión = ( v e n t a s > 150000)? 0.10 : 0.05; si las ventas son superiores a 15OOOO, se adjudica el valor O .1O a comisión; en caso contrario, se le adjudica O .05. 2.24. PRIORIDAD DE LOS OPERADORES Las expresiones se evalúan siguiendo el orden de prioridad de los distintos opera- dores que intervienen en ellas, atendiendo primero a los de mayor prioridad. A igualdad de prioridad se evalúan de izquierda a derecha. Los paréntesis se pueden utilizar con la finalidad de cambiar el orden preestablecido, ya que las operaciones encerradas entre paréntesis siempre se evalúan primero. Cuando hay varios parén- tesis anidados se calcula primero el resultado de las operaciones encerradas en los más internos. La prioridad, de mayor a menor, de los distintos operadores en Java aparece reflejada en la Tabla 2.24, los operadores situados en la misma línea tienen igual prioridad. En Java todos los operadores binarios, excepto los de asignación, se eva- lúan de izquierda a derecha (asociatividad). Consejo: Se pueden utilizar paréntesis para forzar un orden de evaluación, así como facilitarla lectura de un programa.
  • 88. 68 Java 2. Manual de programación Ejemplo ;Cuál es el valor de la siguiente expresión, teniendo en cuenta que i vale l? 5 + 4 * 4 > 5 * ( 5 + 4 ) - i t t Recult a d 0 false Ejercicio Determinar si un ario leído desde teclado es o no bisiesto, teniendo en cuenta que un año es bisiesto cuando es múltiplo de 4 y no lo es de 1 0 0 o si es múltiplo de 4 0 0 . import java.io.*; public class Prioridad public static void main (String[] args) I InputStreamReader isr=new InputCtrearnReader(Systern.in); BufferedReader br= new BufferedReader í -..) ; String cadena; try i System.out .print("Escriba el año co', 4 dígitos " ) ; cadena = br .readLine ( ) ; int año = Integer.parseInt(cadena); boolean bisiesto = año % 400 == O 1 1 System.out.println(bisiesto); I catch(Exception e) i año % 100 ! = O & & año % 4 == O; Cystern.out.println("Cualquier tipo de error");
  • 89. Características de/ lenguaje Java 69 Tabla 2.24. Prioridad de los operadores Operador Asociatividad 0 [I I - D ++ -- D- I new ( t i p o ) D- I / % I - D + I - D >> >>> << I - D > >= < <= i n s t a n c e of I - D __ ! = I - D & I - D I - D I I - D & & I-D I 1 I - D ? : D- I /= %= += -= >>= >>>= <<= &= ^ = / = D- I - I * - __ -- *=
  • 90. 3 Decisiones y bucles CONTENIDO 3.1. La sentencia if. 3.2. La sentencia if-else. 3.3. 3.4. La sentencia switch. 3.5. La sentencia for. 3.6. La sentencia break. 3.7. La sentencia continue. 3.8. 3.9. La sentencia while. Las sentencias if e if-else anidadas Diferencias entre continue y break. 3.10. La Sentencia do-while. 71
  • 91. 72 Java 2. Manual de programación En todos los lenguajes de programación existen construcciones que permiten tomar decisiones basadas en una condición. Para efectuar esta tarea Java dispone de las sentencias if,if-else y switch. Un bucle es una sección de código que se ejecuta muchas veces hasta que se cumple una condición de terminación. Las sentencias disponibles en Java para la creación de bucles son for,while y do-while.Este capítulo pretende introducirle en el manejo de ambos tipos de sentencias. Las sentencias selectivas controlan el flujo de ejecución en los programas basándose en el valor de una expresión sólo conocida en tiempo de ejecución. En Java existen sólo dos tipos de senten- cias selectivas, if y switch,en las que la primera se puede con- siderar a su vez dividida en dos clases, if e if-else. Las sentencias repetitivas permiten repetir una acción o grupo de acciones mientras o hasta que se cumple una determinada condición. Java dispone de tres sentencias de este tipo: for, whileydo-while. 3.1. LA SENTENCIA if La sentencia i f permite en un programa tomar la decisión sobre la ejecuciódno ejecu- ción de una acción o de un grupo de acciones, mediante la evaluación de una expresión lógica o booleana. La acción o grupo de accionesse ejecutancuando la condiciónes cier- ta y en caso contrario no se ejecutany se saltan.Los formatos para una sentencia if son: i f ( condición) sent encia; if (condición) i //secuencia de sentencias Ejemplo . . . double porcentaje = 0; / * Si las ventas son iguales o superiores a 300000 pts. percibe un 12% de comisión, en caso contrario no cobra comisión * / porcentaje = 0.12; i f (ventas >= 300000) i n t prima = ( i n t ) (ventas * porcentaje);
  • 92. Decisiones y bucles 73 Nota: La colocación de un signo de punto y coma después de la condición de una estructura if constituye un error en la lógica del programa: if (condición); / / si se cumple la condición no se ejecuta ninguna acción sen tencia; 3.2. LA SENTENCIA if-else Esta clase de sentencia i f ofrece dos alternativas a seguir, basadas en la conipro- bación de la condición. La palabra reservada e l s e separa las sentencias utili/adas para ejecutar cada alternativa. La sintaxis de la sentencia if-else es: if ( c o n d i c i o n ) else sen t e n c i a 1 ; sen t e n c i a2; if (condicicn) Si la evaluación de la condición es verdadera, se ejecuta la scnteilc.ic// o la secuencia de sentenciasl, mientras que si la evaluación es falsa se ejecuta la sew- tencia2 o la secuencia de sentencias2. Es decir, que las sentencias a realbar tanto cuando se cumple como cuando no se cumple la condición podrán ser simples o compuestas. Posibles errores de sintaxis serían: if ( condi cion) ; s e n t e n c i a 1; else sen t e n c i a 2 ; Nota: Es necesario recordar que Java proporciona un operador, el condicional, capaz de reemplazar instrucciones if -e1se. Ejercicio Adivinar un número pensado por la computadora.
  • 93. 74 Java 2. Manual de programación if más cercana, es cierir zorzepor.de a1 seg.indo * / import 4 a ~ a . i o . ~ ; public c l a s s Juego / * a pesar de la sangría, este e l s e corresponde al primer if * / public s t a t i c void main (String args[]) { InpdtStrearrReader isr = new InputStrearnReader(Cystem.1n); BcfferedReader br = new BufferedReader(isr); Czr-ng cadena; t r y . Syste-;.o~t.pr;n:("Ir.troduzca un número entero entre 1 y 3 " ) ; cader,a = ir.reaciline ( ) ; i n t n = ( i n t ) (Math.random()*3)+1; / / Moz?..randrmO devuelve un cioubie aleatorio entre O.C y 1.0 i n t I= Integer.parseInt(cadeca); i f (i == n) else Cystem.o¿it . p r i n t l n ("Acertó"); Cystem.out.prictln("No acertó, el número era "+n); catch(Exceptivn e) Cys:ei.ozt .print;n ( " C . ~ d l q u i e rtipo de error") ; La estructura i f -e1se anterior podría haber sido sustituida por: Cys:e?.c'~t .pr-~niln(i == n ? "Acertó" : "No acertó, era "+n); 3.3. LAS SENTENCIAS if E if- else ANIDADAS Es posible que alguna de las sentencias a ejecutar especificadas en una instrucción i f sea a su vez otra sentencia i f . i f ( c o ~ d i z i ó c l ) i f (condlci6n2) e l s e ce.?te;:cla:; seíi teEci a2; i f ( c o n d i c i ó n l ) t i f ( condi ción2) sent e n c i a 1 ; else / * la calabra reservada else se corresponde cor la sentencia sen t e n c i a 2 ;
  • 94. Decisiones y bucles 75 if ( c o n d i c i ó n lj if else ( condi ci6n2j sentencial; cen t e ncia2; if ( C o n d i i l c n 3 ) senten cia 3 ; else s e n t e n c i a d ; else / / puede e x i s t i r a n i í i a c i ó n / / en ambas ramas if ( c o n d i c i ó n i ) sen t e n c i a l ; else if ( c o n d i ción2j sen t e n c i a 2 ; / / l a anidación en l a rama e l s e / / puede s e r u;: i f if ( r o n d i c i ó c l j seri t e n cia; ; else / x E l 15 r, :?-else ari:3adz pUede s e r i n a mks de i a secuencia de s e z t e r e i a s que s e pueder. C G ~ O Z ~ ~en cualq,iera de l a c ZaTas * / if ( c o n d i ci5,: ) sente:: iia1 ; else if ( c o c d i ~ i ó ~ ~ 2 ) else ser tencia2; sec r e,?ci5; 3; / * la an:íiac:ón e n la r a x ~ e l s e puede s e r czrz if-eLse * / La construcción i f - e ls e - if múltiple, también denominada de a/ternatiiu~ múltiples i f - e l s e , es muy habitual en programación y se suele escribir de la forma siguiente: if ( c o n d i c i ó n lj s e n t e n c i a l ; else if ( c o n d i c i o n 2 ) sen t e n c i a2; else if ( c o n d i c i ó n 3 j sen t e n c i a 3 ; . . . else if ( c o n d i c i ó n N ) else sen t e n c i a N ; sentenciax; //opcional La sentencia anterior realiza una serie de test en cascada hasta que se produce una de las siguientes condiciones: Una de las cláusulas especificadas en las sentencias i f se cumple; en ese caso la sentencia asociada se ejecuta y no se tiene en cuenta el resto.
  • 95. 76 Java 2. Manual de programación Yinguna de las cláusulas especificadas se cumple y entonces, si existe, se eje- cuta la últiiiia sentencia else. Ejercicio Programa que ordena de mayor a menor tres números leídos desde teclado. import a: 2 . - 3 . * ; public c l a s s Oruiena3 public s t a t i c void rnair, (String(: aryc) l . , p ~ ~ t s t r c J m " e a d e ri c r = new I n p u t s t rearnxeader (S!ystem. i n ) ; I-,ifieredReader hi = new BufferedReader ( i c r ); sr1-ing zzciena; double a , 12, c; t = Y ? y c t e T . c i t . p r i r a t ("2F.tr-oduzia ' ~ 3número " ) ; .-acier,^ = b r .reaciLine ( ) ; i b l e cil = new Cio¿ibie (cadena); ~ m . o i i t . p r i n t("Intoduzca otro iúnierc " ) ; cdcienz = lar. reaaLine ( 1 ; I ? c ~ b l e62 = new X & l e (caaer,a); Sycterri.out . p r i n r ("In~roautcae; tercer nú?,ero " ) ; iaciena = hr.readLii.e ( ) ; Prxble ci3 = new 3c¿ble (caCena) ; b = d2.dsubleValue ( ) ; ~ - d 3 . dsubleValue ( 1 ; i f ( a > b) . - i f (o > c ) else Systeri.out, .prlr?tir,( a f " "tbT" "Cc); i f (c > a ) else Sycte?.cct .println( c ~ ""tat" " A -- ) ; Syctem.~u;.~rictln(a+" "Act" "+b); else i f ( a -,c ) else 3--iem.ou~.orir,tln( b t " "*;;,t" "+c); i f ( c > I=) else s y c t e i . o c t . p r i n t i r . ( i t " "+b+" "+a); Systerr,.out . p r i r l t l n (b+" " ~ c t ""ra); 1 catch(2xcecr:on e ) ' I
  • 96. Decisiones y bucles 77 Ejercicio Obtener las soluciones, reales e imaginarias, de una ecuación de segundo grado. import java.io.*; public Class Ecuacion i public static void main (String[] args) { InputStreamReader isr = n e w InputStreamReader(Systern.in); BufferedReader br = n e w BufferedReader(isr); String cadena; double a, b, c, xl, x2; System.out .println("Introduzca los coeficientes") ; Cystem.out.print ("a ? " ) ; cadena = br .readLine ( ) ; Double dl = n e w Double (cadena); System.out.print ("b ? " ) ; cadena = br.readLine(); Double d2 = n e w Double(cadena); System.out.print ("c ? " ) ; cadena = br.readLine ( ) ; Double d3 = n e w Double (cadena); a = dl .doublevalue ( ) ; b = d2 .doublevalue( ) ; c = d3.doublevalue ( ) ; if (a==O) System.out.println ("No es ecuación de segundo grado"); else i double d = (b*b-4*a*c); if (d>O) i xl = (-btMath.sqrt(d)) / (2*a); x2 = (-b-Math.sqrt (d)) / (2*a); System.out.print1n ("xl = "txl); Systern.out.println("x2 = "tx2); 1 else if (d==O) ( x1=x2= (-b)/ (2*a); else i ' Cystern.out.println("x1 = x2 = "txl); d=Math.abs (d); System.out.println("x1 = "+-b/ (2*a)t" +" + Math.sqrt(d) / (2*a)t" i " ) ;
  • 97. 78 Java 2. Manual de programación System.out.println("x2 = "t-b/ (2*a)+" - " f Math.sqrt(d) / (2*a)t" i " ) ; I i catch(Exception e) i System.out .println("Excepción "te); //Exception es superclase l I I 3.4. LA SENTENCIA switch Cuando se tienen muchas alternativas posibles a elegir, el uso de sentencias if- else-if puede resultar bastante complicado, siendo en general más adecuado en estos casos el empleo de la sentencia switch. La sintaxis de una sentencia switch es la siguiente: switch ( e x p r e s i o n ) I case c o n s t a n t e l : sen t e ncias1; //si se trata de múltiples acciones no es necesario //encerrarlas entre llaves break; case constante2: s e n t encias2; break; . . . case constanteN: ' s e n tencia sN; break; sen t e nc i a sX; default i Importante: En la sentencia s w i t c h la expresión ha de devolver un resulta- do de tipo entero o carácter. La sentencia break se utiliza con la sentencia s w i t c h para abandonar dicha sentencia tras la ejecución de las sentencias asociadas a una determinada cláusula case, El funcionamiento de la sentencia switch es el siguiente:
  • 98. Decisiones y bucles 79 Cuando el valor de la expresión coincide con una constante de case, se ejecutan el grupo de sentencias asociadas y si la Última sentencia de un grupo es break, tras llegar a ella, el programa sale de la estructura switch. Si la sentencia break se omite, la ejecución sigue en el siguiente grupo de senten- cias, con independencia del valor de la constante case. Generalmente la pala- bra reservada break se omite cuando se desea ejecutar la misma acción para dos o más constantes de case. La cláusula d e f a u l t es un caso especial de case. Las sentencias que vie- nen a continuación de ella se ejecutan si ninguna de las constantes que siguen a las diferentes sentencias case coincide con el valor de la expresión de switch. Para comprender mejor cómo utilizar la sentencia switch consideremos un programa que muestra un menú de opciones (una de sus aplicaciones más típicas). Ejemplo Menú de opciones: import java.io.*; public class CelectMult i public static void main (String[] args) t try ( System.out.println ( i i ~ ~ ~ ú i i ); System.out .println("C. Cargar archivo"); System.out.println ("G. Grabar archivo") ; System.out .println("I. Imprimir archivo"); System.out.println ("S. Salir del programa"); System.out.print ("Elija opción (C, G, I, S) " ) ; char opcion =(char)Cystem.in.read() ; System.in.skip(System.in.available()); switch (opcion) t case 'C' .. case 'c' : Cystem.out.println("Ha seleccionado Cargar archivo"); break; case 'G' : case 'g': System.out.println("Ha seleccionado Grabar archivo"); break; case '1'.. case 'i' : System.out.println("Ha seleccionado Imprimir archivo"); break; System.out.println("Ha seleccionado Salir de programa"); break; case ' S I : case 's':
  • 99. 80 Java 2. Manual de programación default: System.out.println("Opción no válida") ; 1 1 catch (Exception e) i ) En el programa anterior, cuando se pulsa la tecla s, se visualiza el mensaje Ha seleccionado Salir de programa,y si pulsa la tecla Z, aparece el de Opción no válida.Observe que se utilizan dos cláusulas case para permitir al usuario introducir letras mayúsculas o minúsculas. Es decir, los múltiples case se utilizan para permitir que una serie de condiciones proporcionen la misma res- puesta. Nota: En una sentencia switch no pueden aparecer constantes case iguales, pero las sentencias a ejecutar en una sentencia switch pueden ser a su vez sentencias switch y las sentencias switch anidadas sí pueden tener cons- tantes case iguales. 3.5. LA SENTENCIA for El bucle for está diseñado para ejecutar una secuencia de sentencias un número fijo de veces. La sintaxis de la sentencia for es: for ( i n i c i a l i z a c i ó n ; condición de terminación; incremento) sentencias; //desde O a un bloque delimitado por { I Las sentencias podrán ser cero, una única sentencia o un bloque, y serán lo que se repita durante el proceso del bucle. La i n i c i a l i z a c i ó n fija los valores iniciales de la variable o variables de control antes de que el bucle for se procese y ejecute solo una vez. Si se desea ini- cializar más de un valor, se puede utilizar un operador especial de los bucles for en Java, el operador coma, para pegar sentencias. Cuando no se tiene que iniciali- zar, se omite este apartado; sin embargo, nunca se debe omitir el punto y coma que actúa como separador. La condición d e termina ción se comprueba antes de cada iteración del bucle y éste se repite mientras que dicha condición se evalúe a un valor verdadero. Si se omite no se realiza ninguna prueba y se ejecuta siempre la sentencia for.
  • 100. Decisiones y bucles 81 El i ncrement o se ejecuta después de que se ejecuten las sen tencias y antes de que serealice la siguienteprueba de la condición d e terminación.Normalmente esta parte se utiliza para incrementar o decrementarel valor de Mas variables de control y, al igual que en la inicialización, se puede usar en ella el operadorcoma para pegar sen- tencias.Cuando no se tienen valores a incrementar se puede suprimir este apartado. En esencia, el bucle for comprueba si la condición de terminación es verdadera. Si la condición es Verdadera, se ejecutan las sentencias del interior del bucle, y si la condición es,fulsa, se saltan todas las sentencias del interior del bucle, es decir, no se ejecutan. Cuando la condición es verdadera, el bucle ejecuta una iteración (todas sus sentencias) y a continuación la variable de control del bucle se incrementa. Nota: Cada parte del bucle f o r es opcional. Es frecuente que 14s variables de control de un f o r sólo se necesiten en el bucle, en cuyo caso pueden declararse en la zona de inicialización. Por ejemplo, para ejecutar una sentencia 1O veces se puede utilizar cualquiera de los dos siguientes bucles for: f o r ( i n t i=l; i<=lO;i++) i n t i; System.out.println(i); for(i=l; i<=lO;i++j System.out .println(i); //Systern.out.println(ij; System.out.println(i); / / i no está definida //i vale 11 En estos ejemplos, la sentencia for inicializa i a 1,comprueba que i es menor o igual a 1O y ejecuta la siguiente sentencia que muestra el valor de i.A continua- ción se incrementa i y se compara con lO, como todavía es menor, se repite el bucle hasta que se cumpla la condición de terminación (i = 11). Si en lugar de una sola sentencia se desea ejecutar un grupo de sentencias, éstas se encierran entre llaves. for (i=l; i<=10;i++) { Systern.out.println(i); System.out.println("i * 10 = "+i*lOj; El siguiente bucle f o r , sin embargo, no ejecuta ninguna sentencia, sólo la ini- cialización y los sucesivos incrementos de la variable de control hasta alcanzar la condición de terminación: for ( i n t i=l; i<=2000000000; i+t);
  • 101. 82 Java 2.Manual de programación Los ejemplos anteriores muestran un incremento de la variable de control del bucle, con lo que la cuenta, realmente, era siempre ascendente. Un bucle for puede también decrementar su variable de control produciendo un bucle que cuente en sentido descendente. for(int 1=10; i>=l;i-) System.out.println(i); Nota: La variable de control de una sentencia f o r puede ser de cualquier tipo simple. for (dxble i=10; i>=l;i-0.5) for (&ar i='a' ; i<='z' ;i++) System.out.println(i); System.out.print(i); La expresión de incremento de un bucle for no siempre serán sumas o restas sim- ples. Se puede utilizar cualquier expresión que tenga sentido en el problema que se está resolviendo.Así por ejemplo, para visualizar los valores 1I 2 I 4I 8I 16 32I 64I 1 28 se puede utilizar la expresión i*2 para realizar el incremento. for( i=l; i< 200; i*=2) System.out.println (i); Es posible usar el operador coma en las cláusulas de inicialización e incremento for( i=O, j=14; (i+j>= O); i++, j - = 2 ) i System.out.print (i+" + "+j+" = " ) ; System.out.println(i+j); 1 Cada parte del bucle for es opcional, de forma que se pueden omitir las sec- ciones de control si ese tratamiento es el adecuado para el problema a resolver. Por ejemplo, el siguiente bucle for incrementa la variable de control del bucle, con independencia del mecanismo de iteración: for(i=l; i< 10;) it+; O bien se puede omitir la sección de inicialización: int i=O; for(; i< 10; i++) System.out.println (i);
  • 102. Decisiones y bucles 83 Es posible poner como condición en un bucle for cualquier expresión de tipo boolean,incluso expresiones no relacionadas con la variable de control. Ejercicio Determinar si un número entero leído desde teclado es o no primo. import java.io.*; public class NumPrimo public static void main (String args [I ) InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String cadena; try i System.out.print ("Deme un número entero " ) ; cadena = br .readLine ( ) ; int i= 1nteger.parseInt (cadena); boolean primo = true; int raiz2 = (int)Math.sqrt(i); for (int d=2; primo & & d <= raiz2; d++) if (i % d == O) primo = false; if (i == O 1 1 !primo) else System.out.print("El "+i+" es compuesto") ; System.out .print("El "+i+" es primo") ; i catch(Exception e) i 1 System.out .println("Cualquier tipo de error"); 3.6. LA SENTENCIA break En apartados anteriores se usó la sentencia break con la sentencia switch para abandonar dicha sentencia tras la ejecución de las sentencias asociadas a una deter- minada cláusula case.La sentencia break se puede utilizar también con las sen- tencias repetitivas, while, do-while y for para romper o salir de un bucle cuando se produce alguna situación especial.
  • 103. 84 Java 2. Manual de programación public class Brl public s t a t i c void main (String[] args) 1 i n t n; for (n=O; n<100; n++) t System.out.print (n+" " ) ; i f ( n == 5 0 ) break; I 1 I Si hay bucles anidados, una sentencia break colocada en el bucle interno sus- pende únicamente la ejecución de dicho bucle interior. public class Br2 public s t a t i c void main (String[] args) i i n t n, m; for (m =O; m<10; m++) i f o r (n=O; n<100; n++) i System.out.print (n+" " ) ; i f (n == 5 0 ) break; I System.out.println(); 1 Para abandonar una serie de estructuras anidadas puede utilizarse break et i - quet a ; ,donde la etiqueta puede ser cualquier identificador válido. Cuando se eje- cuta esta sentencia, el control se transfiere a la sentencia siguiente a un bloque etiquetado con dicho nombre de e t i q u e t a seguido por el signo de dos puntos, que, además, debe ser el que contenga la sentencia break et i q u e t a . public class Br3 I public s t a t i c void main (String[] a r g s ) i i n t n, m; parar: t for (m = O ; m < 10; mtt)
  • 104. Decisiones y bucles 85 f o r ( n = O; n < 1 3 3 ; n--1 if (rn = y - 2 ) break p a r a r ; Sylitern.o;t .print( n i " " ) ; i f ( n 53) break; S y s t e n i . o u : . p r i n t l n ( ) ; } / / f ; n del bloque ccn la etiqueta Syctern.out.println0; S y c t e r n . o u t . p r i n t l n ( " F I N " ); 3.7. LA SENTENCIA continue La sentencia continue es similar a break,pero sólo se puede usar en bucles, y, además, continue no salta fuera del bucle, simplemente salta sobre las sen- tencias restantes del bucle y transfiere el control al final del bucle ejecutándose la siguiente iteración del mismo. En consecuencia, una sentencia continue se uti- liza para comenzar inmediatamente la siguiente iteración de un bucle. Se puede utilizar continue con bucles for,while y do-while.El formato de CCR- tinue es: continue ; Una sentencia continue en cualquier bucle f o r salta inmediatamente a la expresión de control del bucle. En otras palabras, dado este bucle: f o r ( s e n t e n c i a ; expresióni; expresión2) i i f ( e x p r e s i j n 3 ) continue; sen tencia ; i si expresión3 es verdadera, la sentencia continue hace que se evalUe inme- diatamente expresión2,saltándose todas la/s sentencia/s a ejecutar que viene/n después de ella. Java permite el uso de etiquetas en la sentencia continue continue e tiquet a ;
  • 105. 86 Java 2. Manual de programación con las que especificar el bloque al que se aplica. p u b l i c class Ccrti public s t a t i c void rnair: (c;tr:ncj[ 1 clrcq:;) i n t n , rn; uno : f o r (rn = O ; r r < l O ; m t t ) f o r (n=O; n i l O C ; n++) System.out .prir.t(ni" " ) ; i f (r. == 59) continue uno; Cyster.oct.print..n( ) ; Systen.oct.println0 ; Cystem.c¿it .println ( " F I N " ); 3.8. DIFERENCIAS ENTRE continue Y break La sentencia continue fuerza una nueva iteración, mientras quc break fuerza la salida del bucle. En el siguiente ejemplo, se muestra la diferencia entre ambas sen- tencias. En el se observa como el mensaje " E l bucle" nunca se visualiza, pero en cada bucle por una causa diferente (break en el primero y continue en el segundo). t break; Sys:ern.out .prin~ln("21 bucle"); f o r (1 =C; -<=;o;1 j t t ) continue ; Cystern.out.prlntin( " E l bucle"); Otro ejemplo más completo para observar la diferencia de funcionamiento entre break y continue es el que se muestra a continuación: L i
  • 106. Decisiones y bucles 87 p u b l i c c l a s s B r y C i p u b l i c s t a t i c void mal-, ( Y t - i n j [ ] .,LJL) i f ( c u e n t a > 5 ) continue; Cystem.out.jrint (ciier.t,i.+" " 1 ; I Cyctem.o?it . p r ~ n t l r ,( ) ; System.out .printin("Después del b i c l e : c i e n t a = ' I - -"-2cT.:<) ; Cystem.out.print1n ( " C o m i e r i z c b e l bucle 'co?,r r c k " ) ; f o r ( c ; i e n t a , 7 1; c1uent.a 1 1 2 ; (,Lientat+) { i f ( c u e n t a > 5) break; Cystem.out .print (cue::t.ci+" " ) ; I System.out.pr;r,t 1 n ( ) ; System.out . p r i n t l n ("3espués del s u c l e : c u e n t a 1 "~cuer.:a); I AI ejecutar el programa se observa que los bucles f o r cuentan hasta 5 y se detienen. Después del primer bucle, sin embargo, el valor de c u e n t a es 11, y después del segundo es 6. La razón es que en el segundo bucle b r e a k fuerza la terminación y salida del bucle. Sin embargo, la sentencia c o n t i n u e , al igual que b r e a k , sólo debe utilizarse cuando no existe otra alternativa. Por ejeniplo. el listado p u b l i c class Cont2 p u b l i c s t a t i c void main (Ctrinq:; arqc) i f o r ( i n t 2 = O ; i < 10; it+) t if ( i ! = 2 ) continue; ~ystem.out.println("; = "-1);
  • 107. 88 Java 2. Manual de programación muestra sólo una línea, i 2. Si i es igual a O I 1, 3 I 4,5,6,7I 8,9, continue salta sobre la sentencia System.o u t .println.Este caso es un mal ejemplo de aplicación de continue,ya que se puede evitar reescribiendo el códi- go de esta manera: = public class SinCont public s t a t i c void r a i n (String[] a r T s ) f o r ( i n t : = O ; I < 13; ;tt) if (: == 2 ) C y s t em.o1t.printIri ( " i = " t i ); 3.9. LA SENTENCIA while El bucle while ejecuta una sentencia o bloque de sentencias mientrus se cumple una determinada condición; es decir, la acción o acciones se repiten mientras la con- dición es verdadera. La sintaxis general de la sentencia while es: while ( expresión) while (expresi Ón) sen tencia; { / / s e c u e n c i a de sentencia-. Si expresión es verdad, la sentencia o grupo de sentencias se ejecutan. Cuando la expresión es falsa, el bucle while se termina y el programa reanu- da su qjecución en la primera sentencia después del bucle. i n t i=l; while (1 <= 100) Cyctem.out.println ("i = "+I); :++: iiiilc ejectitd la primera iteración ya que 1 tiene un valor menor que 100. t incrementa su valor en 1a cada iteración, cuando I sea igual a 1O 1,lai I 1 ~ <=IO O será falsa y el bucle se terinina.Un ejeniplo de su aplicación es i 1 < . ;-)I ogiaina:
  • 108. Decisiones y bucles 89 import java.io.*; public class While1 i public static void main (String args [I ) i InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String cadena; int n=O ; try i System.out.print ("Deme un número entero " ) ; cadena = br .readLine ( ) ; n = Integer .parseInt(cadena); 1 catch (Exception e) i 1 int i=l; while (i <= n) i System.out .println("Iteración: "+i); i++; 1 1 1 La sentencia while es adecuada para muchas tareas. Un uso típico de while en programación es asegurar entradas de usuario válidas. El programa solicita al usuario si desea o no continuar con el programa mediante mensajes adecuados y mientras el usuario no indica expresamente una respuesta negativa, no (por ejem- plo, mediante la pulsación de la letra n o N), se sigue ejecutando el bucle. import java.io.*; public class While2 i public static void main (String[] args) i try i System.out .print(";Desea continuar? ( C / N ) " ) ; char resp =(char)System.in.read(); int num = Syctem.in.available~); System.in.skip (num); while (resp ! = 'n' & & resp ! = 'N' 1 1 num ! = 2) Cyctem.out.println("Pulse n o N y RETERN para salir"); Cystem.out.print ( " ¿ D e s e a cont;nuar? ( S I " ) " ) ; resp =(char)System.in.readO;
  • 109. 90 Java 2. Manual de programación catchii ., I II 1 Al e-jecutar el prograiiia se solicita tina rcspiicstn al iisiiario y. iiiicntras el carác- ter tecleado iio sea i i i i a letra N o n.el bucle se i-cpetiri iiideliriid~iiiiciitc.Otro tiso típi- co de wh: le es procesar entradas de teclado. 1;ii i i i i i c h x aplicacioiies se cuele so1icitar aI tisiiario qLie introduzca datos repetidaiiieiite h;i sta qiie dicho tisiiario intro- diizca iin .alar que se coiisiciera de /c./.ini/itrc,iti/i. t;l lisíndo qiie se iiiuestra a conti- nuación suiixi una secuencia arb¡traria de iiiiiiictos iiitroclucidos por teclado hasta qiie se produce uii valor concreto (cii niicstro c:iso cl cero) qiic tcriiiina el bucle. import ir* 3 . 1 .'; public c l a s s 15 11- public s t a t i c void I I ( 1 1 7 ~ 1 1 I )
  • 110. Decisiones y bucles 91 La sentencia while ejecuta el bloque de sentencias, mientras que num no sea igual a cero. Cuando el usuario introduce un valor de entrada cero se termina el bucle y se presenta en consola la suma resultante. Si el usuario comienza por intro- ducir un cero, el bucle no se ejecutará y la suma será cero. Otro uso común de la sentencia while es procesar dalos desde un archivo en disco. Esta operación es similar a la entrada de datos por teclado con la diferencia de que los valores de entrada se leen desde el archivo. Un problema frecuente en programacion se produce cuando aparecen bucles infinitos. Un bucle infinito es aquel que nunca termina. Los bucles while infinitos se producen debido a que la condición que se comprueba nunca se hace falsa, de modo que el bucle while ejecuta repetidamente sus sentencias una y otra vez. Si se entra en un bucle infinito se podrá salir de él mediante la pulsación conjunta de las teclas GYRI, y BRFAK ( r x i , t r i i ? m i < ) 3.10. LA SENTENCIA do-while La sentencia do-while es similar a la sentencia while,excepto que la expre- sión se comprueba después de que el bloque de sentencias se ejecute (mientras que la sentencia while realiza la prueba antes de que se ejecute el bloque de sen- tencias). La sintaxis de la sentencia do-while es: do while (expresión); sentencia; do sentencias; while (expresión); La/s s e n t e n c i a / s se ejecutan y, a continuación, se evalúa la expresión. Si la expresión se evalúa a un valor verdadero, las sentencias se ejecutan de nuevo. Este proceso se repite hasta que expresión se evalúa a un valor falso, en cuyo momento se sale de la sentencia do-while.Dado que el test condicional se rea- liza al final del bucle la sentencia o bloque de sentencias se ejecuta al menos una vez. Ejemplo public class DoWhilel i public static void main (String[] a r g s ) i int i = 1; while ( i < 6) i
  • 111. 92 Java 2. Manual de programación Cystem.out .println("Bucle while "ti); it+; i i = 1; do i System.out.println ("Bucle d o - W ~ LLc " + i ); it+; while (i < 6); Cuando se ejecuta este programa, se visualiza: Si se modifica el archivo anterior de modo que la expresión sea falsa la primera vez que se ejecutan los bucles se puede observar la diferencia entre las sentencias while y do-while. Ejemplo public class DoWhile2 public static void main (String/] args) int i = 6; while (i < 6) t System.out .println("Bucle while "ti); i+t; } i = 6; do i System.out.println ("Bucle do-while "ti); it+; while (i < 6); 1
  • 112. Decisiones y bucles 93 Al ejecutar el programa anterior, se visualiza: Bucle do-while 6 Ejemplo Calcular el número de años que ha de estar invertido un capital para que se dupli- que. Se proporcionarán desde teclado el tanto por ciento de interés y el capital inicial. import java.io.*; public class Interes i public static void main (String[] args) t InputCtreamRedder isr = new InputStreamReader(System.inj; BufferedReader br = new BufferedReader(isrj; String cadena; double capitalInicia1 = O; double capitalFina1 = O; double interes=O; try ( Cystern.out.print("Indique el capital inicial " ) ; cadena = br .readLine ( ) ; Double dl = new Double(cadena); capitalInicia1 = dl.doubleValue(); capitalFina1 = CapitalInicial; System.out.print ("Indique el % de interés " ) ; cadena = br.readLine(); dl = new Double(cadena); interes = dl .doublevalue ( ) ; int años = 0; do I años = años + 1; capitalFina1 = capitalFina1 + capitalFinal*interes/lGO; 1 while (capitalFina1 < 2 * capitalInicial) ; System.out.println("El número de años que ha de "+ "estar invertido para poder "+ "duplicarse es "+ años); I catch(Exception e) ( 1 1 1 Importante: En un bucle do-whi 1e si la expresión se evalúa a un valor ver- dadero, las sentencias se ejecutan de nuevo.
  • 113. 4.3. 4.4. 4.5. 4.6. 4.7. 4.8. 4.9. 4.1O. 4.1I . 4.12. 4.13. Acceso a Datos y Métodos. Utilización de métodos. Paso de parámetros. Paso de parámetros por valor. Paso de parámetros por referencia. Constructores. Modificadores de acceso. private. protected. public. Recursividad. 95
  • 114. 96 Java 2. Manual de programación La programación en lenguajes procedimentales -tales como BASIC, C, Pascal, Ada y COBOL- implica estructura de datos, diseño de algoritmos y traducción de algoritmos en código. La pro- gramación orientada a objetos es un tipo de programación que introduce construcciones específicas llamadas objetos, que a su vez contienen datos y procedimientos. Los objetos hacen la pro- gramación más fácil y menos propensa a errores. Un programa en Java implica un conjunto o colección de objetos que cooperan entre sí. En este capítulo se introducen los fundamentos de pro- gramación orientada a objetos: conceptos de clases y objetos, declaración de clases, creación de objetos, manipulación de obje- fosy cómo trabajan los objetos entre sí. 4.1. OBJETOS Y CLASES Un objeto es una colección de datos y las subrutinas o métodos que operan sobre ellos. Los objetos representan cosas físicas o abstractas, pero que tienen un estado y un com- portamiento. Por ejemplo, una mesa, un estudiante, un círculo, una cuenta corriente, un préstamo, un automóvil,...se consideran objetos. Así, ciertas propiedades definen a un objeto y ciertas propiedades definen lo que hace. Las que definen el objeto se conocen como campos de datos y el comportamiento de los objetos se define como métodos. La Figura 4.1 muestra un diagrama de un objeto con sus campos de datos y métodos. I campodato 1 I campo dato E L I I método2 1Objeto Figura 4.1. Un objeto contiene datos y métodos
  • 115. Clases, objetos y métodos 97 Un objeto C i r c u l o contiene un campo de dato r a d i o que es la propiedad que caracteriza un círculo. El comportamiento de un círculo permite calcular su super- ficie y su longitud. Así, un objeto C i r c u l o se muestra en la Figura 4.2. campo dato: radio objeto C i r c u l o método: calcularsuperficie Figura 4.2. Las clases son estructuras o plantillas que sirven para definir un objeto. En una clase Java, se pueden utilizar datos para describir propiedades y métodos que definen su comportamiento. Una clase de un objeto contiene una colección de métodos y definiciones de datos. Si se diseña una clase que representa a un cliente, no se ha creado un objeto. Un objeto es una instancia (ejemplar, caso) de la clase C1i e n t e y, por consiguiente, puede, naturalmente, haber muchos obje- tos de la clase C l i e n t e . La creación de una variable específica de un tipo par- ticular de clase se conoce como instanciación (creación de instancias) de esa clase. Una clase describe la constitución de un objeto y sirve como plantilla para construir objetos, especificando la interfaz pública de un objeto. Una clase tiene un nombre y especifica los miembros que pertenecen a la clase, que pueden ser campos (datos) y métodos (procedimientos). Una vez que se define una clase, el nombre de la clase se convierte en un nuevo tipo de dato y se utiliza para: Declarar variables de ese tipo. Crear objetos de ese tipo. El siguiente ejemplo representa una clase C i r c u l o que se utilizara para cons- truir objetos del tipo C i r c u l o : class Circulo { double radio =5.0; double calcularsuperficie0 i return radio*radio*3.141592;
  • 116. 98 Java 2. Manual de programación objeto 1 de Circulo Esta clase Circulo es, simplemente, una definición que se utiliza para decla- rar y crear objetos Circulo.La clase Circulo no tiene un método main y por consiguiente no se puede ejecutar. Corno estilo de escritura, en este libro se utiliza- rán nombres que comienzan por mayúsculas para las clases. La clase se declara con el siguiente formato: objeto 2 de C i r c u l o class Kcmbre i / / cLerpo de la c l a s e El cuerpo de la clase define los miembros úuto, mietnbro.s m¿todo o ambos. Excepto en el caso de sohrecurgu, todos los miembros deben tener nombres distintos. 4.2. DECLARACIÓN Y CREACIÓN DE UN OBJETO Una clase es una plantilla que define los datos y los métodos del objeto. Un objeto es una instancia de una clase. Se pueden crear muchas instancias de una clase. La creación de una instancia se conoce como insluncicrcicjn. clase Circulo Figura 4.3. Una clase puede tener muchos objetos diferentes Como ya se ha comentado, una vez que se define una clase, el nombre de la clase se convierte en un nuevo tipo de dato y se utiliza tanto para declarar varia- bles de ese tipo, como para crear objetos del inisino. La sintaxis para declarar un objeto es: NcrnbreClase combreObje to; Ejemplo C i r c ¿ i l o m i c i r c u l o ; / / declara l a variable micirculo
  • 117. Clases, objetos y métodos 99 La variable micirculo es una instancia de la clase Circulo.La creación de un objeto de una clase se llama creacirjn de una instancia de la clase. Un objeto es similar a una variable que tiene un tipo clase. La creación de variables de un tipo de dato primitivo se realiza simplemente declarándolas, esta operación crea la variable y le asigna espacio en memoria: i n t j; I . Creución de la clase. 2. Declarar los objetos. 3. Crear los objetos. Una vuriuhle de tipo c h s e es una vuriable referencia, que puede contener la direc- ción de en memoria (o referencia) de un objeto de la clase o n u l l para una referen- cia no válida. La declaración de un objeto simplemente asocia el objeto con una clase, haciendo al objeto una instancia de esa clase. Lu declaración no crea el objeto. Para crear realmente micirculo (objeto de la clase Circulo)se necesita utilizar el ope- rador new con el objeto de indicar a la computadora que cree un objeto micirculo y asigne espacio de memoria para ella. La sintaxis para crear un objeto es: nombreobjeto = n e w Nombreclase 0 ; Ejemplo La siguiente sentencia crea un objeto, micirculo,y le asigna memoria: micirculo = n e w Circulo O ; Declaración e Instanciación Se pueden combinar la declaración y la instanciacibn en una sola sentencia con la siguiente sintaxis: NombreClace nombreobjeto = n e w NombreClaseO; Ejemplo Creación e instanciación de micirculo en una etapa: Circulo m i c i r c u l o = n e w Circulo ( ) ;
  • 118. 100 Java 2. Manual de programación 4.3. ACCESO A DATOSY MÉTODOS Después de que se ha creado un objeto, se puede acceder a sus datos y métodos uti- lizando la notación siguiente: nombre0bjeto.datos nombreObjeto.metodo() Referencia a un dato de un objeto Referencia a un método de un objeto Ejemplo miCirculo.radio radio de micirculo miCirculo.calcularCuperficie() devuelve la superficie de micirculo 4.4. UTILIZACIÓN DE MÉTODOS Los miembros de un objeto son los elementos dato, a los que también se puede denominar variables de instancia, y los métodos. Los métodos son accioncs que se realizan por un objeto de una clase. Una invocación a un método es una petición al método para que ejecute su acción y lo haga con el objeto mencionado. La invoca- ción de un método se denominaría también llamar a un método y pasar un mensa- je a un objeto. Existen dos tipos de métodos, aquellos que devuelven un valor Único y aquellos que ejecutan alguna acción distinta de devolver un Único valor. El método readInt es un ejemplo de un método que devuelve un Único valor de tipo i n t . El método p r i n t l n es un ejemplo de un método que realiza alguna acción distin- ta de devolver un valor único. Nota: Existen dos tipos de métodos: aquellos que devuelven un Único valor y aquellos que realizan alguna acción distinta de devolver un valor. Los méto- dos que realizan alguna acción distinta de devolver un valor se denominan métodos void. La implementación de los métodos podría ser como ésta: public class Cuentacorriente i private double saldo; public void depositar (double cantidad) saldo = saldo + cantidad;
  • 119. saldo = saldo - cantidad; public double ot>t.c:rierS~i1do ( ) ’. return caldo; La ilumudu o invocución a un método se puede realizar de dos formas, depen- diendo de que el método devuelva o no un valor. 1. Si el método devuelve un valor, la llamada al método se trata normalmente como un valor. Por ejemplo, int mayor -- m x ( 3 , 4 ) ; llama al método max ( 3 , 4 ) y asigna el resultado del método a la variable mayor.Otro ejemplo puede ser la llamada System.out.println(max(3,4)); que imprime el valor devuelto por la llamada al método max ( 3, 4) . 2. Si el método devuelve void, una llamada al método debe ser una sentencia. Por ejemplo, el método println ( ) devuelve void.La siguiente llamada es una sentencia System.out .println( “ C i e r r a de Cazorla”); Si se considera ahora un objeto micuenta de la clase Cuentacorriente Cuentacorriente micuenta; una invocación al método depositar tendrá el formato miCuenta.depositar(2400); Cuando un programa llama a un método, el control del programa se trans- fiere al método llamado. Un método llamado devuelve el control al llamador cuando se ejecute su sentencia return o cuando se alcance la llave de cie- rre 0).
  • 120. 102 Java 2. Manual de programación 4.5. PASO DE PARÁMETROS La cabecera de un método especifica el número y tipo de parámetros formales requeridos. Java no soporta parámetros opcionales o de longitud variable. En el interior de una clase, un método se identifica no sOlo por SLI nombre, sino también por su lista de parámetros formales. Por consiguiente, el mismo nombre de método se puede definir mús de una vez con diferentes parámetros formales para conseguir la sobrecarga de métodos. Cuando se llama a un método, se deben proporcionar un número y tipo correctos de argumentos. Los argumentos incluidos en la llamada a un método se conocen como argumentos (parámetros) reales o simplemente argumentos. La llamada a un método exige proporcionarle parámetros reales (actuales) que se deben dar en el mismo orden que la lista de parámetros formales en la especifi- cación del método. Esta regla se conoce como asociocicíii tiel orden de 10s pur& metr'os . Ejemplo El método imprimirN imprime un mensaje n veces: void irnprirnirN(String mensaje, int n) i for (int i=O; i<n; i + + ) Systern.out . p r i n t l n (mensaje); 1 1. Invocación correcta Una invocación imprimirN( "Carchelejo", 4) imprime la palabra Carchelejo cuatro veces. El proceso es el siguiente. La invocación a imprimirN pasa el parametro real cadena, "Carchelejo " , al parametro formal mensaje y el parametro real 4 a la variable n. Se imprime 4 veces la frase Carchelejo. 2. Invocación incorrecta La sentencia imprimirN(4, "Carchelejo") es incorrecta, ya que el tipo de dato 4 no coincide con el tipo del parámetro mensaje y, de igual modo, el segundo parámetro "Carchelejo''tampoco coincide con el tipo del segundo parámetro formal n.
  • 121. Clases, objetos y métodos 103 La operación de enlazar (hitiding) los argumentos reales a los argumentos for- males se denomina puso de urgumetitos. Cuando se llama a un método con más de un argumento, dichos argumentos se evalúan de modo secuencial, de izquierda a derecha. Existen dos tipos de paso de parámetros: por valor y por referencia. 4.6. PASO DE PARÁMETROS POR VALOR Todos los tipos de datos priinitivos ( i n t , long, float,boolean) se pasan en los métodos por valor. En otras palabras, sus valores se copian en nuevas posicio- nes, que se pasan a la subrutina (método); como consecuencia de esto, si un argu- mento se cambia dentro de un método, no se cambiará en el programa llamador original. El siguiente método no producirá un cambio en x: void cambiarünidades ( f l o a t x, f l o a t f a c t o r ) . . . t x = x * fí.,ctor; / / x no se pUede mcdificar ec e- --a;acior El único método sencillo para obtener un valor que se calcula dentro de una clase es utilizar un método cuyo tipo no sea void que específicamente devuelva un valor. f l o a t cay-oiar ( f l o a t x, f l o a t factor) r e t u r n ( x * f a c t - o r ) ; / / el nuevc x se aev;lelve ai Llamaaor I 4.7. PASO DE PARÁMETROS POR REFERENCIA Los objetos, incluyendo arrays, se llaman tipos referencia, ya que se pasan en los métodos por referencia en lugar de por valor. AI igual que se pueden pasar tipos pri- mitivos, se pueden también pasar objetos a métodos como parámetros reales. Existe una diferencia importante entre el paso de un valor de variables de tipos de datos primitivos y el paso de objetos. El paso de una variable de un tipo primiti- vo significa, como ya se ha comentado, que el valor de la variable se pasa a un pará- metro formal. El cambio del valor del parámetro local en el interior del método no afecta al valor de la variable en el exterior del método. El paso de un objeto significa que la referencia del objeto se pasa a un paráme- tro formal. Cualquier cambio al objeto local que suceda dentro del cuerpo del méto- do afectará al objeto original que se pasa como argumento. Este tipo de paso de parámetros se denomina paso por refkrencia.
  • 122. 104 Java 2. Manual de programación Ejemplo El objeto micirculo de la clase Circulo se pasa como argumento al método imprimircirculo ( ) ; C i r c u l o m i c i r c u l o = new C i r c u l o ( 1 0 . O ) ; i r n p r i m i r C i r c u l o ( m i C i r c u 1 o ) ; 4.8. CONSTRUCTORES Un constructor es un tipo especial de método que permite que un objeto se inicia- lice a valores definidos para sus datos. El constructor tiene exactamente el mismo nombre que la clase a la cual pertenece; es un método public,es decir, un méto- do al que puede accederse desde cualquier parte de un programa. Ejemplo class MiClase int micampo ; public MiClase (int v a l o r ) //constructor i 1 micampo = v a l o r ; 1 El constructor de una clase comienza con la palabra reservada public y después de la palabra reservada pub1i c viene el nombre del constructor seguido por sus argumen- tos entre paréntesis. Cuando se crea un objeto de la clase se deben proporcionartambién los argumentos requeridos por el constructor. Los constructores se pueden sobrecargar, lo que permite construirobjetos con diferentestipos de valores inicialesde datos. Ejemplo En la clase Circulo se pueden añadir los siguientes constructores: C i r c u l o (double r ) i r a d i o = r ; C i r c u l o ( ) i r a d i o = 4 . 0
  • 123. Clases, objetos y métodos 105 Para crear un nuevo objeto Circulo de radio 6.O se puede utilizar la siguien- te sentencia que asigna un valor 6 . O a micirculo.radio: micirculo = new Circulo (6.O) ; Si se crea un círculo utilizando la sentencia siguiente, se utiliza el segundo cons- tructor que asigna el radio por defecto 4 . O a micirculo.radio: micirculo = new Circulo ( ) ; Advertencia: Los constructores son métodos especiales que no requieren un tipo de retorno, ni incluso void. Si una clase no tiene constructores, se utiliza un constructorpor defecto que no inicializará los datos del objeto. Si no se utilizan constructores, todos los objetos serán el mismo. Ejemplo Dada la clase c l a s s MiClace { i n t micampo; public Miclase( i n t valor) t 1 micampo = valor; 1 Si se desea crear un objeto de una clase Miclase, se debe proporcionar un valor entero que la clase utiliza para inicializar el campo dato micampo.Este ente- ro es el único argumento del constructor de MiClase.Se creará un objeto de la clase con una sentencia como ésta: Esta línea de programa no sólo crea un objeto de la clase MiClase,sino que inicializa el campo micampo al valor 5. Ejercicio El siguiente programa crea dos objetos Cir cu1o,de radios 1O y 2, y visualiza sus superficies.
  • 124. 106 Java 2. Manual de programación class T e s t C o n s t r u c t o r e s C i r - u l o i public static void main (String [ ! args) i //Circulo de radio 10.C Circulo micirculo y new C i r c i i i l o (1:).ti) ; Cystem.out.println("La superficie del r i rculo de radio ''A miCirculo.rddiot" es "t miCirculo.calc,JlarSuperficie( ) ) ; //Circulo con radio por defecto Circulo suCirculo = new C i r c i i l o ( ) ; System.out .println( " L a superficie del circulo de radio " f suCirculo.radio+" es " + suCirculo.calcularCuperficie()); 1 1 class Circulo I double radio; Circulo (double r ) radio = r; 1 Circulo ( ) radio = 2.0; i double calcularsuperficie0 return radio*radio*3.14?592; I S a l i d a La superficie del círculo de radio 10.0 es 314.1592 La superficie del círculo de radio 2.0 es 12.566368 Notas: La clase C i r c u l o tiene dos constructores. Se puede especificar un radio o utilizar el radio por defecto para crear un objeto C i r c u l o . Así: 1. ElconstmctorCirculo (10. O ) seutilizaparacrearuncírculoconunradio 10.0. 2. El constructor C i r c u l o ( ) se utiliza para crear un círculo con un radio por defecto de 2.0. Los dos objetos creados m i c i r c u l o y s u c i r c u l o comparten los mismos métodos y por consiguiente se pueden calcular sus superficies utilizando el método c a l c u l a r s u p e r f i c i e .
  • 125. Clases, objetos y métodos 107 4.9. MODIFICADORES DE ACCESO Java proporciona modificadores para controlar el acceso a datos, métodos y cla- ses, con lo que se consigue proteger a las variables y los métodos del acceso de otros objetos. En Java, se pueden utilizar especificadores de acceso para prote- ger a variables y métodos de una clase cuando ésta se declara. Existen cuatro diferentes niveles de acceso: p r i v a t e , p r o t e c t e d , public y, si se deja sin especificar, package. La Tabla 4.1 proporciona un resumen de los modifica- dores. Tabla 4.1. Modificadores de acceso __ ~~ - ~ Modificador Clase Método Datos Comentario (por defecto) -I 4 4 Una clase, método o dato es visible en este paquete p u b l i c < v’ v’ Una clase, método o dato es visible a todos los programas de cualquier paquete p r i v a t e t Un método o dato es sólo visible en esta clase p r o t e c t e d v Un método o datos es visible en este paquete y en las subclases de esta clase en cualquier paquete Nota: Un modificador que se puede aplicar a una clase se llama modificador de clase. Un modificador que se aplica a un método se llama modificador de método. Un modificador que se puede aplicar a un campo dato se llama modi- ficador de datos. Nota: El modificador p r i v a t e sólo se aplica a variables o a métodos. Si public o p r i v a t e no se utilizan, por defecto, las clases, métodos y datos son accesibles por cualquier clase del mismo paquete. Precaución: Las variables asociadas con los modificadores son los miembros de la clase, no variables locales interiores a los métodos. Utilizando modífica- dores en el interior del cuerpo de un método producirá un error de compila- ción.
  • 126. 1O8 Java 2. Manual de programación 4.10. private El nivel de acceso más restrictivo es private.Un miembro privado sólo es acce- sible en la clase en que está definido. Se utiliza este nivel de acceso para declarar los miembros que se deben utilizar sólo en la clase. En realidad define los métodos y los datos a los que sólo se puede acceder dentro de la clase en que están defini- dos, pero no por las subclases. El objetivo de private es proteger la información contenida en variables para evitar que al ser accedido por un ((extraño))pongan al objeto en estado inconsisten- te o bien para proteger a métodos que si se invocan desde el exterior puedan cam- biar el estado del objeto o el programa en que se está ejecutando. De hecho, los miembros privados son como secretos que no se difunden a ((extraños)). Para declarar un miembro privado, se utiliza la palabra reservada private en su declaración. La clase DemoPrivado contiene dos miembros privados: una variable y un método. public class DemoPrivado private i n t datoprivado; private void metodoPrivado ( 1 i Syctem.out .println("Es un método privado") ; Funcionamiento 1. El código del interior de la clase DemoPrivado puede inspeccionar o modi- ficar la variable datoprivado y puede invocar al método metodoPrivado,pero no lo puede hacer ningún código perteneciente a otra clase. 2. Otra clase externa, ExternaDemo, no puede acceder a los miembros de DemoPrivado. class ExternaDemo i void rnetodoAcceco( ) i DemoPrivado d = new DemoPrivado ( ) ; d.datoprivado =loo; //no legal d.metodoPrivado ( 1 ; //no legal 1
  • 127. Clases, objetos y métodos 109 3. Cuando una clase intenta acceder a una variable a la que no tiene acceso el compilador imprime un mensaje de error similar al mostrado en la Figura 4.4 y no compila el programa. Figura 4.4. Error. 4. Sucede igual acción si se trata de acceder a un método privado. 4.11. protected El especificador p r o t e c t e d permite que la propia clase, las subclases y las cla- ses del mismo paquete, accedan a los miembros. Los miembros protegidos son como los ((secretos familiares))compartidos por familiares, e incluso por amigos, pero no por ((extraños)).Los miembros protegidos se declaran con la palabra re- servada p r o t e c t e d . Consideremos la clase DemoProtegido que se declara dentro de un paquete denominado Demo y que tiene una variable y un método pro- tegidos. package :~cro.TernzC4.Üeno; public c l a s s CemsProtegido I protected i n t d a t c P r o t e q x i o ; protected void m e t a d c 2 r o t e g i c i c O S y c t e m . o ' i t . p r i n t ; n ("Es un Tétodo p r o t e g i u a " ) ; 1 Compilación C:libroTernaG4Derno>javac DemoFrozeg;do.]ava
  • 128. 110 Java 2. Manual de programación Funcionamiento 1. La clase OtraDemo es del paquete Demo, pero no es subclase de DemoProtegido. La clase OtraDemo puede acceder legalmente a la variable datoprotegido e invocar al método metodoProtegido: package libro.Tema04.Demo; class OCraDemo void VetodoAcceso ( ) DemoProtegido d = new DemoProtegido ( ) ; d.datoFrotegido = 100; //legal d.metodoProtegido(); //legal No produce problemas en la compilación ¿ : ~ ~ b r o ~ ~ e m a C 4 D e m o > ~ a v a cOtraDemo.lava 2. Si OtraDemo fuera una subclase de DemoProtegido este código sería tam- bién legal, ya que la clase esta en el mismo paquete que DemoProtegido . 3. Las subclases externas del paquete de la superclase también tienen acceso a los miembros protegidos pero a través de una referencia al objeto: package libro.Terna34.DemoBic; import libro.Tema04.Demo."; c l a s s NLeva extends CemoProtegido void ?,etodoAcceco (DemoProtegido d, Nueva n ) t d.datoprotegido = 100; //no legal nAatcFrotegido = 100; //legal d.metodoProteqido ( ) ; //no legal n.metouoProteg;do(); //legal 1 Se puede acceder a los miembros protegidos a través de un objeto de la clase Nueva,pero no a través de un objeto de la clase DemoProtegido que no seria válido. AI compilar el programa se producen errores (Fig. 4.5).
  • 129. Clases, objetos y métodos 111 Figura 4.5. Errores Aunque en algunos ejercicios ya se han usado paquetes y se ha visto de forma práctica como trabajar con ellos, los conceptos sobre paquetes se explican con deta- lle en el Capítulo 6. 4.12. public El especificador de acceso public es aquel que define las clases, métodos y datos de modo tal que todos los programas pueden acceder a ellos. Los miembros se declaran públicos sólo si este acceso no puede producir resultados no deseables si un ((extraño))a ellos los utiliza. Se declara a un miembro público utilizando la pala- bra reservada public.Por ejemplo: package NegocLos; public class EBusinesc public - i n t cantidad; void operar 0 System.out .println(“Es .n método púbilcr”) ; 4.13. RECURSIVIDAD Un método es recur.sivo cuando directa o indirectamente se llama a sí mismo. La utilización de la recursividad es apropiada cuando el problema a resolver o los datos a tratar han sido definidos de forma recursiva, aunque esto no garantiza que la mejor forma de resolver el problema sea la recursiva. La recursión es una alternativa a la iteración y las soluciones iterativas están más cercanas a la estructura de la compu- tadora. La definición de factorial de un número (n! = n * (n - 1)!) para todo número n mayor que O,teniendo en cuenta que 0! = 2 , es recursiva. La imple-
  • 130. 112 Java 2. Manual de programación mentación se realiza de forma recursiva mediante un método f a c to r ia 1que se llama sucesivamente a sí mismo. p u b l i c class Funcion //factorial recursivo p u b l i c static long factorial ( i n t n) ! i f ( n < O ) r e t u r n -1; i f (n == O ) r e t u r n 1; else r e t u r n n * factorial (n-1); p u b l i c class Prueba t p u b l i c s t a t i c void maic (String'] args) Funcion f = new Funcion ( ) ; Cysterk.out.println(f.factorial(4)); La función factorial también podría haber sido resuelta de forma iterativa de la siguiente forma: p u b l i c c l a s s Funcior.2 //factorial iterativo p u b l i c s t a t i c long factorial (i;nt n) i f (7.< O ) r e t u r n -1; long fact = 1; while (n > O) fact = fact * n; n--; r e t u r n fact; Todo algoritmo recursivo puede ser transformado en iterativo, para esta trans- formación, en ocasiones, resulta necesario utilizar una pila. En el diseño de una algoritmo recursivo es preciso tener en cuenta que:
  • 131. Clases, objetos y métodos 113 La recursividad puede ser directa o indirecta. El instrumento necesario para expresar los algoritmos recursivamente es el método. Un método presenta recursividad directa cuando se llama a sí mismo dentro de su definición. La recursividad indirecta consiste en que un método llame a otro que, a su vez, contenga una referencia directa o indirecta al primero. Un método recursivo debe disponer de una o varias instrucciones selectivas donde establecer la condición o condiciones de salida. Cada llamada recursiva debe aproximar hacia el cumplimiento de la o las con- diciones de salida. Cada vez que se llame al método los valores de los parámetros y variables locales serán almacenados en una pila. Durante la ejecución de dicho método, parámetros y variables tomarán nuevos valores, con los que trabajará el procedimiento o función. Cuando termine de ejecutarse el método, se retornará al nivel anterior, recupe- rándose de la pila los valores tanto de parámetros por valor como de variables locales y continuándose la ejecución con la instrucción siguiente a la llamada recursiva. Hay que tener en cuenta que la recuperación de los datos almacena- dos en una pila se efectúa siempre en orden inverso a como se introdujeron. Los algoritmos recursivos en los que distintas llamadas recursivas producen los mismos cálculos es conveniente convertirlos en iterativos. Un ejemplo de esta situación es el cálculo de los números de Fibonacci,que se definen por la relación de recurrencia f i b o n a c c i . . = f i b o n a c c i - i fibonac- ci?.:,es decir, cada término se obtiene sumando los dos anteriores excepto f i b o n a c c i = O y f i b o n a c c i = 1.La definición dada es recursiva y su implementación se muestra a continuación tanto de forma recursiva como iterativa. Obsérvense los diferentes tiempos de ejecución según se utilice uno u otro algoritmo. public class Fibcriacci / / F i b o n a c c i r e c u r s i v o public s t a t i c long f i b o r . a c ¿ i r ( i n t n) i f (n < O ) i f (n == O ) else r e t u r n -1; r e t u r n ( O ) ; i f (I: := 1) else r e t u r n (11 ; r e t u r n ( f i b T n a c c i r ( r i - 1 ) -fibonacc;r (ri-2) ) ; 1
  • 132. 114 Java 2. Manual de programación //Fibsnacci i z e r a z i v o public s t a t i c long f i b o n a c c i i ( i n t n ) long f = 3 , fsig = 1; f o r ( i n t 1 = C ; i < n ; i t + ) long a u x = f s i g ; f s i g += f; f = a u x ; r e t u r n ( f) ; i public s t a t i c void main (Str;-,g [ ] a r g s ) throws E x c e p t i o n S y s z e ~ ~ . o u t . p r i n t l n( " V e r s i ó n I t e r a t i v a : " ) ; f o r ( i n t i = O ; i <= 38 ; i t + ) S y s t e r n . o u i . p r ; r t l n ( " F i b o n a c c i-i t e r a t i v o ("+;+") "+ f i b o n a c c i i (i)) ; C$'stem.cYt .print:?. ( " r , P u l s e RETURN p a r a c o n t i ? , ' J a r n " ) ; Syszer;. ir.. r e a d ( ) ; C y s ~ e m . i n . s k i s ( S y c ~ e m . ; ~ . . a v a i l a b l e0 ) ; System.ouz.pr:ntln ( " V e r s i ó n r e c u r s i v a : " ) ; f o r ( i n t i = U; i <= 38 ;I++) System.out . p r i r . t l n ( " F i b o n a c c ; - r e c u r s i v o ("+i+")= "+ , f i b o n a c c i r (i)) ; En general, la recursividad debe ser evitada cuando el problema se pueda resolver mediante una estructura repetitiva con un tiempo de ejecución signi- ficativamente más bajo o similar. Teniendo en cuenta esta afirmación, la recur- si idad debiera evitarse siempre en subprogramas con recursión en extremo final que calculen valores definidos en forma de relaciones de recurrencia siinples. Ejercicio Diseñar una clase Funcion3 con un método que permita calcular el máximo común divisor de dos números enteros y positivos por el algoritmo de Euclides. Para obtener el máximo común divisor de dos números enteros y positivos, a y b por el algoritmo de Euclides, debe dividirse a ente b y, si el resto es distinto de cero, repetir la división tras dar a a el valor de b y a b el resto. La condición de termi- nación o de salida será cuando el resto sea cero. public class Funcion3
  • 133. Clases, objetos y métodos 115 //Máximo común divisor p u b l i c s t a t i c i n t m c d ( i n t a , i n t b) i f ( a < O I 1 b < O ) r e t u r n -1; i f ( a '? b == O ) r e t u r n b; else r e t u r n mcd (b, a b); 1 //Programa para probar la clase creaaa import java.io.*; p u b l i c class Prueba3 i Funcion3 f = new Funcion? ( ) ; InputStreamReader i s r = new InputCtreamReacler(System.in); BufferedReader br = new BufferedReacier(isr); i n t nl = O , n2 = O; t r y i System.out.print( " D e m e un número " ) ; nl = Integer .parseInt(br.readLir.e( ) ) ; System.out.print( " D e m e otro r.,Amero " ) ; n2 = Integer.parseInE (br.readline ( ) ) ; Cystem.out.prict (f.mca(nl,n2)) ; Cystem.out .print( " es el máximo común divisor e n t z e " ) ; System.out.println(p1 + " y " + n2); IOException e ) em.err .println ("Error de lectura"); Existen una serie de técnicas para el diseño de algoritmos que usan recursivi- dad, entre las que destacan la estrategia de dividey vencerás y la de retroceso o backtracking. La técnica divide y vencerás consiste en dividir un problema en dos o más subproblemas, cada uno de los cuales es similar al original pero más peque- ño en tamaño. Con las soluciones a los subproblemas se debe poder construir de manera sencilla una solución del problema general. Para resolver cada subpro- blema generado existen dos opciones, o el problema es suficientemente pequeño o sencillo como para resolverse fácilmente de manera cómoda o si los subproble- mas son todavía de gran tamaño, se aplica de forma recursiva la técnica de divide y vencerás.
  • 134. 116 Java 2. Manual de programación Hay un gran número de problemas cuya solución requiere la aplicación de méto- dos de tanteo de forma sistemática, es decir, ir probando todas las opciones posi- bles. La técnica de backtracking divide la solución del problema en pasos y define la solución del paso i-L;simoen función de la solución del paso i-&.sirno+ 1. Si no es posible llegar a una solución se retrocede para probar con otra posible opción.
  • 135. I 5 Herencia CONTENIDO 5.1. Descripción de herencia. 5.2. La clase base Object. 5.3. El método clone. 5.4. El método equals. 5.5. El método finalize. 5.6. El método tostring. 5.7. El método getclass. 5.8. Ventajas de la herencia. 5.9. Superclases y subclases. 5.1O. Modificadores y herencia. 5.11. Clases abstractas. 5.12. Métodos abstractos. 5.13. Interfaces. 5.14. Definición de una interfaz. 117
  • 136. 118 Java 2. Manual de programación ~~~~~ Una de las propiedades más sobresalientes de la programación orientada a objetos es la herencia, un mecanismo que sirve para definir objetos basados en otros existentes. Java soporta herencia con extensión de clases, que permite definir una nueva clase basada en otra clase ya existente sin modificarla. Tal nueva clase, llamada subclase o clase extendida, hereda los miembros de una superclase existente y añade otros miembros propios. Java soporta herencia simple a través de extensión de clases. En herencia simple una clase se extiende a partir de una única superclase. Por ejemplo, una subclase Cuentacorriente se puede extender (ampliar) de una superclase Cuenta o bien Gerente de Empleado. Algunos lenguajes orientados a objetos, como C++, soportan herencia múltiple, que es aquella en que una subclase puede tener varias superclases. Java, por el contrario, no soporta herencia múltiple aunque su funcionalidad puede ser con- seguida mediante interfaces. Este capítulo introduce al concepto de herencia. Específica- mente examina superclases y subclases, el uso de palabras reser- vadas, super y t h i s , 10s modificadores p r o t e c t e d , f i n a l y a b s t r a c t , diferentes clases Útiles y el diseño de interfaces. 5.1. DESCRIPCIÓN DE HERENCIA En terminología Java, la clase existente se denomina superclase. La clase derivada de la superclase se denomina la subclase. También se conoce a la superclase como clase padre y una subclase se conoce como clase hija, clase extendida o clase derivada. La Figura 5.1 contiene la definición de una clase para estudiantes. Un estudian- te es una persona, por lo que se puede definir la clase E s tudiante que se deriva de la clase Persona.Una clase derivada es una clase que se define añadiendo variables de instancia y métodos a una clase existente. En el ejemplo de la Figura 5.1, la clase Persona es la clase base y la clase Estudiante es la clase deriva- da, Las clases derivadas tienen todas las variables de instancia y los métodos de la clase base, más las variables de instancia y métodos que se necesiten añadir. Persona 7 Figura 5.1. Jerarquía de clases.
  • 137. Herencia 119 La definición de una subclase tiene la sintaxis siguiente: public class nombrecldre extends C l a c e B a c e Un ejemplo puede ser: public class Estu=-ante extends Percoza Nota: La herencia es siempre trunsitiva, de modo que una clase puede here- dar características de superclases de muchos niveles. Si la clase Perro es una subclase de la clase Mamífero y la clase Mamífero es una subclase de la clase Animal,entonces Perro heredará atri- butos tanto de Mamífero como de Animal.Se pueden reutilizar o cambiar los métodos de las superclases y se pueden añadir nuevos datos y nuevos métodos de las subclases. Las subclases pueden anular (redefinir) el comportamiento hereda- do de la clase padre. Por ejemplo, la clase Ornitorrinco redefine el compor- tamiento heredado de la clase Mamifero, ya que los ornitorrincos ponen huevos. /,--- Animal y --. + -<- Mamífero I 1 Perro y A----- -. % -_I’ i. Ornitorrinco ~~ ~ -_ Figura 5.2. Herencia y redefinición de comportamientos. 5.2. LA CLASE BASE Object En Java todas las clases utilizan herencia. A menos que se especifique lo contrario, todas las clases se derivan de una clase raíz, denominada Ob] ect.Si no se pro- porciona explícitamente ninguna clase padre, se supone implícitamente la clase Object.Así, la definición de la clase MiPrimerPrograma:
  • 138. 120 Java 2. Manual de programación public class MiPrimerPrograma ! public static void main (String [ I argsj ! i System.out .println("Mi primer programa Java" j ; es igual que la siguiente declaración: import java.lang.*; public class MiPrimerPrograma extends Object t public static void main (String [ I argsj I Cystem.out .println("Mi primer programa Java"); 1 i La clase Ob] ect' proporciona la funcionalidad mínima garantizada que es común a todos los objetos (Fig. 5.3). Figura 5.3. Todas las clases son descendientes de la clase Object ' http://java.sun.com/products/jdk/I .3/docs/api/java/lanE/Object.htrnl
  • 139. Herencia 121 La clase Obje c t define e implementa el comportamiento que cada clase del sis- tema necesita. La clase Object esta en el nivel mas alto de la jerarquía y se encuentra definida en la biblioteca java .l a n g . Cada clase del sistema Java es un descendiente, directo o indirecto de la clase O bject.Esta clase define el estado básico y el comportamiento que todos los objetos deben tener, tal como comparar un objeto con otro objeto, convertir a una cadena, esperar una variable condición, notificar a otros objetos que ha cambiado una variable condición o devolver la clase del objeto. La clase Object proporciona una funcionalidad mínima que garantiza un comportamiento común a todos los objetos. Estos objetos incluyen los métodos siguientes: public boolean equals ( J ava .lang.Object obj) Determina si el objeto del argumento es el mismo que el receptor. Este método se puede anular para cambiar el test de igualdad de clases diferentes. Devuelve la clase del receptor, un objeto de tipo Class. Devuelve un kalor aleatorio para este objeto. Este método debe también ser anulado cuando public final java.lang.Class getClacs0 public int hashcode ( ) public 1ava.lang.String tostring0 el método equals se cambia. Convierte el objeto a un valor de cadena. Este método se anula también con frecuencia. Regla: Los métodos de la clase O bject que se pueden anular o redefinir son: clone equals finalize tostring Regla: Los métodos que no se pueden anular en la clase O bj ect,ya que son final, son: getclass notify2 notifyAll wait Los métodos wa; t y notify se tratarán en el capítulo destinado a la programación multihilo.
  • 140. 122 Java 2. Manual de programación 5.3. EL MÉTODO clone Se puede utilizar el método clone para crear objetos de otros objetos del mismo tipo. Por defecto, los objetos no son clónicos, de modo que la implementación de este método del objeto lanza una excepción CloneNotCupportedException . Si se desea que la clase sea clónica, se debe impleinentar la interfaz Cloneable y anular este método. protected C'bjert c l o r . e ( ) throws CloneKotCupportedYxceptlon; 5.4. EL MÉTODO equals Se utiliza para determinar la igualdad de dos objetos. Este método devuelve true si los objetos son iguales y false en caso contrario. El siguiente código com- prueba la igualdad de dos enteros (Integer): Inieger Primero = new Integer(i); Inieger CeguEdc = new Integer(i); i f (iri~ero.eqLals(Cegunas)) Cystem.ouz.prinZln ( "L o s O b j e t o s son iguales"); Este programa indicaría que los objetos son iguales aunque referencian a obje- tos distintos. 5.5. EL MÉTODO finalize El método finalize no hace nada. Se redefine finalize para ejecutar opera- ciones especiales de limpieza antes de que se recoleccione la basura correspon- diente al objeto o cuando el programa termina. protected void finalize ( ) La llamada Syster.rxnFinalizercOnExit(true); solicita la ejecución de los métodos finalize cuando un programa termina. Sin la petición los métodos finalize no se invocan cuando termina un programa. I En el Capítulo 13 e estudia el concepto de excepciones.
  • 141. Herencia 123 Nota: Cuando se utiliza el operador new se reserva memoria, esta memoria no es necesario liberarla, pues Java realiza una recolección de basura automática mediante un hilo de baja prioridad, en realidad un demonio,proporcionado por la máquina virtual de Java. 5.6. EL MÉTODO t o s t r i n g El método tostring de Object devuelve una representación String del obje- to. Se puede utilizar tostring junto con System.out .printlnpara visuali- zar una representación de texto de un objeto, tal como el hilo (thread actual. Syctern.out .println(Thread.current-hread() .toltr:ng ( ) ) ; La representación String de un objeto depende totalmente del objeto. La representación String de un objeto Integer es el valor entero visualizado como texto. La representación String de un objeto Thread contiene diversos atribu- tos sobre el hilo tal como su nombre y prioridad. Por ejemplo la salida de la ins- trucción anterior podría ser: Thread[main,5,mainl 5.7. EL MÉTODO getclass El método getCl a ss es un método final que devuelve una representación en tiem- po de ejecución de la clase del objeto. Este método devuelve un objeto Class.Se puede consultar el objeto Class para obtener diversas informaciones sobre la clase, tal como su nombre, su superclase y los nombres de los interfaces que im- plementa. public final java.lang.Clacs getclass0 Ejemplo void imprimirNombreOb~eto(0bJectob]) Cystem.out.println ("La clase del o b j e t o e s "+ obj .getclass ( ) .getName ( ) ) ;
  • 142. 124 Java 2. Manual de programación Si el objeto ob) pasado como parámetro fuera de tipo Integer,la llamada a este método devolvería: La clase del obleto es java.lang.Integer 5.8. VENTAJAS DE LA HERENCIA El mecanismo de herencia presenta importantes ventajas: Facilidad en la modificación de clases. Evita la modificación del código exis- tente al utilizar la herencia para añadir nuevas características o cambiar carac- terísticas existentes. Extracción de commalidad de clases difirentes. Evita la duplicación de estructuras/código idéntico o similar en clases diferentes. Sencillamente, se extraen las partes comunes para formar otra clase y se permite que ésta sea heredada por las demás. Organización de objetos enjerarquía. Se forman grupos de objetos que con- servan entre sí una relación ((es un tipo de)) (is u king oJ>. Por ejemplo, un coche (carro) es un tipo de automóvil, un deportivo es un tipo de coche (carro), una cuenta corriente es un tipo de cuenta, un ingeniero de sistemas es un tipo de empleado, una matriz cuadrada es un tipo de matriz, manzana reineta es un tipo de manzana. 9 Adaptación de programas para trabajur en situaciones similares pero dife- rentes. Evita la escritura de grandes programas, si la aplicación, sistema informático, formato de datos o modo de operación es sólo ligeramente diferente, pues se debe utilizar la herencia para modificar el código exis- tente. 5.9. SUPERCLASES Y SUBCLASES Una clase extendida hereda todos los miembros de sus superclases, excepto constructores y finalize,y afiade nuevos miembros específicos. En esencia, una subclase hereda las variables y métodos de su superclase y de todos sus ascendientes. La subclase puede utilizar estos miembros, puede ocultar las varia- bles miembro o anular (redefinir) los métodos. La palabra reservada this.per- mite hacer referencia a la propia clase, mientras que super se utiliza para referenciar a la superclase y poder llamar a métodos de la misma (aunque esten redefinidos).
  • 143. Herencia 125 Regla: Una subclase hereda todos los miembros de su superclase, que son accesibles en esa subclase a menos que la subclase oculte explícitamente una variable miembro o anule un método. Regla: Los constructores no se heredan por la subclase. Una clase extendida es una clase compuesta con miembros de la superclase (miembros heredados) y miembros adicionales definidos en las subclases (miem- , bros añadidos). Los miembros que se heredan por una subclase son: Las subclases heredan de las superclases los miembros declarados como p u b l i c o p r o t e c t e d . Las subclases heredan aquellos miembros declarados sin especificador de acceso mientras que la subclase está en el mismo paquete que la superclase. Las subclases no heredan un miembro de la superclase si la subclase declara un miembro con el mismo nombre. En el caso de las variables miembros, la varia- ble miembro de la subclase oculta (hides)la correspondiente de la superclase. En el caso de métodos, el método de la subclase anula el de la superclase. Las subclases no heredan los miembros privados de la superclase. Nota: El término subclase se refiere simplemente a los mecanismos de cons- trucción de una clase utilizando herencia y, es fácil de reconocer, a partir de la descripción del código fuente por la presencia de la palabra clave extends. 5.1O. MODIFICADORES Y HERENCIA El lenguaje Java proporciona diversos modificadores que se pueden utilizar para modificar aspectos del proceso de herencia. Los modificadores que controlan el acceso o visibilidad en la clase son: p u b l i c , p r o t e c t e d y p r i v a t e . A m a característica p u b l i c , método o campo (dato público) puede acceder- se desde el exterior de la definición de la clase. A una clase pública se puede acceder fuera del paquete en el que está declarada. A una característica p r o t e c t e d sólo se puede acceder dentro de la definición de la clase en la que aparece, dentro de otras clases del mismo paquete o den- tro de la definición de subclases.
  • 144. 126 Java 2. Manual de programación A una característica private se puede acceder sólo dentro de la definición de la clase en que aparece. Otros componentes posibles de una declaración de clase son static,abs- tract y final.Los campos dato y métodos se pueden declarar como static. Un campo estático se comparte por todas las instancias de una clase. Un método estático se puede invocar incluso aunque no se haya creado ninguna instancia de la clase. Los campos de datos y métodos estáticos se heredan de igual modo que los no estáticos, excepto que los métodos estáticos no se pueden anular (redefinir). Regla: static Define datos y métodos. Representa amplia información de la clase que se comparte por todas las instancias de las clases. public Define clases, métodos y datos de tal modo que todos los pro- gramas puedan acceder a ellos. private Define métodos y datos de tal modo que se puede acceder a ellos por la declaración de la clase, pero no por sus subclases. Nota: Los modificadores static y private se aplican aisladamente a variables o a métodos. Si los modificadores public o private no se utili- zan, por defecto las clases, métodos y datos son accesibles por cualquier clase del mismo paquete. Precaución:Las variables asociadas con modificadores son los miembros de la clase, no variables locales dentro de los métodos. Utilizando modificadores dentro del cuerpo de un método se producirá un error de compilación. Los métodos y las clases se pueden declarar abstractas (abstract).Una clase abstracta no puede ser ((instanciada)).Es decir no se puede crear una instancia de una clase abstracta utilizando el operador new. Tal clase sólo se puede utilizar como una clase padre para crear un nuevo tipo de objeto. De modo similar un método abstract debe ser anulado (redefinido) por una subclase. Un modificador alternativo, final,es el opuesto de abstract.Cuando se aplica a una clase, la palabra reservada indica que la clase no se puede atender: es decir, que no puede ser una clase padre. De modo similar, cuando se aplique a un método la palabra reservada indica que el método no se puede anular y, en conse- cuencia, el usuario tiene garantizado que el comportamiento de una clase no puede ser modificado por una clase posterior.
  • 145. Herencia 127 Nota: Se puede utilizar el modificador final para indicar que UT clase es final y no puede ser una clase padre. Regla: abstract final static La clase no puede ser instanciada. Las clases no pueden ser subclasificadas. Los campos static son compartidos por todas las instancias de una clase. Nota: Los modificadores se utilizan en clases y miembros de la clase (datos y métodos). El modificador final puede utilizarse también en variables locales en un método. Una variable local final es una constante interna al método. 5.11. CLASES ABSTRACTAS En ocasiones, una clase definida puede representar un concepto abstracto y como tal no se puede instanciar. Consideremos, por ejemplo, la comida en el mundo real. ;Se puede tener una instancia (un ejemplar) de comida? No, aunque sí se pueden tener instancias de manzanas, chocolates, naranjas o peras. La comida representa el concepto abstracto de cosas que se pueden comer y no tiene sentido que tenga ins- tancias ya que no es un objeto concreto. Otro ejemplo puede ser la clase abstracta FiguraTresDimensiones;de ella se pueden definir clases concretas (especí- ficas), tales como Esfera,Cilindro,Cono,... Las clases abstractas son Útiles para definir otras clases que sirvan para instan- ciar objetos, pero de ellas no se pueden crear instancias utilizando el operador new. El propósito de una clase abstracta es proporcionar una superclase a partir de la cual otras clases pueden heredar interfaces e implementaciones. Las clases a partir de las cuales se pueden crear instancias (objetos), se denominan clases concretas. Todas las clases vistas hasta este momento son clases concretas, significando que es posi- ble crear instancias de la clase. Importante: Una clase abstracta es una clase que contiene los nombres de los comportamientos sin las implementaciones que ejecutan esos comportamien- tos. Los objetos no sepueden instanciar de una clase abstracta. I
  • 146. 128 Java 2. Manual de programación Uno de los objetivos de la programación orientada a objetos es reconocer los ele- mentos que son comunes y agrupar esos elementos en abstracciones generales. Por ejemplo, si se desea construir un marco de trabajo íJi-ameti?ork)de clases para figu- ras geométricas, se puede comenzar con la noción general de «una figuran como clase base. A partir de esta clase base se pueden derivar las clases de figuras espe- cíficas, tales como Círculo o Rectángulo. - - Figura >- - c,/------- --- / -. / Rectángulo I 1’ - -- /’ Círculo it__/ Figura 5.4. Herencia y jerarquía de clases. Una clase se declara abstracta con la palabra reservada abstract.Una jerarquía de clases no necesita contener clases abstractas, sin embargo, muchos sistemas orien- tados a objetos tienen jerarquías de clases encabezadas por superclases abstractas. La Figura 5.5 representa una jerarquía de figura de la que a su vez se derivan otras dos clases abstractas, FiguraDos Dimensiones y FiguraTresDimensiones. _ - - Figura --* -~~ ,,’ ,-/ - ~ - --.Figura 2 Dimensiones 3 -----7- I / __ ’Figura 3 Dimension& I - * - - % Figura 5.5. Jerarquía de herencia de clases Figura. Las clases abstractas son como las clases ordinarias con datos y métodos, pero no se pueden crear instancias de clases abstractas usando el operador new.Las cla- ses abstractas normalmente contienen métodos abstractos. Un método abstracto es una signatura de un método sin implementación. Su implementación se proporcio- na en sus subclases. Para declarar una clase abstracta tal como Figura se puede hacer con la siguiente sintaxis: abstract class Figura I Si se trata de instanciar una clase abstracta, el compilador visualiza un error similar al mostrado en la Figura 5.6 y rechaza compilar el programa.
  • 147. Herencia 129 1 4 1 I Figura 5.6. 5.12. MÉTODOS ABSTRACTOS Una clase abstracta es una clase definida con el modificador abstract que puede contener métodos abstractos (métodos sin implementación) y definir una interfaz completa de programación. Los métodos abstractos se implementan en las subclases. Regla: No todos los métodos se pueden declarar abstractos. Los siguientes métodos no se pueden declarar como abstractos: Métodos privados. Métodos estáticos. Ejemplo Definir una clase abstracta ObjetoGeometrico. Esta clase debe contener entre otros métodos, los de cálculo del área y perímetro de objetos geométricos. Dado que no se conoce cómo calcular áreas y perímetros de objetos geométricos abstractos, los métodos calcularArea y CalcularPerimetro se definen como méto- dos abstractos. Estos métodos deben implementarse en las subclases. Suponiendo una clase concreta Circulo como subclase de ObjetoGeometrico. La posible implementación de la clase Circulo es como sigue: public c l a s s C i r c ~ l oextends ObletoGeomeLrico t private double r a d i o ; public C i r r u l c (double Y , String nom) super (ncn?); radio = z; I
  • 148. 130 Java 2. Manual de programación public Circslc ( ) / t h i s (1.O, "Blanco"); public double devolverRadio ( ) t return radio; I public double calcularArea ( ) return radio * radic * Math.FI; public double caicularPerimetro ( ) return 2 * Math.PI * radio; I public String tostring ( ) return "Nombre = " t cuper.tcStrinq() t " radio = " t radio; i y la definición de la clase abstracta ObjetoGeometrico es: a b s t r a c t c l a s s ObjetoGeometrico private String nombre; public ObjetoGeometrico(Strinq nom) r.ombre = rom; a b s t r a c t public double calcularkrea(); a b s t r a c t public double calcularPerimetro(); public String tostring ( ) r e t u r n norbre; I Como clase de prueba, se puede utilizar la siguiente clase Prueba: import ]ava.io.*; public c l a s s Prueua public s t a t i c void mair (String'] argc)
  • 149. Herencia 131 InputStreamReader isr = new InputStreamReader(Cystem.;n); BufferedReader br = n e w BufferedReader(icr); t=Y i Circulo uncirculo n e w Circulo ( ) ; Systern.o u t .r>rin t1ri ( iinC ircu1o .tostring ( ) ) ; Cystem.out.prlnt.ln("Area d e l circulo = " + System.out .println("Longitud de la circunferencla = " + Systern.out.println ("Introduzca el nomire y pulse RESiJRN") ; String cadena = br.readLine ( ) ; System.out .printin("Introduzca el radio y p u l s e RETURN") ; String numero = br.readLine ( ) ; Double d = n e w Double(nuner0) ; double real y d.doubleValEe ( ) ; Circulo otroCirc'Jlo = n e w Circulo (real, cadei.a); Systern.out.println(otrcCirculo.toString() 1 ; System.out.println ("Area del circulo = " + Cystem.out.println ("Longitud de la rircunfereccia = " + unCircuio.calcularArea()); unCirculo.calcularPerimetro()); otroCirculo.calcxlarArea()1 ; otrocirculo.ca1cularPerírne:ro ( ) ) ; 1 catch(Exception e ) Cystem.out .println("Error"); Naturalmente se podrá crear también una subclase Cilindro que se extien- de Círculo. 1.. ._--_-~_ - Objeto Geométrico , -_ _ ~- - - A 1 Círculo / 4 - _ CiIindro / Figura 5.7. Cilindro es una subclase de Circulo y Circulc es una subclase de ObjetoGeometrico.
  • 150. 132 Java 2. Manual de programación Consejo: Utilice clases abstractas para generalizar propiedades comunes y métodos de subclases y utilice métodos abstractos para definir los métodos comunes que deben ser implementados en subclases. Precaución: Un método abstracto no puede estar contenido en una clase no abstracta. En una subclase no abstracta extendida de una clase abstracta todos los métodos abstractos deben ser implementados, incluso si no se utilizan en la subclase. Ejemplo , Rectangulo - _ . ObjetoGráfico Línea Círculo Cuadrado Figura 5.8. Las clases heredan cierto estado y comportamiento de su clase padre común O b ~ e t o ~ < r a f i c o . abstract class SbjetoGrdfix i n t x, y; / / . . . void moveTo ( i n t nuevaX, i n t r i i ~ c ~ w Y ) t 1 / / . . . abstract void d i b cj a r ( 1 ; c l a s s C i r c u l o extends Objetosrafico void d;bu j a r ( ) i / / . . . class Reerangulc! extends C b j e t o ( ; r , i f i c c void dibujár ( ) i } / / . . .
  • 151. Herencia 133 Advertencia: Java vs. C++ Una diferencia fundamental entre métodos C++ y métodos Java es que los métodos Java son virtuales por defecto. En otras palabras, Java proporciona el mecanismo de envío virtual con cada jerarquía de clases, de modo que un objeto, basado en su tipo y posición en la jerarquía, podrá invocar la imple- mentación correcta de un método. Cuando una clase derivada anula un método abstracto y proporciona una implementación, debe hacerlo con el mismo nombre de método, lista de argu- mentos y tipo de retorno. Reglas: Java utiliza la palabra reservada abstract abstract public double calcularArea0; que sirve como un modificador al método calcularArea ( ) . Cuando una clase contiene al menos un método abstracto, el modificador abstract debe aplicarse también a la declaración de clases abstract class ObjetoGeometrico No se pueden crear instancias de clases abstractas. Por ejemplo, la senten- cia siguiente es ilegal: ObjetoGeometricoalgunaFigura = new ObjetoGeometico("Blanco"); //Error Ejemplo Definamos la superclase E s tudiante y sus dos subclases, clases derivadas, EstudiantePregrado y Estudiantepostgrado.En principio no parece que tenga sentido crear instancias de la clase Estudiante,ya que un estudiante puede ser de pregrado, de postgrado o puede ser otro tipo de estudiante (de forma- ción profesional, idiomas, bachiller, etc.), por tanto, declararemos la clase estudian- te como abstracta. abstract c l a s s Estudiante i protected f i n a l s t a t i c i n t NUM-DE-PRUEBAS = 3 ; protected String nombre;
  • 152. 134 Java 2. Manual de programación / / vea el capítulo sobre arrays protected i n t [ ] prueba; protected String calificacion; public Estudiante ( ) t h i s ("Ningun nombre") ; 1 public Sstudiante(Ctrlny nornbreEstudiante) nombre = nombreEstudiante; prueba = new i n t [NUM-DE-PRUEBAS]; calific-cion = "*****". I / / rretodo abstracto abstract public void ~alcularCdlificdcion(); public String 1eerNombre ( ) i r e t u r n nombre; I public i n t 1eerNotacPruebas ( i n t riumPriicha) r e t u r n prneba [ numPrueba - 1I ; 1 public void ponerNombre (String niievoNombre) t 1 nombre = nuevoNombre; public void fijarNotacPruebas ( i n t numPrueba, i n t notaprueba) t 1 prueba [numPrueba - 11 = notaprueba; 5.13. INTERFACES El lenguaje Java soporta interfaces que se utilizan para definir un protocolo de com- portamiento que se puede implementar por cualquier clase en cualquier parte de la jerarquía de clases. Definición: Una interfaz (intersace)en Java es una descripción de comporta- miento.
  • 153. Herencia 135 En esencia, una interfaz es un sistema o dispositivo que utiliza entidades no rela- cionadas que interactúan. Ejemplos de interfaces son un mando a distancia para televisión, que es una interfaz entre el espectador y un aparato de televisión, un navegador de Internet, que es una interfaz entre el internauta y la red Internet. Las interfaces en Java tienen la propiedad de poder obtener un efecto similar a la herencia múltiple que soportan otros lenguajes como C++. Si se utiliza la palabra reservada extends para definir una subclase, las subclases sólo pueden tener una clase padre. Con interfaces se puede obtener el efecto de la herencia múltiple. Una interfaz se considera como una clase especial en Java. Cada interfaz se compila en un archivo independiente bytecode tal como una clase ordinaria. No se pueden crear instancias de una interfaz. En la mayoría de los casos, sin embargo, se puede utili- zar una interfaz de un modo similar a como se utiliza una clase abstracta. Una inter- faz Java define un conjunto de métodos, pero no las implementaciones, así como datos. Los datos, sin embargo, deben ser constantes y los métodos, como se acaba de indicar, sólo pueden tener declaraciones sin implementación. , Sintaxis m o d i f i c a d o r interface Nombre Int e r f a z t //decldraciones de constantes //declaraciones de los métodos Definición: Una interfaz es una colección con nombre de definiciones de mé- todos (sin implementaciones) que puede incluir también declaraciones de constantes. Una interfaz se puede considerar una clase abstracta totalmente y en ella hay que tener en cuenta que: Todos los miembros son públicos (no hay necesidad de declararlos piblicos). Todos los métodos son abstractos (se especifica el descriptor del método y no Todos los campos son staticy final(proporcionan valores constantes Útiles). hay ninguna necesidad de declararlos abstract). 5.14. DEFINICIÓN DE UNA INTERFAZ Una definición de interfaz consta de dos componentes (Fig. 5.9): la declaración de la inteyfaz y el cuerpo de la intwfaz.
  • 154. 136 Java 2.Manual de programación declaración de interfaz + public interface Compararobjetos i public static final int MENOR ~ 1; de public static final int I CIJA1 O ; public static final int MAYOR - 1; cuerpo de constantes la interíaz public int comparar (CompararObjetos otroOb1eto); 1 de métodos Figura 5.9. Definición de una interfaz. La declaración de la interfaz declara diversos atributos acerca de la interfaz, tal como su nombre y si se extiende a otra interfaz. El cuerpo de la interfaz contiene las declaraciones de métodos y constantes dentro de la interfaz. Consejo: Las clases abstractas y los interfaces se pueden utilizar para conse- guir programación genérica. Se deben utilizar interfaces si se necesita heren- cia múltiple. Si la herencia que se necesita es simple, es suficiente el uso de clases abstractas. Normalmente el uso de una clase abstracta es mayor que el uso de una interfaz. Ejemplo Diseñar un método de ordenación genérico para ordenar elementos. Los elemen- tos pueden ser un array de objetos tales como estudiantes, círculos y cilindros. En este caso se necesita un método genérico comparar para definir el orden de los objetos. Este método deberá adaptarse para que pueda comparar estudiantes, círculos o cilindros. Por ejemplo, se puede hacer uso del número de expediente como clave para la comparación de estudiantes, del radio como clave para la com- paración de círculos y del volumen como clave para la comparación de cilindros. Se puede utilizar una interfaz para definir el método genérico comparar del modo siguiente: public interface CompararObleto public static final int MENOS = -1; public static final int IGUAL = O; public static final int MAYOR = 1; public int comparar(Comparar0bjeto unobjeto);
  • 155. Herencia 137 El método comparar determina el orden de los objetos a y b del tipo CompararObjeto.La instrucción a.comparar (b)devuelve un valor -1 si a es menor que b,un valor de O si a es igual a b o un valor de 1si a es mayor que b. Un método genérico de ordenación para un array de objetos CompararObje t o se puede declarar en una clase denominada Ordenar: public class Ordenar public void ordenar (CompararObjeto[ ] x) t / / vea el capítulo sobre arrays CompararObjeto maxActual; int indiceMaxActua1; for (int i = x.length-1; i >= 1; i--) i maxActua1 = x[11; indiceMaxActua1 = i; for (int 7 = i-1; j >= O; I--) if (maxActua1.comparar (x[ 7 ] j ==-1) í rnaxActua1 = x[]I; indiceMaxActua1 = 1 ; / * intercambiar x [i] ron x[indiceMaxActua:; si fuera necesario * / if (indiceMaxActua1 ! = ij x [ indiceMaxActua1 I = x [ il ; x[i] = maxActual; I I Nota: La clase Ordenar contiene el método ordenar. Este método se basa en algoritmos de ordenación.
  • 156. 138 Java 2. Manual de programación Precaución: La definición de una interfaz es similar a la definición de una clase abstracta. Existen, sin embargo, unas pocas diferencias: En una interfaz los datos deben ser constantes; una clase abstracta puede tener todo tipo de datos. Cada método de una interfaz tiene sólo una signatura sin implementación; una clase abstracta puede tener métodos concretos. Ningún modificador abstracto aparece en una interfaz; se debe poner el modificador abstract antes de un método abstracto en una clase abstracta. Un método genérico de búsqueda de un determinado objeto en un array de obje- tos CompararObje t o ordenado ascendentemente se puede declarar en una clase denominada Buscar como la que se expone a continuación. Los métodos de orde- nación y búsqueda se explican en el capítulo destinado a arrays, public class Bcscar private int Busqueja-binaria (CompararObjeto [ 1 x, int iz, int de, CompararCbjeto unobjeto) int central = (iz+de)/2; if (de < iz) í / devuelve un r.ú.eroRegativo cuando no encuentra el elemento if ( i n O b J e t o .comparar (x[central]) == CompararObjeto.MEN0S) else if (ur.3bjeto.cornparar(x[central]) == CompararObjeto.MAYOR) else return(-iz) ; return(Busqceda-binaria (x,iz,central-1,unobjeto)) ; return(E.Jsqueda-Dinaria (x,centrait 1,de,.dnObjeto)) ; //devuelve la posición donde se encuentra el elemento return(centra1); i public int bbin (CompararCb]etc[] x, CompararObjeto unobjeto) return(BLsqJeda-tinaria (x, O, x.,ength, un0bjeto)) ; Regla: Una vez que se ha definido una interfaz, el nombre de la interfaz se convierte en el nombre de un tipo. Cualquier clase que implemente la interfaz se convierte en un subtipo de ella. Una interfaz es un contrato entre proveedo- res y clientes de un servicio particular. El diseño de una interfaz afecta a las funcionalidades y capacidad en el lado proveedor y las complejidades y con- veniencias en el lado cliente.
  • 157. Herencia 139 Ejemplo Considerar una interfaz Ordenable. public interface Ordenable i / * Comparar elementos i y J para el elemento~ i >, == , < elemento-j devuelve >O, O, <O si la dirección esta CRECIENDO <O, O, >O si la dirección esta DECRECTENDO * / int comparar(int i, int j); / / Intercambia elementos i y j void intercambio( int i, int j); / / Indice del primer elemento int primero ( ) ; / / Indice del Último elemento int ultimo ( ) ; / / Bandera para indicar dirección de order.ación boolean ordenado ( ) ; void ordenado (boolean b) ; / * Indicador de dirección para CRECIENDO o DECRECIENDO * / void direccion (int dir); int direccion ( ) ; / / Valores de indicadores de direcciones posibles static final int CRECIENTE = 1; static final int DECRECIENTE = -1;
  • 158. 6 Encapsulamiento y poiimortismo CONTENIDO 6.1. Encapsulamiento. 6.2. Modificadores de clases. 6.3. Modificadores de variables. 6.4. Modificadores de métodos. 6.5. Clases internas. 6.6. Paquetes. 6.7. Declaración de un paquete. 6.8. Paquetes incorporados. 6.9. Acceso a los elementos de un paquete. 6.10. Importación de paquetes. 6.1I . Control de acceso a paquetes. 6.12. Polimorfismo. 6.13. Ligadura. 6.14. Ligadura dinámica. 141
  • 159. 142 Java 2.Manual de programación Este capítulo examina las importantes propiedades de Java en- capsulamiento y polimorfismo.La programación orientada a objetos encapsula datos (atributos) y métodos (comportamientos) en paquetes denominados objetos. La ocultación de la información y abstracción,como términos sinónimos, gestiona la visibilidad de los elementos de un programa. Encapsulamiento es un término muy utilizado para significar que los datos y las acciones se combinan en un Único elemento (un objeto de las clases) y que los detalles de la implementación se ocultan. El término polimorfismo significa <<múltiplesformas,, (poly = muchos, morphos = forma). En lenguajes orientados a objetos, el polimorfismo es un resultado natural de la relación es-un y los mecanismosdel paso de mensajes, herencia y el concepto de sus- titución. El polimorfismo es una de las propiedades clave de un tipo de programaciónconocida Comoprogramación orientadaa objetos. El polimorfismo permite a los programadores enviar el mismo men- saje a objetos de diferentes clases. Existen muchas formas de poli- morfismo en Java. Por ejemplo, dos clases diferentes pueden tener métodos con el mismo nombre. 6.1. ENCAPSULAMIENTO Encapsulamiento es un término que se utiliza en las modernas técnicas de programa- ción. Encapsulamiento significa que los datos y las acciones se combinan en una sola entidad (es decir, un objeto de la clase) y se ocultan los detalles de la implementa- ción. La programación orientada a objetos (POO) encapsula datos (atributos) y métodos (comportamientos)en objetos. Los objetos tienen la propiedad de ocultación de la información. Esta propiedad significa que aunque los objetos pueden conocer cómo comunicarse unos con otros a través de interfaces bien definidas, no pueden conocer cómo están implementados otros objetos (los detalles de la implementación están ocultos dentro de los propios objetos). Ésta es una situación muy frecuente del mundo real. Es posible conducir con eficacia un automóvil sin conocer los detalles internos de cómo funciona el motor, el tren de engranajes o el sistema de frenos. En Java se tiene un gran control sobre el encapsulamiento de una clase y un objeto. Se consigueaplicandomodificadoresa clases,variables de instanciay de clases,y méto- dos. Algunos de éstos modificadores se refieren al concepto de paquete, que se puede considerar básicamente como un grupo de clases asociadas. 6.2. MODIFICADORES DE CLASES Se puede cambiar la visibilidad de una clase utilizando una palabra reservada, modifi- cador, antes de la palabra reservada class en la definición de la clase, por ejemplo:
  • 160. Encapsulamiento y polimorfismo 143 public class P e r s o n a I ... i Una clase pública se define dentro de su propio archivo y es visible en cualquier parte. Una clase que es local a un paquete específico no tiene modificador y se puede definir dentro de un archivo que contiene otras clases. Como máximo, una de las clases de un archivo puede ser una clase pública. 6.3. MODIFICADORES DE VARIABLES La cantidad de encapsulamiento impuesta por una clase se establece a discreción del programador. Puede permitirse el acceso completo a todo el interior dentro de la clase o se pueden imponer diversos niveles de restricciones. En particular, se puede controlar cuánto es el acceso a otra clase que tiene la instancia y las variables de clase de una clase. Se consigue esta acción utilizando un modificador, palabra reser- vada, antes del tipo de la variable. Por ejemplo: public static i n t VALOR-MAX =65; protected S t r i n g n o m b r e ="Pepe Mackoy"; private i n t c u e n t a = O ; La Tabla 6.1 lista los modificadores y sus significados. Normalmente es una buena idea imponer tanto encapsulamiento como sea posible. En consecuencia, debe ocultarse todo lo que se pueda, excepto lo que se desea hacer visible a otras clases, en cuyo caso se debe permitir la cantidad mínima de visibilidad. Tabla 6.1. El efecto de un modificador de método o variable Modificador Significado public ningún modificador Visible en el paquete actual protected private Visible en cualquier parte (la clase también debe ser pública) Visible en el paquete actual y en las subclases de esta c!ase en otros paquetes Visible sólo en la clase actual Observación: El modificadorp r o t e c t ed es más débil que el uso de ningún modificador. No se debe utilizar ningún modificador con preferencia a protected.
  • 161. 144 Java 2. Manual de programación 6.4. MODIFICADORES DE MÉTODOS Se puede limitar también el acceso de otras clases a métodos. Esta acción se reali- za utilizando una palabra reservada (modificador),antes del tipo de retorno del método. Los modificadores son los mismos que para las variables. public void leerNombre (String nombre) i 1 . . . private s t a t i c i n t contarObjetos0 i 1 protected f i n a l Object encontrarllave0 t 1 * . . . . . 6.5. CLASES INTERNAS Java permite definir clases e interfaces dentro de otras clases e interfaces. Una clase que no se anida dentro de otra se denomina clase de nivel superior. Esto significa que prácticamente todas las clases iitilizadas hasta ahora son clases de nivel supe- rior. Las clases internas se definen dentro del ámbito de una clase externa (o de nivel superior). Estas clases internas se pueden definir dentro de un bloque de sen- tencias o (anónimamente) dentro de una expresión. La clase Empleado tiene dos clases internas que representan una dirección y un sueldo (Fig. 6.I), El código fuen- te de la clase Empleado y sus dos clases internas D i r e c c i o n y Sueldo es: Ejemplo public class Empleado t i n t edad = 0 ; public String nombre = "Mackoy"; double tasa = 1 6 . 0 0 ; Direccion direccion; Sueldo sueldo; public Empleado (String unNombre, i n t numero, String unacalle, String unaciudad, double tasaHora, i n t horas) t
  • 162. Encapsulamiento y polimorfismo 145 nombre = unNombre; tasa = tasaHora; direccion = new Direccion (numero, unalalle, unaciudad) ; sueldo = new Sueldo (horas); I / / clase interna class Direccion i int numero = O; String calle = ""; String ciudad = ""; Direccion(int num, String unalalle, String unaciudad) I numero = nun; calle = unacalle; ciudad = unaciudad; I void visualizarDeta1 i Cystem.out.println I 1 es 0 numero+" "+calle+", "t ciudad); //clase interna class Sueldo t int horasTrabajadas = O; Sueldo (int horas) I horasTrabajadas = horas; 1 void VisualizarDetalles ( ) i 1 Cystem.out .println("Salario = "t horasTrabajadas * tasa); public static void main (String args[]) i Empleado e = new Empleado ("Mackoy", 45, "Calle Real", e.imprimirDatos ( ) ; "Cazorla", 15.25, 35); public void irnprimirDatos( ) i System.out .println("nFicha Empleado: "tnombre); direccion.visualizarDetalles(); sueldo.visualizarDetalles 0 ;
  • 163. 146 Java 2. Manual de programación El resultado de la ejecución de esta aplicación es: Ficha Empleado: Mackoy 45 Calle Real, Cazorla Salario = 533.75 Empleado Variables de instancia edad, nombre,dirección, tasa, sueldo. I 1 ; I I I I Clase interna Dirección I1 I I 1 I I Clase internaSueldo I I ¡ I 1 11"::Y 1Imprimir Datos ( ) Figura 6.1. Estructura de la clase Empleado. Las clases internas no se pueden utilizar fuera del ámbito. Por consiguiente, las clases externas de la clase Empleado no pueden acceder a la clase interna (a menos que sean subclases o estén en el mismo paquete, dependiendo de la visibili- dad en la definición de la clase). En la práctica, la clase de nivel superior actúa como un paquete de objetos que contienen cero o más clases internas. Esto es particularmente útil en desa- rrollo de software orientado a objetos. Por otra parte, la capacidad para definir un código determinado que se puede crear y pasar donde se necesite es muy importante. Sintaxis: C posee punteros a funciones. El lenguaje Smalltalk utiliza objetos que representancódigo (objetos bloque). Java posee clases internas.
  • 164. Encapsulamiento y polimorfismo 147 Ejemplo class A I int longitud; float valor; //variables durante la ejecucibn public A() //constructor de A i 1 public float leerValor0 //devuelve valor de una clase i 1 return valor; class B i public B O I 1 //definición de B //constructor de B public int leercuenta ( ) i //accede a longitud de la clase externa return 5*longitud; 1 1 / / f i n de la clase B 1 //fin de la clase A Una clase anónima es aquella que no tiene nombre y, cuando se va a crear un objeto de la misma, en lugar del nombre se coloca directamente la definición. I Regla: Estas clases se utilizan principalmenteen el manejo de sucesos. I Ejemplo Programa que permite la e!ección de una opción de un componente Choice y pre- senta en pantalla la opción seleccionada (vea los Capítulos 9 y 1O). Para el cierre de ventana, en lugar de crear la clase Cierre: class Cierre extends WindowAdapter t public void windowClosing(WindowEvent e) i } System.exit (O); 1
  • 165. 148 Java 2. Manual de programación utiliza una clase anónima; es decir, coloca, donde es necesario, directamente la defi- nición. Así, en lugar de addWindowListener(new Cierre0 ) ; se utiliza addWindowListener(new WindowAdapterO I public void windowClosing(WinciowEvenz e) i 1 1 ) ; System.exit (O); La implementación del ejemplo propuesto es: import java.awt.*; import java.awt.event.*; public class EjAnonima extends Frame implements ItemListener i private Choice selección; String elemento = " ' I ; public E]Anonima ( ) t //empleo de una clase anónima para efectuar el cierre de la ventana addWindowListener(new WindowAdapterO i public void windowClosing(WindowEvent e) i System.exit (O); } ) ; selección = new Choice ( ) ; selección.addItem ( "Windows 95" ) ; selección.addItem ( "Windows 98" ) ; selección.addItem ( "Windows NT" ) ; //Opción preseleccionada selección.select (1); selección.addItemListener(this); add (selección); I public static void main ( String args [ ] ) I
  • 166. Encapsu/arniento y poiirnorfismo 149 EjAnonima veritana = new EjAnonima() ; ventana.cetLayout(new Flow;ayqLt()); ventaiia.cetTitle ( "El AWT" ) ; ventana.cetCize( 400,150 ) ; ventana.setVisible(true); public void pair,t(Graphics g) I elemento = selección.getSelectedItem(); g.drawstring ("Elemento seieccionado "+elemento,20,i30); public void itemCtateChanged(1temEvent e) i 1 repaint ( ) ; Compilación C :libroTemaO6>J avac E] Anonima .java Ejecución C:libroTemaOG>java EjAnonima Elemento seleccionado Windows 98 Figura 6.2. Resultado de la ejecución del ejemplo de clase anónima. 6.6. PAQUETES Un paquete es una colección de clases que se compilan en una unidad de compila- ción. Los paquetes proporcionan un medio adecuado para organizar dichas clases. Se pueden poner las clases que se desarrollan en paquetes y distribuir los paquetes a otras personas, por tanto, se puede pensar en los paquetes como bibliotecas que se pueden compartir por muchos usuarios.
  • 167. 150 Java 2. Manual de programación Es posible llevar un conjunto de clases relacionadas juntas a una única unidad de compilación definiéndolas todas dentro de un archivo. Por defecto, se crea un paquete implícito (sin nombre); las clases pueden acceder a variables y métodos que sólo son visibles en el paquete actual y sólo una de las clases puede ser visible públicamente (la clase con el mismo nombre que el archivo). Un enfoque mejor sería agrupar las clases en un paquete explícito con nombre. El lenguaje Java viene con un conjunto rico de paquetes que se pueden utilizar para construir aplicaciones. Por ejemplo, el paquete j ava .io agrega las clases de entrada y salida de datos en un programa. Un paquete puede contener a otros paque- tes. Los paquetes sirven para organizar las clases en grupos para facilitar el acceso a las mismas cuando sean necesarias en un programa. La referencia a una clase de un paquete se hace utilizando un nombre completo, excepto cuando el paquete haya sido importado implícita o explícitamente. Por ejemplo java.awt .Button indica que Button es una clase del paquete awt y que awt es un paquete dentro del paquete java. Los paquetes son unidades encapsuladas que pueden poseer clases, interfaces y subpaquetes. Los paquetes son muy útiles: Permiten asociar clases relacionadas e interfaces. Resuelven conflictos de nombres que pueden producir confusión. Permiten privacidad para clases, métodos y variables que no serán visibles fuera del paquete. Se puede poner un nivel de encapsulamiento tal que sólo aquellos elementos que están concebidos para ser públicos puedan ser accedi- dos desde el exterior del paquete. 6.7. DECLARACIÓN DE UN PAQUETE Cada clase de Java pertenece a un paquete. La clase se añade al paquete cuando se coinpila. Un paquete explícito se define por la palabra reservada package en el comien- zo del archivo en el que se definen una o más clases o interfaces. Para poner una clase en un paquete específico se necesita añadir la siguiente línea como la prime- ra sentencia no comentario: package nombrepaqcete; Por ejemplo: package dibujos;
  • 168. incapsuiamiento y poiimorfismo 151 Los nombres de los paquetes deben ser Únicos para asegurar que no hay con- flictos de nombres. Java impone un convenio de nombres por el que un nombre de paquete se construye por un número de componentes separados por un punto (sepa- rador .). Estos componentes corresponden a la posición de los archivos. En el caso siguiente, los archivos del paquete package pruebac.dibujos; están en un directorio llamado dibujos dentro de un directorio llamado p r u e - bas. Por otra parte, si los archivos de un paquete específico están en un directorio llamado concurso,dentro de un directorio llamado pruebas,el nombre del paquete es package pruebas.concurso; Observe que esto supone que todos los archivos asociados con un único paque- te están en el mismo directorio. Cualquier número de archivos se puede convertir en parte de un paquete, sin embargo, un archivo sólo se puede especificar en un único paquete. Nota: Un paquetp,es una colección de clases relacionadas e interfaces que pro- porcionan protección de acceso y gestión de espacio de nombres. -1 6.8. PAQUETES INCORPORADOS Java proporciona miichos paquetes útiles: Paquete java .applet:permite la creación de upp1rt.s a traves de la clase Applet,propor- ciona interfaces pars conectar un applet a un documento Web y para audición de audio. Paquete java.awt:proporciona un Abstract Window T o o i k i t para programación CUI independiente de la plataforma, gráficos y manipulación de imágenes. Paquete j ava.io:soporta flujos de entrada y salida Java. Paquete j ava .lang:contiene clases esenciales para el lenguaje Java. - Para programación: String,Object,Math,Class,Thread,System,type Wrapper classes y los interfaces Copiable (Cloneable)y Ejecutable(Runnab1e). - Para operaciones de lenguaje: Compiler,Runtime y Sec~JrityManager. - Para errores y excepciones: Exception,Throwable y muchas otras clases. El paquete j ava .lang es el único que se importa automáticamente en cada programa Java. Paquete j ava .math:proporciona cálculos en entero grande y real grande (big,flout).
  • 169. 152 Java 2. Manual de programación Paquete j ava.net:soporta facilidades de red (URL, sockets TCP, sockets UDP, direcciones IP, Paquete lava.rmi:soporta invocación de métodos remotos para programas Java. Paquete j ava.util:contiene diversas clases de utilidad (conjuntos de bits, enumeración, con- tenedores genéricos. Vector y Hashtable,fecha, hora, separación de «token)),generación de números aleatorios, propiedades del sistema). conversión binario a texto). 6.9. ACCESO A LOS ELEMENTOS DE UN PAQUETE Existen dos medios para acceder a un elemento de un paquete: 1) nombrar total- mente ill elemento, inchyelido elpaquete, 2) utilizar sentencias import.Por ejem- plo, cuando se elige nombrar totalmente al elemento, se puede especificar la clase Panel proporcionando su definición completa 1ava.awt .Panel como ocurre en la siguiente cabecera: public abstract class Boton extends java.awt.Pane1 I Esta sentencia indica al compilador dónde buscar exactamente la definición de la clase Panel.Sin embargo, este sistema es un poco complicado para referirse a la clase Panel un número dado de veces, la alternativa es importar la clase java .awt .Panel: import java.awt.Pane1; public abstract class Boton extends Panel ( . . . Hay ocasiones en que se desea importar un número grande de elementos de otro paquete. En este caso, en lugar de colocar una larga lista de sentencias de importa- ción (import),se pueden importar todos los elementos de un paquete en una sola acción utilizando el carácter (comodín)) *. Por ejemplo: import 2 21;s.awt .* ; iiiipoitn todos los elementos del paquete java .awt al paquete actual.
  • 170. Encapsu/arnientoy poiirnorfisrno 153 6.10. IMPORTACIÓN DE PAQUETES Como se acaba de comentar, para utilizar una clase de un paquete en un programa, se puede recurrir a añadir una sentencia import en la cabecera del mismo. Por ejemplo, import rnipaquete.MiPrueba; Las declaraciones import indican ai compilador Java dónde buscar ciertas cla- ses y nombres de interfaces, de forma que, una vez importado, el nombre de la clase se puede utilizar directamente sin el prefijo del nombre del paquete. Si se tienen muchas clases para utilizar del mismo paquete, se puede emplear el caracter asterisco (*) para indicar el uso de todas las clases del paquete. Por ejemplo, import mipaquete.*; importa todas las clases del paquete mipaquete. Existen dos formatos de import 1. import paqueteDestino.UnTipo; importa la clase o interfaz 2. import paqueteDestino.*; Importa todas las clases e interfaces del paquete 6.11. CONTROL DE ACCESO A PAQUETES Java proporciona dos niveles de control de acceso: nivel de clase y nivel de paque- te. Las reglas de acceso a nivel de clase se resumen en la Figura 6.3. Figura 6.3. Control de acceso a nivel de clase.
  • 171. 154 Java 2. Manual de programación Un paquete consta de tipos (clases e inlerjuces) definidos en todos sus archivos. El acceso a nivel de paquete para un tipo es public o package. Sólo los tipos públicos son accesibles desde otros paquetes (Fig. 6.4). Por consiguiente, la colec- ción de todos los formatos de tipos públicos de las interfaces externas de un paque- te a los restantes paquetes. En otras palabras, una clase puede acceder a tipos públicos y sus miembros públicos en otro paquete. Una subclase puede también acceder a los miembros públicos y protegidos de sus superclases en otro paquete. Los códigos interiores de un paquete pueden acceder a todos los nombres de tipo y todos los métodos, campos no declarados p r i v a t e , en el mismo paquete. / Un paquete tipos públicos ~ ,/’ Tipos ‘‘‘‘-I , package ,i’ _ - / / , l-- _ - - - Figura 6.4. Control d e acceso a nivel de paquete 6.12. POLIMORFISMO Polimorfismo es una palabra que significa ((múltiplesformas))y es una de las carac- terísticas más importantes de la programación orientada a objetos. En realidad, poli- morfismo es la propiedad por la que a la misma palabra se le asignan múltiples definiciones. Existen muchas formas de polimorfismo en Java. Por ejemplo, dos clases diferentes pueden tener dos o mas métodos con el mismo nombre. En esencia, polimorfismo es la capacidad para enviar el mismo mensaje a obje- tos totalmente diferentes, cada uno de los cuales responde a ese mensaje de un modo específico. Las aptitudes polimórficas de Java se derivan de su uso como liga- dura dinámica. Además, el mismo nombre de método se puede utilizar con pará- metros diferentes y se permite que áparentemente el mismo método sea declarado un cierto número de veces dentro de la misma clase. Polimorfismo puro‘,se produce cuando una única función se puede aplicar a ar- gumentos de una variedad de tipos. En polimorfismo puro hay una función (el cuer- po del código) y un número de interpretaciones (significados diferentes). El otro ’ Éste es el término utilizado pot Timoty Budd en la segunda edición de su libro Understanding Ohject- Oriented Programming with Java, Addison-Wesley, 2000, p. 195.
  • 172. Encapsulamiento y polimorfismo 155 enfoque se produce cuando se dispone de un número de funciones diferentes (cuer- po del código) todas representadas por el mismo nombre. Esta propiedad también se conoce como sobrecarga y, en ocasiones, polimor-smo ad hoc. El polimorfismo permite a los programadores enviar el mismo mensaje a objetos de clases diferen- tes. Considérese la sentencia cuenta.calcularInteresesMensual0; donde cuenta se puede referir a un objeto Cuentacorriente o a uno CuentaAhorros. Si cuenta es un objeto de Cuentacorriente,enton- ces se ejecuta el método calcularInteresesMensua1 definido en Cuentacorriente.De igual modo, si cuenta es un objeto CuentaAhorros, entonces se ejecuta el método calcular InteresesMensual definido en CuentaAhorros. Esto quiere decir que enviando el mismo mensaje se pueden ejecutar dos métodos diferentes. El mensaje calcularInteresesMensual se denomina un mensaje polimórfico, ya que dependiendo del objeto receptor se eje- cutan métodos diferentes. El polimorfismo ayuda al programador a escribir código más fácil de modificar y ampliar. Polimor-smo es, pues, la capacidad de un objeto para responder a un mensa- je basado en su tipo y posición en la jerarquía de clases. Una respuesta apropiada implica la capacidad del objeto para elegir la implementación del método que mejor se adapte a sus características. En C++ el polimorfismo se debe diseñar en las cla- ses, mientras que en Java el polimorfismo es una característica por omisión de las clases. El término polimorfismo se utiliza para describir como objetos de clases diferentes se pueden manipular de modo diferente. Mediante técnicas polimórficas es posible escribir código que manipule objetos de muchas clases diferentes de un modo uniforme y consistente con independencia de su tipo exacto. La flexibilidad y generalidad de las estructuras polimórficas es una de las ventajas más significati- vas de la programación orientada a objetos. La estrategia para desarrollar una estructura polimórfica comienza con la identi- ficación de los métodos comunes a través de un grupo de tipos de objetos similares pero no idénticos y organizando una jerarquía de clases donde los métodos comu- nes se sitúan en la clase base, mientras que los restantes se organizan en clases deri- vadas, deducidas de esta clase base. La interfaz de la clase base define una interfaz a través de la cual un objeto de cualquiera de las subclases especificadas se puede manipular. Es importante considerar que los métodos de la interfaz compartida se deben declarar en la clase base. Un método abstracto es aquel que se declara en la clase base utilizando la pala- ra reservada abstract y termina con un punto y coma en lugar del cuerpo del método. Como ya se indicó en el capítulo anterior, una clase es abstracta si contie- ne uno o más métodos abstractos o no proporciona una implementación de un méto- do abstracto heredado. Un método se considera implementado si tiene el cuerpo de
  • 173. 156 Java 2. Manual de programación un método. Si una clase derivada no implementa todos los métodos abstractos que hereda de una clase abstracta, entonces esta clase se considera también una clase abstracta. En contraste, el término clase concreta se utiliza para referirse a una clase en la que no se definen métodos abstractos y tiene implementaciones para todos los métodos abstractos heredados. Una clase concreta representa un tipo de objeto espe- cífico, prefijado. Dado que una clase abstracta no está totalmente especificada, sus métodos abstractos están definidos pero no implementados, no es posible crear objetos de las clases abstractas. En consecuencia, si la clase Animal es una clase abstracta: public abstract class Animal I public abstract void mover 0 ; I el siguiente código no es válido: Animal = new Animal ( . . .) ; Regla: No es posible crear un objeto de una clase abstracta, pero sí es posible tener una referencia a clases bases abstractas que se refieren a un objeto de una clase concreta, derivada. 6.13. LIGADURA El término ligadura se refiere al acto de seleccionar cuál es el método que se eje- cutará en respuesta a una invocación específica. En algunos lenguajes, tales como C, la ligadura se realiza totalmente en tiempo de compilación, incluso si están impli- cados métodos sobrecargados. La ligadura que se realiza en tiempo de compilación se denomina ligadura estática ya que una vez que se establece la ligadura, ésta no cambia durante la ejecución del programa. Sin embargo, cuando la conversión de tipos (casting)y la herencia están implicadas, la ligadura no se puede hacer total- mente en tiempo de compilación ya que el cuerpo real del código que se ejecuta cuando se invoca un método puede depender de la clase real del objeto, algo que no puede ser conocido en tiempo de compilación. La ligadura dinúmica se refiere a la ligadura que se lleva a cabo en tiempo de ejecución. El caso de ligadura dinámica se produce cuando se combinan la conversión de tipos, herencia y anulación de métodos.
  • 174. Encapsulamiento y polimorfismo 157 6.14. LIGADURA DINÁMICA La ligadura dinámica se ilustra mediante los siguientes dos ejemplos, que utilizan la jerarquía de clases. public c l a s s Base t public void operacion ( ) public c l a s s Derivadal extends Base i / / no se ancla el método operacion 1 public c l a s s Derivada2 extends Base public void operacion ( ) En esta jerarquía de clases, se derivan dos clases de la misma clase base. La clase Base y la clase Derivada2 contienen una definición de un método llama- do operación.La clase Derivadal no anula la definición de operacion.El siguiente segmento de código ilustra la propiedad de ligadura dinámica. Derivadal primero = new Derivadal ( . . .) ; Derivada2 segundo = new Derivada2 ( . . .) ; Base generica; generica = (Base) primero; generica.operacion0; generica = (Base) segundo; generica.operacion0; En la primera invocación de operacion el objeto real es de la clase Derivadal.Ya que la clase Derivadal no anula el método operacion,la invocación producirá la ejecución del método operacion de la clase Base.En la segunda invocación de operacion el objeto real es de la clase Derivada2 que anula el método operacion definido en Base.La pregunta que podemos hacer es: jcuál de los dos métodos operaciorise invoca? Es decir, en el caso del método anulado (sustituido) operación,cual de los dos métodos se ejecuta bajo las diferentes condiciones que implica conversión de tipos. En Java, la ligadura dinámica ejecuta siempre un método basado en el tipo real del objeto. Por consi- guiente, en el segmento de código anterior la segunda invocación del método ope- ración se enlaza al método operación de la clase Derivada2.Ya que el tipo real del objeto puede no ser conocido hasta el tiempo de ejecución, la ligadura se
  • 175. 158 Java 2. Manual de programación conoce como dinámica para diferenciarlo de las ligaduras que pueden determinarse en tiempo de compilación. Por ejemplo, considere las clases siguientes: public c l a s s Automovil I public void conducir ( ) I System.out.println("Conducir un automóvil") ; 1 I public c l a s s Carro extends Automovil i public void conducir ( ) i 1 System.out.println("Conducir un carro"); Estas dos clases se pueden utilizar en otra clase: public c l a s s Ejemplo i public s t a t i c void main (String argc [ ] ) ( Automovil a = new Automovil ( ) ; Carro c = new Carro(); a.conducir ( ) ; c.conducir ( ) ; a = c; a.conducir ( ) ; 1 I Compilación C:libroTemaGG>javac Automovil.java C:libroTemaGG>javac Carro.java C:libroTemaGG>javac Ejemplo.java Cuando se ejecuta esta aplicación, la versión conducir se define en la clase Carro dos veces, mientras que la versión de la superclase se llama sólo una vez. Así, la ejecución producirá: C:libroTemaGG>java Ejemplo Conducir un automóvil Conducir un carro Conducir un carro
  • 176. Encapsu/amienío y po/imorfismo 159 La variable a se declaró de tipo Automovi1.Cuando se asignó a la instancia de Carro y se recibió el mensaje conducir,se responde con la versión conducir de Carro,que se eligió en tiempo de ejecución. La ligadura dinámica o posterga- da se refiere, pues, al modo en el que Java decide cuál es el método que debe eje- cutarse. En lugar de determinar el método en tiempo de compilación (como sucede en un lenguaje procedimental), se determina en tiempo de ejecución. Es decir, se busca cuál es la clase del objeto que ha recibido el mensaje y entonces decide cuál es el método que se ejecuta. Ya que esta decisión se realiza en tiempo de ejecución, se consume un tiempo de ejecución suplementario, pero, por el contrario, presenta flexibilidad. Cuando Java selecciona un método en respuesta a un mensaje, lo hace utilizando tres cosas: La clase del objeto receptor. El nombre del método. El tipo y orden de los parámetros. Es decir, se pueden definir varios métodos en la misma con el mismo nombre pero con parámetros diferentes. El sistema selecciona el método que desea llamar en tiempo de ejecución examinando los parámetros. public class Golf extends Automovil i public void cargar(int i) i i System.out .println("Cargando datos "+ i); public void cargar (String s ) I 1 System.out .println("Cargando cadenas "+ s ) ; La clase Golf tiene dos métodos denominados cargar,cada uno con un pará- metro de tipo diferente. Este código significa que Java puede diferenciar entre los dos métodos y no se producen conflictos.
  • 177. A 7 Arrays CONTENIDO 7.1. Concepto de array. 7.2. Proceso de arrays. 7.3. Arrays de objetos. 7.4. Copia de arrays. 7.5. Arrays muItidimensionales. 7.6. Ordenación de arrays. 7.7. Selección. 7.8. Burbuja. 7.9. Inserción. 7.10. Shell. 7.11. Ordenación rápida. 7.12. Búsqueda. 7.13. Implementación genérica de los métodos de ordenación. 161
  • 178. 162 Java 2.Manual de programación 7.1. En capítulos anteriores se han utilizado variables para hacer los programas más flexibles. Gracias a las variables se pueden alma- cenar, convenientemente, datos en los programas y recuperarlos por su nombre.Se pueden también obtener entradasdel usuario del programa. Las variables pueden cambiar constantemente su valor. Sin embargo, en algunos casos se han de almacenar un gran número de valores en memoria durante la ejecución de un progra- ma. Por ejemplo, suponga que desea ordenar un grupo de núme- ros,éstos se deben almacenaren memoriaya que se han de utilizar posteriormente para comparar cada número con los restantes. Almacenar los números requiere declarar variables en el programa y es prácticamente imposible declarar variables para miembros individuales,se necesita un enfoque organizado y eficiente. Todos los lenguajes de programación, incluyendo Java, propor- cionan una estructura de datos, array (<matriz,vector,,) capaz de almacenar una colección de datos del mismo tipo. Java trata estos arrays como objetos. CONCEPTO DE ARRAY Un army (((matriz,vector, lista))) es un tipo especial de objeto compuesto por una colección de elementos del mismo tipo de datos que se almacenan consecutiva- mente en memoria. I,a Figura 7.1 es un array de 10 elementos de tipo double y se representa por un nombre, 1i sta, con índices o subíndices. lista [O] lista [l] lista [ Z ] lista [3] lista [4] lista [51 lista [6] lista [71 lista [81 lista [91 I I lista -nombre [ i ] -índice F Figura 7.1. El array lista de 10 elementos, con índices de O a 9.
  • 179. Arrays 163 Otra forma de representar gráficamente un array es en forma de lista horizontal. lista [ O ] lista [l] lista [ 2 ] lista [31 lista [4] . . . Figura 7.2. Array lista de 10 elementos. Los arrays pueden ser unidimensionales (Figs. 7.1 y 7.2), conocidos también como listas o vectores, y multidimensionales, conocidos también como tablas o matrices, que pueden tener dos o más dimensiones. Ejemplo El array temperaturas de ocho elementos consta de los siguientes componentes: temperaturas temperaturas temperaturas temperaturas temperaturas temperaturas temperaturas temperaturas Regla: Un array tiene un nombre o identificador, un índice que es un entero encerradoentre corchetes,un tamaño o longitud,que es Úmerode elemen- tos que se pueden almacenaren el array cuando se le asignaespacioen memo- ria. Un array se representa por una variable array y se debe declarar, crear, iniciar y utilizar. 7.2. PROCESO DE ARRAYS El proceso que se puede realizar con arrays abarca las siguientes operaciones: declaración, creación, inicialización y utilización. Las operaciones de declaración, creación e inicialización son necesarias para poder utilizar un array.
  • 180. 164 Java 2. Manual de programación 7.2.1. Declaración La declaración de un array es la operación mediante la cual se define su nombre con un identificador válido y el tipo de los elementos del array. La sintaxis para decla- rar un array puede adoptar dos formatos: tipoDato [ 1 nombreArray zipo3ato nombreArray[] Ejemplo double [ j miLista; double miLista[]; } Se declara un array rrilista de tipo double f l o a t temperatura[j; f l o a t [ ] temperatura; } Se declara un array temperatura de tipo float Las declaraciones no especifican el tamaño del array que se especificará cuando se cree el mismo. 7.2.2. Creación Un array Java es un objeto y la declaración no asigna espacio en memoria para el array. No se pueden asignar elementos al array a menos que el array esté ya creado. Después que se ha declarado un array se puede utilizar el operador new para crear el array con la sintaxis siguiente: nombreArray = new tipoDato [ tarnafio]; nombreArray es el nombre del array declarado previamente, tipoDa to es el tipo de dato de los elementos del array y tamaño es la longitud o tamaño del array y es una expresión entera cuyo valor es el número de elementos del array. Ejemplo miLista = new double [8!; / / array miLista de 8 elementos temperatura = new float 1301; / / array temperatura de 30 elementos Consejo: El formato más conveniente es tipoDato[ ] nornbreArray. El forma- to tipoDato nornbreArray[ ] se suele utilizar si se desea seguir el estilo de escritura C/C++.
  • 181. Arrays 165 Regla: Se pueden combinar la declaración y la creación de un array con una sola sentencia. tipoDa to[ ] nombreArray = new tipoDa to[ tamaño]; tipoDato nombreArray[] = new tipoDa t o [ tamaño]; - Ejemplo double;] miLicta = new aoub;e[8]; float temperaturalj = new float.3CI; Precaución: Una vez que un array se ha creado su tamaño no se puede modi- ficar. 7.2.3. Inicialización y utilización Cuando se crea un array, a los elementos se les asigna por defecto el valor cero para las variables numéricas de tipos de datos primitivos, ’uO O O para variables de tipo carácter, char,false para variables lógicas, boolean, y null para varia- bles objetos. A los elementos del array se accede a través del índice. Los índices del array están en el rango de O a tamaño-l.Así, miLista contiene 8 elementos y sus índices son O , 1,2 , . . .,7. Cada elemento del array se representa con la siguiente sintaxis: nombreArray[índice]; Ejemplo milista [ 7 ; representa el último elemento del array Regla: En Java, un índice del array es siempre un entero que comienza en cero y termina en tamaño-i. Precaución: Al contrario que en otros lenguajes de programación, los índices siempre se encierran entre corchetes: temperaturas [is];
  • 182. 166 Java 2.Manual de programación Un array completo se puede inicializar con una sintaxis similar a double[] miLista = { 1.5, 2.45, 3.15, 7.25, 8.4 } ; esta sentencia crea el array miLista que consta de cinco elementos. Cálculo del tamaño El tamaño de un array se obtiene con una variable instancia length.Así, por ejem- plo, si se crea un array milista,la sentencia miLista.length devuelve el tamaño del array miLista (10, por ejemplo). Utilización de los elementos del array Las variables que reperesentan elementos de un array se utilizan de igual forma que cualquier otra variable. Por ejemplo: int[l = new int[50]; int 1 = O, j = O; / / . . . j = n[l] + n[10]; Algunas sentencias permitidas en Java: 1. temperatura[5] = 45; temperatura [8] = temperatura [5] + 10; System.out.println(temperatura[8]); 2. int punto = 5; temperatura [punto+31 = 55; System.out .println("La temperatura 8 es 'I + temperatura[punto+3] ) ; 3. System.out.print1n ("La segunda entrada es 'I + entrada[2]); Reglas: temperatura í n+3 I = 45; valor de la variable de índice índicei - (elementodel array) + nombredel array
  • 183. Arrays 167 Se pueden procesar elementos de un array mediante bucles (por ejemplo, f o r ) por las siguientes razones: Todos los elementos del array son del mismo tipo y tienen las mismas propie- dades; por esta razón, se procesan de igual forma y repetidamente' utilizando un bucle. El tamaño de un array se conoce, por lo que el bucle mas idóneo es f o r . Ejemplo 1. El bucle for siguiente introduce valores en los elementos del array. El tama- ño del array se obtiene en milista.length. for (int i = O; i < miLista.iength; i + + ) miLista[il = (double) i; 2.int[l cuenta = new ~ ~ ~ [ I o c I ; int i; for (1 = O; i < cuenta.length; i++) a[i] = O; 7.3. ARRAYS DE OBJETOS Los ejemplos anteriores han creado arrays de elementos de tipos primitivos. Es posible también crear arrays de cualquier tipo de objeto, aunque el proceso es un poco más complicado. Por ejemplo, la siguiente sentencia declara un array de 10 objetos Circulo ( C i r c u l o es una clase definida previamente): Circulo [ ] arraycirculo = new Circulo [ IO]; El array de objetos se inicializa de modo similar a un array ordinario: for (int i = O; i < arrayCirculo.1ength; i+t) arraycirculo [i] = new Circulo ( ) ; Representacióngráfica Crear un array de objetos Persona (clase Persona). Persona[] p = new PersonaL51;
  • 184. 168 Java 2.Manual de programación 2 def:ne LX array de obletos de tipo Persona , q u e puede conrener 5 o~:etos Se crea UII array de oojetos 1 Persoza ~ I new Persona ( ) 1 i Se neceSAta crear los ob-etos de. array .- - - A Figura 7.3. Creación de un array de objetos. 1 Persona Figura 7.4. Estructura completa del array. Crear un array de 50 objetos pertenecientes a la clase Racional. La clase Racional representa los números racionales. Un número racional es un número con un numerador y un denominador de la forma n/d;por ejemplo, 1/ 5,2/ 7 y 3/ 4. Un número racional no puede tener un denominador de valor O. Los enteros son equivalentes a números racionales de denominador 1, es decir, n/l.El siguiente programa crea un arrayRaciona1,que se compone de 50 objetos Racional,lo inicializa con valores aleatorios y a continuación invoca al método suma ( ) para sumar todos los números racionales de la lista. public class PruebaArrayDeObjetos public s t a t i c void main (String[] args) / / crear e inicializar arrayRaciona1
  • 185. Arrays 169 Racional [ ] arrayRaciona1 = new Racional [ 501 ; //inicializar arrayRaciona1 System.out.println("Los números racionales son " ) ; for ( i n t i = O; i < arrayRacional.length; it+) i arrayRaciona1 [ i] = new Racional ( ( i n t ) (Math.random ( ) *50), System.out.print (arrayRacional[i]+" " ) ; l + ( i n t )(Math.random()*lO)); } System.out.println ( " " ) ; / / calcular y visualizar el resultado System.out .println("La suma de los números racionales es "+ suma (arrayRaciona1)) ; 1 public s t a t i c Racional suma(Racional[] arrayRaciona1) t Racional suma = new Racional (O,1); for ( i n t i = O; i < arrayRacional.length; i++) return suma; suma = sama.add (arrayRaciona1[ i] ) ; Observaciones 1. El programa crea un array de 50 objetos Racional y pasa el array al méto- do suma ( ) ,que suma todos los números racionales del array y devuelve su suma. 2. Los números racionales se generan aleatoriamente utilizando el método Math.random ( ) . 3.Precaución. Se ha de evitar un denominador O; para ello se puede añadir al denominador un 1. 7.4. COPIA DE ARRAYS Con frecuencia se necesita duplicar un array o bien una parte de un array. Existen dos métodos para copiar arrays: copiar elementos individuales utilizando un bucle y utilizar el método arraycopy. Método 1 Un método para copiar arrays es escribir un bucle que copia cada elemento desde el array origen al elemento correspondiente del array destino.
  • 186. 170 Java 2. Manual de programación Ejemplo El siguiente código copia arrayFuente en arrayDestino: for (int i = O; i < arrayFuente.lengtn; l i t ) arrayDectino[il = arrayFuente[i]; Este método plantea problemas si los elementos del array son objetos. Método 2 Los inconvenientes anteriores se resuelven usando el método Syctern. array- copy ( ) que copia arrays en lugar de utilizar un bucle y que tiene el siguiente for- mato: public static void arraycopy(java.iang.0bject a r r a y r u e n t e , int pos-in;, lava.lang.0bject arrayCesti,?o, int p o s - f i n , int l e n g t h ) , . La sintaxis del método arraycopy ( ) es: arraycopy (arrayFuente, pos-ini, arrayDest.ino, 90s-f:I-., l o n g i t , ~ d ); intl] arrayFuente = {4, 5, 1, 25, iC0); int[l arrayDestiro = new int[arrayFuente.length]; Syctern.arraycopy(arrayFuente, 0, arrayDectino, 3, arrayFuente.length); ~ ~ ~ Notas: 1. El método arraycopy ( ) puede copiar cualquier tipo (tipo primitivo o tipo Ob] ect) de elementos del array. 2. En Java, se pueden copiar tipos de datos primitivos utilizando sentencias de asignación, pero no objetos ni arrays completos. La asignación de un obje- to a otro objeto hace que ambos objetos apunten a la misma posición de memoria.
  • 187. Arrays 171 7.5. ARRAYS MULTIDIMENSIONALES Las tablas o matrices se representan mediante arrays bidimensionales. Un array hidimensional en Java se declara como un array de objetos array. tipo nombre [ ] [ 3 ; Las tablas de valores constan de información dispuesta enfilas y columnas. Para identificar un elemento de una tabla concreta se deben especificar los dos subíndi- ces (por convenio, el primero identifica la fila del elemento y el segundo identifica la columna del elemento). o 1 2 3 4 5 (a)Array de una dimensión (b)Array bidimensional Figura 7.5. Arrays: (a) Una dimensión; (b) Dos dimensiones (bidimensional). La Figura 7.6 ilustra un array de doble subíndice, a, que contiene tres filas y cua- tro columnas (un array de 3 x 4). Un array con rn filas y n columnas se denomina arra-t’ mgor-n. ColumnaO Columna 1 Columna2 Columna3 -+ Subíndice columna -* Nombre del array -- ---- Subíndice fila -~_ _ _ ~ Figura 7.6. Un array de dos dimensiones con tres filas y cuatro columnas.
  • 188. 172 Java 2. Manual de programación Cada elemento del array a se identifica como tal elemento mediante el formato a [ i 3 I.j] ; a es el nombre del array, e i,j son los subíndices que identifican uní- vocamente la fila y la columna de cada elemento de a, observése que todos los ele- mentos de la primera fila comienzan por un primer subíndice de O y los de la columna cuarta tienen un segundo subíndice de 3 (4-1). 7.5.1. Declaración de arrays multidimensionales Los arrays multidimensionales se declaran de la misma forma que los bidimensio- nales, es decir, con un par de corchetes para cada dimensión del array. t i p o nombre [ I [I [ I . . .; Ejemplo 1. Un array b de 2x2 dimensiones se puede declarar e inicializar con: 2. La declaración crea un array de dos filas y tres columnas, en el que la primera fila contiene 4,5,6. Los arrays con múltiples subíndices con el mismo número de columnas en cada fila se pueden asignar dinámicamente. Por ejemplo, un array de 3x3 se asigna como sigue: int b[l [I; b = new int[3][3]; Los arrays con subíndices múltiples en los que cada fila contiene un número diferente de columnas se pueden asignar dinámicamente, como sigue:
  • 189. int b [ ][ ; ; b = new int[3][ j ; //asigna filas b[O] = new int[5]; //asigna 5 columnas a la f;la O b [ l ] = new int[4]; //asigna 4 columnas a :a fila 1 b [ 2 ] = new int[3]; //asigna 3 columnas a ;a fila 2 La expresión b .length devuelve el número de filas del array, mientras b [ 1] .length devuelve el número de columnas de la fila 1 del array. Ejemplo Declarar y crear una matriz de 5x5 intr; [I ma:riz = new int[5][ 5 1 ; O bien int matriz[] [I = new int[5:[5]; Se puede utilizar también una notación abreviada para declarar e inicializar un array de dos dimensiones: int[][I matriz = I I La asignación de valores a un elemento específico se puede hacer con sentencias similares a: matriz[2] [O] = 3; Un medio rápido para inicializar un array de dos dimensiones es utilizar bucles f o r : tabla[x] [ y ] = 5; 1
  • 190. 174 Java 2. Manual de programación Los hiicles crnidudos funcionan del modo siguiente. El bucle externo, el bucle x, arranca estableciendo x a O. Como el cuerpo del bucle x es otro bucle, a continua- ción arranca dicho bucle interior, bucle y, fijando y a O . Todo esto lleva al progra- ma a la línea que inicializa el elemento del array t a b l a [ O ] [ O ] al valor 5. A continuación el bucle interior establece y a 1,y con ello t a b l a [ O I [ 1] toma el valor 5. Cuando termina el bucle interno el programa bifurca de nuevo al bucle externo y establece x a 1.El bucle interno se repite de nuevo, pero esta vez con x igual a 1,y tomando y valores que van de O a 2. Por Último, cuando ambos bucles terminan el array completo se habrá inicializado. Ejemplo 1. Inicialización de los elementos del array. O OO 1 4 2 ' 8 3 12 ~~ t 1 2 3 5 ~ 6 -1 7 1 13 14 15 ~~ 1 1 2 3 9 10 1' 1 Tras crear y declarar el array t a b l a i n t ¿ a b - a r ; [ = new i n t [ ? 131; El listado siguiente inicializa el array: f o r ( i n t x = 9; x < 3 ; I-x) f o r ( i n t y = C ; y < 3; i + y ) :auls[x] :y1 xx4 + y ; 2. Declarar. crear e inicializar un array de 8 filas y 10 columnas con 80 enteros de ~ a l o rcero i n t ?uneras I I 1 ; / / d e c l a r a r e l a r r a y -,uneras = new i n t [ 8 1 :lo]; / / c r e a r e l a r r a y e n memoria f o r ( i n t x = 3; x < 8 ; t + x ) rirrercc[xI [y1 = U; f o r ( i n t y = C; y < 13; - + y ) Normalmente, la asignación de valores a arrays bidimensionales se realiza median- te bucles anidados, por ejemplo anidando bucles f o r . Es decir que, supuesto un array a de dos dimensimes, mediante dos bucles f o r , uno externo y otro interno, es posible leer y asignar valores a cada uno de los elementos del array. El recorrido de
  • 191. un array, por ejemplo para mostrar la información almacenada en él, también se rea- liza utilizando bucles for anidados, ya que los bucles facilitan la manipulación de cada uno de los elementos de un array. Como se comentó con anterioridad, dado un array, denominado por ejemplo a, la expresión a . length determina su número de filas y, si se usa una estructura for con una variable de control, i, que recorra dichas filas a [ i ].length devolverá el número de columnas en cada fila. Ejemplo 1 . La siguiente estructura declara, crea, inicializa y muestra el contenido del array a, en el que cada fila contiene un número diferente de columnas: int a[] [ I ; a = new int[3] [I; //as:gna filas a [ O ] = new int[5:; //asigna 5 r o l u i . r a s a la fila C a [ l ; = new int[7]; //asigna 7 cclxLzac a la fils 1 a[21 = new int[3]; //asigna 3 columnas a ICfila 2 f o r (int 1 = O; < a.length; i+-) f o r (int j = 3; J < a[:] .length; j++> a[:] [j] = j + 1; / / presexta por consola el conteniac =el array f o r (int I = C; i < a.lengt;i; ;++) t f o r (int j = 3; 7 < a!:] . l e n g t h ; j-+) System.out.orintln0; Cyctem.out.print(o[i] [j:-" " 1 ; 1 2. Declarar, crear e inicializar un array de 8 filas y 10 columnas con 80 enteros de valor cero. int numeroc [ j 1 1 ; numeroc = new int;8][ l o ; ; f o r (int x = 3; x < numeros.length; + + X I f o r (int y = 3; y < numeroc[x;.length; ++y) nunieroc[x] [y] = 3; Ejercicio (aplicación) La siguiente aplicación crea e inicializa un array de dos dimensiones con 10 colum- nas y 15 filas. A continuación presenta en pantalla el contenido del array. public class Tabla1
  • 192. 176 Java 2. Manual de programación s t a t i c i n t tabla [ 3 [I ; s t a t i c void llenar ( ) tabla = new i n t [ l 5 1 [lo]; f o r ( i n t x = O ; x < 15; x++) f o r ( i n t y = O ; y < 10; y++) tabla[x][y] = x * 10 t y; s t a t i c void mostrar 0 f o r ( i n t x = O ; x < 15; x++) I f o r ( i n t y = O ; y < 10; y++) System.out.println0; System.out.print (tabla[x][y]+"t"); public s t a t i c void main (String[] args) llenar ( ) ; mostrar ( ) ; Ejercicio (applet) El AppletTablal,se comporta de forma similar a la aplicación anterior, también crea e inicializa un array de dos dimensiones con 1O columnas y 15 filas.A continua- ción imprime el contenido del array en el área de visualización del upplet, de modo que se puede ver que el array contiene realmente los valores a los que se ha inicializado. package libro.Tema07; import java.awt.*; import java.applet.*; public class AppletTablal extends Applet t i n t tabla [ ] [ ] ; public void init ( ) tabla = new i n t [ l 5 1 [ i o ] ; f o r ( i n t x = O ; x < 15; x++) f o r ( i n t y = O ; y < 10; y++) tabla[x][y] = x * 10 + y; 1 public void paint (Graphics g) f o r ( i n t x = 3 ; x < 15; xt+)
  • 193. for (int y = O; y < 10; y++) i String c = String.valueOf (tabla[XI[y]) ; g.drawString(s, 50+y*25, 50+x*15); I Para ejecutar el applet (vea el Capítulo 11, ((Appletw), será necesario: 1. Su compilación Mediante una instrucción como la siguiente: C:libroTema07>]avac AppletTabla1.java cuando se trabaja con eljdkl.3 Usando el modificador target durante la compilación para generar un archivo class específico para una determinada máquina virtual, ya que no siempre es seguro que el navegador utilizado para ejecutar el código HTML con la marca APPLET soporte todas las características incorporadas a la versión del JDK con la que el applet ha sido compilado. Así, con eljdkl.4se emplea C:libroTema07>javac -target 1.1 AppletTablal.java con la finalidad de que el applet pueda ser ejecutado por los navegadores (browsers)habituales. Otra forma más adecuada para que un applet complilado en la versión 1.4 del jdk pueda ser ejecutado por los browsers habituales consiste en utilizar Plug-in (veáse el Apéndice F, ((Contenido del CDD) 2. Crear un archivo A t 1.h t m l con el siguiente contenido: Archivo HTML (Atl.html) <HTML> <APPLET WIDTH=350 HEIGHT=300 code=libro.Tema07.AppletTablal.class> </APPLES> </FITML> Al abrir la página, usando por ejemplo Microsoft Internet Explorer, el applct se carga y ejecuta automáticamente. La salida obtenida se muestra en la Figura 7.7.
  • 194. 178 Java 2. Manual de programación O 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 Figura 7.7. Ejecución del applet en Microsoft Internet Explorer 7.6. ORDENACIÓN DE ARRAYS La clasificación de datos es una de las operaciones más usuales en programación y podrá considerarse de dos tipos: Interna, es decir, con los datos almacenados en memoria. Externa, con la mayor parte de los datos situados en un dispositivo de almace- namiento externo. Dentro de la ordenación interna habría que considerar la ordenación tanto de arrays como de listas(vea el capítulo sobre estructuras de datos), pero para explicar los métodos de ordenación se estudiará exclusivamente la ordencrcidnde arrays. Además, los métodos de ordenación interna se aplicarán a arrays unidimensionales, aunque su uso puede extenderse a otro tipo de arrays, bidimensionales, tridimensionales, etc., considerando el proceso de ordenación con respecto a filas, columnas, páginas, etc. El concepto de ordenación se puede definir de la siguiente hrma: dado un array unidimensional X y dos índices i y j que permiten recorrerlo, se dirá que está orde- nado ascendentemente si para todo i < j se cumple siempre que X [ i ] <= X [ j] . El array estará ordenado en orden descendente si cuando i < j se cumple siempre, para todos sus elementos, que X [ i I >= X [ jI . Los métodos de clasificación interna más usuales son: Selección, Burbuja, Inserción, Inserción binaria, Shell, Ordenación rúpida (Quick Sort).
  • 195. Arrays 179 7.7. SELECCI~N El algoritmo de ordenación por selección de un array con n elementos tiene los siguientes pasos: 1. Encontrar el elemento menor del array. 2. Intercambiar el elemento menor con el elemento de subíndice 1. 3. A continuación, buscar el elemento menor en la sublista de subíndices 2 . .n, e intercambiarlo con el elemento de subíndice 2. Situándose, por tanto, el segundo elemento menor en la posición 2. 4. Después, buscar el elemento menor en la sublista 3 . .n, y así sucesivamente. Por ejemplo, dada la siguiente lista 7 4 8 1 1 2 . Se compara a [ i ] con los siguientes elementos: -7 4 8 1 12 -4 I 8 1 12 -4 7 8 12 -1 I 8 4 12 con lo que el elemento menor queda seleccionado en a [ i ] Se compara a [ 2j con los siguientes elementos: -7 8 4 12 -I 8 4 12 -4 8 7 12 con los que el elemento menor queda.seleccionado en a [ 2 ] . Se compara el elemento a 13] con los siguientes: -8 7 i2 -7 8 12 con lo que el elemento menor queda en a[3]. Se compara el elemento a[4] con los siguientes: -8 1 2 con lo que el array quedaría 1 4 l a 12. También se podría buscar el elemento mayor y efectuar la clasificación en orden descendente. Codificación p u b l i c class Pruebas p u b l i c s t a t i c void main (String[ 1 args) r i n t a[]= {7,4,8,1,12}; i n t menor; f o r ( i n t i = O; i < a.length-1; I++) I menor = 1; for ( i n t j = i + l ; 1 < a.lergth; j++)
  • 196. 180 Java 2. Manual de programación if (a[:] < a[rnenorJ) menor = 7; i n t auxi = a[iJ; a;iJ=a[menor]; a [menor]=auxi; 1 / / Presentación de los resultados f o r ( i n t i = O ; i < 5; i++) Cystem.out.println(a[i]); 1 7.8. BURBUJA La ordenación por burbuja (buble sort) se basa en comparar elementos adyacentes del array e intercambiar sus valores si están desordenados. De este modo se dice que los valores más pequeños burbujean hacia la parte superior de la lista (hacia el pri- mer elemento), mientras que los valores más grandes se hunden hacia el fondo de la lista. Si se parte de la misma lista que en el método anterior, 7 4 8 1 12: 7 4 8 1 12 4 7- a 1 12 4 7 8- 1 12 4 7 i 8- 12 4- I 1 8 -12 4 7- 1 8 4 1 7- 8 4- 1 7 -8 1 4- 7 quedando el 7 en tercera posición: 1- 4 - quedando el cuatro en la segunda posición: quedando el 12 al final de la lista: quedando el 8 en penúltima posición: 7 1 -4- con lo que la lista resultante sería 1 4 7 8 12. Codificación public c l a s s PruebaB t public s t a t i c void main (String[ ] args) i n t a[;= {7,4,8,1,12}; f o r ( i n t i = 1; 1 < a.length; i++)
  • 197. Arrays 181 f o r ( i n t j = O; j < a.length-i; j++) i f (a[j+il < a[jl) t i n t auxi = a[jI ; a[j] = a[j+l]; a[j+l] = auxi; / / Presentación de los resultados f o r ( i n t i = O; i < 5; I++) System.out .println(a[i]) ; I Una optimización del método anterior que aprovecha posibles ordenaciones ini- ciales en el array es: public c l a s s PruebaBOp t public s t a t i c void main (String[ ] args) I i n t a[] = {7,4,8,1,12}; i n t i = 1; boolean ordenado; do i ordenado = true; f o r ( i n t j = O; j < a.length-i; j++) if (a[j+ll < a[jl) t ordenado = false; i n t auxi = a[jl; a[jl = a[j+ll; a[j+l] = auxi; 1 i++; 1 while (ordenado == false); / / Presentación de los resultados for (i = O; i < 5; i++) System.out.println(a[i] ) ; 7.9. INSERCI~N El método está basado en la técnica utilizada por los jugadores de cartas para clasi- ficar sus cartas, donde eljugador va colocando, insertando cada carta en su posición correcta. Por tanto, el método se basa en considerar una parte del array ya ordena-
  • 198. 182 Java 2. Manual de programación do y situar cada uno de los elementos restantes en el lugar que le corresponda por su valor. Inicialmente la parte ordenada consta de un Único elemento, ya que un único elemento que se podrá considerar siempre ordenado. El lugar de inserción se puede averiguar mediante búsqueda secuencia1 en la parte del array ya ordenada, método de inserción directa, o efectuando una búsqueda bina- ria (la búsqueda binaria se comentará más adelante en este mismo capítulo), con lo que el método pasará a denominarse de ordenación por inserción binaria. Los elementos de la lista, 7 , 4 , 8 , 1, 1 2 , van tomando los siguientes valores: 7.4 8 1 12 seguarda en a u x i a [ i , , s e c o m p a r a a u x i con a[Gl y, como a [ O ] es mayor, se desplaza hasta a [ 1] y en a [ C ] se pone a u x i -1 4 ' a u x i ~ 4 7 8 1 12 no hay desplazamiento. pues a u x i (donde se ha guardado a [2])es mayor que a [ 11 --,8 a u x i I__. 4 7 8,.1 12 s e g u a r d a e n a u x i c o n a i 3 1 ysecomparacona[21 Hay desplazamiento de a [ 2 ] a a [ 3 I ',-1 1 a u x i L A 4 7,+ 8 8 12 e compara a u x l con a [ 1] y. como e mayor a .1 ] que a u x i , hay deiplazamiento de a L 11 a a [ 2 I -1 4,-7 8 12 e compara a u x i con a : O 1 . Se deplaza a [OI a a [ 11 4 4 7 8 12 s e c o l o c a e l l e n a [ O ] 1 4 7 8 12 a [ 4 ] se guarda en a u x i , se compara con a [ 3 ] y no hay desplazamientos. Codificación / / i n s e r c i ó n direcEa public c l a s s P r u e b a I D public s t a t i c void mair. ( S t r i n g [ 3 a r g s ) I i n t a [ ] = {7,4,8,1,12!; i n t i , j , a u x i ; boolean e n c o n t r a d o s i t i o ; for (i = 1; i < a . l e n g t h ; i+i)
  • 199. Arrays 183 auxi = a[i:; er.contradositio = false; while ( 2 >= C & & !eccontradositio) j = 1-1; if (a[]] > a.Jxi) else encontrados:tio = t r ü e ; a [ j+1]= a u x i ; i / / Prese-tarióc de los resultados for (i = O; i < 5; it+) Systen.out.pr;ntln(a[i]); I 7.10. Shell Este método se basa en realizar comparaciones entre elementos no consecutivos, separados por saltos o intervalos mayores que 1. Estos saltos sufrirán sucesivos decrementos. Es un método elaborado que resulta más eficiente cuando las listas son grandes. Considere el siguiente array: 6 1 4 7 2 (5 elementos). En una primera pasa- da, las comparaciones se realizarán entre elementos separados por un intervalo de 5/2. El primer intercambio se produce entre a [ O 1 y a [ 2 ] y luego entre a [ 2 ] y a [ 4] . Puesto que ha habido intercambio entre a [ 21 y a [ 4 I hay que comprobar que dicho intercambio no ha estropeado la ordenación efectuada anteriormente, por tanto, se retrocede y se comparan de nuevo a [ O ] con a [ 2 3 . Como resultado se obtendrá ahora 2 1 4 7 6. Los elementos a [ O ] , a [ 2 ] y a [ 4 ] se encuentran ahora ordenados y por otra parte también a [ 1] y a [ 3 3 . Se repite el proceso con salto o intervalo la mitad del anterior.
  • 200. 184 Java 2.Manual de programación Como hay intercambio entre a [ 3] y a [ 4] se retrocede para comprobar que no se ha estropeado la orde- nación entre a [ 2 3 y a [ 3] y como esté bien no se retrocede más. 1 1 2 ! 4 ; 6 ( 7 ( Resultado final El proceso termina, pues se han comparado todos los elementos con un salto o intervalo de uno y el salto ya no puede ser menor. Codificación public c l a s s PruebaCh public s t a t i c void main (String[ ] args) i i n t a[] = (7,4,8,1,12}; i n t i, j, k , salto; salto = a.length / 2; while (salto > O) t for (i = salto; i < a.length; i++) i j = i - salto; while ( j >= O) i k = j t salto; i f ( a [ j ] <= a[kl) else I j = -1; i n t auxi = a[jl; a[jl = a[kl; a[k] = auxi; j -= salto; } salto /= 2; 1 / / Presentación de los resultados for (i = O; i < 5; i++) Cystem.out.println(a[il) ; ! !
  • 201. Arrays 185 7.11. ORDENACI~NRÁPIDA El método consiste en: Dividir el array en dos particiones, una con todos los elementos menores a un cierto valor específico y otra con todos los mayores que él. Dicho valor es uno cualquiera, tomado arbitrariamente, del vector, y recibe la denominación de pivote. Tratar, análogamente a como se expuso en el primer apartado cada una de las particiones, lo que conduce a un algoritmo recursivo. Codificación public class PruebaQS i public static void quicksort (int a [I, int iz, int de) ( int i = iz; int J = de; int pivote = a [ (iz+de)/2]; do i while(a[i] < pivote) {i++;1 whiie(a[j] > pivote) {I--;1 if (i <= j) i int auxi = a[il; a[i] = a[j]; a [ j ] = auxi; i++; j--; 1 1 while (i <= j); if (j > iz) {quickSort(a, iz, j);} if (1 < de) {quickCort(a, i, d e ) ; } 1 public static void main (String[ ] args) t int[] a = {6,1,4,7,2,5,3}; quicksort (a, O, a.length-1); for (int i = O; i < a.length; i++) Systen.out.println(a[i]) ; !
  • 202. 186 Java 2. Manual de programación 7.12. B~SQUEDA La biísc-/i/edaes una de las operaciones más importantes en el procesamiento de la información, y permite la recuperación de datos previamente almacenados. Cuando el almacenamiento se encuentra en memoria principal, la búsqueda se califica de interna. Existen diversas formas de efectuar búsquedas en un array. del array hasta alcanzar el final del mismo y, si en algún lugar del array se encuen- tra el elemento buscado, el programa deberá informar sobre lailas posicióniposicio- nes donde ha sido localizado. El algoritmo se puede optimizar utilizando una variable lógica que evite seguir buscando una bez que el dato se ha encontrado si únicamente se desea obtener la posición donde se localiza por primera vez al ele- mento buscado. array de forma ordenada. Consiste en comparar el elemento buscado con el ele- mento que ocupa la posición central y, según sea mayor o menor que el central y el array se encuentre clasificado en orden ascendente o descendente, se repite la ope- ración considerando un siihar~.a~~formado por los elementos situados entre el que ocupa la posición central+l y el último, ambos inclusive, o por los que se encuentran entre el primero y el situado en central-1,también ambos inclusive. El proceso finalizará cuando se encuentre el dato o el sz/hcrrra.v de hzísqz/edu se quede sin elementos. La bzisqz/eúcrlined consiste en recorrer y examinar cada uno de los elementos La biisqiieda hinrrria requiere que los elementos se encuentren colocados en el Codificación recursiva La implementación que se efectúa es recursiva (una operación se llama a sí misma). AI encontrar el elemento buscado se devuelve su posición y, si no se encuentra, devuelve un número negativo, cuyo valor absoluto representa la posición donde dicho elemento debiera ser situado si se quisiera añadir a la lista sin que ésta per- diera su ordenación. public class Bbin private int bucquedaB;nar;a(int[: a, int iz, int de, int c) int central = (iz + de)/2; if (de < ir) return(-iz); return(bucque3aBinaria (a, iz, central-1, 2 )) ; if (a[central] < c) if (c < arcectral:) else return(%usquedaEinaria (a, centzal+l, de, c)) ;
  • 203. Arrays 187 else return(cectra1) ; i public int búsqüedaB(int[] a, int c) return(b~squecaB1:iar;a (a,3,a.leng~h,c)) ; i 1 public class Class1 i public static void mair.(Str-n.g [ ] a r g s ) / / er. el array a los elemenLos están colocados ae forma ordenada int[] a = !?,2,5,7,8,9,11,123; //muestra el array for (int I = O; I < a.length; :-+) Cystem.o'dt.println(a[i:); System.out.println(); Bbin buscador = new Bbin ( ) ; //Busca el 1 int p = buscador.búsqaedaB(a, 1); /*Interpreta la i n f o r m a c i j n devuelta por el if (p >= O) proceso de búsqueda * I Cysten.out.pr:nt ("El elemento 1 esta en " ) ; System.out .println("la posición "+ pj ; else Cystem.out . p r i n t ("El eiemento no esza."); System.out .print("Su l u g a r deberia ser " j ; Cystem.out.println("la posición " + Math.abs ( p )) ; Importante: La búsqueda binaria es mucho más eficiente que la lineal, pero requiere que los elementos se encuentren colocados en el array de forma orde- nada.
  • 204. 188 Java 2. Manual de programación 7.13. IMPLEMENTACIÓNGENÉRICA DE LOS MÉTODOS DE ORDENACIÓN Antes de presentar una implementación genérica de los distintos métodos de orde- nación hay que tener en cuenta que cuando los elementos de un array se declaran a partir de la superclase Object,dicho array se podrá utilizar para almacenar objetos de distinta clase. Los métodos de ordenación y búsqueda deben imple- mentarse de forma que respectivamente puedan ordenar y buscar información en arrays con cualquier tipo de contenido; para ello, se define una interfaz, Comparable y se declara la información almacenada en el array, en lugar de Object,como Comparable. La interfaz Comparable tendrá la siguiente estructura: / * Interfaz básico estándar de comparación, concebido para admitir varios criterios de ordenación en este caso el campo criterio no será usado*/ interface Comparable boolean menorque(Comparab1e c, i n t criterio) throws Exception; El objeto a almacenar en el array implementará la interfaz Comparable;por ejemplo: //objeto Comparable public c l a s s Entero implements Comparable i n t valor; Entero ( i n t valor) this.valor = valor; public boolean menorque (Comparable c, i n t criterio) throws Exception i f ( ! (c instanceof Entero)) //Lanza una excepción (vea el capítulo sobre excepciones) throw new Exception ("Tipo de comparación inválido"); Entero e = (Entero)c; return (valor < e .valor); 1 I
  • 205. Arrays 189 Los métodos de ordenación deben codificarse ahora de la siguiente forma: public class Metord i public void celeccion (Comparable[ ] a, int criterio) throws Exception t int mesor; for (int 1 = O; 1 < a.length-í; i++) menor = 1; for (int j = 1+l; j < a.length; I++) if (a[ j] .mezorque(a[r;e>.or],crizerio) menor = j; Comparable auxi=a [ i I ; a[i]=a[menor]; a [menor]=auxi; } public void incercion (Comparable[ ] a, int cr;rer-c) throws Exception Comparable dux; int 1 ; boolean encoctradocitio; for (int i = 1; i < a.length; I++) i aux = a [ i ] ; encontrados;tio = false; while (j >= O & & !encontradositio) (aux.mencrque(a[II , criterio)) 1 = i-1; if a[j+l]=a[jl; j--; else encontradositio = true; a [ jtl]=aux; public void burbula (Comparable[ ] a, int criterio) throws Exception Comparable auxi = a[] I ; a[j] = a [ ] + l ] ; a [ j + i ] = auxi;
  • 206. 190 Java 2. Manual de programación public void burbulaMelorada (Comparable[I a, i n t criterio) throws Exception boolean ordenado; i n t i = 1; do ordenaao = true; for ( i n t 3 = O; < < a.length-1; I++) (a:j + 1 ].menorque (a[ J! ,crizerio))i f ordemdo = f a l s e ; Comparable aux: = a[]'; a[]; = a [ j L l 1 ; a [ : t l ] = aux:; i-t; while (ordenado == f a l s e ) ; public void gC (Comparable a [ 1 , i n t c r i t e r i o ) throws Exception i ql-iciCort (a, criter-o, O, a.LengLh-1) ; public void quicksort(Comparable a[], i n t criterio, i n t i z , i n t de) i throws Exception i n t : = :z; i n t j = de; Ccinparable pivote = a [ (iz+de)/2]; do w h i l e ( a [ i ; .menorque(pivote,criteric) {it+;1 while ( p i v o t e . r n e n o r q u e (a[ J I , criterio) ) {I--; 1 i f (i <= j) Comparable aux: = a [i! ; a i i ; = a[];; a[:] = auxi; i-+; - - _ .> I while (i <= 1) ; if (j > iz) { q c i c k S o r t ( a , criterio, iz, 3);) if (: < ae) { q u i c k C o r t ( a , criterio, i, de);}
  • 207. Arrays 191 El programa de prueba podría ser: public c l a s s PruebaT I public s t a t i c void r i d i n (String[I args) throws Excepticr i Encero[: a = new Zntero[7]; a[u] = new Entero(6); a[:] = new Entero(1); a[2] = new Entero(4); a[3] = new Entero(7); a[4] = new Entero(?); a[5] = new Entero([>); a[61 = new Ertero(3); Metcrd ordenadcr = new Yetordo ; orderador.seleccior (a,3 ) ; for ( i n t 1 = O; 1 < a.,~qgth; I++) System.out.printlnía[i].valor); 1
  • 208. Cadenas y fechas CONTENIDO 8.1. Creación de cadenas. 8.2. Comparación de cadenas. 8.3. Concatenación. 8.4. 8.5. La clase StringTokenizer. 8.6. La clase StringBuffer. 8.7. 8.8. La clase Date. 8.9. Los formatos de fechas. Otros métodos de la clase String. Métodos de la clase StringBuffer. 8.10. La Clase Calendar. 193
  • 209. 194 Java 2. Manual de programación Una cadena (string)es una secuencia de caracteres. Los arrays y las cadenas se basan en conceptos similares. En la mayoría de los lenguajes de programación, las cadenas se tratan como arrays de caracteres, pero en Java, una cadena (string)se utiliza de modo diferente a partir de un objeto array. Java proporciona la clase incorporada string para manejar cadenas de caracteres.En el caso de que se desee modificarcon fre- cuencia estas cadenas, es conveniente usar la clase StringBuffer en lugar de String con objeto de consumir menos memoria. En algunas ocasiones es, necesario efectuar un análisis gra- matical básico de una cadena y, para ello, se emplea la clase CtringTokenizer,que permite dividir una cadena en subcade- nas en aquellos lugares donde aparezcan en la cadena inicial unos determinados símbolos denominados delimitadores. Los programas también necesitan manejar frecuentemente la fecha del sistema. Para trabajar con fechas en los programas se utiliza la clase GregorianCalendar,mientras que la clase Date se puede utilizar para medir el tiempo que una determinada tarea tarda en ejecutarse. En este capítulo se comentan las características de cada una de las clases, de uso frecuente, anteriormente citadas. 8.1. C R E A C I ~ NDE CADENAS Una de las clases más frecuentemente utilizadas en los programas Java es la clase S t r i n g perteneciente al paquete Java.l a n g . Las cadenas S t r i n g de Java no son, simplemente, un conjunto de caracteres contiguos en memoria, como ocurre en otros lenguajes, sino que son objetos con propiedades y comportamientos. La clase S t r i n g se declara en Java como clase f i n a l como medida de seguridad y, por tanto, no puede tener subclasec. public final class Strinq extends Oblect implements Cerializable, Cciiparable Existen dos formas de crear una cadena en Java, mediante un literal y mediante el empleo de un constructor explícito. Cada vez que en un programa Java se utiliza una constante de cadena, automáticamente se crea un objeto de la clase S t r i n g . Para crear una cadena con un literal y asignarle una referencia, puede emplearse una sentencia como la siguiente: String saludo = “Hcla”;
  • 210. Cadenas y fechas 195 La cadena así creada se coloca en un lugar especial reservado para las mismas y, si posteriormente se crea otra cadena con el mismo literal, no se añade un nuevo objeto a dicho espacio, sino que utiliza el objeto existente, al que añade una nueva referencia. Ejemplo Las siguientes líneas de código producen el resultado que se muestra en la Figura 8.1: String ciudad = "Madrid" ; String miciudad = "Madrid" : _.- Ambas referencias amputan al mismo literal físico en el espacio reservado para el ~~ _ _ ~ almacenamiento de literales String ciudad 7:Madrid miciudad Figura 8.1. Creación de cadenas con el mismo literal. Otra forma de crear cadenas es usar un constructor explícito, por ejemplo: char arr [ ] = { 'H' , 'o', '1', 'a' } ; String saludo = new C;ring(arr) ; Esta última sentencia coloca un objeto String en el montíczdo (heap),en lugar de situarlo en el espacio reservado para las cadenas anteriormente comentado. Entre los diversos constructores que posee la clase S t r i n g pueden destacarse los siguientes: public String ( ) public Str,cg(char[ ] arr) public Ctring(java.lang.String cad) public Strir.g(java .la=g.Stringsuffer buffer) Crea un objeto Strinq sin caracteres. Crea un objeto srring a partir de un array de caracteres. Crea un String con los mismos caracteres que otro objeto String,es decir. realiza una copia. Crea un objeto String con una copia de los caracteres existentes en un CtringBuffer,que es una cadena dinámicamente redimensionable.
  • 211. 196 Java 2. Manual de programación Nota: La sentencia cad2 = new String(cad1); permite efectuar la copia de la cadena, en este caso cadl,que se pasa como argumento. La sentencia cad2 = cadl;copia la referencia cadl en cad2 y consigue que ambas variables permitan acceder al mismo objeto. La sentencia cad2 = cadl .tostring ( ) produce unos resultados análogos a la anterior, puesto que cadl .tostring ( ) devuelve el propio objeto String. Ejemplo Tras la siguiente sentencia: String ciudad2 = new String (“Madrid”); ciudad2 no tiene un valor literal colocado en el espacio reservado para el almace- namiento de literales String,sino que es parte de un objeto separado String. ciudad2 -Madrid ciudad -Madrid miciudad f Figura 8.2. Diferencias entre la creación de cadenas con el mismo literal y mediante el uso de un constructor explícito. AI elegir entre uno u otro método es importante recordar posteriormente cuál se ha usado, pues esto afecta a la forma en la que las cadenas Strings se pueden comparar. Las cadenas de caracteres también se pueden leer desde teclado y el método habitualmente utilizado para ello es readLine de la clase BufferedReader que lee una secuencia de caracteres de un flujo de entrada y crea un objeto de tipo String devolviendo una referencia al mismo. Se ha de tener en cuenta que para efectuar este tipo de entrada debe construirse previamente un objeto de la clase Buf feredReader sobre otro de la clase InputStreamReader aso- ciado a System.in. Otro aspecto importante de los objetos de tipo String es que no pueden ser modificados en memoria. En realidad, lo que esto quiere decir es que para modifi- car una cadena existente Java crea un nuevo objeto String con las modificacio- nes y deja la cadena inicial, sin utilidad, disponible para la recolección de basura.
  • 212. Cadenas y fechas 197 Por tanto, un programa que necesite efectuar muchas manipulaciones de cadenas String puede consumir grandes cantidades de memoria y, para evitarlo, en dichos casos deben reemplazarse los objetos S t r i n g por objetos de la clase StringBuffer. 8.2. COMPARACIÓN DE CADENAS La comparación de cadenas se basa en el orden numérico del código de caracteres; es decir, que, al comparar cadenas, Java va comparando sucesivamente los códigos Unicode de los caracteres correspondientes en ambas cadenas y si encuentra un carácter diferente o una de las cadenas termina detiene la comparación. Para que dos cadenas sean iguales, han de tener el mismo número de caracteres y cada carác- ter de una ser igual al correspondiente carácter de la otra. Al comparar cadenas la presencia de un carácter, aunque sea el blanco, se considera mayor que su ausencia. Además, la comparación de cadenas distingue entre mayúsculas y minúsculas pues- to que su código no es el mismo, las letras mayúsculas tienen un número de código menor que las minúsculas. A la hora de comparar cadenas hay que tener en cuenta que el operador == com- para solamente las referencias de objeto, mientras que el método equals compa- ra los contenidos de los objetos. public boolean equals (java.lang.Object un0bject) Así, cuando se crean cadenas mediante literales, éstas podrán ser comparadas tanto con el operador == como con el método equals. Ejemplo Comparar dos cadenas usando primero el método equals y a continuación el ope- rador ==. import java.io.*; public class Cornpararcadenas i public static void main (String[] args) t String nornbrel, ciudadl, nornbre2, ciudad2; nombre1 = "Ana"; ciudadl = "Madrid"; nombre2 = "Pedro";
  • 213. 198 Java 2. Manual de programación ciudad2 = "Madrid"; System.oiit.println("Comparacihn con equals"); i f (ciuaacil. e q ~ a l s(ci>~dad2)) System..cut.println(nombrel + " y "+ ncmbre2~ " son de ;a misaa ciudad"); else Syscen.cuz.pristln (nor?brel + " y "t nombre2+ " son de distinta ciudad"); Sycter.o ~ t.println("Cciparacicc con ==" j ; i f (c:¿idadl == ciudad2) Systerr,.out.println(nombre1 t " y " + nor?,bre2- '' scn de la rnis.3 c1~1aad"); else Syszem.out .prir.tln(?,cr.brel+ " y " + ncmbre2+ " son de distinta ciudad"); t Si se desea comparar cadenas creadas usando un constructor explícito. será nece- sario emplear el método equals. Importante:Para comparar cadenas, lo más seguro es usar siempre el método equals, aunque en algunas ocasiones esta operación nos devolvería un resul- tado análogo al empleo del operador ==. Ejemplo Comparar dos cadenas leídas desde teclado usando primero el método e q u a l s y a continuación el operador == . import java.ic.*; public class Compararcadenas2 public s t a t i c Szring leer ( ) IrputStreamRea&r i c r = new 1nputStrear.Reader(Syccern.in); BufferedReader br = new BufferedReader (isrj; String cadena = " " ; t r y / " readL:ne: public java.lang.Ctring readL;ne(), es an rietodo de java.ic.BufferedReader * / cadera = br.read¿ir.e ( j ;
  • 214. Cadenas y fechas 1% i catch(Excepticr e) : i return cadena; String n o i b z e l , v i - d a d l , noY.bre2, ciuaad2; Syszem.out.printlr- ("IndlqJe el nombre y pu no-crel = l e e r ( ) ; Byste~.oit.prir_ln("~-diquela ciuaad y pci ciudad1 r leer(); se R E T C W " ) ; Cystem.cut .priritlr.("InC;q,e el nombre y pulse RETCZL"); nomcre2 = l e e r ( ) ; Systei.out . p r i r . t l n ("Indique la ci-dad y pulse R5;'JRN") ; ciuaad2 = leer ( ) ; Cystem.cu:.printlz ("Comparación con eqiials") ; if (ciudad1.equals(ciuaad2)) System.out.println(nombre1 + " y "+ nombre2 + " sor' de la misma ci¿idad"); System.out.println(ncmbre1 - " y "t nombre2 t " cor de distinta ciudad"); else Cyscem.out .printlr.("Conparaciór, ccn = = " ) ; if (ciudaal == ciudad2) Cyste~.out.printl-(nomhLel + " y "- ncmbre2 + " san de la misma ciudad"); C y s t e m . o u t . p r i n t l r ( n o m b r e l + " y ''& n o i b r e 2 t " son de d i s t i r t a ciuaad"); else I Si el método leer del programa anterior se sustituye por este otro: public static Ctrinq l e e r ( ) InputStreamReader :sr = new 1np~~tStreaaReaderjSystern.ir.); BufferedReader br = new B u f f e r e d R e a c e r ( i s r j ; S t r i n g cadena = " " ; try i cadena = Icr .readLine ( ) .intern ( ) ; i catch(Exceptior, e ) t i return cadena;
  • 215. 200 Java 2. Manual de programación el resultado obtenido al comparar con el operador == será diferente, ya que el méto- do intern ( ) obliga a las cadenas a colocarse en el espacio reservado por Java para el almacenamiento de literales String. emplearse el método Cuando se desean ignorar las diferencias entre mayúsculas y minúsculas, debe public boolean equalsIgnoreCase (java.1ang.String o t r a c a d ) y, por tanto, la ejecución de las siguientes líneas de programa if ("ANA".equalsIgnoreCase ("Ana")) System.out .println("son iguales"); mostraría que las cadenas son iguales. Nota: compareToy compareToIgnoreCaseson métodos habitualmen- te utilizados en los programas que necesitan ordenar arrays de cadenas. Otra forma de comparar cadenas es utilizar el método compareTo,cuyo for- mato es el siguiente: public int compareTo (java.lang.String o t r a C a d ) Este método devuelve O cuando las cadenas son iguales, un número negativo si el objeto String que invoca a compareTo es menor que el objeto String que se le pasa como argumento y un número positivo cuando es el argumento el que es mayor. Ejemplos I . String cadl = new String("Ana"); String cad2 = new String ("Anastasia"); System.out .print ("La cadena " ) ; if (cadl.compareTo (cad2) < O) else if (cadl.compareTo (cad2) == O) else System.out.println(cad1 t " es menor que " + cad2); Cystem.out.println(cad1 t " es igual que "t cad2); System.out.println(cad1 + " es mayor que " + cad2); el resultado es La cadena Ana es menor que Anastasia
  • 216. Cadenas y fechas 201 2. if ("Ana".CGmpareTG ("ANASTASIA")< O) Systern.out.println ("es menor") ; Systern.out .println("no es menor") ; else el resultado es no es menor 3. System.out.println("Juan".cornpareTo("Javier")< o ) ; el re.sultado es false Para no diferenciar entre mayúsculas y minúsculas, en lugar de compareTo se emplea compareT o IgnoreCace. 8.3. coNCATENACIóN Concatenar cadenas significa unir varias cadenas en una sola conservando el orden de los caracteres en cada una de ellas. En Java es posible concatenar cadenas usando tanto el operador + como el método concat. El operador t en Java tiene un significado especial de concatenación de cadenas y se puede utilizar con objetos de la clase String. Ejemplo String cadl = n e w String("4 + 2"); String cad2 = n e w String(" = " ) ; String operacion = cadl + cad2; //imprime 4 + 2 = Cystern.out.println(operacion); En el caso de que uno de los operandos que intervienen en una expresión sea de cadena, el operador t convierte a cadena los valores de otros tipos que intervienen en la expresión y efectúa concatenación. Ejemplo S y S t e m . o u t . p r i n t l n ( o p e r a c i o n t 4 t 2); //Salida 4 + 2 = 42 En el estudio de la concatenación de cadenas y teniendo en cuenta la imposibi- lidad de modificar los objetos String,es importante comprender el funciona- miento de las siguientes instrucciones:
  • 217. 202 Java 2. Manual de programación S:r:.ig av;co = new S t r i n g ("Ura c a d e r a " ) ; aviso = ob-co - " puede z c n t e n e r caracteres n u m é r i c o s " ; Estas sentencias no cambian el objeto String original, sino que Java adquiere una nueva zona de memoria para un nuevo objeto String,donde quepa la nueva cadena, copia el antiguo en el nuevo objeto y añade la nueva parte. La referencia aviso apunta ahora hacia la nueva cadena. La vieja versión del String queda disponible para la recolección de basura. Estas sentencias se podrían haber escrito de la siguiente forma: S t r i n g a v i s o = new S t r i n g ( " J n a c a d e n a " ) ; aT~7:r.o t = 1' puede c o n z e n er c a ract ere s n , m e r 1coc " ; es decir, es posible también usar el operador += en operaciones de concatena- ción. Otra forma de efectuar la concatenación de cadenas es utilizar el método con- cat.Este inétodo devuelve un nuevo objeto, resultado de añadir los caracteres del objeto String especificado como parámetro a continuación de los del objeto String que invoca concat. Ejemplo S t r i r . g r a d 1 = new S t r i n g ( " 4 t 2 " ) ; Stri7.g cae2 = new C:rinq ( " = " ) ; Srr:ng o p e r a c i o r . = cacil. c o n c a t (cad21; //i:1,prime 4 t 2 = C ~ s t e ~ . c ; t . p r : n t l i ( o p e r a r i o n ) ; 8.4. OTROS MÉTODOS DE LA CLASE String Entre los restantes métodos de la clase String se pueden destacar: I . , public i n t l e n g t h ( ) ) El método length devuelve la longitud de la cadena Ejemplo C-ririg cad1 = new C t r i n q (" ANA" ) ; Cys:em. out.pr:r.tln (cad:. l e r , g t h ( ) ) ;
  • 218. Cadenas y fechas 203 Nota: Referencia un carácter fuera de los límites de una cadena S t r i n g , es decir, con índice negativo o mayor o igual al tamaño del String,produce una StringIndexOutOfBoundsException. 2. /public char c h a r A t ( i n t indice)l Devuelve el carácter de la cadena que se encuentra en la posición especificada mediante el parámetro i n d i c e , lo mismo que en el caso de los arrays se considera que el primer carácter de una cadena se encuentra situado en la posición cero y el último en length ( ) -1. Ejemplo public class EjcharAt public s t a t i c void rnair. ( S t r - n g [ ] args) I String cad1 = new String (" ANA" ) ; for ( i n t i = O ; I < cadl.;engtk. ( ) ; i t t ) C y s t e m . o u t . p r i n t i n ( c a S l . c h a r A t ( l ) ) ; i 1 h p r i t w e t i priritcillci A N A 3U. /public java.lang.String substring ( i n t i ' i c i ü , i n t Z : R ) ~ 36. public java.iang.Strinq substring ( i n t i n i c i o ) 1 El método substring permite extraer una subcadena de una cadena y puede ser invocado con el paso de uno o de dos parámetros a elección del programador. Si se especifica un parámetro el método devuelve una nueva cadena que comienza donde indica inicio y se extiende hasta el final de la misma; si se especifican dos. la nueva cadena estará formada por los caracteres existentes en la cadena original entre la posición inicio y la fi n - 1 , ambas inclusive. public class Ejsubstrir,gs I
  • 219. 204 Java 2. Manual de programación public s t a t i c void main (String[] args) i String cadl = new String (" ANA" ) ; for ( i n t i = O ; i < cadl.length(); I++) Cystem.out.println(cadl.substring(i,itl)); -rime en pantalla A N A 4. lpublic cnar [ ] toCharArray ( ) 1 Devuelve un array de caracteres creado a partir del objeto S t r i n g . Ejemplo public c l a s s EjtoCharArray { public s t a t i c void main (String[] a r g s ) Ctrinq sal>Jdo = new String ("hola"); / / Crea un array de caracteres a partir de la cadena c h a r [ ; arr = s a l u c i o . t o C k a r A r r a y ( ) ; / / Eodifica e l array de caracteres pasando cada for ( i n t i=O; i<arr.length; i t t ) Cyscerr.out.println(arr); / / La cadera no se ha modificado Systen.o';t .println(saludo); 'Jno de sus caracteres a mayúsculas a r r [ i ] = ( c h a r )(arr[i]-('a'-'A')); iinprime en pantalla HOLA hola Observación: El método length() devuelve la longitud de una cadena mientras que la variable length de un array informa sobre la longitud del mismo: cadl .length ( ) ; arr.length;
  • 220. Cadenas y fechas 205 5. public boolean regionMatches (boolean i g n o r a D i f , int i n i c i o l ,’ java.lang.String o t r a c a d , int i n i c i o 2 , int c u a n t o s ) Compara una parte de una cadena con parte de otra y devuelve un resultado b o o l e a n . Si el primer parámetro es t r u e , no distingue entre mayúsculas y minúsculas. El significado de los restantes parámetros es: i n i c i o l , posición en la que comienza la comparación para la cadena que invoca al método. o t r aCad, la segunda cadena. i n icio2 posición de la segunda cadena en la que empieza la comparación. c u a n t o s número de caracteres a comparar. 6.[public boolean endcWith(java.1ang.String s u f i j o ) I Devuelve t r u e cuando la cadena termina con los caracteres especificados como argumento. 7.lpublic boolean startsWith(java.lang.String p r e f i j o ) l Devuelve t r u e cuando la cadena comienza con los caracteres especificados como argumento. 8U.l public int indexof (int car)] 8b.l public int indexof (java.lang.String cad)I Estos métodos buscan la cadena o carácter especificados como parámetros en la cadena fuente; y cuando los encuentran, interrumpen la búsqueda, devolviendo la posición donde aparece el carácter o donde comienza la cade- na buscada en la cadena fuente. Si no encuentran el carácter o cadena bus- cados, devuelven - 1, indexof podría utilizarse para comprobar si la opción elegida en un menú de opciones es válida. import java.io.*; public class VerificaOpcion i public static void main (String[] args) i
  • 221. 206 Java 2. Manual de programación //Cadena con el conjunto de opciones válidas String opciones = "ABCS"; char opcion; int n; try i System.out .println("MENÚ"); System.out .println("A. Altas") ; System.out.println ("B. Bajas") ; System.out.println ("C. Consultas") ; System.out.println ("S. Salir"); do t System.out.print("Elija opción (A, B, C, S) " ) ; opcion =(char)System.in.read() ; n = System.in.available(); System.in.skip (n); )while (opciones.index0f(opcion) == -1 1 I n!=2); switch (opcion) i case 'A': //Altas break; case 'B' : break; case 'C': //Consultas break: case ' S I : //Salir //Bajas 1 1 catch (Exception e) t } 9.lpublic java.lanq.Strinq replace (char oldchar, char newChar)l Devuelve una nueva cadena resultante de reemplazar todas las apariciones del oldchar con el newchar. 1O.Ipubiic java.lang.string trim0 I Elimina los espacios en blanco que pudieran existir al principio o final de una cadena. 11.lpubiic java.iang.string toLowerCase 0 1 Convierte a minúsculas las mayúsculas de la cadena.
  • 222. Cadenas y fechas 207 13d. 12./public java.lang.string touppercase 01 public static java.lang.String valueof (char[ ] datos, int desplazamiento, int cont) Convierte a mayúsculas las minúsculas de la cadena. 13a.lpublic static java.lang.String valueOf(boo1ean b)l ~~ 13b.Ipublic static java.lang.String valueOf(char .>I 13~.bublic static java.lang.String valueof (char[ ] datos)] 13e.publicstatic java.lang.String valueof (double d)l 13f. lpubiic static java.1ang.String valueof(fioat f); 13g.lp~biicstatic java.lang.String valueOf(int i)] 13h. lpubiic static java.lang.String valueof (long 13i.lpublic static java.lang.String valueof (java.lang.Object obj)1 Todos estos métodos crean cadenas a partir del correspondiente parámetro y devuelven dichas cadenas. ~ - Recuerde: Para convertir una cadena de caracteres que representa un número al valor correspondiente se utilizan métodos de las clases Double,Float, Integer,como doublevalue,floatvalue o parseint.En el caso de doubley floatel primer paso seráconstruir un objeto Doubleo Float, mientras que en el caso de los tipos enteros no es necesario. int entero = Integer.parseInt(cadena); Double d = n e w Double(cadena); double real = d.doubleValue ( ) ;
  • 223. 208 Java 2. Manual de programación 8.5. LA CLASE StringTokenizer StringTokenizer pertenece al paquete java .uti1 y actúa sobre String. Proporciona capacidades para efectuar un análisis gramatical básico de cadenas, efec- tuando su división en subcadenas por aquellos lugares donde aparecen en la cadena inicial unos determinados símbolos denominados delimitadores. El primer paso para efectuar el análisis consiste en la creación de un objeto StringTokenizer mediante alguno de los siguientes métodos: la. public StringTokenizer (java.lang.String cad) lb. public StringTokenizer(java.1ang.String cad, java.lang.Ctring delim) IC. public StringTokenizer(java.1ang.String c a d , java.lang.String delim, boolean devol verTokens) El parámetro cad representa la cadena que se desea analizar y el parámetro, delim representa los delimitadores; si no se especifica ningún parámetro se con- sideran delimitadores por defecto, el espacio en blanco, tabulador, avance de línea y retorno de carro ( I ' t n rI ! ) , El parámetro que aparece en el tercer construc- tor devolverTokens,de tipo booleano, permite establecer si se deben devolver o no los delimitadores cuando se analiza una cadena. Otros métodos interesantes de la clase en estudio son los siguientes: public java.lang.String nextToken0 Devuelve el siguiente token (unidad lexicográfica) y cuando no lo encuentra lanza una excepción, NoSuchElementException public java.lang.String nextToken(java.lang.String delim) Devuelve el siguiente token y permite cambiar la cadena delimitadora. public boolean hasMoreTokens ( ) Devuelve true o false según queden o no tokens en la cadena. public int countTokens ( ) Devuelve el número de tokens que aun no se han analizado. Ejemplo El siguiente ejemplo muestra el funcionamiento de StringTokenizer a traves del método divide que recibe como parámetro una cadena con una expresión y devuelve en un array de cadenas los operandos y operadores de la misma.
  • 224. Cadenas y fechas 209 Cadena a analizar en el ejemplo " (31.4+5^2)* 7 . 3 " Cadena delimitadora que se establece I l + - * / A ( ) I 1 Salida en pantalla ( 31.4 5 2 + A I * 7 . 3 import java.util.*; public c l a s s EjStringTokenizer t private s t a t i c String[] expresionDividida; private static String [ ] divide (String cad) t StringTokenizer st2 = new StringTokenizer (cad, i n t cont = O; while (st2.hasMoreTokens ( ) ) i "+- * / " ( ) ' I , true) ; cont++; st2.nextTokenO; 1 StringTokenizer st = new StringTokenizer (cad, String[] aux = new String[cont]; for ( i n t i=O; i<aux.length; i++) return dux; " +- * / " ( ) " , t r u e ) ; aux[i] = st.nextToken(); 1 public s t a t i c void main (String[] args) { String cad = " (31.4+5^2)* 7 . 3 " ; expresionDividida = divide (cad); for ( i n t i=O; i < expresionDividida.length; it+) System.out.println(expresionDividida[i]); 8.6. LA CLASE StringBuffer AI igual que S t r i n g , la clase StringBuff er también pertenece al paquete j ava. l a n g y ha sido declarada como f i n a l ; pero a diferencia de los objetos S t r i n g , con los que se necesita reservar una nueva área en memoria para crear una nueva versión, los objetos Str ingBu f f er son modificables, tanto en contenido como en tamaño. public finai class StringBuffer extends Object iqlements Serializable
  • 225. 210 Java 2. Manual de programación A la hora de elegir entre usar objetos String o StringBuffer hay que tener en cuenta que los String mejoran el rendimiento cuando el objeto no se modifica, mientras StringBuffer es la clase recomendada si el objeto va a sufrir muchas modificaciones. Los objetos StringBuffer tienen una determi- nada capacidad y, cuando ésta se excede por la adición de caracteres, crecen auto- máticamente. En realidad Java utiliza objetos de la clase Str ingBuffer por su cuenta cuando se utilizan los operadores + o += para concatenar cadenas. Constructores public StringBufferO public StringBuffer (int longitud) Construye un CtringBuffer sin caracteres, con capacidad inicial para 16. Construye un CtringBuffer sin caracteres, con capacidad inicial para longitud carac- teres. public StringBuffer (java.lang.Ctring cad)Construye un StringBuffer con la misma secuencia de ca- racteres que la cadena recibida como parámetro. La capacidad inicial del StringBuffer es para 16 caracteres más de los almacenados en dicha cadena. 8.7. MÉTODOS DE LA CLASE StringBuffer Los métodos importantes de la clase Str ingBuffer son: public int length() Devuelve el número de caracteres actuales. public int capacity Devuelve la capacidad. public synchronized void encurecapacity (int minimacapacidad) Establece una capacidad minima. public synchronized void setLength (int nuevaLongi tud) Establece la longitud, si es menor que el número de caracteres actuales se trunca a la longitud especificada. public synchronized java.1ang.CtringBuffer append(boo1ean b)
  • 226. Cadenas y fechas 211 public synchronized java.1ang.StringBuffer append(char c) public synchronized java.1ang.StringBuffer append(char[] cad) public synchronized java.1ang.StringBuffer append(char[] cad, int desplazamiento, int longitud) public java.1ang.StringBuffer append(doub1e d) public java.1ang.StringBuffer append(f1oat f) public java.1ang.CtringBuffer append(int i) public synchronized java.1ang.CtringBuffer append(1ong 1) public java.lang.StringBuffer append(java.lang.0bject o b j ) public java.1ang.StringBuffer append(java.lang.String cad) Los métodos append añaden al final del StringBuffer la cadena resultante de la transformación del correspondiente argumento. public java.1ang.StringBuffer insert(int desplazamiento, boolean b) public synchronized java.lang.StringBuffer insert(int desplazamiento, char c) public synchronized java.lang.StringBuffer insert(int desplazamiento, char [ ] cad) public synchronized java.1ang.StringBuffer insert(int index, char[] cad, int desplazamiento, int longitud) public java.lang.StringBuffer insert (int desplazamiento, double d) public java.1ang.StringBuffer insert(int desplazamiento, float f) public java.1ang.StringBuffer insert(int desplazamiento, int i) public java.1ang.StringBuffer insert (int desplazamiento, long 1) public synchronized java.lang.StringBuffer insert(int desplazamiento, java.lang .Object o b j ) public synchronized java.1ang.StringBuffer insert(int desplazamiento, java.1ang.String cad) Los métodos insert colocan distintos tipos de datos, previamente transformados a cadena, en una determinada posición del StringBuffer. public synchronized java.1ang.StringBuffer delete(int inicio, int fin)
  • 227. 212 Java 2. Manual de programación Elimina del objeto StringBuffer los caracteres exitentes entre las posiciones inicio y fin-1. public synchronized java.lang.StringBuffer replace (int i n i c i o , Sustituye los caracteres existentes entre las posiciones inicio y fin-i por los especifi- cados mediante cad. int f i n , String c a d ) public synchronized java.1ang.StringBuffer reverse0 Invierte la cadena almacenada en el StringBuffer. public java.lang.String substring(int i n i c i o ) public java.lang.String substring (int i n i c i o , int f i n ) Permite extraer un String de un StringBuffer y puede ser invocado pasándole dos o bien un único parámetro. Cuando sólo se le especifica un parámetro el método devuelve una nueva cadena que comienza donde indica inicio y se extiende hasta el final de la mis- ma, si los parámetros son dos la nueva cadena estará formada por los caracteres existentes en la original entre la posición inicio y la fin-1,ambos inclusive. public java.lang.String tostring() Copia el StringBuffer en un String y devuelve dicha copia. public synchronized char charAt(int i n d i c e ) Devuelve el carácter existente en una determinada posición. public synchronized void setCharAt (int i n d i c e , char car) Coloca el carácter car en una determinada posición, sobreescibiendo el allí existente con el nuevo. public synchronized void getchars (int fuenteInicio, int fuenteFin, char [ I d e s t , int d e s t l n i c i o ) Copia en un array los caracteres del StringBuffer,devolviendo dicho array. 8.8. LA CLASE Date En Java 2 la clase Date representa fechas y horas y tiene dos constructores: public Date0 public Date (long num) Crea un nuevo objeto Date y coloca en e1 la fecha y hora actuales Crea un nuevo objeto Date y coloca en el la fecha obtenida al interpretar el paráme- tro como el número de milisegundos en que debe incrementarse una fecha arbitra- ria,] de enero de 1970.
  • 228. Cadenas y fechas 213 Entre los métodos de esta clase destacan: public java.lang.S t r i n g tostring ( ) Convierte el objeto Date en una cadena de caracteres. public long getTirne ( ) Devuelve el número de milisegundos transcurridos desde una fecha arbitraria. 1 de enero de 1970. import java.util.*; Date actual = new Date(); S y s t e r n . o u t . p r i n t l n ( a c t u a l ) ; 8.9. LOS FORMATOS DE FECHAS Los formatos especiales para las fechas se establecen mediante la clase DateFormat del paquete java .text y se crea un objeto,formateador. Format es la clase base en el formate0 de información sensible a la localidad, como fechas y números. public abstract class Format extends Object implements Serializable, Cloneable y DateFormat extiende Format. public abstract class DateFormat extends Format Los métodos public s t a t i c f i n a l java.text.DateFormat getDateInstance0 Y public s t a t i c f i n a l java.text.DateForrnat getTirneInstance0 sin parámetros permiten crear unformateador con el estilo de formato local. Ejemplo import java.util.*; import 1ava.text.DateForrnat;
  • 229. 214 Java 2. Manual de programación . . . Date actial = new Date 0; DaieFormat forrateador = DateFormat.getDateInstance0; C y s t e r . o ü t . p r i n t l n ( f o r n a t e a d o r . f o r . f o r m a c ( a c t u a 1 ) ) ; También es posible establecer un estilo específico, utilizando el método public s t a t i c f i n a l java.text.3ateForrat get3ateInctance(int e s t i l o ) y pasándole alguno de los siguientes valores como parámetro: public s t a t i c f i n a l i n t DEFAULT public s t a t i c f i n a l i n t FULL public s t a t i c f i n a l i n t LONG public s t a t i c f i n a l i n t MEDIUM e incluso establecer la localidad public static f i n a l java.text.DateFormat getDateInctanc ( i n t e s t i l o , java.util.Locale unalocalidad) Observe que el segundo parámetro es de la clase Locale,algunas de cuyas constantes son: public s t a t i c f i n a l java.ut;l.Locale ENGLISH public s t a t i c f i n a l java.ut:l.Locale GERMAN Ejemplo import lava.util.*; import lava.text.*; . . . DaLe actual = new Date 0 ; DateFormat formateadcr = CateLormat.getDate1nstance CycteI-.oct.pri?tln(formateador.format(actual)); (>ateFcrnat.LC!dG, Locale.ENGLISH); 8.10. LA CLASE Calendar La clase Calendar y su subciase GregorianCalendar representan datos de tipo calendario. La clase Calendar permite crear fechas específicas, establecien- do el día, mes y año, incluyendo la zona y los ajustes horarios y también permite obtener todos ellos, así cdmo el día de la semana.
  • 230. Cadenas y fechas 215 p u b l i c a b s t r a c t c l a s s Calendar extends Object implements C e r i a l i z a b l e , Cloneable p u b l i c c l a s s GregorianCalendar extends Calezdar Entre los métodos de la clase Calenciar se pueden citar: p u b l i c s t a t i c synchronized j a v a . u t i l . C a l e n d a r g e t I n s t a n c e 0 Devuelve un objeto de tipo Gregoriar!Calendar inicializado con la fecha y hora actuales y huso horario y sitio por omisión. p u b l i c f i n a l i n t g e t ( i n t campo) Devuelve parte de una fecha. p u b l i c f i n a l Date getTime0 Devuelve el tiempo actual del calendario. p u b l i c f i n a l void s e t ( i n t año, i n t mes, i n t d i a ) p u b l i c f i n a l void s e t ( i n t año, i n t mes, i n t d i a , i n t h o r a , i n t minutos) public f i n a l void s e t ( i n t año, i n t mes, i n t d i a , i n t h o r a , i n t minutos, i n t segundos) Establecen partes de una fecha. p u b l i c f i n a l void cetTime (Date unDatej Establece el tiempo para el calendario con la fecha dada. Constantes p u b l i c static f i n a l i n t JANUARY p u b l i c s t a t i c f i n a l i n t FEBRUARY p u b l i c s t a t i c f i n a l i n t MON3AY p u b l i c s t a t i c f i n a l i n t TUESDAY . . . Campos p u b l i c s t a t i c f i n a l i n t DAYP -OF WEZK p u b l i c s t a t i c f i n a l i n t DAY OF-YEAR p u b l i c static f i n a l i n t HOUE-OF~~AY Ejercicio El programa FechaCumpl determina cuantos días faltan para un cumpleaños.
  • 231. 216 Java 2. Manual de programación import java.io.*; import java.util.*; public class FechaCumpl public static void main (String[] argc) I InputStreamReader isr = new InputStreamReader(System.in); BafferedReader br = new BufferedReader(isr); String nombre; try System.out.println ("Escriba su nombre y pulse RETURN") ; nombre = br .readLine ( ) ; System.out .print111("indique el día de su cumpleaños"+ int dia = Integer.parseInt(br.readLine0); System.out.println ("indique el número de mes en que"+ int mes = Integer.parseInt(br.readLine ( ) ) ; Calendar call = Calendar.getinstance(); Calendar cal2 = Calendar.getInstance(); ca12.set (call.get (Calendar.YEAR),mes - int diferencia = ca12.get(Calendar.DAY-OF-YEAR) - if (diferencia > O) else "y pulse RETURN") ; "nació y pulse RETURN"); 1,dia); call.get(Calendar.DAY-OF-YEAR); System.out .println("Faltan "+diferencia+" dias"); if (diferencia == O) else System.out.println("FELICIDADES"); System.out.println("Su cumpleaños fué hace " t Math.abs (diferencia)+" dias"); 1 catch (IOException e) I System.out .println("Error"); 1
  • 232. CAPlT 9 InterfacesI gráficasI de usuario CONTENIDO 9.1. El AWT. 9.2. 9.3. La clase Component. 9.4. La clase Container. 9.5. Ventanas. 9.6. Clase Panel. 9.7. Clase Label. 9.8. Clase Button. 9.9. Clase Textcomponent. 9.10. Clase Canvas. 9.11. Clase Choice. 9.12. Clase Checkbox. 9.13. Listas. 9.14. Clase Scrollbar. 9.15. Menús. 9.16. Administradores de diseño. 9.17. Swing. Realización de dibujos: clase Graphics. 217
  • 233. 218 Java 2. Manual de programación ~~ Las interfaces Gráficas de Usuario (IGU)' ofrecen objetos visuales sobre los cuales pueden los usuarios actuar y de esta forma comu- nicarse con un programa. En la versión 2 de Java, la biblioteca denominada Java Foundation Classes proporciona un conjunto de clases destinadas al diseño de interfaces gráficas, entre las que, conjuntamente con las de j ava .awt,destacan las pertenecientes al paquete j avax.swing. Los componentes Swing se ejecutan uniformemente en cualquier plataforma y constituyen una mejora sobre los del awt aunque no siempre los reemplazan. Los compo- nentes de las IGU (botones, campos de texto, etc.) esperan a que el usuario ejecute alguna acción sobre ellos; es decir, esperan un evento (o suceso). Por eso se dice que la programación con IGU es una programación dirigida por eventos. La gestión de eventos se verá con mayor profundidad en el capítulo diez. AWT (Abstract Window>Toolkit) es un paquete en el que se encuentran clases capa- ces de crear componentes de la IGU (GUI); es decir, clases capaces de crear obje- tos visuales sobre los cuales pueden los usuarios actuar, mediante el empleo del ratón o el teclado, para comunicarse con el programa, sustituyendo, por tanto, dichos objetos la entradahalida clásicas. El aspecto de estos componentes puede variar de una plataforma a otra, ya que existe una vinculación con la IGU local. Los componentes de la IGU (botones, campos de texto, etc.) se organizan en contenedores y esperan hasta que el usuario ejecute alguna acción sobre ellos, es decir, esperan un evento (suceso).Por eso se dice que la programación IGU es una programación dirigida por eventos. Para el diseño de este tipo de programas es necesario considerar, como se acaba de indicar, que las interfaces gráficas están construidas por elementos gráficos denominados componentes agrupados dentro de otros que se denominan contenedores, pero además hay que tener en cuenta que los contenedores son a su vez componentes y pueden volver a ser agrupados en otros contenedores. Habitualmente en un contenedor habrá varios componentes y para situarlos de forma conveniente pueden usarse los administradores de diseño. ' En ingles, Grupízicul U.yerInrerfuce (CUI)
  • 234. Interfaces gráficas de usuario 219 p u b l i c abstract void copyArea(int pl, i n t p2, i n t p 3 , i n t p4, i n t p5, i n t p6) Copia un área rectangular de la pantalla y la coloca en otro lugar; p1,p2 representan la esquina superior izquierda del área a copiar; p3 y p4 la anchura y altura de la misma y p5 y p6 un desplazamiento relativo con respecto a los dos primeros valores, a través del cual se obtiene el lugar donde se situará la esquina superior izquierda de la copia. p u b l i c abstract java.awt.Graphics c r e a t e 0 Crea una nueva referencia para un contexto gráfico. Es interesante también conocer que los métodos gráficos de Java se encuentran en la clase Graphics,que permite dibujar rectángulos, arcos, polígonos, etc., y, median- te el método drawstring ( ), puede mostrar cadenas en una determinada posición. En resumen, las clases del paquete AWT pueden clasificarse en: gráficos, com- ponentes, administradores de diseño, manipuladores de sucesos y manipuladores de imágenes y, para poder hacer uso de las mismas y gestionar los eventos que se pro- duzcan, los programas deben incluir las siguientes sentencias: import j a v a . a w t . * ; import j a v a . a w t . e v e n t . * ; 9.2. REALIZACIÓN DE DIBUJOS: CLASE Graphics Graphics es una clase abstracta que proporciona un conjunto de métodos para dibu- jar en pantalla -incluido uno para el dibujo de cadenas-y permite escribir programas que usan gráficos independientemente de la plataforma sobre la que van a ser ejecuta- dos. Para efectuar dichos dibujos se necesita un objeto Graphics que no puede ser instunciado, pero se puede obtener a través de los métodos paint y update que lo reciben como parámetro; por tanto, para dibujar, se redefinen los métodos paint y update de componentes que soportan el dibujo (pintura) o visualización de imáge- nes. Los métodos paint y update se explicarán al hablar de la clase Component; por ahora sólo diremos que reciben como parámetro un objeto Graphics, que repre- senta el contexto gráfico del objeto al que pertenecen, y no hacen nada por omisión. Dentro de los métodos pertenecientes a la clase Graphics mencionaremos los siguientes: p u b l i c abstract void clearRect ( i n t pl, i n t p2, i n t p3, i n t p4) Dibuja un rectángulo cuya esquina superior izquierda es pl,p2 y cuyas dimensiones son p3 y p4 (ancho y alto respectivamente) en el color actual del segundo plano. public abstract void c i i p R e c t ( i n t pl, i n t p2, i n t p3, i n t p4) Establece una subzona en el contexto gráfico donde se van a realizar las modificaciones con las siguientes operaciones de dibujo; esta subzona será la intersección entre el rectángulo formado por los parámetros pasados al procedimiento y el rectángulo anteriormente consi- derado.
  • 235. 220 Java 2. Manual de programación p u b l i c abstract void drawArc(int p l , i n t p2, i n t p3, i n t p4, i n t p 5 , i n t pó) Dibuja un arco de modo que pl y p2 son las coordenadas de la esquina superior izquierda de un rectángulo que contuviera dicho arco; p3 y p4 especitican la altura y anchura de dicho rec- tángulo y p5 y p6 son un ángulo de inicio y un ángulo de barrido, ambos expresados en gra- dos. El arco se dibuja desde la posición que indica el ángulo de inicio, recorriendo en sentido contrario a las agujas del reloj los grados especificadas como ángulo de barrido. p u b l i c abstract void drawLine(int pl, i n t p2, i n t p 3 , i n t p4) Dibuja una línea del color seleccionado que comienza en pi,p2y termina en p3,p4. p u b l i c abstract void drawOval(int pl, i n t p2, i n t p3, i n t p4) Dibuja una elipse o un círculo. En el caso de la elipse, pl y p2 son las coordenadas para la esquina superior izquierda de un rectángulo que contuviera a la elipse; p3 y p4 especifican la altura y anchura de dicho rectángulo. Se obtiene un círculo cuando se enmarca en un cuadrado. p u b l i c abstract void drawPoiygon ( i n t pl [ 1 , i n t p2[ 1 , i n t p3) Dibuja una serie de líneas conectadas. Para que la figura esté conectada el primer punto debe ser igual al último. El primer y segundo parámetro son las matrices que contienen las coor- denadas y el tercero especifica el número de puntos. p u b l i c void drawRect(int pl, i n t p2, i n t p 3 , i n t p4) Dibuja un rectángulo cuya esquina superior izquierda es pl,p2y cuyas dimensiones son p3 y p4 (ancho y alto respectivamente). public void draw3DRect ( i n t pl, i n t p2, i n t p3, i n t p4, boolean p5) Dibuja un rectángulo tridimensional en el color actual; pl y p2 son las coordenadas de la esquina superior izquierda; p3 y p4 la anchura y altura del rectángulo, y p5 un valor boo- leano que especifica si el rectángulo debe dibujarse hundido ( f a l s e )o realzado (true). public abstract void drawstring (java.lang. String pl, i n t p2, i n t p3) Dibuja una cadena empleando la fuente y color actuales a situando el primer carácter de la misma arriba y a la derecha del pixel especificado por los parámetros p2 y p3. p u b l i c abstract void f i l l A r c ( i n t p l , i n t p2, i n t p3, i n t p4, i n t p5, i n t p6) Dibuja un arco relleno. p u b l i c abstract void f i l l O v a l ( i n t pl, i n t p2, i n t p 3 , i n t p4) Dibuja una elipse o un círculo rellenos. p u b l i c abstract void f i l l R e c t ( i n t pl, i n t p2, i n t p3, i n t p4) Dibuja un rectángulo relleno cuya esquina superior izquierda es pl,p2 y cuyas dimensio- nes son p3 y p4 (ancho y alto respectivamente). p u b l i c abstract java.awt.Color g e t l o l o r ( ) Permite obtener el color actual en el que se realizarán los dibujos. p u b l i c abstract Font getFont ( ) Devuelve un objeto Font que representa la fuente actual.
  • 236. Interfaces gráficas de usuario 221 public abstract void setColor(java.awt.Color pl) Establece el color actual para dibujar en el contexto gráfico. Las constantes y métodos de color se definen en la clase Color.Constantes de color predefinidas son: Color.black, Color.white,Color.gray,Color.lightGray, Color.darkGray,Color.red, Color.pink,Color.orange, Color.yellow,Color.green, Color.blue, Color.cyan, Color .magenta. public abstract void cetFont (java.awt .Font pl) Establece como fuente actual la especificada en el objeto Font.Para crear un objeto Font con una determinada fuente, estilo y tamaño se utiliza: public Font(java.lang.String pl, int p2, int p3) El primer parámetro es el nombre de la fuente, el segundo el estilo y el tercero el tamaño en puntos. La fuente puede ser cualquiera de las reconocidas por el sistema; si la elegida no está disponible en el sistema donde luego se ejecuta el programa será sustituida por la fuente por omisión en dicho sistema. Constantes predefinidas en cuanto al estilo de fuen- te son Font.PLAIN (normal), Font.ITALIC (cursiva), Font .BOLD (negrita). Otra herramienta muy útil de la clase Font es public int getsize ( ) que devuelve el tamaño de la fuente actual en puntos. public java.awt.FontMetrics getFontMetrics0 Devuelve los siguientes datos sobre la fuente actual: línea de base (posición del renglón sobre el que se escribe), parte ascendente, parte descendente, anchura de los caracteres, interlineado, altura de la fuente. Se utiliza en combinación con otros métodos: public int getAscent 0 public int getDescent 0 public int getHeight ( ) public int getleadingo public int [ ] getwidths ( ) para obtener información sobre una determinada característica de la fuente. Un ejemplo es: int alto = g .getFontMetrics ( ) .getHeight ( 1 ; public abstract void setXORMode(java.awt.Color pl) Establece el modo de pintura XOR,que consigue que las figuras se transparenten y permitan ver la que está debajo cuando se dibujan una encima de otra. En los métodos descritos se observa que para dibujar la primera acción que se realiza es un posicionamiento; por tanto, es necesario conocer que la posición 0,O corresponde a la esquina superior izquierda de la superficie de dibujo, y además, como se verá más adelante, que algunos contenedores tienen bordes, y el área ocu- pada por estos bordes se considera como parte integrante de la zona de dibujo, de modo que, en estos casos, la posición 0,O queda oculta por los bordes. Otro aspecto interesante a tener en cuenta es que el modo de pintura por omisión es el de sobrescritura y, así, cuando una figura se dibuja sobre otra la tapa, es posible
  • 237. 222 Java 2. Manual de programación modificar esta situación y permitir que se vean ambas figuras estableciendo el modo de pintura XOR. Para volver al modo sobrescritura se utiliza public abstract void setPaintMode0. Las aplicaciones que se diseñan pueden crear un gran número de objetos Graphics, pero los recursos consumidos por los objetos Graphics obtenidos a través de los métodos paint y update son liberados automáticamente por el sistema cuando finaliza la ejecución del método; por esta razón, en estos casos, no es necesaria una llamada a dispose. Recuerde: Graphics proporciona, entre otros, el método drawstring que permite el dibujo de cadenas y constituye una forma muy fácil de presen- tar mensajes. Nota: Para efectuar dibujos se redefinen los métodos paint y update de componentes que soportan la pintura o visualización de imágenes; ésta es una forma de obtener el objeto Graphics necesario. 9.3. LA CLASE Component Component es una clase abstracta situada en la parte superior de la jerarquía de clases del paquete AWT y que representa todo aquello que tiene una posición, un tamaño, puede dibujarse en pantalla y además recibir eventos. En esta clase se definen métodos para la gestión de los eventos producidos por el ratón o el tecla- do, otros destinados a especificar el tamaño, el color o tipo de fuente y otros que permiten obtener el contexto gráfico. Entre todos esos métodos, de momento, se destacarán los siguientes: public void paint(java.awt.Graphicc pl) El método paint proporcionado por el componente debe ser redefinido por el progra- mador; este método recibe como parámetro el contexto gráfico del objeto al que perte- nece el método y no tiene que ser invocado. La llamada a un método paint se efectúa de dos formas: Directamente por el sistema, por ejemplo cuando el componente se muestra por pri- mera vez en pantalla, deja de estar tapado por otro o cambia de tamaño. En este tipo de llamadas el AWT determina si el componente debe ser repintado en su totalidad o sólo en parte.
  • 238. Interfaces gráficas de usuario 223 Por la aplicación, que invoca al método repaint,considerando que éste, indirecta- mente, a través de update llama a paint. public void repaint ( ) Es el método que permite a las aplicaciones, mediante invocaciones a dicho método sobre los componentes, ordenar la repintura de los mismos. Este método hace que el intérprete eje- cute una llamada al método update,que en su implementación por defecto llama al méto- do paint.El formato mostrado es el básico. Figura 9.1. Jerarquía de clases.
  • 239. 224 Java 2. Manual de programación public void repaint(int pl, int p2, int p3, int p4) Formato del método comentado anteriormente en el que se especifica la región a repintar, para que el proceso sea más rápido cuando no se necesita vover a pintar todo el área. public void repaint (long pl) El parámetro especifica el máximo de milisegundos que pueden pasar antes de llamar al método update. public void repaint (long pl, int p2, int p3, int p4, int p5) Formato de repaint en el que se especifica tanto el tiempo como las dimensiones del área a repintar; pi y p2 son las coordenadas de la esquina superior izquierda, p3 la anchura y p4 la altura. public void update(java.awt.Graphics pl) Este método posibilita repinturas incrementales. AI igual que paint recibe como paráme- tro el contexto gráfico del objeto al que pertenece y se invoca automáticamente cuando una aplicación llama al método repaint.Cuando no se sobreescribe, el método update borra el contexto gráfico rellenando el fondo con el color de fondo por defecto y llama a continuación a paint para que dibuje de nuevo; estas operaciones hacen que se origine un parpadeo. Una forma de evitar esto es sobrescribir update para que no borre el contexto gráfico; por ejemplo, escribiendo en él una simple llamada a paint. Todos los elementos de la interfaz de usuario que aparecen en pantalla e inte- ractúan con el usuario son subclases de Component (Fig. 9.1). 9.4. LA CLASE Container Container es una subclase abstracta de Component que contiene métodos adi- cionales que van a permitir a los contenedores almacenar objetos Component. Nota: Los objetos Container también son Component y, por consiguiente, resulta posible anidar Container. Los componentes se colocan en los contenedores empleando el método add de la clase Container y los administradores de diseño acomodan los componentes en el contenedor e intentan reajustarlos cuando el usuario redimensiona dicho con- tenedor. Los administradores de diseño se asocian al contenedor mediante el méto- do setLayout.El formato de los métodos citados es: public java.awt.Component add(java.awt.Cornponent pl) public void add(java.awt.Cornponent pl, java.lang.0bject p 2 ) public java.awt.Component add(java.lang.Ctring pl, public void setLayout(java.awt.LayoutManager pl) java.awt.Component p2)
  • 240. Interfaces gráficas de usuario 225 Los principales administradores de diseño son: FlowLayout, BorderLayout y GridLayout. 9.5. VENTANAS La clase Window hereda de Container y contiene métodos para manejar venta- nas. Frame y Dialog extienden Window y FileDialog extiende Dialog, pudiéndose obtener así cuatro tipos básicos de ventanas: Window Frame Dialog FileDialog Ventana de nivel superior, sin barra de título ni borde. Marco, es decir, ventana con borde, título y una barra de menús asociada. Ventana de diálogo con borde y título. Ventana de diálogo especializada en mostrar la lista de archivos de un directorio. 9.5.1. Clase Frame En las aplicaciones IGU se emplea Frame como contenedor más externo, siendo BorderLayout su administrador de diseño por defecto. La clase Frame tiene los siguientes constructores: public Frame ( ) Crea una ventana estándar sin titulo. public Frame ( java.lang .String p i ) Crea una ventana con el titulo especificado. El método publicsynchronizedvoidsetTitle (java.lang.Stringpl) permite cambiar el título de un marco. IIFigura 9.2. Marcos sin y con barra de menús. Las dimensiones de una ventana tienen que ser establecidas después de que ésta ha sido creada, y para ello se utiliza el método public void setSize (int pl, int p2) de java .awt .Component. Además, las ventanas Frame necesitan que se las haga visibles, para lo que se emplea el método public void setvisible (boolean pl) de java.awt .Component.
  • 241. 226 Java 2. Manual de programación Cierre de la ventana de una aplicación Para cerrar una ventana, el método usualmente aceptado es que el usuario efectúe clic sobre el botón de cierre de la misma m.La pulsación de este botón genera un suceso que puede ser detectado por el oyente WindowListener del paquete java .awt .event,para ello se instancia y registra un objeto receptor de even- tos de ventana. addWindowListener(new ReceptorEventoO) y luego se define el receptor de eventos de forma que suplante y redefina el méto- do windowClosing de WindowAdapter realizando la acción adecuada, que, para el contenedor más externo, es salir al sistema. class ReceptorEvento extends WindowAdapter public void windowClosing(WindowEvent e) System.exit(O); WindowAdapter es una clase que proporciona implementaciones vacías de los métodos presentes en WindowListener y que resulta conveniente utilizar, pues evita tener que codificar los muchos métodos que requiere el uso de dicha interfaz. WindowListener public abstract void windowActivated(java.awt.event.WindowEvent pl) public abstract void windowClosed(]ava.awt.event.WindowEvent pl) public abstract void windowClosing(~ava.awt.event.WindowEventpi) public abstract void windowDeactivated(java.awt.event.WindowEvent pl) public abstract void windowDeiconified(java.awt.event.WindowEvent pl) public abstract void windowIconified(java.awt.event.WindowEvent pl) public abstract void windowOpened(java.awt.event.WindowEvent pl)
  • 242. lnterfaces gráficas de usuario 227 Los tipos WindowEvent se generan cuando una ventana cambia de estado y se procesan por los objetos que implementa la interfaz WindowListener. Ejemplo Un ejemplo de Frame que utiliza Graphics y permite el cierre de la ventana de la aplicación usando WindowAdapter es EjMarco. IBienvenido ai AWT I Figura 9.3. Escribir en un marco. import java.awt.*; import java.awt.event.*; public c l a s s EjMarco extends Frame i public s t a t i c void main( String args[] ) t new EjMarco ( ) ; public EjMarco ( ) t addWindowListener (new Cierre ( ) ) ; setTitle ("Marco"); setsize (200,100); setvisible (true) ; 1 public void paint (Graphics g) t Font letrero = new Font ("CancCerif", Font.ITALIC, 14); g.setFont (letrero); g.drawString("Bienvenido al AWT", 42,60); 1 c l a s s Cierre extends WindowAdapter I public void windowClosing (WindowEvent e) i I Cystem.exit (O); 1
  • 243. 228 Java 2. Manual de programación El ejemplo anterior sin la utilización de WindowAdapter es: import java.awt.*; import java.awt.event.*; public class EjMarco2 extends Frame implements WindowListener t public static void main( String args[] ) I new EjMarco2 ( ) ; i public EjMarco2 ( ) addWindowListener (this); setTitle ("Marco"); setsize (200,100); setvisible (true); public void paint (Graphics g) i Font letrero = new Font ("SansSerif", Font.ITALIC, 14); g.setFont (letrero); g.drawString ("Bienvenido al AWT",42,60); public void windowClosing(WindowEvent e) i System.exit (0); i public void windowActivatediWindowEvent e) i } public void windowClosed(WindowEvent e) t i public void windowDeactivated(W1ndowEvent e) I! public void windowDeiconified(Wind0wEvent e) t i public void windowIconified(WindowEvent e) i! public void windowOpened(WindowEvent e) t i
  • 244. hterfaces gráficas de usuario 229 9.5.2. Clase Dialog Los cuadros de diálogo son parecidos a las ventanas Frame, excepto porque no son el contenedor más externo, sino ventanas hijas de otras de nivel superior, y además no tienen barra de ineiiús. Estos objetos pueden ser redimensionados, desplazados y colocados en cualquier lugar de la pantalla, no estando su posición restringida al inte- rior de la ventana padre, pero no pueden ser maximizados ni minimizados. Figura 9.4. Cuadro de diálogo. A veces, cuando se muestra un cuadro de diálogo, lo que se persigue es que el usuario introduzca o tome alguna información y cierre dicho cuadro de diálogo antes de continuar, no se debe permitir el acceso a ninguna otra parte de la aplica- ción mientras tanto. Para conseguir esto, habrá que utilizar un cuadro de diálogo modal. En contraposición, los cuadros de diálogo sin modo dejan acceder a otras ventanas mientras se exhibe el cuadro de diálogo. Los constructores son: public Dialog (1ava.awt .Frame pl) El paráinetro pl es la ventana de nivel superior padre del cuadro de diálogo. public Dialog (java.awt .Frame p i , boolean pZ) El priiner paráinetro sigue siendo la ventana de nivel superior, mientras que p2 permite especificar si va a ser o no un cuadro de diálogo modal. public Dialog(]ava.awt.Frame pl, java.lang.Ctring p2) Este formato permite especificar el titulo del cuadro de diálogo que se está creando public Dialog(:ava.awt.Fraxe pl, java.lang.String p2, boolean p 3 ) Incluye el título y si es modal o no. Después de la creación, se puede establecer el tipo de cuadro de diálogo (modal o no modal) mediante el método public void setModal (boolean pl) Ejemplo Muestra el funcionamiento de Dialog.
  • 245. 230 Java 2. Manual de programación import java.awt.*; import java.awt.event.*; public class Dialogos public static void main( String args[]) t Marco elMarc0 = new Marco(); elMarco.setTitle ("Marco"); elMarco.setCize( 400,200 ) ; elMarco.setVisible( true ) ; elMarco.addWindowListener(new Cerrar()); Dialogo dialogoNoModa1 = new Dialogo(elMarco, dialogoNoModal.setBackground(Color.yel10~); dialogoNoModal.getGraphics0; / * setBounds coloca la esquina superior de: diálogo en la posición 100, 100 con respecto a su contenedor y establece su anchura en 300 pixels y su altura en 100 * / "Dialogo no modal", false); dialogoNoModal.setBounds(100,100,300,100); dialogoNoModal.addWindowListener(new Cerrar(dialogoNoModa1)); dialogoNoModal.setVisible(true); Dialogo dialogoModa1 = new aialogo (elklarco, diaiogoModal.setSize(300,iOO); dialogoModal.addWindowListener(new Cerrar(dialogoModa1)); dialogoModal.setVisible(true); "Dialogo modal", true); 1 class Marco extends Frame i public void paint (Graphics g ) Font letrero = new Font ("Courier", Font.BOLD, 12); g.setFont (letrero); g.drawString("Bienvenid0 ai AWT",24,70); ! class Dialogo extends Dialog Dialogo (Frame ventana, String titulo, boolean modo) super (ventana, titulo, modo) ; 1 public void paint (Graphics g)
  • 246. interfaces gráficas de usuario 231 i f (super.icModal ( ) ) g.drawstring ("Ciérreme para poder acceder" + "a otras ventanas", 10,40); else g.drawCtring ("Desde este cuadro puede acceder" + "a otras Ventanas", 10,40); } J c l a s s Cerrar extends WindowAdapter I Dialogo otroDialogo; Cerrar( Dialogo unDialogo ) i otroDialogo = unDialogo; I Cerrar ( ) otroDiaiogo = null; i public void windowclosing( WindowEvent evt ) t i f (otro3iaiogo ! = n u l l ) otroDialogo.dispose(); else System.exit (O); Llr;S@ 0'1n í u m u 11i ~ d 8dcceú~i3 01t.35 irF<nlarid: - J Figura 9.5. Cuadros de diálogo modales y no modales.
  • 247. 232 Java 2. Manual de programación Nota: Un cuadro de diálogo modal, mientras no se cierra, no permite el acce- so a ninguna otra parte de la aplicación. Los cuadros de diálogo sin modo dejan acceder a otras ventanas mientras se exhibe el cuadro de diálogo. 9.5.3. Clase FileDialog Estos cuadros de diálogo heredan de la clase Dialog,son modales por omisión y tienen ciertas capacidades incorporadas, como la de recorrer el árbol de directorios. El aspecto que presentan depende del sistema de manejo de ventanas, así como del subtipo de cuadro del que se trate: abrir archivos o guardar archivos, especificado en el constructor. Ejemplo El programa DialogoA permite seleccionar un archivo mediante un cuadro FileDialog (Fig. 9.6) y, si se selecciona alguno, muestra a continuación un diá- logo informativo con el nombre completo del archivo seleccionado (Fig. 9.7). 3Cei dDie tiDit 2Ve, alventanas1 Dialogos d larclal Mi PC Archivo CLASS Iioga4 & Disco de 3%[A 1 Archivo CLASS Archivo CLASS Archivo CLASS 1E Archivo CMCC 2: lulo CI libro Archivo CLASS -J ,.,,a Y Y l U l l l l l l l V I Ttana a m ID 1 Figura 9.6. Elección del archivo FileDialog.LOAD. Archivo P6tt@tC¡ondd Figura 9.7. Diálogo informativo.
  • 248. Interfaces gráficas de usuario 233 import java .awt .* ; import java.awt.event.*; public class DialogoA { public static void main ( String args [ ] ) i } Ventana ventanas = new Ventana ( ) ; 1 class Ventana i String msg=""; public Ventana ( ) t Frame elMarco = new Frame ( ) ; FileDialog dialogoArchivos = new FileDialog(elMarco, dialogoArchivos.setVisible(true); String nombre = dialogoArchivos.getFile(); String directorio = dialogoArchivos.getDirectory0; if (nombre != null) { "Elija archivo", FileDialog.LOAD); msg ="Archivo seleccionado: "t directorio t nombre; Dialogo2 dialogoModa1 = new Dialogo2(elMarco, dialogoModal.setSize(msg.length()*5+24,lOO); dialogoModal.addWindowListener(new Cerrar2(dialogoModal)); dialogoModal.setVisible(true); "Diálogo modal", true, msg) ; System.exit (O); 1 class Dialogo2 extends Dialog I String mensaje; Dialogo2 (Frame ventana, String titulo, boolean modo, String msg) { super (ventana, titulo, modo) ; mensaje = msg; 1 public void paint (Graphics g) I Font letrero = new Font ("Helvetica", Font.PLAIN, 10); g.setFont (letrero); g.drawString (mensaje,12,4O); }
  • 249. 234 Java 2. Manual de programación class Cerrar2 extends WindowAdapter { Dialogo2 otroDialogo; Cerrar2( Dialogo2 unDialogo ) otroDialogo = unDialogo; i public void windowClosing( WindowEvent evt ) I ) otroDialogo.dispose0; 9.6. CLASE Panel Los objetos de la clase Panel carecen de barra de título, barra de menús y borde, se emplean para almacenar una colección de objetos a los que de esta forma se organiza en unidades, no generan eventos y adquieren el tamaño necesario para que quepan los componentes que contienen. Esta clase es la superclase de Applet y su administrador de diseño por defecto es FlowLayout. Constructores public Panel ( ) Crea un nuevo panel. public Panel ( java .awt .LayoutManager pi ) Crea un nuevo panel y establece un determinado administrador de diseño para él. Por ejemplo: Panel pX = new Panel (new GridLayout ( ) ) ; Para destacar un panel se establece un determinado color de fondo para él. El panel se coloca en un contenedor mediante el método add y, como él también es un conte- nedor, se le pueden agregar componentes, incluidos otros paneles, mediante el método add. 9.7. CLASE Label Label extiende la clase Component y permite mostrar texto estático, es decir, texto que no puede ser modificado por el usuario, en una IGU. Para crear un rótulo con la clase Label es necesario declarar una referencia y llamar al constructor.
  • 250. interfaces gráficas de usuario 235 Constructores public Label ( ) Crea una etiqueta sin texto. public Label (java.lang.String p i ) Creaunaetiquetacuyotextoeslacadena pasada como parámetro. La cadena de caracteres que presenta la etiqueta puede modificarse con el método public synchronized void setText(java.lang.String p l ) y se devuelve mediante public java.lang.String getText() El procedimiento public synchronized void setAlignment (int pi) permite establecer la alineación del texto. El parámetro p l puede ser cualquiera de las siguientes constantes predefinidas: public static final int CENTER public static final ant LEFT public static final int RIGHT Como todos los componentes, las etiquetas se colocan en los contenedores median- te el método add de la clase Container. add (referencia-etiqueta) I Figura 9.8. Etiquetas, paneles. Empleo de colores de fondo para destacar los paneles.
  • 251. 236 Java 2. Manual de programación El siguiente ejemplo muestra cómo crear etiquetas y paneles y establecer colores de fondo. import java.awt.*; import java.awt.event.*; public class Paneles extends Frame i public Paneles ( ) t addWindowListener(new Cierre30 ) ; Panel pX = new Panel(); pX.setBackground(Color.black); Panel pY =new Panel ( ) ; pY.setBackground(Co1or.red); Label etiqueta1 = new Label ("Los paneles se adaptan") ; Label etiqueta2 = new Label ("a nuestro tamaño"); etiquetal.setBackground(Co1or.white); pY.add(etiqueta1) ; pY.add(etiqueta2); pX.add(pY); add (pX); public static void main( String args[l ) i Paneles ventana = new Paneles 0 ; ventana.setLayout(new FlowLayoutO); ventana.setTitle ( "El AWT" ) ; ventana.setSize( 300,120 ) ; ventana.setVisible(true); I 1 class Cierre3 extends WindowAdapter t public void windowClosing(WindowEvent e) t I System.exit (O) ; 1 9.8. CLASE Button Esta clase produce botones con etiqueta que provocan la ejecución de una acción cuando se efectúa clic en ellos con el ratón. La clase Button define los siguientes constructores:
  • 252. Interfaces gráficas de usuario 237 public Button ( ) Crea un botón sin etiqueta. public Button (java.lang .String p i ) Crea un botón cuya etiqueta es la cadena pasada como parámetro. y pone a disposición del programador una colección de métodos entre los que des- tacan public synchronized void addActionListener(java.awt.event.ActionListener pi) Añade un receptor de eventos semánticos public synchronized void removeActionListener(]ava.awt.event.ActionListener p i ) Elimina el receptor de eventos public java.lang.String getlabel() Devuelve la etiqueta del botón public synchronized void setLabel(java.1ang.String pi) Establece la etiqueta del botón Ejemplo Colocación de botones en un contenedor (Fig. 9.9). Los botones de este ejemplo no ejecutan ninguna acción. import java .awt .* ; import java.awt.event.*; public class Prueba extends Frame i public Prueba ( ) I addWindowListener(new Cierre30); Panel panelBotones = new Panel ( ) ; for (int i = 1; i < 8 ; i++) panelBotones.add (new Button ("Botón "+i ) ) ; /* Se utiliza el administrador de diseño por defecto en la clase Frame para colocar el panel en el área Sur * / add ( "South", panelBotones ) ; public static void main( String args[J ) i Prueba ventana = new Prueba ( ) ;
  • 253. 238 Java 2. Manual de programación ventana.setTitle ( "El AWT" ) ; ventana.setSize( 400,250 ) ; ventana.setVisible(true); 1 La clase Cierre3 ya fue implementada en el Apartado 9.7. Figura 9.9. Botones. Aunque la gestión de eventos se tratará en el Capítulo 10, es necesario advertir que, cuando se colocan botones en un contenedor, tienen como objetivo reaccionar ante su pulsación. Para que se pueda reaccionar ante la pulsación de un botón hay que enlazarlo a ActionListener, interfaz definida en awt .event con un único método a implementar denominado actionperformed, por lo que no necesita adaptadores. Este método tiene un parámetro del tipo ActionEvent,que puede informar a través del método getsource sobre el botón que ha sido pulsa- do, y deberá ser redefinido para establecer la reacción adecuada ante la pulsación de un determinado botón. El marco en uso será el responsable de la redefinición del método actionperformed. 9.9. CLASE Textcomponent La clase Textcomponent dispone de ina gran colección de métodos para fa ili- tar la presentación de texto en un programa IGU, pero no dispone de constructores públicos, por lo que no puede ser instanciada. Posee dos subclases, TextField y TextArea.TextField permite mostrar al usuario un area de una Única línea, mientras que TextArea presenta varias líneas. El texto mostrado, tanto en uno como en otro caso, puede ser editable o no.
  • 254. Interfaces gráficas de usuario 239 Los constructores de TextField son: public TextField ( ) Crea un campo de texto por defecto. public TextField (int pl) Crea un campo de texto con p 1 caracteres de ancho, este número de caracteres no define la anchura del campo, pues esto depende del tipo de letra y del administrador de diseño que se empleen. public TextField(java.1ang.String pi) Crea un campo de texto y lo inicializa con la cadena pl public TextField (java,lang.String pi, int p2) Crea un campo de texto, inicializándolo con la cadena p i y estableciendo su ancho a p2 caracteres. Otros métodos interesantes en el trabajo con campos de texto son: public synchronized java.lang.String getText0 Método de lectura. Obtiene la cadena contenida en un campo de texto. public synchronized void setText(java.lang.Ctring pi) Método de escritura. Establece el contenido de un campo de texto. public synchronized void select(int pl, int p2) Selecciona una serie de caracteres comenzando en pi y terminando en p2. public synchronized void selectAl1 ( ) Método para seleccionar todos los caracteres pertenecientes a Textcomponent. public synchronized java.lang.String getSelectedText0 Obtiene el texto previamente seleccionado. La selección previa pudo realizarse por la orden select o directamente por el usuario. public synchronized void setEditable (boolean pl) Controla la editabilidad del campo. public void setEchoChar (char pl) Sirve para introducir contraseñas, pues inhabilita el eco de los caracteres, exhibiendo en su lugar el carácter especificado como parámetro. En los cuadros de texto será necesario tratar el evento que se produce al pulsar la tecla RETURN. Este tratamiento consistirá en enlazar el campo de texto a la inter- faz ActionListener,y redefinir su método actionperformed,que tiene un parámetro capaz de informar sobre el campo de texto en el que ha sido pulsada la tecla RETURN (INTRO).
  • 255. 240 Java 2.Manual de programación Ejemplo Solicita el nombre y la edad del usuario mediante cuadros de texto. La edad se soli- cita con un cuadro «sin eco)),de forma que no se vea lo que se está tecleando. Tras la pulsación de RETURN en el cuadro edad, el programa transforma la cadena leída en un número, muestra dicha edad, y se disculpa por su falta de confidencialidad mediante la adición al mensaje de la palabra Joven".El ejemplo pretende resal- tar que los cuadros de texto no permiten la lectura directa de números. Utiliza repaint y responde a eventos. Intoduzca su nombre 5' lntoduzca la edad en añosy pulse <RETURN>a continuación Figura 9.10. Cuadros de texto. lntoduzca la edad en añosy pulse <RETURN>a continuación Joven de 86 años Figura 9.11. Salida mostrada por el programa
  • 256. lnterfaces gráficas de usuario 241 import java.awt.*; import java.awt.event.*; public class CTexto extends Frame implements ActionListener t int edad = 0; TextField texto2; public CTexto ( ) t addWindowListener(new Cierre30); Label etiqueta1 = new Label ("Introduzca su nombre"); add(etiqueta1); TextField texto1 = new TextField ( " " , 35); add(texto1); Label etiqueta2 = new Label ("Introduzcala edad en años" + add (etiqueta2); texto2 = new TextField("",2); textoZ.setEchoChar('*'); add (texto2); textoZ.addActionListener(this); "y pulse <RETURN> a continuación"); 1 public void paint (Graphics g) i try i edad = Integer.parseInt(texto2.getText( ) ) ; g.drawCtring ("Joven de "+edad+" años",24,150); 1 catch (Exception ex) t } 1 public void actionperformed (ActionEvent e) i if (e.getsource ( ) ==texto2) repaint ( ) ; i public static void main( String args[] ) I CTexto vt = new CTexto ( ) ; vt.setLayout (new FlowLayout 0 ) ; vt.setTitle( "El AWT" ) ; vt.setSize( 400,250 1 ; vt.setVisible(true); I i La clase TextArea efectúa la presentación de areas de texto en pantalla. Sus constructores y algunos otros métodos destacables son:
  • 257. 242 Java 2. Manual de programación public TextArea ( ) Crea un área de texto por defecto. public TextArea (int pl, int p 2 ) Crea un área de texto con p i filas y p2 columnas. public TextArea(java.1ang.String pl) Crea un área de texto y la inicializa con la cadena p i . public TextArea (lava.lang.String pi, int p2, int p 3 ) Crea un área de texto y la inicializa con la cadena p 1, estableciendo como número de filas p2 y como número de columnas p3. public synchronized java.lang.String getText0 Método de lectura. Obtiene el texto. public synchronized void setText(java.1ang.String pi) Método de escritura. Establece el contenido del área. public synchronized void append(j’ava.1ang.String pi) Añade cadenas a un área de texto. public synchronized void setEditable (boolean pi) Controla la editabilidad del campo. public synchronized java.lang.String getSelectedText() Obtiene el texto seleccionado. Pertenece a j ava .awt .TextComponent. Si el texto a mostrar no cabe en el número de filas o columnas visibles aparecen automáticamente barras de desplazamiento en la dirección adecuada para que se pueda acceder cómoda y rápidamente a toda la información. Figura 9.12. TextArea,el texto a mostrar no cabe en el número de filas ni de columnas visibles. Para capturar sus eventos, el objeto TextArea se enlaza a la interfaz TextListener y se sobrescibe el método textValueChanged. 9.10. CLASE Canvas La clase Canvas hereda de Component,encapsulando una ventana vacía o lien- zo, sobre el que se puede dibujar y que es capaz de recibir información por parte
  • 258. lnterfaces gráficas de usuario 243 del usuario en forma de eventos producidos por el ratón o el teclado. Los lienzos no generan eventos, sólo los reconocen. El constructor de Canvas no tiene pará- metros public Canvas ( ) Los lienzos no tienen un tamaño por omisión y es necesario adjudicárselo; si no se le adjudica, éste dependerá del administrador de diseño que se esté utilizando y podría llegar a ser demasiado pequeño o incluso invisible. El método empleado con esta finalidad pertenece a la clase Component y es public void setSize(int pl, int p2) import java.awt.*; import java.awt.event.*; public class VLienzo extends Frame i public VLienzo ( ) i addWindowListener (new Cierre3 ( ) ) ; Canvas 1 = new Canvas ( 1 ; 1.setsize (300,150); l.setBackground(Color.yel1ow); add(1); / / se establece un color de fondo para hacer resaltar el lienzo 1 public static void main ( String args [ ] ) VLienzo ventana = new VLienzo ( ) ; ventana.setLayout(new FlowLayoutO 1 ; ventana.setTitle ( "El AWT" ) ; ventana.setSize( 400,250 ) ; ventana.setVisible(true); Se puede observar tras la ejecución del ejemplo que en el lienzo creado no apa- rece ningún dibujo, sólo un fondo amarillo. Los Canvas heredan de Component el método paint,pero como ya se comentó anteriormente, para que este método haga algo es preciso redefinirlo y para ello es necesario crear una subclase de Canvas.Un ejemplo más completo sobre Canvas aparece en el apartado dedica- do a los administradores de diseño.
  • 259. 244 Java 2. Manual de programación 9.11. CLASE Choice Este tipo de componentes permite seleccionar una Única opción de entre una lista des- plegable de ellas (Fig. 9.13). Cuando se agregan a un contenedor, sólo muestran una determinada opción y una flecha que será la que permita escoger las restantes opcio- nes al efectuar clic sobre ella. El ancho que ocupan se establece automáticamente como el suficiente para mostrar las opciones incluidas en la lista. El constructor no tiene parámetros y crea una lista vacía: public Choice ( ) Las opciones son cadenas de caracteres y aparecen en el orden en que se añaden mediante el método public synchronized void addItem(java.1ang.String pi) A cada una de estas opciones le corresponderá un índice, de forma que el primer elemento añadido tiene índice O, el siguiente 1 y así sucesivamente. Los índices se pueden obtener con el método public int getSelectedIndex ( ) y estos números se utilizan frecuentemente como subíndices de vectores que con-, tienen información relativa a cada una de las opciones. Figura 9.13. La clase Choice antes y después de desplegar sus opciones. Otros métodos destacables son: public synchronized java.lang.String getSelectedItem() Devuelve una cadena con el nombre del elemento seleccionado. public synchronized void select (int pi) Permite especificar la elección por defecto. El evento de selección de una opción se tratará de la forma siguiente: se enlaza el objeto Choice a la interfaz ItemListener y se redefine su método itemstatelhanged,que tiene un parametro de tipo ItemEvent.
  • 260. lnterfaces gráficas de usuario 245 Ejemplo Construir un menú de opciones con el componente Choice, a continuación el usuario selecciona una opción y se presenta en la pantalla la opción seleccionada. i 1 ElementoseleccionadoDos Figura 9.14. Presentaciónde la opción seleccionada. import java.awt.*; import java.awt.event.*; public class EjChoice extends Frame implements ItemListener { private Choice selección; String elemento = ""; public EjChoice ( ) I addWindowListener(new Cierre30); selección = new Choice ( ) ; selección.addItem ( "Uno" ) ; selección.addItem ( "DOS" ) ; / * La Última opción se denomina Tercero en vez de Tres, para que se vea con mayor facilidad la anchura que adquieren los objetos Choice automáticamente * / selección.addItem ( "Tercero" ) ; //Opción preseleccionada selección.select (1); selección.add1temListener( t h i s ) ; add (selección); } public s t a t i c void main ( String args [ ] ) t EjChoice ventana = new EjChoice 0 ; ventana.setLayout(new FlowLayoutO ) ; ventana.setTitle ( "El AWT" ) ;
  • 261. 246 Java 2. Manual de programación ventana.setSize( 400,250 ) ; ventana.setVicible(true); 1 public void paint (Graphics g) I elemento = selección.getSelectedItern(); g.drawString ("Elemento seleccionado " + elemento, 20, 230); public void iternStateChanged(1temEvent e) i 1 repaint ( ) ; 9.12. CLASE Checkbox Las casillas de verificación son componentes IGU con dos estados posibles: activa- do (true) y desactivado (false). Están formadas por un pequeño cuadro que puede presentar o no una marca de verificación y una etiqueta descriptora de la opción (Fig. 9.15). r Casilla Verificación Figura 9.15. Casilla de verificación desactivada. Las casillas de verificación pueden utilizarse individualmente y también pueden agruparse en un CheckboxGroup. Los CheckboxGroup agrupan de 1 a n casillas de verificación de forma que no podrá haber varias activadas al mismo tiempo. El constructor de un grupo CheckboxGroup crea un grupo vacío y la forma de conseguir que las distintas casillas de verificación se añadan al grupo será especificar el nombre del grupo cuando se creen las casillas de verificación. La clase CheckboxGroup hereda de Object y no es un Component,por lo que los objetos CheckboxGroup no pueden agregarse a un contenedor, lo que se hará es añadir individualmente cada una de las casillas que constituyen el grupo. Dentro de los métodos para manejar este tipo de objetos citaremos. Constructor de un conjunto de un CheckboxGroup. public CheckboxGroup ( ) public Checkbox(java.lang.String p l , java.awt.CheckboxGroup p2, boolean p 3 ) Construye un Checkbox cuya etiqueta será la cadena especificada como pnmer parámetro, su estado (activado o desactivado) el tercer parámetro y lo agrega al CheckboxGroupespecifica- do como segundo parámetro, que debe haber sido previamente creado. El formato de las casi- llas de verificación cambia y se convierten en circulares.
  • 262. Interfaces gráficas de usuario 247 public Checkbox ( ) Crea un Checkbox vacío y no seleccionado. public Checkbox(java.lang.String pl) Crea un Chekbox no seleccionado cuya etiqueta es la cadena pasada como parametro. public Checkbox (java.lang.String pl, boolean p2) Crea un Chekbox cuyo estado inicial, seleccionado o no seleccionado, dependerá de lo especificado como segundo parámetro y cuya etiqueta es la cadena pasada como primer parámetro. public java.awt.Checkbox getSelectedCheckbox0 Determina dentro de un grupo el objeto Checkbox seleccionado. public boolean getstate0 Obtiene el estado del Checkbox. public java.lang.String getlabelo Obtiene la etiqueta de un Checkbox. Para tratar el evento de selección de una opción, se siguen lo mismos pasos que se expusieron en el caso de Choice. Ejemplo Creación de un CheckboxGroup que trata el evento de selección de una opción. ............................................... C Primera opción 6 !se.ci!.nd.a..oP.c!4!; r Tercera opción C Cuarta opción Elemento seleccionado Segunda opción Figura 9.16. CheckboxGroup,el formato de las casillas de verificación cambia y se convierten en circulares.
  • 263. 248 Java 2. Manual de programación import java.awt.*; import java.awt.event.*; public class EjCheckboxGroup extends Frame implements ItemListener i private Checkbox opl, op2, Op3, Op4; private CheckboxGroup menu; public EjCheckboxGroup ( ) i addWindowListener(new Cierre30); menu = new CheckboxGroup ( ) ; opl = new Checkbox ("Primera opción", menu, false); op2 = new Checkbox ("Segunda opción", menu, false); op3 = new Checkbox ("Tercera opción", menu, false); op4 = new Checkbox ("Cuarta opción", menu, false); add(op1); add (op2); add (Op3); add(op4); opl.addItemListener(this); op2.addItemListener(this); op3.addItemListener(this); op4.addItemListener(this); I public static void main( String args[] ) I EjCheckboxGroup ventana = new EjCheckboxGroup ( ) ; ventana.setLayout (new GridLayout (3,2)) ; ventana.setTitle ( "El AWT" ) ; ventana.setSize( 400,250 ) ; ventana.setResizable(fa1se); ventana.setVisible(true); / * Redefinir el método getInsets de la clase Container es una forma de conseguir que los componentes que situemos en un contenedor queden ligeramente separados del borde del mismo. Los valores que especifiquemos en getinsets los utilizarán los administradores de diseño a la hora de colocar compo- nentes en el contenedor * / public insets getInsets ( ) i 1 return new Insets(20,20,20,20); public void paint (Graphics g ) I if (menu.getSelectedCheckbox ( ) ! = null) g.drawstring ("Elemento seleccionado 'I+ menu.getSelectedCheckbox().getLabel(),20,230);
  • 264. Interfaces gráficas de usuario 249 public void itemStateChanged(1temEvent e) I 1 repaint ( ) ; 1 Compilación C:libroTema09>javac EjCheckboxGroup.java Ejecución C:libroTema09>java EjCheckboxGroup 9.13. LISTAS La clase L i s t proporciona listas donde se pueden realizar selecciones múltiples. Si todos los elementos de una lista no caben en el número de filas visibles, aparece automáticamente una barra de desplazamiento para que se pueda acceder a los res- tantes elementos de la lista; sucede, de modo análogo, si el número de caracteres de alguna de las opciones supera el número de columnas visibles. Enero 1Febrero Agosto Octubre INoviembre Figura 9.17. Lista cuyos elementos no caben en el número de filas visibles y con varias opciones seleccionadas: Marzo, Abril, Julio. Los constructores de una lista son: public List ( ) Crea una lista que no permite selecciones múltiples. public List(int pi) Crea una lista con tantas filas visibles como especifique el parámetro pl y que no admite selecciones múltiples.
  • 265. 250 Java 2. Manual de programación public List (int pl, boolean p2) Crea una lista con tantas filas visibles como indique el parámetro p i y que admitirá o no selecciones múltiples según sea true o falseel valor que le pasemos como parámetro p2. Para añadir nuevas opciones a una lista se emplea: public void add(java.lang.String pl) Otros métodos útiles son: public synchronized java.lang.String getSelectedItem() Devuelve una cadena con el nombre del elemento seleccionado, si no se selecciona ningún elernento o se selecciona más de uno devuelve nu11. public synchronized int getSelectedIndex0 Devuelve el índice del elemento seleccionado.AI primer elemento de la lista le corresponde un cero, al siguiente un uno y así sucesivamente. Si hay más de un elemento seleccionado o aún no se ha seleccionado ninguno, devuelve -1. public synchronized void select (int p l ) Permite especificar la elección por defecto. public synchronized java.lang.String[] getSelectedItems0 Se emplea para tratar selecciones múltiples, devolviendo un vector de cadenas que contiene los nombres de los elementos seleccionados. public synchronized int[] getSelectedIndexes0 Se utiliza para tratar selecciones múltiples, devolviendo un vector de enteros con los índices de los elementos seleccionados. En una lista se han de considerar dos tipos de eventos; si se efectúa doble clic con el ratón sobre un elemento de la lista se produce un ActionEvent; si se efec- túa un único clic sobre los elementos de la lista, se produce un ItemEvent.Para tratar el suceso ActionEvent se necesita enlazar el ,objeto List a la interfaz ActionListener y sobreescribir actionperformed,y para tratar el suceso ItemEvent es necesario enlazarlo a ItemLictener y sobreescribir itemStateChanged. Ejemplo Este programa permite efectuar selecciones múltiples en una lista con las siguien- tes características: Efectuando clic con el botón izquierdo del ratón sobre elementos no seleccio- Si efectúa clic sobre un elemento seleccionado, lo elimina de la selección. nados, los selecciona.
  • 266. Interfaces gráficas de usuario 251 Selección. Elemento 1 Elemento 4 Figura 9.18. Resultado de la ejecución del programa ejemplo de listas. El marcado y desmarcado de los elementos podrá efectuarse tantas veces como se quiera (Fig. 9.18). Para terminar el proceso de selección múltiple, deberá efec- tuar doble clic sobre un elemento aún no seleccionado de la lista, el cual, con ésta operación, también se añadirá a la selección. Si efectúa doble clic sobre un elemento previamente seleccionado, también terminará el proceso de selección, pero este último elemento no se añadirá a la misma. import java.awt.*; import java.awt.event.*; public class EjLista extends Frame implements ItemListener, ActionListener i private List lista; public EjListaO addwindowlistener (new Cierre3 ( ) ) ; lista = new List(5,true); for (int i = 1; i < 8; i++) lista.add("Elemento "+i); lista.addActionListener(this); 1icta.addItemListener (this); add(1ista) ; 1 public static void main ( String args [ ] ) EjLista ventana = new EjListaO; ventana.setLayout (new FlowLayout ( ) ) ; ventana.setTitle ( "El AWT" ) ; ventana.setCize( 400,250 ) ; ventana.setVisible(true);
  • 267. 252 Java 2. Manual de programación public void paint (Graphics g) I String arr [I = 1ista.getSelectedIterns( ) ; int alto = g.getFontMetrics ( ) .getHeight( ) ; if (arr.length ! = O) { g.drawString ("Selección: ' I , 20,250-alto*8); for (int i = O; i < arr.length; i++) g.drawString(arr[i],20,250-alto* (7-i)) ; 1 1 public void actionPerformed(ActionEvent e) { if (e.getSource0 == lista) repaint ( ) ; 1 public void iternStateChanged(1ternEvent e) t 1 9.14. CLASE Scrollbar Las barras de desplazamiento son componentes que recorren valores enteros y pue- den estar orientadas horizontal o verticalmente (Fig. 9.19). Figura 9.19. Barra de desplazamiento. Constructores public Scrollbar ( ) Crea una barra de desplazamiento vertical. public Scrollbar (int pi) Crea una barra de desplazamiento en la dirección indicada por el parámetro p1: Scrollbar.HORIZONTALoScrollbar.VERT1CAL.
  • 268. Interfaces gráficas de usuario 253 public Scrollbar (int pl , int p2, int p 3 , int p 4 , int p5) Crea una barra de desplazamiento en la dirección que se le indique mediante el parámetro p l , con el valor inicial especificado en p2 (el cuadro de desplazamiento aparecerá inicial- mente en esta posición), cuyo tamaño para el cuadro de desplazamiento es el tercer paráme- tro y con los valores mínimo y máximo que contengan los parámetros p4 y p5. Si el valor inicial es menor que el mínimo o mayor que el máximo, el valor inicial se hará igual al míni- mo o máximo respectivamente. Otros métodos necesarios para trabajar con barras de desplazamiento son: public synchronized void setvalues(intpl, int p2, int p3, int p 4 ) Establece los parámetros para una barra de desplazamiento. public int getMaximum() Devuelve el valor máximo. public int getMinimum ( ) Devuelve el valor mínimo. public int getvalue ( ) Obtiene el valor actual de la barra. public synchronized void setvalue (int pl) Establece el valor actual. Ejemplo Crea una barra de desplazamiento horizontal (Fig. 9.20). import java.awt.*; import java.awt.event.*; class EjBarra extends Frame { public EjBarra ( ) ' ( Scrollbar barra = new Scrollbarí Scrollbar.HORIZONTAL, 100,o, o, 200); Frame v = new Frame( "El AWT" ) ; v.add ("North", barra ) ; v.setSize( 200,200 ) ; v.setVisible( true ) ; v.addWindowListener( new Cierre3 ( 1 public static void main( String args ( } new E] Barra ( ) ; 1 '
  • 269. 254 Java 2. Manual de programación La salida del programa anterior es la mostrada en la Figura 9.20. I Figura 9.20. Resultado de la ejecución del ejemplo. Cada vez que se mueve el cuadro de desplazamiento se genera un evento del tipo AdjusmentEvent, que debe ser recogido por el receptor AdjustmentListener,por lo que se enlazará el objeto a la interfaz corres- pondiente y se sobreescibirá el método adjustrnentvaluechanged. 9.15. MENÚS Menucomponent es la superclase de todos los elementos relacionados con los menús, siendo subclases suyas tanto MenuItem como MenuBar. MenuItern contiene los métodos para crear los elementos de un menú. La clase MenuBar con- tiene el constructor de barras de menú. Las barras de menú actúan como contene- dores de menús. La clase Menu es una subclase de MenuItem y proporciona métodos para la administracción de los menús. Los menús contienen elementos de menú y se agregan a barras de menú. Cuando se selecciona un elemento de un menú se genera un evento del tipo ActionEvent,que se tratará de forma análoga a como se ha explicado en otras ocasiones. Los elementos se añaden al menú mediante el método add y los menús a la barra de menús de la misma forma, pero la adición del menú a un marco se efectúa con: public synchronized void setMenuBar(java.awt.MenuBar pl) Constructores public MenuBar ( ) Construye la barra de menús.
  • 270. lnferfaces gráficas de usuario 255 public Menu (Java.lang.String pl) Construye el menú, recibe como parámetro el nombre del menú. Crea un elemento de menú, recibe como parámetro el nombre de la opción public MenuItem(java.1ang.String pl) Ejemplo Pasos a seguir para la creación de un menú que responda a eventos: Figura 9.21. Menús. / / Frame con barra de menú. import java.awt.*; import java.awt.event.*; public class EjMenu extends Frame implements ActionListener i public EjMenu ( ) t addWindowListener (new Cierre3 ( ) ) ; setTitle ("Marco"); MenuBar mb = new MenuBar ( ) ; Menu m = new Menu ("Archivo"); MenuItem abrir = new MenuItem("Abrir archivo"); MenuItem cerrar = new MenuItem ("Cerrar archivo"); abrir.addActionListener(this); cerrar.addActionListener(this); m.add(abrir) ; m.add(cerrar) ; mb.add (m); setMenuBar (mb); setsize (200,100); setVisible(true); 1 public void actionPerformed(ActionEvent e) t System.out.println(e.getSource());
  • 271. 256 Java 2. Manual de programación public static void main ( String args [ ] ) I new EjMenu ( ) ; 9.16. ADMINISTRADORES DE DISEÑO Java tiene cinco administradores de diseño que controlan la ubicación de los componentes añadidos a un contenedor y, cuando el usuario redimensiona el contenedor, estos administradores intentan reajustar dichos componentes en la nueva área. Los más importantes son: FlowLayout, BorderLayout y GridLayout.Para incorporar un administrador de diseño se utiliza la siguiente sentencia: setLayout (new NombreGestor(parámetros)) ; y cuando se desee no usar un administrador se pasa null al método setlayout; en este caso habrá que colocar y dimensionar los componentes de forma manual, para lo que se puede utilizar el método public void setBounds(int p l , int p2, int p 3 , int p4) en el que los parámetros p l y p2 representan la posición, en pixels, del extremo superior izquierdo del componente con respecto a su contenedor, mientras p 3 y p4 son la anchura y altura del objeto respectivamente. Cuando se quiere dejar un pequeño borde entre un contenedor y los componen- tes que situamos en él se puede recurrir a redefinir el método getinsets de la clase Container,especificando en él la cantidad de espacio que se desea reser- var para dicho borde. Estos valores serán tenidos en cuenta por el administrador de diseño correspondiente cuando vaya a colocar los componentes en el contenedor. Un ejemplo de getinsets aparece en el apartado que comenta la clase Checkbox. Las características de los administradores de diseño fundamentales se detallan a continuación. 9.16.1. FlowLayout Utiliza la interfaz LayoutManager y es el administrador de diseño que usan por omisión los paneles y las applets. Cuando se utiliza FlowLayout los componentes se colocan en el contenedor de izquierda a derecha en el orden en el que van siendo agregados y, cuando no caben más en una fila, continúan colocándose en la siguiente.
  • 272. lnterfaces gráficas de usuario 257 Los constructores son: public FlowLayout ( ) public FlowLayout ( i n t pi) Construye un FlowLayout por defecto, que centra los componentes, dejando 5 pixeles de espacio entre cada uno de ellos. Construye un FlowLayout y mediante el parámetro permite especificar el alineamiento. Son valores válidos para dicho pa- rámetro. FlowLayout.LEFT FlowLayout.CENTER FlowLayout.RIGTH public FlowLayout ( i n t pl, i n t p 2 , i n t p 3 ) Construyeun FlowLayout de forma que se pueden especifi- car tanto el alineamiento como el espacio horizontal y vertical a dejar entre los componentes. El diseño se establece mediante s e t l a y o u t . Por ejemplo: setLayout (new FlowLayout (FlowLayout.LEFT)) La adición de componentes se efectúa empleando el método add. 9.16.2. BorderLayout Es el administrador de diseños por defecto para los cuadros de diálogo y los mar- cos y se caracteriza por acomodar a los componentes en cinco areas: North, South, E a s t , West y C e n t e r , especificadas en el orden en el que dichas áreas son dimensionadas. I South I Figura 9.22. BorderLayout: áreas. Es posible usar, por tanto, de uno a cinco componentes con BorderLayout, uno para cada posición, y, excepto en el caso de Center, cuando alguna posición no es usada la zona correspondiente será ocupada por los otros componentes.
  • 273. 258 Java 2. Manual de programación Si no se usa North ni south,quedaría así. Si no se usa North,ni south,ni East. Figura 9.23. BorderLayout cuando no se usan algunas posiciones. Sus constructores son: public BorderLayout ( ) Construye un BorderLayout. public BorderLayout (int pl, int p2) Construye un BorderLayout separando cada área horizontal y verticalmente el número de pi- xeles indicados como argumento. Estableciéndose el diseño de la siguiente forma: setLayout (new BorderLayout ( ) 1 setLayout (new BorderLayout (pi, p2) ) para situar un componente en una determinada posición se incluye la posición o área en el método add : public java.awt.Component add(java.lang.String pl, java.awt.Component p2) el primer parámetro es la posición, cuyo nombre (North, South, East, West o Center) debe comenzar siempre por mayúscula y, puesto que el área ha de especificarse, los componentes podrán agregarse en cualquier orden. 9.16.3. GridLayout Divide el contenedor en una cuadrícula que permite colocar los componentes en filas y columnas, concediendo el mismo tamaño a todos ellos. Dichos componentes se agregan a la cuadrícula ocupando la primera fila de izquierda a derecha y pasando a continuación a ocupar, en el mismo sentido, la fila siguiente y así sucesivamente. Los constructores de GridLayout son: public GridLayout(int pi, int p2) Construye un GridLayout con el número de filas especificado como primer parámetro y el número de columnas especificado como segundo parámetro. public GridLayout (int pl, int p2, int p3, int p4) Construye un GridLayout con el número de filas especificado como primer parámetro y el número de columnas especificado como segundo parámetro y cada componente separado horizontalmente por p 3 pixeles y verticalmente por p4.
  • 274. Interfaces gráficas de usuario 259 El diseño se establece mediante: setLayout (new GridLayout (pl, p2) ) setLayout (new GridLayout (pl, p2, p3, p4) ) y la adición de componentes se realiza con add: public java.awt.Cornponent add(java.awt.Cornponent p l ) Nota: Redeñnir cl =¿todo getinsets de la clase Container sirve para $esque secdoquenea uncontenedorquedenlige- íi8lmisrrns. €jemplo En este ejemplo se muestra el comportamiento de los administradores de diseño y dis- tintos componentes del AWT. Pero no incluye la gestión de eventos, excepto la del even- to de cierre que se produce cuando se hace clic en el icono de salida de la ventana. Figura 9.24. Ejemplo sobre el comportamiento de los administradores de diseño.
  • 275. 260 Java 2. Manual de programación import java .awt .* ; import java.awt.event.*; public class Ventanas extends Frame t public Ventanas ( ) I addWindowListener (new Cierre3 ( ) ) ; Panel panelBotones = new Panel ( ) ; Panel panelcentral = new Panel ( ) ; MenuBar mb = new MenuBar ( ) ; Menu m = new Menu ( "Menú" ) ; m.add( new MenuItem( "Opción 1" ) ) ; m.add( new MenuItem( "Opción 2" ) ) ; m.add( new MenuItem( "Opción 3" ) ) ; mb.add( m ) ; setMenuBar( mb ) ; panelBotones.add ( new TextField ( "Campo de Texto" ) ) ; panelBotones.add ( new Button ( "Botón" ) ) ; panelBotones.add( new Checkbox ( "Casilla Verificación" ) ) ; Choice selección = new Choice ( ) ; selección.addItem ( "1" ) ; selección.addItem ( "2" ) ; selección.addItem ( "3" ) ; panelBotones.add( selección ) ; //Se utiliza GridLayout para dividir el contenedor panelcentral.setLayout ( new GridLayout ( 2 , l ) ) ; //se coloca el dibujo Dibujo d = new Dibujo ( ) ; d.setBackground(Color.yel1ow); panelCentral.add(d); / / se colocan la etiqueta y el área de texto Panel p = new Panel ( ) ; p.setLayout ( new BorderLayout ( ) ) ; p.add ( "North",new Label ( "Etiqueta",Label.CENTER ) ) ; TextArea Texto= new TextArea ("Puede escribir aquí + for ( i n t i=l; i<=12; it+) Texto.append (i+"n"); p.add ( "Center",Texto ) ; panelCentral.add( p ) ; "el texto que deseen") ;
  • 276. Interfaces gráficas de usuario 261 /*se utiliza BorderLayout para acomodar los componentes en las distintas áreas * / setLayout ( new BorderLayout ( ) ) ; add ( "South",panelBotones ) ; add ( "Center",panelcentral ) ; List lista = new List(); lista.add( "Mercurio"); 1ista .add ( "Venus" ) ; lista.add ( "Tierra"); lista.add ( "Marte"); lista.add( "JÚpiter"); lista.add ( "Saturno"); lista.add ( "Urano"); lista.add ( "Neptuno"); lista.add( "Plutón"); add( "East",lista ) ; 1 public s t a t i c void main( String args[] ) i Ventanas ventana = new Ventanas ( ) ; ventana.setTitle ( "El AWT" ) ; ventana.setSize( 400,250 ) ; ventana.setVisible(true); 1 1 //Subclase de Canvas class Dibujo extends Canvas I public void paint( Graphics g ) { i n t ancho = getsize0 .width; i n t alto = getsize0 .height; Font fuente = g.getFont ( ) ; i n t tamañoletra = fuente.getsize ( ) ; g.drawString ( "Los planetas", (ancho-g.getFontMetrics ( ) . g.drawOval(l,l+tamañoLetra,ancho-2,alto-tamañoLetra-2 ) ; g.fill0val(ancho/4,tamañoLetra+alto/6,ancho/2, (alto- stringWidth("Los planetas") ) /2,10 ) ; tamañoletra)/ 2 ) ; 1 1 Otros administradores de diseño son: GridBagLayout,parecido a GridLayout pero admitiendo que los componentes ocupen varias celdas, y CardLayout,que crea una organización con tarjetas.
  • 277. 262 Java 2. Manual de programación java . awt . 9.17. swing Component java.awt.Container El paquete swing extiende el awt,añade nuevos componentes e incorpora dos administradores de diseño más. La superclase de los componentes swing es la clase JComponent,que deriva de la clase estándar Container y, por tanto, des- ciende también de la clase Component del awt,de esta jerarquía se deduce que todos los componentes swing son contenedores (Fig. 9.25). Entre las novedades aportadas por j avax .swing destacan las ventanas con pestañas, el hecho de poder añadir bordes así como asociar un texto de ayuda a cualquier componente. Además, los componentes swing se ejecutan uniformemente en cualquier plata- forma. Hay que tener en cuenta que, en muchas ocasiones, los nombres de los com- ponentes en ambos paquetes casi coinciden, diferenciándose únicamente en que los de swing anteponen una J,y la forma de trabajo también, facilitándose así el paso de awt a swing. Figura 9.25. Jerarquía de clases: la clase JComponent.
  • 278. - 10 Gestión de eventos CONTENIDO 10.1. Tipos de eventos. 10.2. Los componentes del AWT como fuente de eventos. 10.3. Receptores de eventos. 10.4. Procesamiento de eventos. 10.5. Clases adaptadoras. 10.6. Clases receptoras anónimas. 10.7. Problemascomunes en el tratamiento de eventos. 263
  • 279. 264 Java 2. Manual de programación Los usuarios pueden comunicarse con los programas a través de los objetos visuales que ofrecen las InterfacesGráficasde Usuario (IGU). Cuando se trata del paquete awt la comunicación se pro- duce de la siguiente forma, los distintos componentes del AWT son capaces de detectar eventos de una determinada clase y notificar esta acción a un objeto receptor. Si el receptor recibe el aviso de que ha ocurrido determinado suceso, llama a un método, redefini- do por el programador, que ejecuta las acciones deseadas. Por otra parte, Swing proporciona nuevostipos de eventos pero el pro- cesamiento de los mismos es análogo al comentado anteriormen- te. En este capítulo se comentan los diferentes tipos de eventos del AWT,así como los problemas que se presentan en el procesa- miento de los mismos. 10.1. TIPOS DE EVENTOS La programación GUI es una programación dirigida por eventos que implica la necesidad de procesar los mismos y, por tanto, la utilización de las clases propor- cionadas por el paquete j ava .awt .event que definen los tipos de eventos del AWT. Jerarquía de clases Figura 10.1. Clases proporcionadas por el paquete j ava .awt .event Lajerarquía de clases conduce a una división de los eventos en dos categorías fun- damentales, de bajo nivel, subclase de ComponentEvent,y semánticos, colegas de
  • 280. Gestión de eventos 265 ComponentEvent.No obstante, la programación de los eventos de ambas cate- gorías es similar y su principal diferencia reside en la naturaleza del objeto evento y la información que es capaz de proporcionar. Los eventos de bajo nivel ofrecen acceso al componente que ha generado el evento y, con él, acceso a los métodos de la clase Component mediante el método: public java.awt.Component getComponent0 Los eventos semánticos proporcionan diferentes métodos para obtener una refe- rencia al objeto que ha generado el evento. Por ejemplo, en ActionEvent se puede obtener la etiqueta identificativa del objeto fuente mediante public java.lang.Ctring getActionCommand0 mientras que en ItemEvent debiera utilizarse public java.awt.ItemCelectable getItemSelectable0 Nota: Si no se desea recordar métodos específicos es posible recurrir al método public java.lang.0bject getsource0 perteneciente a la clase java.uti1.Eventobject,situada muy arriba en la jerarquía; como consecuencia, este método puede ser utilizado con todo tipo de eventos, 10.2. LOS COMPONENTES DEL AWT COMO FUENTE DE EVENTOS Los distintos componentes del AWT son capaces de actuar como fuente de even- tos, es decir, como objetos capaces de detectar eventos de una determinada clase y, para conocer los eventos que pueden ser detectados por cada uno de ellos, hay que tener en cuenta tanto la siguiente tabla como la jerarquía de cla- ses del AWT.
  • 281. 266 Java 2. Manual de programación Tabla 10.1. Fuentes de eventos Fuente Clase de evento B u t t on L l S t Y e r.u I ten T e x t F i e l d A c t i o n E v e n t A c t i o n E v e n t A c t i o n E v e n t A c t i o n E v e n t S c r o l l B a r AdjustrnentEvent Cornpor.e nt CornponentEvent C o n z a i n e r C o n t a i n e r E v e n t Conponent FocucEvent Checkbox CheckboxMen~dItern Choice L;ct I ternEvent I ternEven t IternEvent I ternEvent Corrponenr K e y0ver,t Cunponent MouseEvent T e x t A r e a T e x t F i e l d T e x t E v e n t T e x t E v e n t D;alog WindowEvent Frame WindowEvent 10.3. RECEPTORES DE EVENTOS Las clases de nivel más bajo dentro de los distintos subárboles a considerar en lajerarquía de eventos tienen una interfaz ((oyente))asociada, excepto MouseEvent que tiene dos, con un único método o bien un conjunto de métodos declarados en ellas para tratar los eventos de las mismas y los receptores de eventos son clases que imple- mentan interfaces oyentes específicas. Clase de evento Interfaz I A r t i o n E v e n t I A c t 1 onLi s tener ~ct i o n L i st e n e r , métodos: public abstract void actionPerformed(java.awt.event.ActionEvent pl)
  • 282. Gestión de eventos 267 ItemEvent Clase de evento Interfaz ItemListener 1 1 AdjustmentEvent 1 Ad] ustmentlistener 1 A d j ustmentListener, métodos: public abstract void adjustment~a:ueChanged(~ava.awt.event.Adjustme~~tEventpl) Clase de evento Interfaz 1 ComponentEvent 1 ComponentListener ComponentListener, métodos: public abstract void componentHidden(~ava.awt.event.ComponentEvent pl) public abstract void componentMoved(java.awt.event.ComponentEvent pl) public abstract void componentResized(]ava.awt.event.ComponentEVent p i ) public abstract void componentShown(]ava.awt.event.ComponentEvent pZ) Clase de evento Interfaz ContainerEvent 1 ContainerListener ContainerListener, rne'todos: public abstract void cornponentAdded(java.awt.event.ContainerEvent pl) public abstract void componentRemoved(java.awt.event.ContainerEvenc pl) Clase de evento Interfaz 1 FocusEvent 1 FocusListener I FocusList ener, public abstract void focusGained(java.awt.event.FocdsEve~tpi) public abstract void f o c u s L o s t ( ~ a v a . a w t . e v e n t . F o c ; s E v e n t pl) métodos: ItemListener, métodos: public abstract void itemCtateChanged(java.awt.event.1temEvent pl)
  • 283. 268 Java 2. Manual de programación MoxseEvenc i Clase de evento Interfaz MouceLictener MouceMotionLictener 1 KeyEvenr. 1 KeyListener I TextEvent KeyLis t e n e r , métoclos: public a b s t r a c t void keyPressed(java.awt.event.KeyEvent pl) public abstract void keyReleased(;ava.awt.event.KeyEvent pl) public abstract void keyTyped(java.awt.event.KeyEvent pl) TextListener ~ MouceLic tener , métodos: public a b s t r a c t void public a b s t r a c t void public abstract void public a b s t r a c t void public abstract void MoLIseMot ioI:Li s t ener , public abstract void public abstract void Clase de evento mouseClicked(java.awt.event.MouseEvent pl) mouseEntered(java.awt.event.MouseEvent pl) mouseExited(java.awt.event.MouseEvent pl) mousePressed(~ava.awt.event.MouseEventpl) mouseReleased(java.awt.event.MouseEvent pl) métodos: mOuSeDragged (1ava.awt .event.MouseEvent pi) mouceMoved(java.awt.event.MouseEvent pl) Interfaz Text Lis tener , public abstract void textValueChanged(java.awt.event.TextEvent pl) WlétOdOS: Clase de evento Interfaz WindowEvent1 I WindowListener WinciowLi s tener , métodos: public abstract void windowActivated(java.awt.event.WindowEvent pl) public abstract void windowClosed(java.awt.event.WindowEvent pl) public abstract void windowClosing(java.awt.event.WindowEvent pl) public abstract void windcwDeactivated(java.awt.event.WindowEvent p l ) public abstract void windowDeiconified(~ava.awt.event.WindowEventpl) public abstract void windowIconified(java.awt.event.WindowEvent pl) public a b s t r a c t void windowCpened(java.awt.event.WindowEvent pl)
  • 284. Gestión de eventos 269 10.4. PROCESAMIENTO DE EVENTOS Para el procesamiento de eventos, hace falta que un objetofuente capaz de detectar eventos de una determinada clase, notifique a un objeto receptor que se ha produ- cido un evento de la clase que dicho receptor es capaz de interpretar y, para ello, dicho receptor debe implementar una interfaz «oyente», asociada a un determinado tipo de suceso, sobreescribiendo cada uno de sus métodos, y registrarse con la fuen- te. Cuando el receptor recibe el aviso de que ha ocurrido un suceso llama al méto- do correspondiente al evento particular generado, sobreescrito por el programador, que ejecuta las acciones deseadas. Ejemplo Presentar las coordenadas de la posición donde se pulse el ratón dentro del área de un marco. El programa termina cuando se cierra la ventana. Pnsicidn del ratdn: 60, 40 Figura 10.2. MousseEvent. - import java.awt.*; import java.awt.event.*; public class Marco extends Frame { int x = O, y = O; public static void main( String args[] ) t Marco fuente = new Marco fuente.setTitle ("Marco"); fuente.setCize(250,lOO); fuente.setVisible(true); //se instancian y regist. 1 ; in los receptores fuente.addWindowListener(new ReceptorCierreO); fuente.addMouseListener(new ReceptorRaton(fuente)); public void paint (Graphics g) t g.drawString ("Posición del ratón: "ixt", "+y,60,40);
  • 285. 270 Java 2.Manual de programación / * Las clases receptoras implementan oyentes y sobreescriben * / sus métodos class Receptorcierre implements WindowListener public void windowClosing(WindowEvent e) i i 1 System.exit (O); public void windowActivated(WindowEvent e) t i public void windowClosed(WindowEvent e) 0 public void windowDeactivated(WindowEvent e) i 1 public void windowDeiconified(WindowEvent e) i } public void windowIconified(Wind0wEvent e) i 1 public void windowOpened(WindowEvent e) i } class ReceptorRaton implements MouseListener 1 Marco laventana; ReceptorRaton(Marco fuente) i laventana = fuente; 1 public void mousepressed (MouseEvent e) laventana.x = e.getX ( ) ; laventana.y = e.getY ( ) ; laventana.repaint0; 1 public void rnouseReleased(MouseEvent e) o public void rnouseEntered(M0useEvent e) i 1 public void mouseExited (MouseEvent e) t ) public void mouseClicked(MouseEvent e) i } 1
  • 286. Gestión de eventos 271 Otra forma de implernentación podría haber sido: import java.awt.*; import java.awt.event.*; public class Marco2 extends Frame implements WindowListener, MouseListener { int x = O, y = O; Marco2 ( ) ( setTitle ("Marco"); setsize (250,100); setvisible (true); //se registra el receptor addWindowListener(this); addMouseListener(this) ; 1 public static void main ( String args [I ) i 1 i 1 Marco2 fuente = new Marco2 ( ) ; public void paint (Graphics g ) g.drawCtring ("Posición del ratón: "tx+", "+y,60,40); public void windowClosing (WindowEvent e) t System.exit (O); public void windowActivated (WindowEvent e) i l public void windowClosed(WindowEvent e) { I public void windowDeactivated(WindowEvent e) { I public void windowDeiconified(WindowEvent e) { I public void windowIconified(WindowEvent e) i } public void windowOpened(WindowEvent e) i ) public void mousePressed(MouseEvent e) i x = e.getX(); y = e.getY(); repaint ( ) ; I
  • 287. 272 Java 2. Manual de programación public void mouseReleased(MouseEvent e) public void mouseEntered (MouseEvent e) public void mouseExited(MouseEvent e) public void mouseClicked(MouseEvent e) i } { I i } 1 En cuanto a swing,hay que destacar que aunque proporciona nuevos tipos de eventos el procesamiento de los mismos es análogo al estudiado. Los programas que utilicen swing deberán incorporar las siguientes sentencias: import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swinq.event.*; En versiones anteriores, swing ha usado otros nombres de paquetes: corn.sun.java.swing java.awt.swing + 10.5. CLASES ADAPTADORAS Dado que existen interfaces ((oyentes))con un gran número de métodos y que un receptor que implementa una de estas clases se ve obligado a sobreescribir todos ellos, cuando se requiere una interfaz de este tipo se utilizan clases adaptadoras, que implementan las interfaces oyentes con métodos vacíos y se definen las clases receptoras para que extiendan las adaptadoras. Ejemplo Implementación de un programa que presenta las coordenadas de la posición donde se pulsa el ratón dentro del área de un marco usando clases adaptadoras. import java.awt.*; import java.awt.event.*; public class Marco3 extends Frame i int x = 0 , y = O; public static void main( String args[] ) i
  • 288. Gestión de eventos 273 Marco3 fuente = new Marco3 0 ; fuente.setTitle ("Marco"); fuente.setSize(250,lOO); fuente.setVisible(true); //se instancian y registran los receptores fuente.addWindowListener(new ReceptorCierre20); fuente.addMouseListener(new ReceptorRaton2(fuente)); 1 public void paint (Graphics g) i g.drawString("Posición del ratón: "txt", "+y,60,4O); //Las clases receptoras extienden adaptadoras class ReceptorCierre2 extends WindowAdapter public void windowClosing (WindowEvent e) t I System.exit (O); 1 class ReceptorRaton2 extends MouseAdapter t Marco3 laventana; ReceptorRaton2(Marco3 fuente) t laventana = fuente; 1 public void mousePressed (MouseEvent e) I laventana.x = e.getX ( ) laventana.y = e.getY ( ) ; laventana.repaint0; I 1 Nota: Las clases adaptadoras hacen innecesario redefinir aquellos métodos, declarados en la interfaz, no Útiles para el programa que se está diseñando. Las clases adaptadoras disponibles en j ava .awt .event son: Class CornponentAdapter Class ContainerAdapter Class FocucAdapter Class KeyAdapter
  • 289. 274 Java 2. Manual de programación Class MouseAdapter Class MouseMotionAdapter Class WindowAdapter 10.6. CLASES RECEPTORAS ANÓNIMAS Una clase anónima es aquella que no tiene nombre y, cuando se va a crear un obje- to de la misma, en lugar del nombre se coloca directamente la definición. Las cla- ses receptoras pueden ser definidas como clases anónimas. Ejemplo Construir un menú de opciones con el componente Choice,elegir una opción, pre- sentarla en pantalla y realizar el cierre de la ventana mediante una clase anónima (Fig. 10.3). Elemento seleccionado Tercero Figura 10.3. Ejemplo de Choice y clase anónima para el cierre de ventana. import java.awt.*; import java.awt.event.*; public class EjAnonima extends Frame implements ItemListener i private Choice selección; String elemento = " " ; public EjAnonima ( ) t /*empleo de una clase anónima para efectuar el cierre de la * / addWindowListener(new WindowListenerO ventana
  • 290. Gestión de eventos 275 t public void windowclosing (WindowEvent e) I I public void windowActivated (WindowEvent e) t } public void windowClosed(WindowEvent e) t } public void windowDeactivated(Wind0wEvent e) t l public void windowDeiconified(WindowEvent e) t l public void windowIconified(WindowEvent e) I } public void windowopened (WindowEvent e) I I System.exit (O); 1 ) selección = new Choice ( ) ; selección.addItem ( "Uno" ) ; selección.addItem ( "Dos" ) ; selección.addItem ( "Tercero" ) ; //Opción preseleccionada selección.select (1); selección.addItemListener(thís); add (selección); I public static void main( String args[] ) i EjAnonima ventana = new EjAnonima ( ) ; ventana.setLayout(new FlowLayoutO ) ; ventana.setTitle ( "El AWT" ) ; ventana.setSize( 400,250 ) ; ventana.setVisible(true); 1 public void paint (Graphics g) I elemento = selección.getSelectedItem(); g.drawstring ("Elemento seleccionado"+elemento, 20,230); I public void itemStateChanged(1temEvent e) t I repaint ( ) ; 1
  • 291. 276 Java 2. Manual de programación Resulta práctico definir como anónimas las clases receptoras que extienden adaptadoras. Por ejemplo, en el caso anterior se podría definir la siguiente clase anónima: //empleo de una clase anónima addWindowListener(new WindowAdapter I public void windowClosing i System.exit (O) ; ) WindowEvent e) 10.7. PROBLEMASCOMUNES EN ELTRATAMIENTO DE EVENTOS Un problema frecuente en el tratamiento de eventos se origina por los «titubeos» del usuario ante la realización de una determinada elección y la medida a tomar suele ser ignorar las selecciones realizadas por el mismo hasta que éste confirme su deci- sión; para ello se añade un botón de confirmación y se ignoran los eventos genera- dos hasta que el usuario pulse dicho botón. Ejemplo Crear un CheckboxGroup que agrupe 4 casillas de verificación. Sólo se acepta la selección de la opción cuando se pulsa el botón de confirmación (Fig. 10.4). import java.awt.*; import java.awt.event.*; public class EjCheckboxGroup extends Frame implements ActionLictener i private Checkbox opl, op2, op3, op4; private CheckboxGroup menu; private Button confirmacion; private Label 1; String elemento = "Elija opción y pulse Aceptar"; public EjCheckboxGroup() i addWindowListener (new Cierre ( ) ) ; menu = new CheckboxGroup ( ) ; opl = new Checkbox ("Primera opción", menu, false op2 = new Checkbox ("Segunda opción", menu, false op3 = new Checkbox ("Tercera opción", menu, false op4 = new Checkbox ("Cuarta opción", menu, false)
  • 292. Gestión de eventos 277 add(op1); acid(op2); add(op3); add(op4); Panel p = new Panel ( ) ; p.setLayout (new GridLayout (2,l)) ; 1 = new Label (elemento); confirmacion = new Button ( "Aceptar" ) ; p.add(confirmacion) ; . confirmacion.addActionListener(this); p.add(1); add(p); public static void main( String args[] ) i EjCheckboxGroup ventana = new EjCheckboxGroup() ; ventana.setLayout (new GridLayout (3,2)) ; ventana.setTitle ( "El AWT" ) ; ventana.setSize( 500,250); ventana.setVisible(true); public void paint (Graphics g) I if (menu.getSelectedCheckbox ( ) ! = null) elemento = "Elemento seleccionado:" t menu.getCelectedCheckbox() .getLabel(); 1.setText (elemento); 1 public Insets getInsets ( ) i 1 return new insets (20,20,20,20); public void actionPerformed(ActionEvent e) i 1 repaint ( ) ; 1 class Cierre extends WindowAdapter I public void windowClosing (WindowEvent e) System.exit (0); 1 1
  • 293. 278 Java 2. Manual de programación ~ r Ptimera opción C Sewnda aotión r Tercera opcl6n @ Cualta opcldn ,-____.. ___ Aceptar L ..--..........<..I ~ .............---,.,.._I_<._~ _._._._._,_,..__; Elementoseleccionada: Cuarta opclón Figura 10.4. Confirmación de la selección de una opción. Por otra parte, en algunos programas las acciones a realizar ante un determinado evento deben depender de eventos anteriores y, en estos casos, lo habitual es recu- rrir a variables booleanas que reflejen lo que ha sucedido antes y programar las acciones a realizar en relación con el valor de dichas variables. Ejercicio Diseño de una calculadora sencilla (Fig. 10.5). Figura 10.5. Calculadora. En un programa que efectúe la creación de una calculadora será preciso en pri- mer lugar distinguir entre la parte correspondiente al diseño de la pantalla y la de
  • 294. Gestión de eventos 279 manejo de los sucesos; dentro de esta última, es necesario resaltar que las acciones a realizar ante la pulsación de un botón van a depender sobre todo de si dicho botón es un dígito o un operador. Considerando operadores binarios y las operaciones como series de operando operador operando operador para evaluar según el orden de introducción, cuando el botón pulsado sea un operador marcará el fin de la ope- ración anterior, pero la actual no se podrá realizar hasta que no se introduzca un segundo operando y se marque su fin con un nuevo operador. Cuando el botón pul- sado sea un dígito la acción dependerá de la selección anterior y de si esta fue un dígito, la coma decimal o un operador. Por tanto, la ejecución de unas acciones u otras requerirá la consulta de los valores de variables booleanas ( o troNumero, esDecimal) que informen sobre dicha selección anterior. import java.awt.*; import java.awt.event.*; public class Calculadora extends Frame TextField resultado; boolean otroNumero = true, esDecirnal = false; double total =O. O; char operador='x' ; / / sin operador / * Diseña la pantalla utilizando 2 paneles auxiliares que se colocan con BorderLayout. Uno de estos paneles auxiliares contiene a su vez otros dos, uno de operandos y otro de operadores, q u e se colocan .,t-li- zando GridLayout. Los paneles de operandos y operadores con- tienen los botones y vuelven a hacer uso de GriaLayout * / public Calculadora ( j Botones cero, uno, dos, tres, cuatro, cinco, seis, s ~ e t e , ocho, nueve, coma; Botones suma, resta, multiplica, divide, obtiene, borra; setFont (new Font ("Arial",Font.PLAIN,14)) ; setBackground(Color.1ightGray); setTitle ("Calculadora"j ; setsize (200,140); addWindowListener(new Cierre0 ) ; Panel paneloperandos = new Panel ( ) ; panelOperandos.setLayout(new GridLayout(3,4) ) ; cero = new Botones("O", 'x', 'O', this); / * el segundo parametro que se pasa al constructor indica panelOperandos.add(ceroj; cero.addActionListener(cero); que no es un operador, el tercer parámetro es el valor * /
  • 295. 280 Java 2. Manual de programación c uno = n e w Botones ("l", 'x' , '1' t h i s ) ; paneloperandos.add (uno); uno.addActionListener(un0); doc = n e w Botones ( "2", 'x', '2', t h i s ) ; paneloperandos.add (dos); dos.addActionListener(dos); tres = n e w Botones ( " 3 " , 'x' , ' 3 ' , t h i s ) ; panel@perandos.add(tres); tres.addActionListener(tres); cuatro = n e w Botones ("4", 'x' , '4', t h i s ) ; panelOperandos.add(cuatro); cuatro.addActionListener(cuatro); c i n c o = n e w B O t O n e S ( " 5 " , 'x'' '5', t h i s ) : panelOperandos.add( cinco ) ; cinco.addActionListener(cinco); seis = n e w Botones ("6", 'x' , '6', t h i s ) ; panelOperandos.add(seis); ceis.addActionListener(seis); s i e r e = n e w Botones ("7", 'x', 'If, t h i s ) ; panelOperandos.add(siete); ciete.addActionLictener(siete); ocho = n e w Botones ("8", 'x' , '8', t h i s ) ; panelOperandos.add( ocho ) ; ocho.addkctionListener(ocho); n'Jeve = n e w Botones ("9", 'x' , '9', t h i s ) ; panelOperandos.add(nueve); nueve.addActionLictener(nueve); coma = n e w Botones(",", 'x', ' . ' , t h i s ) A panelOperandos.add(coma); coma.addActionListener(coma); Panel paneloperadores = n e w Panel ( ) ; paneloperadores .cetLayout( n e w GridLayout ( 2 , 3 )) ; / / borra pasa como operador el espacio en blanco borra = n e w Botones ("C", ' ', ' O ' , t h i s ) ; / * el segundo parametro que se pasa al constructor indica el operador, el tercer parámetro es el valor y para los opera- dores es cero * / panel@peradores.add(borra); borra.addActionListener(borra); suma = n e w Botones ( ' I + " , ' + r , 'O', t h i s ) ; panelOperadores.add(suma); sJma.addActionListener (suma); resta = n e w Botones ( " - ' I , I - ' , 'O', t h i s ) ; panelGperadores.add(resta); recra.addA-zionLictener(resta); multiplica = n e w Botcnec ( " * ' I , ' * I , 'O', t h i s ) ; panelCperadcres .add (multiplica); -.ultiplica.addActionListener(multiplica); diviSe = n e w Bo:onec ( " / ' I , ' / r , 'O', t h i s ) ;
  • 296. Gestión de eventos 281 panelOperadores.add(divide); divide.addActionListener(divide); obtiene = new Botones ("=", ' = I , 'O', this ) ; panelOperadores.add(obtiene); obtiene.addActionListener(obtiene); Panel panelcentral = new Panel(); panelcentral.setLayout (new GridLayout (1,2,10,10)) ; panelCentral.add(panel0perandos); panelCentral.add(panel0peradores); Panel panelResultado = new Panel(); panelResultado.setLayout(new FlowLayout 0); resultado = new TextField( "O",15); resultado.setEditable(false); panelResultado.add(resultad0); add ("North", panelResultado) ; add ("center", panelcentral) ; setVisible(true); 1 public static void main ( String args [I ) i 1 new Calculadora ( ) ; / / no se trata de un operador void coloca(char valor ) I String .digit0 = " " ; if( valor == I . ' ) if( !esDecirnal ) { I if( otroNumero ) i resultado.setText ( "O"); otroNumero = false; 1 esDecirna1 = true; digito = " ."; 1 I else if( otroNurnero ) digito = ""tvalor;
  • 297. 282 Java 2. Manual de programación resultado.setText( digito ) ; if ( valor ! = 'O' ) otroNumero = false; else repaint ( ) ; resultado.setText(resultado.getText() + digito ) ; //es un operador void calcula(char otrooperador) i double numero; ncmero = (new Double (resultado.getText ( ) ) ) .doublevalue ( ) ; if ( (!otroNumero 1 1 operador == '=' ) & & otrooperador ! = ' ' 1 t switch( operador ) i case '+' : total += numero; break; case I - ' : total -= numero; break; case ' * I : total *= numero; break; case ' / ' : total / = numero; break; case 'x' : case ' ' : total = numero; break; resultado.setText ( ( new Double (total) ) .tostring ( ) ) ; 1 operador = otrooperador; otroNumero = true; esDecima1 = false; if (otrooperador == ' ' ) t resultado.setText ( "O" ) ; operador = ' '; total = 0.0; 1
  • 298. Gestión de eventos 283 c l a s s Botones extends Button implements ActionListener I char unoperador, unvalor; Calculadora calc; Botones(Ctring texto, char oper, char valor, Calculadora c ) t super( texto ) ; unoperador = oper; u n v a l o r = v a l o r ; calc = c; 1 public void actionPerformed(ActionEvent e) i i f ( unoperador == 'x' ) / / no es un operador calc.coloca (unvalor); calc.calcula(unoperador); else 1 i c l a s s Cierre extends WindowAdapter i public void windowclosing (WindowEvent e) t 1 Cystem.exit (O);
  • 299. I 11 Applets CONTENIDO 11.1. Introducción a HTML. 11.2. Incorporación de applets a páginas Web. 11.3. Estructura de un applet. 11.4. Transformación de aplicaciones en applets. 11.5. Incorporación de sonido. 11.6. Incorporación de imágenes. 285
  • 300. 286 Java 2. Manual de programación ~~ ~ ~~ ~ ~~~ ~~ ~ Los applets son pequeños programas Java que se incluyen en páginas Web y cuyo código se descarga desde el sevidor para ser ejecutado localmentepor un navegador. Por tanto, para trabajar con applets es necesario conocer algunas de las características de las páginas Web y del lenguaje en que éstas están escritas, y el capí- tulo comienza exponiendo conocimientos básicos sobre HTML. También se explicará la estructura fundamental de un applet. Te- niendo en cuenta que las applets trabajan con IGU y están guia- das por eventos, el capítulo se apoya en los conocimientos aportados por otros anteriores para la creación de las primeras applets. 11.1. INTRODUCCIÓN A HTML Internet es útil para el intercambio de información y la comunicación multiperso- nal gracias a su organización en servidores, que disponen de la información y los recursos, y clientes, que acceden a ellos. Dentro de los servicios proporcionados por Internet, la Web ocupa un lugar destacado, constituyendo las páginas Web, archivos guardados en servidores repartidos por todo el mundo y los navegadores programas cuya misión es conectarse a un servidor Web para recibir sus datos y presentar las páginas en pantalla. Las paginas Web se escriben en lenguaje HTML (lenguaje de marcas de hipertexto). En un documento HTML existe texto normal y marcas encerradas entre llaves angulares que indican al navegador cómo mostrar el contenido del documento en pantalla. Existen marcas básicas que necesitan otra de cierre, como las mostradas en la Tabla 11.1. Tabla 11.I.Marcas básicas de un documento HTML ~~ ~ __ Marca Significado <HTML> . . . </HTML> Comienzo y fin del documento HTML <HEAD> . . . </HEAD> Comienzo y fin de cabecera <BODY> . . . </BODY> Comienzo y fin del cuerpo
  • 301. Applets 287 Las marcas <HTML> y </HTML> señalan el principio y fin del documento y <HEAD> </HEAD> y <BODY> </BODY> dividen el documento en sus dos par- tes fundamentales: cabecera y cuerpo. PARTES EN UN DOCUMENTO HTML <HTML> -Comienzo del documento <HEAD> </HEAD> <BODY> </BODY> Cabezera Cuerpo 1 1 ... ... </HTML> -Fin del documento Otras marcas que necesitan cierre se muestran en la Tabla 11.2. Tabla 11.2. Marcas en las que se exige cierre Marca Significado <TITLE> título-de-fagágina </TITLE> <Hn> ...</Hn> <UL> <UL> <OL> <OL> < L I > ...</OL> <B> ...</B> < I > ...</I> entradas-de-la-lista entradas-de-la-lista Irá dentro de la cabecera y permitirá poner título al documento. Cabeceras cuyo nivel viene representado por el número n que las acompaña. El tamaño de texto más grande es para las de nivel 1 Comienzo y fin de una lista no numerada Comienzo y fin de una lista numerada Entrada de la lista Negrita Cursiva Existen también en HTML otras marcas que no necesitan cierre (Tabla 11.3).
  • 302. 288 Java 2. Manual de programación Tabla 11.3. Marcas en las que se requiere cierre Marca Significado <BR> <P> <HR> Salto al principio de la siguiente línea sin introducir una línea en blanco para separar el texto anterior. Nuevo párrafo, introduciendo una línea en blanco para separar el siguiente texto del anterior. Línea horizontal gráfica como separador de bloques de texto. Es preciso tener presente que la escritura de saltos de línea en una página HTML Así mismo, existe otra clase de marcas que requieren atributos con especifica- se trata como si fuera una escritura de espacios en blanco. ción de la información adicional necesaria para completar la acción. Tabla 11.4. Marcas que requieren atributos Marca Significado ~ ~ ~~~ ~~~~ ~ <FONT SIZE=nÚmero> Cambia el tamaño de las fuentes. <IMG SRC=nombre-imagen> Permite incluir en una página Web la imagen con el nombre especificado. La marca para la inclusión de una imagen se puede complementar con el atributo ALT que permite la sustitución de la imagen por una descripción de la misma cuando dicha página se visite con el navegador en modo texto. <IMG SRC=nombre-imagen ALT=descripción> Los enlaces en las páginas Web se indican a traves de la marca <A>. ..</A>, que se denomina ((ancla))(anchors)y que necesita como atributo la referencia al documento con el cual se enlaza (URL), de la siguiente forma: <A HREF= ref-a1- docurnento- con-e1- cua1- se-en1az a> texto- que-se-rno strara- en-panta11a </ A> Además de las marcas citadas, existen caracteres que tienen un significado espe- cial en lenguaje HTML. Estos caracteres especiales sirven para representar en el dispositivo de salida (pantalla, impresora,...) a otros caracteres normales de escritu- ra que no pueden escribirse directamente, dado que tienen un significado especial en HTML. Es decir, por ejemplo, para representar en pantalla el símbolo es pre- ciso escribir en el documento HTML el carácter (( & 1t;D.
  • 303. Applets 289 Tabla 11.5. Representación de caracteres especiales Carácterque se desea presentar < &It; > &gt; 11 & q u o t ; Carácterpor el que debe sustituirse & &amp; . . . ... HTML también tiene códigos especiales para los caracteres que no forman parte de conjunto ASCII estándar (Tabla 11.6). Tabla 11.6. Códigos especiales para representar caracteres no ASCII Carácterque se desea presentar Carácterpor el que debe sustituirse ó ñ Ñ ... &oacute; &ntilde; &Ntilde; ... 11.2. INCORPORACIÓN DE APPLETS A PÁGINAS WEB Los applets permiten vincular código Java con páginas Web. Esta acción permite construirpáginas Web dinámicas. Además, hay que tener en cuenta que el código Java se ((descarga))desde el servidor para ser ejecutado en el navegador, de forma que se aprovecha la potencia del sistema local y se evita la sobrecarga del servidor. Un applet se incorpora en una página Web usando las siguientes órdenes (comandos) html: <APPLET CODEBASE= U R L - d e - l a - c l a s e CODE=nombre- de-1a- c1ase NAME=nornbre WIDTH=núrnero H E I G H T = n Ú m e r o ALT= t e x t o ALIGN=?’ ust i f i c a c i ó n V S P A C E = e s p a c i o - vert i cal <PARAM H S P A C E = e s p a c i o - h o r i zon t a l > NAME=n o m b r e - a rgurnen t o VALUE= va1or-a rgumen to> . . . (parametros, puede haber varios) (códigosHTML alternativos para clientes que no soportan Java) < / A P P L E T >
  • 304. 290 Java 2. Manual de programación Los distintos elementos y su responsabiiicLd se describen a continuación: CODEBASE:Necesario cuando el upplet no se encuentra en el mismo lugar que la página Web y representa el directorio, relativo al directorio en donde se encuentra la página Web, que contiene la clase del upplet. CODE:Obligatorio; nombre del archivo que contiene el código byte de la clase ya compilada. NAME:Opcional. Nombre de la instancia del applet. Este nombre permite a los upplets de una misma página encontrarse y comunicarse entre sí. WIDTH y HEIGHT:Obligatorios; representan el tamaño del rectángulo que ocupará el applet en la página Web. ALT: Opcional; sirve para especificar el texto alternativo que presentará un navegador cuando comprenda la etiqueta APPLET, pero no pueda ejecutar el applet. ALIGN:Opcional; establece la alineación del upplet con respecto a los otros elementos de la pagina. Como justificación, se podrá indicar LEFT,RIGHT, TOP, TEXTTOP,MIDDLE,ABSMIDDLE,BASELINE,BOTTOM y ABSBOT- TOM. tal que separará al upplet del texto que le rodea. VSPACE y HSPACE:Opcionales, permiten fijar el espacio vertical y horizon- Entre las órdenes APPLET y /APPLET se pueden colocar parámetros para el upplet con la sintaxis: <PARAM NAME=nornbre-argumento V A L U E = v a l o r - a r g u m e n t o > - NAME: Nombre del parametro que se desea pasar al applet. El nom- bre a r g u m e n t o puede escribirse encerrado o no entre comillas y no se hacedistinción entre mayúsculas y minúsculas. - VALUE:Valor que se desea enviar al upplet mediante el parametro. El valor que se envía también puede escribirse encerrado o no entre comillas. Es importante tener presente que los parámetros pasados a un upplet pueden ser varios, resultando necesario especificar para cada uno de ellos un nombre (NAME)y un valor (VALUE). Otro factor a considerar es que si se desea que las applets que trabajan con parámetros puedan ejecutarse siempre, conviene que en las mismas se proporcionen valores por omisión para dichos parámetros. Por último, diremos que los parámetros se reciben en el upplet siempre como cadenas median- te el método getparameter: public java.lang.Ctring getParameter(java.1ang.String pl)
  • 305. Applefs 291 La sentencia necesaria sería, pues: String argumento= getParameter ( "nombre-argumento" ) ; donde las comillas son obligatorias. Esta sentencia devuelve el valor-argumento del parámetro cuyo nombre (NAME) es nombre-argumento; si no lo encuentra, devuelve nu 11. 11.2.1. Edición de un documento HTML y-ejecución de applefs La edición de una página HTML se realiza con un editor de texto. Una vez escrito el código en el editor, se debe almacenar con la extensión HTML. La visualización de la página Web que incorpora un applet se podrá efectuar usando un navegador o el visor de applets, appletviewer;de ambas formas el applet se carga y ejecuta automáticamente. FORMATO BÁSICO DE UNA PÁGINA WEB QUE INCORPORA UN APPLET <HTML> <HEAD> </HEAD> <BODY> <APPLET CODE= nombre-de-la-clase WIDTH= número height= número > </APPLET> </BODY> </ HTML> Ejemplo Una página HTML que incorpora un applet al que se le pasan parámetros podría ser la mostrada en la Figura 11.1.
  • 306. 292 Java 2. Manual de programación <HEAD> ;/HEAD, <RODY> <HI .EjernpIo</Hl> <UL> ~TlTLE>T&iacute,iulocírlTLE> <Ll> Lino <LI> Dos </Liz </UL> <I-- Colocacion del codiaa HTML aue interese - - > 4PFLET CODE = libro Tenia11 El4pplet class WIDTH = 220 HEIGHT = ion> ~ P A R A MNAME = "Colar" VALJE = 'w5,1nn,inn": cPARAM NAME = "Nombre" VALUE = "Cadena"> aAPFLET> </BODY, :/HTML> Figura 11.1. Página T.html. Es conveniente observar el código HTML y, sobre todo, cómo se especifica en CODE el nombre del archivo que contiene el código byte (bytecode)de la clase com- pilada. CODE=libro.Temall.EjApplet.class El applet de la Figura 11.2 recibe como cadenas los parámetros Nombre y Col or. Dicho upplet no adjudica valores por omisión para los parámetros, ya que el ejemplo pretende ser una demostración sobre el paso de los mismos y, si se pro- dujeran errores basta con que éstos se visualicen. Es importante destacar trata- miento del parámetro Color que en el mencionado upplet se efectúa. Es necesario tener en cuenta que en Java el color está encapsulado en la clase Color,que defi- ne algunas constantes para especificar un conjunto de colores comunes, pero ade- más es posible definir colores utilizando constructores de color. De esta forma es posible especificar cualquier color y después Java busca el más cercano al solici- tado en función de las limitaciones del sistema donde se esté ejecutando el pro- grama o applet. El tratamiento efectuado es debido a que applet exige recibir cadenas como parámetros y el constructor de color empleado requiere tres núme- ros enteros. public Color (int p l , int p 2 , int p3) Los parámetros son valores del O al 255 que se corresponden con la cantidad de colores puros, rojo, verde y azul, utilizados en la mezcla para obtener el color deseado.
  • 307. Applets 293 package libro Tema11, import java awt *, import Java applet *, public class EjApplet extends Applet String nombre, String color, public void init0 i nombre = getParameter(1'Nombre"), coIot = yetParameter("CoIoI"), int cl = Integer parselnt(co1or substring(0,3)), int c2 = Integer parselnt(co1or subctring(4,6)), int c3 = Integer parselnt(co1or substringp,lO)), setBackground(new Color(c1 ,c2, c3)), I 1 i public void paint(Graphics g) g setFont(new Font("Arial", Font BOLD, 14)), y drawString(nombre ,20,2O), Figura 11.2. Applet: EjApplet.java. El método init ( ) es proporcionado por la clase Applet e inicializa el upplet cada vez que se carga (posteriormente se ampliará el concepto de init). El upplet puede hacer uso de paint debido a que la clase Applet hereda de Panel,que a su vez lo hace de Container y ésta de Component. Tanto la página como el upplet se almacenan en C : 1ibro Tema11 . Una vez creados el applet y la pagina, la única operación necesaria será compi- lar el upplet, para lo que se utiliza la siguiente instrucción: C:libroTemall>javac EjApplet .Java Al abrir la página, usando por ejemplo Microsoft Internet Explorer, el upplet se Otra forma de ejecutar un upplet es utilizando uppletviewer; éste simula un carga y ejecuta automáticamente. El resultado se muestra en la Figura 11.3. navegador elemental y necesita que se le pase como parámetro el nombre del archi- vo HTML donde se incorpora el upplet. Es decir, ejecutar la orden: C:libroTemall>appletviewer T.html
  • 308. 294 Java 2. Manual de programación .uti0 m Dos Parámetro: Parámetro: rnelGI Nombre y lugar donde se encuentra la página Figura 11.3. Resultado de la ejecución del applet E] Applet .class. El uso de uppletviewer requiere añadir al archivo HTML la orden: CODECASE = .. . . 11.3. ESTRUCTURA DE UN APPLET La clase Applet extiende la clase Panel del AWT y Panel extiende Container que, a su vez, extiende Component, proporcionándose así a las upplets todas las herramientas necesarias en la programación IGU (Znterfuz Gráfica de Usuario) y, al igual que todos los programas que trabajan con IGU, las upplets están guiadas por eventos. Las upplets disponen de cinco métodos que pueden sobreescribir, aunque no es obligatorio que lo hagan, pues tienen implementaciones por defecto que se invoca- rán automáticamente durante la ejecución de la misma. Cuatro de estos métodos son proporcionados por la clase App1et: public void init ( ) Inicializa el applet y es invocado por el Appletviexlev o el navegador cuando se carga el applet.
  • 309. Applets 295 public void s t a r t ( ) Se ejecuta a continuación de init y también cada vez que el usuario del navegador regresa a la página HTML donde reside el upplet y debe contener las tareas que deban llevarse a cabo en estas ocasiones. public void stop() Se ejecuta cuando el usuario abandona la página HTML en la que reside el applet. public void destroy ( ) Libera todos los recursos que el applet está utilizando y se ejecuta antes de que el applet se descargue cuando el usuario sale de la sesión de navegación. El quinto método es paint perteneciente a la clase Container,que se invo- ca para dibujar en el applet al iniciar su ejecución, así como cada vez que el mismo necesita redibujarse. Un ejemplo se presenta cuando el applet se oculta por una ven- tana y luego esta ventana se mueve o se cierra. ESTRUCTURA BÁSICA DE UN APPLET import java.awt.*; import java.applet.*; public class NombreApplet extends Applet / / métodos que se pueden sobreescribir public void init ( ) { / I . ..i public void start O { / / .. . I public void stop0 { / I . ..I public void destroy O { / / . . . I public void paint (Graphics g) { / / .. . I I Otros métodos de interés cuando se trabaja con upplets son: public void recize(int pl, int p2) Redimensionar el applet.
  • 310. 296 Java 2. Manual de programación public void repaint ( ) Repintar el upplet a petición del programa. public void update(java.awt.Graphics pl) Es llamado por repaint y, como paint,se utiliza para dibujar en el upplet, ofreciendo la posibilidad de efectuar repintados incrementales. public void showstatus (java.lang.Ctring pi) Muestra un mensaje en la barra de estado del navegador o visor de applets. public java.awt.Image getImage (java.net.URL pl, java.lang.String p 2 ) . Devuelve un objeto image que encapsula la imagen encontrada en la dirección especifica- da mediante el parámetro p l y cuyo nombre es el especificado como segundo parámetro. public java.applet.AudioClip getAudioClip (java.net.URL p l , java.lang.String p 2 ) . Devuelve un objeto Audioclip que encapsula el fragmento de audio encontrado en la dirección especificada mediante el parámetro pl y cuyo nombre es p2. public java.applet.App1etContext getAppletContext0 Obtiene el contexto del upplet. public java.net.URL getCodeBase0 Obtiene el URL del upplet. public java.net.URL getDocumentBase0 Devuelve el URL del archivo HTML que inició el upplet. public abstract void showDocument (java.net.URL pi) Muestra, desde el contexto de un upplet, el documento especificado mediante el parámetro pl.Es un método definido en la interfaz java.app1et.AppletContext public abstract java.util.Enumeration getApplets ( ) Método que permite obtener las applets que se encuentran en el contexto de la actual. Definido en la interfaz java.applet.App1etContext public abstract java.applet.Applet getApplet(java.lang.String pl) Devuelve el upplet de nombre pl,si dicha upplet se encuentra en el contexto actual, en otro caso devuelve null Definido en la interfaz java.applet.App1etContext
  • 311. Applets 297 Además de AppletContext que permite acceder al entorno de ejecución del applet, la clase Applet dispone de otras dos interfaces mas: 1) AppletStub, proporciona mecanismos para la comunicación entre el applet y el navegador; 2) Audioclip,reproduce archivos de sonido. La incorporación de imágenes y soni- do a un applet se verá más adelante. Ejemplo Applet que calcula el volumen de una esfera y lo muestra en la barra de estado. package libro.Ternal1; import java.awt.*; import java.awt.event.*; import java.applet.*; public class Esferavol extends Applet implements ActionListener i Label mensaje; TextField valor; public void init ( ) i mensaje = new Label("Introduzca el radio y pulse <RTM>: " ) ; valor = new TextField(l0); add (mensaje); add (valor); valor.addActionListener(this); public void actionPerformed(ActionEvent e) i Couble val = new Double (valor.getText( 1 ) ; double radio = val.doublevalue ( ) ; showstatus ("El volumen es " + Double.toString(volumenEsfera(radio))); public double volumenEsfera( double radio) double volumen; volumen = (double)4/3*Math.PI*Math.pow (radio,3); return volumen; I
  • 312. 298 Java 2.Manual de programación Figura 11.4. Resultado de la ejecución del applet Esferavol.class. Archivo HTML (Pagina.HTML) <HTML> <HEAC> </HEAD> <BODY> <APPLET CODE=libro.Temall.EsferaVol.class NAME=EsferaVol WIDTH=32O HE;GHT=lOO > </APP¿ET> </BODY> </HTML> 11.4. TRANSFORMACIÓN DE APLICACIONES EN APPLETS Las técnicas generales a seguir para transformar en upplets las aplicaciones con IGU desarrolladas en Java son: Añadir a las importaciones del programa la del paquete java .applet .*. Hacer que la clase que define el applet extienda Applet.La sustitución de Frame por Applet obliga a eliminar las posibles llamadas a setTitle y a cambiar dispose por destoy. Reemplazar el constructor de la clase por el método init. Eliminar el método main. Eliminar las llamadas a System.exit. Hacer que la entrada y salida de datos se efectúe siempre a través del AWT.
  • 313. Appleis 299 Tener en cuenta que el administrador de diseño por defecto para las applets es Crear un archivo HTML que incorpore el applet. FlowLayout. Se requiere, además, tener presente las siguientes consideraciones: Los applets, por razones de seguridad, no pueden efectuar todos los trabajos que realizan las aplicaciones. Por ejemplo, no pueden ejecutar un programa de la computadora del usuario, ni listar directorios, ni borrar, ni leer, ni escribir, ni renombrar archivos en el sistema local. Cuando se efectúa programación multihilo, deben detenerse los hilos de un applet cuando se sale de la página Web en la que el mismo reside. Para ello, se sobreescribe el método s t o p del applet. Los hilos se reinician en el método start del applet que se invoca automáticamente cuando el usuario retorna a la página Web. Los applets sólo pueden crear conexiones por red con la computadora de la que proceden. Ejemplo Transformar en applet la aplicación de la calculadora vista en el capítulo anterior. package libro.Temal1; import java.awt.*; import java.awt.event.*; / / se añade la importación del paquete applet import java.applet.*; / / En la aplicación la clase Calculadora extendía Frame public class Calculadora extends Applet i TextField resultado; boolean otroNumero = true, esDecima1 = false; double total = 0.0; char operador = 'x'; / / init reemplaza al constructor de la clase, Calculadora0 public void init 0 this.setLayout (new BorderLayout ( ) ) ; Botones cero, uno, dos, tres, cuatro, cinco, seis, siete, ocho, nueve, coma; Botones suma, resta, multiplica, divide, obtiene, borra;
  • 314. 300 Java 2. Manual de programación setFont (new Font ("Arial",Font.PLAIN,14)) ; setBackground(Color.1ightGray); Panel paneloperandos = new Panel(); paneloperandos.setLayout (new GridLayout (3,4)) ; cero = new Botones ("O", 'x', 'O', t h i s ) ; panelOperandos.add(cero); cero.addActionListener(cero); uno = new Botones ("l", 'x' , '1' , t h i s ) ; panelOperandos.add(uno); uno.addActionListener(uno); dos = new Botones( "2", 'x', '2', t h i s ) ; paneloperandos .add(dos); dos.addActionListener(dos); tres = new Botones ( " 3 " , 'x' , ' 3 ' , t h i s ) ; panelOperandos.add(tres); tres.addActionListener (tres); cuatro = new Botones ("4", 'x' , '4', t h i s ) ; panelOperandos.add(cuatro); cuatro.addActionListener(cuatro); cinco = new Botones ( " 5 " , 'x' , '5', t h i s ) ; panelOperandos.add( cinco ) ; cinco.addActionListener(cinco) ; seis = new Botones ("6", 'x' , '6', t h i s ) ; panelOperandos.add(seis); seis.addActionListener(seis); siete = new Botones ("7", 'x' , 'I!, t h i s ) ; panelOperandos.add(siete); siete.addActionListener(siete); ocho = new Botones ("8", 'x', '8', t h i s ) ; panelOperandos.add( ocho 1 ; ocho.addActionListener(och0); nueve = new Botones ("9", 'x', '9', t h i s panelOperandos.add(nueve); nueve.addActionListener(nueve); coma = new Botones ( " , ' I , 'x' , ' .' , t h i s panelOperandos.add(coma); coma.addActionListener(coma); Panel paneloperadores = new Panel ( ) ; panelOperadores.setLayout(new GridLayout(2,3)); borra = new Botones("C", ' ', 'O', t h i s ) ; panelOperadores.add(borra); borra.addActionListener(borra); suma = new Botones ( " + " , 't' , 'O', t h i s ) ; panelOperadores.add(suma); suma.addActionListener(suma); resta = new Botones ( ' I - " , '-', ' O ' , t h i s ) ; panelOperadores.add(resta); resta.addActionListener(resta); multiplica = new Botones ( " * " , ' * ' , ' O ' , t h i s ) ; panelOperadores.add(mu1tiplica);
  • 315. nultiplica.addActionListener(multip1icaj; divide = new Botones ( " / ' I , ' / ' , 'O', this); panelOperadores.add(divide); aivide.addActionListener(dividej; obtiene = new Botones ( " = ' I , I = ', 'O', this j; panelOperadores.add(obtiene); obtiene.addActionListener(obtienej; Applets Panel panelcentral = new Panel ( ) ; p a n e l C e n t r a l . s e t L a y o U t ( n e w GridLayout(l,2,:0,13)); panelCentrai.add(panelCperandos); panelCentral.add(panel0peradcre.s); Panel panelResultado = new Panel(); panelResultado. setLayout (new FlowLayout ( j j ; resultado = new TextField( "O",15); resultado.setEditable(false); panelResultado.add(resultadoj; add ("North", panelResuitadoj ; add("Center", panelcentral) ; / / Desaparece el método main() void coloca (char valor ) i String digito = " ' I ; if( valor == ' . )' I if ( !ecDecimal ) if ( otroNumero ) i resultado.setText ( "O") ; otroNumero = false; I esDecimal = true; digit0 ' f . I' l . I I else if ( otroNumero ) i d i g i t o = ""+valor; resultado.setText( digito 1 ; if ( valor ! = 'O' ) otroNumero = false; 1 else repaint ( ) ; resultado.setText(resultado.getText() + digit0 1;
  • 316. 302 Java 2. Manual de programación void calcula (char otrooperador) i double numero; numero = (new Double (resultado.getText ( ) ) ) .doublevalue ( ) ; i f ( ( !otroNumero 1 1 operador == '=' ) & & otrocperador != ' ' ) switch( operador ) i case I t ' : total t= numero; break; case I - ' : total -= numero; break; case ' * I : total *= numero; break ; case ' / I : total /= numero; break; case 'x' : case ' ' : total = numero; break: 1 resultado.setText ( ( new Double (total) ) .tostring()) ; 1 operador = GtroOperadGr; otroNumero = true; esDecimal = false; i f (otrocperador == ' ' 1 i resultado.setText ( "0" ) ; operador = ' '; total = 0.0; 1 class Botones extends Button implements ActionListener i char unoperador; char unvalor; Calculadora calc; Botones(Str1ng texto, char oper, char valor, Calculadora c ) i super( texto ) ; unoperador = oper; unvalor = valor; calc = c; I
  • 317. Applets 303 p u b l i c void actionPerformed (ActionEvent e ) if ( .;noperador == ‘x’ ) else caic.coloca (unvalor); calc.calcula(unoperado=); / / No es necesaria la clase Cierre Archivo HTML (PagCalc.HFML) <HTML> <HEAD> < T I T T E , C a l c u i a d o r a < / T I T = E > </ HEAC> <BODY> <APPLE, C03Y=libro.Teia;l.Ca~cui~d~~a.class NAME=Ca1cuiadora WIDTH=2 OC HEIGHT=14@ > </ APPLET> </B03Y> </HTML> Cuando un programa no trabaja con interfaz gráfica de usuario, su transforma- ción en applet conlleva modificaciones más profundas, ya que se requiere pasar a una programación dirigida por eventos. Ejemplo Transformar en applet una aplicación que rellena un vector con 1O números enteros aleatorios, muestra los números generados y la media de los mismos. / / Aplicación class LLenaArr p u b l i c s t a t i c void main (String[ j args) f i n a l i n t n5iems=lG; i n t arr [ ] = new int[nElerns] ; i n t j ; i n t suma = O ; for(j = 0; j < nElems; j + + ) i arr[j] = 1 + ( i n t ) (Math.randorn() * 1 0 ) ; suma += arr[jl;
  • 318. 304 Java 2. Manual de programación double media = (double)(suma) / nElems; for(j = O; 1 < nElems; j++) System.out.println ( " ' I ) ; System.out .println("La media es "+ media) ; system.out.print( arr[j] + " ' I ) ; i Compilación C:libroTemal:>]avac LLenaArr.java Ejecución y resultado de la misma C:libroTemall>]ava LLenaArr 8 9 3 4 9 10 7 7 3 6 La necia es 6.6 / / applet import ]ava.awt.*; import ]ava.applet.*; public class LLenaArr2 extends Applet final int nElems = 10; int arr[] = new int[nElemsl; double media = 0.0; public void init ( ) int suma = O; t for(int j = O; j < nElems; 1 ++) arr[j] = 1 + (int) (Math.random0 * 10); suma += arr [j]; media = (double)(suma)/ nE1ern.s; public void paint (Graphics g ) int x = O; for(int j = O; j < nElems; j++) I x += 35; g.drawString(String.valueOf (arr[j]), x, 35);
  • 319. Applets 305 g.drawString("La media es "+ media,35,70); 1 Compilación C:librotema ll>javac LLenaArr2.java Archivo HTML (Numeros.html) IHTMLZ <HEAD> </HEAD> <BODY> <APPLET CODE= LLenaArr2.class WIDTH= 400 HEIGHT= loo> </APPLET> </BODY> </ HTML> Ejecución C:libroTemall>appletviewer numeros.htm1 El resultado se muestra en la Figura 11.5. 7 2 9 6 8 6 1 8 1 3 Lamediaes 51 Figura 11.5. Resultado de la ejecución del applet LLenaArr .class
  • 320. 306 Java 2. Manual de programación 11.5. INCORPORACIÓN DE SONIDO Para reproducir sonidos desde un applet, se comienza por cargar el archivo de soni- do mediante public java.applet.AudioC1ip getAudioCl;p(;ava.net.URL pi, lava.lang.String p2) y posteriormente se controla la reproducción mediante los métodos proporcionados por Audioclip. Ejemplo Audioclip audiocl; audiocl = getAudioClip (getCodeBase( ) , "Sonido.au"); audiocl .play( ) ; . . . . . . De esta forma los datos de audio se cargan cuando se construye el audio clip. La interfaz Audioclip del paquete java .applet define los siguientes métodos: public abstract void l o o p ( ) Reproduce el archivo de forma continua. public abstract void play() Reproduce el archivo. public abstract void stop() Detiene la reproducción. La versión 1.3 de la Plataforma 2 de Java incluye una nueva y poderosa A P I ( javax .sound) que permite capturar, procesar y reproducir audio y MIDI. Este A P I permite una flexible configuración del audio y del sistema M I D I , inclu- yendo métodos para que las aplicaciones puedan preguntar al sistema cuáles son los recursos que están instalados y disponibles. Los archivos de audio pueden ser de los formatos AIF, AU y WAV y los de música M I D I Tipo O, M I D I Tipo 1y RMF. 11.6. INCORPORACIÓN DE IMÁGENES El método a seguirpara la incorporaciónde imágenes a un applet es similar al anterior- mente descritopara la incorporaciónde sonido. La imagen se carga mediante el método public java.awt.Image getImage(java.net.URL pi, java.lang.String p2)
  • 321. Applets 307 en el que pi representa el lugar de ubicación de la imagen, mientras que p2 es el nombre del archivo que la contiene, que puede ser de tipo j pg o gif,y se puede mostrar utilizando p u b l i c abstract boolean drawImage(java.awt.1mage p l , i n t p2, i n t p3, java.awt.image.ImageObserver p4) El primer parámetro p l es la imagen, el segundo, p2,y tercero, p3, representan el lugar donde debe situarse la imagen en el applet (en realidad son las coordena- das para la esquina superior izquierda de la misma) y el cuarto, p4, es una refe- rencia a un objeto Imageobserver,que puede ser cualquiera que implemente la interfaz Imageobserver y normalmente es el objeto en el que se muestra la ima- gen. También se puede utilizar para mostrar la imagen p u b l i c abstract boolean drawImage(java.awt.1mage p l , i n t p2, i n t p3, i n t p4, i n t p 5 , java.awt.image.Irnage0bserver p6) Este segundo método permite establecer una anchura y altura determinadas para Imageobserver es una interfaz implementada por la clase Component que la misma mediante los parámetros p5 y p6. define el método public abstract boolean imageupdate (java.awt .Image pl, i n t p2, i n t p3, i n t p4, i n t p5, i n t p6) el cual puede redefinirse para cambiar su comportamiento por defecto, que es pin- tar las imágenes mientras se cargan. El método imageupdate devolverá false cuando se haya completado la carga de una imagen y true en caso con- trario. Ejemplo Modificación del ejercicio que calcula el volumen de una esfera y lo presenta en la barra de estado, para que muestre la imagen de un altavoz y haga sonar un pitido especial tras la introducción de los datos. package libro.Ternal1; import java.awt.*; import java.awt.event.*; import java.applet.*;
  • 322. 308 Java 2. Manual de programación public class EsferaVol2 extends Applet implements ActionListener label mensale; TextField valor; Audioclip pita; Image audio; public void init ( ) / * Se supone qae los archivos, tanto de imagen como de sonido, se encuentran almacenados en el mismo lugar que el applet, por eso se obtiene su dirección con getCodeBase " / audio = getImage (getCodeBace( ) , "Audio.gif"); pi=a = getAudioClip (getCodeBase( ) , "Sonido.au"); mensaje = new Label("1ntroduzca el radio y pulse <RTM>: " ) ; valor = new TexLField(l0) ; add(mensaje1 ; ada (valor); valor.addActionlistener(this); public void actionPerformed(Acti0nEvent e) t Couble val = new Double (valor.getText ( ) ) ; double radio = val.doublevalue ( ) ; showCtatus ("El volumen es " + pita.play() ; Double.toString(volumenEsfera(radio))); 1 public double volumenFsfera ( double radio) i double volumen; volumen = (double)4/3* Math.PI * Math.pow(radio,3); return volumen; public void paint (Graphics g) i i g.drawImage (audio, O, O, this); Archivo HTML (Pagina2.HTML) <HTML> <HEAD> </HEAD> <BODY> <APPLET
  • 323. CGDE=iibro.Temall.EsferaVol2.class NAME=EsferaVol2 WIDTH=320 HEIGHT=100 > </APPLES>. </BODY > </HTML> I I Figura 11.6. Resultado de la ejecución de EsferaVol2. class. Si se requiere cargar varias imágenes simultáneamente en lugar de la interfaz Imageobserver y su método imageupdate, es mejor utilizar la clase MediaTracker de java.awt, con la cual se puede comprobar el estado de diversas imágenes en paralelo. Métodos public MediaTracker (java.awt..Component p l ) Permite crear la instancia. public void addImage (java.awt.Image pl, int p 2 ) Añade una nueva imagen sobre la que controlar el estado de carga. El primer parámetro es la referencia a la imagen que está siendo cargada y el segundo es un número identificativo del misma. public boolean Image checkID (int pl) Verifica el estado de la imagen. public void waitForID(int pi) Obliga al programa a esperar hasta que la imagen cuyo identificador se especifica como pará- metro se haya cargado por completo. public void waitForAll ( ) Obliga al programa a esperar hasta que todas las imágenes registradas se hayan terminado de cargar.
  • 324. A 12 rrogramacion concurrente: Hilos de ejecución CONTENIDO 12.1. La programación multihilo en Java. 12.2. Estados de un hilo. 12.3. Creación de hilos. 12.4. Planificación y prioridades. 12.5. Hilos de tipo demonio. 12.6. Grupos de hilos. 12.7. Sincronización. 12.8. Animaciones. 12.9. Doble buffer. 311
  • 325. 312 Java 2. Manual de programación Java permite la creación de programas con múltiples hilos de eje- cución (multithreading); es decir, programas con varias partes, denominadas hilos, que realizan sus actividades en paralelo. Hay que tener en cuenta que la mayor parte de las computadoras per- sonales disponibles hoy día cuentan con un Único procesador, lo que hace imposible la ejecución simultánea de los diferentes hilos, dado Io cual se utiliza un sistema de planificación que permite compartir el uso del procesador según unas prioridades previa- mente establecidas. La creación de programas con varios hilos de ejecución resul- ta muy útil en algunas ocasiones; por ejemplo, para imprimir un documento largo mientras el usuario continúa con el uso de la IGU, o para conseguir una eficiente implementación de las anima- ciones. No obstante, también puede dar origen a multitud de pro- blemas y, en la mayor parte de los casos, los hilos habrá que coordinarlos, por ejemplo, para impedir que uno lea datos de una estructura antes de que otro los escriba en ella. 12.1. LA PROGRAMACIÓN MULTlHlLO EN JAVA Los hilos de ejecución en Java están implementados en la clase Thread, que forma parte del paquete j ava .l a n g . Cada hilo (thread) tiene un principio, unflujo de ejecución y un,fin definidos, pero no es una entidad independiente sino que debe ejecutarse en el contexto de un programa. La clase Thread implementa el con- cepto de ejecución multihilo de una forma independiente de la plataforma donde se va a producir dicha ejecución. El intérprete de la máquina virtual específica donde se rueda (se ejecuta) el programa es el encargado de conseguir que los hilos se eje- cuten de forma concurrente, esto es, alternada en el tiempo, dando la apariencia de una ejecución simultánea. Por esta razón, la alternancia de código se efectúa de forma muy diferente en distintas computadoras. Imp~rtante:Los sistemas operativos tienen diferentes formas de planificar la concreta de la concurrencia de ope- .Cuando varios hilos con la misma ede predecirse durante cuánto tiempo se ido en un sistema específico.
  • 326. Programación concurrente: Hilos de ejecución 313 12.2. ESTADOS DE UN HILO Los objetos hilo de Java tienen cuatro posibles estados: nuevo, ejecutable, bloqueado, muerto (Tabla 12.1). Tabla 12.1 Estados de objetos hilo ~~~ ~ ~ ~ ~ ~ ~~ ~~~ Nuevo A este estado se accede mediante la llamada a un constructor de la clase hilo, y durante el mismo el hilo aún no tiene asignados recursos. Ejecutable Se accede con una llamada al método start.éste método asigna los recursos necesarios para ejecutar el hilo, planifica su ejecución y realiza una llamada a su método r u n , que es el que contiene el código con las acciones que debe realizar el hilo y habitualmente es un bucle.Como los hilos se alternan, un hilo en estado ejecutable no tiene por qué ser el que, en un determinado momento, se encuentra ejecutándose. Bloqueado Un hilo puede estar bloqueado como consecuencia de: Una llamada al método sleep,se tendrá así un hilo dormido que, al cabo de un cierto tiempo, despertará y pasará al estadoEjecutable.El método i n t e r r u p t consigue que un hilo dormido se despierte inmediatamente, producién- dose una excepción. Esperando la terminación de una operación de entradaisalida. Llamadas a otros métodos como wait, y i e l d o j o i n . Muerto A este estado se llega tanto tras completar el método r u n . El método s t o p de versiones anteriores ya no se usa en Java2, debido a que ocasionaba problemas por ejemplo por no limpiar, antes de finalizar la ejecución de un hilo, el estado de los objetos con los que el mismo se encontraba trabajando. Es preciso tener en cuenta que un hilo puede pasar fácilmente del estado Bloqueado al estado Ejecutable, y la forma de paso estará estrechamente relaciona- da con la causa que provocó la detención del hilo. Para obtener información sobre el estado de un hilo, se puede recurrir al méto- do isAlive, que devuelve true siempre que el hilo no se encuentre en los esta- dos Nuevo, ni Muerto. Otro método que indirectamente proporciona también información sobre el estado de un hilo es jo i n , que obliga al hilo llamador a espe- rar hasta que finalice el hilo al que se llama. El método j oin permite, además, especificar el límite de tiempo que se esperará a que el otro hilo termine su trabajo. Un hilo Muerto no puede volver al estado Ejecutable. Importante: Los métodos stop, suspendedy resumepertenecen a ver- siones anteriores y ya no se usan en Java2.
  • 327. 314 Java 2. Manual de programación 12.3. CREACIÓN DE HILOS La creación de hilos en Java se puede efectuar de dos formas: 1 . Usando una instancia de una clase que implemente la interfaz Runnable. Esta interfaz sólo tiene el método run, que es el método donde habrá que colocar el código que debe ejecutar el hilo y su implementación constituye la mejor elección desde una perspectiva orientada a objetos. 2. Creando una subclase de la clase Thread para obtener un objeto que here de de ella. Hay que tener en cuenta que Java no admite la herencia múltiple, por lo que cuando se utiliza este método y se hereda de Thread, dicha subcla- se ya no podrá serlo de ninguna otra. En ambos casos, para que el hilo comience su ejecución es necesario: I ) crear el El siguiente es un ejemplo de creación de un hilo implementando la interfaz hilo, 2) llamar al método start. Runn ab1e: public class Principal public static void main (String[] args) I Encuentra bcl = new Encuentra ("0012R"); 1 public class Encuentra implements Runnable I Thread t; String claveb; public Encuentra (String clave) i claveb = clave; t = new Thread (this); t.start0; public void run ( ) i Cystem.out.println("Esta es la tarea a realizar por el hilo"); t=Y Thread.currentThread().cleep(2000); 1 catch ( InterruptedException e)
  • 328. Programación concurrente: Hilos de ejecución 315 t I System.out .println("Fin"); I Después de compilar el programa, ejecute C : libroTemal2>java Principal. En este ejemplo, una clase llamada Encuentra implementa la interfaz Runnable,lo que obliga a Encuentra a implementar el método run. A continuación se construye un hilo con el constructor public Thread (lava.iang.Runnabie PI) cuyo parámetru es una instancia de la clase que implementa la interfaz Runnable, y después se llama al método start,cuyo formato es public synchronized void start ( ) para que comience la ejecución del hilo. El código a ejecutar por el hilo será el definido en el método run, aunque éste 3uede llamar a otros métodos. Para que se pueda observar mejor el funcionamiento ie run, se han colocado en él las instrucciones System.out.println y el método sleep. El método sleep se utiliza cuando se pretende retrasar la ejecución de un hilo; -ecibe como parámetro un número de milisegundos y hace dormir al hilo dicho iúmero de milisegundos como mínimo. Debe colocarse en un bloque :ry/catch,ya que puede lanzar una excepción si algún otro hilo intenta inte- rumpirlo mientras está dormido. Cuando el hilo completa el método run se con- iierte en muerto y finaliza. El hilo actual puede obtenerse mediante el método Chread.currentThread ( ) . La creación de hilos podría efectuarse también de la siguiente forma: public class Principal2 I public static void main ( S t r i n g [ ] argc) t Encuentra2 bcl = new Encuentra2 ("@@12R"); bcl.start ( ) ; 1 public class Encuentra2 extends Thread i String claveb;
  • 329. 316 Java 2. Manual de programación public E n c u e n t r a 2 ( S t r i n g c l a v e ) I claveb = c l a v e ; public void r u n ( ) i Cystem.out . p r i n ~ l n("Esta es l a tarea a r e a l i z a r por e l hilo"); t=Y { s ; e e p ( 2 0 0 0 ) ; i catch ( I n t e r r u p t e d E x c e p t i o n e ) S y s t e m . o i i t . p r i n t 1 1 1 ( " F i n " ); En este caso, el método r u n se coloca en una subclase de Thread. Esta clase, en vez de implementar la interfaz R u n a b l e , extiende T h r e a d y redefine su método r u n . El hilo se crea instanciando la clase E n c u e n t r a 2 y, como en el caso anterior, para que comience su ejecución se recurre también a start. 12.4. PLANIFICACIÓN Y PRIORIDADES Los sistemas operativos difieren en la forma de planificar la ejecución de los hilos. Solaris 7 , por ejemplo, usa multitarea por derecho de prioridad (preemptive) esto quiere decir que ejecuta un hilo de cierta prioridad hasta completarlo o hasta que está listo otro hilo de más alta prioridad que lo desaloja. Windows utiliza reparti- ción de tiempo por turno circular (round-robin),esto implica la concesión a cada hilo de una cantidad limitada de tiempo, transcurrida la cual el hilo puede ser desa- lojado por otro que esté listo con su misma prioridad; los hilos con mayor prioridad siguen ejecutándose los primeros y desalojando, como siempre, a los de menor prio- ridad. Además, hay que tener en cuenta que Windows NT es capaz de utilizar máquinas con más de una unidad central de proceso (UCP). En un sistema con múl- tiples UCP los hilos del programa podrían ser planificados en UCP separadas. Como Java puede rodar en diferentes sistemas, cada uno de los cuales tiene su propia forma de manejar hilos, no se puede predecir durante cuánto tiempo se eje- cutará un hilo antes de que sea interrumpido en un sistema específico. Si en un determinado momento existen varios hilos en estado Ejecutable, se ejecutará pri- mero el que tenga mayor prioridad y, sólo cuando finalice o se detenga dicho hilo, se iniciará la ejecución de otro con menor prioridad; por otra parte, si un hilo con
  • 330. Programación concurrente: Hilos de ejecución 317 mayor prioridad que el que está en ese momento ejecutándose pasa al estado Ejecutable, <<arrebataránla UCP al que se encuentra en ejecución. El problema exige tener cuidado con los algoritmos para que resulten independientes de la pla- taforma y sólo se presenta ante hilos de idéntica prioridad, y métodos que pueden ayudar a resolverlo son sleep y y i e l d . El método sleep quita el control de la UCP a un hilo con cualquier prioridad, ofreciendo oportunidad para que otros se ejecuten. Además, un hilo puede ceder su derecho de ejecución efectuando una llamada al método yield,pero sólo a hilos adecuados y disponibles; es decir, a hilos ejecutables con igual prioridad que el mismo, por lo que éste método no asegura que el hilo actual detenga su ejecución. Es redundante en los sistemas con repartición de tiempo por turno circular. Los métodos suspend y resume pertenecen a versiones anteriores y ya no se usan en En Java la prioridad de los hilos por omisión es 5 y, cuando se crea uno nuevo, hereda la prioridad del que lo creó. La prioridad podrá ser modificada mediante el método ' Java2. public final void secpricrity (int pl) al que se le pasa como parámetro valores numéricos enteros comprendidos entre M I N PRIORITY (constante que vale i ) y MAX P R I O R I T Y (constante que vale IO), definidas en la clase Thread. Cuanto mayor sea el valor entero, mayor será el nivel de prioridad que indica. Para obtener la prioridad de un hilo se utiliza el método public final int getPriority() 12.5. HILOS DE TIPO DEMONIO Un demonio es un hilo cuyo propósito es ofrecer servicios a otros hilos de ejecu- ción existentes dentro del mismo proceso. El intérprete de Java permanece en eje- cución hasta que todos los hilos de un programa finalizan su ejecución, pero no espera a que terminen cuando éstos han sido establecidos como demonios. Para especificar que un hilo de ejecución es de tipo demonio, se deberá realizar una lla- mada al método public final void setDaernon (boolean pl) pasándole como argumento true.Para determinar si un hilo es de este tipo, se deberá llamar al método public final boolean isDaernon ( )
  • 331. 318 Java 2. Manual de programación 12.6. GRUPOS DE HILOS Los hilos en Java siempre pertenecen a un grupo, lo cual va a permitir que se pue- dan manipular y gestionar de forma colectiva. Cuando se crea un hilo Java lo colo- ca por defecto en el grupo del hilo bajo el cual se crea y para colocarlo en otro hay que especificarlo en el constructor, no siendo posible cambiar a un hilo de grupo tras su creación. Los constructores proporcionados por Thread que permiten aso- ciar un nuevo hilo a un grupo específico son: public Thread(java.1ang.ThreadGroup pl,java.lang.Runnable p2) public Thread(java.lang.ThreadGroup pl, java.lang.Runnable p2, java.lang.String p 3 ) El grupo de un hilo actual puede obtenerse mediante el método public final java.1ang.ThreadGroup getThreadGroup0 y el del hilo actual lo podría proporcionar la siguiente instrucción: Thread.currentThread0 .getThreadGroup(); Es necesario tener en cuenta que los grupos no sólo pueden contener hilos de eje- cución, sino también otros grupos. La clase ThreadGroup implementa las carac- terísticas y posibilidades de los grupos de hilos y dentro de ella es posible destacar los siguientes métodos: public ThreadGroup ( java.lang.String pi) Crea un grupo de hilos, el parámetro pl es el nombre para el grupo. public ThreadGroup java.1ang.ThreadGroup pl, java.lang.String p2) Crea un grupo hijo del grupo pasado como argumento, el parámetro p2 es el nombre para el grupo hijo. public int activecount ( ) Número de hilos Ejecutahles de un grupo de hilos public final void destroy() Destruye un grupo de hilos y sus subgrupos. public int enumerate (java.iang.Thread p1[ 1 ) Devuelve en el array una referencia a todos los hilos activos del grupo. public int enumeraze (java.1ang.ThreadGroup pi[ 1 ) Devuelve en el array una referencia a todos los grupos activos del grupo.
  • 332. Programación concurrente: Hilos de ejecución 319 public final int ';'.' ','../ I , ' , ' I Devuelbe la prioridad máxima que puedc tcricr tin hilo dc u n grupo public final - J - . J . ' , f , Devuelve el nombre del grupo public final javc.lanq.Thre,~Jr2r,&L ~ J Ct I 0 Devuelve el grupo padre de un grupo de hilos public final Boolean isüaemon ( ) Indica si el grupo es un demonio. public final void setMaxpriority (int pl) Establece la prioridad máxima para un grupo. public final void setDaemon (boolean pl) Establece si el grupo actual es o no un demonio. 12.7. SINCRONIZACI~N Cuando hay muchos hilos rodando en una máquina virtual de Java, es posible que varios de ellos deseen modificar la misma fuente al mismo tiempo; en estas cir- cunstancias, se hace necesario sincronizarlos de alguna forma y que cada uno de ellos conozca de algún modo el estado y las actividades de los demás. La forma más sencilla de explicar la sincronización es recurrir al clásico problema de produc- tor/consumidor, en el que existe un productor que genera datos y los almacena en una estructura de tamaño limitado, por ejemplo un array, desde donde se extraen por un consumidor. El productor será un hilo que añade los datos a la estructura tan rápido como puede, mientras que el consumidor va a ser otro hilo que extrae esos mismos datos también tan rápido como puede. En esta situación es evidente que será necesario un contador para saber el número de elementos almacenados en el array en un instante determinado e impedir que, de momento, siga trabajando el productor cuando el array esté lleno o el consumidor si se queda vacío, como se muestra en el siguiente programa.
  • 333. 320 Java 2. Manual de programación public class Principals t public static void main (String[ ] args) Datos d = new Datos ( ) ; Productor p = new Productor (d); Consumidor c = new Consumidor (d); I i public class Datos double[! ad; int contador = -1; public Datos ( ) ad = new double [ 41 ; 1 public void poner(doub1e d) while (contador < ad.length - 1) contador++; ad[contador] = d * 1000 + contador; public void quitar0 while (conEador >= O) double d = ad[contador]; ad[contador] = O; contador--; System.out .println("Consume "+d); public class Productor implements Runnable Thread hilol; Datos dtos; int num = 0;
  • 334. Programación concurrente: Hilos de ejecución 321 public Productor (Datos d) t dtos = d; hilol = new Thread(th1.s); hilol.start ( ) ; public void r u n 0 i for (int i = O ; i < 5; i++) dtos .poner (i); t=Y Thread.currentThread0 .sleep(100); 1 catch ( InterruptedException e) t } public class Consumidor implements Runnable i Thread h i l o 2 ; Datos dtos; public Consumidor (Datos d) dtos = d; h i 1 0 2 = new Thread(this); hilo2.start ( 1 ; public void run() t for (int i = O; 1 < 5; i++) dtos.quitar ( ) ; try i Thread.currentThread ( ) .sleep(100);
  • 335. 322 Java 2. Manual de programación El problema que surge ahora es debido a que puede ocurrir que, tras un incre- mento del contador por parte del hilol, y antes de que éste coloque un nuevo dato en la estructura, el planificador decida dejar de ejecutar el productor y comen- zar a ejecutar consirmidor y pase a ejecutarse el h i 1 0 2 , que quita un dato de la posición indicada por el contador, donde aún no hay un dato válido, y decrementa el contador; si ahora vuelve a ejecutarse el hilol como ya tenía efectuado su incremento de contador no lo realiza de nuevo y coloca el dato actual sobrescri- biendo uno anterior. Java soluciona este tipo de problemas mediante la sincroniza- ción, usando variables de condición y monitores. . Los monitores son objetos especiales asociados a datos que controlan el acceso a los mismos. Por otra parte, se denominan secciones críticas a aquellos bloques de código de un programa que acceden a datos compartidos por hilos de ejecución dis- tintos y concurrentes. Cuando, en Java, se marcan secciones críticas con la palabra reservada synchronized se asocia un Único monitor a los datos contenidos en ellas; de esta forma, durante el tiempo que un hilo permanece dentro de uno de estos bloques sincronizado, los demás hilos que quieran acceder ai mismo o a cualquier otro sincronizado sobre la misma instancia tienen que esperar hasta que el monitor esté libre, pues sólo un hilo puede obtener el monitor sobre los datos en un instante dado y los hilos que no poseen el monitor no pueden tener ningún tipo de acceso a los datos con él asociados. Para aplicar todo esto al ejemplo anterior bastaría marcar con synchronized los métodos poner y quitar, impidiendo su interrupción: public synchronized void poner (double d) i while (contador < a d . lenqth-1) { contador++; ad[contador] = d * 1030 + contador; public synchronized void qu;tar í ) I while (contador >= O) i double d = ad[contador]; ad[contador] = 3; contador--; Cyctem.out .println("Consume "+d); Para que la sincronización sea efectiva, todos los bloques que acceden a los recursos compartidos deben estar sincronizados. También hay que tener en cuenta que, aunque los bloques sincronizados pueden no ser métodos completos, en gene-
  • 336. Programación concurrente: Hilos de ejecución 323 ral, la mejor opción es que lo sean. No hay problema en que un hilo llame a un método que accede a datos para los que ya tiene el monitor. La sincronización es necesaria en programas donde hay varios hilos que de- sean modificar las mismas fuentes al mismo tiempo; no obstante, puede dar ori- gen a algunos problemas. Imagine que dos hilos de ejecución necesitan el mo- nitor sobre dos estructuras y cada uno coge el monitor para una de ellas, pero como cada hilo necesita los dos monitores y ninguno puede obtener el que tiene cogido el otro, ambos se paran. La solución consiste en que alguno de estos hilos ceda voluntariamente el monitor al otro, estas cesiones voluntarias se efec- túan a través de los métodos wait, notify y notifyAll de la clase Ob] ect. En el problema productor/consumidoK citado como ejemplo, si uno de los pro- cedimientos de monitor descubre que no puede continuar, situación que correspon- dería a los casos array lleno para productor y vacío para consumidor, mejor que dormirse por un cierto periodo de tiempo es que dicho procedimiento se bloquee (wait) hasta que el otro le indique que se debe despertar y volver a competir por el monitor (notify). Métodos public final void wait ( ) Cuando un hilo en ejecución invoca el método wait pasa a una cola asociada al objeto y su ejecución se detiene hasta que otro hilo active el método notify de ese mismo objeto. public final void notify() Es el método por el que un hilo que está ejecu- tando un método sincronizado puede despertar al primero de la cola asociada ai objeto. public final void notifyAll() Convierte en Ejecutables todos los hilos que esperaban en la cola del objeto, aunque sólo uno de ellos podrá obtener el monitor. Resumen: Se denominan secciones críticas a aquellos bloques de código de un programa que acceden a datos compartidos por hilos de ejecución distintosy con- currentes; si las secciones criticas se marcan con la palabra s y n c h r o n i z e d se asocia un único monitor a los datos contenidos en ellas. Losmonitores son objetos especiales asociadosa datos que controlan el acce- so a los mismos, ya que sóloun hilo puede obtener el monitor sobre los datos en un instante dado. Un hilo puede ceder voluntariamente el monitor al otro a tra- vésdelosmétodos w a i t , n o t i f y y n o t i f y A l 1 delaclaseObject.
  • 337. 324 Java 2. Manual de programación Ejemplo public class Principals2 'L public static void pain (String[ ] a r g s ) Datos2 d = new Datos20; Proauctor2 p = new Productor2(d); Consumidor2 c = new Consumidor2 (d); 1 public class Datos2 double[: ad; int conzador = -1; public Datos2 ( ) t ad = new double [ 4;; public synchronized void poner( double d) while (cor.tador >= ad.length-1) / * debe estar en un bucle w h i l e , no en un if, por si en la ciguienze llamada se repite el problema, por ejexplo a causa de un notifyAll() * / W a l t ( ) ; catch (InterruptedException e) t } while (contador < aa.1eng:h-1) contador+*; ad[contadorl = d*1000 + contador; i notify ( ) ; public synchronized void quitar() ! while (contador < O) t t=Y t wait ( ) ;
  • 338. Programación concurrente: Hilos de ejecución 325 i catch ( InterruptedCxception e) t i i while (contaacr >= 3) double d=ad [contadorj ; contador--; Cystem.o,t .pri?,tln( “ C c ~ c - m e“+d); notify ( ) ; I public class Productor2 implements Runnable I Thread hilol; Datos2 dtos; int Rum = O; public Produc~or2(Datos2 d) t dtos = d; hilol = new Thread(this); hilol.start ( ) ; public void r u n 0 t for (int : = O ; i < 3 ; i t + ) dtcc.poner (i); public class Consumidor2 implements Runnable i Thread hilo2; Datos2 dtcs; public Consumidor2 (Datos2 d) dtos = d; hilo2 = new Thread(this); hilo2.star: ( 1 ; public void run() for (int i = O; 1 < 3 ; i++) I
  • 339. 326 Java 2. Manual de programación citos.quitar(); 1 12.8. ANIMAClONES Un upplet trabaja con animaciones cuando efectúa una presentación sucesiva de imágenes, cada una con pequeñas diferencias con respecto a la anterior, dando así la apariencia de movimiento. Estas applets, además de dibujar las imágenes, deben poder responder a las acciones del usuario, por lo que las animaciones deben ejecutarse como hilos independientes que no obstaculicen otras tareas y los hilos deben detenerse cuando se sale de la página Web en la que reside el applet. Para todas estas tareas: El upplet implementará la interfaz Runnable, que se encargara de reali- zar las tareas de dibujo. Por ejemplo: public class Rebota extends Applet implements Runnable, MouseListener public void run ( ) i . . . . . . repaint ( ) ; . . . Se sobreescribirán los métodos s t a r t y s t o p del applet con el código ade- cuado para convertir en Ejecutables y Muertos los hilos que hayan podido crearse. Por ejemplo: public void start0 { if (hilo == null) i hilo = new Thread( this ) ; hilo.start 0; En s t o p se asigna n u l l al/los hilo/s para que se puedan recolectar sus recursos cuando se abandone la página Web en la que el applet reside.
  • 340. Programación concurrente: Hilos de ejecución 327 Por ejemplo: public void stop() hiloctop ( ) ; public void hiloctop ( ) ejecutable = false; hilo = null; Lógicamente, las animaciones pueden ser efectuadas por cualquier programa Java con GUI, no es necesario que se trate de un applet. Nota: No confunda los métodos start y stop de los hilos y de las upplets. El método stop para hilos está obsoleto. Recuerde: Las animaciones deben ejecutarse como hilos independientes para que no obstaculicen la simultánea realización de otras tareas. 12.9. DOBLE BUFFER Una técnica muy empleada en las animaciones con la finalidad de reducir el parpa- deo es el doble buffer. Esta técnica permite que, mientras se presenta un imagen en pantalla (primer bqfler), también puede tratarse de texto o gráficos, se pueda ir ela- borando en memoria la imagen siguiente (segundo bqffer).El doble buffer requiere: La creación de un objeto Image vacío, que actúa como buffer. El método a emplear pertenece a la clase java .awt .Component: public java,awt .Image createImage (int pl, int p2) donde pi y p2 son la anchura y altura de la misma. Por ejemplo imagen = createhage (ANCH0,ALTO ) ; Obtener un contexto gráfico para dibujar la imagen en segundo plano, con el siguiente método de la clase java .awt .Image: public abstract java.awt.Graphice getGraphics0
  • 341. 328 Java 2. Manual de programación Por ejemplo, contextoGraf = imagen.getGraphicc0; Mostrar el contenidodel buffer mediante drawImagede j ava.awt.Graphics public abstract boolean drawImage(~ava.awt.Imagep l , i n t p2, i n t p3, java.awt.image.Image0bserver p4) en donde el primer parámetro es la imagen a dibujar, los dos siguientes son las coordenadas para la esquina superior izquierda de la misma y el cuarto es el observador. Por ejemplo, g .arawimage ( imagen,O, O,t h i s ) ; Pero tenga presente que drawImage tiene otros muchos formatos mediante los cuales puede ser invocado. Ejercicio Pelota que rebota en los bordes de un upplet; su movimiento se puede detener y reactivar efectuando clics con el ratón sobre en cualquier posición del mismo (Fig. 12.1). / / Ejemplo de animación y doble buffer. import ;ava.awt.*; import java.awt.event.*; import java.appiet.*; p u b l i c class Rebota extends Applet implements Runnable, MouceListener { public f i n a l i n t ANCHO = 2 0 0 ; public f i n a l i n t ALTO = 100; f i n a l i n t TMIN = 25; i n t actual = TMIN; i n t px = O ; i n t p y = O ; i n t dx = 1; i n t dy = 1; boolean e2ecutable = t r u e ; Tsread hiio = n u l l ; Image imagen; Graphics contextoGraf; public void init ( )
  • 342. Programación concurrente: Hilos de ejecución 329 I resize ( ANCH0,ALTO ) ; / * La pelota sale de una posición aleatoria e?. ;a p a r z e superior del applet * / int rango = ANCHO - TMIN; px = (int) (Math.random0 * rango); try i imagen = createImage (ANCH0,ALTO ) ; contextoGraf = imagen.getSraphics0; I catch (Exception e) t contextoGraf = null; 1 addMouseListener(this); public void start() i if (hilo == null) i hilo = new Thread( this ) ; hilo.start ( ) ; public void stop() I hilostop ( ) ; I public void run() i while (hilo ! = null) I if (ejecutable) t if ( px + actual > ANCHO I I px < 0) if ( py + actual > ALTO 1 1 py < O) dx *= -1; dy *= -1; px = px + dx; PY = PY + dy; t=Y hilo.sleep( 10 ) ; 1 catch( Exception e ) i }
  • 343. 330 Java 2. Manual de programación regaint ( 1 ; niic = null; public void hiloct.op ( ) ejecutable = false; hilc = null; public void hilosuspend() elecutable = false; public void hiloresume ( ) eJ ecurable = true; public void update(Graghics g ) pairt( g ) ; public void paint(Graphics g ) if ( ccptextosraf ! = null ) t dibuja (contextcGraf ) ; g.cirawIrnage(imagen,O, O, this ) ; else d i b u j a ( g ) ; public void diCu 1a (Graphics g ) y.setColor (Color.gray); g.filLRect (O,O,ANCEG,ALTG ) ; g.setcoior ( C o l o r .red) ; y.fil,Oval(px, py, acz,al, actua-); public void mousePrecced (YouseEvent e) if (ejecutable ) else e ~ e c u ~ a b l e= !ejecutable; hiloresume ( ) ; hiloslspend ( 1 ;
  • 344. Programación concurrente: Hilos de ejecución 331 1 public void rnouceReleaced(MouceEvent e) { I public void mouseEntered (MonseEvent e) 1 1 public void rnouseExited (MouceEvent e) t i public void mouseclicked (MouseEvent e) I } Unas Últimas aclaraciones: en el ejemplo expuesto, el método run se encarga de obtener la posición donde la pelota ha de ser dibujada, de forma que se consiga su rebote en los bordes del applet, y manda que se redibuje. Cuando se presiona el ratón, mousepressed detiene o activa alternativamente la ejecución del hilo. El archivo Rebota.h t m creado es el siguiente: Archivo HTML (Rebota.htm) <HTML> <HEAD> </HEAD> <BODY> <applet code=Rebota.clasc name=Rebota width=200 height=100 > </ applet> </BODY> </HTML> Applet started 1 Applet started I Applet started I~~ ____ Figura 12.1. Applet Viewer muestra Rebota,class. Compilación C:libroTemal2>javac Rebota.3 ava
  • 345. 332 Java 2. Manual de programación Ejecucion con appietviewer C:iibroTe~a12>appletviewerRebota.htm Ejercicio El siguiente applet que muestra el funcionamiento del método de ordenación deno- minado método de la burbuja. Este applet presenta dos botones; uno permite la generación de un nuevo array aleatorio de números enteros y el otro lanza un hilo que efectúa la ordenación del mismo (Fig. 12.2). Cada número entero contenido en el array se representa en su correspondiente posición mediante un gráfico de barras, donde la altura de la barra se corresponde con el valor del número. El proceso de ordenación aparece paso a paso, pudiéndose apreciar en cada momento los inter- cambios que se van efectuando (Figs. 12.3 y 12.4). Figura 12.2. Situación inicial El applet diseñado es: import java.awt.*; import lava.awt.event.*; import java.applet.*; import java.util.*; / * Se utiliza la clase Random, perteneciente a java.uti1, para la generación de números aleatorios * / / * Clase que permite la ordenación gráfica de un array de enteros por el método de Burbuja * / public class OrdenacionGrafica extends Applet implements Act:onLis tener, RLInnab1e
  • 346. Programación concurrente: Hilos de ejecución 333 / / Variables generales private s t a t i c i n t nurnelems = 100; //No de enteros private s t a t i c i n t rango = 160; //Rango private i n t [ ] arr0rd; //Array de ordenación private Thread t = null; //Hilo de ordenación private final i n t ANCHO = 640; private final i n t ALTO = 400; / / Variables de proceso private boolean ejecutable = true; / / Variables de gráfico private static Color colordeBarra = Color.blue; //Color de barra private static int AnchuradeBarra = 3; //Anchura private static i n t yIni = 100 t rango; //Ordenada inicial private static i n t xIni = 20; //Abscisa inicial private static i n t xSep = AnchuradeBarra*2; //Ceparación x entre barras private image imagen; private Graphics contextoGraf; / / Paneles Panel pl; / / Botones Button nuevoArr; Button nueva0rd; / / Constructor public OrdenacionGrafica ( ) ( setLayout (new BorderLayout ( ) ) ; pl = new Panel ( ) ; / / Configuración de panel pl .setLayout (new FlowLayout ( ) ) ; nuevoArr = new Button ("Nuevo array") ; nuevaOrd = new Button ("Ordenar"); nuevoArr.addActionListener(this); nuevaOrd.addActionListener(this); pl .add (nuevoArr); pl .add(nuevaOrd); add ( " South",pl ) ; / / Generación inicial de array aleatorio arrOrd = randomEntArray(nume1erns); public void init ( ) I resize ( ANCH0,ALTO ) ;
  • 347. 334 Java 2. Manual de programación imagen = createImage(ANCH0,ALTO ) ; contextoGraf = imagen.getGraphicc(); catch(Exception e) contex2oGraf = null; public void stop() i 1 hilostop ( ) ; public void paint(Graphics g ) if( contextoGraf ! = null ) t dibuja (contextoGraf ) ; g .drawImage (imagen,O O, this ) ; else . dibuja( g ) ; public void update(Graphics g ) paint( g ) ; 1 public void dibuja (Graphics g) g.setcolor (Color.gray); g.fillRect (O,O,ANCHG,ALTO ) ; for (int i = O; 1 < arrGrd.length; it+) dibujaEnt(g, arrGrd[i], i); / * Control de Eventos. Al pulsar el botón nuevoArr se genera un nuevo array y se interrumpe cualquier ordenación que se estuviera llevando a cabo. Al pulsar el botón nuevaOrd comienza el proceso de ordena- ción tras la creación de un nuevo array y no ocurre nada si el array ya se estaba ordenando. Una vez empezado el proceso de ordenación o se genera un nuevo array o hay que esperar a que dicho proceso termine */ public void actionPerformed(ActionEvent e) i if (e.getCource0 == nuevoArr)
  • 348. Programación concurrente: Hilos de ejecución 335 4, if (t ! = null ) tilostop ( ) ; arrOrd = r a n a o r n E n t A r r a y ( n u w e 1 e m s ) ; repaint ( 1 ; 1 if (e.netsourre ( ) == nieva0rd) if (t == null ) ejecutable = true; t.start0; t = new Thread( this 1 ; I public void hilostop ( ) ejecutable = false; t = null; / / Birbuja public void run ( ) i while (t ! = null) i for (int i = 1; i < arr0rd.length & & ejecutable; it-) for (int j = O; j < arr0rd.length-i & & ejecutable; J + + ) if (arrOrd[:+l] < arrOrd[jj & & e<ecutable) int tr?p = arrOrd[jj ; arr0rd [ j] = arrOrd:j+1]; arr3rd[J+l] = =nip; repaint ( ) ; t*Y t t.sleep (100); i catch(Exception e ) t } } t = null; / / Método para :a construcción de un array aleatorio de entezcs public int[ ] randomEntArray (int N) Random gen = new Random() ; int[] a = new int:N] ; for (int 1 = C; i < a.lenqth; i++) a[i]=Math.abs (gen.nextInz():rango);
  • 349. 336 Java 2. Manual de programación r e t u r n (a); I / / Método para la representación de un entero en su posición i public void dibujaEnt(Graphics g, i n t h, i n t i) i n t x = xIni + i * xSep; i n t y = yIni - h; i n t w = AnchuradeBarra; g.setColor(co1ordeBarra); g.fillRect(x,y,w,h); AOOlet starfeu I Figura 12.3. Fase intermedia del proceso de ordenación, se observa cada intercambio. Figura 12.4. Array ordenado.
  • 350. Programación concurrente:Hilos de ejecución 337 El archivo Ord .h t m tiene el siguiente contenido: Archivo HTML (Ord.htm) <HTML> <HEAD> <TITLE>Proceso de ordenación en el método de la Burbuja</TITLE> </HEAD> <BODY> <applet code=OrdenacionGrafica.class name=OrdenacionGrafica width=640 height=400 > </applet> </BODY> </HTML>
  • 351. I I Maneio de excepciones CONTENIDO 13.1. Conceptos generales. 13.2. Manejo de excepciones. 13.3. Captura y tratamiento de excepciones. 13.4. Lanzar la excepción. 13.5. Declarar la excepción. 13.6. El bloque finally. 13.7. Creación de excepciones. 13.8. Métodos de la clase Throwable. L 339
  • 352. 340 Java 2. Manual de programación Las excepciones son objetos que describen y permiten controlar errores y problemas inesperados en el funcionamiento de un pro- grama sin oscurecer el diseño del mismo, y se manejan por un código especial que no sigue el flujo normal de ejecución de dicho programa. El compiladorobliga al manejode algunas excepciones, mientras que para otras esto será potestativo del programa.Java, además de proporcionar múltiples clases de excepciones, permite crear nuevos tipos para que respondan a una anomalía en el fun- cionamiento de un programa sobre la que los usuarios deban ser informados. En este capítulo se explica la captura, tratamiento, declaración, creación y lanzamiento de excepciones y se comen- tará su importancia e inexcusable uso en algunas ocasiones, por ejemplo en operaciones con archivos. 13.1. CONCEPTOS GENERALES Todos los tipos de excepción son subclases de Throwable y, como se puede observar en el esquema de la jerarquía de clases (Fig. 13.1), por debajo de Throwable hay dos clases, Error y Exception,que dividen las excepcio- nes en dos ramas distintas. Las excepciones de la clase Error abarcan fallos graves de los que los pro- gramas no pueden recuperarse y, por tanto, no suelen ser capturadas por los mismos. La clase Exception abarca las excepciones que los programas suelen captu- rar; tiene varias subclases, entre las que destacan RuntimeException, IOException e InterruptedException. - RuntimeException comprende errores en tiempo de ejecución que se producen al efectuar operaciones sobre datos que se encuentran en la memo- ria de la computadora, se subdivide en diversas subclases entre las que destacan ArithmeticException y NullPointerException, ambas pertenecientes al paquete j ava .lang,como casi todas las RuntimeException, y disponibles en todos los programas ya que este paquete se importa automáticamente. - IOException comprende los errores de entrada/salida y pertenece al paquete j ava .io. - InterruptedException,de cuyo tipo son los errores debidos a la interrupción de un hilo de ejecución por otro,pertenece también a j ava.lang.
  • 353. Manejo de excepciones 341 Además de disponer de todas estas clases, es posible extender la clase Exception o sus subclases y crear nuevos tipos de excepciones que respondan a una anomalía en el funcionamiento de un programa sobre la cual deben ser infor- mados los usuarios, aunque hay que tener en cuenta que no es conveniente utilizar las excepciones como un método alternativo para especificar flujo de control. Importante: Todos los errores que se pueden originar en un método, excepto los de tipo Error y RuntimeException,hay que declararlos en una cláusula throws o bien capturarlos y tratarlos dentro de ese mismo método. Los proga- mas no están obligados a capturar ni declarar las excepciones del tipo RuntimeException. Throwable Error Exception InterruptedException RuntimeException ArithmeticException IlLegalArgumentException r--NumberFormatException 1- ~~ IndexOutOfBoundsException I StringlndexOutOfBoundsException ArraylndexOutOfBoundsException ... NullPointerException ILegalMonitorStateException ...- - IOException FileNotFoundException , ... EOFException - AWTException Figura 13.I . Excepciones,
  • 354. 342 Java 2. Manual de programación Dada la obligatoriedad impuesta por el compilador con respecto a la captura de algunas excepciones, hace ya tiempo que se viene utilizando código para la gestión de las mismas y se ha visto ya que para capturar excepciones basta con escribir el códi- -go que se quiere controlar en un bloque try y especificar la excepción que se desea capturar en una cláusula catch.Así, si escribe el siguiente programa, el compilador le obligará a modificarlo y capturar, de la forma especificada, la excepción IOException que por la operación de lectura pudiera haber sido generada. Ejemplo El programa siguiente pide la introducción por teclado de un número entero, n, comprendido entre 1y 2 O; a continuación, muestra las sucesivas potencias de 2 desde 2 elevado a 1 hasta 2 elevado a n . import java.io.*; public c l a s s E:emplo //E:enplo 1. public s t a t i c void main (String args [ ] ) InputStreamReader icr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(1sr); String cadena; i n t n = O ; Syctem.out.print("Deme un numero entero entre 1 y 20 ' I ) ; cadena = br.readLine(); n = Integer .parseInt(cadena); i n t 1 = 1; while (1 <= n) System.out.println ("2""+i+" = "+Math.pow(2,i)) ; it+; Si lo modifica de la siguiente forma, el compilador lo aceptará y funcionará correctamente cuando introduzca números enteros en el rango indicado, pero dará una excepción si teclea una letra en lugar de un número o pulsa RETURN (INTRO) sin introducir nada. Ejemplo import 3 ava .IC.* ; public c l a s s Ejemplo2
  • 355. Manejo de excepciones 343 public static void r a i n (CrrLrg args [ ] ) ! InputStreamReader isr = new InputStreamReaser(Cys=em.;n); BufferedReader br = new BufferedReader(icr); / * se hace necesaria la inicialización de la cadena, debido a que las instrucciones en el CLoque try pasria?. no ser ejecutadas,pero seria igual in2cializarla a " I ' * / String cadena = "C"; int n; System.out .print("Deme un número entero entre 1 y 2C " ) ; t=Y I cadena = br .readLine ( ) ; 1 catch (IOException e) t } n = 1nteger.parseInt (cadena); int i = 1; while (i <= n) System.out.println("2^"+i+" = "+Math.pow(2,i)) ; Iff; I I I importante: No se puede garantizar que las sentencias siguientes a un deter- minado catch vayan a ser ejecutadas. 13.2. MANEJO DE EXCEPCIONES Las operaciones que se pueden realizar con excepciones son: captura y tratamiento (manejo), lanzamiento y declaración. 13.3. CAPTURA Y TRATAMIENTO DE EXCEPCIONES Para capturar una excepción, se escribe el código que se quiere controlar en un blo- que t r y ; se especifica la excepción que se desea capturar en una cláusula catch y se coloca el tratamiento para la misma en el bloque catch. La cláusula catch con- siste en la palabra reservada catch, seguida por el tipo de excepción que se desea capturar y un nombre de parámetro encerrados entre paréntesis. El conjunto try/catch no se puede separar con sentencias intermedias.
  • 356. 344 Java 2. Manual de programación No se debe colocar una estructura try/catch para cada una de las instruccio- nes de un programa que pueda lanzar una excepción, sino agrupar las que estén rela- cionadas en un único bloque try.En estos casos, es decir, cuando las sentencias encerradas en un bloque try pueden producir más de una excepción, es posible poner varias cláusulas catch consecutivas; permite efectuar un tratamiento distin- to para cada una de las excepciones. La búsqueda de la excepción originada se efec- tuará secuencialmente en cada una de las claúsulas catch,por tanto no se debe colocar una claúsula catch que capture excepciones de una superclase antes de otra que capture las de una de sus subclases. Ejemplo Modificar el ejercicio de las potencias de modo que no se produzca una interrupción si se teclea una letra en lugar de un número o se pulsa RETURN (INTRO) sin introdu- cir nada. import java.io.*; public class E j emplo3 public s t a t i c void main (String args[]) InputCtreamReader icr = new InputStreamReader(System.in); BcfferedReader b r = new BufferedReader (isr); i n t n = O ; System.out.print("Deme un número entero entre 1 y 20 " ) ; t r y i String cadena = br.readLine ( ) ; n = Integer .parseInt(cadena); catch ( IOException e) {//tratamiento 1 1 catch (NurnberFormatException e) {//tratamiento 2 i n t i = 1; while (i <= n) System.out .println( " 2 ^ " + 1 + " = "tMath.pow(2,i)) ; it+; Otra posibilidad para resolver este problema de las múltiples excepciones gene- radas en un bloque try,es utilizar una claúsula catch que capture excepciones de
  • 357. Manejo de excepciones 345 una superclase que englobe todos los tipos de excepciones que, por las instruccio- nes incluidas en try,pueden ser generadas y utilizar instanceof para determi- nar el tipo de excepción. Ejemplo Dado que la clase Exception engloba las excepciones a considerar en los ejem- plos I a 3 ya explicados, para capturar las citadas excepciones IOException y NumberFormatException podría escribirse el código de la siguiente manera: import java.io.*; public c l a s s Ejemplo4 t public s t a t i c void main (String args [I ) InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader (isr); String cadena; i n t n = O; System.out.print("Deme un número entero entre 1 y 20 " ) ; t=Y t cadena = br .readLine ( ) ; n = Integer.parseInt(cadena); 1 catch (Exception e) i if (e instanceof IOException) else if (e instanceof NumberFormatException) System.out .printin("Error de entrada/calida") ; System.out .println("No tecleó un número entero"); 1 i n t i = 1; while (i <= n) i System.out.printin("2^"+i+" = "+Math.pow (2,i)) ; i++; 1 13.4. LANZAR LA EXCEPCIÓN Una claúsula catch puede recibir una excepción y, en lugar de tratarla o después de hacerlo, volver a lanzarla mediante una instrucción throw.
  • 358. 346 Java 2. Manual de programación Ejemplo Modificando levemente el ejemplo anterior, puede utilizarse también en el presen- te caso. La modificación consiste en la creación de un método de lectura que, des- pues de su tratamiento, lanza la excepción NumberFormatException. import java.io.*; public class Ejemplo5 t public static int leer ( ) i InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(1sr); String cadena = I"'; int n = O; try i cadena = br.readLine ( ) ; n = 1nteger.parseInt (cadena); 1 catch (IOException e) { ) catch(NumberFormatException e) i System.out.println("1) ¿Tecleó solo return?"); throw (e); 1 return n; 1 public static void main (String args [ ] ) i int n = O; System.out.print("Deme un número entero entre 1 y 20 ' I ) ; try { n = leer ( ) ; catch(NumberFormatException e) System.out.println( " 2 ) ¿Tecleó una letra o un real?"); 1 int i = 1; while (i <= n) i System.out .println("2A"+it"= "+Math.pow(2,i)) ; i++; 1 1 1
  • 359. Manejo de excepciones 347 13.5. DECLARAR LA EXCEPCIÓN Las excepciones pueden no ser tratadas (manejadas), posponiendo su tratamiento para que sea efectuado por el método llamador, pero cuando no pertenecen a la clase RuntimeExcepti o n , es necesario listar los tipos de excepciones que se pasan en la cabecera del método. En general las excepciones R u n t imeExcept ion deben capturarse en el método donde se han producido; en caso contrario serán tratadas por el bloque t r y del método invocador más próximo que capture dicha excepción y sin necesidad de ser listadas en la cabecera del método. Ejemplo En este caso leer no efectúa ningún tratamiento y, como se puede observar, se hace necesario listar la IOExceptionen la cabecera del método. import java.io.*; public class Ejemplo6 public static int leer ( ) throws IOException I InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String cadena = ""; try t cadena = br .readLine ( ) ; return Integer.parseInt(cadena); 1 finally t i 1 public static void main (String argstl) i int n = O; System.out.print("Deme un número entero entre 1 y 20 ' I ) ; I try n = leer ( ) ; 1 catch (IOException e) i } catch (NumberFormatException e) i 1 int i=l; while (i <= n) System.out .println("¿Tecleó solo return?");
  • 360. 348 Java 2.Manual de programación SyStem.out.println ("2""+i+" = "+Math.pow(2,i)) ; i++; Hay que tener en cuenta que el bloque try no puede aparecer sólo, por lo que, al no ser necesario ninguna claúsula catch,se ha de colocar una cláusula y bloque finally. f i n a l l y I } 13.6. EL BLOQUE finally Cuando no se produce ninguna excepción en un método y también cuando se pro- duce pero es capturada, la ejecución continúa en la sentencia siguiente a catch, excepto si se fuerza a otro tipo de abandono mediante instrucciones como return, break o continue.Cuando la excepción no se captura, la búsqueda de la claúsu- la catch adecuada para la captura de la excepción lanzada continúa por los restan- tes métodos en orden inverso a como fueron efectuadas las llamadas. Por tanto, no se puede garantizar que las sentencias siguientes a un determinado catch vayan a ser ejecutadas. Ejemplo Compare los siguientes códigos. En el primer caso, las instrucciones Siguientes a los catch se ejecutan Únicamente si ocurre una excepción. En el segundo caso, por las instrucciones siguientes a los catch en el método leer no pasa ni cuando todo es correcto ni cuando se produce una NumberFormatException. import java.io.*; public c l a s s Ejemplo7 t public s t a t i c i n t leer ( ) i InputStreamReader isr = new InputCtreamReader(System.in); BufferedReader br = new BufferedReader(1sr); String cadena = " ' I ; try cadena = br .readLine ( ) ; return Integer.parseInt(cadena);
  • 361. Manejo de excepciones 349 //cuando todo es correcto sale 1 catch (IOException e) o catch (NumberFormatException e) i i / / Instrucción siguiente a catch System.out .println("Pasa solo cuando ocurre excepción") ; return O; public s t a t i c void main (String args [ I ) i i n t n = 0; System.out.print ("Deme un número entero entre 1 y 20 ' I ) ; n = leer ( ) ; i n t i=l; while (i <= n) f System.out.println ("2""+i+" = "+Math.pow(2,i)); it+; 1 import java.io.*; public c l a s s Ejemplo8 t public s t a t i c i n t leer() i InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader (isr); String cadena = ""; try I cadena = br.readLine ( ) ; return Integer.parseInt(cadena); 1 catch (IOException e) I 1 / / Instrucción siguiente a catch System.out.println("No pasa cuando no hay error ni" + return O; "cuando seproduceunNumberFormatException"); public s t a t i c void main (String args[]) I
  • 362. 350 Java 2. Manual de programación int n = O; System.out.print("Deme un número entero entre 1 y 20 " ) ; t=Y i 1 catch(NumberFormatException e) I } int i = 1; while (i <= n) i n = leer ( ) ; S y s t e m . o u t . p r i n t l n ( " 2 ^ " + i + " = "+Math.pow(2,i)) ; i++; 1 1 I Nota: El bloque finally sirvepara colocar en él instruccionesque se desea se realicen siempre que se sale de un bloque t r y y es opcional, pero pasa a ser obligatorio cuando un bloque t r y no va seguido por ninguna claúsula catch ya que, como se dijo, el bloque t r y no puede aparecer solo. El formato general es: try 1 } catch(Tipo-de-excepcion identificador) i 1 //otros catch si los hubiera finally { 1 ... . . . ... Las instrucciones colocadas en el bloque f i n a l l y se realizan siempre que se sale del bloque t r y : tanto si se ha producido una excepción y se ha capturado, como si no se ha capturado, como si no se ha producido la excepción, como si se ha salido del bloque t r y con r e t u r n , b r e a k o c o n t i n u e . No resulta, pues, adecuado poner en un bloque f i n a l l y sentencias que a su vez puedan produ- cir nuevas excepciones.
  • 363. Manejo de excepciones 351 Ejemplo Aunque el tratamiento de archivos se verá en el capítulo siguiente, dado que el tnanejo de excepciones es muy importante en el trabajo con archivos, se muestra a continuación el control de excepciones en un programa diseñado para comparar dos archivos especificados mediante la línea de órdenes. Para comprender la imple- mentación efectuada se necesita conocer que los argumentos pasados en la línea de órdenes a un programa se reciben por el método main y se almacenan en el array unidimensional de tipo string que dicho método especifica siempre como pará- metro. public static void main (String args [ I ) Los argumentos escritos a continuación del nombre del programa se separan unos de otros por un espacio en blanco y Java almacenará el primero de ellos en args [ O ] ,el segundo en args [ 1] ,y así sucesivamente. El programa compara los archivos, efectuando una lectura secuencia1 de ambos y comprobando la igualdad entre lo que va leyendo de cada uno de ellos. Se detiene cuando encuentra alguna diferencia o uno de los archivos termina. La claúsula t r y inicial prueba de forma agrupada diversas excepciones que se pueden producir en el programa. No obstante, en el caso de que la excepción sea generada por no encontrarse el archivo, conviene identificar cuál de los dos archi- vos pasados como parámetros es el que no ha sido encontrado, por tanto se colo- can dentro del try anterior otros dos bloques t r y que permitan identificar cuál de ellos ha sido la causa. La instrucción de cierre de archivo debe aparecer en el boque finallypara que siempre sea ejecutada y como lanza una IOException ésta vuelve a ser capturada. La llamada al programa debe efectuarse de la siguien- te forma: C:libroTemal3>java CompArch a.txt b.txt Una llamada sin parámetros produce la salida siguiente: C:libroTemal3>java CompArch La llamada debe ser: java CompArch archivo1 archivo2 Otros casos considerados son aquellos en los que alguno o ambos archivos no existen. import java.io.*; class CompArch I
  • 364. 352 Java 2. Manual de programación public static void main (String args [ ] ) l int i = O, j = O; FileInputStream fl = nuii; FileInputCtream f2 = null; try t / / Abre el primer archivo try i //Excepción por apertura del archivo fl = new FileInputCtream(args [O]) ; 1 c a t c h ( F i 1 e N o t F o u n d E x c e p t i o n e) t 1 Cystem.out.println(args[O] + 'I Archivo no encontrado") ; / / Abre el segundo archivo try I f2 = new FileInputCtream(argc[11) ; catch(Fi1eNotFoundException e) I System.out.println (args[l] + " Archivo no encontrado"); i / / Compara los archivos do t /*Las excepciones generadas en la lectura se capturan i = fl.read0; j = f2.readO; if (i ! = j) break; por el try externo * / I while(i ! = -1 & & j ! = -1); / / fin de archivo if(i ! = j) else System.out.print1n ("Los archivos son diferentes.") ; System.out.println("Los archivos son iguales.' I ) ; i catch (IOException e) t System.out.println("Error");
  • 365. Manejo de excepciones 353 I c a t c h ( A r r a y I n d e x O u t 0 f B o u n d s E x c e p t i o n e) i Cystem.out.println ("La llamada debe ser: "+ "java CompArch archivo1 archivo2"); 1 catch(Exception e) I } finally i / / ]ava.lang.NullPointerException try i / * el cierre de a r c h i v o no debe colocarse en el anterior bloque try pues pudiera no ejecutarse. La operación de cierre lanza una excepción que hay que tratar * / if (fl ! = null) fl .close0; catch ( IOException e) i 1 try t if (f2 ! = null) f2.closeO; 1 catch ( IOException e) t } I Nota: Los argumentos pasados en línea de comandos a un programa se reci- ben por el método main y se almacenan en el array unidimensional de tipo String que dicho método especifica siempre como parámetro. Cuando se llama al programa sin parámetros, la posterior referencia a losmismos origina una excepción del tipo Array IndexOutOfBoundsException. 13.7. CREACIÓN DE EXCEPCIONES En Java es posible definir nuevas excepciones específicas para una determinada situa- ción, que se usarán para detectar anomalías en el funcionamiento de una aplicación.
  • 366. 354 Java 2. Manual de programación Para crear una excepción se define una subclase de Exception que implemente un constructor con un parámetro de tipo String y sobreescriba el método getMecsage ( ) de la clase Throwable. Hay que tener en cuenta que la clase Exception no define ningún método, sólo hereda los definidos por Throwable. Ejemplo Creación de una nueva excepción. c l a s s NuevaExcp extends Exception ! String mensaje; public NuevaExcp (String causa) i I mensaje = causa; public String getMessage ( ) return mensaje; Para usar la nueva excepción la aplicación creará y lanzará un objeto de ese tipo cuando se cumpla una determinada condición. Como en cualquier otro caso, la excepción deberá ser capturada o declarada escribiendo su tipo en la cabecera del método que la lanza precedido por la palabra reservada throws.Si se lanza desde main el tratamiento no se podrá posponer y habrá que capturarla. Ejemplo Esta aplicación que usa la nueva excepción (NuevaExcp).La excepción se lanza y captura en main.El ejemplo lanza la excepción siempre, aunque lo normal sería que ésta sólo se lanzara cuando ocurriera algún motivo. public c l a s s Ejemplo9 i public s t a t i c void main (String[ I argc) i try i / / se lanza siempre throw new NuevaExcp("C1n motivo"); I catch (NuevaExcp e)
  • 367. Manejo de excepciones 355 System.out.println(e.getMessage0); El programa siguiente solicita la edad y, si no está en el rango adecuado, lanza una excepción. import java.io.*; public c l a s s Ejemplo10 public s t a t i c void main (String args[]) i InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String cadena; i n t edad = O; System.out.print ("Introduzca la edad " ) ; try I cadena = br .readLine ( ) ; edad = Integer.parseInt(cadena); i f (edad < 18 1 1 edad > 65) throw new FueraDeRango("ExcepciÓn: valor fuera de rango"); System.out .println("Edad: " + edad); catch (Exception e) i f (e instanceof IOException) else i f (e instanceof NumberFormatException) else System.out .println("Error de entrada/salida") ; System.out .println("No tecleó un número entero"); System.out.println(e.getMessage()) ; c l a s s FueraDeRango extends Exception I String mensaje; public FueraDeRango (String causa) i 1 public String getMessage ( ) i I mensaje = causa; return mensaje; i
  • 368. 356 Java 2. Manual de programación Ejemplo El problema de las Torres de Hanoi es un problema clásico de recursión. Se tienen tres torres y un conjunto de discos de diferentes tamaños. Cada disco tiene una perfora- ción en el centro que le permite ensartarse en cualquiera de las torres. Los discos han de encontrarse siempre situados en alguna de las torres. Inicialmente todos están en la misma torre, ordenados de mayor a menor, como se muestra en el dibu- jo. Se debe averiguar los movimientos necesarios para pasar todos los discos a otra torre, utilizando la tercera como auxiliar y cumpliendo las siguientes reglas: En cada movimiento sólo puede intervenir un disco. Origen Destino Auxiliar 2 3No puede quedar un disco sobre otro de menor tamaño. ’ El problema se puede resolver considerando que para pasar, por ejemplo, tres discos del pivote origen al destino, han de pasar dos discos al pivote auxiliar, mover uno al destino y mover dos discos del auxiliar al destino. Paso 7 1 Orinen Destino Auxiliar Paso 3-~ Paso 2 -~~ Oriqen Destino AuxGr-T Oriqen Destino Auxiliar El paso 1, vulnera la primera regla, pero para solucionarlo, podemos recurrir a la misma mecánica: movemos un disco de origen a destino, movemos el siguiente al auxiliar y, por último movemos el disco de destino a auxiliar. Fases del Paso 1 1 Origen Destino Auxiliar 1 Origen Destino Auxiliar ~ Origen Destino Auxiliar Lo mismo ocurriría con el paso 3 y se solucionaría de la misma forma. Se creara la clase Hanoi para resolver el problema. En esta clase el método movsTorre lanza una NuevaExcp si el número de discos es negativo. El método
  • 369. Manejo de excepciones 357 m a i n de la clase PruebaH captura y trata las excepciones; vuelve a pedir el núme- ro de discos cuando éste fue negativo y ante cualquier otro tipo de excepción, como introducir una letra en lugar de un número, el programa termina. public class Hanoi private s t a t i c void movsTorre ( i n t ndiscos, i n t origen, i n t destino, i n t auxiliar) throws NuevaExcp i //Control Excepciones i f (ndiscos < O) i f (ndiscos == O) i f (ndiscos == 1) else throw new NuevaExcp ("Numero de discos incorrecto") ; return ; System.out.println("Paso disco de "+origen+" a "tuestino); movsTorre(ndiscos-1, origen, auxiliar, destino); Cystem.out.println("Paso disco de " + origen t " a 'I + destino) ; movsTorre(ndiscos-1, auxiliar, destino, origen); public Hanoi ( i n t n)throws NuevaExcp i System.out.println("Bienvenidoa las torres del fin del munao"); Cystem.out .println("Movimientos: "+ ( i n t )(Math.pow(2,n)-1)) ; Cystem.out .println("Listado: " ) ; movsTorre(n, 1, 2, 3); / / esta clase ya ha sido comentada c l a s s NuevaExcp extends Exception i String mensaje; public NuevaExcp (String causa) I mensaje = causa; i public String getMecsage ( ) I return mensaje;
  • 370. 358 Java 2. Manual de programación import java.io.*; public class PruebaH I public static void main (String[] args) i int n = O; boolean repetir = false; do t try I repetir = false; System.out.println("Introduzca número de discos:") ; InputStreamReader isr = new InputCtreamReader(System.in); BufferedReader br = new BufferedReader (isr); n = Integer .parseInt(br.readLine ( ) ) ; Hanoi h = new Hanoi(n); 1 catch (NuevaExcp el) t System.out .println("tEl número de discos no puede "+ "ser negativo") ; repetir = true; 1 catch (IOException e2) { 1 catch (Exception e3) i 1 System.err.println ("Error de lectura"); System.err.println (e3); 1 while (repetir); 1 13.8. MÉTODOS DE LA CLASE Throwable public java.lang.Throwable fillInCtackTrace() Devuelve un objeto con los métodos en ejecución en el momento de lanzarse la excepción. public java.lang.String getMessage0 Devuelve el mensaje descriptivo almacenado en una excepción.
  • 371. Manejo de excepciones 359 public void printCtackTrace() Muestra por consola un mensaje con la clase de excepción, el mensaje descriptivo de la misma y una lista con los métodos en ejecución en el momento de lanzarse la excepción. public void printStackTrace(java.io.PrintStream p l ) Envía el mensaje anteriormente especificado al flujo que se le especifique como parámetro. public java.lang.String tostring() Devuelve una cadena descriptora de la excepción.
  • 372. D I iI I i l l 111 I I Arch¡vos CONTENIDO 14.1. La clase File. 14.2. Flujos. 14.3. Apertura de archivos. 14.4. Encadenamiento de flujos 14.5. Excepciones en archivos. 14.6. Métodos de Inputstream. 14.7. Métodos de Outputstream. 14.8. Métodos de Reader. 14.9. Métodos de Writer. 14.10. 14.11. 14.12. 14.13. 14.14. 14.15. 14.16. 14.17. 14.18. Métodos de DataInputstream. Métodos de Dataoutputstream. Métodos de RandomAccessFile. Serialización de objetos. StringTokenizer y StreamTokenizer. Operaciones con archivos y mantenimiento de los mismos. Archivos secuenciales. Archivos directos. Funciones de transformación de clave y tratamiento de colisiones. 361
  • 373. 362 Java 2. Manual de programación Como estructura de datos, los archivos permiten el almacena- miento permanente y la manipulación de un gran número de datos. Los archivos de datos son un conjunto de datos estructura- dos que se tratan como una unidad y se encuentran almacenados en un dispositivo de almacenamiento externo. Un archivo se con- sidera formado por una colección de datos lógicamente relaciona- dos, a los que denominaremos registros, cada registro agrupa datos también con una relación lógica entre sí a los que se deno- mina campos y es el programador el encargado de estructurar los archivos de tal forma que se adapten a las necesidades del pro- grama ya que, en realidad, Java considera los archivos simple- mente como flujos secuenciales de bytes. En los archivos de datos se pueden destacar dos organizaciones fundamentales: secuencia/y la directa o aleatoria, siendo posible trabajar en Java con ambos tipos de organizaciones. La organi- zación secuencia/implica que los datos se almacenan consecu- tivamente en el soporte externo, no siendo posible acceder directamente a un determinado dato si no se recorren todos los anteriores. La organización directa permite el posicionamiento directo en un determinado lugar de un archivo para leer la informa- ción allí almacenada y no obliga al almacenamientode la misma en forma secuencial.Además, a diferencia de la secuencial, la organi- zación directa permite modificar un dato previamente almacenado, eliminarlo o insertar uno nuevo en cualquier posicióndel archivo sin que sea necesario efectuar una copia de todo el archivo cada vez que se realizauna de estas operaciones.En el presentecapítulo, se explicará el concepto de fhjo y se mostrará cómo estructurar los datos e implementar en Java ambos tipos de organizaciones. 14.1. LA CLASE F i l e Los objetos de la clase File no especifican cómo se almacena o recupera la infor- mación en un archivo, sólo describen las propiedades del mismo y permiten obte- ner información sobre él. Nota: Un objeto de la clase File posibilita la obtención de información sobre las propiedades tanto de un archivo como de un subdirectorio y permite la modificación de algunos de sus atributos. Los métodos delete y renameTo de la clase File permiten borrar y renombrar archivos. Los objetos File se crean mediante los siguientes constructores:
  • 374. Archivos 363 public File (java.io.Fiie dir, java.lang.Ctring nombre) Donde el primer parámetro es un objeto File que referencia un directorio y el segundo el nombre del archivo. public File ( 7 ava .lang .String path) El parámetro es el nombre de un directorio o bien el nombre completo, incluyendo ruta de acceso, de un archivo. public Fiie(java.lang.String path, java.1ang.Ctring nombre) Donde el primer parámetro es el nombre del directorio y el segundo el nombre del archivo. Ejemplos //ruta relativa, el directorio actual File arch = new File ("ejemplo.dat"); / * ruta absoluta, en ei siguiente caso especifica el directo- rio raiz en Windows que utiliza un separador ( ) distir.- to de ünix ( / ) * / File arch = new File ( " ' I , "ejemplo.dat"); / * es posible utilizar en una versión Windows de Java el ca- File arch = new File("/","e]emplo.dat") ; rácter/ como separador * / Métodos y campos a destacar dentro de la clase son: public static final char separatorchar public java.lang.String getName0 public 1ava.lang.Ctring getparento public java.lang.String getAbsolutePath() public java.lang.String getpath() public boolean canwrite 0 Variable inicializada co'n el separador indicado en el archi- vo de propiedades del sistema que permite especificar rutas independientes de la plataforma. Devuelve el nombre del archivo referenciado por el objeto. Devuelve el nombre del direc- torio padre. Devuelve la ruta absoluta del archivo. Devuelve la ruta relativa. Devuelve true si se puede escribir en el archivo o directo- rio. public boolean canRead() Devuelve true si se puede leer desde el archivo o directorio.
  • 375. 364 Java 2. Manual de Programación public boolean i s F i l e ( 1 public boolean : s D i r e c t o r y ( ) public ;ava.lang.String[] l i s t ( ) public boolean m k d i r ( ) public boolean d e l e r e ( ) I>euclvetrue si el archivo re- presentado por el objeto F i l e es un archivo normal. Devuelve t r u e si el archibo representado por el objeto ?i 10 es un directorio. Devuelve un array con los nom- bres de los archivos y directo- rios existentes en el directorio especificado por el objeto F i l e . Esta lista no incluye el directo- rio actual ni el padre del actual. Crea el directorio especificado por el objeto F i l e . Borra el objeto 0 1 ~ ecspecifica- do, cuando se trate de un direc- torio cste ha de estar vacio public boolean renar?eTo (java.i o . F i l e dect) lienombra el archivo especifi- cado por el objcto F i l e con el nombre del archivo File pasado como parámctro y devuelve t r u e cuando la operación se efectúa con éxito y f a l c e si se intenta renoinbrar un archivo cambiándolo de directorio. public boolean e x i s t s ( ) Ejercicio Mostrar el contenido de un subdirectorio. Detielbe t r u e si existe el ob.jeto F i l e especificado y f a l c e en caso contrario. Figura 14.1. Listado del contenido de un subdirectorio
  • 376. 7 Archivos 365 import java.io.*; public class Listado t public static String l e e r ( ) InputStrearnReader isr = new I n p u t C t r e a m R e a d e r ( S y 3 t e - . - n ) ; BufferedReader br = new EufferedReader(1sr); try return br.readLine0; i catch(Excepticn e) t i return I"'; 1 public static void main (Strin,-[] a r g s j Systern.out.println("Indique nombre de cubdirecEoris"); System.out .println("Trayectoria absoluta, ej : C::.icrcj") ; String nomdir = leer(); File arch = new File(norndir); if (arch.exictc( 1 j if (arch.isnirectory ( ) ) { Systern.out.println ("iontenibo de "Tnom5:r) ; String arr[j = arch.list0; for(int J = 3; j < arr.length; I++) I File otro = new File(nomdir + ""+arr[]]); if ( o t r o . isDirectory ( 1 ) else System.out .println(arr[j] + " < f i R > " j ; Systen.out.printic(arr[jl); else System.out .println(r~omdirA"no es un directorio") ; else Cyster..out.println("No existe"); 1 Ejercicio i I Utilice AWT para efectuar la misma tarea que el ejercicio anterior y defina una clase anónima para el cierre de la ventana.
  • 377. 366 Java 2. Mar ual de Programación -i-i LEkr LE Figura 14.2. Listado del contenido de un subdirectorio. Pantalla inicial. Contenidci de c libro A Temaül qCilR5 Tema1 1 <[)IR- _. 1 Figura 14.3. Listado del contenido de un subdirectorio. import java.awt.*; import java.awt.even:.*; import java.io.*; public class EjFile extends Frame implements ActionListener TextField textoi; TextArea texto2; public EjFile ( ) cet¿ayoct (new BorderLayout ( ) ) ; //empleo de Ena clase anónima
  • 378. Archivos 367 aadWindow;istep.er (new WindowAdopter ( ) t public void windowclosing (WinCc,dEver.te) System.exit (3); I 1 ) ; textol = new TextField ("Introduzca en esze -,gar"- textol.selectAll ( 1 ; add ("North",textolj ; textol.addActionListener(this); texto2 = new TextArea 0; add ("Center", texto2) ; "el novbre ae un sundirectorio", 55); public void actionPerformed(ActionEveKt e ) I File arch = new File (textol.getText( ) ) ; if (arch.exists( ) ) if (arch.isDirectory ( ) ) texto2.append ("Contenido de " + arch t "n"); String arr [ ] = arch.list ( ) ; for(int J = O; j < arr.length; jc+) i File otro = new File,(arch+ " " f arr [j]j ; if (otro.2sDirectory ( ) 1 texto2 .append(arr[ j1 + 'I <CIX>" - "F."); else texto2.append (arr[ J ] + "n"); I I else texto2.append (e.tostring ( ) - " nc es cc direitsri3"); else texto2.append (e.tostring (j + " n3 existe"); public static void main( String args[] ) EjFile vt = new EjFileO; vt.setTitle ( "Ejemplo FILS" ) ; vt.setSize( 400,250 ) ; vt.setVisibie(truej;
  • 379. 368 Java 2. Manual de Programación 14.2. FLUJOS Los programas en Java realizan las operaciones de entrada/salida a través de,flu- jos; así se consigue gestionar de forma similar la entrada/salida sobre dispositi- vos muy diferentes, como teclado, pantalla, impresora, una conexión a red, un bz@r en memoria o un archivo en el disco. A diferencia de la pantalla, la impre- sora no tiene definido en Java un flujo de salida estándar y para sacar por impre- sora los resultados de un programa hay que asociar un flujo al puerto (LPT1, ...) donde esté conectada. Las diferentes clases de flujos se encuentran agrupadas en el paquete java .io y en la parte superior de esta jerarquía destacan las clases: Inputstream,Outputstream, Reader, Writery RandomAccessFile. Figura 14.4. Clases de flujos que heredan de Object. inputstream es una clase abstracta, superclase de otras concretas que tratan con flujos de entrada de bytes, mientras que Outputstream es la clase abstracta superclase de otras que representan un flujo de salida de bytes. Estas clases definen, pues, la funcionalidad básica común a todas las clases de flujo de bytes. Vea la Figura 14.5. Writer es una clase abstracta para escribir caracteres en flujos y Reader la clase abstracta cuyas subclases podrán leerlos (Fig. 14.6.). Cuando se trabaja con Reader o Writer el flujo se orienta a Unicode (16 bits) y con Stream a bytes (8 bits). Las clases Stream,en gran parte, se consideran obsoletas, ya que Java usa Unicodey tiene más sentido usar Reader/Writer que trabajar con byres, donde Java tiene que traducir los bytes en Unicode para impri- mirlos y de vuelta en Unicode cuando los lee. Por otra parte, en adición a Stream,Reader y Writer,el paquete java.io define la clase RandomAccessFile que permite implementar archivos de acce- so directo.
  • 380. Archivos 369 Figura 14.5. Inputstream y Outputstream,jerarquía de clases.
  • 381. 370 Java 2. Manual de Programación Reader I Figura 14.6. Reader y Writer, jerarquía de clases. 14.3. APERTURA DE ARCHIVOS Para crear, escribir o leer un archivo se requiere establecer un flujo a/desde él; las clases capaces de crear un flujo aidesde un archivo requieren una referencia a un objeto File o un nombre de archivo como argumento. Estas clases son: La subclase FileOutputCtream hereda de OutputCtream y permite crear un flujo de salida para escribir bytes en un archivo. Los constructores son: public FileOurputCtream(java.lang.String nombre). public FileOctputCtream (java.io.File file) / / f i l e es un objeto F i l e public FiLeCutputCtream (java.lang.Ctr;ng nombre, boolean a ñ a d i r ) .
  • 382. Archivos 371 Los tres constructores lanzan excepción. Con los dos primeros si el archivo existe y se abre de esta forma, se destruye. El último constructor permite aña- dir datos a un archivo existente, cuyo nombre viene especificado por nombre. Ejemplo Fileoutputstream f1 = n e w FileOutputCtream ("info.txt"); o bien File arch = n e w File("ejemplo.da~"j; Fileoutputstream f2 = n e w FileOutputStream (arch); Un flujo debe cerrarse cuando ya no vaya a utilizarse con las sentencias sufi- cientes: fl.close0; f 2 .close ( j ; La subclase FileInputStream hereda de Inputstream y permite crear un flujo para lectura de bytes desde un archivo. La lectura comienza desde el principio del archivo y cuando se leen datos del mismo, para que se puedan volver a leer los datos del principio es necesario cerrar el flujo y volverlo a abrir. Los constructores son: public FileInputStream(]ava.ic.File f i l e ) public FileInputCtream(java.lang.String nombre) Ambos constructores lanzan una FileNotFoundException Ejemplo FileInputStream fl = n e w FileInputStream("notas. txt"); o bien File arch = n e w File ("e]emplo.txt"j ; FileInputStream f2 = n e w FiLeInputStream(arch); El flujo se cierra de modo similar al caso anterior. Filewriter hereda de Writer y proporciona la posibilidad de crear un flujo para escritura de caracteres en un archivo. Los constructores son:
  • 383. 372 Java 2. Manual de Programación public FiieWriter(java.1o.F public FileWriter (]ava.lang public F-leWr-ter (7ava.lar.g le f i l e ) String nombre) String nombre, boolean añadir) y lanzan una IOException.Los dos primeros constructores destruyen una archivo existente; el último permite añadir datos al final del mismo. Ejemplo FlieWrlter fe new FileWriter ("info.txt"); fe.:lose ( ) ; . . . FileReader permite crear un flujo para la lectura de caracteres desde un archivo. Análogamente a lo que ocurre con FileInputStream,la lectura comienza desde el principio del archivo y cuando se leen datos del mismo, para una nueva lectura desde el principio es necesario cerrar el flujo y volverlo a abrir. Los constructores son: public FileReader (lava.io.F i i e f i l e ) public FileReader(java.lang.String nombre) y lanzan una excepción FileNotFoundException. Ejemplo FileReader fl = new FileReader ("info.txt"); fl.close ( ) ; . . . La clase RandomAccess File permite el acceso directo (también llamado ucceso aleatorio) a una determinada posición dentro de un archivo, así como la lectura y escritura de datos en dicho archivo. Esta clase no deriva de Inputstream ni de Outputstream,sino que implementa las interfaces DataInput y Dataoutput que definen los métodos de entradahalida bási- cos. El flujo se crea mediante: public RandcmAccessFile(java.io.File f i l e , java.lang.Ctring m) throws FileNotFoundException public RandorrSiccessFile(java.lang.Ctring nombre,]ava.iang.String m) throws IOException El parámetro m representa el modo en el que se creará el flujo y en la llamada se le podrá pasar: r (lectura) o rw (lectura/escritura).
  • 384. Archivos 373 Ejemplo RanaomAcceccFile :le = new RaidomAcceccFile ("datos.=a-", "rw"); f le.close ( 1 ; Nota: En Java RandomAccessFilees la clase que permite el acceso directo y FileReader,FileInputStream, FileWritery FileOutputStream ofrecen tratamiento secuencial. 14.4. ENCADENAMIENTO DE FLUJOS Para conseguir flujos personalizados,que se adapten a los requisitos de transferencia de datos en Java se utiliza la composición de flujos. Este sistema sirve no sólo para archi- vos, si no que se aplica también a los flujos de red y de conector (socket).Existen una serie de flujos que efectúan tratamientos especiales de la información; son, por ejemplo: InputStreamReader OutputCtreamWriter BufferedReader BufferedWriter BufferedInputStream BufferedOutputStream Printstream PriztWrLter DataInputCtream DataoutputCtream Convierten bytes a caracteres. Establecen un buffer para caracteres I Establecen un buffer para bytes Escribe valores y objetos en un flujo de bytes. Escribe valores y objetos en un flujo de caracteres. Permiten leer y escribir tipos de datos primitivos, efectuando conversiones desde un flujo de bytes a dichos tipos de datos primitivos. Estos flujos pueden asociarse unos con otros y con los de apertura de archivos para obtener el flujo deseado ai escribir o leer de un archivo. Por ejemplo, la clase FileOutputStreamconsidera el flujo como una colección de bytes, pero no como unidades más grandes; cuando se desea imprimir unidades más grandes, se le puede asociar un objeto Printstream.Los objetos PrinStream admiten los métodos print y println para valores y objetos. Cuando se trata de objetos, estos métodos
  • 385. 374 Java 2. Manual de Programación llaman al método tostring del objeto e imprimen el resultado. Prinstream almacena los datos a imprimir en un bufer con la finalidad de trabajar de la forma más eficiente posible y disminuir el número de operaciones de transferencia, así los datos sólo se escriben cuando se llena el buffer o termina el programa. Esto resulta muy con- veniente para los archivos, pero no para la pantalla. Systern. out es una instancia de PrinStream y por eso print y print1n son los métodos que se vienen utilizan- do para mostrar información por pantalla. La clase posee el método public void flush ( ) que se utiliza para asegurar que los buffers de datos se escriben físicamente en el flujo de salida. Ejemplos 1. System.out.print ("Deme una cadena " ) ; System.out .println("y a continuación pulse RETURN"); / * Habitualmente Java vacía el buffer cuando, este se llena, cuando termina el programa y cuando se efectúa una lectura desde teclado, por lo que la siguiente instrucción no suele ser necesaria * / System.out.flush0 ; 2. File f = n e w File ("texto.txt"); //la siguiente instrucción abre el archivo para escritura Fileoutputstream fe = n e w FileOutputStream(f) ; Printstream salida = n e w PrinStream (fe); / * Después se utilizarían los métodos println o print de salida.println ("Los f l u j o s proporcionan canales "+ Printstream * / "de comunicación") ; / * P o r último seria conveniente cerrar los f l u j o s con el método close * / Otro encadenamiento se puede utilizar para leer cadenas desde un archivo abierto con FileInputStream.El programa que lee llama a un BufferReader que utiliza un InputStreamReader,que a su vez utiliza un FileInputStream para leer del File. Ejemplo / / Objeto File File f = n e w File ("texto.txt"); //Apertura del archivo para lectura. F l u l o de bytes FileInputStream fl = n e w FileInputStream(f);
  • 386. Archivos 375 //Conversión a f l u j o de caracteres InputCtreamReader entrada = n e w InputStreamReader(f1j; / * Buffer para caracteres y objeto que permite leer una línea BufferedReader lectorcad = n e w BufferedReader(entrada); / / Lectura String cadena = lectorCad.readLine0; //lanza una IOException completa * / El método readLine ( ) de la clase BufferedReader permite leer una secuencia de caracteres de un flujo de entrada y devuelve una cadena; además, uti- liza un byffeer para mejorar el rendimiento. Para efectuar lectura desde teclado, se utiliza system.in,que es una instancia de java.i o . Inputstream;por esta razón, las lecturas de una cadena desde teclado se han efectuado con un método análogo ai anteriormente expuesto. Ejemplo InputCtreamReader entrada = n e w InputCtreamReader(System.in); BufferedReader lectorcad = n e w BufferedReader(entradaj; String cadena = lectorcad.readLine ( ) ; DataInputStream y DataOutputStream se utilizan respectivamente para leer o escribir en un flujo FileOutputStream o FileOutputStream datos de tipos primitivos y recuperarlos como tales y también en este caso se aplica enca- denamiento. Ejemplo FileInputCtream fe = n e w FileInputCtream DataInputCtream de = n e w DataInputStream cad = de.readUTF(j; de.close ( ) ; //método heredado de Filter "datos.dat"); fe); nputstream 14.5. EXCEPCIONES EN ARCHIVOS Cuando se trabaja con archivos se pueden producir errores de entrada/salida y Java obliga a prever este tipo de errores y recoger las excepciones que pueda lanzar el sistema. Las excepciones del paquete java .io se muestran en la Figura 14.7. Cuando el programador diseña un método tiene dos opciones con este tipo de excepciones: listarías en la cabecera del mismo o bien recogerlas y tratarlas. Si está sobrescribiendo un método del que no puede modificar la interfaz, se verá obligado a recoger estas excepciones y tratarlas en el propio método. Las excepciones en el trabajo con archivos pueden ser lanzadas por los métodos de escritura y lectura, pero además hay que tener en cuenta que la apertura de un
  • 387. 376 Java 2. Manual de Programación archivo puede producir una excepción IOException cuando falla la operación; por ejemplo, si se intenta abrir para lectura un archivo que no existe, y el cierre de un archivo con el método close también puede producir una IOException.Por otra parte, los archivos en Java terminan con una marca de fin de archivo y cuando en la lectura de un archivo se llega a dicha marca se puede lanzar una EOFException. Capturar y tratar las excepciones en la apertura y cierre de un archivo. public class ControlExcepciones t public static void main (String[] args) i AbreYCierra arch = new AbreYCierra ( ) ; arch.leer ( ) ; import java.io.*; public class AbreYCierra I FileInputStream fl = null; public void leer0 File f = new File("texto.txt"); fl = new FileInputCtream(f); 1 catch(I0Exception e) I Cystem.out .println(e); 1 finally t try i / * no debe colocarse en el primer bloque try ya que if (fl ! = null) fl.close0; 1 catch(I0Exception e) pudiera no ejecutarse * / Cyctern.o.dt.println(e); Systerr..out.println("Fin"); :t 1
  • 388. Archivos 377 Figura 14.7. Excepciones del paquete 1ava. 10 Nota: Al trabajar con archivos, las excepciones pueden ser lanzadas por los métodos de lectura y escritura y también por las operaciones de apertura y cie- rre del archivo. El compilador obliga a tratar dichas excepciones.
  • 389. 378 Java 2. Manual de Programación Nota: Cuando se detecta el fin de flujo: .El método read de inputstream devuelve - 1. El método readLine devuelve null. Los métodos que se exponen en DataInputStream generan una EOFException. 14.6. MÉTODOS DE inputstream public int available ( ) Deuelve el número de bytes actualmente disponibles para su lectura en el flujo de entrada. public void close 0 Cierra el flujo de entrada. Genera una IOException si se produce un error. public synchronized void mark(int num) Coloca una marca en el flujo de entrada, válida hasta que se lea el número de bytes especi- ficado como parámetro. public boolean marksupported0 Comprueba si el flujo de entrada soporta los métodos mark y reset. public abstract int read0 Devuelve como entero el siguiente byte disponible de la entrada. public int read(byte b [ I ) Intenta leer desde el flujo de entrada el número de bytes necesarios para llenar el array b pasado como parámetro y devuelve el número real leído. public int read(byte b [ 1 , int d e s d e , int c u a n t o s ) Intenta leer desde el flujo de entrada el número de bytes especificados corno tercer paráme- tro y los introduce en el array b empezando en b [decde] . public synchronized void reset ( ) Coloca el puntero de entrada en la marca establecida con mark. public long skip(1ong n) Salta y descarta n bytes del flujo de entrada, devolviendo el número real de bytes saltados. Excepto m a r k , todos los métodos restantes lanzan una IOException.
  • 390. Archivos 379 14.7. MÉTODOS DE Outputstream public void close() Cierra el flujo de salida. Genera una IOException si se produce un error public void flush() Vacía y limpia el buffer. public void writ-e (byte b [ I ) Escribe b . length bytes del array b en el flujo de salida. public void write(byte b [ 3 , int d e s d e , int cuantos) Escribe b . cuantos bytes del array b en el flujo de salida comenzando desde b [doczel. public abstract void writeíint 5) Escribe un Único byte en el flujo de salida. Todos estos métodos lanzan una excepción IOException. 14.8. MÉTODOS DE Reader La clase Reader es una clase abstracta, superclase de todos los flujos de entrada orientados a carácter que proporciona un conjunto de métodos similar al que la clase inputStream proporciona para los flujos de entrada orientados a byte. Todos sus métodos lanzan una excepción IOException. public public public public public public public public public abstract void close ( ) void mark (int n u m l a r a c t e r e s ) boolean markSupported() int read() int read (char c [ ] ) abstract int readíchar c[ I , int d e s d e , int cuantos) boolean ready ( ) void reset 0 long skip(1ong n) 14.9. MÉTODOS DE Writer La clase Writer es una clase abstracta superclase de todos los flujos de salida orientados a carácter que proporciona un conjunto de métodos similar al que la clase Outputstream proporciona para los flujos de entrada orientados a byte. Todos sus métodos lanzan una IOException.
  • 391. 380 Java 2. Manual de Programación public abstract void close ( ) public abstract void flush ( ) public void write (char c [ I ) public abstract void write (char c[ 1 , int d e s d e , int public void write (int c) public void write (lava.lang.Ctring c a d e n a ) public void write (java.lang.Ctring c a d e n a , int d e s d e , int c u a n tos) c u a n t o s ) 14.10. MÉTODOS DE DataInputStream Esta clase actúa como filtro envolviendo un flujo de entrada para así permitir la lectura desde un archivo de datos de tipos primitivos. Métodos de DataIripu t Stream son: public public public public public public public public public public public public public public public public public final int read (byte b u f f e r [ ] ) final int read(byte b u f f e r [ 1 , int d e s d e , int c u a n t o s ) final boolean readBoolean0 final byte readByte( ) final char readchar( ) final double readDoubie( ) final float readFloat( ) final void readFully(byte b u f f e r [ 1 ) final int skipBytes(int n) final void readFully(byte b u f f e r [ 1 , int d e s d e , int c u a n tos) final int readInt ( ) final long readLong ( ) final short readshort( ) final int readUnsignedByte( ) final int readUnsignedChort( ) final java.lang.Ctring readUTF() static final java.lang.Ctring readUTF(java.io.DataInput e n t r a d a ) Todos estos métodos lanzan una IOException y casi todos ellos están defini- dos en la interfaz DataInput implementada por la misma. Los métodos readUTF devuelven una cadena de caracteres Unicode y generan una excepción del tipo UTFDataFormatException si los bytes no representan una codificación UTF- 8 válida de una cadena Unicode. En el formato UTF-8' los dos primeros bytes indi- can el número de bytes que han de ser leídos a continuación para formar la cadena. El nombre de los restantes métodos realizan las tareas que dicho nombre sugiere. ' Las siglas UTF-8 significan Formato de Transformación Universal 8; es un formato de transmisión para Unicode válido para los archivos de sistemas Unix.
  • 392. Archivos 381 14.11. MÉTODOS DE DataOutputStream Esta clase actúa como filtro envolviendo un flujo de salida para así permitir la escritura en un archivo de datos de tipos primitivos. Todos los métodos de DataOutputStream,excepto size ( ) lanzan una IOException.Métodos de DataOutputStream son: public void flush() public final int size() public synchronized void write (byte b u f f e r [ i , int desde, int c u a c t s c ) public synchronized void write (int v a l o r ) public final void writeBoolean(boo1ean b o o l e a n o ) public final void writeByte (int v a l o r ) public final void writeBytec (]ava.lang.Ctring c a d e n a ) public final void writechar (int c a r á c t e r ) public final void writechars (java.lang.Stringc a d e n a ) public final void writeDoubie (double v a l o r ) public final void writeFloat:(float v a l o r ) public final void writeInt(int v ) public final void writeLong (long v) public final void writeshort (int v ) public final void writeUTF(]ava.lang.String c a d e n a ) El método s i z e ( ) devuelve el número de bytes escritos y, por su nombre y lo comentado en otras ocasiones, puede deducirse el significado de los restantes. Casi todos los métodos de esta clase están definidos en la interfaz Dataoutput imple- mentada por la misma. Nota: DataInputStream y DataOutputStream se utilizan respec- tivamente para leer o escribir en un flujo FileOutputCtream o FileOutputStream datos de tipos primitivos y recuperarlos como tales aplicando encadenamiento. 14.12. MÉTODOS DE RandomAccessFile Esta clase implementa las interfaces DataInput y Dataoutput y además de los métodos de ambas interfaces ofrece también los siguientes: public long getFilePointer ( ) Devuelve, en bytes, la posición actual en el archivo. public long length0 Devuelve, expresada en bytes, la longitud del archivo.
  • 393. 382 Java 2. Manual de Programación publice void ceek(1ong pl) Coloca en una posición especí- fica relativa al principio del archivo, de forma que las ope- raciones de lectura o escritura puedan realizarse directamente en dicha posición. 14.13. SERIALIZACIÓN DE OBJETOS En Java un registro de un archivo se puede corresponder con una clase y los cam- pos del registro coincidirían con las variables de instancia; por consiguiente, en lugar de leer y escribir series de datos agrupadas en los archivos, puede resultar más adecuado leer y escribir objetos. La serialización de objetos es la forma de guardar objetos en archivos o enviarlos a través de la red, ya que permite escribir o leer obje- tos en flujos. El mecanismo de serialización mantiene el control sobre los tipos de objetos y las relaciones entre ellos. Para que se pueda serializar un objeto, basta con establecer que implemen- te la interfaz S e r i a l i z a b l e . Esta interfaz no tiene métodos, por lo que no habrá que añadir implementaciones a la clase, pero obliga a que todos los campos de datos del objeto sean serializables; como los tipos predefinidos son todos serializables, en realidad lo único que habrá que considerar es que si desde ese objeto se refe- rencian otros, estos también hayan sido declarados serializables. La clase que permite escribir los objetos en el flujo de salida es O b j e c t O u t p u t S t r e a m y C b j e c t I n p u t C t r e a m la que permite leerlos. O b j e c t O u t p u t S t r e a m implementa la interfaz O b j e c t c u t p u t que a su vez implementa D a t a c u t p u t que le añade la capacidad de escribir, además de objetos, tipos básicos de datos. Las operaciones con archivos se harán encade- nando un O b j e c t c u t p u t s t r e a m a un F i l e C u t p u t C t r e a m y el método w r i t e o b j e c t ( o b j e t o ) es el que se utiliza para escribir objetos en el flujo abierto hacia el archivo: public final void writeObject(java.iang.0bject o b j ) Los métodos f l u s h ( ) y c l o s e ( ) se emplearán para obligar a volcar el con- tenido del bgfer y cerrar el flujo respectivamente. C b j e c t I n p u t C t r e a m implementa la interfaz C b j e c t I n p u t que a su vez implementa D a t a I n p u t que le añade la capacidad de leer, además de objetos, tipos básicos de datos. Las operaciones con archivos se harán encadenando un C b j e c t I n p u t S t r e a m a un F i l e I n p u t S t r e a m y el método readobject ( ) . public final java.lang.Object readobject0 es el método que se utiliza para leer objetos en el flujo abierto hacia el archivo.
  • 394. Archivos 383 I I Nota: La serialización de objetos permite guardar en archivos objetos que implementan la interfaz Ser ia1iz ab1e. 14.14. StringTokenizer Y StreamTokenizer StringTokenizer pertenece al paquete java. util;trabaja sobre cadenas y se puede utilizar como herramienta para efectuar el análisis de las líneas leídas de un archivo de texto. La clase StreamTokenizer es miembro del paquete j a v a . io y realiza un trabajo muy similar a StringTokenizer,permitiendo dividir un flujo de entrada en fragmentos significativos mediante el empleo de unos delimitadores. El constructor es: public StreamTokenizer (java.io.Reader r) La constante TT EOF indica que se ha leído el final del flujo; de modo análogo TT EOL y TT WORD indican el fin de línea y el fin de palabra. Para inicializar los del&itadores,se emplea resetsyntax ( ) y después con el método wordchars se puede establecer la serie de caracteres que pueden constituir una palabra. El método eolIsSignificant determina que los caracteres de línea nueva sean tratados como tokens, de forma que nextToken devuelva TT-EOL cuando se lea el fin de línea. 14.15. OPERACIONES CON ARCHIVOS Y MANTENIMIENTO DE LOS MISMOS Las operaciones con archivos son aquellas que tratan con su propia estructura, tales como la creación, apertura o cierre de los mismos y que son proporcionadas por el lenguaje, en este caso Java. Además de utilizar este tipo de operaciones al trabajar con archivos, será necesario diseñar métodos que efectúen tareas de mantenimien- to. El mantenimiento de un archivo incluye las siguientes operaciones: 9 Actualización Altas. Operación de incorporar al archivo un nuevo registro. Bajas. Acción de eliminar un registro de un archivo. Las bajas pueden ser de dos tipos: Ldgicu. Se efectúa colocando en el registro que se desea borrar una bandera o indicador que lo marque como borrado. Admite la posterior recuperación de la información.
  • 395. 384 Java 2. Manual de Programación Fkica. implica la desaparición de esa información del archivo de forma que no pueda ser recuperada por operaciones posteriores. Puede efectuarse mediante la sobreescritura del registro o bien creando un nuevo archivo que no incluya dicho registro. Modificaciones. Proceso de modificar la información almacenada en un determinado registro de un archivo. Consulta De un Único registro. De todos los registros del archivo. 14.16. ARCHIVOS SECUENCIALES En los archivos secuenciales los registros se almacenan unos al lado de otros sobre el soporte externo y se pueden designar por números enteros consecutivos; sin embargo, estos números de orden no se pueden utilizar como funciones de acceso y para realizar el acceso a un registro resulta obligatorio pasar por los que le prece- den. Además, este tipo de archivos no pueden abrirse simultáneamente para lectura y escritura y terminan con una marca de final de archivo. Los archivos secuenciales en Java se pueden abrir para lectura con Fi1eInputStream o Fi1eReaderypara escritura con Fi1eOutputStream o Filewriter. Cuando un archivo secuencial se abre para lectura, un puntero de datos imagi- nario se coloca al principio del archivo, de forma que la lectura siempre comen- zará por el principio. Cuando un archivo secuencial se abre para escritura, el puntero de datos imaginario puede colocarse al principio del archivo, con lo que si éste existía se perderá cualquier información almacenada en el mismo, o bien al final: public FileOutputCtream(java.lang.String nombre, boolean a ñ a d i r ) public Filewriter (Java.lang.String nombre, boolean aríadir) para así poder añadirle nueva información por el final. Un caso particular de archivos secuenciales son los archivos de texto, que están formados por una serie de líneas cada una de las cuales se encuentra constituida por una serie de caracteres y separadas por una marca de final de línea. Ejercicio Diseñar Ún programa con interfaz gráfica que muestre el contenido de los archivos de texto que se le indiquen a través de un campo de texto (Fig. 14.8).
  • 396. Archivos 305 !- mode con codepage prepate=((850) C iWINDüWSCOMMANDega I mode con codepage select=850 keyb sp,,C iWINDOWSiCOMMANDkeyboard SYS set path=%path%,C h i p Fin f Figura 14.8. Ejecución: muestra el contenido del archivo c : autoexec.bak. import java.io.*; import java.awt.*; import java.awt.event.*; public class LeeTexto extends Frame implements Actioniistener TextArea contenido; T e x t F i e l d nombre; File arch = null; public LeeTexto ( ) cetLayout (new BorderLayout ( ) ) ; addWindowListener (new W indowAdapter ( ) public void windowClosing (WindowEvent e) Cystem.exit (O) ; 1 1 ) ; nombre = new TextField(); nombre.addActionLictener(this); add ("North",nombre) ; contenido = new TextArec3( ) ; add ("Center",contenido) ; 1 public void actionPerformed (ActionEvent e) nombre.selectAll ( ) ; arch = new File (nombre.qetText ( 1 ) ; CargarArchivo ( ) ;
  • 397. 386 Java 2. Manual de Programación public static void main( String args[] ) I LeeTexto v e n t a n a = new LeeTexto ( ) ; ventana.cetCize( 400,250 ) ; v e n t a n a . cet-it-e ("Zlemplo de Lectura desde Archivo") ; ver.tana.cetV-sible(true); void CargarArc?.ivo ( 1 i File3eader f = null; SufferedReader br = null; String cadena = null; try f = new FiieReader (arch); br = new Suf feredReader (f); do cadena = br.reasLine0; if (rader,a ! = null) cor.tenido.append(cadena + " n " ) ; i while (cadena ! = null); catch (FileNozFoundExceptisn e) ! contenido.apFend("Ei arch;vo no existen"); I catch (IOException e) ccntenido.append("Errorn"); finally t=Y t if (br ! = null) { Dr.close(); //basta con cerrar el oDjeto nac exterior i catch ( IOException e) ! contenido.append ("Errorn"); i coxtenido.appexd ("F:nnn") ;
  • 398. Archivos 387 Ejercicio Un ejemplo de serialización. El programa debe permitir efectuar altas y bajas y con- sultas de los datos de los empleados de una empresa. En la implementación expuesta a continuación, las operaciones se efectúan en un array en memoria; este array es el campo de datos de un objeto de tipo Personal.El objeto Personal se recupera y escribe desdeien un archivo en el disco empleando serialización. Como los elementos del array son objetos de tipo Empleado,la clase Empleado también ha de ser serializable. El método main de la clase Ejemplo llama a: 1) leer,método que cuando el archivo existe lee el objeto, 2) operaciones,que a través de un menú de opciones permite elegir la operación a realizar, 3) escribir,que escribe el objeto en el archivo cuando dicho objeto ha sufrido cambios. La clase Empleado representa los registros y sus campos son: código, edad, nombre, domicilio y telSfono.El código es el campo clave que identifica al empleado y se supone que no se van a introducir en ningún momento códigos repetidos. Las altas se efectúan simplemente añadiendo nuevos elementos al final del array. El array se crea de nuevo, para aumentar su tamaño, en cada adición y se utiliza otro array auxiliar copiaDeLista para conservar la información anterior. Tras crear el nuevo array arrEmpleados, se copian en e1 los elementos del array copiaDeLista y se coloca al final el nuevo empleado (unEmpleado). Esta forma de trabajar imita el funcionamiento de la clase Vector del paquete java .util,que inicialmente crea un array de objetos de un tamaño determinado y, si más adelante se necesita, crea otro de mayor tamaño, mueve todos los objetos al nuevo y borra el antiguo; la clase Vector proporciona así arrays dinámicos, que aumentan o disminuyen de tamaiio en tiempo de ejecución. La baja de un empleado (método eliLminar de la clase Personal)disminu- ye el tamaño del array. La consulta pide un código y efectúa un recorrido secuencia1 del array hasta que éste se acaba o encuentra un empleado cuyo código sea igual al introducido desde teclado. En el caso de que encuentre a dicho empleado, muestra la informa- ción almacenada sobre dicho empleado. import java.io.*; public c l a s s Ejemplo static Personal lista = n u l l ; //si ?a lista s-ifre cambios se escribe en el disco s t a t i c boolean carcbios;
  • 399. 388 Java 2. Manual de Programación public static void maip(String[] args) leer ( ) ; operaciones ( ) ; escribir ( ) ; public s t a t i c void leer ( ) / * Creación considera dos casos si el archivo existe Lile fichero = new File("empresa.dat") ; i f i previamente o no * / ( ! fichero.exists ( ) ) lista = new Personal ( 1 ; System.out.printlr! ("Nuevo archivo"); else ois = new ObjecticputStream(new Fileinputstream lista = (Personal)ois.readoblect 0 ; System.out .printin("Archivo existente") ; ("empresa.dat")); 1 catch (ClassNotFoundExceptisn e) System.out .printir.("Error: " + e.tostring ( ) ) ; catch (IOException e) I System.out .println("Error: " + e.tostring ( ) ) ; 1 f i n a l l y I i f ( o i s ! = null) ois .close ( ) ; 1 catch ( IOException e) t j public s t a t i c void operaciones ( ) t short opción = O ; InpuZCtreamReader isr = new :nputStreamReader(System.in); BufferedReader br = new BLfferedReader(1sr);
  • 400. Archivos 389 int posi = -1; short código = 3; short edac = O; Ctrinq Rornbre, dorniciiio, teléfono; boolean eliminado = false; boolean error; / / Mantenimiento try t do Systern.out.println("MENC"); Systern.out.printin("?. Altas") ; Systern.oUt.println("2. Bajas") ; Systern.out.println("3. Consultas"); Systern.out.println ("4. Fin"); Systern.out.printin(); Systern.cGt.print ( " E l i j a opción: " ) ; do opción = Short .parseShort (new BufferedReacer (new inputCtrearnReader(System.in)).readLineO); while (opcL6n < 1 ' 1 opción > 4); switch (opciór.) / * Con el fin de simplificar el ejemplo, se supone case 1: / / altas q u e no se inti-od~cencódigos repetidos * / / * se trata la excepcihn para que vrelva a pedir el dato en el caso de que se ;ntroduzca un valor no n,xiérico * / do error = false; try System.out.print ("código: " 1 ; código = Short .parseshort(br.readLine ( ) ) ; catch (NumcerFormatExcepti o n ne) System.out.println ("Vaior no vál;do "+ error = true; "(ha de ser un número)"); I while (error); System.out .prini: ( " nombr e : nombre = br.reaiLine ( ) ; do { " ) ;
  • 401. 390 Java 2. Manual de Programación error = false; try System.out.print ("edad: ' I ) ; edad = Short.parseShort(br.readLlne0); catch (NumberFormatException ne) t System.out.println("Valor no váildo " f error = true; "(ha de ser UI número)"); while (error); System. o u t . print ( "domicilio : " ) ; domicilio = br.readLine ( ) ; System.out.print("teléfono: ' I ) ; teléfono = br .readLine ( ) ; 1ista.añadir (new Empleado (código, nombre, edad, domicillo, teléfono)); cambios = true; break; do case 2: / / bajas t error = false; try t System.out .print("Código a borra::: " ) ; código = Short .parseshort (br.reatlLine ( ) ) ; 1 i catch (NumberFormatException ne) System.out .println("Vaior no válido " f error = true; "(ha de ser un número)"); ! i while (error); eliminado = licta.elimlnar(código); if (eliminado) Sys tem.out .pr1nt1n ( "RegIc tro e1imiriado" ) ; cambios = true; 1 else if (licta.longitud() ! = O) else break; System.out.println ("No esta"); System.out .println("Lista vacía") ;
  • 402. Archivos 391 case 3: / / consultas do error = false; try I System.out .print("Código a buscar: " ) ; código = L h o r t . p a r s e C h o r t ( b r . r e a d l i n e 0 ) ; catch (NumberFormatYxception re) t Cystem.out .pri~tln("Valor no válido " + error = true; "(ha de ser UT. n , h e r o ) " ) ; while (error); posi = lista.biiscar (código); if (posi == -1) if (lista.lo.igitud0 ! = O) else Cystem.out .print13("Registro no encoctzado") ; Cystem.out .println("Lista vacia") ; else lista.e:emento(posi) .mostrar 0; break ; case 4: while (opci6n ! = 4); catch ( IOException e) public static void escrib;r ( ) t ObjectOutputStream ous =: null; //si hubo cambios l o s i':;cribe en el a r c h i v o try if (cambios) t out = new ObjectOutputCtream( new ous.write0bject (lista); FileOntputCtzean("empresa.dat")) ; i lista = null; catch ( IOException e)
  • 403. 392 Java 2. Manual de Programación t Cystem.out.printin("Error: " + e.toString()) ; finally t if (ous ! = null) ous.close ( ) ; catch ( IOException e) t i / * Clase Personal de la empresa. Objeto que representa un array de Empleado * / import lava.io.*; public class Personal implements Serializable private Empleado[] arrEmpleados; private int nElementos; public Personal ( ) / / Crea'el array nElementos = O; arrEmpleados = inicializar(nE1ementos); private Empleado[] inicializar(int nElementos) t return new Empleado [nElementos]; catch (OutOfMemoryError e) I System.out.println(e.toString()); return arrEmpleados; public Empleado elemento(int i ) if ( i >= O & & i < nElementos) else return arrEmpleados [ i1 ; I
  • 404. Archivos 393 System.out .println('"3 hay elementos en esa poSici6Z"); return null; I 1 public int longitud() i 1 return arrEmpleados.lencjth; public void añadir (Empleado unEmpleado) i Empleado [ ] copiaDeLista; / / el array crece conform se le van añadiendo nuevos eiementoc copiaDeLista = arrEmpleados; nElementos = copiaDeLisia.length; arrEmpleados = inicializar (nElernentoc t 1); for ( int i = O; i < nElernentos; i++ j arrErnpleados [i] = copLaDeLista[i] ; arrEmpleados[nElementos] = unEmpleado; nElementos++; public boolean eliminar(short cod) { Empleado[] copiaDeLista; int posi = buscar(cod); if (posi ! = -1) i / / el array disminuye cuando se eliminan elementos arrEmpleados [posil = null; cop1aDeLista = arrEmp:.eados ; if (copiaDeLista.lengLh ! = O) i int k = O; nElementos = copiaDeLista.length; arrEmpleadoc = inic ializar (nElementos - 1j ; for (int i = O; i < nElementos; I++) if (copiaDeLista[ i] ! = null) arrEmpleados [ k + t ] = copiaDeLista [i]; nElementos--; return true; 1 1 return false; } public int buscar(short cod) i int posi = O;
  • 405. 394 Java 2. Manual de Programación if (pos1 < nElementoc) for (int 1 = posi; I < nElementos; I++) if (arrEmpleadcc [ i] .devolvercodigo ( ) == cc d) return 1; return -1; / / Clase Empleado. Objeto que representa un registro. import ;ava._o.*; public class Enpleado implements Serlaiizable private short codigo; private short edad: private Strirg nombre, domicilio, telefono; public Empleado ( ) public nmpleado(short cod, Strinq zom, short annos, String =om, String tfno) I código = cod; noxbre = corn; edad = annos; domicilio = dcm; teléforo = tfno; public void establecerCódigo(short cod) i cócigo = cod; i public short devolvercódigo ( ) return código; i public void estabiecerNombre (String nom) I ' nombre = nori; public String devolverNombre0 return nombre;
  • 406. Archivos 395 public void establecerEdad ( s h o r t annos) t I edad = annos; public s h o r t devolverEdad ( ) t r e t u r n edad; public void ectablecerDomicilio(String dom) i domicilio = dom; public String devolverDomicilio() I r e t u r n domic i 1io; i public void establecerTelSfono (String tfno) I teléfono = tfno; 1 public String devolverlel'ifono( ) i ret u r n teiéf ono ; I public void mostrar ( ) i System.out .println(devolverCodigo( ) ) ; System.out .println(devoLverNombre ( ) ) ; Cystem.out .println(devo.LverEdad( ) ) ; System.out .println(devo..verDomicilio( ) ) ; System.out .println(devo1-verTeléfono( ) ) ; I 14.17. ARCHIVOS DIRECTOS Los registros en un archivo de acceso directo han de ser de longitud fija. En un archivo directo, el orden físico de los registros no tiene por qué corresponderse con aquel en el que han sido introducidos, y los registros son accesibles directamente mediante la especificación de un número que indica la posición del registro con res- pecto al origen del archivo. Los archivos directos, también denominados aleatorios,
  • 407. 396 Java 2. Manual de Programación se abren para lectura y escritura al mismo tiempo. En Java RandomllccessFile es la clase que permite la apertura de archivos de acceso directo y ofrece el método seek ( p o s i c i ó n ) para el posicionamiento sobre un determinado registro del srchivo. Nota: A diferencia de los secuenciales: Los archivos directos se abren para lectura y escritura al mismo tiempo. Permiten el posicionamiento sobre un determinado registro, sin que sea necesario recorrer los anteriores. 14.18. FUNCIONES DE TRANSFORMACIÓN DE CLAVE Y TRATAMIENTO DE COLISIONES Aunque la información en un archivo directo puede colocarse simplemente de forma secuencial, normalmente esto no se hace así, dado que la utilidad fundamen- tal de los archivos directos es proporcionar un rápido acceso a la información. Con esta finalidad los datos deben situarse de tal manera que puedan ser localizados rápidamente y, como éste tipo de archivos permite el posicionamiento directo en un determinado lugar del archivo y el acceso a la información en los archivos se suele efectuar utilizando una clave, la solución consiste en crear una relación perfecta- mente definida entre la clave identificativa de cada registro y la posición donde se colocan dichos datos. La clave es un campo del propio registro que lo identifica de modo único, por ejemplo el número de matrícula de un alumno en el caso de un archivo que almacenara datos de alumnos o el NIF, número de identificación fiscal, en el caso de querer guardar información sobre los clientes de una empresa. Es pre- ciso tener en cuenta que, aunque en ocasiones la clave (x)podrá ser utilizada para obtener la posición empleando simplemente la fórmula mostrada en la Tabla 14.1, otras veces esto no es posible. Tabla 14.1. Fórmula que en algunas ocasiones se puede aplicar para transformar la clave en una posición Fórmula Clave Posición relativa al comienzo del Archivo O 5*tamaño registro Posicior. = (long) (x-1)* tamaño registro;
  • 408. Archivos 397 La citada fórmula no se puede utilizar cuando el porcentaje de claves a almace- nar en el archivo es reducido en comparación al rango en el que pueden oscilar los valores de las mismas o cuando las claves son alfanuméricas. La solución en estos casos es aplicar funciones que transformen las claves a números en el rango conve- niente, a estas funciones se las denomina funciones de conversión (hash),y luego usar dichos números en la fórmula expuesta. El resultado de dicha fórmula hay que convertirlo a un tipo l o n g dado que el argumento de s e e k es de tipo long. Cuando se aplica una función de conversión puede ocurrir que dos registros con claves diferentes produzcan la misma dirección física en el soporte. Se dice enton- ces que se ha producido una colisión y habrá que situar ese registro en una posición diferente a la indicada por el algoritmo de conversión. Si esto ocurre, el acceso se hace más lento, por lo que resulta importante encontrar una función de conversión que produzca pocas colisiones. Ejemplo Imagine que las claves identificativas de los registros que desea almacenar oscilan entre los valores 1a 1O O OO O O, pero la cantidad de registros sobre los cuales se va tener que guardar información sólo es 5O. Según la fórmula de la Tabla 14.1,habría que disponer de un archivo de tamaño (1000000-1)* tamañoRegistro para así poder situar en la posición adecuada cualquier registro que fuera necesario almacenar. Este archivo sería demasiado grande y estaría en su mayor parte deso- cupado. Puesto que se sabe que no va a ser necesario guardar más de 50 registros, se podría aplicar una función de conversión como la siguiente: x = clave % 50; / * dividir por un número primo da origen a un menor número de colisiones, es decir de restos repetidos * / que convertiría cualquier clave entre 1 y 1 0 0 0 0 0 0 en números entre O y 49. Lógicamente con esta función a registros con diferentes claves les puede corres- ponder el mismo x y, por tanto, la misma posición. posición = x * tamañoRegistro; / * la función hash aplicada hace innecesario restar l a x * / Existen muchos tipos de funciones de conversión. La eficiencia de la función hush y el método de resolución de colisiones se mide por el número de comparaciones de claves necesarias para determinar la posición en la que se encuentra por fin un
  • 409. 398 Java 2.Manual de Programación determinado registro. El tratamiento de las colisiones también se puede efectuar de muy diferentes formas: Creando una zona especial, denominada zona de excedentes, a la cual se lle- van exclusivamente esos registros. La zona de desbordamiento, excedentes o sinónimos podría encontrarse a continuación de la zona de datos o ser incluso otro archivo. Buscando una nueva dirección libre en el mismo espacio donde se están intro- duciendo todos los registros, zona de datos, para el registro colisionado. Lo que se puede hacer mediante diferentes técnicas, por ejemplo, direccionamiento abierto y encadenamiento. - El direccionamiento abierto resuelve las colisiones mediante la búsqueda, en el mismo espacio donde se están introduciendo todos los registros (zona de datos) de la primera posición libre que siga a aquella donde debiera haber sido colocado el registro y en la que no se pudo situar por encontrarse ya ocupada. El archivo se considera circular y cuando se busca sitio para un registro las primeras posiciones siguen a las últimas. - El encadenamiento se basa en la utilización de tablas hash que permitan localizar rápidamente por la clave la posición donde se ha escrito el archivo en el disco. Los registros se colocan en el archivo de forma secuencia1 excepto cuando se deseen aprovechar los huecos dejados por las operaciones de baja. Ejercicio Presentar un menú de opciones que permita efectuar altas, bajas y consultas en un archivo directo mediante el método de transformación de claves. El archivo, otrosempleados.dat,almacenará código, nombre, edad, domici- lio y teléfono de los empleados de una empresa. El campo clave es el código. El método de transformación de claves consiste en introducir los registros en el soporte que los va a contener en la dirección que proporciona el algoritmo de con- versión. Su utilización obliga al almacenamiento del código en el propio registro, ya que éste no se podrá deducir de la posición, y hace conveniente la inclusión en el registro de un campo auxiliar, ocupado,en que se marque si el registro está ocu- pado o no. Se requiere tener en cuenta que códigos distintos, sometidos al algorit- mo de conversión pueden proporcionar una misma dirección, por lo que se tendrá previsto un espacio en el disco para el almacenamiento de los registros que han colisionado. Aunque se puede hacer de diferentes maneras, en este caso se reser- vará espacio para las colisiones en el propio archivo a continuación de la zona de datos. Se supondrá que la dirección más alta capaz de proporcionar el algoritmo de
  • 410. Archivos 399 conversión es FINDATOS y se colocaran las colisiones que se produzcan a partir de allí en posiciones consecutivas del archivo. La zona de colisiones será la compren- dida entre FINDATOS y MAX; siendo MAX una constante establecida por el progra- mador que determina el tamaño total del archivo y cuyo valor, lógicamente, será mayor que FINDATOS. Creación. Cuando se abre el archivo por primera vez se debe realizar un reco- rrido de todo el archivo inicializando el campo ocupado a un valor vacío, por ejemplo, a espacio en blanco. La inicialización a espacio en blanco del campo ocupado se realiza hasta MAX. Altas. Para introducir un nuevo registro se aplica al campo código de dicho nuevo registro el algoritmo de conversión, obteniendo así la posición donde debe situarse. Se lee la información almacenada en el archivo en dicha posi- ción y si el campo ocupado indica que dicho lugar está libre el nuevo registro se sitúa allí; cuando la mencionada posición no esta libre el nuevo registro se sitúa en la primera posición libre existente en la zona de colisiones. Consultus. Para localizar un registro se aplicará al código a buscar la función de transformación de claves y, si no se encuentra en la dirección devuelta por la función, se examinará registro a registro la zona de colisiones. Para decidir que se ha encontrado habrá que comprobar que el registro no está de baja y que su código coincide con el que se está buscando, en cuyo caso se interrumpi- rá la búsqueda y se mostrará el registro por pantalla. Bajas. La eliminación de un registro se efectuará mediante baja lógica y con- sistirá en: - Localizar el registro buscándolo por su código, primero en la zona direc- ta y, si allí no se encuentra, en la zona de colisiones. - Una vez localizado eliminar la marca existente en su campo ocupado, asignando a dicho campo el valor que se interpreta como vacío, y escribir nuevamente la información en el archivo en la posición donde se encontró. import java.io.*; public class Ejemplo2 i public s t a t i c f i n a l i n t MAX = 1 0 0 ; / / Número máximo de registros public static f i n a l i n t FINDATOS = 15; //Fin de la zona de datos static InputCtrearnReader isr = new InputCtreamReader s t a t i c BufferedReader br = new BufferedReader (isr); s t a t i c Personal2 archivo = n u l l ; (System.in);
  • 411. 400 Java 2. Manual de Programación public s t a t i c void main (String[ ] args) i try I abrir ( ) ; operaciones ( ) ; 1 catch (IOException e) i: 1 finally i try i archivo.cerrar ( ) ; 1 catch ( IOException e) i } System.out.println("Error: " t e.toString()) ; } public s t a t i c void abrir ( ) throws IOException 1 Empleado2 unEmpleado = null; archivo = new Personal2 ( ) ; i f (archivo.longitud()== O) I System.out.println("Operación de inicialización") ; unEmpleado = new Empleado2 ( ) ; unEmpleado.establecerOcupado(' I ) ; for ( i n t i = O; i < MAX; it+) archivo.añadir(unEmpleado); 1 else System.out .println("Archivo ya existe"); public s t a t i c void operaciones() throws IOException i: short opción = O; boolean error; do i System.out.println("MENÚ") ; System.out .println("1. Altas") ; System.out.println ("2. Bajas"); System.out.println ("3. Consultas") ;
  • 412. System.out.print1n ("4. Fin"); System.out.println(); System.out.print ("ELja opción: " ) ; do { error = false; try i opción = Short.parseShort(new BufferedReader(new InputStreamReader(Systern.in)).readLine()); 1 catch (NumberFormatException ne) { System.out .println("Valor no válido "+ error = true; "(ha de ser un número)"); ) ) while (opción < 1 1 1 opción > 4 1 I error); switch (opción) I case 1: / / altas altas ( ) ; break; bajas ( ) ; break; consultas ( ) ; break; case 2: / / bajas case 3: / / consultas case 4: 1 1 while(opción ! = 4); ) public static int hash(int código) { } return código % FINDATOS; public static void altas ( ) throws IOException { Empleado2 unEmpleado = null; int posi = -1; short código = O; short edad = O; String nombre, domicilio, teléfono; boolean error, encontradoHueco; char ocupado;
  • 413. 402 Java 2. Manual de Programación / * se trata la excepción para que vuelva a pecir el dato do i en caso de error * / error = false; try System.out.print ("código: ' I ) ; código = Short .parseshort(br.readLine ( ) ) ; I catch (NumberFormatException ne) i System.out.println ("Valor no válido "+ error = true; "(ha de ser un número)"); 1 while (error); / * se comprueba si está libre la posición correspondiente posi = hash (código); unEmpleado = archivo.elemento(posi); encontradoHueco = false; //si no está libre se busca hueco en la zona dc? colisiones if (unEmpleado.devolverOcupado ( ) == ' * ' ) en la zona de datos * / t posi = FINDATOS - 1; while (posi < MAX-1 & & !encontradoHueco) I posi = posi + 1; unEmpleado = archivo.elemento (posi); if (unEmpleado.devolverOcupado ( ) ! = ' * ' ) encontradoHueco = true; 1 i else if (encontradoHueco) i encontradoHueco = true; / / Leer otros campos System.out.print ("nombre: ' I ) ; nombre = br.readLine ( ) ; do i error = false; try I System.out.print("edad: ' I ) ; edad = Short.parseShort(br.readLine()); 1
  • 414. Archivos 403 catch (NumberFormzltException ne) ! System.out .print:ln("Valor no válido "+ error = true; " (ha de ser un número)" ) ; 1 i while (error); System.out .print("domicilio: " ) ; domicilio = br .read1,ine( ) ; System.out .print("teléfono: " ) ; teléfono = br.readLine0 ; ocupado = I * ' ; / / s e marca como ocupado / * se escribe en la posición posi que puede pertenecer archivo.ponerelemento(posi, new Empleado2 (código, nombre, edad, domicilio, teléfono, ocupado)) ; a la zona de dat'3.s o a la de colisiones * / 1 1 public static void bajas ( ) throws IOException Empleado2 unEmpleado = null; int posi = -1; short código = O; boolean error, eliminado, encontrado; do i error = false; try ! System.out.print ("Código a borrar: " ) ; código = Short .parseshort(br.readLine ( ) ) ; i catch (NumberF0rmatE:xception ne) i System.out .printlri("Valor no válido "+ error = true; "(ha de ser un número)" ) ; 1 i while (error); / / se busca en la zona de datos posi = hash (código); unEmpleado = archivo.elemento (posi); encontrado = false; if (unEmpleado.devolverOcupado()=='*' & & unEmpleado.devolverCÓdigo ( ) == código) else i encontrado = true;
  • 415. 404 Java 2. Manual de Programación / * si no se encontró en la zona de datos se recorre secuencialmente la de colisiones para intentar encontrarlo * / posi = FINDATOC - 1 ; while (posi < MAX-1 & & ! encontrado) t posi = posi + 1; unEmpleado = archivo.elemento (posi); if (unEmpleado.devolverOcupado ( ) == * ' & & unEmpleado .devolverCÓdigo( ) == código) encontrado = true; 1 1 if ( !encontrado) else i System.out.println ("No esta"); //se marca como libre unEmpleado.establecerOcupado(' I ) ; //se escribe en la posición adecuada archivo.ponerelemento(posi, unEmpleado); 1 public static void consultas ( ) throws IOException { Empleado2 unEmpleado = null; int posi = -1; short código = O ; boolean encontrado, error; do ( error = false; try ( Cystem.out .print ("Introduzca el código a buscar " ) ; código = Short.parseShort(br.readLine()); } catch (NumberFormatException ne) I Cystem.out.println("Valor no válido "t error = true; "(ha de ser un número)"); 1 1 while (error); //se busca el código en la zona de datos posi = hash (código); unEmpleado = archivo.elemento (posi); encontrado = false;
  • 416. Archivos 405 i f (ünEmpleado.devolver OcJpado ( ) == ' * ' & & unEmpleado.devolverCodigo ( 1 == codigo) else encontrado = true; t / * si n3 se encuentri en la zorAa ce datos se recorre encontrado = f a l s e ; while (POSI < MAX-1 & & !encontrado) la de colisiones para inteptar 1ocal;zarlo " / pos1 = FINDATOS - 1; I posi = posi t I; UnEmpleado = archi.io.eiemento(posi); i f (unEmpleado.devolverOcupado ( ) == ' * ' & & unEmpleado.devo..verCódigo ( ) == código) encontrado = true; 1 1 i f ( !encontrado) else System.out.println("No está") ; unEmpleado.mostrar0; I / / Clase Personal2, personal de la empresa. import java.io.*; public c l a s s Personal2 i private RandomAccessFile raf = n u l l ; private i n t nElementos; private i n t longReg = 102; //registros de longitud fija, no se permite que excedan longReg public Personal2 ( ) throws IOException i File arch = new File ("ctrosempleados.dat"); //se abre para lectura/escritura raf = new RandomAccessFile (arch, "rw"); nElementos = t h i s . longitud ( ) ; i public void añadir (Empleado2 obj) throws IOException i / * se utiliza para inicializar el archivo, escribiendo un determinado número de registros con el campo ocupado a espacio en blanco. El archivo crece corforme se le van añadiendo nuevos elementos.
  • 417. 406 Java 2. Manual de Programación x / nZ1emeP. tost + ; ponere;emento(nElementos, obj); public void ponerelemento ( i n t 1, Empleado2 unEmp .eado ) throws ICException i f (1-I>= O & & 1-1 < nElementos) / * En el formato UTF-8 los dos primeros bytes indican el numero de bytes que han de ser leídos a conti- nuar-on para formar la cadena, como se escriben 3 cadenas en este formato se suman 6 bytes al tamaño de los campos de datos de unEmpleado * / //posicionamiento en el lugar adecuado raf.seeK( (long) (1-1) * longReg); raf.writeShort(unEmpleado.devolverCódigo() ) ; raf.writeUTF(unEmpleado.devolverNombre() ) ; raf.writeShort(unEmpleado.devolverEdad()); raf.writeUTF(unEmpleado.devolverDomicilio0 ) ; raf.writeUTF(jnEmpleado.devolverTeléfono()i; raf.writeChar(unEmpleado.devolverOcupado() i ; 1 else System.out .println("unEmpleado demasiado grande"); Cystem.out .println("No se puede poner e n esa posición"); else public Empleado2 elemento ( i n t i ) throws IOExcept Lon lL i f (i-1 >= O & & i-1 < nElementoc) t //posicionamiento de nuevo raf.seek ( (long) (1-1) * longReg); s h o r t codigo = raf .readshort ( ) ; String nombre = raf.readUTF0; short edad = raf.readShort(); S t r i n g domicilio = raf.readUTF0; String teléfono = raf.readUTF0; char ocupado = raf.readChar0; r e t u r n new Empleado2 (codigo, nombre, edad, domicilio, teléfono, ocupado); 1 else i System.out .println("No hay elementos en esa posición") ; r e t u r n n u l l ;
  • 418. Archivos 407 public i n t longitud ( ) throws IOException return ( i n t )Math.ceil( (double)raf .length ( ) / 1orgReg); public void cerrar ( ) throws IOException if (raf ! = n u l l ) raf .close ( ) ; I i / / Clase Empleado2. Objeto que representa un registro import java.io.*; public c l a s s Empleado2 i / / campo clave p r i v a t e short código; p r i v a t e short edad; p r i v a t e String nombre, domici1io, teléfono ; / / campo para efectuar b31as lógicas, por marca p r i v a t e char ocupado; public Empleado2 ( ) i código = O; edad = O; nombre = " " ; domicilio = " " ; teléfono = " ' I ; oc;ipado = ' ' ; //cadena nula /*espacio en blanco marca e- registro como vacio * / public Empleado2 ( s h o r t cod, String nom, s h o r t annos, Str1r.g dom, String tfno, char m3rca) I código = cod; nombre = nom; edad = annos; domicilio = dom; teléfono = tfno; ocupado = marca; i public long tamaño ( ) i / * tamaño que ocupan los campos de datos. Un short ocspa 2 bytes. Se utiliza para ver si el tamaño es permitido y no se excede la 1ongReg establecida * / return 2 + nombre.length() * 2 + 2 + domicilio.length()*Z + teléfono.lengtk,() * 2 + 2; 1
  • 419. 408 Java 2. Manual de Programación public void establecerOcupado (char marca) ocupado = marca; public char devolverocupado ( ) return ocupado; public void establecerCódigo(short cod) código = cod; public short devolvercódigo ( ) return código; I public void establecerNombre(Str1ng nom) nombre = nom; 1 public String devolverNombre() return nombre; 1 public void establecerEdad(sh0rt annos) I edad = annos; public short devolverEdad0 return edad; public void estab?ecerDomicilio(String dorn) 1 domicilio = dom; 1 public String devolverDomicilio() i return dorn;cillo; public void establecerTelefono(Ctring tfno) telkfonc = t f n o ;
  • 420. Archivos 409 public String devolverTelefono() I return teléfono; I public void mostrar ( ) I System.out.println(devolverCódigo()); System.out.println(devolverNombre()); System.out.println devolverEdad0); System.out.println devolverDomicilio()); System.out.println devolverTelefono()); 1
  • 421. CA 15 Estructuras de datos definidas por el programador CONTENIDO 15.1. Listas. 15.2. Implementación de una lista. 15.3. Lista ordenada. 15.4. Listas genéricas y uso de interfaces. 15.5. Listas doblemente enlazadas. 15.6. Pilas. 15.7. Colas. 15.8. Colas circulares. rn 411
  • 422. 412 Java 2. Manual de programación Java, como los restantes lenguajes de programación, suministra una serie de ti’pos de datos básicos y una serie de operaciones para su manipulación. En ocasiones, estos tipos de datos no son los adecuados para resolver un problema y es necesario crear nuevos tipos de datos, que será preciso definir especificando tanto sus datos componentes como las operaciones que los manipulan. Estos tipos de datos se definen mediante clases y proporcionan una de las características más importantes de la PO0 (Pro- gramación Orientada a Objetos), la reutilización de componentes. Las colecciones de datos organizados y a las que se accede de forma perfectamente definida constituyen una estructura de datos. Existe un cierto número de estructuras de datos de reconocida uti- lidad, cuyo uso se repite frecuentemente en los programas, y que pueden llegar a considerarse como una extensión de los tipos básicos del lenguaje; estas estructuras tienen un nombre y unas características establecidas y entre ellas destacan: listas, pilas, colas, árboles y grabs. Las tres primeras son estructurasde datos lineales,puesto que en ellas cada elemento tiene un único prede- cesor y un Único sucesor, mientras que las dos Últimas son estruc- turas no lineales. En este capítulo se describen estructuras de datos lineales, ya que las estructuras de datos no lineales quedan fuera de los objetivos de este libro. Dada la importancia de las estructuras de datos, Java ofrece clases que implementan algunas de ellas: java.u t i 1 .vector, java.util.Stack, java.util.Hastable, java.util.BitSet. 15.1. LISTAS Una lista es una secuencia de elementos del mismo tipo o clase almacenados en me- moria. Las listas son estructuras lineales, donde cada elemento de la lista, excepto el primero, tiene un único predecesor y cada elemento de la lista, excepto el último, tiene un único sucesor. El número de elementos de una lista se denomina longitud. En una lista es posible añadir nuevos elementos o suprimirlos en cualquier posición. Existen dos tipos de listas: contiguas y enlazadas. En una lista contigua los ele- mentos son adyacentes en la memoria de la computadora y tienen unos límites, izquierdo y derecho, que no pueden ser rebasados cuando se añade un nuevo ele- mento. Se implementan a través de arrays. En este tipo de listas la inserción o eli- minación de un elemento, excepto en la cabecera o final de la lista necesitará una traslación de parte de los elementos de la misma (Fig. 15.1). Una lista enlazada se caracteriza porque los elementos se almacenan en posiciones de memoria que no son contiguas (adyacentes), por lo que cada elemento necesita almacenar la refe- rencia al siguiente elemento de la lista.
  • 423. Estructuras de datos definidas por el programador 413 Las listas enlazadas son mucho más flexibles y potentes que las listas contiguas y, en ellas, la inserción o eliminación (supresión) de un elemento no requiere el des- plazamiento de otros elementos de la misma. Las listas enlazadas (Fig. 15.3) se suelen construir vinculando nodos (objetos que contienen al menos un miembro que es una referencia a otro objeto de su mismo tipo, Fig. 15.2). Esta forma de organización resulta la más adecuada si el número de elementos a almacenar en un momento dado es impredecible. Si se utiliza un array para almacenar una serie o colección de elementos; en el caso de que el número de elementos exceda el tamaño establecido para el citado array en el momento de su creación, los nuevos elementos no se podrán almacenar en dicho array y la posible solución será la creación de un nuevo array de las dimensiones adecuadas y el tras- paso de la información del viejo al nuevo array. Se ha de tener en cuenta que la clase Vector de Java permite crear estructuras de datos de tipo array de objetos redi- mensionables durante la ejecución de un programa. En el caso de utilizar nodos vin- culados para almacenar la información, éstos se crean y destruyen conforme se requieran, de esta manera la lista aumenta o disminuye de tamaño dinámicamente y sólo se llena cuando se agota la memoria disponible. El acceso a la lista se realiza mediante una referencia al primer nodo de la misma y, para marcar su fin, se esta- blece la referencia de enlace del último nodo a n u l l . LLongitud Vacíos Límite de la lista superior Límite inferior Figura 15.1. Lista contigua. public clas Nodo I Object info; Nodo sig; Nodo (Object información, Nodo siguiente) ( 1 info = información; sig = siguiente; I Figura 15.2. Nodo.
  • 424. 414 Java 2. Manual de programación info sig I -+ info sig -+ I Figura 15.3. Lista enlazada. xi Las listas enlazadas se clasifican a su vez en tres tipos: circulares, doblemente enlazadas y doblemente enlazadas circulares. xi Circulares. El Último elemento referencia al primero de la lista (Fig. 15.4). f i n Figura 15.4. Lista enlazada circular. Doblemente enlazadas. Su recorrido puede realizarse tanto desde frente a final como desde final a frente.Cada nodo de dichas listas consta de un miembro con información y otros dos que referencian objetos de su mismo tipo ( a n t y sig),uno para referenciar al nodo sucesor y otro al predecesor (Fig. 15.5). 7~~ tina1 frente I I xrl Figura 15.5. Lista doblemente enlazada. Listas doblemente enlazadas circulares. En este tipo de listas el miembro a n t del primer nodo de la lista referencia, o apunta, al último nodo y el miembro sig del último nodo al primero (Fig. 15.6).
  • 425. Estructuras de datos definidas por el programador 415 inicio Figura 15.6. Lista doblemente enlazada circular. Resumen: Una lista enlazada se caracteriza porque los elementos se almace- nan en posiciones de memoria que no son contiguas o adyacentes. Cada ele- mento necesita almacenar al menos una referencia al siguiente elemento de la lista. En una lista enlazada la inserción o eliminación (supresión) de un ele- mento no requiere el desplazamiento de otros elementos de la misma. Importante: Una lista enlazada que se implementa vinculando nodos aumen- ta y disminuye de tamaño dinámicamente. I 15.2. IMPLEMENTACIÓN DE UNA LISTA Los métodos básicos que necesitaría implementar una lista son los especificados en la clase Lista: El constructor Lista crea una lista vacía asignando el valor n u l 1al miem- bro privado inicio que contiene la referencia al primer nodo de la lista. El método vacia determina si la lista esta vacía comprobando si la referen- cia al primer nodo de la lista es null.Devuelve true cuando la lista está vacía y f a1se en caso contrario. El método insertarprincipio crea un nuevo nodo donde almacena una referencia al objeto que recibe como parámetro y otra al inicio de la lista, por último asigna a inicio el nuevo nodo y convirtiéndolo así en el primer elemento de la lista. El método borrarprincipio guarda en auxi la referencia al primer nodo de la lista, y quita éste nodo de la lista, asignando a inicio la referencia al siguiente nodo de la lista, contenida en inicio.sig;por Último, devuelve la referencia al nodo que se ha quitado (auxi).
  • 426. 416 Java 2. Manual de programación public class Lista i private Nodo inicio; Lista ( ) i inicio = null; public boolean vacía ( ) ( 1 return (inicio == null); public void insertarPrincipio(0bject elemento) Nodo nuevoNodo = new Nodo (elemento, inicio); inicio = nuevoNodo; } public Nodo borrarPrincipio0 ( if (vacía( ) ) t return null; 1 else I Nodo auxi = inicio; inicio = inicio.sig; return (auxi); I 1 public void mostrarLista ( ) i Nodo actual = inicio; while (actual != null) ( actual.rnostrarNodo0; actual = actual.sig; 1 I public class Nodo i public Object info; public Nodo sig;
  • 427. Estructuras de datos definidas por el programador 417 public Nodo (Object información, Nodo siguiente) I info = información; sig = siguiente; 1 public void mostrarNodo ( ) t 1 System.out.println(info); } public class Prueba I public static void main (String[] args) t Lista unaLista = new Lista ( ) ; unaLista.insertarPrincipio(new Integer(1)); unaLista.insertarPrincipio(new Integer(2)); unaLista.mostrarLista(); while (!unaLista.vacía()) I Nodo unNodo = unaLista.borrarPrincipio0; unNodo.mostrarNodo0; 1 unaLista.mostrarLista(); 1 En la implementación expuesta, la inserción de un nuevo elemento se efectúa siempre por el principio de la lista y la supresión también. En muchas ocasiones esta situación no es la deseada, y lo que se desea es buscar o suprimir un ele- mento determinado. Estas acciones requieren añadir métodos que permitan la búsqueda y el borrado de elementos con un determinado valor en un campo de datos clave. 15.3. LISTA ORDENADA Una lista está ordenada cuando sus elementos están organizados, en orden cre- ciente o decreciente, por el contenido de uno de sus campos de datos. Para que una lista resulte ordenada es probable que la inserción de nuevos elementos requiera colocarlos en posiciones intermedias de la misma (Fig. 15.7). Las listas enlazadas realizan este tipo de inserciones más eficientemente que las contiguas, al no ser necesario para insertar un nuevo elemento desplazar ningún otro de la lista. También resultan más rápidas las operaciones de supresión de elementos en posiciones intermedias mediante el empleo de este tipo de listas (Fig. 15.8).
  • 428. 418 Java 2.Manual de programación i n f o s i g I i n i c i o ...... * ........--c i n f o s i g --+ i n f o s i g -+ I I x I i n f o s i g i L .t ........ I I -+ i n f o s i g -+ i n f o s i g --+ I x2 I xi I Xi X3 nullI xn I Figura 15.7. Inserción de un nuevo elemento en una posición intermedia de la lista. i n i c i o ............................................ Figura 15.8. Supresión de un elemento en una posición intermedia de la lista. < . , l n l C l O .................. ~ I - 1 I / I r I Figura 15.9. Supresión del primer elemento de la lista en una lista con varios elementos.
  • 429. Estructuras de datos definidas por el programador 419 , . . lnlCIO ......................... Figura 15.10. Supresión del primer elemento de la lista en una lista con un único elemento. La clase Listaordenada muestra las operaciones básicas para necesarias para trabajar con una lista encadenada ordenada construida mediante vinculación de nodos. Estas operaciones san: El constructor Listaordenada crea una lista vacía, asignando el valor null al miembro privado inicio que contiene la referencia al primer nodo de la lista. El método vacia comprueba el valor de inicio y devuelve true cuando la lista está vacía, es decir, cuando la referencia al primer nodo es null.y false en caso contrario. El método insertarcrea un nuevo nodo de la clase Nodo2,capaz de alma- cenar un entero, una cadena y la referencia a otro objeto de su misma clase, y almacena en dicho nodo la clave y el nombre a insertar.El método utili- za una variable de la clase Nodo2 para recorrer la lista hasta que esta se acabe o encontrar un elemento con clave menor o igual al que se desea insertar. En otra variable, anterior,de la clase Nodo2 guarda en todo momento la refe- rencia al elemento anterior al que en ese momento está siendo visitado. Cuando termina el recorrido inserta el nuevo nodo a contiuación del anterior.Si el anterior es null,puede significar que la lista está vacía o que la clave del primer elemento de la misma es menor o igual a la del nuevo y, en ambos casos, dicho nuevo elemento ha de situarse al comienzo de la lista. El método borrar intenta suprimir de la lista un elemento cuyo campo clave almacena un determinado valor. Para ello, recorre la lista buscando el elemento, de forma análoga a la indicada para la inserción,empleando también las variables actual y anterior.Si encuentra el elemento y es el primero, hace que inicio referencie al siguiente nodo de la lista, mientras que si lo encuentra en cualquier otra posición, lo que hace es que el campo sigdel elemento anterior referencie al elemento siguiente (actual.cig). El método mostrarLista utiliza la variable actual para efectuar un recorri- do de la lista y presentar la información almacenada en cada uno de sus nodos.
  • 430. 420 Java 2. Manual de programación //lista ordenada descendentemente public class Listaordenada i private Nodo2 inicio; Listaordenada ( ) i 1 inicio = null; public boolean vacía ( ) return (inicio == null); 1 public void insertar (int clave, String nombre) i Nodo2 nuevoNodo = new Nodo2 (clave, nombre); Nodo2 anterior = null; Nodo2 actual = inicio; boolean pasado = false; / * recorre la lista hasta encontrar un elemento con clave menor while (actual ! = null & & ! pasado) i o igual al que se desea insertar * / if (clave < actual.clave) i anterior = actual; actual = actual.sig; 1 else pasado = true; I / * inserta el nuevo elemento a continuación de anterior, si el anterior era null significa que ha de insertarse al comienzo de la lista * / if (anterior == null) inicio = nuevoNodo; else anterior.sig = nuevoNodo; nuevoNodo.sig = actual; i public Nodo2 borrar (int clave) i Nodo2 anterior = null; Nodo2 actual = inicio; boolean encontrado = false; / / se recorre la lista buscando el elemento while (actual ! = null & & !encontrado) i
  • 431. Estructuras de datos definidas por el programador 421 if (clave == actual.clave) else encontrado = true; I anterior = actual; actual = actual.sig; I 1 / / si se encuentra se borra if (encontrado) / * si es el primero se hace que inicio referencie al siguiente elemento de la lista, si no lo que se hace es que el campo sig del elemento anterior referencie al elemento siguiente * / if (anterior == null) else return (actual); inicio = actual.sig; anterior.sig = actual.sig; i return null; public void buscar (int clave) 1 Nodo2 anterior = null; Nodo2 actual = inicio; boolean er.contrado = false; //se recorre la while (actual ! i if (clave == encontrado else ! anterior = lista buscando el elemento con dicha clave = nuii & & !encontrado) actual.clave) = true; actual; actual = actual.sig; 1 / / si se encuentra se muestra if (encontrado) else actual.mostrarNodo0 ; System.out.println (“No esta”); 1 public void mostrarlista 0 i Nodo2 actual = iniCi0; while (actual ! = null)
  • 432. 422 Java 2. Manual de programación actual.mostrarNoao(); actual = actual.sig; public class Nodo2 public int clave; public String nomlsre; public n'odo2 sig; public Nodo2(int cl, String n) clave = cl; nombre = n; slg = null; public void mostrarNodo ( ) Cyster.out .println ("Clave: "- clave+" Nombre "+nombre); I public class P r ~ e b a 2 i public static void main (CtrinqI ] args) Listaordenada u n a i i s t a = new ListaOrdenadaO; ur.aLista.insertar (4, "Pedro"); unaUicta.insertar (1, "Luis"); unaLista.insertar (8, "Tomas"); ;naLista.mostrarLista(); / / . * . 15.4. LISTAS GENÉRICASY USO DE INTERFACES A diferencia de la clase Lista,la clase Listaordenada creada en el apartado anterior es demasiado específica, ya que sólo puede almacenar un tipo entero y una cadena. Para arreglar situaciones como ésta y que una lista pueda almacenar datos de cualquier clase, los métodos de la lista deberán trabajar con la superclase Ob] ect.Esta estructura permitirá, siempre que se efectúen las conversiones ade- cuadas, utilizar la lista para almacenar objetos de distinta clase. Se ha de tener pre-
  • 433. Estructuras de datos definidas por el programador 423 sente que Java convierte implícitamente una referencia a un objeto de una subclase en una referencia a su superclase y también que es conveniente que en un objeto listu sólo se almacenen datos homogéneos, de una misma clase. En la clase L i s taordenada,se requiere en ocasiones efectuar comparaciones; por ejemplo, para encontrar un determinado elemento en una lista, dado que las lis- tas genéricas pueden almacenar toda clase de objetos, debe dejarse a los tipos de datos la iinpleinentación de los métodos de comparación. Como ya se ha comenta- do en ocasiones anteriores, esta característica se consigue definiendo una interfaz, Comparable y declarando la información almacenada en el nodo, en lugar de per- teneciente a la clase Object,como perteneciente a la interfaz Comparable.Así, para construir una L i s taOdenadaGenerica y utilizarla para almacenar en ella una serie de libros ordenados por el ISBN se requiere: Definir la interfaz de comparación; en este caso, concebida para admitir varios criterios de ordenación. interface ComFarabLe { boolean mencrque (Co-,parablec, int cr:teric) throws Exceptiun; Declarar Comparable el campo de datos del nodo, i n f . / / Ncdo comparable public class Nodo3 private Comparable inf; private Ku'ado3 sig; Nodo3 (comparable información, Ncdo3 sigu-ente) inf = informacicn; c i g = siguiente; . . . 1 Diseñar la lista de forma que sus inétodoc trabajen con Comparable. //Lista enlazada ordenada estandar para Copparables public class L-staCdeoadaSenerica I private int c r i t e r i o ;
  • 434. 424 Java 2. Manual de programación private Nod03 primero; ListaOdenadaGenerica(int criterio) i primero = null; this.criterio = criterio; i / / . .. public void insertar(Comparab1e elemento) throws Exception i 1 / / . . . public Comparable obtener(Comparab1e elemento) throws Exception t / / . .. 1 / / . . . Hacer que los tipos de datos a colocar en la lista implementen los métodos de comparación. Así, para construir una lista de libros ordenada por ISBN, la clase Libro debe implementar el método menorque. class Libro implements Comparable i private String autor; private String titulo; private long ISBN; public Libro(String a, String t, long i) t autor = a; titulo = t; ISBN = i; 1 public booiean menorque(Comparab1e c, int criterio) throws Exception {
  • 435. Estructuras de datos definidas por el programador 425 if ( ! (c instanceof Libro) ) t throw new Exception ("Error de comparación"); i return( ( (Libro)c ) .ISBN < ISBN); 1 public String devolverAutor ( ) t return (autor); I public String devolverTitulo ( 1 ( return(titu1o) ; i public long devolverISBN ( ) I 1 return (ISBN); íjercicio Diseñar una clase ListadeLibros, que permita efectuar la gestión de una biblioteca. La clase ListadeLibros representa un array unidimensional cuyos elemen- tos son listas enlazadas ordenadas de la clase ListaOrdenadaGenerica y ten- drá métodos para efectuar el almacenamiento, recuperación y eliminación de los libros. Los libros se almacenan por inicial de título e ISBN. La inicial del título ( a - z ) determina la posición en el array unidimensional donde será colocado el libro. Como cada elemento del array es una ListaOrdenadaGenerica, los libros que comiencen por la misma inicial serán situados en la correspondiente lista enlazada ordenados por ISBN.
  • 436. 426 Java 2.Manual de programación z Figura 15.11. La clase Lista enlazada. Los aspectos más importantes en cuanto a genericidad de la clase ListaOrdenadaGenerica acaban de ser comentados, ya que esta clase ha sido puesta como ejemplo para exponer las características de las listas genéricas. Por otra parte, ListaOrdenadaGenerica es una lista ordenada y los métodos estaliacia,insertar y elimina funcionan de manera similar a los ya expli- cados (vacia,insertar y borrar)de la clase Listaordenada,excepto por el empleo del método menorque,en lugar de un operador relacional, para efectuar las comparaciones entre los elementos de la lista y el elemento a insertar o eliminar. Otros detalles se especifican en el código como comentarios. Como ListadeLibros representa un array cuyos elementos pertenecen a la clase ListaOrdenadaGenerica,su constructor crea e inicializa el array, cre- ando cada uno de sus objetos, de la clase ListaOrdenadaGenerica.El méto- do guardar: 1) llama al método 1ista y le pasa como parámetro el título del libro, para que lista determine por la inicial del título la posición en el array de la lista donde el libro debe ser insertado; 2) invoca al método insertar de ListaOrdenadaGenericapara que efectúe la inserción. Los métodos recuperar y eliminar también recurren a lista para determinar la posición en el array de la lista donde el libro a consultar o suprimir debe encontrarse situado; la diferen- cia entre ambos es que recuperar una vez localizada la lista llama a obtener para que encuentre el elemento dentro de la misma, mientras eliminar llama a eli- mina para que suprima dicho elemento de la lista.
  • 437. Estructuras de datos definidas por el programador 427 Otras clases e interfaces implementadas son: NOd03.Clase de los nodos de la ListaOrdenadaGenerica. Libro.Clase que implementa la interfaz Comparable. Comparable.Interfaz de comparación. NoEsta.Excepción general de búsqueda. PruebaL.Clase de prueba para comprobar el buen funcionamiento del ejercicio. p u b l i c class ListadeLibros i / / Tamaño del array de indexación f i n a l s t a t i c i n t 1 = 'z'-'a'+l; / / Declaración del array de Indexación p u b l i c ListaOrdenadaGenerica[] libros; / * Constructor: Inicialización del array de indexación asi como de sus elementos lista. La ordenación en cada una de las listas se efectúa ascendentemente por el ISBN y carece de valor el parámetro pasado a ListaOrdenadaGenerica * / p u b l i c ListadeLibros ( ) I libros = new ListaOrdenadaGenerica[l]; f o r ( i n t i=O; i<libros.length; it+) libros [i] = new ListaOrdenadaGenerica ( O ) ; 1 / / Simple conversión de clave Titulo-->no de lista i n t lista (String titulo) i r e t u r n ( (titulo.toLowerCase( ) ) .charAt(O)-'a'); / / No de libros i n t nlibros ( ) ! i n t c = O ; f o r ( i n t i = 0;i < 1ibros.length; i + + )
  • 438. 420 Java 2. Manual de programación c += libros [i].nelems( ) ; return(c) ; 1 / / Método para el almacenamiento public void guardar (Libro libro) { try I 1 catch(Exception e) { ) libros[lista(libro.devolverTitulo())].insertar(libro); / / Se intercepta la posible excepción de insertar / / Método para la recuperación (vea class NoEsta) public Libro recuperar (String titulo, long ISBN) throws NoEsta { Libro nuevo = null; try { nuevo = (Libro)libros [lista(titulo)] .obtener( new Libro ( " " , titulo,ISBN)) ; } catch (Exception e) { ) / * Nótese la necesidad de 'downcasting' Dado que la lista es estándar para objetos 'comparables'(vea interface Comparable) hay que realizar una inevitable conversión a Libro. Nótese también que puesto que en este método se conoce la integridad de la lista que se maneja(todos sus obje- tos son Librono se realiza comprobación de seguridad para este downcasting (al contrario que en la clase Libro) * / if (nuevo == null) return(nuev0) ; throw new NoEsta ( ) ; / / Metodo para la elirninaciÓn(vea class NoEsta) public void eliminar (String titulo, long ISBN ( try { 1 libros [lista(titulo)].elimina(new Libro ( " " titulo,ISBN)) ;
  • 439. Estructuras de datos definidas por el programador 429 catch(Exception e) { } private int criterio; private Nodo3 primero; ListaOrdenadaGenerica(int criterio) t prir,ero = null; this.criterio = criterio; 1 / / Informa sobre si la lista está o no vacia public boolean estavacia ( ) t return (primero == null); / / No de elementcs public int nelemc ( ) int n = C; ~ o d o 3aux = primero; while (aux ! = null) I aux = aux.devolversiguiente ( ) ; ni+; return(n); / * Método para inserción. Ei hecho de que se permita arrojar una excepción es debido a que se puede Lntentar incrod>Jc:r comparables de métodos menorque incompatibles lo qi;e daria un primer aviso aquí * / public void insertar(Comparab1e elernentc) throws ExceptLon Nodo3 nuevo = new Nodo3(eleme~to,null); Nodo3 a7Jxl = null; Nodo3 aux2 = primero; while (aux2 ! = null & & aux2 .?~enorq~.e(nuevo,cr:terio) )
  • 440. 430 Java 2. Manual de programación acxl = aux2; a.Gx2 = aux2.devolversiguiente ( ) ; / * Obsérvese la importancia del & & en cortocircuito que eviza problemas dado el posterior acceso al método menorque. Obsérvese también la peculiar simplificación de la sirtaxis i2plementando un método menorque en Nodo3 (vea -;ass Nodo3) * / n.~ev3.asignarCigüiente(aux2); if (aLxl == null) else pri;-.ero= ~ . u e v o ; a u x l . asignarsigciente (nuevo); / / Dletodo para BIuscpeda (ver comentario sobre throws en insertarj public Corparable obtener(Comparab1e elemento) throws Exception //* ;Comparanos nodo con nodo o valor con valor? A práctica iqlialdad s-stemática se opta por lo mas fácil * / Nodc3 nuevc = new Nodo3(elernento, null); Ncao3 dux = primero; while(aJx ! = null & & aux.menorque (nuevo,criterio)j if (aux ! = null & & !nuevo.menorque (aux,criterio)) aux = acx.devolversiguiente ( ) ; return(aux.devolverValor()); 1 " Si el uno no es menor que el otro y el otro r.o es / * Obsfrvese zambiér. la importancia del & & en cortocir- menor que el uno: son iguales: (a<b & a>b)<=>b=a * / c ~ i t odado el posterior uso del método menorque (vea Libro.menor que) que lanzarla una excepcijr. * / else return (null); * Yetodo para eli-inacion (ver comentario sobre throws er. irsertar) * / public void eliiina(Comparab1e elemento) throws Exception N o m ? aeliiinar = new Rod03 (elemento, null); ?&ceo3 auxl = null; Nodo3 a¿ix2 = primero;
  • 441. Estructuras de datos definidas por el programador 431 while (aux2 ! = n u l l & & aux2.menorque (aeliminar, criter:~) ) auxl = aux2; acx2 = aux2.devolverSiguiente(); i f (aux2 ! = n u l l & & !aeliminar.menorque(aux2, criterio)) i f ( a u x 1 == n u l l ) else primero = n u l l ; auxl .asignarsiguiente (aux2.devolversiguiente ( 1 ) ; 1 / * Nodo3 comparable que implementa la facilidad adicicial de delarce comparar por el mismo sin-plif,randc l a sintaxis * / p u b l i c class Nodo3 p r i v a t e ComparabLe inf; p r i v a t e n’odo3 c i g ; Nodo3 (Comparable información, Nodo3 sig,;iente) i :nf = información; sig = sig¿iiente; I p u b l i c Comparable devolvervalor() i r e t u r n (inf); p u b l i c Nodo3 devolverCigaiente ( 1 r e t u r n (cig); 1 p u b l i c void asignarvalor (Comparable ir.formacio~.) inf = infornación; p u b l i c void asignarSiguiente(Nodo3 siguiente) i s;g = ciguierte;
  • 442. 432 Java 2. Manual de programación boolean menorque (Nodo3 c, int criterio) throws Exception t return(inf.menorque(c.inf, O) ) ; / / Objeto comparable Libro class Libro implements Comparable private String autor; private String titulo; private long ISBN; public Libro(Ctring a, String t, long i) I autor = a; titulo = t; ISBN = i; public String devolverAutor ( ) return (autor); public String devolverTitulo ( ) I return(titu1o); 1 public long devolverICBN ( ) t return (ISBN); / * Método obligado para comparables, como se indica en la interfaz el campo criterio no sera utilizado en este caso * / public boolean menorque(Comparab1e c, int criterio) throws Exception if ( ! (c instanceof Libro)) return ( ( (Libro)c) .ISBN<ISBN); throw new Exception ("Error de comparación") ; 1
  • 443. Estructuras de datos definidas por el programador 433 / * Interfaz básico estándar de comparación. Es la base sobre la que se implementa cualquier ordenación o búsqJeda. A r n q u e en principio está concebido para admitir varios cr;terics de ordenación en este caso el campo criterio no será usado * / interface Comparable boolean menorque(Comparab1e c, i n t criterio) throws Excepzion; 1 / / Excepción estándar general de bjsqueda c l a s s NoEsta extends Exception i public NoEsta ( ) super ("No se encuentra el libro") ; / / Una prueba simple para la biblioteca ListadeLibros public c l a s s PruebaL i public s t a t i c void main (String[ ] args) i / / Inicializa un objeto ListadeLibros ListadeLibros 1 = new ListadeLibros 0; / / Crea dos objetos Libro aimacenándolos después Libro librol = new Libro ("Chesterton", "El padre Brown",471193089); Libro libro2 = new Libro ("Froid", "Die Traumdeutung",1571690956); 1.guardar (librol); 1.guardar (libro2); / / ?rr;ieba su recuperación t = Y ! Libro nuevo: = i.recuperar ("Si padre Rrcw::", 6711333E9); Librc r.uevo2 = 1.recuperar("Die :raundeut~~y",15?1CYV93%) ;
  • 444. 434 Java 2. Manual de programación ........................ ...... a n t i n f s i g ...................... Sycrerr.out.print ("En Stock: " ) ; Sycrem.out.printlr (1.nlibrosO ) ; Sys:em.out.println(nuevol.devolverTitulo()+ " : "+nuevol.devolverAutor ( ) ) ; System.ouz.prLntln(nuevo2.devolverTitulo()+ " : "+nuevo2.devolverAutor ( ) ) ; Cycrem.in.read ( ) ; a n t i n f sig I catch (Exception e ) { 1 / / 3 o r r a ;no de los libras 1.eliainar ("El padre Brown",471193089); System.olit.print("En Stock: " ) ; Systern.c;lt. p r i n t l n (1.nlibros( ) ) ; catch (Exception e) { I 15.5. LISTAS DOBLEMENTE ENLAZADAS Se caracterizan porque su recorrido puede realizarse tanto desde frente a final como desde frente a final.Este tipo de listas se suele construir vinculando nodos. Cada nodo de dichas listas consta de un campo con información y otros dos campos (ant y s i g ) que referencian el nodo antecesor y el sucesor respectiva- mente. Además en una lista doblemente enlazada, cada nodo, excepto el primero y el último, se encuentra referenciado por otros dos, su sucesor y su antecesor. Figura 15.12. Inserción de un nuevo elemento al principio de una lista doblemente enlazada.
  • 445. Estructuras de datos definidas por el programador 435 En la operación de inserción será necesario tener en cuenta si se trata del primer elemento de la lista; en caso contrario, el nuevo elemento ha de colocarse por delan- te del primero, en una posición intermedia o al final. La supresión debe contemplar si se desea eliminar un elemento al principio de la lista, en el medio o ai final, y ade- más la posibilidad de que la lista conste de un único elemento y quede vacía tras su eliminación. 15.6. PILAS Una pila es una lista que tiene establecidas ciertas restricciones en cuanto a la forma de extraer o colocar en ella nuevos elementos. La pila se utiliza siempre que se desea recuperar una serie de elementos en orden inverso a como se introdujeron. La extracción de un elemento de una pila se realiza por la parte superior, de igual forma que la inserción. Esta propiedad implica que el único elemento accesible de una pila es el último. Estas estructuras se denominan LIFO (Last Input First Output), ((últimoelemento que se pone en la pila es el primero que se puede extraer)). Las pilas se pueden implementar vinculando nodoc y también mediante arrays, utilizando una variable auxiliar, cima,que apunte al Último elemento de la pila. En realidad, en Java no es necesario definir la clase Pila,ya que en el paquete java.uti1 viene la clase Stack (pila). La clase Stack hereda de Vector,ya que una pila se puede implementar con eficiencia mediante una tabla que no tiene tamaño fijo. Los métodos proporcionados por Stack son: public boolean empty ( ) Comprueba si la pila está vacía public synchronized java.lang.Cbject peek() Consulta el elemento situado en la cima de la pila, sin quitarlo de ésta. Si la pila está vacía, devuelve una excepción EmptyStackException. public synchronized java.lang.Object pop ( ) Quita el objeto situado en la cima de la pila y lo devuelve como resultado de la función. Si la pila está vacía, devuelve la excepción anteriormente mencionada. public java.lang.Object push(java.lang.0bject obj) Coloca un nuevo elemento en la cima de la pila. public synchronized int search(java.lang.0bject obj) Devuelve la distancia existente desde la cima de la pila hasta la posición donde el objeto, obj,se encuentra situado o -1 si el objeto no está en la pila. public Stack ( ) Constructor.
  • 446. 436 Java 2. Manual de programación vacía se coloca un elemento se coloca otro elemento se quita un elemento cima = 2. cima = 1 ... ... ... 3 2 1 Figura 15.13. Pila implementada con vector La implementación de una pila utilizando nodos vinculados requiere el diseño de los métodos: . . Se Pila,el constructor. Crea una pila vacía asignando null al miembro pri- vado cima que contiene la referencia a la cima (tope)de la pila. vacia.Determina si la pila está o no vacía comprobando el valor de cima; devuelve true cuando el valor de cima es null y false en caso contra- rio. apilar.Añade un nuevo elemento en la cima de la pila, es decir, crea un nuevo nodo cuyo campo sig referencia la cima de la pila y a continuacitn asigna a cima el nuevo nodo. desapilar.Comprueba que la pila no está vacía, suprime el nodo de la cima haciendo que cima pase a referenciar al siguiente nodo, o a null si la pila se ha quedado vacía, y devuelve el objeto perteneciente al nodo eliminado. obtenercima.Devuelve el objeto almacenado en la cima de la pila. podría efectuar de la siguiente forma: public class Pila private Nodo4 cima; P i l a ( ) I cima = null; 1 public boolean vacía ( ) return (cima == null); I
  • 447. Estructuras de datos definidas por el programador 437 public void apilar(0bject elemento) { cima = new Nodo4(elemento, cima); public Object desapilar ( ) throws Exception { i f (vacía( ) ) Object aux = cima.inf; cima = cima.sig; return aux); throw new Exception ("Pila Vacia"); 1 public OLject obtenercima ( ) throws Exception i i f (vacía( ) ) return (cima.inf); throw new Exception ("Pila Vacia") ; 1 public c l a s s Nodo4 i Object inf; Nod04 sig; Nodo4 (Object información, Nod04 siguiente) i inf = información; sig = siguiente; 1 //La información se muestra en orden inverso al de introducción import java.io.*; public class PruebaP I public s t a t i c void main (String args [ ] ) i String cadenai, cadenaf; Pila p = new Pila(); System.out .println("Prueba"); System.out.println ("Escriba una palabra:") ; try I InputStreamReader is = new InputStreamReader(System.in); BufferedReader bf = new BufferedReader (is); cadenai = bf .readLine ( ) ;
  • 448. 438 Java 2. Manual de programación for (int i = O; i < cadenai.length(); i+t) cadenaf = ""; for (int i = O; i ¿ cadenai.length 0 ; it+) p.apilar (new Character (cadenai.charAt(i)) ) ; cadenaf = cadenaf + ( (Character)p.desapilar ( ) ) . charvalue ( ) ; System.out .println(cadenaf); 1 catch(Exception e) i 1 Cuando un programa llama a un subprograma, se utilizan internamente pilas para guardar el lugar desde donde se hizo la llamada y el estado de las variables en ese momento. Entre las aplicaciones de las pilas destacan: 1) Su uso en la transformación de expresiones aritméticas de notación injija apostfija' y en la posterior evaluación de la expresión. 2) Su utilización para la transformación de algoritmos recursivos en iterativos. 15.7. COLAS Una cola es una estructura de datos lineal en donde las eliminaciones se realizan por uno de sus extremos, denominadofrente, y las inserciones por el otro, denominado final. Se las conoce como estructuras FIFO (First Input First Output). La cola de un autobús o de un cine son ejemplos de colas que aparecen en la vida diaria. La cola se podrá implementar mediante un array unidimensional, usando la clase Vector o utilizando nodos vinculados. Cuando se implementa con un array (Fig. 15.14) se utilizan dos variables nu- méricas, primero y último,para marcar el principio yfinal de la cola; como los elementos se añaden por el final y se quitan por el principio, puede ocurrir que la variable último llegue al valor máximo del array, aun cuando queden posi- ciones libres a la izquierda de la posición primero (Fig. 15.15). Existen diver- sas soluciones: ' Una de las tareas que realiza un compilador es la evaluación de expresiones aritméticas. En la mayo- ría de los lenguajes de programación las expresiones aritméticas se escriben en notación infiju, que son aque- llas en las cuales el símbolo de cada operación binaria se sitúa entre los operandos: 4 * (3+5). Muchos compiladores transforman estas expresiones irzfijas en notación po.s?fij~~,en la cual el operador sigue a los operandos (oprefija, en la cual el operador procede a los operandos) y a continuación generan instrucciones máquina para evaluar esta expresión postfija: 4 3 5 + *. Nunca se necesitan paréntesis para escribir expre- siones en las notaciones posífija y prefija.
  • 449. Estructuras de datos definidas por el programador 439 Retroceso Consiste en mantener fijo a 1 el valor de primero, realizando un desplazamiento de una posición para todas las componentes ocu- padas cada vez que se efectúa una supresión. Reestructuración Cuando último llega al máximo de elementos se desplazan las componentes ocupadas hacia atrás las posiciones necesarias para que el principio coincida con el principio de la tabla. Un array circular es aquel en el que se considera que la compo- nente primera sigue a la componente última. Mediante un array circular primero último MAX Figura 15.14. Cola implementada con array. primero último I MAX Figura 15.15. Cola implementada con un array tras una serie de operaciones de adición y sustracción de elementos. La clase Vector de Java, así como la creación de una cola utilizando nodos vinculados evitan los problemas originados por MAX en las implementaciones con arrays. Las operaciones típicas en una cola son: crear la cola, comprobar si la cola está o no vacía, poner elementos en la cola por el,final, quitar elementos por elfrente y obtener el objeto situado en e1,frente de la misma. En la implementación de una cola utilizando nodos vinculados que se efectúa a continuación los métodos que realizan las mencionadas tareas se denominan respectivamente: Cola, vacía, poner, quitar y obtenerprimero.Los miembros privados primero y último guardan la información sobre elfrente yJinal de la cola; inicialmente, el constructor asigna null a ambos.
  • 450. 440 Java 2. Manual de programación El método vacia comprueba si queda algún elemento que se pueda extraer de la cola consultando primero y si el valor de primero es null devuelve truepara indicar que la cola está vacía, en caso contrario devuelve false. El método poner se encarga de añadir nuevos elementos a la cola por el final; para ello, comienza por comprobar si la cola está vacía, si esto ocurre, será necesario que primero referencie al nuevo elemento, en caso contra- rio será el elemento referenciado por u1t imo,a través de su campo si g , quien establezca un vínculo con el nuevo elemento, el método poner termi- na asignando a u1timo el nuevo elemento. El método quitar,si la cola no está vacía, asigna a una variable aux el objeto alamacenado en el campo inf del primer elemento, después hace que primero referencie al nodo referenciado por el campo si g de dicho primer elemento, si la cola se ha quedado vacía y primero es null asigna tam- bién null a ultimo,en cualquier caso, cuando la cola no está vacía, devuelve aux. El método obtenerprimero devuelve el objeto referenciado por el campo info del elemento referenciado por primero. public class Cola t private Nodo4 primero; private Nodo4 ultimo; Cola ( ) { primero = null; ultimo = null; 1 public boolean vacía ( ) { return (primero == null) ; public void poner (Object elemento) t Nod04 aux = new NOdO4(elemento, n u l l ) ; i f (vacía( ) ) else ultimo = aux; primero = aux; u1timo.si.g = aux; 1 public Object quitar ( ) throws Exception { i f (vacía( ) ) Object aux = primero.inf; throw new Exception ("Cola vacía");
  • 451. Estructuras de datos definidas por el programador 441 primero = primero.sig; if (primero == n u l l ) ultimo = n u l l ; return (dux); ) public Object obtenerprimero0 throws Exception I if (vacia( ) ) return (primero.inf); throw new Exception ("Cola vacía") ; 1 public class Nodo4 i Object inf; Nodo4 sig; Nodo4 (Object información, Nodo4 siguiente) i inf = información; sig = siguiente; 1 1 Una aplicación de las colas es una cola de impresión. En un sistema de tiempo compartido suele haber un procesador central y una serie de periféricos comparti- dos: discos, impresoras, etc. Los recursos se comparten por los diferentes usuarios y se utiliza una cola para almacenar los programas o peticiones de los diferentes usuarios que esperan su turno de ejecución. El procesador central atiende, normal- mente, por riguroso orden de llamada del usuario; por tanto, todas las llamadas se almacenan en una cola. Existe otra aplicación de las colas muy utilizada, la cola de prioridad; en ella el procesador central no atiende por riguroso orden de llamada, sino por las prioridades asignadas por el sistema o bien por el usuario, y sólo den- tro de las peticiones de igual prioridad se producirá una cola. Resumen: En realidad las pilas y las colas son listas que tienen establecidas ciertas restricciones en cuanto a la forma de extraer o colocar en ellas nuevos elementos: La extracción de un elemento de una pila se reaIiza por la parte superior, lo mismo que la inserción. Estructura LIFO. En una cola las eliminaciones se realizan siempre por uno de sus extre- mos, denominado frente, y las inserciones por el otro, denominado final.
  • 452. 442 Java 2. Manual de programación 15.8. COLAS CIRCULARES Una cola circular es una variante de las listas circulares. Una cola necesita dos refe- rencias, una al primer elemento y otra al último; por consiguiente, una cola circular se toma como referencia de acceso la del Último nodo, de esta forma se tiene implí- citamente la del primero puesto que en una cola circular el primer elemento sigue al Último (Fig. 15.16). último I 1 L iprimero Figura 15.16. Cola circular. Teniendo en cuenta las consideraciones anteriores y utilizando nodos vincula- dos, los métodos a implementar tendrán las siguientes características: El constructor, Colacircular.Crea la cola, asignando null al miembro privado uitimo. vacia.Devuelve true si la cola está vacía (ultimoes null) y false en caso contrario. poner.Crea un nuevo nodo y comprueba si la cola está vacía; si está vacía, al campo sig del nuevo nodo le asigna el nuevo nodo; si no está vacía, asig- na al campo sig del nuevo nodo el primero (ultimo.sig)y a ultimo.sig el nuevo. Al terminar, en ambos casos, asigna a u1timo el nuevo. quitar.Tras verificar que la lista no está vacía, el método considera dos casos: 1) que la lista tenga un único elemento (ultimo.sig será igual a ultimo), por lo que, al quitarlo, ultimo debe pasar a tomar el valor null; 2) que la lista tenga más de un elemento y, para eliminar el primero, este primero (que es uitimo.sig) deberá pasar a referenciar a su siguiente (ultimo.sig.sig). obtenerprimero devuelve el objeto referenciado por el campo info del primer elemento.
  • 453. Estructuras de datos definidas por el programador 443 La implementación de la cola circular es: public class Colacircular i private Nodo4 ultimo; Colacircular ( ) i ultimo = null; public boolean vacía ( ) i return(u1timo == null); 1 public void poner (Object elemento) I Nodo4 aux = new Nodo4(elernento, null); if (vacia( ) ) else i aux.sig = aux; aux.sig = ultimo ultimo.sig = aux 1 ultimo = aux; 1 public Object quitar i if (vacia( ) ) sig; ) throws Exception throw new Exception ("Cola vacía") ; Object aux = ultimo.sig.inf; if (ultimo.sig == ultimo) else return (aux); ultimo = null; ultimo.sig = ultimo.sig.sig; public Object obtenerprimero ( ) throws Exception if (vacía( ) ) return (u1timo.sig .inf) ; throw new Exception ("Cola vacía"); 1 //La clase Nodo no cambia public class Nodo4
  • 454. 444 Java 2.Manual de programación Object inf; Nodo4 sig; Nodo4 (Oblect información, Nodo4 siguiente) I inf = información; sig = siguiente; / * Cína prueba similar a la que se efectuó con la pila se puede utilizar ahora para ver el funcionamiento de la cola circular. La información se muestra en el mismo orden en el que fue introducida * / import java.io.*; public class PruebaCC public static void main (String args [ ] ) t String cadenai, cadenaf; Colacircular cc = new Colacircular ( ) ; System.out .println("Prueba"); System.out .println("Escriba una palabra:") ; try InputCtreamReader is = new InputStreamReader(Systern.in); BufferedReader bf = new BufferedReader(is); cadenai = bf .readLine ( ) ; for (int i = O; i < cadenai.length(); it+) cadenaf = " " ; while ( ! cc.vacía ( ) ) System.out.println(cadenaf); cc.poner (new Character (cadenai.charAt(i)) ) ; cadenaf = cadenaf t ( (Character)cc.quitar ( ) ) .charvalue ( ) ; ! catch(Exception e) { } 1
  • 456. 446 Java 2. Manual de programación Las siguientes palabras no se pueden utilizar como identificadores: aDstract booleai break byte case catch char class const contirue defau-t aouble e-se exter.ds falce final 13 finally float for goto lf implements import instanceof in: interface long r.atIT,e rew n,ll package private protected public return short szatic super switch synchronized this throw znrows trar.s ient true try void volatiie *..ile..h ' Las siguientes palabras reservadas pueden no tener significado en algunas ver- siones actuales, pero están reservadas para uso futuro: byvalue cast C0.T s t f u t u r e g e n e r i c got0 i n n e r operat o r outer r e s t var
  • 458. 448 Java 2. Manual de programación B.1. PRIORIDAD DE OPERACIONES Los operadores se muestran en orden decreciente de prioridad de arriba a abajo. Los operadores del mismo grupo tienen la misma prioridad (precedencia)y se ejecutan de izquierda a derecha (asociatividad). Operador Tipo Asociatividad o Paréntesis o Llamada a función [I Subíndice Acceso a miembros de un objeto Dcha-Izda Dcha-Izda Dcha-Izda Dcha-Izda ++ _ - Prefij o incremecto Prefijo aecremer.to Dcha-Izda Dcha-Izda Más unitario Mei.os unitario Kegacion 1ógica un1tar1a Complemento bit a bit Lnitario (tipo) Modelo unitario new Creaccion de obletos Dcha-Izda Dcha-Izda Dcha-Izda Dcha-Izda Dcha-Izda Dcha-Izda + - Producto Division Resto entero Surna Resta Izda-Dcha Izda-Dcha Izda-Dcha Izda-Dcha Izda-Dcha << Desplazamiento bit a bit a la izquierda Dcha-Izda >> Desplazamiento bit a bit a la derecha >>> Desplazamiento bit a bit a la derecha con extensión de signo Dcha-Izda rellenando con ceros Dcha-Izda < Menor que Izda-Dcha > Mayor que Izda-Dcha <= Menor o ig;ial qUe Izda-Dcha >= Mayor o igiial que Izda-Dcha instanceof Verificación tipo de objeto Izda-Dcha Izda-DchaI9.Ja1dad-__ _ I = Desigualdad Izda-Dcha & AND bit a bit Izda-Dcha OR exclcsive Sit a biz IZCa-DCha OR inclLs;ve bit a bir Izda-Dcha
  • 459. Prioridad de operadores 449 Operador Tipo Asociatividad ~ & & AND lógico Izda-Dcha ~~~ ~~ I 1 OR lógico Izda-3cha ? : Condiciona: ternario 3cka-Izda -- += -= *= /= ~,-c - & = -- I = <<= >>= >>>= Asignación Asignación Asignación Asignación Asignación Asignación Asignac-ón Asignación Asignación Asignación de suma de resta de producto de división de módulo AND bit a bit OR exclusive bit a bit OR inclusive bit a bic de desplazamiento 3ck. a-Izda Echa-Izda Dcha-Izda Dcna-Izda Echa-Izda Dcna-Izda Dcha-Izsa Dcha-: zda Ccha-Izcio a izquierda bit a bit Echa-Izaa Desplazamiento derecho bit a bit con asignación de extensiór. de signo Echa-Izda Desplazamiento derecho bit a bit con asignación de extensión a cero Dcha-Izda
  • 461. 452 Java 2. Manual de programación Este apéndice describe las reglas básicas de sintaxis de Java que cumplen las dife- rentes versiones existentes en la fecha de publicación de este libro: JDKl .1, 1.2y 1.3, con el compilador Java 2.0. Gran parte de la sintaxis de Java se basa en C y/o C++. C.1. ESTRUCTURA DE PROGRAMAS JAVA Un programa Java consta de una colección de archivos o unidades de compilación. Cada archivo puede contener un nombre opcional de paquete, una serie de declara- ciones i m p o r t y por último una secuencia de declaraciones de interfaces o clases. Una unidad de compilación puede identificar sus paquetes, importar cualquier número de otros paquetes, clases o interfaces y declarar cualquier número de clases e interfaces. C.1.1. Declaración de importaciones Una declaración de importación (import)nombra un elemento de otro paquete que se utilizará en las declaraciones posteriores de interfaces o clases. Se puede uti- lizar un asterisco para incluir todos los elementos de un paquete. importnombrePaquece.*; import nombrePaquete.NorrDreC-2se; importnonbrePaquete.NambreI?terfaz; Así, import java .io.* ; indica al compilador que importe cualquier clase del paquete java .io proporcionado por Java a medida que se necesite. Es una buena idea incluir esta línea al principio de cualquier archivo j ava que realice operaciones de entradaisalida. Otros ejemplos: importjava.ut;l.Date; import.]ava.net.*; C.1.2. Definición de clases Una definición de una clase consta de una declaración y un cuerpo. El cuerpo con- tiene campos de datos y declaraciones de métodos. La declaración de una clase cons- ta de palabras reservadas e identificadores: una secuencia opcional (en el modelo sintáctico para indicar que es opcional se encierra entre [ ] ) de modificadores, la palabra reservada class,el nombre de la clase, un nombre opcional de la clase padre, una secuencia opcional de interfaces y el cuerpo de la clase con sus miembros.
  • 462. Guía de sintaxis 453 [modificadoresDeClase] class Nombre [extends P a d r e ] [implements Inter f az I [ , I n t e r f a z 2 [ , . . .I:] { I //cuerpo de la clase (miembros) Los modificadoresDeClase pueden ser: abstract, final,public. Una clase abstracta es aquella que tiene uno o más métodos abstractos y de la que el programador no piensa instanciar objetos. Su fin es servir como supercla- se de la que otras puedan heredar. Las clases que heredan de una clase abstracta deben implementar los métodos abstractos de su superclase o seguirán siendo abs- tractas. Una clase final no puede ser superclase y todos sus métodos son implí- citamente final.Una clase pública debe estar en su propio archivo, denominado Nombre. java. Los miembros de una clase pueden ser métodos y variables de ins- tancia (pertenecientes a un tipo base o una clase). / / Formato más simple de una definición de clase class Claseüno I } I / Claseüno / / campos de datos y declaraciones de métodos / / Una clase que extiende otra clase public class ClaseDos extends Otraclase I / / campos de datos y declaraciones de métodos } / / ClaseDos / / Clase compleja public abstract class Miobjeto extends Otraclase iniplaments InterfazUno, InterfazDos t } / / MiObjeto / / campos de datos y declaraciones de métodos Ejemplos 1. public class Primerprograma public s t a t i c void main (String[] args) I 1 System.out.println("SierraMagina-Carchelejo");
  • 463. 454 Java 2. Manual de programación 2. public abstract c l a s s Numero t . . . 1 C.1.3. Declaración de variables En Java, las variables se pueden declarar: 1) como campos de datos de una clase, 2) como argumentos de un método, o 3) como variables locales dentro de un bloque. C.1.4. Declaracionesde campos de datos y variables de métodos Una variable se declara proporcionando su tipo y su identificador. El tipo puede ser uno de los tipos primitivos o puede ser una clase. Las declaraciones de las variables locales y campos de datos pueden incluir la asignación de un valor inicial. Los argu- mentos obtienen su valor inicial cuando se llama al método. //Elempios de declaraciones de variables de método o campos de datos i n t z; / / identificador z es de tipo int char in;cialNonbre =' M' ; / / inicialNombre es de tipo char / / y de valor inicial 'M' Strir,g saludo = "HolaMackoy"; / / saludo es de tipo String / / y de valor inicial "HolaMackoy" boolean interruptor = false; / / interruptor es de tipo boolean / / y valor inicial false Una declaración de variables de instancia o campos de datos tiene una parte de modificador opcional, un tipo, un nombre de variable y una inicialización opcional. [modificadoresDeVariable] tipo nombre [ = valor] ; Los modificadoresDeVariable pueden ser: public, protected, static,final. Ejemplos 1. public class protected protected protected / / . . . i Figura Rectangulo position; double dx,dy; Color color;
  • 464. Guía de sintaxis 455 2. c l a s s Empleado extends Persona i protected String nombre = " " ; protected i n t edad; protected Empieado unEmpleado; 11... C.1.5. Visibilidad de campos de datos Los campos de datos son accesibles desde cualquier método dentro de la clase. Dependiendo de la visibilidad declarada, otros objetos pueden acceder también a los campos de datos. A los campos de datos que no se les proporciona un valor inicial explícito se les asigna un valor por defecto. C.1.6. Declaración de constantes de clase Las constantes de una clase se decíaran como variables, siendo necesario comenzar su declaración con las palabras reservadas f i n a l y s t a t i c y se les asigna un valor en la declaración. Este valor ya no se podw modificar. Ejemplo c l a s s Empleado extends Persona t public s t a t i c f i n a l cantidaa = 50; //declaración de variabies //declaraciones de métodos C.l.7. Conversión explícita de tipos (nombre-t i p o ) expresibn C.1.8. Creación de objetos Una instanciación (creación) de objetos crea una instancia de una clase y declara una variable de ese tipo. Los objetos se crean a partir de una clase utilizando el ope- rador new. La sintaxis adecuada es:
  • 465. 456 Java 2. Manual de programación [ tipo] nombrevariable = new tipo( [parámetrol[ , parámetroZ[, ...I I]) ; Repuesto unapieza = new Repuesto ( ) ; Automovil micarro = new Automovil (5, "Golf"); La creación de una instancia (un objeto): Le asigna memoria dinámicamente. Crea un objeto con el nombre nombrevariable. inicializa sus variables de instancia a los valores por defecto: n u l 1para los objetos, false para variables booleanas, O para los otros tipos base. Llama al constructor con los parámetros especificados. Por último, devuelve una referencia al objeto creado, es decir, la dirección de memoria donde se encuentra dicho objeto. C.1.9. Declaración de métodos Las declaraciones de métodos simples, denominadas también signuturus, constan de un tipo de retorno, un identificador, y una lista de argumentos (parámetros). El tipo de retorno puede ser cualquier tipo válido (incluyendo una clase) o el tipo void si no se devuelve nada. La lista de argumentos consta de declaraciones de tipo (sin valores iniciales) separados por comas. La lista de argumentos puede estar vacía. Los métodos pueden también tener una visibilidad explícita. [modificadoresDeMetodos] tipoDeResu1tado nombreMé todo ( [ tipoparámetrol parámetrol [,tipoParámetroZ parámetroZ[, ...I ] ] ) [throws ExcepciÓn1 [ , ExcepciÓn2[ ,.. .I I I t //cuerpo del método i Los modificadoresDeMetodospueden ser: public, protected,private, abstract,final,static,synchronized.Como tipoDeResultado se espe- cificará void cuando el método no devuelva resultados. En la implementación del método, cuando éste no haya sido declarado void, se utilizará la instrucción return para devolver un valor al punto de llamada del método. Es decir, en cuan- to que se ejecuta return,el método termina devolviendo un Único valor como resultado. Para devolver múltiples valores mediante una función en Java deben com- binarse todos los ellos en un objeto y devolver la referencia al objeto. A continua- ción del nombre del método y entre paréntesis se especificará la lista de parámetros, que constará de cero o más parámetros formales cada uno de ellos precedido por su tipo y separados por comas.
  • 466. Guía de sintaxis 457 Cuando se llama a un método, íos parámetros actuales se asignan a los paráme- tros formales correspondientes. Entre los parámetros actuales, los de la llamada, y los formales, los de la declaración, debe existir concordancia en cuanto a número, tipo y orden. La palabra reservada throws permite listar tipos de excepciones lanzadas por el método cuyo tratamiento se pospone para que sea efectuado por el método llamador. Los métodos de una clase están asociados con una instancia específica de la misma, excepto si son estáticos. public class Ejemploi { / / campos de datos declarados, ninguno / * Declaración simple: no se devuelve nada, no se pasa ningún private void calcularImpuestos(){ 1 argumento * / / / cuerpo del método / * Un método con un argumento de tipo double que devuelve us public int CalCUlarTotal (double x) [ entero * / / / cuerpo del método 1 / * Un método que devuelve un objeto de tipo Miobjeto con un protected MiObjeto convertir(int z, String s) { } entero y una cadena de entrada * / / / cuerpo del método 1 / / clase Ejemplo1 C.l.I O. Llamadas de métodos Cuando se llama a un método, se deben proporcionar los argumentos del tipo ade- cuado: / / interior de un método i calcularZ ( ) ; int z = calcularZ (16,25); Miobjeto ob] = convertir(25, " Hola Mackoy" ) ; C.l .I 1. El método main Cada aplicación Java (no los appkts) debe tener un método main que es donde comienza la ejecución de la misma. Es decir, para ejecutar un programa el intérprete de Java comienza llamando al método main ( ) . Este método se llama antes de la
  • 467. 458 Java 2. Manual de programación creación de un objeto y ha de declararse como static para que se pueda llamar sin tener que referirse a una instancia particular de la clase. Como además es Ila- mado por código fuera de su clase, también tiene que ser declarado como pub1ic, que es la forma de permitir que un miembro de una clase pueda ser utilizado por código que está fuera de la misma. La palabra reservada v o i d indica que main no devuelve nada. public s t a t i c void ma;?. (String[I args) String [ ] args es la declaración de un array de String,mediante el cual la clase podría tomar un número variable de parámetros en la línea de órdenes; aunque no se use, es necesario incluir este parámetro cuando se define el método main(). C.1.12. Extensión de clases [acceso] [ f i n a l : c l a s s Nombreclase extends Superclase / / cLerpo de la clase ampliaaa Constructor de la subclase 2TbreClase (arqll, . . . ) . . .) ; public i super . . . 1 C.1.I 3. Constructores La sintaxis de un constructor es similar a la de un método, sin tipoDeResultado y cuyo nombre debe coincidir con el de la clase. El constructor se invoca automáti- camente cuando se crea una instancia de la clase. ~ n o d i i i e a c o r e ~ D e C o n s ~ r t i c t o r ]nombreConstructor ( [ tipoParánetrol parámetrol [ , tipoParámetro2 parámetro2 [ , . . . I 1 1 ) //cuerpo ael constructor 1
  • 468. Guía de sintaxis 459 Los modificadoresDeConstructor siguen las mismas reglas que en los Un constructor debe ser invocado con el operador new. Una clase puede tener múltiples métodos constructores, siempre que éstos se diferencien unos de otros en el número y/o tipo de parámetros. métodos normales, pero un constructor abstracto estático final no está permitido. c l a s s Persona protected Ctrirg nombre = " " ; protected i n t edad = O; public Persona (String nom, int años) t nombre = nom; edad = años; public s t a t i c void main (String args [ 3 ) Persona p = new Persona ("Luisito Mackoy", 13); System.out.println("Nombre: 'I + p.nombre + " " + "Eaad: " t p.edad) ; 1 C.1.14. Los constructores en la extensión de clases El cuerpo de un constructor comienza con una llamada heredada al constructor de la superclase de la clase. Esta llamada debe ser la primera sentencia del cuerpo de un constructor y no puede aparecer en ningún otro lugar. En Java super ( . . .) es usado en vez del nombre del constructor de la superclase. Si no se usa super entonces se supone implícitamente que el cuerpo del constructor comienza con la llamada super ( ) sin parámetros. El resto del cuerpo es como un método normal. c l a s s Empleado extends Persona protected String categoria = " ' I ; protected i n t salario = O; public Empleado (String nom, i n t años, Ctrizg n:vel, i n t sueldo) super (nom, años); categoria = nivel; salario = sueldo; public s t a t i c void main (Strinq args [ ] )
  • 469. 460 Java 2. Manual de programación Empleado e = new Empieado ("Arzurito Mackoy", 13, "medio", System.out.println("Nombre: " + e.nombre + " '' + "Eaad: I' + e.edad) ; System.out.println("Nive1: " t e.categoria + " " + "Salario: " + e.salario); 200000); C.1.15. Definición e implementación de interfaces Definiciónde una interfaz public interface Nornbrein t e r f a z t public abstract tipoDeResu1 tado nombreMétodo () ; //otras declaraciones de métodos vacios. Se ha de tener en cuenta que: Todos los miembros de una interfaz son públicos automáticamente. Todos los métodos son abstractos automáticamente. Todos los campos deben ser declarados static y final. La clase que implementa la interfaz debe implementar todos los métodos decla- rados en ella. public class Irnplementa [extends Padre] implements NombreInterfaz public tipoDeResEltado nombreKétodo0 t / / . . . / / s e inplementan todos los métodos de la interfaz NombreInterfaz 1 Es posible que una clase implemente más de una interfaz. [ modificadoresDeClase] class Nombre [extends Padre] [implements I n t e r f a c e ] i, I n t e r f a c e 2 [, . . .111 //Implementación de todos los métodos de las distintas interfaces
  • 470. Guía de sintaxis 461 Es posible definir clases que tengan objetos del tipo NombreInterfaz,como si la interfaz fiera una clase, pudiendo así usarse en ellas, las diversas implementa- ciones de ésta. La clase E j emplo puede usar, entre otras que hubiera definidas, la que ofrece la clase Implementa. public class Ejemplo { public Ejemplo ( ) ( 1 public tipoDeResult a d o unMetodo(NombreInterfaz elemento) { / / . .. / / . .. C.l.I6. Clases anónimas Una clase anónima es aquella que no tiene nombre y, cuando se va a crear un obje- to de la misma, en lugar del nombre se coloca directamente la definición. n e w SuperNombreO { cuerpo clase ] Por ejemplo, considerando declarada una clase Implementa que implementa NombreInterfaz,la siguiente instrucción e.unMetodo ( n e w Implementa ( ) ) ; pasa a e.unMetodo una nueva instancia de dicha clase Implementacomo pará- metro. Si se quisiera emplear una clase anónima no se efectuaría la declaración de implementa y la instrucción anterior se sustituiría por: e.unMétodo ( n e w NombreInterfaz ( ) I public tipoDeResultado nombreMétodo() ( / / . .. 1 / * se implementan todos los métodos de la interfaz NombreInterfaz * / 1 ) ;
  • 471. 462 Java 2. Manual de programación C.2. SENTENCIAS C.2.1. Sentencias de declaración tipo nombreVariab1e; Ejemplos int longitud; double e; Circulo circulo; C.2.2. Sentencias de asignación Una sentencia se asignación asigna el valor de la expresión en el lado derecho a la variable del lado izquierdo. nombre = expresiónlegal; Ejemplos longitud = 5 + I ; i += 5; C.2.3. Sentencias return Las sentencias return proporcionan una salida de un método con un valor de retorno no void. Las sentencias de retorno pueden no aparecer en un método con un tipo de retorno void. Las sentencias return pueden aparecer en cualquier parte de una estructura de control; producen un retorno inmediato del método. El valor de la expresión a continuación del retorno debe coincidir con el tipo de retor- no del método. Ejemplo public int calcularResta(int x, int y) { I return x- y;
  • 472. Guía de sintaxis 463 C.2.4. Sentencias compuestas Las sentencias compuestas se encierran entre llaves { } y se ejecutan secuencial- mente dentro del bloque. Ejemplo i i n t m = 25; i n t n = 30; i n t p = m + n; / / asigna el valor 25 a m / / asigna el valor 30 a n / / asigna el valor 55 (m + n) a p C.2.5. Sentencia if Las sentencias de selección proporcionan control sobre dos alternativas basadas en el valor lógico de una expresión. i f (expresiónlógica) bloqueCen t e n c i a s l //si son varias sentencias se encierran entre { } bloqueCen tencias21 [else i f (expresiónlógica) [else bloqueSen tenciashr] Ejemplo i f (i < O ) else t System.out .println("Número negativo") ; System.out.print("Número válido, ' I ) ; System.out .println("es positivo") ; 1 C.2.6. Sentencia switch La sentencia switch es la bifurcación múltiple. switch (expresion-int) f
  • 473. 464 Java 2. Manual de programación case constante-expl: sentenciasl; entre llaves * / [break;] sentencias2; [break;] ] /*si se trata de múltiples acciones no es necesario encerrarlas [case constante-exp2 : [case constante-expN: sentenciasN; [break;] ] sentenciasX; [break;] ] [default Ejemplos 1. switch ( y / 50) { case 2: elemento = new Demo2 (O, O) ; break; case 3: elemento = new Demo3(0, O, 100); break; case 4: elemento = new Demo4(0, O, 200); break; case 5: elemento = new Demo5(O, O); break; 1 2. switch (n) case 1: case 2: i visualizarResultado break; case 3: case 4: case 5: case 6 : visualizarResultado visualizarResultado break; default: visualizarResultado } //fin de switch C.2.7. Etiquetas nombreE tiqueta: break [nombreEtiquetal; continue [nombreEtiqueta]; "1, 2, Sierra de Cazorla"); "3, 4, Sierra Magina"); "3, 6, Sierra de Jaen"); n + " fuera de rango");
  • 474. Guía de sintaxis 465 salir: i for (i = O; i < 10; i++) { for (j = O; j < 20; j++) I if (i == 1) break salir; System.out.print(j + " " ) ; System.out.println0; 1 } //fin del bloque con la etiqueta C.2.8. Sentencia while La sentencia while se utiliza para crear repeticiones de sentencias en el flujo del programa. while (expresiónlógica) bloqueSentencias //el bloquesentencias puede ejecutarse de O a n veces Ejemplo while (cuenta <= numero) { System.out .print(cuenta + ' I , " ) ; cuenta++; 1 C.2.9. Sentencia do-while La sentencia do-while se utiliza para repetir la ejecución de sentencias y se eje- cuta al menos una vez. do while (expresiónLÓgica); bloquesentencias //el bloquesentencias se ejecuta al menos una vez
  • 475. 466 Java 2. Manual de programación Ejemplo do S y s t e m . o u t . p r i n t ( c u e n t a + ' I , ' I ) ; c u e n t a + + ; I while ( c u e n t a <= numero) C.2.1O. Sentencia for La sentencia f o r se usa para repetir un número fijo de veces la ejecución de una serie de sentencias. f o r ( [ i n i c i a c i ó n ]; [ c o n d i c i ó n D e T e s t ] ; [ a c t u a l i z a c i ó n ] ) s e n t e n c i a s Ejemplo f o r ( i n t i = O ; i < 1 0 ; it+) a [ i ] = 5 * i; C.2.11. Método e x i t y sentencia break La sentencia b r e a k se puede utilizar en una sentencia swit ch o en cualquier tipo de sentencia de bucles. Cuando se ejecuta b r e a k el bucle que lo contiene o la sen- tencia switch terminan y el resto del cuerpo del bucle no se ejecuta. Una invoca- ción al método e x i t termina una aplicación. El formato normal de una invocación al método e x i t es S y s t e m . e x i t ( O ) ; La captura de excepciones se realiza mediante bloques t r y - c a t c h . La/s senten- ciais de un bloque se colocarán siempre entre llaves. try bloqueAIntentar //aunque sea una ú n i c a s e n t e n c i a ésta i r á e n t r e { } boqueCen t e nc ias1 catch ( t i p o E x c e p c i o n 1 i d e n t i f i c a d o r l )
  • 476. Guía de sintaxis 467 [catch (tipoExcepcion2 identificadoz-2) boqueSentencias2] . . . [ f i n a l l y boqueSentenciashr] o bien try f i n a l l y bloqueAintent a r boquesentenciasN ya que el bloque try no puede aparecer sólo. import java.io.*; public class ReturnTryEj { public s t a t i c i n t leer ( ) i InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader (isr); String cadena = ' I " ; try { cadena = br .readLine ( ) ; return Integer.parseInt(cadena); 1 catch (Exception e) { i f (e instanceof IOException) else i f (e instanceof NumberFormatException) System.out .print111("Error de entrada/salida") ; System.out .println("No tecleó un número entero"); 1 / / Instrucción siguiente a catch System.out .print111("Se devuelve O") ; return O; public s t a t i c void main (String args [ ] ) t i n t n; do {
  • 477. 468 Java 2.Manual de programación System.out.print("Deme un número entero entre 1 y 20 ' I ) ; n = leer ( ) ; 1 while ((n <= O) I 1 (n > 20)) ; System.out.println("2A'' + n + " = " + Math.pow(2,n)); 1 C.2.13. Sentencia throw Una sentencia throw lanza una excepción, que puede ser una excepción recibida o bien una nueva excepción. Una cláusula catch puede recibir una excepción y, en lugar de tratarla o después de hacerlo, volver a lanzarla mediante una instrucción throw. try bloqueAIntentar catch ( NumberForma tException i d e nt if icador) { / / . .. throw ( i d e n t i f i c a d o r ); 1 Para lanzar una nueva excepción, se crea un objeto de una subclase de Exception que implemente un constructor y se lanza con throw cuando ocurra el hecho que debe provocar la excepción: if ( e x p r e s i ó n l ó g i c a ) throw new ConstuctorSublclaseException( [parámetroi[ , parámetro2 [ , ...I l l ) ; Ejemplo if (edad < 18 I I edad > 65) throw new FueraDeRango ("Excepción: valor fuera de rango"); class FueraDeRango extends Exception { String mensaje; public FueraDeRango (String causa) i mensaje = causa;
  • 478. Guía de sintaxis 469 public String getMessage ( ) i 1 return mensaje; C.2.14. Sentencia throws Lista las excepciones no tratadas y pertenecientes a clases distintas de RuntimeException.Así, su tratamiento será pospuesto y deberá ser efectuado por el método llamador o tendrán que volver a ser listadas en la cabecera de éste con otra cláusula throws. [ rnodifi cadoresDeMé todos] tipoDeResultado nombreMétodo ( [t i p o p a r á m etrol paráme t r o l [,tipoParárnetro2 parárnetro2[, ... I , ' ] ) [throws Excepción1 [, Excepción2 [, . . .I I I //cuerpo del método que no trata la excepción C.2.15. Sentencia package Cada clase pública definida en Java debe ser almacenada en un archivo separado y si hay varias relacionadas todas ellas se almacenan en el mismo subdirectorio. Un conjunto de clases relacionadas definidas en un subdirectorio común puede constituir un paquete Java. Los archivos del paquete deben comenzar con la siguiente sentencia: package nombrepaquete; donde el nombre del paquete refleja el subdirectorio que contiene dichas clases. Se utiliza el carácter punto ( .) como separador entre nombres de directorios, cuando es necesario especificar varios para referenciar al que contiene las clases. Ejemplo package libro.Tema03;
  • 479. 470 Java 2. Manual de programación Se puede usar una clase definida en otro paquete especificando, para referirse a ella, la estructura de directorios del otro paquete seguida por el nombre de la clase que se desea usar y empleando el carácter punto como separador. Referenciar clases de esta forma puede resultar molesto y la solución consiste en utilizar import, que permite incluir clases externas o paquetes enteros en el archivo actual. c.3. MISCELÁNEA C.3.1. Referencia a miembros de una clase r:arnkre0bj e t o.i?omOreComponen te Si es static no es necesario referirse a una instancia en particular de la clase y puede referenciarse como nombreClase. nombreComponente Los miembros de una clase están asociados con una instancia específica de la misma, excepto si son estáticos. C.3.2. Conversión explícita de tipos Existen dos tipos fundamentales de conversiones de tipos que pueden ser realizados en Java, con respecto a tipos numéricos y con respecto a objetos. El formato a apli- car para efectuar una conversión explícita de tipos es: (tjpoA'ombre) expresión; Ejemplo double resultaao = (double) (4/8); //asigna 0.0 al resultado double resultado = (double)4/(double)8;//asigna 0.5 al resultado double reslJltado = (double)4/8; //asigna O. 5 al resultado double resiiltaao = 4/5; /*conversión implícita, asigna 0.0 al resultado * / A1cmr.o unAlumno = (Aluyno)KnaPersona;
  • 480. Guía de sintaxis 471 C.4. ARRAYS Un array es un objeto que contiene un número de posiciones de memoria consecu- tivas, celdas de memoria, cada una de las cuales contiene datos del mismo tipo. Los arrays en Java pueden se unidimensionales o multidimensionales C.4.1. Declaración de un array int arrEnt ] ; //array unidimensional capaz ae alnace-ar enteros float [ ] arrFloat; //array unidimensional capaz de almacenar floa: double[]; j arrCodble; //array bidimensional para almacenar datos cioLble int a [ ][I; //array bidimens-ona- capaz de alrracenar enteros C.4.2. Creación de un array arrEnt = new int[100]; /*necesaria su previa dec1araz:ón: int arrEnt[]; * / Es posible crear arrays en los que cada fila contiene un número diferente de columnas: a = new int[3][I; //asigna filas (supuesta la previa aeclaración) a [ O ] = new int[7]; //asigna 7 columnas a la f;ia O a[i] = new int[5]; //asigna 5 columnas a la fila 1 a [ 2 ] = new int[9]; //asigna 9 columnas a la fila 2 C.4.3. Combinar declaración y creación La declaración y la creación se pueden combinar. int[] arrEnt = new intiloo]; double[][ I arrDouble = new doubie[8j [lo]; Pelota [ ] arrayPelotas = new Pelota;lC]; C.4.4. Combinar declaración creación e inicialización int[] arrEnt = 119, 2, 3 , 5, 7, 6, 8, 15, 9, 12);
  • 481. 472 Java 2. Manual de programación C.4.5. Recorrido de los elementos de un array Se suele efectuar con ayuda de estructuras repetitivas. for (int i = O; i < arrayPelotas.1ength; i++) arrayPelotas [ i] = new Pelota ( ) ; C.4.6. Acceso a un elemento de un array Se accede a un elemento de un array mediante un índice que debe ser un valor ente- ro mayor o igual que cero y menor que el número de elementos del array (almace- nado en la variable de instancia length)y que especifica la posición del elemento en el array arrayPelotas [ 5 ] .moverA(24,15); a [ O ] [5] = 2 + a[Ol [4]; C.5. CADENAS Una cadena (string) es una secuencia de caracteres. Java proporciona una clase incorporada String para manejar cadenas de caracteres: String msg = "Sierra de Cazorla"; Si cadl y cad2 son variables de tipo cadena cadl == cad2 comprueba si las dos variables se refieren al mismo objeto. Mientras que cadl.compareTo(cad2) devuelve positivo, cero o negativo según cadl sea mayor, igual o menor que cad2. C.5.1. Concatenación de cadenas El operador + en Java tiene un significado especial de concatenación de cadenas y se puede utilizar con objetos de la clase String,que pertenece al paquete
  • 482. Guía de sintaxis 473 java .lang.Al contrario que C++, Java no soporta sobrecarga de operadores, el caso del operador +para concatenación de cadenas es una excepción a esta regla de Java. En cuanto uno de los operandos que intervienen en una expresión es de cade- na, el operador +convierte a cadena los valores de otros tipos que intervienen en la expresión y efectúa concatenación: a + b / / al menos a o b han de ser una cadena Ejemplos System.out.println (5+1); //Salida 6 System.out.println (""t5ii); //Salida 51 g.drawString(5+1, 100,100); //Error de sintaxis g.drawCtring ("5 + 1 = "+5+1,100,100); //Salida 5 + 1 = 51 String h = new String ("Felicidades"); String pm = new String("para Mackoy") ; String titulo = h + " " + pm; //imprime Felicidades para Mackoy; Cystem.out.println(titu1o); C.6. APPLETS Los applets son pequeños programas Java que se incluyen en páginas Web y cuyo código se descarga desde el servidor para ser ejecutado localmente por un navega- dor. Todas las applets disponen de cinco métodos que pueden sobreescribir, aunque no resulta obligatorio que lo hagan, pues tienen implementaciones por defecto, y que se invocarán automáticamente durante la ejecución de la misma. Cuatro de ellos son proporcionados por la clase Applet y el otro es paint perteneciente a la clase Container. import java.awt.*; import java.applet.*; public class NombreApplet extends Applet t public void init ( ) t / * Inicializa el applet y es invocado por el Appletviewer o el navegador cuando se carga el applet * / 1 public void start ( ) I
  • 483. 474 Java 2. Manual de programación / * Se ejeccta a continuacion de init y tambien cada vez que e ; usuario ael navegador regresa a la pagina HIM¿ donde reside el applet. Debe contener las tareas a Llevar a cabo en estas ocasiones * / public void stop() / x Se e;ecLta cuando el usuario abandona la pagina HTML er, la que reside el apple: * / public void destroy() I / * Libera todos l o s recursos que el applet est2 Ltilizaxdo y se ejecuta axtes de q'üe la applet se descargue cuando e l usuario sale de la sesión de navegación * / public void pain= (Graphics g) I / * D-bula en el applet al comenzar esta a ejecutarse y tamb;en cada vez qLe la misma necesita redibujarse * /