0% encontró este documento útil (0 votos)
948 vistas422 páginas

Programacion en Java 2

Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
948 vistas422 páginas

Programacion en Java 2

Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 422

PROGRAMACIÓN EN JAVA 2

fflrJ

PROGRAMACIÓN EN JAVA 2

Jesús Sánchez Allende


Doctor Ingeniero de Telecomunicación
Dpto. de Electrónica y Sistemas
Universidad Alfonso X El Sabio
Gabriel Huecas femández-Toribio
Doctor Ingeniero de Telecomunicación
Dpto. de Ingeniería de Sistemas Telemáticos
Universidad Politécnica de Madrid

Baltasar fernández Manjón


Doctor en Ciencias Físicas
Dpto. de Sistemas Informáticos y Programación
Universidad Complutense de Madrid

Pilar Moreno Día:z


Licenciada de Matemáticas
Dpto. de Electrónica y Sistemas
Universidad Alfonso X El Sabio

Antonio José Reinoso Peinado


Ingeniero en Informática
Dpto. de Electrónica y Sistemas
Universidad Alfonso X El Sabio

Ricardo Sosa Sánchez-Cortés


Ingeniero en Informática
Dpto. de Electrónica y Sistemas
Universidad Alfonso X El Sabio

h l'so...Ci.?...
t' A1 o~ 2.. --:r-<r/'K

MADRID• BOGOTÁ• BUENOS AIRES• CARACAS• GUATEMALA• LISBOA• MÉXICO


NUEVA YORK• PANAMÁ• SAN JUAN• SANTIAGO• SÁO PAULO
AUCKLAND • HAMBURGO •LONDRES• MILÁN• MONTREAL • NUEVA DELHI • PARÍS
SAN FRANCISCO • SIDNEY • SINGAPUR • ST. LOUIS • TOKIO • TORONTO
La información contenida en este libro procede de una obra original entregada por los autores.
No obstante, McGraw-Hill/Interamericana de España no garantiza la exactitud o perfección
de la información publicada. Tampoco asume ningún tipo de garantía sobre los contenidos
y las opiniones vertidas en dichos textos.

Este trabajo se publica con el reconocimiento expreso de que se está proporcionando una
información, pero no tratando de prestar ningún tipo de servicio profesional o técnico.
Los procedimientos y la información que se presentan en este libro tienen sólo la intención
de servir como guía general.

McGraw-Hill ha solicitado los permisos oportunos para la realización y el desarrollo de esta obra.

Programación en Java 2. Serie Schaum

No está permitida la reproducción total o parcial de este libro, ni su tratamiento informático,


ni la transmisión de ninguna forma o por cualquier medio, ya sea electrónico, mecánico,
por fotocopia, por registro u otros métodos, sin el permiso previo y por escrito de los titulares
del Copyright.

McGraw-Hm / lnteramericana
de España S. A. U.
DERECHOS RESERVADOS© 2005, respecto a la primera edición en español, por
McGRAW-HILL/INTERAMERICANA DE ESPAÑA, S. A. U.
Edificio Valrealty, 1ª planta
Basauri, 17
28023 Aravaca (Madrid)

www.mcgraw-hill.es
[email protected]

ISBN: 84-481-4591-7
Depósito legal: M. 24.998-2005

Editor: Carmelo Sánchez González


Compuesto en: GAAP Editorial, S. L.
lmpreso en:
A mis padres y a mis chicas, por estar conmigo.
JSA

A mi mujer, Paqui
y a mis hijos, Femando, Carmen y Raquel.
GHFT

A Pilar, Balti y Celia.


BFM

A mis padres.
PMD

A mis padres, Luis y María.


AJRP

A mis padres Gloria y Ricardo por apoyarme siempre en todo.


RSS
o ¿Qué es Java? ••• ma •• R • ME ••••••• B ••• M • B ••• WDNSE • R ••••• MRM •• D •• a• U ••• RB ••• m•• mnn 1.
0.1 El lenguaje de programación Java y la plataforma Java ...................... . 1
0.2 Desarrollo de programas ...................................................................... . 2
0.3 Aspectos sobre cómo escribir los programas ....................................... . 2
0.4 Entornos de desarrollo ......................................................................... . 3
0.4.1 NetBeans (java.sun.com o www.netbeans.org) ....................... . 3
0.4.2 Eclipse (www.eclipse.org) ....................................................... . 4
0.4.3 BlueJ (www.bluej.org) ............................................................. . 6
0.4.4 JCreator LE (www.jcreator.com) ............................................ . 7

Introducción a la programación ••••• ••• •••• ••... •••••• •••.. ••• •• •••• •... 9
1.1 Estructura de un programa.................................................................... 9
1.2 Identificadores ... .. ...... .. ..... ............... ... .......... ........ .................... ... .. .. ...... 1O
1.3 Tipos, variables y valores .. ................ ...................... ................... ........ .. 11
1.4 Expresiones........................................................................................... 13
1.5 Conversiones de tipo ............................................................................. 15
1.6 Enumerados........................................................................................... 15
l. 7 Petición de valores primitivos al usuario .............................................. 16
Problemas resueltos ...................... .. .......................................... ............ ............. 17

2.1 Estructura de una clase ....................................................................... .. 35


2.2 Atributos ............................................................................................... 36
2.3 Métodos ......................... ..................................................................... .. 37
2.4 Constructores ... ............. ...... ..... ............................................................. 38
Problemas resueltos ........................................................................................... 41
Ampliación de clases .....................................•..........•.... 6. 67
3.1 Elementos de clase (static) ... ...... .. .. ....... ... ... .. ...... ... ....... .. ... ........ ........ .. . 67
3.1.1 Valor inicial de atributos de clase............................................ 68
3.2 Derechos de acceso ............................................................................... 68
Contenido

3.3 Paquetes ................................................................................................ 69


3.3.1 Uso........................................................................................... 69
3.3.2 Nombres................................................................................... 69
3.4 Clases internas...................................................................................... 70
3.5 Importación estática de clases ..... .. ....... .. .. ...... .. ............ .. ........ .. .. ......... .. 71
3.6 Clases predefinidas ............................................................................... 72
3.6.1 Envoltorios............................................................................... 72
3.6.2 Math ........................................................................................ 74
3.6.3 String ....................................................................................... 74
Problemas resueltos ........................................................................................... 75

4 Estructuras de control .. IJil • • l!l • • lilllllllllllllllllill'ilD • ••m•a111111m•••m•n1111lllR • ••····•ªMtllili11'11!4!1111S!ll!llli l 95


4.1 Estructuras de selección ........................................................................ 95
4.1.1 Estructura if .. ................ .... ..... .. .... .. .... ..... .... .... .. .. ...... .. .. .. ...... .. . 95
4.1.2 Estructuraif-else:..................................................................... 95
4.1.3 Operador condicional............................................................... 96
4.1.4 Estructura switch ....... .... ...... ......... ..... ...... ...... .... .. .......... ........ .. 96
4.2 Estructuras de repetición....................................................................... 97
4.2.1 Estructura while ....................................................................... 97
4.2.2 Estructura do-while .................................................................. 98
4.2.3 Estructura for ........................................................................... 99
4.2.4 Uso de las estructuras de repetición......................................... 100
4.3 Estructuras de salto............................................................................... 100
4.3.1 Sentencia break........................................................................ 100
4.3.2 Sentenciacontinue ................................................................... 100
4.4 Excepciones.......................................................................................... 100
4.4.1 Captura.................................................................................... 100
4.4.2 Delegación............................................................................... 102
4.4.3 Definición de excepciones de usuario ...................................... 102
4.4.4 Lanzamiento de excepciones de usuario y redefinición ..... ....... 102
4.5 Aserciones............................................................................................. 103
4.5.1 Aserciones como comprobación de invariantes........................ 103
4.5.2 Aserciones como precondiciones ............................................. 103
4.5.3 Aserciones como postcondiciones ............................................ 104
4.5.4 Aserciones como invariantes.................................................... 104
Problemas resueltos ........................................................................................... 105

5.1 Composición ......................................................................................... 147


5.2 Herencia................................................................................................ 148
5.3 Compatibilidaddetipos ........................................................................ 149
5.4 Ámbitos y visibilidad ............................................................................ 149
5.5 Sobreescritura ....................................................................................... 150
5.6 Constructores........................................................................................ 150
5.7 Polimorfismo......................................................................................... 151
5.8 Herencia forzada y clases abstractas .................................................... 152
Problemas resueltos ........................................................................................... 153

Estructuras de almacenamiento ••••••••..••.•••••••.•..••.•••••.•••••• 185


6.1 Arrays ................................................................................................... 185
6.1.1 Declaración.............................................................................. 185
Contenido

6.1.2 Creación................................................................................... 185


6 .1. 3 Inicialización estática .... ....... ..... ... ..... .. ........ ..... ..... ..... .. .......... .. 186
6.1.4 Acceso a los valores................................................................. 186
6.1.5 Tamaño de un array ................................................................. 186
6.2 Arrays multidimensionales .................................................................... 186
6.2.1 Declaración y creación............................................................. 186
6.2.2 Acceso...................................................................................... 187
6.2.3 Tamaño de un array ................................................................. 187
6.2.4 Array de dos dimensiones no rectangulares............................. 187
6.3 API de manejo de arrays ....................................................................... 187
6.3.1 Uso con arrays de tipos primitivos........................................... 187
6.3.2 Uso con arrays de objetos........................................................ 188
6.4 Colecciones........................................................................................... 189
6.4.l ArrayListyLinkedList ............................................................ 190
6.4.2 HashSetyTreeSet.................................................................... 190
Problemas resueltos ................................................................ ........................... 193

CAPÍTULO 7 Entrada y salida 111a••·••11••·••111••11u1111••1111•m••······· ........ ll!:l.® • •••111•11••11uu1••••tU•r$· 229


7 .1 Concepto de flujo en Java ...... .. ....................... .. .................................... 229
7.2 Tipos de flujos....................................................................................... 229
7 .3 Leer y escribir en un archivo ........................................................... /;;,.}; i;!,30
7 .4 Filtros ...... .......... ....................... ......................... .......................... .......... 232
7 .5 Entrada desde teclado............................................................................ 233
7.6 La clase File.......................................................................................... 234
7. 7 Archivos de acceso aleatorio .............. .................................... ............... 235
7.8 Lectura y escritura de objetos............................................................... 236
Problemas resueltos ................................................................................ .,.........,; 238

CAPÍTULO 8 Interfaces 1111111m1111111m111111 ill lllllll 111. 111111u1111111111 Slil 11111111111111111lll11111111DIII11111111 • • • • • • 11!1 !11 • ••••••• 11111 • • • • • • • • • l!l:$1911:illll& 2-7,5
8.1 Definición y uso de interfaces ............................................................... 275
Problemas resueltos .... ........ ....... ........................................................................ 278

CAPÍTULO 9
9.1 Genéricos .............................................................................................. 301
9 .2 Definición de genéricos ........ ............ ............... ...................................... 301
9 .3 Herencia de genéricos y conversión de tipos ......................................... 302
9.4 Comodines............................................................................................. 302
9.5 Métodos genéricos................................................................................. 303
Problemas resueltos .... ............ ............ ............................................................... 305

CAPÍTULO 10 Interfaces gráficas de usuario con Swing ........................... 321


10.1 Creación de una interfaz gráfica ............. .............................................. 321
10.2 Tratamiento de eventos: El modelo de delegación................................. 321
10.2.1 Eventos, objetos fuente y objetos oyente................................ 322
10.3 Jerarquía y tipos de eventos ................... ................ ............................... 322
10.4 Clases oyentes y adaptadoras de eventos .............................................. 322
10.5 Contenedores y componentes en Java ................................................... 323
10.6 Componentes gráficos: Jerarquía y tipos .............................................. 323
10.6.1 Clases básicas.......................................................................... 324
10.6.2 Contenedores de alto nivel ....................................................... 324
10.6.3 Cuadros de diálogo estándar .................................................... 324
Contenido

10.6.4 Contenedores intermedios ........................................................ 326


10.6.5 Componentes atómicos ............................................................ 327
10.6.6 Otras clases gráficas de Swing ................................................ 331
10.7 Administradores de disposición o diseño (layout managers)................. 331
10.7.1 FlowLayout.............................................................................. 331
10.7.2 BoxLayout ............................................................................... 331
10.7.3 BorderLayout ........................................................................... 332
10.7.4 CardLayout .............................................................................. 332
10.7.5 GridLayout .............................................................................. 332
10.7.6 GridBagLayout ........................................................................ 332
Problemas resueltos ... ..................... ...... ............................................................. 333

CAPÍTULO 11 Applets ............................................................... s••••n••···· 381


11.1 Entorno y ciclo de vida de una applet ............................ ....................... 381
11.2 Creación de una applet ...... ............................................................... ..... 381
11.3 Clases Applet y JApplet .................... ............................... ................ ..... 382
11.4 HTML, XHTML y las applets: la marca <APPLET>
y la marca <OBJECT> ....................... ..................... ............... .......... ..... 382
Problemas resueltos .. ......................... ...... .............................. .. ............. ........ ..... 386
APÉNDICE A Documentación del código 111lllllllilfllllll811lllll • li •• IIIIIVIXilllllllllillfll!llllllllllll'll!l&l •• am•1111111111 • 11!lllllllllll'lilS81 397
A.1 Etiquetas y posición ....................... .................... .................... ........ ....... 398
A.2 Uso de las etiquetas............................................................................... 398
A.3 Orden de las etiquetas ................ ........................................................... 400
A.4 Ejemplo de documentación de una clase .......................................... ..... 400
APÉNDICE B Convenios de programación en Java .................................. 405
B.1 Estructura de un archivo fuente en Java ............................. ............. ..... 405
B.2 Sangrado y tamaño de las líneas........................................................... 406
B.3 Comentarios.......................................................................................... 407
B.4 Declaraciones........................................................................................ 408
B.5 Espacio en blanco ................................................................................. 408
B.6 Sentencias ............................................................................................. 409
B. 7 Elección de nombres ............................. ........................... ..................... 411
B.8 Prácticas de diseño................................................................................ 412
¿Qué es Java?

0 .. 1 EL LENGUAJE DE PROGRAMACIÓN JAVA Y LA PLATAFORMA JAVA


El lenguaje de programación Java es un lenguaje moderno, presentado por primera vez por Sun Microsystems en el
segundo semestre de 1995. Desde el principio ganó adeptos rápidamente por muy diversas razones, una de las más
importantes es su neutralidad respecto de la plataforma de ejecución lo que permite, entre otras cosas, añadir progra-
mas a una página Web.
Pero quizá lo que más guste a los programadores son un par de aspectos que le hacen muy cómodo y agradable de
usar para programar:

'" La sencillez y elegancia de cómo se escriben los programas en Java. A ello se une que es un lenguaje orientado
a objetos que evita muchas preocupaciones a los programadores. En el proceso de compilación se realizan
multitud de comprobaciones que permiten eliminar muchos posibles errores posteriores.
'" Las bibliotecas ya definidas que proporciona el lenguaje y que el programador puede utilizar sin tener que
hacerlas de nuevo.

La evolución de Java ha sido muy rápida. Desde que se hizo público el lenguaje y un primer entorno de desarrollo,
el JDK (Java Development Kit), hasta el momento actual, la plataforma Java ha ido creciendo constantemente y a un
ritmo cada vez mayor según se han ido incorporando un gran número de programadores de todo el mundo.
Pero Java 2 no es sólo un lenguaje. Es una plataforma de desarrollo de programas que consta de:

• Un lenguaje de programación: el lenguaje Java, del mismo nombre que la plataforma.


• Un conjunto de bibliotecas estándar que se incluyen con la plataforma y que deben existir en cualquier entorno
con Java. También se denomina Java Core. Estas bibliotecas comprenden: strings, procesos, entrada y salida,
propiedades del sistema, fecha y hora, Applets, API de red, Internacionalización, Seguridad, Componentes,
Serialización, acceso a bases de datos, etc.
• Un conjunto de herramientas para el desarrollo de programas. Entre ellas cabe citar el compilador de Java a
código de bytes, el generador de documentación, el depurador de programas en Java, etc.
e Un entorno de ejecución cuyo principal componente es una máquina virtual para poder ejecutar los programas
en código de bytes.

La plataforma Java2 se puede utilizar desde distintos sistemas operativos, ejecutándose cada uno de ellos en el
hardware correspondiente. (Véase Figura 0.1.)
Programación en Java 2

Java
Sistema de ejecución
(runtime) API

Máquina virtual

Sistema operativo
(Solaris, Linux, Windows, Macos, ... )

Hardware
(Sparc, Pentium, PowerPC, ... )

Figura 0.1. Elementos de la plataforma Java 2.

0.2 DESARROLLO DE PROGRAMAS


El desarrollo de programas en Java, al igual que ocurre normalmente en otros lenguajes de programación, sigue un
proceso como el siguiente:

.. Edición del programa fuente. Se denomina programa fuente al programa que se escribe utilizando un entor-
no de programación como los descritos, o cualquier editor, en un lenguaje de programación. En Java los
archivos fuentes tienen un nombre como nombre.java, donde el nombre ha de ser el mismo que el empleado
como nombre de la clase y la extensión ha de ser .java.
.. Compilación. Tras escribir el programa hay que compilarlo utilizando un compilador. Los entornos de desa-
rrollo facilitan esa tarea, haciéndola casi invisible en alguno de ellos. También se puede compilar utilizando la
línea de comandos con la herramienta javac, de la siguiente forma: javac nombre.java.
En el proceso de compilación se comprueba que lo que se ha escrito es correcto en Java y se traducy a otro
lenguaje, denominado código de bytes (bytecode). Si durante la compilación se detectan errores, el entorno
avisará de los problemas detectados y dónde se han encontrado para que pueda corregirlos. Si en la compila-
ción no se detecta ningún error se genera un archivo como nombre.class, con el mismo nombre que la clase
que se compila pero con la extensión .class.
" Ejecución. Una vez compilado se ejecuta el programa y se comprueba si hace lo que se había previsto. Si el
programa no hace lo previsto se vuelve a editar, modificando los aspectos que no funcionan adecuadamente.

0.3 ASPECTOS SOBRE CÓMO ESCRIBIR LOS PROGRAMAS


Los pasos indicados anteriormente dan una idea muy breve de cómo escribir programas. Cuando escriba un programa
debe tener en cuenta a qué dar más importancia de acuerdo con la siguiente máxima:

Legibilidad > Corrección > Eficiencia


¿Qué es Java?

Que viene a indicar la importancia relativa que debe conceder a estos tres aspectos en la programación:

111 Legibilidad: El programa ha de ser fácil de leer y entender, incluso para una persona que no haya participado
en el desarrollo del programa. Este aspecto es en la actualidad el más importante. A pesar de lo que pueda
pensar en este momento, dar legibilidad a un programa hará que los otros aspectos salgan ganando.
111 Corrección: Un programa debe hacer lo que tiene que hacer, ni de más, ni de menos. Se supone que con la fase
de pruebas se comprueba hasta cierto nivel que es cierto y que el programa funciona correctamente.
• Eficiencia: Suele ser una preocupación típica de muchos programadores. La eficiencia se suele medir en
tiempo que se tarda en ejecutar o en cantidad de memoria que ocupa el programa. Nuestro consejo es que se
olvide completamente de este tema. Una vez domine el lenguaje ya tendrá tiempo de ocuparse de ello.

En el Apéndice B puede encontrar recomendaciones específicas para mejorar la legibilidad de un programa y, por
tanto, debería conocerlas y seguirlas lo máximo posible. Siempre que pueda fíjese en cómo escriben los programas los
buenos programadores.

0.4 ENTORNOS DE DESARROLLO


Existen multitud de fabricantes que disponen de entornos de desarrollo para Java. En primer lugar están teniendo una
gran aceptación algunos entornos de libre distribución. Puede utilizar otros entornos, aunque sean de pago, ya que
existen versiones reducidas que se pueden utilizar para aprender los fundamentos del lenguaje y la programación con
Java.
En esta sección se va a hacer un recorrido rápido por cuatro entornos de desarrollo en Java que puede obtener de
forma gratuita y cómo utilizarlos para las tareas básicas que, como se han descrito en la sección anterior, son:

" Editar el programa fuente.


" Compilación y ejecución del programa.

Dada la extensión del libro, no se describirán otros aspectos de los entornos de programación. Tenga en cuenta
también, que los entornos que aquí se describen son las últimas versiones disponibles de los programas en el momen-
to final de entrega del libro manuscrito.
Dada la evolución de los entornos es fácil que la versión actualizada que usted pueda encontrar ya haya variado.
Sin embargo, esperamos que le siga siendo útil esta presentación.

0.4.1 NetBeans ljava.sun.com o www.netbeans.org)


NetBeans es un proyecto de creación de un entorno de libre distribución profesional patrocinado por Sun MicroSystems.
En java.sun.com puede encontrar un paquete completo que viene con el entorno de desarrollo NetBeans y la última
versión del lenguaje. Puede encontrarlo enjava.sun.comlj2se/J.5.0/
Tras iniciar NetBeans aparece una ventana como la de la Figura 0.3. Para empezar se elige en ella File -> New
Project. En la ventana que aparece seleccione Java Aplication. A continuación, aparece la ventana de la Figura 0.2. En
ella introduzca en Project Name el nombre del proyecto, por ejemplo Notas. En el último cuadro de texto (Create
Main Class) sustituya el nombre Main que aparece por defecto por el nombre de la clase principal que desee, en este
caso Notas, como ya aparece en la Figura 0.2.
En la ventana de trabajo aparece parte de una clase ya realizada. En ella debe completar el método main. También
puede eliminar todo lo que no va a necesitar para su aplicación. Una vez terminada de escribir la clase puede compi-
larla y ejecutarla en un paso pulsando sobre la flecha verde hacia la derecha de la barra de herramientas de la parte
superior.
En la parte inferior se mostrará tanto el proceso de compilación y los errores que pueda tener el programa como el
resultado de la ejecución del mismo.
Programación en Java 2

"'l
~------~--~.J
l'rlljectli/)O;l!lroí j::\DocumsntsandSe~~ 1 !lr!;tw$e... 1
[s doolmsntos. . 91!lj.-!
~~~~~.l'r;Q¡eá
@~~~<;l¡¡oo !~'is:~¡;;;-··--···--·--··- ··---·]

Figura 0.2. Ventana de configuración de proyecto de NetBeans.

J .... Crer,,.tetl' a new instance of Notas "/


publ..io lletas() {
}

/U
" 8pe.rarn arg:s the .::orm.1:!tlld l1n.e l:l.rgw,i,ento
•1
pülic :ita.U.e: 't'Oid ma1n (String[] m:gs) (
Systcm.out.)llr:lntln("tiotu de Progr~1ón"l;
S7:rto.out.11rint("Nota del pri?m!!r parcial: "I:
Sr,,te:ia.out.print.ln(4.5):
Syatem.out.pr:lnt("Nota del :segundo pe.retal: "):
Sr,,tem.out.11rintl.n(7 .SJ;
Sy:stem.out.print("Nota ttnal: "):
Sr,,tem.0ut.J1riniln(6):

Figura 0.3. Ventana principal de trabajo de NetBeans.

0.4.2 Edipse (www.eclipse.org)


Eclipse es un proyecto de creación de un entorno genérico de desarrollo patrocinado principalmente por IBM. Su
objetivo es crear un marco de trabajo para distintas tareas y lenguajes de programación. Se puede encontrar una
versión preparada para trabajar con Java en www.eclipse.org/downloadsl. Tras iniciar el programa para empezar un
nuevo proyecto seleccione File-> New -> Project. Aparece la ventana de la Figura 0.4. En ella seleccione Java Project.
¿Qué es Java?

A continuación, en la ventana siguiente introduzca en el campo de texto Project Name el nombre del proyecto, por
ejemplo Notas. Tras generar el proyecto pulse Finish para terminar.

t~.$11 Plug-in Project


r¡i.¡;¡,,¡.cvs
Ej}.Q>Java
ljHli- Plug-in Development
l!Hzi,Simple

Figura 0.4. Ventana de selección de un nuevo proyecto en Eclipse.

Una vez generado el proyecto aparece en la parte derecha del entorno de desarrollo la información del proyecto.
Para crear la clase inicial del programa seleccione, pulsando con el botón derecho del ratón sobre el nombre del
proyecto, la opción New -> Class, y en la ventana que aparece rellene los campos Name, con el nombre de la clase, por
ejemplo Notas y marque la casilla de verificación para crear el método public static void main(), tal como aparece en
la Figura 0.5.

Figura 0.5. Ventana de creación de la clase principal en Eclipse.


Programaci6n en Java 2

Una vez aparezca el código fuente generado complételo como aparece en el Figura 0.6. Para ejecutarlo seleccione
el icono verde con una flecha hacia la derecha. Le aparecerá una ventana de configuración de la ejecución la primera
vez. En ella seleccione en la parte derecha Java Aplication, seleccione en el modo Run la opción Java y haga doble clic
en Java Aplication para, por último hacer doble clic en Notas.java. Las siguientes veces ya guarda esta configuración
y basta con hacer clic en el icono verde de ejecución.

/O
* ?pi.%illl<"\ ar9s
•/
publi.c static voi.d main{String{] args) f
system.out.println(,.Notas de Pt:e>gramaci6n");
system.out.print{"Nota del primer parcial: "
system .out.println (4.5);
system.out.print("Nota del segundo parcial:
system.out.println n .5);
System.out.print(,.Mota final: ");
System.out.println(ó);

Figura 0.6. Ventana de trabajo de Eclipse.

0.4.3 BlueJ (www.bluej.o rg)


BlueJ es un entorno desarrollado en la Universidad de Kent. Antes de instalar el entorno debe descargar de la página
de Sun el paquete J2SE e instalarlo. Como podrá observar en las siguientes figuras, su aspecto es mucho más sencillo
que los entornos anteriores.
Al iniciarse debe elegir Project -> New Project y elegir un nombre para el proyecto, por ejemplo Notas. A continua-
ción, aparece la pantalla de la Figura 0.7. Escriba en ella el nombre de la clase y seleccione Class. Se creará un recuadro
rayado (significa que no está compilada la clase). Si hace doble clic en el recuadro rayado podrá editar la clase.

Figura 0.7. Pantalla de creación de una nueva clase, interface, enumerado, etc.
¿Qué es Java?

ente todo dejando sólo el


Por defecto se crea una clase con muchos elementos predefinidos. Puede borrar prácticam
el resto de la clase como en
nombre de la clase y las llaves de apertura y cierre de la misma. Escriba el método main y
o de la ventana de clases.
el ejemplo de la Figura 0.8. Para compilar, pulse el botón Compile de la ventana de edición
a la clase aparecerá sin rayar.
Una vez compilado el programa, si compila correctamente, el recuadro que represent
Pulse OK. Aparecer á una
Para ejecutar el programa pulse con el botón derecho sobre él y seleccione el método main.
nueva ventana con el resultado de la ejecución.

.,
• Ovt.u1cn (4 vt.r::1<:m. mooei: ce a lh.~J

1c cl.u:r Xous (
publ1c 9to.tic void "111(.Str:irl.9[] u:qs) (
Systea.wt.p.r:1ntln .("'!OtM d'1: Pr:o,¡r&¾a':U·n")J
1'ystt::!l.cut,l)únt. rl'Jota dtl p-rlvAt V{lrt1,i<,1: ");
SfSttihO\&t,pc1nU Dl4,S): .
~cut.pu.M.C"'! t"'t<l <td ; ¡ : ~ p&.u:t-'111: .. ,J
~~t..p'timl11. (1.S);
sy.,ta.cuc,prtnt("t t1>tll !11:.'.':ll~ ");
Sp«111;,out.p1:1m. lu!61;

Figura 0.8. Ventana general y de edición de clases de BlueJ.

0.4.4 JCrea tor LE (www .jcrea tor.co m)


se le enviará un URL de
La versión LE es una versión de uso gratuito. Tras indicar su nombre y dirección de correo
puede seleccion ar File -> New -> New project. Aparece la ventana de
donde descargarse el programa. Tras instalarlo
En este caso se le ha dado el nombre Notas.
la Figura 0.9 donde puede dar un nombre al proyecto.

Project TemplalB
@~
Project Cia!ISPalh
ProjectTools

Figura 0.9. Ventana de creación del proyecto en JCreator.


Programación en Java 2

Aparece entonces la ventana principal como la de la Figura 0.9. Haga doble clic en el nombre del programa
Notas.java y borre lo que no necesite del código que aparece en la ventana de trabajo. Pulse el botón de
compilar y
después el de ejecutar (como se ha marcado en la Figura 0.10). Al ejecutar el programa aparece una ventana
con el
resultado de la ejecución.

'l
3
4
5
/H

* AWf Sam.ple appl 1ca.tion



* @duthor
* @vers1on l. 00

8l
,i: fl/
7 8 pub lle class Notas {
publlc stat1c vo1d main(String[J ar¡¡s) {
$ System.out.pr intln("Notas de Programación" );
10 System.out.pr 1nt("Nota del primer parcial: ");
11 System.out.p rintln(4.5),
12 System.out .pr1nt ( "Nota del segundo parcial: ")
l;! System.out.pr intln(7 .5);
14 System.out.pr 1nt("Nota final: ");
lS System.out.p rintln(6);
16
17 }
18

Figura 0.10. Pantalla principal de trabajo de JCreator.


Introducción a la programación

1.1 ESTRUCTURA DE UN PROGRAMA


Un programador debe utilizar los elementos que le ofrece el lenguaje de programación para, utilizándolos de forma
inteligente y lógica, crear un programa que resuelva un problema.
En el siguiente programa de ejemplo puede ver un programa muy sencillo escrito en Java. Este programa escribe
en la pantalla el texto Hola a todos.

/**
* Programa en Java que escribe un texto en la pantalla.
*/
public class Hola {
public static void main(String[J args) {
System.out.println("Hola a todos.");

En este programa se pueden ver algunos de los elementos que se van a utilizar siempre que se escribe un programa
en Java:

• Comentario. El programa empieza con un comentario. El comentario del programa empieza con /** y acaba
con*/.
• Defmición de clase. La primera línea del programa después del comentario def'me una clase que se llama
Ho l a. La definición de la clase empieza en el carácter abre llave { y termina en el carácter cierra llave }. Todo
lo encerrado entre las llaves defme el bloque de la clase.
• Definición de método. A continuación, se escribe el método ma in ( ) • Todos los programas en Java deben tener
un método ma in ( ) , que se escribe de la misma forma que el del ejemplo.
• Sentencias. Dentro del método ma i n( ) , en el bloque delimitado por abre llave y cierra llave, existe una única
sentencia o instrucción que escribe un texto por pantalla.

Para ver el resultado de ejecutar este programa, utilice el entorno de programación que haya elegido de la forma
descrita en la documentación del mismo. Tenga en cuenta que en Java las letras mayúsculas y las letras minúsculas
son letras distintas, por lo que debe escribirlas tal como aparecen en el ejemplo dado.
Programación en Java 2

La estructura general de una clase principal en Java suele ser la siguiente:

/**
* Estructura de una clase en Java
*/
public class NombreOeClase {
/! Declaración de los atributos de la clase

// Declaración de los métodos de la clase

// El método main, que indica donde empieza la ejecución


public static void main(String[J args) {
// Declaración de las variables del método

/! Sentencias de ejecución del método

En el caso de ser una clase distinta de la clase principal, el método ma i n( ) no suele aparecer.
Se han puesto como comentarios (que empiezan por dos barras) los elementos que suelen componer una clase, que
son los siguientes:

., Atributos de la clase. Son las variables que definen el estado de los objetos. Se tratarán con detalle en el
Capítulo 2. Puede pensar en ellos como variables definidas en el bloque de la clase.
,. Declaración de métodos. Son fragmentos de código que hacen una determinada función. Se tratarán con
detalle en el Capítulo 2.
., El método principal main(). Ya se ha visto en el primer ejemplo. Dentro de este método se escribe lo que se
desea que ejecute el programa, ya que siempre se empieza a ejecutar este método .
., Declaración de variables. Se verán en las siguientes secciones .
., Sentencias. Es la parte que se ejecuta en el programa. Ya se ha visto en el primer ejemplo un programa con
una sentencia para escribir un texto en la pantalla. Las sentencias se ejecutan siempre en el orden en el que se
escriben y, siempre, una detrás de otra, hasta que se acaba el método ma in ( ) .

1.2 IDENTIFICADORES
Un identificador es un nombre. Los nombres permiten identificar los elementos que se están manejando en un
programa. Existen reglas estrictas sobre cómo se pueden escribir los nombres de las clases, las variables, métodos,
etc. Cualquiera de estos nombres debe ser un identificador. Un identificador debe empezar con una letra y debe
seguir una sucesión de letras y dígitos.
Una letra es cualquier carácter que se considera una letra en Java. Como en Java se utiliza Unicode para los
caracteres, un identificador se puede escribir con caracteres hebreos, cirílicos, armenios, katakana, etc. Para formar
un identificador también se consideran letras los caracteres subrayado '_' y dólar '$', aunque el carácter'$' práctica-
mente no se suele utilizar, salvo en algún tipo de nombrado automático. Se considera un dígito a cualqnier carácter
entre los caracteres 'O' a '9'. De esta forma son válidos los siguientes identificadores:

ejemplo. EjemploOeidentificador. ecpeµnA.O. otroEjemplol2. uno2tres4oMás. AñoMás,


_víó_L6Qüeo_N6_3303459345
Introducción a la programación

Aunque de acuerdo con la regla anterior serían válidos, sin embargo, no lo son los identificadores que coincidan
con una palabra reservada del lenguaje (tenga cuidado porque final es una palabra reservada).
Cuando elija un identificador, siga las siguientes recomendaciones:
qué
" Debe utilizar nombres que sean significativos, de forma que cuando lo vea escrito sepa para qué sirve y de
tipo va a ser sin necesidad de acudir a su declaración.
, cada
" Los nombres de variables y métodos empiezan con minúscula. Si se trata de un nombre compuesto
de otras. Ejemplos de
palabra empieza con mayúscula. No se utiliza el carácter subrayado para separar unas
nombres de variables o métodos: n, númeroElementos, ponValor, escribeTít ulo.
empieza
" Los nombres de clases empiezan con mayúscula. Si se trata de un nombre compuesto, cada palabra
con mayúscula. No se utiliza el carácter subrayado para separar unas de otras. Ejemplos de nombres de clases:
VolumenCilindro,Alumno,ProgramaDePrueba .
carácter
., Los nombres de constantes se escriben en mayúsculas. Si el nombre es un nombre compuesto utilice el
subrayado para separar unos de otros. Ejemplos de nombres de constantes: PI, TAMAÑ0_MÁ XIM0.

1.3 TIPOS, VARIABLES Y VALORES


s, solici-
Un programa maneja valores, maneja datos de forma apropiada para cambiarlos, hacer cálculos, presentarlo
tarlos al usuario, escribirlos en un disco, enviarlos por una red, etc.
Una
Para poder manejar los valores en un programa se guardan en variables. Una variable guarda un único valor.
variable queda determinada por:

., Un nombre. Este nombre debe de ser como se ha indicado en la sección de identificadores .


., Un tipo. Permite conocer qué valores se pueden guardar en dicha variable.
" Un rango de valores que puede admitir. Viene determinado por el tipo de la variable.
guardar
Por ejemplo, si se tiene una variable de nombre númeroElementos, donde el tipo de valores que se pueden
no tenga sentido
son números enteros, númeroEl ementos puede contener el número 34, o el número -234 (aunque
el valor 3.45 ni un
contar elementos negativos, la variable podría contener ese valor). Pero nunca puede contener
como por ejemplo
texto como "ejemplo de texto", ni un valor mayor que el admitido por la variable,
239849695287398274832749. Para declarar una variable de un tipo, se indica de la siguiente forma:

double radio:
va a
Con ello se declara que va a existir en el programa una variable con el nombre radio y que esa variable
del programa poniendo su
guardar un valor del tipo doub le. Una vez declarada se puede utilizar en cualquier lugar
nombre. Siempre que se utilice el nombre de una variable es como si pusiese el valor que tiene.
forma:
Si se quiere guardar un valor en una variable, se utiliza el operador de asignación de valor de la siguiente

radio= 23.4:
desee. El
Donde se indica el nombre de la variable, el carácter igual (=), y cualquier expresión o cálculo que se
símbolo igual significa lo siguiente: haz el cálculo de la expresión que se encuentra a la derecha del igual y, después,
guarda el valor calculado en la variable que hay a la izquierda. Si después se ejecuta:

radio= 44.56:

la variable radio guarda el valor 44.56. El valor anterior se pierde en esa variable.
Programación en Java 2

Se puede declarar una constante poniendo el modificador final:

final double PI= 3.1415926536;

El valor de una constante no se puede modificar en el programa, por eso hay que darle un valor a la vez que se
declara.
Los tipos primitivos que se pueden utilizar para declarar variables, y los intervalos de valores de cada uno de ellos,
se pueden ver en la Tabla 1.1.

Tabla 1.1. Tipos primitivos en Java 2.

byte Entero con signo -128 a 127


short Entero con signo -32768 a 32767
int Entero con signo -2147483648 a 2147483647
long Entero con signo -922117036854775808 a 922117036854775807
float Real de simple precisión ±3.40282347e+38 a ±1.40239846e-45
double Real de doble precisión ±1.79769313486231570e+308 a ±4.94065645841246544e-324
char Caracteres Unicode \uOOOO a \uFFFF
boolean Verdadero o falso true o false

Los tipos primitivos se pueden clasificar en:

• Números enteros. Permiten representar números enteros positivos y negativos con distintos intervalos de valores.
• Números reales. Permiten guardar valores con decimales con distinta precisión.
., Caracteres. Existe un tipo carácter (char) que permite representar cualquier carácter Unicode.
• Booleano. Es un tipo que indica un valor lógico. Sólo tiene dos valores, verdadero (true) y falso (false).

Otro tipo muy utilizado es para los textos o cadenas de caracteres. En realidad se trata de objetos, que se verán con
detenimiento en los Capítulos 2 y 3, pero se pueden utilizar de forma sencilla como si fueran variables de tipos
primitivos.

Stri ng texto;
texto= "En un lugar de la mancha de cuyo nombre ... ";

Literales

Números enteros
Los números enteros se pueden escribir de tres formas:

.. En decimal: 21. Es la forma habitual.


• En octal: 025. En octal un número siempre empieza por cero, seguido de dígitos octales (del O al 7) .
., En hexadecimal : 0x15. En hexadecimal un número siempre empieza por Ox seguido de dígitos hexadecimales:
del O al 9, de la 'a' a la 'f' y de la 'A' a la 'F'.

Si se escribe un valor del tipo long se le debe añadir detrás el carácter 'l' o 'L' (una letra ele minúscula o
mayúscula).
Introducción a la programación

Números reales
Para escribir valores reales en Java, se puede hacer de las siguientes formas: le2, 2., .54, 0.45, 3.14, 56.34E-45. Es
decir, un número real en Java siempre tiene que tener un punto decimal o un exponente indicado por la letra e
minúscula o la letra E mayúscula.
Si no se indica nada se supone que pertenecen al tipo doub 1e. Si se desea que se interpreten como del tipo float se
debe añadir un carácter 'f' o 'F' detrás del valor de la siguiente forma: le2f, 2.f, .54f, 0.45f, 3.14f. Se puede añadir el
carácter 'd' o el carácter 'D' para indicar explícitamente que el valor es del tipo doub 1e, de la siguiente forma: 4.56d,
78.34e-4d.

Booleanos
Los valores del tipo boo lean sólo pueden ser dos, true y fa 1se, y se escriben siempre en minúsculas.

Caracteres
Los valores del tipo carácter representan un carácter Unicode. Un carácter siempre se escribe entre comillas simples.
Un valor carácter se escribe como 'a', 'Z', 'Ñ', ';', '1t', etc., o por su código de la tabla Unicode, en octal o en
hexadecimal. Por ejemplo: '\u00A3', en hexadecimal o '\102' en octal.
Existen algunos caracteres especiales como los que se indican en la Tabla 1.2.

Tabla 1.2. Caracteres especiales en Java.

\b Retroceso
\t Tabulador
\n Salto de línea
\r Cambio de línea
\" Carácter comillas dobles
\' Carácter comillas simples
\\ Carácter barra hacia atrás

1.4 EXPRESIONES
Sobre cada uno de los tipos de valores se pueden utilizar un conjunto de operadores para formar expresiones o
cálculos.

Números enteros
Al realizar una operación entre dos números enteros el resultado siempre es un entero.

• Unarias: poner un signo más o un signo menos delante. Por ejemplo: +44, -56.
• Multiplicativas: * multiplica dos valores, / divide el primer valor entre el segundo, y % calcula el resto de la
división entera. Ejemplos: 4 * 5, 8 / 2, 5 % 2.
• Aditivas(+,-): La suma y la resta de la forma usual. Ejemplo: 4 + 5
• Incremento y decremento(++, - -): Incrementa el valor en uno y decrementa el valor en uno de una variable.
Los operadores de incremento y decremento se pueden poner antes o después de la variable que se desea
incrementar o decrementar.
., Relación(>,>= ,<, <=): Permiten comparar valores. El resultado de una operación con los operadores de
relación es un valor boo 1ean indicando si es cierta o falsa la relación.
.. Operadores de igualdad(=, !=): Comparan si dos valores son iguales o son distintos. El resultado es un valor
del tipo boolean, indicando si es cierta o no la igualdad o desigualdad.
., Operadores de asignación(=,+ =,-=,*=,/=,%=) : El primero es el operador de asignación ya descrito y el resto
son operadores que permiten simplificar la escritura de expresiones muy comunes.
Programación en Java 2

Números reales
Con los números reales se pueden realizar las mismas operaciones que con números enteros. En el caso de las
operaciones unarias, aditivas o multiplicativas el resultado de la operación con números reales es un número real.
También se pueden utilizar los operadores de relación e igualdad cuyo resultado es un valor del tipo boo lean.

Booleanos
Los operadores sobre booleanos son los siguientes:

" Negación(!): Devuelve true si el operando vale false y viceversa.


., Y lógico(&&): Devuelve false si el primer operando vale false. En otro caso, dewelve lo que valga el segundo
operando. También existe la versión con un solo ampersand (&)en cuyo caso siempre se evalúan los dos operandos .
., O lógico (11): Devuelve true si el primer operando vale true. En otro caso, devuelve lo que valga el segundo
operando. También existe la versión con una sola barra vertical (1) en cuyo caso siempre se evalúan los dos
operandos.

Precedencia de operadores
Toda expresión se evalúa a un valor de una forma estricta. El cómo se evalúa una expresión depende del orden de
prioridad de los operadores que contenga dicha expresión. De forma simplificada el orden de prioridad y la forma de
evaluación es:

1. Operadores unarios.
2. Operadores multiplicativos, de izquierda a derecha.
3. Operadores aditivos, de izquierda a derecha.
4. Operadores de relación.
5. Operadores de asignación.

Teniendo en cuenta el orden de evaluación, la siguiente sentencia:

a= -3 + 5 + 2 * 4 - 6 / 4 * 3 - 5 %2:
(D@(z) ® ® ® ©® ®
evalúa la expresión de acuerdo al orden indicado debajo de la misma. De esta forma primero se aplica el operador
unario a 3 para obtener el valor -3. A continuación se van evaluando los operadores multiplicativos de izquierda a
derecha, 2 * 4 se evalúa a 8, 6 / 4 se evalúa a 1 que multiplicado por 3 se evalúa a 3 y 5 % 2 se evalúa a l. En este
momento la expresión queda:

a= -3 + 5 + 8 - 3 - 1:

Por último, se evalúan los operadores aditivos de izquierda a derecha, siendo el resultado final de 6. Este es el
valor que se guarda en la variable a.
Si se desea que la evaluación se realice en un orden específico, se deben utilizar paréntesis. En una expresión
siempre se empieza a evaluar por los paréntesis más internos.

Expresiones aritmético-lógic as
Una expresión aritmético-lógica es una expresión que devuelve un valor booleano donde se utilizan operadores
aritméticos y operadores relacionales y de igualdad. Una expresión aritmético-lógica podría ser la que sigue y su valor
es true, pues es cierto que 8 es menor que 10:

(3 + 5) < (5 * 2)
Introducción a la programación

En una expresión aritmético-lógica se pueden combinar varias expresiones sencillas de las anteriores mediante
los operadores lógicos. La precedencia de los operadores booleanos es menor que la de los operadores relacionales,
por lo que primero se evalúan las desigualdades y después los operadores booleanos. El orden de prioridad entre los
operadores booleanos es: la negación, después el Y lógico y, por último, el O lógico. La prioridad de los operadores de
asignación es la menor de todas. Por tanto, en la expresión:

3+5 < 5*2 11 3 > 8 && 7 > 6

se evalúa primero las expresiones aritméticas y después las relacionales, quedando la expresión

true 11 false && true

En realidad se evalúa en primer lugar la primera expresión a true, para, como el operador es 11, evaluar la
expresión completa a true.

1. 5 CONVERSIONES DE TIPO
En muchas ocasiones resulta necesario realizar algunas conversiones de tipos, de forma que el resultado sea del tipo
esperado. Para convertir valores entre tipos existen dos formas:

.. Conversión automática de tipos. Cuando el tipo al que se asigna un valor es "mayor'', la conversión se realiza
automáticamente. Así un valor de tipo doub le se puede multiplicar por otro del tipo i nt. Antes de hacer la
multiplicación se convierte el valor i nt a doub le y luego se hace la multiplicación entre reales .
., Conversión explícita. Se pone delante del valor a convertir, entre paréntesis, el tipo al que se desea convertir.
Como esta conversión suele implicar una pérdida de valor, hay que tener mucho cuidado. Por ejemplo ( i nt) 34. 45,
hace una conversión a un tipo i nt, trunca el valor y se pierden los decimales.

En la conversión de tipos existe un tipo especial de expresiones que involucra a los valores del tipo char. Un
tipo cha r siempre se puede utilizar en una expresión junto con números enteros como si fuese un número entero
más:

char e = 'A":
int n;
n =e+ 2:

1.6 ENUMERADOS
Los enumerados son conjuntos de valores constantes para los que no existe un tipo predefinido. Por ejemplo, no existe
ningún tipo predefinido para representar los días de la semana, las estaciones del año, los meses del año, los turnos de
clases, etc.
Para definir un tipo enumerado con sus valores se haría de la siguiente forma:

enum DíaSemana {LUNES. MARTES. MIÉRCOLES. JUEVES. VIERNES. SABADO. DOMINGO}


enum TurnoDeClase {MAÑANA. TARDE}
enum TipoDeClase {TEORIA. LABORATORIO. SEMINARIO. CHARLA. EXPERIMENTO}

En el siguiente ejemplo se manejan los valores de los días de la semana.


Programación en Java 2

public class Dias {


public enum DíaSemana {LUNES. MARTES. MIÉRCOLES. JUEVES. VIERNES. SABADO. DOMINGO}

public static void main(String[J args) {


DiaSemana hoy= DíaSemana.JUEVES:
DiaSemana último= DíaSemana.DOMINGO:

System.out.println("Hoy es " + hoy):


System.out.println("El ultimo día es " + último);

1. 7 PETICION DE VALORES PRIMITIVOS Al USUARIO


Como ya habrá imaginado lo habitual en un programa es que solicite datos al usuario para realizar los cálculos del
programa. En el siguiente ejemplo se presenta un programa para el cálculo del volumen de un cilindro en el que se
piden al usuario los datos del radio y la altura.

/**
* Programa en Java que pide al usuario los datos
* del radio y la altura de un cilindro y calcula su volumen
*/
import java.util.Scanner;
public class PedirDatos {
public static void main(Stríng[J args)
// El valor del numero pi
final double PI= 3.1415926536;
double radio;
double altura:

System. out. pri nt ln(" Introduzca los datos del ci 1indro: ");
.print("Radio: ");

"Altura:");

System.out.print("El área del cilindro es: ");


System.out.println(PI *radio* radio* altura);

En la primera línea marcada se declara un objeto de la clase Scanner. Ya verá en el Capítulo 2 qué es un objeto y
cómo se utiliza. De momento, piense que la variable teclado va a ser un objeto que nos va a permitir leer los datos que
se escriben por el teclado. En la segunda línea marcada, cuando el programa la ejecuta se queda esperando a que el
usuario escriba algo en el teclado y pulse la tecla de retorno. En ese momento convierte lo leído en un valor del tipo
doub l e y lo guarda en la variable radio. Igual ocurre con la tercera línea marcada para leer un valor para la altura. Si
lo que desea es leer otro tipo de datos hágalo como se indica en la Tabla 1.3.
Introducción a la programación

Tabla 1.3. Métodos para la lectura de distintos tipos de datos.

byte teclado.nextByte();
short teclado.nextShort();
int teclado.nextint();
long teclado.nextlong();
float teclado.nextFloat();
double teclado.nextDouble();
boolean teclado.nextBoolean();

PROGRAMAS DE ESCRITIJRA DE DATOS

Ejercicio 1.1:
Escriba un programa que escriba en la pantalla su nombre completo en una línea y en la línea siguiente su
fecha de nacimiento.

Planteamiento: Para escribir este programa se va a utilizar el esquema básico donde la clase tiene el nombre
Mi sDatosPersona les (fíjese en las mayúsculas y minúsculas). Dentro del bloque del ma in () se utilizarán dos
sentencias para escribir en pantalla, una para el nombre y otra para la fecha de nacimiento. Ambos datos se
escribirán como textos entre comillas dobles.

Solución:
public class MisDatosPersonales
public static void main(String[J args) {
System.out.println("José Juan Juárez Juárez"); <Cí¿----11
Para escribir un texto se pone entre
comillas dobles.
System.out.println("l2/12/1977");

Comentarios: Se utiliza System. out. pri nt l n() para escribir un texto y pasar a la línea siguiente.

Ejercicio 1.2:
Escriba un programa que imprima en la pantalla su nombre completo en una línea y en la línea siguiente su
fecha de nacimiento. Para ello escriba una sentencia para escribir el nombre, otra sentencia para escribir su
primer apellido y otra para escribir su segundo apellido.

Planteamiento: Se va a escribir un programa de nombre Mi sDatosPersona l es2 que escriba el nombre, que se
hará sin cambiar de línea, a continuación escriba el primer apellido sin cambiar de línea y, después, el segundo
apellido y cambie de línea. Para terminar escribe la fecha de nacimiento.

Solución:
public class MisDatosPersonales2 {
Programación en Java 2

public static void main(String[] args)


System. out. pri nt ("José Juan ") : < 1 t ¿ - - - - - - - - - 1 1 Hay que escribir un espacio para
que el apellido aparezca separado.
System.out.print("Juárez "):
System. out. printl n( "Juárez"):
System. out. pri nt l n( "12/12/1977") :

Ejercicio 1.3:
Escriba un programa que escriba en pantalla las notas de la asignatura de "Programación". En la primera
línea se escribirá el nombre de la asignatura. En las siguientes líneas se escribirán las notas de los dos
parciales realizados poniendo la nota de cada uno en líneas distintas. En la última línea escribirá la nota
final de la asignatura. Escriba lo que sea texto como un texto entre comillas dobles y lo que sea un número
como un número.

Planteamiento: Se va a escribir un programa de nombre Mi sNotas que escriba los textos tal y como se ha
hecho en los ejercicios anteriores. Para escribir las notas se utilizará la misma sentencia pero poniendo entre
paréntesis el número de la nota. Hay que tener cuidado porque en Java los números con decimales utilizan el
punto decimal.

Solución:
public class Notas
public static void main(String[] args) {
System. out. pri ntl n( "Notas de Programación"):
System.out.print("Nota del primer parcial: ");
System.out.println(4.5);4~------------11 Para los decimales hay que utilizar
el punto decimal.
System.out.print("Nota del segundo p9rcial: ");
System.out.println(7.5);
System.out. print( "Nota final: ");
System.out.println(6);

IDENTIFICADORES
Ejercicio 1.4:
Dados los siguientes identificadores que se van a utilizar en un programa escrito en Java, diga cuáles de ellos
son correctos y cuáles no. Justifi.que su respuesta.

a) mi carta
b) unacarta
c) mis2escritos
d) 4cientos
e) es_un_mensaje
f) no_vale nada
g) _ _ejemplo _ __
h) mi-programa
i) ¿cuantos?
j) el%Descontado
k) al50PORHORA
l) TengoMUCHOS$$$
Introducción a la programación

m) LOS400GOLPES
n) quieroUNAsolución

Planteamiento: Hay que tener en cuenta que un identificador sólo puede estar formado por letras y dígitos y
que debe comenzar exclusivamente por una letra.
En Java también se consideran letras los caracteres subrayado y $, aunque este último se utiliza sólo de forma
especial.

Solución:
a)No es correcto. pues tiene un espacio en medio.
b)Es correcto. pues está formado sólo por letras.
c)Es correcto. pues está formado por letras y tiene un dígito en medio.
d)No es correcto. pues comienza por un dígito y eso no es válido.
e) Es correcto. pues está formado sólo por letras. ya que el carácter subrayado se considera
también como una letra.
f) No es correcto. pues tiene un espacio en medio.
g) Es correcto. pues el carácter subrayado se considera una letra. Por tanto. el identificador
está formado sólo por letras.
h) No es correcto. pues el carácter guión no se considera una letra ni un dígito.
i) No es correcto. pues los caracteres de abre interrogación y cierra interrogación no se
consideran letras ni dígitos.
j) No es correcto. pues el carácter tanto por ciento no se considera una letra ni un dígito.
k) Es correcto. pues está formado por letras y tiene dígitos en medio.
l) Es correcto. pues el símbolo$ se considera también una letra.
m) Es correcto. pues está formado por letras y tiene dígitos en medio.
n) Es correcto, pues está formado sólo por letras.

Ejercicio 1.5:
Dados los siguientes identificadores que se van a utilizar en un programa escrito en Java, diga cuáles de ellos
son correctos y cuáles no. Justifique su respuesta.

a) descarta2
b) cuántosQuerrás
c) Carr3Mesas
d) raVaBienAvec$$
e) Égresa
f) osterreich
g) Nosyevan
h) EsaCziMÉceJEóoouuyOÜrfJ[(J)

Solución:
a) Es correcto. pues está formado sólo por letras y acaba en un dígito.
b) Es correcto. pues está formado sólo por letras.
c) Es correcto. pues está formado sólo por letras y un dígito en medio.
d) Es correcto. pues está formado sólo por letras. ya que la c con cedilla es una letra y el
carácter$ se considera una letra.
e) Es correcto. pues está formado sólo por letras. ya que la E tal como está acentuada es una letra.
f) Es correcto. pues está formado sólo por letras. ya que la o con diéresis es una letra.
g) Es correcto. pues está formado sólo por letras. ya que la y con diéresis es una letra.
h) Es correcto. pues está formado sólo por letras.
Programación en Java 2

VARIABLES Y EXPRESIONES ARITMÉTICAS

Ejercicio 1.6:
Escriba un programa que escriba en la pantalla cuánto le costará comprar unas deportivas cuyo precio de
catálogo es de 85,00 €, si sabe que puede conseguir una rebaja del 15%.

Planteamiento: Hay que realizar el cálculo de 85,00€ menos el 15%, para ello se utiliza la fórmula (85*(1-
0,15)). Hay que tener cuidado, pues en Java los números con decimales utilizan el punto decimal. Se llamará
al programa CompraZapati 11 as.

Solución:
public class CompraZapatillas
public static void main(String[J args) {
System.out.print(85.00 * (1 - 0.15)): 11-~----~1
Se utiliza el punto decimal para los
números reales.

Comentario: Al ejecutar el programa en la pantalla aparece 72. 25, cuyo valor también se puede calcular como
(85 * 0.85).

Ejercicio 1.7:
Escriba un programa que escriba en la pantalla cuánto le dará su banco después de seis meses si pone 2000€ en una
cuenta a plazo fijo al 2, 75% anual. Recuerde que al pagarle los intereses el banco le retendrá el 18% para hacienda.

Planteamiento: Hay que realizar el cálculo de 2000€ al 2,75%, es decir, los intereses son 2000*2,75/100/2, ya
que seis meses es ½ del año. De esos intereses le retienen el 18%, por lo que realmente el banco le pagará
2000*2,75/100/2 * (1-0,18).

Solución:
public class Calculolntereses
public static void main(String[J args)
System.out.print(2000*2.75/100/2 * (1-0.18)): +- Se utiliza el punto decimal para los
números reales.

Comentario: Al ejecutar el programa en la pantalla aparece 22. 55.

Aviso: En la expresión se han mezclado números reales y números enteros. Por tanto, se está haciendo una conver-
sión automática de tipos, convirtiendo todos los valores a reales y haciendo las operaciones entre números reales.

Ejercicio 1.8:
Escriba un programa que escriba en la pantalla cuánto le dará su banco después de seis meses si pone 2000€
en una cuenta a plaza fijo al 2, 75% anual. Recuerde que al pagarle los intereses el banco le retendrá el 18%
para hacienda. Escriba los mensajes apropiados para entender todos los cálculos.

Planteamiento: Hay que realizar el cálculo de 2000€ al 2,75%, es decir, los intereses son 2000*2,75/100/2, ya
que seis meses es ½ del año. De esos intereses le retienen el 18%, por lo que realmente el banco le pagará
2000*2,75/100/2 * (1-0,18).

Solución:
public class Calculolntereses
1.ntroducclón a Da programación

public static void main(String[J args) {


System. out .printl n( "Cálculo de intereses."): Se han puesto los cálculos entre
System.out.println("Dinero ingresado: 2000€."): paréntesis por claridad.
System.out.println("Interés anual: 2,75%"):
System.out.println("Intereses a los seis meses: "+ (2000*2.75/100/2)):
System. out. println( "Retenciones real izadas: " + (2000*2.75/100/2 * 18/100)):
System.out.println("Intereses cobrados: " + (2000*2.75/100/2 * (1 - 0.18))):

Aviso: Hay que tener cuidado al realizar cálculos e imprimirlos. Si se hubiese realizado una suma en lugar de
un producto y se hubiese escrito:

System. out. printl n( "La suma de 2 + 2 val e: " + 2+2):

se hubiese impreso en la pantalla:

La suma de 2 + 2 vale: 22

Es decir, los operadores + se evalúan de izquierda a derecha, por lo que se concatena el texto con el primer 2,
y el resultado es un texto. A continuación se concatena el texto con el segundo 2, pues hay otra operación+,
dando como resultado La suma de 2 + 2 vale: 22. Sin embargo, si se escribe:

System.out.println("El producto de 2 * 2 vale: "+ 2 * 2):

como el operador* tiene mayor precedencia que el operador+, en primer lugar se evalúa el operador*, por lo que
2*2 se evalúa a 4. A continuación, se evalúa la concatenación del texto con el 4, escribiendo, por tanto, en pantalla:

El producto de 2 + 2 vale: 4

Para escribir correctamente la suma de 2 + 2 hay que escribir la expresión aritmética entre paréntesis:

System.out.println("La suma de 2 + 2 vale: " + (2 + 2)):

Ejercicio 1.9:
Dadas las siguientes expresiones aritméticas, calcule cuál es el resultado de evaluarlas.

a) 25 + 20-15
b) 20 * 10 + 15 * JO
c) 20*10/2-20/5*3
d) 15 I 10 * 2 + 3 I 4 * 8

Planteamiento: Para cada una de las expresiones anteriores hay que tener en cuenta la precedencia de los
operadores. Como sólo constan de operadores aditivos y multiplicativos se harán primero los multiplicativos
de izquierda a derecha y luego los aditivos de izquierda a derecha. Hay que tener en cuenta también que como
todos los números son números enteros el resultado de todas las operaciones serán números enteros.

Solución:
a) 25 + 20-15
Se realizan las operaciones de izquierda a derecha, pues son todas aditivas:
25 + 20 - 15 = 45 - 15 = 30
Programación en Java 2

b) 20 * 10 + 15 * 10
Se realizan primero las operacione s multiplicativas de izquierda a derecha:
20 * 10 + 15 * 10 = 200 + 15 * 10 = 200 + 150
Después se realiza la operación de suma
200 + 150 = 350
c) 20 * 10 / 2- 20 / 5 * 3
Se realizan primero las operacione s multiplicat ivas de izquierda a derecha:
20 * 10 / 2 - 20 / 5 * 3 = 200 / 2 - 20 / 5 * 3 = 100 - 20 / 5 * 3 = 100 - 4 * 3 = 100 - 12
Después se realiza la operación de sustracción
100-12= 88
d) 15 / 10 * 2 + 3 / 4 * 8
Se realizan primero las operacione s multiplicativas de izquierda a derecha:
15 / 10 * 2 + 3 / 4 * 8 = 1 * 2 + 3 / 4 * 8 = 2 + 3 / 4 * 8 = 2 + O * 8 = 2 + O
Después se realiza la operación de suma
2+0=2

ello, en el
Comentari os: Hay que recordar que las operacione s entre valores enteros siempre son enteros. Por
apartado d) 15/10 se evalúa a 1 y, de la misma forma, 3/4 se evalúa a O.

Ejercicio 1.10:
Dadas las siguientes expresiones aritméticas, calcule cuál es el resultado de evaluarlas. Suponga que las
variables a y b que aparecen son del tipo i nt y a tiene el valor 2 y b tiene el valor 4.

a) -a + 5 % b - a * a
b) 5 + 3 % 7 * b * a-b % a
c) (a+l)*( b+l)-bl a

Planteamiento: En cada una de las expresione s anteriores, cuando sea necesario el valor sustituye la variable
en cuenta
por su valor. En el cálculo hay que tener en cuenta la precedenci a de los operadores. Hay que tener
enteros el resultado de todas las operacione s serán números
también que como todos los números son números
enteros.

Solución:
a) -a+ 5 % b - a * a
Antes de operar se va realizando la sustitución de valores
(se
Primero se evalúa la operación unaria del signo - delante de la variable a. El- 2 se evalúa al valor -2
representa por un signo menos más pequeño)
-2+5% 4-2*2= ~+5%b -a*a
Después se evalúan las operacione s multiplicativas de izquierda a derecha
-2 + 5 % b - a * a= -2 + 5 % 4 - a * a = -2 + 1 - a * a = -2 + 1 - 2 * 2 = -2 + 1 - 4
Por último se evalúan las operacione s aditivas de izquierda a derecha
-2+ 1-4=-l- 4 =-5
b) 5+3%7 *b*a-b% a
Se evalúan las operacione s multiplicativas de izquierda a derecha
5 + 3 % 7 * b * a-b % a =5 + 3 * b * a- b % a =5 + 3 * 4 * a-b % a =5 + 12 * a- b % a =5 +
12 *
2-b % a =5 + 24-b % a=5 +24-4 % 2 =5 +24-0
Por último se evalúan las operacione s aditivas de izquierda a derecha
5 + 24 - O = 29 - O = 29
c) (a+ 1) * (b + 1) - b / a
En primer lugar se evalúan las expresione s entre paréntesis
(2 + 1) * (b + 1) - b /a= 3 * (b + 1) - b /a= 3 * (4 + 1) - b / a = 3 * 5 - b / a
Introducción a la programación

Después se evalúan las operaciones multiplicativas de izquierda a derecha


3 * 5 - b /a= 15 - b / a= 15 - 4 / 2 = 15 - 2
Por último se evalúa la operación de sustracción
15 -2 = 13

Comentarios: Cuando en una expresión hay expresiones entre paréntesis, en primer lugar se evalúan los
paréntesis más internos.

Ejercicio 1.11:
Escriba un programa que defina dos variables enteras para describir las longitudes de los lados de un
rectángulo. El programa debe calcular y escribir en la pantalla las longitudes de los lados, el perímetro y el
área del rectángulo. (Suponga que el rectángulo mide 15cm de alto y 25cm de ancho.)

Planteamiento: Se necesita declarar dos variables para guardar los valores de los lados. Como se dice que los
lados son números enteros, las variables se declaran del tipo i nt. Para realizar los cálculos se van a declarar
dos variables más, una para el cálculo del perímetro y otra para el cálculo del área. Finalmente, se imprimirán
por pantalla todos los datos y resultados de los cálculos.

Solución:
public class Rectangulo
public static void main(String[] args) {
int alto= 15:
int ancho= 25:

int perímetro= 2 *alto+ 2 * ancho; Concatenación de textos y valores


int área= ancho* alto: de forma mezclada.

System.out.print("El recUngulo mide " + alto + " de alto ");


System.out.println("y " +ancho+ " de ancho.");•~- -----------'
System.out.println("El perímetro del rectángulo es: " + perímetro);
System.out.println("El área del rectángulo es: " + área);

Comentarios: Fíjese en los nombres elegidos para las variables. Es importante que se entienda bien para qué sirve
cada valor. Fíjese también en la estructura del programa: primero la declaración de variables y valores iniciales, un
segundo bloque de cálculos a partir de las variables y un tercer bloque de presentación de resultados. Tanto la elección
de nombres como la estructura utilizada facilitan seguir el programa y entender lo que hace fácilmente. Imagínese la
diferencia si las variables se hubiesen llamado a, b, e y d. Sería casi imposible saber para qué sirve el programa.

Ejercicio 1.12:
Escriba un programa para calcular el área y el volumen de un cilindro. Para ello declare una constante que
guarde el valor de 1r. Declare, también, variables para el diámetro y la altura del cilindro. Suponga para el
ejemplo que el cilindro tiene un diámetro de 15,5cm y una altura de 42,4cm.

Planteamiento: Se necesita declarar dos variables para guardar los valores del diámetro y la altura del cilin-
dro, que debe ser del tipo doub le. Además, hay que declarar una constante para el valor de x. El cálculo del
área y el volumen se realiza con las fórmulas clásicas para ello.

Solución:
public class AreaVolumenCilindro
Programación en Java 2

public static void main(String[J args)


final double PI= 3.14159265; ""~-----11 Se declara PI como una constante.

double diámetro= 15.5: // en cm.


double altura = 42.4: // en cm.

double radio =diámetro/ 2:


double área = 2 *PI* radio* radio+ 2 *PI* radio* altura;
double volumen= PI* radio* radio* altura;

System.out.print("Para un cilindro de radio " + radio);


System.out.println(" y altura"+ altura):
System.out.println("El área es:"+ área);
System.out.println("El volumen es: " + volumen);

Comentario: Para utilizar el número PI podría haberse utilizado el que ya está definido en la biblioteca
matemática. Para ello basta sustituir PI en las fórmulas por Math. PI (consulte en el Capítulo 2 cómo hacerlo).
Quizá el número de decimales que resulta al escribir los valores no sea el más apropiado. Puede dar un formato
más apropiado, con sólo dos decimales, utilizando el siguiente fragmento de código:

System.out.print("Para un cilindro de radio"+ radio):


System.out.println(" y altura "+ altura);
System.out.printf("El área es: %.2f\n". área);
System.out.printf("El volumen es: %.2f\n", volumen):

Además pri ntf() realiza una localización de los datos de forma que los números reales aparecen escritos con
coma decimal como se hace habitualmente. El % significa que a continuación aparecerá una definición de
formato. La expresión %.2f significa escribe un número real con dos dígitos después de la coma. En el mismo
punto del texto donde se escribe esa definición de formato se escribirá el valor de la variable que aparece a
continuación. El carácter \n al final del texto en el método printf() es el carácter de fm de línea.

Ejercicio 1.13:
Escriba un programa que escriba en la pantalla cuánto le dará su banco después de seis meses si pone 2000€
en una cuenta a plaza fijo al 2,75% anual. Recuerde que al pagarle los intereses el banco le retendrá el 18%
para hacienda. Utilice variables para manejar las cantidades y realizar los cálculos. Escriba los mensajes
apropiados para entender todos los cálculos.

Planteamiento: Para el cálculo se necesitarán variables para guardar el dinero a invertir (doub l e), el tipo de
interés anual (double) y el número de meses de la inversión (int). Como el tipo de retención que se aplica es
fijo se declarará como una constante de tipo double (pues pudiera ser un número no entero). También se
utilizará una constante que guarde el número de meses que tiene el año.

Solución:
public class Calculointereses
public static void main(String[] args) {
final double RETENCIÓN= 18;
final int mesesAño = 12:

double capital Invertido= 2000: //en euros


Introducción a la programación

double interésAnual = 2.75;


int meseslnversión = 6;

double interesesObtenidos = capital Invertido*


interésAnual / 100 *
meseslnversión / mesesAño;
Se hace conversión automática
double retención= interesesObtenidos *RETENCIÓN/ l00; •~,----11 de tipo de int a double.
double interesesCobrados = interesesObtenidos - retención;

System.out.println("Cálculo de intereses.");
System.out.printf("Dinero ingresado: %.2f€.\n", capitallnvertido);
System.out.printf( "Interés anual: %.2f%%. \n". interésAnual); &=====""""'"""'"'""'""""'"""'""""'""""'
System.out .printf("Intereses a los %d meses: %.2f€. \n". ~~---1i Seimprimendosvaloresenorden
de aparición.
mesesinversión. interesesObtenidos):
System.out.printf("Retención realizada: %.2f€. \n". retención);
System.out.printf("Intereses cobrados: %.2f€.\n". interesesCobrados);

Comentario: Para escribir valores monetarios resulta muy apropiado el uso de printf() (impresión con
formato) pues permite decidir que se desean imprimir sólo dos decimales. El formato %d indica escribir
un número entero y %f, un número real. Si aparece una definición de formato (siempre empieza con%),
se sustituye cada una de ellas por las variables que se pongan a continuación separadas por comas en el
mismo orden de aparición. Los tipos de los valores deben coincidir con el formato indicado para ellos.
Como % indica el principio de definición de formato, si se desea escribir el signo % hay que ponerlo dos
veces.

EXPRESIONES ARITMÉTICO-LÓGICAS

Ejercicio 1.14:
Dadas las siguientes expresiones aritmético-lógicas calcule cuál es el resultado de evaluarlas.

a) 25 > 20 && 13 > 5


b) JO+ 4 < 15 -3 11 2 * 5 + 1 > 14 -2 * 2
c) 4 * 2 <= 8 11 2 * 2 < 5 && 4 > 3 + 1
d) JO<= 2 * 5 && 3 < 4 11 !(8 > 7) && 3 * 2 <= 4 *2 - 1

Planteamiento: Para cada una de las expresiones anteriores hay que tener en cuenta que se trata de expresio-
nes aritméticas junto con operaciones de comparación y operaciones relacionales. De acuerdo con la preceden-
cia de las operaciones habrá que realizar las operaciones en el siguiente orden: operaciones aritméticas, opera-
ciones relacionales y, por último, operaciones booleanas. Las operaciones booleanas tienen la siguiente
precedencia: primero la negación, después el y-lógico(&&) y, por último, el o-lógico (11).

Solución:
a) 25 > 20 && 13 > 5
Se realizan las operaciones de relación
25 > 20 && 13 > 5 = true && 13 > 5
Como la parte izquierda del y-lógico(&&) vale true hay que evaluar la parte de la derecha:
true && 13 > 5 = true && true
Ahora se evalúa el &&
true && true = true
. Programación en Java 2

b) 10 + 4 < 15 - 3 112 * 5 + 1 > 14 - 2 * 2


Se evalúa la parte izquierda del operador o-lógico (11). Para ello se evalúa la relación<, y para hacerlo hay
que evaluar las expresiones aritméticas a su izquierda y a su derecha
10 + 4 < 15 - 3 11 2 * 5 + 1 > 14 - 2 * 2 = 14 < 15 - 3 11 2 * 5 + 1 > 14 - 2 * 2 = 14 < 12 11 2 * 5 + l > 14
-2*2
Se evalúa el operador <
14 < 12 11 2 * 5 + l > 14 - 2 * 2 = false 11 2 * 5 + 1 > 14 - 2 * 2
Como la parte izquierda del operador II vale false hay que evaluar su parte derecha
false 112 * 5 + 1 > 14-2 * 2=false 1110+ 1 > 14-2 * 2 =false 1111 > 14-2 * 2 =false 1111 > 14-8=false
11 11 > 6 = false II true
Por último se evalúa el operador 11
false II true = true
c) 4 * 2 <= 8 11 2 * 2 < 5 && 4 > 3 + 1
Esta expresión se evalúa de izquierda a derecha. Como tiene mayor prioridad el operador && que el
operador II se evalúa como si estuviese escrito (el 11 (e2 && e3)), por tanto se evalúa el y si su valor es
false se evalúa la parte derecha del operador 11, por ello:
4 * 2 <= 8 11 2 * 2 < 5 && 4 > 3 + 1 = 8 <= 8 11 2 * 2 < 5 && 4 > 3 + 1 = true 11 2 * 2 < 5 && 4 > 3 + 1
Como la expresión a la izquierda del operador II vale true ya no es necesario evaluar la parte a su derecha
true 11 2 * 2 < 5 && 4 > 3 + 1 = true
d) 10 <= 2 * 5 && 3 < 4 11 !(8 > 7) && 3 * 2 <= 4 * 2 - 1
Teniendo en cuenta la prioridad de los operadores booleanos la expresión a evaluar tiene la siguiente
estructura: ((el && e2) 11 (e3 && e4)). Por ello en primer lugar hay que evaluar la parte izquierda del
operador 11, y para ello en primer lugar la parte izquierda del primer operador&&, es decir, el.
10 <= 2 * 5 && 3 < 411 !(8 > 7) && 3 * 2 <= 4 * 2-1 = 10 <= 10 && 3 < 411 !(8 > 7) && 3 * 2 <= 4 *
2 - 1 = 10 <= true && 3 < 4 11 !(8 > 7) && 3 * 2 <= 4 * 2 - 1
Como la parte izquierda del primer operador && vale true se evalúa su parte derecha
true && 3 < 4 11 !(8 > 7) && 3 * 2 <= 4 * 2 - 1 = true && true 11 !(8 > 7) && 3 * 2 <= 4 * 2 - 1
Por tanto, el resultado de evaluar el primer operador && es true.
true && true 11 !(8 > 7) && 3 * 2 <= 4 * 2 - 1 = true 11 !(8 > 7) && 3 * 2 <= 4 * 2 - 1
En este momento como el operador II tiene a su izquierda el valor true, ya no necesita evaluar la parte a su
derecha, siendo el valor final de la expresión true
true 11 !(8 > 7) && 3 * 2 <= 4 * 2 - 1 = true

Ejercicio 1.15:
Dadas las siguientes expresiones aritmético-lógicas calcule cuál es el resultado de evaluarlas. Suponga que
las variables a y b que aparecen son del tipo i nt y a tiene el valor 5 y b tiene el valor 3.

a) !(a> b && 2 *a<= b)


b) b++ > 311 a+ b <= 8 && !(a> b)
c) a++ < 6 && (b += 2) < a
d) a++/2 < b && (a++/2 > b 11 (a* 2 < b *4))

Planteamiento: En cada una de las expresiones anteriores se sustituye la variable por su valor cuando se vaya a
utilizar. En el cálculo hay que tener en cuenta la precedencia de los operadores. Hay que tener en cuenta también
que como todos los números son números enteros el resultado de todas las operaciones serán números enteros.

Solución:
a) !(a> b && 2 * a<= b)
En primer lugar se evalúa la parte entre paréntesis. Para ello se evalúa primero la parte izquierda del
operador&&
!(a> b && 2 *a<= b) = !(5 > 3 && 2 *a<= b) = !(true && 2 *a<= b)
Introducción a la programación

Como la parte izquierda del operador && vale true, hay que evaluar su parte derecha
!(true && 2 *a<= b) = !(true && 2 * 5 <= 3) = !(true && 10 <= 3) = !(true && false)
De donde evaluando los operadores booleanos
!(true && false)= !(false)= true
b) b++ > 311 a+ b <= 8 && !(a> b)
Esta expresión se evalúa de izquierda a derecha. Como tiene mayor prioridad el operador && que el
operador II se evalúa como si estuviese escrito (el 11 (e2 && e3)), por tanto se evalúa el y si su valor es
false se evalúa la parte derecha del operador 11, por ello
b++ > 3 11 a+ b <= 8 && !(a> b) = 3 > 3 11 a+ b <= 8 && !(a> b) =false II a+ b <= 8 && !(a> b)
Además, al evaluar b++, b se incrementa en 1 pasando a valer 4. Como la parte izquierda de la expresión
vale false hay que evaluar la parte derecha. Se comienza entonces por la parte izquierda del operador &&
false II a+ b <= 8 && !(a> b) =false 115 + 4 <= 8 && !(a> b) = false 119 <= 8 && !(a> b) = false 119 <=
8 && !(a> b) = false II false && !(a> b)
Como la parte izquierda del operador && vale false ya no es necesario evaluar la parte derecha
false II false && !(a > b) = false II false = false
c) a++< 6 && (b += 2) < a
Esta expresión sólo tiene un operador boolean &&. Por tanto, se evalúa en primer lugar su parte izquierda
a++ < 6 && (b += 2) < a= 5 < 6 && (b += 2) < a= true && (b += 2) < a
y el valor de la variable a se incrementa en 1 a 6. A continuación se evalúa la parte derecha del operador
&&. (b += 2) añade a b el valor 2 y devuelve el valor resultado de la asignación
true && (b += 2) < a= true && (5) < a= true && 5 < 6= true && true= true
El resultado final es true y las variables a y b han quedado con los valores a = 6 y b = 5
d) a++/ 2 < b && (a++/ 2 > b 11 (a* 2 < b * 4))
Esta expresión consta de un operador booleano (&&) entre dos expresiones, por lo que en primer lugar se
evalúa su parte izquierda
a++/2 <b && (a++/2> b 11 (a* 2<b * 4))=5 /2<b && (a++/2> b 11 (a* 2<b * 4))=2< 3 && (a++
/ 2 > b 11 (a * 2 < b * 4)) = true && (a++/ 2 > b 11 (a* 2 < b * 4))
Tras obtener el valor de la variable a, esta se ha incrementado en 1, valiendo en este momento 6. Como la
parte izquierda del operador && vale true hay que evaluar su parte derecha. Para ello se comienza
evaluando la parte izquierda del operador 11
true && (a++/ 2 > b 11 (a* 2 < b * 4)) = true && (6 / 2 > b 11 (a* 2 < b * 4)) = true && (3 > 3 11 (a* 2 <
b * 4)) =true && (false 11 (a* 2 < b * 4))
Tras obtener el valor de la variable a, esta se incrementa en 1, valiendo en este momento 7. Como la parte
izquierda del operador II vale false hay que evaluar su parte derecha
true && (false 11 (a* 2 < b * 4)) =true && (false 11 (14 < 12)) =true && (false 11 (false)) =true && (false)
= false
Evaluándose, finalmente, la expresión a false.

Comentario: Cuando en una expresión hay expresiones entre paréntesis, en primer lugar se evalúan los
paréntesis más internos.

Ejercicio 1.16:
Dado el siguiente programa, indique qué escribe en pantalla. Justifique su respuesta.
public class OperadoresPrePostincremento {
public static void main(String[J args) {
int a=3. b=6. e:
e= a/ b:
System.out. pri ntl n( "El va lar de e es: " + e):
e= a% b:
System.out.println("El valor de e es: " + e):
a++:
Programación en Java 2

System.out.println("El valor de a es: " + a);


++a;
System.out.println("El valor de a es: .. + a):
e= ++a+ b++;
System.out.println("El valor de a es: .. + a):
System.out.println("El valor debes: " + b);
System.out.println("El valor de e es: .. + e):

e= ++a+ ++b;
System.out.println("El valor de a es: " + a):
System.out.println("El valor debes: " + b):
System.out.println("El valor de e es: .. + e):

Planteamiento: En sentencias donde se utiliza el operador de preincremento y el de postincremento hay que


tener cuidado por que si es de postincremento primero se observa el valor de la variable y, una vez se ha
utilizado, se incrementa el valor de la misma.

Solución: Se imprime en pantalla lo siguiente:

El valor de e es: o
El valor de e es: 3
El valor de a es: 4
El valor de a es: 5
El valor de a es: 6
El valor debes: 7
El valor de e es: 12
El valor de a es: 7
El valor debes: 8
El valor de e es: 15

El primer valor de e vale O pues se realiza la división entera. El segundo valor que se imprime de e es 3 pues
se calcula el resto de la división entera de 3 con 6. La primera vez que se imprime el valor de a vale 4, pues
antes de imprimirlo se incrementa su valor. La segunda vez ocurre lo mismo y vale entonces 5, pues se
incrementa, esta vez en preincremento antes de imprimir su valor.
Los valores que se imprimen a continuación de a y b son, efectivamente 6 y 7 respectivamente pues ambas
se han incrementado en la expresión que hay delante. Sin embargo, el valor que se imprime de e es de 12 pues
se realiza la suma de a ya incrementado (6) y b antes de incrementarse (6), ya que se utiliza el operador de
postincremento, lo que suma 12. Los últimos valores de a, b y e son, respectivamente, 7, 8 y 15, ya que al
imprimir a y b, ya se han incrementado y al guardar el valor en e se hace con los valores ya incrementados, ya
que tanto para a como para b se utiliza el operador de preincremento.

Ejercicio 1.17:
Dado el siguiente programa, indique qué escribe en pantalla. Justifique su respuesta.
public class ExpresionesConincrementos {
public static void main(String[] args) {
boolean expresión:
int a= 7;

expresión= 2 * 5<5*211 a+ 1 < 10 && ++a% 2 = O:


Introducción a la programación

System.out.println("El valor de la expresión es: "+ expresión):


expresión= 3 < 2 11 ++a> 6:
System.out.println("El valor de la expresión es: "+ expresión):

expresión= a++< 10 && a% 2 == O && a<= 10;


System. out. printl n( "El valor de la expresión es: " + expresión):

expresión= a++< 10 11 a% 3 == 2:
System.out.println("El valor de la expresión es: "+ expresión):

System. out. pri ntl n( "El valor de a es: " + a):

Planteamiento: Al evaluar las expresiones aritmético-lógicas, como ya se ha visto en los Ejercicios 1.14 y
1.15, la dificultad adicional es que hay que llevar cuenta de cómo se realiza el incremento, bien preincremento
o bien postincremento, de la variable a.

Solución: Se imprime en pantalla lo siguiente:

El valor de la expresión es: true


El valor de la expresión es: true
El valor de la expresión es: true
El valor de la expresión es: true
El valor de a es: 11

En la primera expresión aritmético lógica tanto la parte a la izquierda del operador && como la de su derecha
valen true, ya que en la parte de la derecha al hacerse el incremento en preincremento a valdrá 8 y por tanto
8 % 2 vale, ciertamente, O. En la segunda expresión aritmético lógica el valor de a se incrementa a 9, y este
valor sí es mayor que 6 por lo que la expresión vale true. En la tercera expresión aritmético lógica en la
primera comparación del valor de a, esta variable vale 9 y, por tanto, sí es menor que 10. Cuando pasa a
evaluar a en la siguiente comparación a vale 10, por lo que al hacer 10 % 2, el valor es, efectivamente, O. En
la última comparación también es cierto que 10 <= 10, por lo que la expresión completa vale true.
En la cuarta expresión aritmético lógica en la primera comparación del valor de a, esta variable vale 10 y,
por tanto, es falso que sea menor que 1O. Sin embargo, cuando se evalúa la parte derecha del operador II a ya se
ha incrementado al valor 11, por lo que sí es cierto que 11 % 3 es igual a 2 y, por tanto, la expresión vale true.
Para terminar se imprime el valor de a, que como se puede observar se ha incrementado en cuatro veces,
por lo que su valor final es de 11.

ENUMERADOS

Ejercicio 1.18:
Escriba un programa que defina un enumerado para los días de la semana. En el programa defina una
variable del enumerado y asígnele el valor del día que corresponde al martes. A continuación, escriba por
pantalla dicha variable y escriba el valor del enumerado correspondiente al domingo.

Planteamiento: Los valores del enumerado se escriben, como indica el convenio, todos en mayúsculas. Para
declarar una variable para este tipo de dato se utiliza el nombre dado al enumerado. Para asignarle el valor del
martes hay que poner delante el nombre del enumerado, un punto y el nombre del valor que corresponde al
martes. Para escribir el valor del domingo se pone, de la misma forma, el nombre del enumerado, un punto y
el nombre del valor que corresponde al domingo.
Pmgramaclón en Java 2

Solución:
public class Enumerados

public enum DíasSemana {LUNES. MARTES. MIERCOLES. JUEVES. VIERNES. SABADO. DOMINGO}

public static void main(String[] args) {


DíasSemana unDía = DíasSemana.MARTES;

System.out.println("El día elegido es:"+ unDía);


System.out.println("El último día de la semana es: "+ DíasSemana.DOMINGO);

Ejercicio 1.19:
Escriba en Java los siguientes tipos enumerados:

a) Los días laborables


b) Los tres primeros meses del año
c) Las calificaciones de un alumno
d) Los colores primarios
e) Las notas musicales
f) Los colores del arco iris
g) Los colores de síntesis de televisión

Planteamiento: Los valores del enumerado se escriben, como indica el convenio, todos en mayúsculas. Para
declarar los valores de cada uno de los enumerados se utilizarán los nombres que son de aplicación para cada
uno de ellos.

Solución:
a) Los días laborables
enum DíasLaborables {LUNES. MARTES. MIÉRCOLES. JUEVES. VIERNES}
b) Los tres primeros meses del año
enum TresPrimerosMeses {ENERO. FEBRERO. MARZO}
c) Las calificaciones de un alumno
enum Calificaciones {NO_PRESENTADO. SUSPENSO. APROBADO.
NOTABLE. SOBRESALIENTE. MATRÍCULA_DE_HONOR}
d) Los colores primarios
enum ColoresPrimarios {ROJO. AMARILLO. AZUL}
e) Las notas musicales
enum NotasMusicales {DO. RE. MI. FA. SOL. LA. SI}
h) Los colores del arco iris
enum ColoresArcoiris {AMARILLO. ROJO. ANARANJADO. AZUL. VERDE. AÑIL. VIOLETA}
i) Los colores de síntesis de la televisión
enum ColoresTelevisión {ROJO. VERDE. AZUL}
O también en inglés, por ejemplo:
enum RGB {RED. GREEN. BLUE}

Ejercicio 1.20:
Escriba un enumerado para los tipos de lavado de un túnel de lavado que guarde la información de los
tiempos. Los tipos de lavado son básico, normal y super y el tiempo que se tarda en cada uno es de 3, 5 y 8
minutos, respectivamente. Escriba un programa que muestre su funcionamiento.
Introducción a la programación

Planteamiento: Se escribe el enumerado con los valores correspondientes. Hay que declarar un atributo para
el tiempo y un método para obtenerlo. Para probarlo en una clase se declara una variable y se usa para ella el
método que obtiene el tiempo.

Solución:
enum Tipolavado{BASIC0(3), NORMAL(5). SUPER(8);
private int tiempo;
Tipolavado(int tiempo){
this.tiempo = tiempo;

public int tiempo(){


return tiempo;

public class Tunellavado{


public static void main(String[] args){
Tipolavado lavadoSuper = Tipolavado.SUPER:

System.out.println("El lavado"+ lavadoSuper +"tarda"+ lavadoSuper. tiempo());

ENTRADA DE DATOS DE USUARIO

Ejercicio 1.21:
Escriba un programa que solicite al usuario una cantidad en segundos y la convierta a días, horas, minutos
y segundos.

Planteamiento: Tras solicitar el número de segundos, el programa debe dividir sucesivamente el dato entre 60
para obtener los minutos, entre 60 para obtener las horas y entre 24 para obtener los días.

Solución:
import java.util.*;

public class Segundos


public static void main(String[] args) {
int segundosiniciales. segundos. minutos. horas. días;

Scanner teclado= new Scanner(System.in);

System.out.print("Introduzca un número de segundos: ");


segundosiniciales = teclado.nextint();

// se calculan los minutos y los segundos que restan


minutos = segundosiniciales / 60;
segundos= segundosiniciales %60:

// se calculan las horas y los minutos que restan


horas =minutos/ 60;
Programación en Java 2

minutos= minutos% 60;

// se calculan los días y las horas que restan


días =horas/ 24:
horas= horas% 24:

System.out.println(segundosiniciales +" segundos son"+ días+


" días. " + horas + " horas. " + minutos+
"minutos y"+ segundos+" segundos.");

Ejercicio 1.22:
Escriba un programa que solicite al usuario el tamaño del lado de un triángulo equilátero y calcule su
perímetro y su área.

Planteamiento: Tras solicitar el tamaño del lado, que ha de ser un número real, pues es una medida que
seguramente no sea un número de metros o de centímetros exactos, se calcula el perímetro como tres veces el
lado. Para calcular el área se necesita la base, que es un lado, y la altura, que se obtiene utilizando el teorema
de Pitágoras entre un lado y la mitad de la base.

Solución:
import java.util .Scanner;

public class TrianguloEquilatero


public static void main(String[J args) throws Exception{
double lado:
double perímetro. área:

// Se pide al usuario que introduzca por teclado el valor del lado


Scanner teclado= new Scanner(System.in);
System.out.print("Introduzca un valor para el lado: "):
lado= teclado.nextDouble():

perímetro= 3 * lado;
double altura= Math.sqrt(lado * lado - (lado/2.0) * (lado/2.0));
área= lado* altura/ 2:

System.out.print("El área del triángulo de lado"+ lado):


System.out.println(" es: "+ área):

System.out.print("El perímetro del triángulo de lado"+ lado):


System.out.println(" es: "+ perímetro):

Ejercicio 1.23:
Escriba un programa para calcular el consumo medio de un automóvil. Para ello el programa debe solicitar
información sobre las tres últimas veces que se repostó combustible. De la primera solicitará el precio del
litro del combustible, el total pagado en llenar el depósito y el número de kilómetros que marcaba el cuenta-
kilómetros. De la segunda vez sólo solicitará el precio del litro del combustible y el total pagado en llenar el
Introducción a la programación

dep6sito, y de la tercera vez, solicitará el valor que indicaba el cuentakil6metros. Con estos datos debe
calcular el consumo por cada 100 km y el coste por kil6metro.

Planteamiento : Para calcular el consumo medio hay que tener en cuenta cuántos kilómetros se han hecho
con el automóvil y cuántos litros de combustible se han consumido. El total de litros de combustible
consumidos es la suma de litros de los dos repostajes realizados, ya que de lo que se reposte en el último
no se puede conocer cuántos kilómetros se van a hacer hasta que se consuma el combustible que se ha
echado. A partir del precio por litro y el total pagado se puede obtener el número de litros que se han
echado en el depósito. Se hará la suma de los litros según se vayan introduciendo los datos. El consumo
por cada 100 km se calcula como el consumo total dividido por el número de kilómetros multiplicado por
100. El coste por kilómetro se calcula como lo que se ha pagado en los repostajes dividido por el total de
kilómetros realizados.

Solución:
import java.util.*:

public class Main {


public static void main(String[J args)
double preciolitro. litros= O:
double pagado. coste= O:
int kminicial. kmFinal. kilómetros:

Scanner teclado= new Scanner(System.in):

System.out.print("Introduzca el precio por litro del primer repostaje: "):


preciolitro = teclado.nextDouble():
System.out.print("Introduzca el coste total del primer repostaje: "):
pagado= teclado.nextDouble():
System. out. print( "Introduzca el valor del cuentakilómetros en el primer repostaje: "):
kminicial = teclado.nextlnt():
litros= pagado/preciolitro:
coste= pagado:

System.out.príntln():
System. out. print( "Introduzca el precio por 1itro del segundo repostaje: "):
preciolitro = teclado.nextDouble():
System.out.print("Introduzca el coste total del segundo repostaje: "):
pagado= teclado.nextDouble():
litros+= pagado/preciolitro:
coste+= pagado;

System.out.println():
System.out.print("Introduzca el valor del cuentakilómetros en el tercer repostaje: ");
kmFinal = teclado.nextlnt():
kilómetros= kmFinal - kminicial:

System.out.println("El consumo medio del automóvil es de " +


(litros/kilómetros*lOO) + " litros por cada 100 Km.");
System.out.println("El gasto medio es de"+ coste/kilómetros+" por kilómetro."):
Programación en Java 2

Aviso: Al utilizar la clase Scanner para leer los datos, éstos se leen localizados. Esto significa que para
introducir un número real, por ejemplo el coste por litro, hay que escribirlo con coma decimal, no con punto
decimal. Si se hace con punto decimal dará un error al intentar convertirlo a un número válido. Además, si en
un momento que se esperaba un número entero, se introduce otro tipo de dato, el sistema termina abruptamente.

Ejercicio 1.24:
Escriba un programa que calcule cuánto le dará su banco después de realizar una imposición a plazo fijo.
Para ello el programa debe pedir la cantidad que desea invertir en el banco, el tipo de interés anual que le
paga el banco por el dinero y el plazo que se mantiene la inversión. El programa debe calcular el dinero que
se obtiene después de dicho plazo. Recuerde que al pagarle los intereses el banco le retendrá el 18% para
hacienda. Escriba los mensajes apropiados para que el usuario pueda seguir el proceso de cálculo realizado.

Planteamiento: Hay que realizar un programa que utilice variables donde se vayan recogiendo los valores que se
piden al usuario, que serán el capital a invertir (capital Invertido), el tipo de interés anual (interésAnual) y los
meses que se mantiene la inversión (meses Inversión). El dato de la retención que se aplica sobre los intereses es fija
del 18%, por lo que se definirá como una constante (RETENCION). Se declarará un objeto de la clase Scanner para
solicitar al usuario los valores y leerlos. Después se realizarán los cálculos y se imprimirán por pantalla los resultados.

Solución:
import java.util.*;
public class CalculointeresesUsuario
public static void main(String[J args)
final double RETENCI0N = 18:
final int MESES_AÑO = 12;
Scanner teclado= new Scanner(System.in);
System.out.print("Introduzca la cantidad que desea invertir: "):
double capitallnvertido = teclado.nextDouble();
System.out.print("Introduzca el interés anual que le ofrece el banco: ");
double interésAnual = teclado.nextDouble():
System.out.print("Introduzca el número de meses de la inversión: "):
int mesesinversión = teclado.nextint();

double interesesübtenidos = capitalinvertido *


interésAnual / 100 *
mesesinversión / MESES_AÑO;
double retención= interesesübtenidos * RETENCION / 100;
double interesesCobrados = interesesübtenidos - retención:

System.out.println();
System.out.println("Cálculo de intereses."):
System.out.printf("Dinero a invertir: %.2f€. \n". capital Invertido):
System. out. printf(" Interés anual: %. 2f%%. \n". interésAnual):
System. out. pri ntf(" Intereses a los %d meses: %. 2f€. \n".
mesesinversión. interesesübtenidos):
System.out. printf( "Retención que se real iza: %. 2f€. \n". retención):
System .out. pri ntf(" Intereses a cobrar: %. 2f€. \n". i nteresesCobrados):

Aviso: Recuerde que al utilizar la clase Scanner los datos se leen localizados, por lo que se debe introducir los
valores no enteros con coma decimal.
Clases y objetos

2.1 ESTRUCTURA DE UNA CLASE


Como ya se ha comentado en el Capítulo 1, la estructura de una clase suele seguir el siguiente esquema:

/**
* Estructura de una clase en Java
*/
public class NombreDeClase {
// Declaración de los atributos de la clase

// Declaración de los métodos de la clase

// El método main, que indica donde empieza la ejecución


public static void main(String[] args) {
// Declaración de las variables del método

// Sentencias de ejecución del método

En el caso de ser una clase distinta de la clase principal, el método ma i n( ) no suele aparecer. Una clase es la
descripción (modelo) de un tipo de objetos. Una aplicación, un programa, se compone de un conjunto de clases, que
crean objetos que interactúan entre sí. El nombre de la clase se empezará, como convenio de programación, en
mayúscula. Una vez que la clase está disponible, el programador puede instanciar, crear, objetos de dicha clase. Por
ello, los términos "objeto" e "instancia de clase" o, simplemente, "instancia" se usan como sinónimos.
Para disponer de un objeto de la clase hace falta declarar una variable y crear el objeto. Suponga que dispone de
una clase Al umno de la siguiente forma, donde se ha suprimido su contenido:

class Alumno { }

La declaración de variables es similar a la de una variable, como se ha hecho en el Capítulo L


Programación en Java 2

Alumno al umnol;
Al umno a1umno2;

Para crear un objeto para cada variable, se utiliza el operador new:

alumnol = new Alumno():


alumno2 = new Alumno();

Referencia null
Una referencia a un objeto puede no tener asignada ninguna instancia. Existe un valor especial, llamado nu11, que indica
cuándo una referencia no tiene asignada ninguna instancia. Como ejemplo, se declara un nuevo al urnno3 de la clase Alumno:

A1umno a1umno3: / / va 1e "nu 77" por defecto

Se puede poner explícitamente una referencia a nu l l :

alumno2 = null: // vale "nu77" por asignación explfcita

Cuando una referencia a un objeto vale nul l, no se puede utilizar como objeto, pues no existe como tal.

Referencias compartidas: alias


Es posible que se disponga de varias referencias a un mismo objeto. Si sobre las declaraciones anteriores de al umnol
y al umno2 se hace:

alumnol = alumno2; // asignación de referencias

en este momento, las variables alumnol y alumno2 hacen referencia al mismo objeto de la clase alumno. Ello implica
que cualquier modificación del objeto alumno 1 modifica también el objeto al que hace referencia alumno2, ya que
realmente es el mismo.

2.2 ATRIBUTOS
Los atributos permiten guardar la información de un objeto. Por ejemplo, para un alumno se necesita saber la siguien-
te información: el nombre, los apellidos, el curso en que está matriculado, si su horario es de mañana o de tarde, etc.
Estos datos se almacenan en campos o atributos que se declaran como variables en el ámbito de la clase. La declara-
ción de atributos se hace de la siguiente forma:

enum Horario { MAÑANA. TARDE} // posibles horarios

el ass Al umno
String nombre:
String apellidos:
int añoDeNacimiento:
int númeroPersonal; // Número Personal: identificativo único
String grupo:
Horario horario= Horario.MAÑANA;

En este ejemplo, se ha declarado que la clase Alumno contiene seis atributos, nombre, ape 11 idos, añoDeNacimi ento,
númeroPersonal, grupo y horario. El Horario se ha definido como un enumerado con dos posibles tumos, MAÑANA y
Clases y objetos

TARDE. Como puede observar se puede dar un valor inicial a los atributos en la declaración. De esta forma se ha
indicado que el horario predeterminado para un alumno es el de mañana.
Si los atributos no se declaran como privados ni protegidos (consulte el Capítulo 3), se puede acceder a sus valores
con la notación objeto. atributo. Por ejemplo, para imprimir por pantalla el nombre del a1umnol, se puede escribir:

System. out. pri nt l nC"El nombre es: " + al umnol. nombre) ;

Aunque es posible acceder a un atributo de la forma indicada, suele ser preferible acceder a los mismos mediante
un método, llamado en este caso método de acceso.

2.3 MÉTODOS
Los métodos sirven para definir el comportamiento del objeto en sus interacciones con otros objetos. Siguiendo el
ejemplo de objetos de la clase Al umno se puede pedir su nombre, asignarle grupo, etc.

enum Horario { MAÑANA, TARDE} // posibles horarios

class Alumno {
String nombre;
String apellidos;
int añoDeNacimiento;
int númeroPersonal; // Número Personal: identificativo único
String grupo;
Horario horario~ Horario.MAÑANA;

public String dameGrupo() { ... }


public void ponGrupo(String nuevoGrupo) { ... }

Se han añadido dos métodos a la clase Alumno, uno llamado dameGrupo() para pedir a un objeto de la clase Alumno
el grupo al que asiste a clase y otro ponGrupo () para poder asignar un nuevo grupo a un Alumno. Se ha omitido por
claridad el cuerpo con el código de los métodos.
Para utilizar un método de la clase se utiliza la notación objeto.metodo( ), pasando entre los paréntesis los argu-
mentos que necesite el método al que se llama. Por ejemplo, para dar al al umnol el grupo "INF-01" y luego imprimir
por pantalla el grupo que tiene asignado, solicitándoselo mediante su método dameGrupo( ), se puede escribir:

al umnol. ponGrupo( "INF-01");


System.out. pri ntl n( "El alumno está en el grupo: " + al umnol.dameGrupoO);

Además de utilizar los nombres ponXXX() para los métodos que asignan un valor a un atributo y dameXXXX()
para los métodos que devuelven el valor del atributo, suele ser común utilizar la forma inglesa setXXXX() y getXXXX(),
respectivamente. En los ejemplos de los distintos capítulos, se usará una u otra indistintamente, prefiriéndose la
versión inglesa en los capítulos avanzados.

Valor de retorno
Los métodos pueden realizar una función y no devolver un valor, lo que se indica con la cláusula void, o pueden
comportarse como una función y devolver un valor primitivo o una referencia a un objeto. En este caso, se pone
Programación en Java 2

delante del nombre del método el tipo o clase del valor devuelto. En el caso del método dameGrupo(), el método
devuelve una referencia a un objeto de la clase Stri ng. Para devolver un valor dentro del método, se utiliza la
sentencia return. El método dameGrupo() se puede escribir:

public String dameGrupo(){


return grupo;

Autoreferencia thi s
Para referirse a los atributos del objeto desde un método del mismo, se puede hacer directamente con su nombre o
utilizando thi s. Esta palabra del lenguaje se utiliza, sobre todo, cuando existe ambigüedad entre nombres de parámetros
de un método y atributos del objeto (otros usos se explican más adelante). Por ejemplo, en el siguiente método

public void ponGrupo(String grupo. Horario horario) {


this.grupo = grupo;
this.horario = horario;

thi s funciona como una referencia especial, de forma que thi s. grupo se refiere al atributo grupo declarado en la
clase, para diferenciarlo de la variable grupo declarado como parámetro del método.

Sobrecarga
La única limitación en la elección del nombre de un método es que, en una clase, todos los métodos deben tener
diferente signatura (básicamente distinto nombre y parámetros). Esto permite que existan varios métodos con el
mismo nombre pero con diferentes parámetros. Por ejemplo, se podrían tener dos métodos de nombre ponGrupo( ).

public void ponGrupo(String grupo, Horario horario){


this.grupo = grupo;
this.horario = horario;

public void ponGrupo(Stríng grupo){


this.grupo = grupo;

Dependiendo de los valores de los argumentos con que se llame al método ponGrupo , se ejecutaría uno u otro de los
definidos.

2.4 CONSTRUCTORES
Al principio del capítulo se ha visto que para crear un objeto se usa la instrucción new seguida del nombre de la clase
y una pareja abre paréntesis - cierra paréntesis:

Alumno alumnol= new Alumno();

Esta operación invoca al constructor por defecto, que se proporciona automáticamente y tiene el mismo nombre
que la clase.
da fonna. Para
Lo habitual es que al escribir una clase se desee construir los objetos de la clase de una determina
acceso, el nombre de la clase,
se escribe uno o más constructores. Para definir un constructor, se pone el tipo de
de código, de la fonna:
parámetros que acepta, si lanza excepciones (opcional) y un cuerpo o bloque

acceso nombreClase (parámetros) throws excepciones {cuerpo }


los apellidos y el
Así, para la clase Alumno, se pueden proporcionar dos constructores: uno que recibe el nombre,
año de nacimiento; y otro que, además, aceptase el grupo y el horario. El código sería el siguiente:

class Alumno {
Alumno(String nombre. String apellidos. int año) {
this.nombre ·= nombre:
this.apellidos = apellidos:
this.añoDeNacimiento = año:

Alumno(String nombre. String apellidos. int añoDeNacimiento.


String grupo, Horario horario) {
this.nombre = nombre:
this.apellidos = apellidos:
this.añoDeNacimiento= añoDeNacimiento:
this.grupo = grupo:
this.horario = horario:

JI resto de la clase. igual

r por defecto ya no
Los constructores declarados sustituyen al proporcionado por defecto. Por tanto, el constructo
nar los valores apropiado s de acuerdo
se puede utilizar. Ahora, para construir cualquier alumno es necesario proporcio
con el constructor que se utilice:

Alumno al umnol= new Alumno( "Juan". "García". 1980):


Alumno alumno2= new Alumno("María". "López". 1981. "INF-01". Horario.TARDE):

Ahora sería ilegal el siguiente código:

Alumno alumno2= new Alumno(); // error: no hay construct or sin parámetros


con valores correc-
El uso de los constructores permite comprobar que los objetos se construyen apropiadamente
lanzar una excepción para no crear el objeto.
tos. Si los valores pasados al constructor no son apropiados, se puede
Para conocer más sobre el uso y manejo de excepciones, consulte el Capítulo 4.

class Alumno {
Alumno(String nombre, String apellidos. int año) throws Exception
// Si el nombre o los apellidos son cadenas null
// se lanza una excepción y el objeto no se crea
if (nombre== null 11 apellido s= null)
throw new Exception("Argumentos no válidos");

// Si el año es negativo
Programación en Java 2

// se lanza una excepción y el objeto no se crea


if (año < O)
throw new Exception("Año incorrecto");

this.nombre= nombre;
this.apellidos= apellidos:
thi s. añoDeNaci miento= año·:

// resto de la clase. igual

Autoreferencia thi s
En la construcción de objetos se puede utilizar un constructor ya definido desde otro constructor. Para ello
se utiliza
la referencia thi s () seguida de los parámetros del constructor que se desea invocar. Esta llamada sólo
se puede
realizar como primera sentencia de un método. De esta forma, los constructores de la clase se pueden escribir:

class Alumno {
Alumno(String nombre. String apellidos. int año) throws Exception {
// Si el nombre o los apellidos son cadenas null
// se lanza una excepción y el objeto no se crea
if (nombre== null 11 apellidos== null)
throw new Except ion ( "Argumentos no vá l idos" ) ;

// Si el año es negativo
// se lanza una excepción y el objeto no se crea
if (año< O)
throw new Exception("Año incorrecto");

this.nombre= nombre:
this.apellidos= apellidos:
this.añoDeNacimiento= año:

// constructor de la clase alumno con grupo y horario


// Se invoca al constructor anterior para comprobar y poner
// el nombre. apellidos y año de nacimiento
Alumno(String nombre. String apellidos. int añoDeNacimiento.
String grupo. Horario horario) throws Exception {
this(nombre. apellidos. añoDeNacimiento):

if (grupo== null)
throw new Exception("Grupo no especificado"):

this.grupo= grupo:
this.horario= horario:

// resto de la clase. igual


y objetos

ATRIBUTOS

!Ejercicio 2.1:
Definir una clase que represente a un coche. En la definición se debe incluir:

" el modelo,
• el color,
• si la pintura es metalizada o no,
" la matrícula,
" el tipo de coche, que puede ser MINI, UTIUTARIO, FAMIUAR o DEPORTNO
• el año de fabricación
" la modalidad del seguro, que puede ser a terceros o a todo riesgo

Planteamiento: Al diseñar una clase, hay que prestar especial atención a los atributos que se incluyen y sus
tipos. Para los atributos hay que elegir nombres significativos, por ejemplo, "modelo" es un buen nombre para
el atributo que representa el modelo del coche. Al elegir el tipo de un atributo, se debe pensar tanto en los
valores que puede tomar, como en las operaciones que se van a aplicar.
Para el modelo, el color y la matrícula, se elige el tipo Stri ng. Para determinar condiciones que se satisfa-
cen o no, se debe elegir un boo lean, como es el caso de si la pintura es metalizada o no.
Cuando un atributo puede tomar una serie de valores, lo más adecuado es utilizar un tipo enumerado,
eligiendo los nombres adecuados para los diferentes valores. De esta forma, para el tipo de coche se usa un
enumerado con los valores que sugiere el enunciado.
Para el año de fabricación, se usa un número entero. Evidentemente, valores negativos o muy grandes
podrían no ser legales, pero queda a cargo del programador comprobarlo.
Por último, para la modalidad de seguro, de nuevo es adecuado un enumerado, con los valores { A_TERCEROS,
A_TODO_RIESGO }.

Solución:
enum TipoDeCoche { MINI, UTILITARIO, FAMILIAR. DEPORTIVO}:

enum TipoDeSeguro { A_TERCEROS, A TODO RIESGO}:

public class Coche

String modelo:
String color: Los nombres de los atributos han de
boolean esMetalizado: «t~---~1 ser lo más significativos posible, pero
String matricula; no han de ser demasiado largos.
TipoDeCoche tipo:
int añoDeFabricación:
TipoDeSeguro seguro; 4~----1 Escoger adecuadamente los tipos de
los atributos no siempre es tarea fácil.

Comentario: Se podría pensar en utilizar un valor de tipo boo lean para la modalidad de seguro, por ejemplo,
boolean seguroATerceros. Se usaría el valor true cuando se disponga de un seguro a terceros, y false cuando
el seguro sea a todo riesgo. En general, no es una buena decisión usar los booleanos para atributos que toman
Programación en Java 2

dos valores. Por un lado, no queda claro el significado del valor false. Por otro, se pueden aplicar operaciones
que quizá no tengan sentido. Lo peor es que compromete la extensibilidad del programa: si se necesitara otra
modalidad de seguro habrá que modificar muchas líneas de código, mientras que añadir un valor nuevo a un
enumerado es sumamente sencillo.

Aviso: En este problema se ha abordado la elección de los atributos y sus tipos, sin tener en cuenta el tipo de
acceso de los mismos; esto se tratará en posteriores ejercicios.

Ejercicio 2.2:
Se desea imprimir el modelo y el color de un coche dado. Para ello, se pide escribir un método, que acepte un
objeto de la clase Coche. Si dicha referencia no es null, el método deberá imprimir el modelo y el color. Si es
null, el método no hará nada.

Planteamiento: No se dice el nombre del método, por lo que se elige uno significativo del problema, por
ejemplo, i mpri meCoche. Este método acepta una referencia de la clase Coche. Se usa una sentencia i f para
comprobar si la referencia es nu l l o contiene un objeto, en cuyo caso se imprime el modelo y el color.

Parámetros: La referencia a un objeto de la clase Coche.

Valor de retorno: El método no necesita devolver ningún valor de retomo por lo que se utiliza la cláusula voi d.

Solución:
public void imprimeCoche (Coche coche) {

if (coche != null) { Para acceder al valor de los atributos,


System.out.println("El coche " + coche.modelo+ •¿~----11 se pone el nombre del objeto, un
"es de color"+ coche.color): punto y el nombre del atributo.

Comentario: En el ejercicio siguiente se verá una forma más conveniente de escribir métodos que añaden
comportamiento a una clase.

Aviso: Es un error común que en ejecución se use un método o atributo de una referencia que está a nul l. Esto
provoca un error en tiempo de ejecución (RunTi meError) denominado Nul l Poi nterExcept ion, que normalmen-
te terminará la ejecución del programa. Es una buena práctica asegurarse de que al usar una referencia, no
contendrá el valor especial nu 11.

MÉTODOS

Ejercicio 2.3:
Añadir a la clase Coche del Ejercicio 2.1 un método de nombre imprimeCoche que imprima el modelo y el
color del coche.

Planteamiento: Cuando se invoca un método de un objeto, desde el mismo se puede acceder directamente a los
atributos de la clase. Por tanto, simplemente se han de imprimir los atributos modelo y color.

Parámetros: Ninguno. Al ser un método de la clase Coche, no necesita ningún valor como parámetro ya que se
dispone del modelo y color del coche como atributos.

Valor de retorno: El método no necesita devolver ningún valor de retomo por lo que se utiliza la cláusula voi d.
ses y objetos

Solución:
enum TipoDeCoche { MINI. UTILITARIO. FAMILIAR. DEPORTIVO};

enum TipoDeSeguro { A_TERCEROS. A_TODO_RIESGO }:

class Coche {

String modelo;
String color:
boolean esMetalizado:
String matricula;
El comportamiento de la clase
Ti poDeCoche tipo: "'l~,-------- --------11 Coche se recoge en su definición.
int añoDeFabricación:
TipoDeSeguro seguro:

public void imprimeCoche () { Los atributos del objeto dentro de la


System.out.println("El coche"+ modelo+ misma clase se usan directamente,
"es de color"+ color); sin cualificación.

Comentario: Este ejercicio es similar al anterior en cuanto a funcionalidad. Sin embargo, el comportamiento
de los objetos ha de recogerse siempre en la definición de la clase y no depender de funciones externas en la
medida de lo posible.

Ejercicio 2.4:
Escribir un programa que tenga una instancia de mi coche, que es un Rolls Royce de color dorado. El
programa ha de imprimir un mensaje que diga de qué modelo y color es mi coche.

Planteamiento: Los objetos han de usarse por medio de referencias. Por tanto, habrá que declarar una referen-
cia a la clase Coche. Además, hay que elegir un nombre significativo para la referencia. Como en este caso, se
guarda la información de mi coche, el nombre mi Coche (u otro similar) puede ser adecuado. Luego se inicializan
los atributos modelo y color. Para ello, se escribe el nombre de la referencia, un punto, y el nombre del atributo,
de la forma mi Coche.modelo. Y con el operador de asignación ("=") se le asigna el valor "Ro 11 s Royce". Lo
mismo aplica al atributo color. Por último, se imprimen esos valores; como la clase Coche ya dispone del
método imprimeCoche() (del ejercicio anterior), se puede invocar dicho método de la forma
miCoche.imprimeCoche().

Solución:
enum TipoDeCoche { MINI, UTILITARIO. FAMILIAR, DEPORTIVO};

enum TipoDeSeguro { A_TERCEROS. A_TODO_RIESGO };

class Coche {

String modelo:
String color:
boolean esMetalizado:
String matricula;
TipoDeCoche tipo;
int añoDeFabricación:
Programación en Java 2

TipoOeSeguro seguro:

public void imprimeCoche () {


System.out.println("El coche"+ modelo+
"es de color"+ color):

class pruebaCoche
public static void main (String args[J)
Coche miCoche= new Coche():

mi Coche.modelo= "Ro 11 s Royce":


miCoche.color= "dorado":

mi Coche. imprimeCoche(): •. J , - - - - - - - - - - - - - 1 1 Se invoca a cierto comportamiento


de los objetos de tipo Coche.

Comentario: La salida por pantalla que produce el programa es:

El coche Rolls Royce es de color dorado

Ejercicio 2.5:
Escriba una clase que represente un Semáforo, que podrá estar rojo, ámbar o verde. La clase tendrá un
atributo llamado color, inicialmente a rojo. También dispondrá de un atributo que determine si el semáforo
está parpadeando. Inicialmente, el semáforo no está parpadeando.

Planteamiento: Para describir el color del semáforo, se usa un tipo enumerado con los tres posibles colores
denominado Col orSemáforo. Después, se escribe la clase Semáforo, que tendrá dos atributos: el primero será el
color, de tipo ColorSemáforo; el segundo representará si el semáforo está parpadeando, para lo que se usa un
boolean.

Solución:
enum ColorSemáforo { ROJO, ÁMBAR, VERDE }: ....~ - - - - - - 1 1 Este enumerado representa el color
que puede tomar un semáforo.
public class Semáforo {
Se pueden inicializar los atributos de
ColorSemáforo color= ColorSernáforo.ROJO: 4
-4 ---~1 un objeto en la misma línea que se
boolean estáParpadeando = false: declaran.

Comentario: Los atributos de los objetos pueden tomar un valor inicial en la misma línea que se decla-
ran. No obstante, lo normal es que cada objeto tenga valores distintos, en cuyo caso se proporcionará
uno o más constructores para el valor inicial de los atributos de un objeto, como se verá en siguientes
ejercicios.

Aviso: Para los atributos que especifican condiciones que se cumplen o no, es muy habitual utilizar el tipo
boo lean. Los nombres de dichos atributos suelen ser adjetivos o, como en el ejemplo, una palabra formada por
el verbo "estar'' y la condición.
s y objetos

Escriba un programa que instancie un semáforo de la clase Semáforo del ejercicio anterior. El programa
escribirá por pantalla el color del semáforo. Luego pondrá el semáforo en ámbar y volverá a imprimir el
color.

Planteamiento: Se define una clase para el método ma in ( ), que se llamará PruebaSemá foro. En dicho método
ma in ( ), se declara un semáforo, llamado s1, por ejemplo. Se instancia mediante new un objeto de la clase
Semáforo y se asigna a sl. Ahora se puede imprimir su color, luego se cambia a ámbar y se vuelve a imprimir.

Solución:
enum ColorSemáforo { ROJO. ÁMBAR. VERDE};

class Semáforo {

ColorSemáforo color= ColorSemáforo.ROJO;


boolean estáParpadeando = false:

class PruebaSemáforo {

public static void main (String args[J) {


Semáforo sl;

sl = new Semáforo(): <111~---------11 Se crea el objeto semáforo con la


instrucción new.

System.out.println("Sl está " + sl.color);


Para poner un valor de un tipo
sl.color = ColorSemáforo.ÁMBAR;-<rr~-----11 enumerado, se escribe el nombre
System.out.println("Sl está " + sl.color): del tipo, un punto y el valor deseado.

Comentario: Hasta que no se genera el objeto con new, la referencia sl contiene el valor nul l (inicialización
por defecto de Java). Es muy común hacer ambas cosas en la misma línea, como se presenta a continuación:

Semáforo sl = new Semáforo();

Aviso: La forma utilizada en la solución para acceder a los atributos no se considera la más adecuada. Ya se
verá en otros ejercicios los métodos accesores y los derechos de acceso. En el siguiente capítulo se hará hinca-
pié en el tema.

Ejercicio 2.7:
Escriba un programa que disponga de una clase para representar las asignaturas de una carrera. Una asig-
natura tiene un nombre, un código numérico y el curso en el cual se imparte. Los valores iniciales han de
proporcionarse en el constructor. La, clase ha de tener métodos para obtener los valores de los atributos. El
programa ha de construir un objeto con los siguientes valores: nombre "Matemáticas", código 1017, curso l.
A continuación, el programa ha de imprimir los valores del objeto por pantalla.

Planteamiento: Se proporcionarán dos clases, una que representa a las asignaturas, llamada Asignatura, y
otra para el programa, llamada EjercicioAsignatura. La clase Asignatura dispondrá de un constructor que
acepta los valores para representar una asignatura: el nombre, el código y el curso. El nombre del constructor
Programación en Java 2

es el mismo de la clase, Asignatura en este caso. Los atributos serán privados y se disponen de métodos para
acceder a sus valores. Normalmente, estos métodos denominados accesores, se suelen llamar como el atributo,
anteponiendo el verbo dame o get. En la clase EjercicioAsignatura, habrá un método main( ), en el que se crea
la asignatura de matemáticas de primero y luego una sentencia para imprimir sus datos.

Solución:
class Asignatura {

prívate String nombre: Conviene que los atributos sean


private int código: "li_¿----------t, privados y accesibles con métodos
private int curso: explícitos.

public Asignatura (String nombre. int código, int curso).


this.nombre = nombre:
this.código = código:
this.curso = curso:

Métodos accesores a los atributos.


public String dameNombre(){ •~----~, Típicamente estos métodos se llaman
return nombre: dameAtri buto o getAtri buto.

public int dameCódigo(){


return código;

public int dameCurso(){


return curso:

class EjercicioAsignatura {

public static void main(String args[])


Asignatura a = new Asignatura ("Matemáticas". 1017, 1):

System.out.println("Asignatura " + a.dameNombre() +


" código " + a .dameCódigo() +
"del curso"+ a.dameCurso()):

Comentario: Se podría haber incluido el método main() en la clase Asignatura, con lo que con una sola clase
se hubiera resuelto el ejercicio. Es muy típico añadir un ma in ( ) a clases intermedias para probar o ejercitar la
clase, aunque dicho método ma i n( ) no forme parte del proyecto en el que participa la clase.
Respecto de los métodos accesores, nótese que no disponen de parámetros, lo que se indica con los parén-
tesis vacíos, como en dameNombre ( ) . Estos métodos devuelven el mismo tipo que el atributo al que acceden.

Aviso: La codificación de los métodos accesores es tremendamente trivial, lo que suscita la tentación de elimi-
narlos y poner los atributos como públicos. Se desaconseja esta práctica, pues el programador ha de responsa-
bilizarse de una clase y no debe permitir que se modifiquen los atributos de forma arbitraria.
'cio 2.8:
Definir una clase que represente un punto en un espacio bidimensional. La clase debe disponer de un cons-
tructor con las coordenadas del punto y métodos accesores a las coordenadas.

Planteamiento: En un espacio bidimensional, un punto se representa por un par ordenado de números reales.
Se deben elegir nombres representativos para los mismos, como x e y. El tipo más adecuado dependerá del tipo
de aplicación en que se usen estos objetos. Como el enunciado no dice nada, se usará doub le. Para asegurar la
consistencia de un objeto, es conveniente que los atributos sean privados y existan métodos públicos para
averiguar su valor. Estos métodos se llamarán dame X() y dameY(), sin parámetros, y con tipo de retomo igual al
del atributo que devuelven.

Solución:
public class Punto
Los atributos son privados, de forma
prívate double x . y;~ que sólo pueden modificarse
mediante métodos de la clase.

public Punto(double x. double y) { Nótese el uso de thi s para resolver


this.x = x: .J
la ambigüedad entre los nombres de
'
this.y = y; los parámetros y los atributos.

public double dameX(){


return x:

publ ; e double dameY() { <11~------1i Los métodos accesores proporcionan la


información adecuada sobre el objeto.
return y;

Comentario: Fíjese que se ha elegido doub le como tipo para las coordenadas. No obstante, ciertas aplicacio-
nes (por ejemplo, gráficos) podrían requerir int, o podría ser suficiente float.

Aviso: Se ha elegido representar el punto en coordenadas cartesianas. Se podría representar en polares, lo que
supondría tener que programar las conversiones entre los diferentes sistemas de representación.

Ejercicio 2.9:
Escriba un programa que instancie cuatro puntos: el primero situado en el origen, el segundo situado en
(5, 3), el tercero en (2, -1) y para el cuarto como punto medio entre el segundo y el tercero.

Planteamiento: Los tres primeros puntos se crean con los valores literales que nos proporciona el enunciado.
Para el último, se calculan sus coordenadas como las medias entre las respectivas coordenadas del segundo y
tercer puntos.

Solución:
public static void main (String args[J) {
Punto pl = new Punto (O. O): // origen de coordenadas

Punto p2 = new Punto (5. 3):


Punto p3 = new Punto (2. -1):
Programación en Java 2

Punto p4 = new Punto ((p2.dameX() + p3.dameX())/2,


(p2.dameY() + p3.dameY())/2);

Comentario: Los tres primeros puntos se crean con los valores literales que nos indica el enunciado. Para el
cuarto punto, se usan los métodos accesores de los puntos, obteniendo las coordenadas de los puntos segundo
y tercero, haciendo luego la semisuma.
Para crear objetos, se usa la instrucción new seguida del nombre de la clase y después, entre paréntesis, los
parámetros para el constructor de la clase.

Ejercicio 2.10:
Añada a la clase Punto un constructor sin parámetros que permita construir puntos en el origen de coordenadas.

Planteamiento: Se pide que los valores de las coordenadas sean (0, 0). Se pueden inicializar directamente,
pero es más conveniente invocar al otro constructor con los argumentos a O. De esta forma, se dispone de un
solo constructor que realiza el código de inicialización. Para invocar a otro constructor, se utiliza el nombre
especial thi s, seguido de los parámetros que espera ese constructor. En este caso, se escribe thi s (O.O). Esta
invocación ha de aparecer como la primera sentencia del cuerpo del constructor.

Solución:
// sólo se incluye el constructor. el resto del código como
// el ejercicio anterior
public Punto() {
thi 5 ( o. o) ; - . . A - - - - i i Se invoca al constructor anterior con
los valores deseados.

Comentario: Es muy adecuado tener diferentes constructores cuando se desea que el objeto tenga valores
iniciales tomados de diferente forma.

Aviso: Cuando los diferentes constructores tienen código común, es conveniente que unos se llamen a otros, si
es posible, en lugar de repetir código.

Ejercicio 2.11:
Añada un método a la clase Punto que calcule la distancia a otro punto.

Planteamiento: El método debe recibir como parámetro el punto al cual se calcula la distancia. Se aplica la
fórmula de la distancia euclídea entre dos puntos con ayuda de la clase Math. En dos variables auxiliares se
almacenan las diferencias entre las coordenadas de los puntos.

Parámetros: El punto al cual se calcula la distancia, es decir, un objeto de la clase Punto.

Devuelve: Un doub le con el valor de la distancia al punto pasado como parámetro.

Solución:
// sólo el método distancia
public double distancia (Punto p)
double diffX = x - p.x;
double diffY = y - p.y;

return Math.sqrt (diffX * diffX + diffY * diffY); 4(---1[ d = ✓ (a. -b.}2 +(ay -by}2
l
s y objetos

Comentario: Para elevar un número al cuadrado, se podría haber optado por la función pow, escribiendo
alternativamente:

return Math.sqrt (Math.pow (diffX. 2) + Math.pow (diffY. 2)):

Aviso: El método distancia puede fallar si se le pasa un punto a nul l. En efecto, si p es nul 1, no se puede
acceder a los atributos.

Modificar el método distancia del ejercicio anterior para que lance una excepción si el punto que se le pasa
es nu 11. La, excepción deberá contener un mensaje descriptivo del problema.

Planteamiento: Se debe modificar la cabecera del método distancia para declarar que ahora va a lanzar
excepciones. Para ello, después de los parámetros se añade la palabra reservada throws seguida del tipo de
excepción que se va a lanzar. En este caso, se usa Exception. Con un if se comprueba si la referencia p
contiene el valor nu 11, en cuyo caso se lanza una excepción. En caso contrario, p contiene un objeto y puede
accederse a sus atributos.

Parámetros: El punto al cual se calcula la distancia, es decir, un objeto de la clase Punto.

Devuelve: Un doub le con la distancia al punto pasado como parámetro.

Solución:
!! sólo el método distancia
public double distancia (Punto p) throws Exception {
if(p == null) + - - - - - - - - - - - - - - - - t i El método distancia comprueba
que su(s) argumento(s) son correctos.
throw new Exception("p no puede valer null"):

double diffX = x - p.x:


double diffY = y - p.y:

return Math.sqrt(diffX * diffX + diffY * diffY):

Comentario: Es muy recomendable que los métodos comprueben primero los valores que se les pasan y, si no
están en un rango aceptable, se lance una excepción, indicando la naturaleza del problema. A la larga, esto facilita
tanto el descubrimiento y diagnosis de errores en programas grandes, como el mantenimiento del programa.

. Ejercicio 2.13:
Escriba un programa que cree un punto en (4, 3) e imprima la distancia del punto al origen de coordenadas.

Planteamiento: Para calcular la distancia de un punto al origen, se aplica el teorema de Pitágoras, resultando
,J
d = x 2 - y 2 • No obstante, dado que se dispone del método distancia a otro punto, se puede calcular la distan-
cia al punto origen de coordenadas.

Escribe: Se escribe el mensaje "Distancia de p al origen" seguido del valor.

Solución:
public class distanciaAlOrigen

public static void main (String args[]) {


Programación en Java 2

!/ origen de coordenadas
Punto origen= new Punto (O. O): Se utiliza el método distancia a otro
- punto para hacer el cálculo~

Punto p = new Punto (4. 3):


,,
System.out.println("Distancia de pal origen"+ p.distancia(origen)):

Aviso: Es conveniente estudiar el API de Java y las bibliotecas disponibles para evitar escribir varias veces el
mismo código.

Ejercicio 2.14:
Escriba un método llamado sumaTotal que, dada una lista arbitraria de números enteros, devuelva la suma
de todos ellos. Además, escriba un programa que pruebe dicho método, calculando la suma de las secuencias
{3, 5, 2, 4, 6), la secuencia {2, 10, -1, 2), la secuencia {JO} y la secuencia{}. El programa imprimirá el valor
de dichas sumas.

Planteamiento: El método suma Total deberá aceptar un número variable de parámetros, lo que se indica con
la notación " ... ". Entonces, deberá ir recorriendo todos los parámetros e ir acumulando la suma de cada uno de
ellos. Para ello, se guarda en una variable llamada suma el resultado parcial.
El valor inicial de la variable suma será O. Para sumar los valores que se reciben como parámetro, se usa un
bucle for sobre la lista de valores recibidos en el método. Por último, el método devolverá el valor almacenado
en suma.

Parámetros: La lista de números enteros, denotado como i nt ·- números.

Valor de retorno: El valor de la suma acumulada. Como la suma de enteros es un entero, el valor de retomo
será del tipo i nt.

Solución:
public class suma
La notación ... significa que se espera un
public static int sumaTotal (int ... números) {~, - - - - ~ 1 número arbitrario (O o más) de parámetros.
1

int suma= O;
Con un bucle far se recorren los
for Cint num: números) {• ~-------------1 1 p:~rárnet1·os1~onlosque1sellanna~tl miét0<fo. 11
suma+= num;

return suma:

public static void main (String args[J) {


int x;

x = sumaTotal (3. 5. 2. 4. 6):


System.out.println("Primera suma="+ x):

x = sumaTotal (2. 10. -1. 2):


System.out.println("Segunda suma = " + x):
y objetos

x = sumaTotal (10):
System.out.println("Tercera suma = " + x):

x = sumaTotal ();
System.out.println("Cuarta suma="+ x):

Comentario: Este programa imprimirá por pantalla lo siguiente:

Primera suma= 20
Segunda suma= 13
Tercera suma= 10
Cuarta suma= O

Hay que resaltar la cuarta suma: cuando se llama al método s urna Total , se pasa una lista (array, véase Capítulo 6)
vacía, con O elementos. El cuerpo del bucle for, por tanto, no se llega a ejecutar ninguna vez, con lo que la
variable suma no se modifica.

Aviso: Hay que tener especial cuidado con los métodos con un número variable de argumentos cuando la lista
está vacía. Por otro lado, si se desea disponer de un número variable de argumentos, la variable para ellos debe
ser la última de los parámetros que acepta el método.

Escriba un método de nombre mediaAritmetica que, dada una lista de números reales, calcule y devuelva su
media aritmética. Escriba también un programa que, utilizando dicho método, determine la media de los
números -JO, 5, O, 7, 20. "

Planteamiento: La media aritmética de una serie de números se calcula como


~>-
í=I ' •
n

Por tanto, hay que calcular la suma de todos los números, de forma similar al ejercicio anterior: para ello se
recorre la lista de los números y se determina su suma. Posteriormente, se divide entre el número de valores en
la lista, información que se puede obtener del atributo l ength de la secuencia.

Parámetros: La lista de valores, denotado como double ... números.

Valor de retorno: La media aritmética de valores doub le será un valor del tipo doub le.

Solución:
public class mediaAritmetica

public static double mediaAritmetica (double ... números) {


double suma= O.O;

for (double num: números)


suma+= num;

1 El atributo números . 1ength contiene la


return suma / números.length;,~------111 cantidad de parámetros recibidos en números.
Programación en Java 2

[]) {
public stat ic void main (String args
double media:
7. 20):
media= mediaAritmetica (-10. 5. O.
media es = " +media):
System.out.println("La

por números. length. ¿Qué


med iaA ritm etica divide la suma de todos los valores
Com enta rio: El mét odo divide por O. Ahora bien, como el
una lista de parámetros vacía? En este caso, se
ocurre cuan do se pasa porque suma contiene el valor
en Java se asigna el valor NaN (Not a Number). Esto es
resultad o es un doub le, ltando en la división O.O/O que es
El buc le for no se ejecuta, pues la lista es vacía, resu
O.O de la inic ializ ación. obtener +oo, - 00 o NaN, según el
inad a. (Not a: al dividir por O.O con reales en Java, también se puede
indeterm
cero, respectivamente.)
numerador sea positivo, negativo o

Ejercicio 2.16: il sigue movimientos rectilíneos


la dist anc ia reco rrid a por un móvil. Se sabe que el móv ancia
Se dese a calc ular serie de pun tos y determine la dist
e una seri e de pun tos. Se pide escribir un método que reciba una ia reco rrid a entre
entr calcule la distanc
rrid a por el móv il. Para pro bar el método, escriba un programa que rre cua ndo se llam a
reco también qué ocu
tos (0,0 ), (2,4), (4,5), (4, 6), (3,4 ) y (0,0) (vuelta al origen). Pruebe
los pun
al método con un solo punto.
define una clase llamada Trayectori
a, que contendrá el método pedido
Plan team ient o: Para el prog ram a, se método main() donde se
se llam ará reco rrid o. La clase Trayectoria contendrá un
en el enu ncia do, que odo recorrí do ( ) con dichos puntos,
ran prim ero los pun tos que pide el enunciado y luego se llama al mét
gene
por último, sin ningún punto.
posteriormente con un solo punto y, tipo se puede especificar con la
arbitrario de argumentos del mismo
Cuando un método recibe un número tos. Con un bucle for se pueden
ifica que se espera un número variable de argumen
nota ción " ... ", que sign como si fuera un array, consulte el
tos de la secu encia (la secuencia se puede tratar
recorrer todo s los pun onces se calcula la distancia de un
ítulo 6). Para calc ular el reco rrid o, se considera un punto cada vez. Ent
Cap rrido total.
o a una variable que acumula el reco
punto al anterior, añadiendo el resultad
ia de puntos, denotado como Punto
. . . puntos.
Parámetros: Una secuencia arbitrar
n, como la distancia será un
de reto rno : La sum a de las dist anci as entre los puntos considerados en orde
Valor
tipo doub le.
valor real, el valor devuelto será del

Solución:
class Trayectoria {
to ... puntos) {
public stat ic double recorrido (Pun
double dist = O.O:
Como primer punto se pone el que
Punto anterior = puntos [ oJ : <11Á_ _ _ _ _ _ _11
está en la posición O.

for (Punto actual : puntos) {

ant erio r= actual: t


dist += actual .distancia(anterior): Se calcula la distancia desde el punto
actual al anterior y se acumula en
- - - - - - - - - 1 1 di st. Luego se actualiza el anterior
punto con el valor del actual.
return dist ;
Clases y objetos

public static void main (String args[J)


Punto pl. p2. p3. p4. p5:

pl = new Punto (O. O):


p2 = new Punto (2. 4):
p3 = new Punto (4. 5):
p4 = new Punto (4. 6):
p5 = new Punto (3. 4):

System. out. printl n( "Se ha recorrí do " +


recorrido Cpl. p2. p3. p4. p5. pl));

System.out.println("Se ha recorrido"+ recorrido (pl)):

System. out. pri nt1n( "Se ha recorrí do " + recorrí do () ) :

Comentario: Hay varios puntos que resaltar en este ejercicio; nótese en primer lugar el uso de recon-:tQO
primer caso: el punto pl se pasa dos veces, como origen y final de la trayectoria. Por otro lado, a1 eieé~tafJi!Ste
programa, se imprime lo siguiente:

Se ha recorrido 14.94427190999916
Se ha recorrido O.O
Exception in thread "main" java. lang.ArrayindexOutüfBoundsException: O
at Trayectoria.recorrido(Trayectoria.java:7)
at Trayectoria.main(Trayectoria.java:30)

La primera línea corresponde al recorrido entre los puntos. La segunda, corresponde a la llamada.a recorrí do
con un solo punto. Es conveniente considerar si es correcto que al "recorrer" un solo punto se devuelva un
cero, pues con un solo punto no ha habido trayectoria real. La tercera línea es inaceptable en la mayoría de los
casos: se lanza una excepción (ArrayindexOutüfBoundsException) por intentar acceder a1 primer elemento de
la secuencia en la inicialización de (Punto anterior = puntos[O];) cuando en realidad no hay ningún punto.
Se podría haber protegido el método comprobando el número de parámetros pasados (puntos.si ze),. como en
el siguiente código:

class Trayectoria {

public static double recorrido2 (Punto ... puntos) throws Exception {


double dist = O.O:
·f e
1 pun t os· l eng th = O) < 1 1 , - - - - - - - - - - - 1 i que
Á En el método recorrí do2 comprueba
se le pasan parámetros.
throw new Exception("No hay trayectoria");

Punto anterior= puntos[OJ:

for (Punto actual : puntos)


dist += actual.distancia (anterior):
anterior= actual:
Programación en Java 2

return dist;

public static void main (String args[J) throws Exceptíon


Punto pl. p2. p3. p4. p5; -~
El método ma í n delega excepciones,
pl = new Punto (O. O): dado que se invoca al método
p2 = new Punto (2. 4): recorrí do2 que las lanza.
Punto
Consulte el Capítulo 4.
p3 = new (4. 5);
p4 = new Punto (4. 6):
p5 = new Punto (3. 4):
pl));
System.out.println("Se ha recorr ido"+ recorrido2 (pl. p2. p3, p4. p5.

System.out.println("Se ha recorrido " + recorrido2 (pl));

System.out.println("Se ha recorrido " + recorrido2 ());

De esta forma, se sigue lanzando la excepción en el método ma in (


), pero la responsabilidad ahora recae en el
diferen cia es sutil, pero MUY importante, pues cada
uso del método, no en la codificación del mismo. Esta
efecto, ahora al ejecutar el programa con este nuevo
programador debe responsabilizarse de su código. En
método,

Se ha recorrido 14.94427190999916
Se ha recorrido O.O
Exception in thread "main" java.lang.Exception: No hay trayec toria
at Trayectoria.recorrido2(Trayectoria.java:21)
at Trayectoria.main(Trayectoria.java:46)

la excepción que se lanza es de tipo Exception, con el mensaje "No


hay trayec toria", en contraposición del
caso anterior que se lanzaba la excepción Arraylndexüutü fBound sExcep tion. En el primer caso, hay un error
abilidad está clara.
de uso, en el segundo un error de codificación: la respons

ningún punto al método o que alguno sea


Aviso: En el método recorrido no se comprueba que no se pasen
al método . Adicionalmente, si se pasa un solo
nu 11. Tampoco se comprueba que no se pase ningún punto
. El caso de qué un punto fuese nul 1, se podría
punto, devuelve O, lo que podría no tener mucho sentido
la corresp ondient e excepc ión, como se muestra a
codificar el bucle for para detectar el caso y lanzar
continuación:

for (Punto actual : puntos) {


if (actual == null)
throw new Excepti on ( "Hay un punto nulo" ) :

dist += actual.distancia(anterior):
anterio r= actual;
Clases y objetos

Por otra parte, aunque se ha puesto en el método ma i n( ) que este delega Exception, esto nunca debería ocurrir,
sólo se pone para simplificar el ejercicio, ya que no se tratan excepciones con todo detalle. Sobre el tratamiento
de excepciones de forma apropiada consulte el Capítulo 4.

Ejercicio 2.17:
Escriba la clase Punto con dos métodos llamados distancia. Uno de ellos calcula la distancia a otro punto y
el otro calcula la distancia al origen.

Planteamiento: La clase Punto, como en ejercicios anteriores, tendrá dos atributos para las coordenadas x e y.
Para los métodos distancia, se proporciona uno que admite como parámetro un Punto y devuelve un doub le
con la distancia a dicho punto; asimismo, se escribirá otro método también llamado distancia, pero sin
parámetros, que calcule la distancia al origen.

Parámetros: Uno de los métodos distancia aceptará una referencia a la clase Punto y el otro no dispone de
parámetros.

Valor de retorno: Como la distancia entre dos puntos será un número real, ambos métodos devolverán un
valor del tipo doub le.

Solución:
import java.lang.Math:

public class Punto {

prívate double x. y;

public Punto (double x. double y) {


this.x = x:
this.y = y:

public double dameX(){


return x;

public double dameY(){


return y;

public double distancia()


return Math.sqrt(x * x +y* y);

public double distancia(Punto p) -----11 Sobrecarga del método distancia.


double diffX = x - p.x;
double diffY = y - p.y;

return Math.sqrt(diffX * diffX + diffY * diffY);


Programación en Java 2

Comentario: Cuando se encuentran varios métodos con el mismo nombre, pero que aceptan diferentes
parámetros, bien por diferente cantidad de parámetros o bien por tener los parámetros diferente tipo, se dice
que el método está sobrecargado. Para la sobrecarga no se tienen en cuenta ni las diferencias de acceso, ni el
tipo devuelto ni las excepciones lanzadas. La sobrecarga de métodos es útil cuando se desean hacer cosas
similares con diferentes parámetros.

Aviso: Usar la sobrecarga en exceso dificulta la legibilidad del programa y puede comprometer, por tanto, su
mantenimiento.

Ejercicio 2.18:
Escriba una clase que represente un reloj que señale la hora, el minuto y el segundo. La clase dispondrá de
dos constructores, uno sin parámetros que pone el reloj a 0:0:0 y otro al que se le pasa la hora, los minutos
y los segundos.
Se proporcionarán los siguientes métodos:

" Uno que da la hora, los minutos y los segundos, separados por el carácter ": ", en una cadena.
" Otro que también da la hora pero en formato 24 horas (como el anterior) o en formato 12, en cuyo caso
debe distinguir entre "am" (para las horas de Oa 11) o "pm" (para las horas de 12 a 23 ), también en una
cadena.
.. Un método para poner el reloj en hora. Se le pasa la hora y los minutos, poniendo los segundos a O.
., Un método para poner el reloj en hora al que, además, se le pasan los segundos.

Planteamiento: Existen muchos problemas en los que la representación de la información admite diversos
formatos (por ejemplo, coordenadas polares o cartesianas en el ejercicio de la clase Punto). En general, lo más
adecuado es trabajar en un formato interno, que sea cómodo y fácil de programar y sólo las funciones que
toman datos o los devuelven se preocupan del formato. En este caso, hay que elegir entre representar un reloj
con las horas de O a 23 o bien de Oa 12 y seleccionar "am" o "pm". El formato de O a 23 es más cómodo, pues
no hay que guardar otro atributo con el uso horario.
Los atributos serán, por tanto, tres enteros, para la hora, los minutos y los segundos. No obstante habrá que
comprobar que los valores son correctos, tanto en el constructor como en los métodos que ponen la hora. Si son
incorrectos, se lanza una excepción descriptiva del problema. Como hay que hacer la comprobación en varios
sitios, es conveniente escribir un método que lo haga. A este método se le llamará compruebaHora.
Existirán dos métodos que dan la hora, que se llamarán dameHora( ); el primero, sin parámetros, la devol-
verá como un objeto Stri ng. El segundo necesita un parámetro para determinar el formato de la hora. Para
ello, se proporciona un enumerado con los dos posibles formatos, el de 24 horas y el de 12. En el caso de que
el formato sea de 12 horas y la hora sea de tarde (entre 12 y 23) habrá que restar 12 al valor de la hora y añadir
la cadena "pm". En el mismo formato, pero con la hora entre O y 11 habrá que poner "am".
Por último, existen dos métodos para poner la hora, uno que toma dos parámetros, para la hora y los
minutos, y otro que toma tres parámetros, la hora, los minutos y los segundos.

Parámetros: La hora, los minutos y los segundos serán representados en todos los casos con valores del tipo
i nt. No obstante, se comprobarán los rangos adecuados. Se proporciona un enumerado para distinguir los
formatos de 24 horas y el de 12 horas.

Valor de retomo: El valor devuelto por los métodos dameHora () será un objeto de la clase Stri ng con la hora
en el formato adecuado.

Solución:
· Horario { H24 • H12 } ; .,o¡¡-:----11 Enumerado adicional para determinar
enum T1po
el formato de la hora.

class Reloj {
Clases y objetos

private int hora. minutos. segundos:

private void compruebaHora (int hora. int minutos. int segundos)~-------....


throws Exception {
if (hora< O 11 hora> 23)
throw new Exception ("Error en hora"): Método auxiliar que comprueba que
if C minutos< O 11 minutos> 59) los valores de hool, ml~ y
segundos son corr~, o lwa una
throw new Exception ("Error en minutos"): excepción.
if C segundos< O 11 segundos> 59)
throw new Exception ("Error en segundos"):

public Reloj()
hora= minutos= segundos= O:

public Reloj(int hora. int minutos. int segundos) throws Exception {


compruebaHora(hora, minutos. segundos): < 1 t - - - - - - - - - - - 1 i

this.hora = hora:
this.minutos = minutos:
this.segundos = segundos:

public Reloj(int hora. int minutos) throws Exception


this(hora. minutos, O):

String dameHora()
return hora+":"+ minutos+":"+ segundos;

String dameHora(TipoHorario tipo)


String res:

if (tipo== TipoHorario.Hl2 && hora>= 12


res=""+ (hora-12):
else
res=""+ hora:

res += ":" + minutos + ":" + segundo + ( (hora < 12) ? "am" "pm" ) :

return res:

void ponHora(int hora. int minutos) throws Exception {


Este método sobracargado delega en
ponHora(hora. minutos. O); ~¿--------------,1 suhomónimo,sinrepetircódigo.

void ponHora (int hora. int minutos. int segundos) throws Exception {
Programación en Java 2

compruebaHora(hora. minutos. segundos):~~..-..-- ---------

this.hora = hora:
this.minutos = minutos; De nuevo se invoca a
this.segundos = segundos: compruebaHora para determinar si
los valores son correctos. Si no lo
son la hora no se modifica.
}

Comentario: En este enunciado, existen muchos puntos abiertos. Por ejemplo, los nombres de los métodos, el
tipo de representación de la información, etc. Generalmente, el punto más delicado es elegir un buen modelo
de datos, que permita programar de forma cómoda, sencilla y legible.
Respecto del enumerado TipoHorario, los valores que contienen no pueden ser { 24H. 12H }, como podría
parecer natural, puesto que los identificadores de Java no pueden empezar por un dígito. Por ello, se antepone
la hache delante.

Aviso: Nótese que el constructor sin parámetros NO delega en el otro constructor mediante thi s (O. O. O).
Esto es así para evitar lanzar excepciones (o capturarlas como se verá en ejercicios posteriores del Capítulo 4).
En este caso, se justifica el evitar usar el thi s por la sencillez del código que resulta. Hay que tener en cuenta
que no tiene sentido que el constructor sin parámetros se declare que lanza excepciones, pues siempre debe ser
correcto o no existir.
Por otro lado, el método compruebaHora es privado. Aunque los derechos de acceso se tratan en el siguiente
capítulo, baste decir que de esta forma la clase Re l oj contiene los métodos tal como indica el enunciado, pues
compruebaHora no puede invocarse desde fuera de la clase.

Ejercicio 2.19:
Añada al ejercicio anterior un método para poner la hora especificando si es AM o es PM.

Planteamiento: Una vez más se sobrecarga el método ponHora( ), en este caso se le añade un parámetro para
determinar si la hora es AM o PM. En principio, se podría pensar en pasar una Stri ng, con los valores "am" o
"pm". Pero ello implicaría comprobar que no se ponga otra cadena o un null. Es mucho mejor añadir un
enumerado con los valores { AM. PM }, llamado TurnoHorario.
Al añadir el turno horario quiere decir que las horas se pasan en formato de 12 horas. Hay que comprobar,
entonces, que el rango de la hora es de O a 11. Se puede optar por modificar compruebaHora, que comprobaba
la hora en formato 24 horas o bien en añadir una línea de comprobación adicional. La solución mejor depen-
derá del uso posterior que se quiera dar a compruebaHora. En este caso, se añade una línea adicional.

Parámetros: Además de la hora, los minutos y los segundos como i nt, el turno de horario, de tipo TurnoHora ri o.

Valor de retomo: El método no necesita devolver ningún valor de retorno por lo que se utiliza la cláusula voi d.

Solución:
// Sólo se incluye el enumerado con el turno y el nuevo método ponHora
enum TurnoHorario { AM. PM };

void ponHora(int hora. int minutos. int segundos. TurnoHorario t) throws Exception {

compruebaHora Chora. minutos. segundos):

if Chora> 11 ){
throw new Exception ("Hora incorrecta en horario de 12 horas");
Clases y objetos

if ( t == TurnoHorario.PM ){
hora += 12; ---------------11 Se pasa a formato

this.hora = hora;
this.minutos = minutos;
this.segundos = segundos;

Comentario: La hora se almacena en formato 24 horas, como se explicó en el ejercicio anterior. ·'Pt-l!lf.~llfü .
hora es PM, se suman 12 horas al valor de hora recibido.
También se podría haber modificado el método compruebaHora (), quedando un código
nuevo comprueba Hora () y ponHora () quedarían de la siguiente forma:

private void compruebaHora (int hora, int minutos. int segundos. TipoHorario t)
throws Exception {
if ( t = TipoHorario.H24){
if (hora< O 11 hora> 23 ){
throw new Exception ("Error en hora formato 24H");

if ( t == TipoHorario.Hl2){+-------
if Chora< O 11 hora> 11 ){
throw new Exception ( "Error en hora formato 12H");

if (minutos< O 11 minutos> 59 ){
throw new Exception ("Error en minutos");

if (segundos< O 11 segundos> 59 ){
throw new Exception ("Error en segundos");

void ponHora (int hora. int minutos. int segundos. TurnoHorario t)


throws Exception {
compruebaHora (hora. minutos. segundos. TipoHorario.Hl2);

; f ( t = TurnoHorari O • PM ){ ,, Sigue siendo necesario pasar al


+ - - - - - - - 1 i formato interno del reloj de 24 horas.
hora += 12;

this.hora = hora;
this.minutos = minutos;
this.segundos = segundos;
Programación en Java 2

Aviso: Evidentemente, si se introduce esta segunda codificación en la clase Reloj, habrá que modificar todas
las invocaciones del método compruebaHora, especificándose si el formato de reloj es de 24 horas o 12 horas,
según corresponda.

Ejercicio 2.20:
Se define la serie de Fibonacci como 1, 1, 2, 3, 5, 8, 13, 21, ... donde los dos primeros términos son 1 y cada
término restante es la suma de los dos anteriores. Formalmente, considerando el O como índice del primer
elemento, el término a; se calcula como:

i= o, i =1
i>l

Se pide escribir dos métodos que calculen el término i-ésimo de la serie de Fibonacci, uno de ellos de forma
recursiva y otro deforma iterativa.

Planteamiento: Se llamará fi bR al método recursivo y fi bI al método iterativo. Ambos tomarán como parámetro
el índice del término que se desea calcular. Fíjese que el primer elemento se denota como a0, empezando con el
índice O. También ambos lanzarán una excepción cuando el índice sea negativo (fuera de rango).
Para la versión recursiva, se escribe la función prácticamente como se define formalmente: con un i f se deter-
mina si el índice es Oo 1, en cuyo caso se devuelve 1; en caso contrario, se devuelve la suma computando recursivamente
(esto es, llamando a fibR) el valor de los anteriores términos. Esto se escribe como fibR(i-1) + fibR(i-2).
Para la versión iterativa, hay que idear alguna forma de ir computando los términos hasta llegar al deseado.
Para ello, se almacenarán los valores inmediatamente anteriores en dos variables, llamadas último y penú l ti -
mo. La suma de estos valores se almacenará en otra variable, llamada res. Con un bucle for se calculan los
términos hasta el i-ésimo, de forma que en cada iteración, res se computa como úl timo + penú l timo y luego
se actualizan sus valores. Las tres variables se inicializan a 1 y el bucle no se ejecutará para los dos primeros
términos.

Parámetros: El índice del término a calcular, como un valor del tipo i nt.

Valor de retomo: El cómputo de la función de Fibonacci, como i nt. Podría también devolverse un valor long
si se desea poder calcular mayores valores de la función de Fibonacci.

Solución:
public int fibR(int i) throws Exception {
if(i<O){
throw new Exception ("Índice negativo"):

if e ; == o 11 i==1 ) { ...------------- ----1! Condición de convergencia: las llamadas


recursivas tenninan alguna vez.
return 1:
}else{
ada recursiva. Hay que asegurarse de que los valores
return fibR(i - 1) + fibR(i - 2 ) : - - - - se pasan convergen a la condición de parada.

public int fibI(int i) throws Exception {


if Ci < O){
throw new Exception ("Índice negativo"):
Clases y objetos

int último= l. penúltimo= l. res= 1:


(F"=====-
for (; nt n = 1: n < i : n++) {..,~----ii El bucle no se ejecuta para
los términos Oy 1.
res= último+ penúltimo:

penúltimo= último:
último = res : 4~ - - - - - - i i Hay que tener cuidado en el orden
de actualización.

return res:

Comentario: No siempre será fácil encontrar una versión iterativa de un algoritmo o


recursivamente. Si es posible, como en este caso de Fibonacci, el algoritmo se de11011llina tieci~iVP

Aviso: Las funciones recursivas tienen una codificación mucho más legible y elegante de
iterativa. Por tanto, la versión recursiva es mucho más fácil de mantener y de depurar que la
obstante, la implementación recursiva consume más recursos y generalmente tarda más en
versión iterativa. Cuál debe elegirse dependerá sobremanera de los requisitos de ejecución

Ejercicio 2.21:
La función de Ackerman se define para valores enteros no negativos n y m como:

A(m,n) = {:;~-1,1) : :;m > O


A(m-1,A(m,n-I)) n>0,m>0

Se pide codificar un método que calcule la función de Ackerman y un programa que imprima los valo~s de
Ackerman (0,0), Ackerman(2,2) y Ackerman (6,6).

Planteamiento: La definición de la función de Ackerman es recursiva, por lo que se implementa un método


recursivo, que se llamará Ackerman, que acepte dos enteros y calcule la función. Como Ackeroian se. d,efine
para números no negativos, se lanzará una excepción si alguno de los dos parámetros es menor que O. Luego,
según los valores de my n, se calcula el valor según la definición.
Para obtener los valores de Ackerman que pide el enunciado, se escribe un ma i n( ) en la misma clase, que
calcula e imprime por pantalla los resultados.

Parámetros: Dos variables para los valores de my n de tipo i nt.

Valor de retomo: Un entero (i nt) con el valor de la función de Ackerman. Podría también devolvet111eun valor
1ong si se desea poder calcular mayores valores de la función de Ackerman.

Solución:
public class Ackerman

public static int Ackerman (int m. int n) throws Exception {


if ( n < O 11 m <O){
throw new Exception ("Parámetros no válidos.");

if ( m = O ){
Programación en Java 2

return n + l;

Cuando el cuerpo del i f contiene


if C n == O ) {~~---- ------- 11 un return, muchas veces no se
pone e1se para los otros casos.
return Ackerman Cm - l. 1):

return Ackerman Cm - l. Ackerman Cm. n - 1)):

public static void main(String[J args) throws Exceptíon {


System.out.printlnC"AckermanC0.0)= " + AckermanC0.0));
System.out.printlnC"AckermanC2.2)= "+ AckermanC2.2)):
System.out.printlnC"AckermanC3.3)=" + AckermanC3.3));
System.out.printlnC"AckermanC6.6)= " + AckermanC6.6)):

Comentario: La función de Ackerman es una función recursiva no primitiva, esto es, no es posible codificar
un método iterativo que la implemente. El inconveniente que tiene Ackerman es que consume muchos recur-
sos, aunque el valor de la función no sea muy elevado. Como ejercicio, se podría calcular el número de veces
que se llama al método Ackerman. De hecho, la salida de este programa es:

Ackerman(0,0)= 1
Ackerman(2.2)= 7
Ackerman(3.3)= 61
Exception in thread "main" java. lang.StackOverflowError
at Ackerman.Ackerman(Ackerman.java:20)
at Ackerman.Ackerman(Ackerman.java:21)
at Ackerman.Ackerman(Ackerman.java:21)
at Ackerman.Ackerman(Ackerman.java:21)
at Ackerman.Ackerman(Ackerman.java:21)
at Ackerman.Ackerman(Ackerman.java:21)
at Ackerman.Ackerman(Ackerman.java:21)

donde la última línea se repite un número muy grande de veces, que depende de la configuración del sistema,
la cantidad de memoria instalada, etc.

Aviso: Existen algunos mecanismos, como la Programación Dinámica, para tratar algunos de estos problemas,
pero el tratamiento de los mismos y su justificación excede del propósito de este libro. En el caso de la función
de Ackerman, una implementación mediante Programación Dinámica es una solución muy adecuada. De
todas formas, incluso para valores no muy grandes de m y n, el resultado de Ackerman es demasiado grande
para almacenarlo en un entero.

Ejercicio 2.22:
Escriba un programa que permita modelar el movimiento rectilíneo uniforme de un móvil en un plano. El
móvil puede seguir una trayectoria en cualquier recta del plano. Se conoce la posición inicial del móvil, así
como su velocidad lineal. Escriba, asimismo, un programa que ejercite dichas clases, de forma que se instancie
un móvil que se mueve a una velocidad de 2.4 metros/segundo, que parte de la posición (2.1, 5.2) y se mueve
sobre la recta y = 2x + 1. El móvil se irá moviendo en incrementos de tiempo arbitrarios. El programa ha de
determinar las posiciones en las que se encuentra el móvil tras el paso de 3.5, 4, y 6.2 unidades de tiempo
Clases y obje tos

temente, el punto de partida del móvil ha de


respectivamente y las imprimirá por pantalla. (Nota: Eviden
pertenecer a la recta que define el movimiento.)
icar las clases más adecuadas para representar el
Plante amien to: Este ejercicio tiene como objeto el identif
de ellas y su interrelación (véase la sección "Com en-
problema, así como los atributos que contienen cada una
tarios", al final del ejercicio).
an los conceptos encontrados en el proble ma
Lo primero es idear la solución al problema. Luego se model
()) como pide el enunciado. La siguiente figura
y en la solución. Por último, se escribe un progra ma (main
representa el problema:
Segundo avance tras
12 unidades de tiempo.

la posición tras t unidades de tiempo, se calcula el


El móvil comienza en una posición. Para saber cuál es
v (d= v * t). Como el recorrido es lineal, el punto
recorrido en esas t unidades de tiempo a una velocidad
al origen los incrementos en abcisas y ordenadas,
alcanzado dentro de la trayectoria se calcul a suman do
pendiente de la recta.
respectivamente d*coseno( a) y d*seno( a), siendo a la
Por tanto, partiendo de un punto, se calcul a prime ro la distancia recorrida. Después se determinan los
punto en el que está situado el móvil, para obtener el
incrementos en abcisas y ordenadas. Luego se suman al
varse el punto anterior, para calcular el siguiente
punto destino. Tras cada uno de estos avances habrá de conser
punto en la trayectoria.
ma ha de manejar objetos que representen puntos,
Del enunciado y de la solución se deduce que el progra
movimientos uniformes, rectas y móviles.
anteriores en este mismo capítulo. Además, se le
Primero se model a un punto, de forma similar a ejercicios
entación del punto de forma "(x. y)".
añade un método que devuelve una cadena con la repres
llamada MovUni forme, con un único atributo, la
Después se modela el movimiento uniforme, con una clase
un constructor en el que se inicializa su atributo y un
velocidad lineal del movimiento. También dispondrá de
), calcula el recorrido que se hace a dicha velocidad.
método que, dado un intervalo de tiempo (en unidades de tiempo
nea en un plano, es decir, una recta. Existen
También hay que model ar lo que es una trayectoria rectilí
así que se elige una que sea cómoda. Por ejemplo, se
multitud de representaciones matemáticas de una recta,
propone el enunciado. En el constructor de la clase
usa la representación de una recta como y = ax + b, como
conoc er el ángulo de la pendí ente, por lo que
Recta, se le pasarán los valores de a y b. De la recta es necesario
nte, que devolverá un doub 1e.
se proporciona un método que la calcule, llamado pendie
que será una clase llamada Móvi 1, que tendrá como
Con estas tres clases, ahora se puede model ar un móvil,
del mismo, la posición anterior a la última vez que
parámetros la posición inicial del móvil, la posición actual
que sigue. Dispondrá de un método que devuelva
avanz ó el móvil, el movimiento que ejecuta y la trayectoria
es de tiempo.
la posici ón actual y un método que permita avanz ar t unidad
e sencillo: Primero se crea un punto en la posición
Con todo ello, el progra ma principal queda relativament
enta la trayectoria del móvil (y= 2x +1). También
inicial del móvil (2.1, 5.2). Luego se crea una recta que repres
orden de creación de estos tres objetos es irrelevante.
se crea un movimiento uniforme con velocidad 2.4. El
Móvi 1, al que se llamará m. Entonces, altern.ati'Vamente,
Pero con los tres, ya se puede crear un objeto de la clase
a según indica el enunciado: 3.2, 4.0 y 6.2 segundos.
se imprime la posición actual del móvil, y el móvil avanz
Entre cada avance, se imprime la posición actual.
Programación en Java 2

Solución:
class Punto
private double x. y;

Punto(double x. double y)
this.x = x;
this.y = y;

doub le dameX O {
return x:

double dameY() {
return y;

String posición() {
return "(" + x +","+y +")";

class MovUniforme {
prívate double vel;

MovUniforme(double vel)
this.vel = vel;

double recorrido(double t)
return vel * t;

class Recta {
prívate double a. b;

Recta(double a. double b){


this.a = a;
this.b = b;

double pendiente(){
return Math.atan(a);

class Móvil

prívate Punto posinicial;


Clases y objetos

private Punto posAnterior:


prívate Punto posActual:

private Recta trayectoria:


private MovUniforme mov:

Móvil(Punto origen. Recta trayectoria. MovUniforme mov)


this.posAnterior = this.posActual=
this.posinicial = origen:

this.trayectoria = trayectoria;
this.mov = mov: 11 a1var1zacalc:ula la nueva posición pasados t segundos.

void avanza(double t)
Punto intermedio= new Punto (posActual.dameX(),4~:.....-----------.
posActual .dameY()): 1
Punto intennedio para actualizar el punto
double dist = mov.recorrido (t): anterior cuando acaben los cálculos.

double alfa= trayectoria.pendiente():

double incrX = dist * Math.cos(alfa):


double incrY = dist * Math.sin(alfa):

posActual = new Punto(posAnterior.dameX() + incrX.


posAnterior.dameY() + incrY):

posAnterior = intermedio:

Punto posActual(){
return posActual:

public class problemaMóvil{

public static void main(String[J args) {


Punto inicial= new Punto (2.1. 5.2): Avanza e imprime la posición actual.
Si el modelo de datos de nuestro
problema es adecuado, el código
Recta trayectoria= new Recta (2. 1): resulta mucho más simple.

MovUniforme miMov = new MovUniforme (2.4):

Móvil m= new Móvil(inicial. trayectoria. miMov):

System.out.println("Me encuentro en"+ m.posActualO.posiciónO):

m.avanza(3.2):
System.out.println("Me encuentro en"+ m.posActualO.posición());"'...;¡_..---..1
Programación en Java 2

m.avanza(4);
ición() );
System.out. println ( "Me encuentro en " + m. posActual ().pos

m.avanza(6.2);
ción()) ;
System.out.println("Me encuentro en"+ m.pos Actual O.posi

Comentario; La salida de este programa es:

Me encuentro en (2.1,5.2)
Me encuentro en (5.534600413439678.12.069200826879353)
Me encuentro en (6.393250516799597,13.78650103359919)
Me encuentro en (12.189138714479054,25.3782774289581)
Primero determina el recorrido lineal en ese
El método avanza calcula la nueva posición pasados t segundos.
oria, calcula los incrementos en x e y. Por
plazo. Luego, según la pendiente de la recta que representa la trayect
actualiza la anterior.
último, calcula la nueva posición actual a partir de la anterior. Y
de atributos para todos los valores que se
Aviso: Otra posibilidad es crear una única clase que tenga un montón
han de almacenar o calcular. Esto, en general, es una mala idea.
ar una posible solución. Luego, para cada
Siempre hay que entender el problema antes de ponerse a codific
que lo modela.
concepto del problema o de la solución, se propone una clase
Ampliación de clases

3.1 ELEMENTOS DE CLASE (STATIC)


Los atributos y métodos de una clase precedidos por la palabra stat i e se denominan elementos de clase. Los elemen-
tos de clase se comparten entre todas las instancias de la clase. Si se modifica un atributo de clase, todas las instancias
de la clase ven dicha modificación.
Como ejemplo, si se declara un atributo de clase llamado numA l umnos y un método de clase llamado
imprimeTota 1A1umnos, el código quedaría así:

class Alumno {
JI Cuenta de alumnos matriculados.
JI inicialmente a O
static int numAlumnos = O:

JI Resto de los atributos que se han omitido por simplificación

JI Se omiten las excepciones por claridad


Alumno(String nombre. String apellidos. int año)
JI Se Incrementa el núm. de alumnos matriculados
numAlumnos++:

JI Resto del código del constructor que se ha omitido por simplificación

static void imprimeTotalAlumnos()


System.out.println("Número total de matriculados"+ numAlumnos):

Dado que tanto el atributo numA1umnos como el método imprimeTotal Alumnos existen aunque no haya objetos se
les llamará desde el programa principal de la siguiente forma:

public static void main(String args[J) {


Programación en Java 2

Alumno.imprimeTotalAlumnos();

Es decir, con el nombre de la clase y el nombre del método.

3.1.1 Valor inicial de atributos de dase


Como los atributos y métodos estáticos se pueden utilizar aunque no exista ningún objeto de la clase, deben tener
siempre un valor correcto. Los atributos se pueden declarar e inicializar de la misma forma que las variables normales.
Si los valores iniciales de los atributos de clase requieren cálculos adicionales iniciales, se usa un bloque de
inicialización .de atributos estáticos, de la siguiente forma:

class Alumno {
static int numAlumnos:

static {
numAlumnos = O:

3. 2 DERECHOS DE ACCESO
El estado de un objeto es el conjunto de los valores de sus atributos. Una modificación arbitraria, intencionada o por
error, de este estado puede dar lugar a inconsistencias o comportamiento s indeseados del objeto. Sería deseable poder
controlar el acceso a los atributos de los objetos.
Java proporciona mecanismos de acceso a los componentes de una clase, de forma que es posible ajustarlo a las
necesidades de los objetos. Para ello, se antepone a la declaración el modificador de acceso que se requiere:

• Acceso privado (prívate): Los elementos privados sólo se pueden usar dentro de la clase que los define, nunca
desde ninguna otra clase.
• Acceso de paquete: No se pone nada. El acceso a estos componentes es libre dentro del paquete en el que se
define la clase.
e Acceso protegido (protected): Los elementos protegidos sólo se pueden usar dentro de la clase que los define,
aquellas clases que la extiendan y cualquier clase en el mismo paquete.
• Acceso público (publ ic): Dicho elemento se puede usar libremente.

Así, para limitar el acceso a los atributos nombre, apellidos y añoDeNacimiento de un objeto alumno se declara-
rían como:

enum Horario {MAÑANA.TARDE}

class Alumno {
private String nombre:
private String apellidos:
private int añoDeNacimiento:
Ampliación de clases

private int NP: / / Número Persona 7: identific ativo único


private String grupo:
private Horario horario:

!/ Resto de la clase Alumno

compilación, y sólo se
De esta forma, el intento de cambiar cualquier atributo privado dará lugar a un error de
modificar los valores de los atributos desde los propios
podrá acceder a la parte pública de la clase. Sólo se pueden
modificar los atributos a través de un método ponGrupo( ), éste
métodos de la clase. De esta forma, aunque se puedan
caso contrario lanzar una excepción .
puede verificar que la modificación es segura y en

3.3 PAQUETES
nte relacionados entre sí.
Los paquetes son agrupaciones de clases, interfaces y otros paquetes (subpaquetes), normalme
ción de mayor nivel que las clases. Los paquetes permiten unifi-
Los paquetes proporcionan un mecanismo de encapsula
funcional mente. Por ejemplo, el paquete java engloba una serie de
car un conjunto de clases e interfaces relacionados
de la aplicación . Contiene, a su vez, los subpaquetes ut i l o
paquetes con utilidades de soporte al desarrollo y ejecución
o pertenece a un paquete, la primera sentencia debe tener la sintaxis:
l ang. Para indicar que la clase que se está escribiend

package nombrePaquete;
parte del paquete
Todos los elemento s contenido s en el fichero en el que aparece tal declaraci ón formarán
nombrePaquete.

3.3.1 Uso
se añade una declaración de
Cuando en una clase se quieren utilizar componentes que están en otro paquete diferente,
importación, que puede tener las siguientes formas:

// Importación de la clase "Alumno"


I / de 7 paquete "Matri cu 7a"
import Matricula.Alumno:// importación de la clase "Alumno" del paquete "Matricul a"
import Matricula.*: // importación del paquete "Matricul a". incluye la clase Alumno

3.3.2 Nombres
n que contiene. El nombre
El nombre del paquete, como todos los identificadores, debe ser representativo de la agrupació
se puede recomend ar incluir el dominio de la empresa para que
puede contener la declaración de subpaquete. Incluso
que pudieran existir o comprars e a otros proveedores.
quede identificado de forma única respecto a otros paquetes

package com.empresa.Matricula:
que contenga dos
Los derechos de paquete no se modifican porque estén contenidos en otro paquete. Un paquete
agrupar paquetes es convenien te p~a el posterior
subpaquetes no implica permisos de acceso entre ellos. Es decir,
desarrollo de código, pero no para modificar los derechos de acceso.
Programación en Java 2

3.4 CLASES INTERNAS


externa
Una clase interna es una clase cuya definición está dentro de otra clase. Una clase exterior se denomina clase
que en muchos casos
o clase contenedora. Las clases internas permiten evitar la proliferación de clases muy pequeñas
es de eventos, como
sólo se usan dentro de una sola clase. El uso más común es la creación de adaptadores y manejador
fuera
se verá en los últimos capítulos, así como en la implementación de interfaces tipo Iterator. Otros usos quedan
del ámbito de este libro.
Hay distintos tipos de clases internas pero, por simplicidad, sólo se presentan las clases internas que se definen
a sólo
como miembros normales no estáticos de una clase contenedora. Como son miembros de la clase contenedor
puede existir un objeto de la clase interna cuando exista un objeto de la clase contenedora.
Las clases internas pueden acceder directamente a todos los miembros de la clase contenedora. Y ello es indepen-
utilizar
diente de los modificadores de control de acceso que tengan los miembros de modo que, por ejemplo, puede
directamente una variable miembro aunque esté declarada como privada.
a
Las clases internas no estáticas tienen algunas limitaciones: los nombres de los miembros de la clase contenedor
miembro estático y no
tienen que ser diferentes de los de la clase interna, una clase interna no puede contener ningún
es posible crear un objeto de la clase interna sin tener un objeto de la clase contenedora.
los
En el siguiente ejemplo se añade una clase interna a la clase Al umno previamente definida para poder tener
Se han añadido los
datos sobre la dirección del alumno. Se ha simplificado la dirección a sólo la calle y el número.
en forma de cadena y
métodos toStri ng() tanto en Alumno como en Dirección que devuelve el contenido del objeto
permite la escritura directa por pantalla de un objeto utilizando el método System. out. pri nt l n( ).

public class Alumno {

private String nombre:


prívate String apellidos;
private int añoNacimiento;
prívate Horario horario;
private Direccion direccion;

public Alumno(String nombre.


String apellidos.
int año.
Horario horario.
String calle.
int num) {
this.nombre = nombre;
this.apellidos = apellidos;
añoNacimiento = año;
this.horario = horario;
direccion = new Direccion(calle. num);

public void ponDireccion(Direccion dir)


direccion= dir;

!! devuelve los datos del objeto en formato cadena


public String toString(){
return nombre+" "+apellid os+" "
+ añoNacimiento +" "
+ horario + " " + direccion;
Ampliación de clases

class Direccion{
String calle:
int numero:

Direccion(String calle. int numero){


this.calle = calle:
this.numero = numero:

public String toString()


return ca ll e + " " + numero:

public static void main(String args[J)


Alumno alumno = new Alumno("Balta". "Fernández". 1991.
Horario.MAÑANA. "Zamora". 23):
System.out.println("Datos alumno: "+ alumno):
Alumno.Direccion direccion = alumno.new Direccion("Figueruela". 28);
alumno.ponDireccion(direccion):
System.out.println("Datos alumno:"+ alumno):

Con las clases internas se introduce una nueva sintaxis en el nombrado de las clases, en el operador new, de
creación de una instancia y en la autorreferencia thi s. Como se puede ver en el ejemplo, si se quiere utilizar directa,.
mente la clase interna, por ejemplo, para crear un nuevo objeto, hay que hacerlo NombreCl aseContenedora.
NombreCl ase Interna. Si la clase interna no se ha declarado privada se puede crear un objeto de esa clase interna
mediante referenci aübjetoCl aseContenedora. new NombreCl ase Interna ().
Si dentro de la clase interna se desea hacer una referencia al objeto actual de la clase contenedora se hace mediante
NombreClaseContenedora.this.
Java también permite crear clases locales. Las clases locales son aquellas que se definen dentro de un método y
que, por tanto, sólo son visibles y utilizables en dicho método. Así mismo, permite crear clases a,iánimas.qut són
clases locales sin nombre. Las clases locales y las clases anónimas se usan de forma habitual en el trabajo con archivos
y en la creación de interfaces gráficas de usuario de las que se verán ejemplos en el Capítulo l O.

3.5 IMPORTACIÓN ESTÁTICA DE CLASES


Para acceder a los miembros estáticos de una clase hay que escribir el nombre de la clase, un punto y el nombre del
atributo o método. Esta sintaxis puede comprometer la legibilidad de un programa, sobre todo cuando aparecen muchos
métodos y atributos estáticos con el nombre de la clase. Java proporciona un mecanismo para la importación de miem-
bros estáticos, anteponiendo el cualificador static tras la importación. Se permite tanto la importación individual:

import static java.lang.Math.PI:

como todos los miembros de la clase:


Programación en Java 2

import static java.lang.Math.*:

De esta forma, se puede escribir un programa para el cálculo genérico de un logaritmo como:

import static java.lang.Math.*:

class LogGenerico {
static double x = // poner valor double
static double a= // poner valor double

// calcula logaritmo de "x" en base "a"


public static void main (String args[J) {
double res:
res= log{x) / log{a): // uso de lag sin cualificar
System.out.println("res=" + res);

En este ejemplo el método l og ( ) pertenece a la clase Math.

3.6 CLASES PREDEFINIDAS


Uno de los puntos fuertes de Java es la gran cantidad de clases predefinidas que aporta. Abarcan temas como comu-
nicaciones, web, diseño gráfico, utilidades matemáticas, contenedores genéricos y muchas más. En este apartado se
verán algunas de las más utilizadas:

.. Envoltorios de los tipos simples.


.. String, para la manipulación de cadenas de texto.
• Math, biblioteca de funciones matemáticas.

3.6.1 Envoltorios
Los tipos predefinidos en el lenguaje Java son tipos simples, en el sentido de que no son clases. Por conveniencia,
existen unas clases predefinidas, denominadas envoltorios (wrappers, en inglés), para estos tipos simples. Estas
clases envoltorio proporcionan métodos de clase, útiles para convertir cadenas de texto al tipo adecuado, imprimir
con varios formatos, constantes estáticas con el valor mínimo y máximo del tipo, etc. Además, estas clases envoltorio
generan automáticamente una instancia cuando se usan tipos simples en contextos en los que se espera un objeto. Así
mismo, los envoltorios son compatibles con los tipos simples que representan, por lo que pueden usarse en expresio-
nes en que se espera el tipo simple. Los envoltorios definidos en Java pueden verse en la Tabla 3.1.
Los tipos byte y short se incluyen en el lenguaje Java por razones de eficiencia, por lo que no tienen envoltorios
predefinidos, utilizándose la clase Integer.
Todos los envoltorios disponen, entre otros, de los siguientes constructores y métodos:

• Constructor a partir de un valor del tipo simple,

Character miletra = new Character('H'):


Integer miEntero = new Integer(l024):
AmpHaclón de clases

Tabla 3.1. Envoltorios definidos en Java.

Boolean boolean
Character char
Integer int
Long long
Float float
Oouble double

.. Constructor que toma una cadena y lo traduce al tipo correspondiente,

Float miRealCorto = new Float("l2.3E-2"):

.. Método toStri ng() que transforma el valor en una cadena,

System.out.println("Mi entero es "+ miEntero): !!llamada implfcna a toString()

• Método que devuelve el valor primitivo. El nombre del método es la concatenación del tipo simple con la
palabra Value, es decir, charVa l ue() en el envoltorio Character, i ntVa l ue() en el envoltorio Integer, etc.

int m = miEntero.intValue():

.. Método equa l s ( ) para comparar el valor entre envoltorios,

Integer otroEntero = new Integer(2048):


boolean res= miEntero.equals(otroEntero):

En el siguiente ejemplo se muestra la posibilidad de mezclar tipos simples y envoltorios en expresiones matemá-
ticas realizándose la conversión entre ellos de forma automática.
public static void main(String args[J)
Integer envX = new Integer(7):
int y= 8:
double z:
envX += y; // añade y a envX
envX++; // incrementa en uno el valor de envX
z = Math.sqrt(envX): // rafz cuadrada de envX. z = 4.0

Esta conversión automática permite utilizar un tipo primitivo en el ámbito en que se requiere un objeto, por
ejemplo para añadir un entero a una lista de la clase ArrayList, como se verá en ejercicios del Capítulo 6.

Boolean
La única particularidad de Boo l ea n es que al convertir una cadena, se traduce la cadena "true" (cualquier combina-
ción de minúsculas y mayúsculas) al valor true. Cualquier otra cadena se traduce al valor false.

Character
El envoltorio Character proporciona métodos para determinar si un carácter es una letra o un dígito, espacio en
blanco(' ', '\t', '\n', '\ f' o '\r'), pasar de mayúsculas a minúsculas, etc. Existen algunas particularidades en estos
Programación en Java 2

métodos dependiendo del alfabeto al que pertenecen los caracteres. Java, como utiliza Unicode para codificar los
caracteres, permite otros alfabetos como el cirílico, griego, kanji, etc., cuyo comportamiento con las mayúsculas y
minúsculas puede diferir de los alfabetos occidentales derivados del latín. Asimismo, los dígitos para dichos alfabetos
también son diferentes de 'O', 'l', etc. Para estos detalles, consúltese un manual de referencia de Java.

Integer
Además de almacenar un valor i nt, se suele usar para los tipos predefinidos byte y short, ya que no tienen envoltorios propios.

Float y Double
En Java, los tipos fl oat y doub le pueden contener el valor +oo y el -oo, por ejemplo, en las divisiones por O. Pero también
algunas expresiones pueden dar lugar a valores que no representan un número, como por ejemplo Math. sqrt ( -1). Esto
en Java se representa con el valor NaN. Asimismo, existen métodos para determinar si un número es +oo, -oo o NaN.

float s= O:
s = 10 / s:
Float infinito= new Float(s):

// Imprimirá "infinito es Infinity"


System.out.println("infinito es " + infinito):
Float noNumero= new Float(Math.sqrt(-1));
// Imprimirá "noNumero es NaN"
System.out.println("noNumero es " + noNumero);

3.6.2 Math
La clase Math contiene constantes y métodos de uso común en matemáticas. Todas las operaciones que se llevan a
cabo en dicha clase se realizan con tipo doub le. Contiene las constantes 1t (Math. PI) y el número de Euler, e (Math. E),
ambos de tipo doub le. En las funciones trigonométricas, los ángulos están en radianes y los métodos devuelven
valores doub le.

3.6.3 String
La clase Stri ng se usa para manejar cadenas de caracteres de cualquier longitud finita. Es una clase especial con
soporte específico incluido en el lenguaje Java. Para crear un objeto Stri ng no hace falta llamar al constructor, basta
escribirlo como un valor.

String nombre: // crea variable "nombre" de tipo String


String saludo = "hola": // crea un objeto String y lo asigna a la variable "saludo"
String mensaje= saludo:

La clase String tiene un tratamiento particular en Java, pues aparte de la construcción de objetos a partir de
literales entre comillas, se pueden aplicar los operadores+ y+= que se usan para concatenar String.

String s = "Hola " + "Pedro.": // s valdrá "Hola Pedro."


s +=" Hola "+ "Juan.": // s valdrá "Hola Pedro. Hola Juan."

Para comparar si los valores de dos Stri ng son iguales se utiliza el método equa 1s ().
Ampliación de clases

ELEME NTOS DE CLASE (STATIC)

Ejercicio 3.1:
Math.
Escriba un programa que imprima en la pantalla las constantes de la clase
un punto y el nombre de la
Planteamiento: Para utilizar una constante de clase, se pone el nombre de la clase,
es, su valor no puede cambiar. La clase
constante. Las constantes son atributos calificados como final, esto
Euler, llamados Math. PI y Math. E.
Math proporciona dos constantes, el valor de 1t y el de la constante de

Solución:
import java.lang.Math:

public class PruebaCtesMath

public static void main(String args[J)


System.out.println("Pi vale " + Math.PI);<11,<.------11 Uso de la constante n, (Math. PI). )
System.out.println("E (cte de Euler) vale"+ Math.E):

Comentario: La salida del programa es;

Pi vale 3.141592653589793
E (cte de Euler) vale 2.718281828459045

Ejercicio 3.2:
es:
Escriba una clase de nombre Constantes que declare las siguientes constant

.. Velocidad de la luz, c : 2,9979 · 108 mis


Constante Universal de Gravitación, G: 6,67-1()- N m /kg
11 2 2
"
34 l•s
.. Constante de ·Planck, h: 6,6262 • ]0·

de la clase Constantes y luego


Escribir asimismo un programa llamado pruebaConstantes, que cree un objeto
imprime los valores de las constantes y sus dimensiones.

Planteamiento: Una constante es un atributo al que se le ha declarado como final


. Estos atributos sólo pueden
ión. Como todos estos valores tienen
tomar valor una vez, normalmente en la misma línea de la declarac
rangos muy pequeños o grandes, deberán ser doub le.
Una constante es un atributo final,
Solución: que no se puede modificar.
class Constantes {
public final double C = 2.9979E08; // mis VELOCIDAD DE LA LUZ+ -----"
public final double G = 6.67E-ll; // N m2 /kg 2 CONSTANTE GRAVITARORIA UNIVERSAL (O DE NEWTON)
public final double h = 6.6262E-34; // J•s CONSTANTE DE PLANK

class PruebaConstantes {
Programación en Java 2

public static void main (String args[J) {


Constantes ctes = new Constantes():

System.out.println("La velocidad de la luz es"+ ctes.C +


"en metros por segundo");
System.out.println("La constante de gravitación universal es "+ ctes.G +
" en Newtows por metros al cuadrado partido kilogramos al cuadrado"):
System.out.println ("La constante de Plank es"+ ctes.h +
"en julios por segundo"):

Comentario: La salida del programa es:

La velocidad de la luz es 2.9979E8 en metros por segundo


La constante de gravitación universal es 6.67E-ll en Newtows por metros al cuadrado partido kilogramos
al cuadrado
La masa en reposo del electrón es 9.1096E-31 en kilogramos
La carga del electrón es l.6022E-19 en culombios
La constante de Plank es 6.6262E-34 en julios por segundo

Aviso: Este programa adolece de un defecto: para acceder a las constantes hay que crear primero un objeto. Es
mejor declararlas como constantes de clase, como se vio en el Ejercicio 3.1, en el que las constantes de la clase
Math están disponibles sin necesidad de objetos. (Nota: además, Math está escrito de forma que no se pueden
crear objetos.)

Ejercicio 3.3:
Escriba un programa para representar el consumo de energía de una instalación eléctrica. Para ello, se
dispondrá de una clase que representa los aparatos conectados en la instalación. Cada aparato tiene un
consumo eléctrico determinado. Al encender un aparato eléctrico, el consumo de energía se incrementa en la
potencia de dicho aparato. Al apagarlo, se decrementa el consumo. Inicialmente, los aparatos están todos
apagados. Además, se desea consultar el consumo total de la instalación.
Hacer un programa que declare tres aparatos eléctricos, una bombilla de 100 watios, un radiador de 2000
watios y una plancha de 1200 watios. El programa imprimirá el consumo nada más crear los objetos. Poste-
riormente, se enciende la bombilla y la plancha, y el programa imprime el consumo. Luego se apaga la
plancha y se enciende el radiador y se vuelve a imprimir el consumo.

Planteamiento: Según el enunciado, la clase que modela a los aparatos eléctricos tiene dos datos, su potencia
y si están encendidos o no. Esta clase se llamará Apa ratoEl éctri co. Por otro lado, el consumo total debe ser un
atributo accesible a todos los aparatos eléctricos, lo que se consigue con un elemento de clase. Para ello, se
declara el atributo consumoTotal, de tipo double y se califica como static. Así, todas las instancias de
Apa ratoEl éctri co comparten el mismo atributo.
Para consultar el consumo total de la instalación, se proporciona un método que devuelva el valor de
consumoTotal. Este método ha de ser también de clase (calificado como static) y se llamará consumo().
Cuando un aparato eléctrico se enciende puede incrementar el consumoTata l con la potencia que consume.
Esto lo llevará a cabo el método enci ende ( ). Correspondientemente, cuando el aparato se apaga, se resta su
potencia al consumo total. Y de nuevo, sólo si estaba encendido. Esto se implementa en el método apaga ().
Evidentemente, hay que incrementar el consumo sólo si el aparato estaba encendido

Solución:
class AparatoEléctrico
Ampliación de clases

static double consumoTotal = O:

static double consumo() { , ~ - . - - - - - 1 1 Método de clase para acceder a un


atributo de clase.
return consumoEléctrico:

prívate double potencia:


prívate boolean encendido:

AparatoEléctrico (double potencia)


this.potencia = potencia:
encendido= false:

void enciende()
if ( ! encendido){ Al encender o apagar, sólo se
encendido= true: •~ - - - - - - - 1 1 modifica el consumoTata l si
consumoEléctrico += potencia: se cambia de estado.

void apaga()
if (encendido){
encendido= false:
consumoEléctrico -= potencia:

class ConsumoEléctrico

public static void main(String[J args) {


AparatoEléctrico bombilla= new AparatoEléctrico (100):
AparatoEléctrico radiador= new AparatoEléctrico (2000):
AparatoEléctrico plancha = new AparatoEléctrico (1200):

System.out.println("El consumo eléctrico es"+


AparatoEléctrico.consumo()):

bombilla.enciende():
plancha.enciende():
System.out.println("El consumo eléctrico es "+
AparatoEléctrico.consumo ()):

plancha.apaga():
radiador.enciende():
System.out.println("El consumo eléctrico es"+
AparatoEléctrico.consumo ()):
Programación en Java 2

Comentario: La salida por pantalla que genera este programa es:

El consumo eléctrico es O.O


El consumo eléctrico es 1300.0
El consumo eléctrico es 2100.0

Aviso: El punto más delicado es olvidar que si se invoca el método enciende() dos veces seguidas, la segunda
no debe incrementar el consumo. Podría ser muy incómodo lanzar una excepción en ese caso. Por ello, el
método enciende ( ) sólo incrementa el consumo si el aparato estaba apagado. Correspondientemente, sólo se
decrementa el consumo si el aparato estaba encendido.

Ejercicio 3.4:
Añada a la clase Punto una constante llamada ORIGEN que sea el origen de coordenadas. La constante debe
ser accesible de forma estática. Escriba un programa, de nombre PruebaPunto, que determine la distancia de
los puntos (3,4), (0,4) y (2, -1) al origen usando la constante ORIGEN.

Planteamiento: Una constante es un atributo al que no se puede cambiar el valor una vez inicializado. Nor-
malmente, son atributos públicos de clase. En este caso, el valor constante es un punto situado en (0, 0). Para
declarar la constante se pone la palabra final delante de un atributo. El atributo no podrá cambiar de valor.
Como se desea que la constante esté disponible de forma estática, se antepone también la palabra stat i c. Así,
se podrá usar la constante escribiendo Punto. ORIGEN, sin necesidad de tener objetos de la clase Punto.

Escribe: Se escribe el mensaje "Distancia de p al origen" seguido del valor.

Solución:
class Punto

public static final Punto ORIGEN= new Punto (O. O);-<t~----...


1
prívate double x. y: Las constantes sólo pueden tomar
valor una vez. Se recomienda
escribir su nombre en mayúsculas.
public Punto (double x. double y) {
this.x = x:
this.y = y;

public double dameX(){


return x:

public double dameY(){


return y;

public double distancia (Punto p)


double diffX = x - p.x;
double diffY = y - p.y;

return Math.sqrt(diffX * diffX + diffY * diffY):


AmpHación de clases

class PruebaPunto {
public static void main(String[J args) {
Punto pl = new Punto (3. 4):
Punto p2 = new Punto (O. 4):
Punto p3 = new Punto (2. -1):

System.out.println("Distancia de pl al ORIGEN= " + pl.distancia(Punto.ORIGEN)):


System.out.println("Distancia de p2 al ORIGEN="+ p2.distancia(Punto.ORIGEN)):
System.out.println("Distancia de p3 al origen="+ p3.distancia(Punto.ORIGEN)):

Comenta~o: Es muy común declarar e inicializar las constantes simultáneamente. También es posible añadir
una sección donde se inicializan los miembros estáticos de una clase. Algunas clases de utilidad pública tienen
todos sus atributos y métodos declarados stat i c, para usarlos directamente sin crear objetos. Un caso de
ejemplo ya visto es la clase Math. La salida del programa es:

Distancia de pl al ORIGEN= 5.0


Distancia de p2 al ORIGEN= 4.0
Distancia de p3 al origen= 2.23606797749979

Aviso: Puntos delicados acerca del problema o de la solución.

Ejercicio 3.5:
Escriba una clase llamada Elemento, que disponga de un atributo con su nombre. La clase debe contener un
método llamado númeroDeElementos que devuelve el número total de elementos que se han instanciado.

Planteamiento: Para determinar el número total de elementos, se crea un atributo de clase que se incrementa
cada vez que se crea una nueva instancia. Esto se hace en el constructor de Elemento. Además, se añade el
método de clase númeroDeEl ementos que lo devuelve.

Solución:
class Elemento
private String nombre:

Elemento(String nombre)
this.nombre = nombre:
Además de la construcción habitual
numElementos++; 4~---~, de un objeto de la clase, se actualiza
el atributo de clase numEl ementos.

static private int numElementos = O:

static int númeroDeElementos(){


return numElementos:

public class PruebaElemento {

public static void main(Stríng[J args) {


Programación en Java 2

Elemento H = new Elemento("Hidrógeno"):


Elemento He = new Elemento( "Helio"):
Elemento Li = new Elemento( "Litio"):

System.out. println( "Creados: " + Elemento. númeroDeElementos()):

Comentario: Este programa imprime "Creados: 3" por pantalla.

Ejercicio 3.6:
Escriba una clase de nombre Ítem, que acepta un nombre en su constructor. Cada ítem debe disponer de un
número que servirá como identificador único de cada objeto. La clase Ítem dispondrá de un método para
obtener el identificador y otro para obtener el nombre. Haga un programa de prueba que genere tres ítems,
"uno", "dos" y "tres" y luego escriba los nombres e identificadores de cada ítem.

Planteamiento: La parte del atributo no presenta ningún problema. Para asignar un identificador único a cada
instancia de la clase, se proporciona un atributo de clase, que no es más que un contador de objetos construi-
dos. Además, se guarda el valor de ese contador en un atributo de cada objeto. Así, cada objeto recibe un
número distinto, único. Luego, el programa de prueba consiste en crear los tres objetos Ítem con nombres. Es
al acceder a los identificadores cuando se ve que cada uno ha recibido un número distinto.

Solución:
class Ítem
private static int contador= O:

private int Id:


private String nombre:

Ítem (String nombre) {


this.nombre = nombre:

Id= ++contador: 4
<o¡,----~1
Usamos un atributo de clase para
identificar a cada objeto de la clase.

int Id(){
return Id:

String nombre(){
return nombre:

public class PruebaÍtem {


public static void main(String args[J)
Ítem il = new Ítem("uno"):
Ítem i2 = new Ítem("dos"):
Ítem i3 = new ftem("tres"):

System.out. println( "Ítem " + i l. nombre() + " id " + i l. Id()):


System.out.println("Ítem" + i2.nombre0 +"id"+ i2.Id());
System.out.println("Ítem" + i3.nombre() +" id "+ i3.Id());

Comentario: La salida del programa es:

Ítem uno id 1
Ítem dos id 2
Ítem tres id 3

Aviso: Como mecanismo de identificador de objetos, el sistema puede ser un poco pobre. Cuando los objetos
desaparecen, quedan números sin asignar que no se volverán a usar. Todos los objetos en Java reciben un
identificador único, pero basado en funciones de dispersión (hash function).

Ejercicio 3.7:
Se desea representar las bombillas que pueda haber en una casa. Cada bombilla tiene asociada un interrup-
tor y sólo uno. Así mismo, existe un interruptor general de la casa. Un interruptor tiene dos estados, ON y
OFF. Una bombilla luce si el interruptor general de la casa está ON y su interruptor asociado también.
Escriba una clase de nombre Bombilla que permita modelar la información anterior. Para ello, la clase
dispondrá de:

.. un método para cambiar el estado del interruptor de la bombilla


., un método para cambiar el estado del interruptor general de la casa
• un método que determina si una bombilla está luciendo o no

Planteamiento: Los interruptores se representan por los estados ON y OFF. Para ello, se usa un enumerado
con ambos valores, llamado Estado. Por otro lado, del enunciado se puede deducir que cada Bombi 11 a tendrá
un atributo que será su interruptor asociado. Ahora bien, el interruptor general es único y común para todas las
bombillas. Esto se modela como un atributo de clase (static) que comparten todos los objetos. Asimismo, el
método que pulsa dicho interruptor ha de ser de clase también. Por último, para el método que determina si la
bombilla luce o no, hay que tener en cuenta que tanto el interruptor de la bombilla como el interruptor general
deben estar a ON. Cuando uno de ellos esta a OFF la bombilla no luce.

Solución:
enum Estado { ON. OFF};

class Bombilla {
// Parte estátjca que representa al Interruptor General
prívate static Estado interruptorGeneral = Estado.OFF;
La parte común a todos los objetos
de una clase se representa con
public static void pulsalnterruptorGeneral(){ ~¿---~1 miembros de clase y se manejan
if (interruptorGeneral == Estado.ON){ con métodos de clase.
interruptorGeneral = Estado.OFF;
}else{
interruptorGeneral = Estado.ON;

/! Atrjbutos y métodos relatjvos a cada bomb;lla


private Estado interruptor;
Programación en Java 2

public Bombilla() {
interruptor= Estado.OFF:

public boolean luce()


return (interruptor== Estado.ON) &&
(interruptorGeneral = Estado.ON);

public void pulsalnterruptor()


if (interruptor= Estado.ON){
interruptor= Estado.OFF:
}else{
interruptor= Estado.ON:

!! El main no forma parte del ejercicio


public static void main(String[J args) {
System.out.println("Este main no forma parte del ejercicio"):

Bombilla al= new Bombilla():


Bombilla a2 = new Bombilla():
Bombilla a3 = new Bombilla():

al.pulsalnterruptor():
System.out. println( "al " + (al. luce() ? "SI" "NO") + " luce."):

al.pulsainterruptorGeneral():
System.out.println("al " + (al. luce() ? "SI" "NO") + " luce."):

Comentario: Los métodos que pulsan el interruptor {tanto el general como el de la bombilla) comprueban el
estado para cambiarlo, mediante un i f (o un switch).
Si se modela el estado del interruptor con un booleano, llamado está Pulsado, el método pulsar se
reduce a:

public void pulsainterruptor()


estáPulsado = ! estáPulsado:

Aviso: No sería correcto en este problema representar los interruptores como boo lean. Es cierto que cada
interruptor sólo dispone de dos estados, así como el tipo boo lean tiene sólo dos valores. Pero las operaciones
sobre el interruptor no son las que se dispone de los boolean.

Ejercicio 3.8:
Escriba un programa que utilice la clase Bombilla del apartado anterior. Para ello, se creará una Bombilla
y se imprimirá por pantalla si luce o no. Luego se pulsa el interruptor de la Bombilla y se vuelve a imprimir
el estado de la misma. Por último, se pulsa el interruptor general y se imprime el estado.
AmpHaclón de clases

Planteamiento: Se define una clase pruebaBombi l la. Primero instancia una Bombilla, llamada al. Como los
interruptores pueden tener el valor ON y OFF, con el operador temario "?:" se imprimen las palabras
"SI" 0
"NO" para determinar si lucen.

Solución:
class PruebaBombilla

public static void main(String[J args) {


Bombilla al= new Bombilla():

System.out.println("al "+ (al.luce() ? "SI" "NO")+" luce."):

al.pulsalnterruptor():
System.out.println("al "+ (al.luce() ? "SI" "NO") + • luce."):

al.pulsainterruptorGeneral():
System.out.println("al " + (al. luce() ? "SI" "NO")+" luce."):

Comentario: La salida por pantalla será:

al NO luce.
al NO luce.
al SI luce.

PAQUET ES

Ejercicio 3.9:
Se desea realizar una biblioteca de clases para el tratamiento de imágenes, vídeo y audio para la realización
de aplicacion es multimedia. Como existirán multitud de formatos de imágenes, vídeo y sonido, se estructuran
las distintas clases en un paquete, llamado mediaBib. Se agruparán los posibles codificadores y decodificad
ores
en tres subpaquetes:

• "imagen", con los fonnatos GIF, TIFF y JPEG.


.. "video" con los formatos H.263, MPEG-I y MPEG-4
"' "audio" con los formatos GSM y MP3.

Y, para cada uno de los formatos, se proporcion ará una clase que pueda codificar y decodifica r dichos
formatos. El nombre de esta clase será "codecFormato", sustituyend o "Formato" por el tipo tratado,
por
ejemplo, codecG/F, codecGSM, etc.
Se pide diseñar la estructura de directorios necesaria para la biblioteca, indicando los directorios
y
ficheros necesarios. Asimismo, para cada fichero se debe escribir la declaración pertinente respecto
de la
pertenenci a al paquete. NO SE PIDE que se codifiquen las clases, sólo la informació n de estructura.

Planteamiento: En Java, la estructura de paquetes se ha hecho coincidir con la estructura de carpetas y


ficheros en que se organizan las clases, así como las clases públicas han de residir en ficheros con el mismo
nombre. Por ello, se generará una carpeta de nombre medí aBi b, dentro de la cual habrá tres carpetas
más,
imagen, vi deo y audio. Por último, dentro de la carpeta imagen se crearán los ficheros codecGIF. java,
codecTIFF.java y codecJPEG.java. Dentro de la carpeta vídeo existirán los ficheros codecH263.java,
Programación en Java 2

codecMPEGl.java y codecMPEG4.java. Por último, en la carpeta audio se pondrán los ficheros codecGSM. java y
codecMP3. java.

Solución:
La estructura de directorios se muestra a continuación:

Cada fichero debe contener al principio una línea indicando el paquete al que pertenece y luego las clases que
aporte. La siguiente lista recoge sólo las líneas de declaración de paquete:

• codecGSM.java: package mediaBib.audio;


• codecMP3.java: package mediaBib.audio;
" codecGIF.java: package mediaBib. imagen:
• codecJPEG.java: package mediaBib.imagen:
• codecTIFF.java: package mediaBib.imagen;
• codecH263.java: package mediaBib.video:
" codecMPEGl.java: package mediaBib.video:
• codecMPEG4.java: package mediaBib.video:

Comentario: Evidentemente, cada fichero tendrá, al menos, una clase pública con el mismo nombre que el
fichero. Los detalles de codificación exceden del propósito de este libro, pero Java Media Framework (JMF) es
una biblioteca que cubre estos aspectos.

Aviso: Tenga en cuenta que para la clase que trata el formato H.263 se ha elegido el nombre codecH263. No se
puede usar codecH. 263, porque los identificadores de clase no pueden llevar un punto. Esto es así porque el
punto es el separador para paquetes y generaría ambigüedad un nombre como medi aBi b. vi deo. codecH. 263.
Tampoco se admiten caracteres como el guión ' -'. Por razones parecidas, se suelen evitar las peculiaridades de
internacionalización, y se suelen evitar acentos y eñes, que sí están admitidos.

CLASES PREDEFINIDAS

Ejercicio 3.10:
Escriba un programa que inicialice dos cadenas de caracteres, una llamada nombre y otra llamada apellido.
Los valores iniciales de las cadenas son "Juan" y "Pérez", respectivamente. El programa debe escribir ambas
cadenas y su longitud por pantalla.

Planteamiento: Se declaran dos referencias a Stri ng, y se inicializan directamente, asignando la cadena de
caracteres sin necesidad de new, en la misma línea. Para conocer la longitud de una cadena de caracteres, se usa
el método l ength ( ) .

Solución:
class Cadenasl
AmpUación de clases

public static void main (String args[J)


String nombre = "Juan":
String apellido = "Pérez": -------11
System.out.println(nombre +"tiene"+
nombre.length ()+"letras"):
System.out.println(apellido + " tiene " +
apellido. length () + " letras"):

Juan tiene 4 letras


Pérez tiene 5 letras

Alternativamente, una cadena se puede inicializar como Stri ng nombre = new


completamente equivalente a la anterior, razón por la cual no se usa mucho.

Ejercicio 3.11:
Escriba un programa que declare una cadena de caracteres denominada nombre, con
primerApellido, con valor "Pérez" y segundoApellido con valor "Lópei'. Después, el programa
nombre el primer apellido y luego el segundo. Por último, el programa imprime el nombre c01noteto

Planteamiento: Para concatenar dos cadenas, se usa la operación"+". También existe la Vaíiifflttcn+';;>;iJ
hacer el programa, se crean las tres variables nombre, pri merApe l l ido y segundoApe 11 ido, 1ruc1atiz1i~~ ,GJí;IO
indica el enunciado. Luego se concatena con nombre con pri merApe l l ido con el operador "+=''.
segundoApe l l ido. Por último, se imprime el nombre y el número de letras.

Solución:
class Cadena2

public static void main(String args[J)


String nombre= "Juan":
String primerApellido = "Pérez":
St ri ng segundoApe 11 ido = "López" :

nombre+= primerApellido:
nombre+= segundoApellido:

System.out.println(nombre +"tiene"+ nombre.length ()+"letras"):

Comentario: Se podría resolver en una sola sentencia la concatenación de los dos apellidos, de la forma:

nombre+= primerApellido + segundoApellido:

La salida del programa es:

JuanPérezlópez tiene 14 letras


Programación en Java 2

dos originales seguidas sin separa-


Aviso: Cuando se concatenan cadenas, se forma una nueva, que contiene las de la forma:
nas, hay que ponerlo s explícit amente,
ción ninguna. Si se hubiesen querido blancos entre las subcade

nombre += " " + primerApellido:


nombre += " " + segundoApe ll do:

Ejercicio 3.12:
programa ha de imprimir por pantalla
Haga un programa que contenga la cadena "Juan Piñón Lópei'. El
en mayúsc ulas.
ambas cadenas con todos los caracteres en minúsculas y luego
y toUpperCase() que devuelven una
Planteamiento: La clase Stri ng proporciona dos métodos, tolowerCase ()
cadena con todos los caracteres en minúsculas y en mayúsculas.

Solución:
class Cadenas3

public static void main (String args[J) {


String sl= "Juan Piñón López":

System.out.println("En minúsc ulas"+ sl.tolowerCase 0):


System.out.println("En mayúsc ulas"+ sl.toUpperCase 0):

Comentario: La salida de este programa es:

En minúsculas juan piñón lópez


En mayúsculas JUAN PIÑÓN LÓPEZ
ulas y minúsculas.
Fíjese en que las letras acentuadas y la eñe también han pasado a mayúsc
sino que devuelven una nueva con
Aviso: Los métodos de la clase Stri ng no modifican la cadena contenida,
las modificaciones deseadas.

Ejercicio 3.13:
pasados en línea son iguales o no.
Escriba un programa que determine si los dos primeros argumentos
comparar cadenas, se usa el método
Planteamiento: Los dos primeros argumentos son args[OJ y arg[l]. Para
equa l s ( ) que devuelve un booleano indicando si son iguales.

Solución:
class Cadena4

public static void main (String args[J) {


if ( args[O J.equal s(args[ l])){
System.out.println("Son iguales ."):
}else{
System.out.println("NO son iguales ."):
Ampliación de clases

Comentario: Se podría implementar alternativamente, usando la función compareTo(), que devuelve un O si


ambas cadenas son iguales. La sentencia quedaría:

if ( args[OJ.compareTo(args[l]) ==O){
System. out. println( "Son iguales."):
}else{
System. out .println( "NO son igual es."):

Aviso: Un error muy común es usar el operador "==" para comparar objetos. Los objetos son referencias, es
decir, al comparar con "==" se está evaluando si las referencias apuntan al mismo sitio. El caso de Stri ng es
más delicado porque, por razones de eficiencia, las cadenas con el mismo valor apuntan al mismo objeto. El
siguiente programa:

public static void main(String args[J)


String sl = "hola":
String s2 = "hola":

if (sl = s2) {
System.out.println("Son iguales."):
} else {
System.out.println("NO son iguales."):

imprime por pantalla el mensaje "Son igual es . ", con lo que parece que "==" funciona bien. Se aconseja usar
siempre el método equa 1s ( ).

Aviso: En este programa habría que comprobar que el array de argumentos tiene al menos dos.

Ejercicio 3.14:
Escriba un método que dado un objeto de la clase String cuente diferentes tipos de caracteres. En particular,
el método imprimirá el número de letras, dígitos y espacios en blanco de la cadena. Haga un programa que
escriba el conteo de la cadena "Hola, vivo en Marquina 123, 5-7").

Planteamiento: El envoltorio Character tiene funciones que trabajan sobre caracteres. Se usarán los
métodos i sletter(), i sOigit() e i sWhitespace() para comprobar el tipo de un carácter. Para examinar
cada carácter del Stri ng, se recorre con un bucle for. Pero el bucle for espera una secuencia de un tipo
base. Con el método toCharArray() de la clase Stri ng, se puede obtener un array de caracteres a partir de
un Stri ng.

Parámetros: Un Stri ng con la cadena a procesar.

Valor de retomo: El método escribe en pantalla, por lo que el valor de retomo se especifica como voi d.

Solución:
class Contarletras
static void conteo (String s)
int numletras = O:
int numDígitos = O;
int numEspacios = O:
Programación en Java 2

for (char c: s. toCharArray()) {+ -- -- --


-- -- -- -
if (Character.isletter(c)){
numletras++; Se obtiene un array de caracteres \
}else if (Character. isDigit(c)){ para que el for pueda recorrerlo. '
numOígitos++;
}else if (Character.isWhitespace(c)){
numEspacios++:
Cada tipo de carácter se contabíliza
en el apartado correspondiente.

etras):
System.out.println ("Número de letras "+ numl
tos" + numO ígitos):
System.out.println ("Número de dígi
ios "+ numE spacios):
System.out.println ("Número de espac

public stati c void main (String args[])


{
conteo ("Hola. vivo en Marquina 123. 5-7")
;

como sigue:
Comentario: La salida del programa quedaría

Número de letra s 18
Número de dígitos 5
Número de espacios 5
) de la clase
a sería utilizando el método charAt(int index
Otra forma de hacer el recorrido por la caden
. El bucle se escribiría así:
String, que devuelve el carácter en la posición index

4,1(-----------[[
for (int i = O: i < s.length(); i++)
{
RecorridoconcharAt enelString. ))
char c = s.charAtO:

if (Character.isletter(c))
numletras++:
}else if (Character.isDigit(c)) {
numOígitos++;
}else if (Character.isWhitespace(c)) {
numEspacios++:

y de legib ilidad .
Esto no suele usars e por razon es de efici encia

Ejercicio 3.15: todas las vocales


elve otro objeto String en el que se cambian
Escriba un método que, dado un String, devu
minúsculas del original por la letra 'a'.
Com o se pide
Plan team iento : El méto do rep 1ace() de la clase
Stri ng sustituye un carácter por otro en una cadena.
ta a sustit uir por la letra 'a'.
ivamente, cada vez con una vocal distin
camb iar varias letras, se invoc a rep1ace ( ) suces

Pará metr os: El objet o Stri ng a modificar.


Ampliación de clases

Valor de retomo: Un valor String con las vocales sustituidas.

Solución:
String sustituye (String s)
s = s.replace('e', 'a');
s = s.replace('i'. 'a'): +-----------11EJoibietoorioirnaln<>sem0<lffic.:1. II
s = s.replace('o'. 'a'):
s = s.replace('u', 'a');

return s;

Aviso: Sólo hay que tener cuidado con no sustituir la vocal 'a', pues es innecesario. El método no sustituye
letras acentuadas, etc.

Ejercicio 3.16:
Escriba un método que, dada una cadena de caracteres, devuelve la mitad inicial de la cadena. Escriba un
programa que pruebe el método con las cadenas "Hola que tal" y "Adiós".

Planteamiento: El método substri ng( i ni ci o. final) toma dos números y devuelve una cadena que comien-
za en inicio y termina en final. Las cadenas comienzan en O, y length()/2 da el punto medio. Luego se
escribe un ma in ( ) para probar con las cadenas propuestas por el enunciado.

Parámetros: La cadena a dividir, de tipo String.

Valor de retorno: Un objeto de la clase Stri ng, con el resultado.

Solución:
class ParteAlMedio {

static String parteAlMedio(String s) {


return s.substring(O. s.length() / 2): •(-----4[1[ Seempiezaacontarporo. ]j

public static void main(String args[])


String s:

s = "hola que tal":


System.out.println(s + " " + parteAlHedio(s)):

s = "Adiós":
System.out.println(s +" "+ parteAlMedio(s)):

Comentario: Este programa escribe por pantalla:

hola q
Ad
Programación en Java 2

Ejercicio 3.17:
sustituya todas las ocurrencias del texto "es" por
Escriba un método que, dada una cadena de caracteres,
los grupos de dígitos por un único carácter asteris-
"no por". Escriba un segundo método que sustituya todos
ueno9 00" el prime r método debe devolver "no
co, es decir, si la cadena de caracteres es "estol 234es 5678b
er "esto*es*bueno*". Escriba el programa que
portol 234no por5678bueno900" y el segundo debe devolv
permita comprobar que funciona correctamente.
una expresión regular y la cadena porla que desea
Plante amien to: El método rep lace (Stri ng. Stri ng) toma
el primer parámetro se utiliza una cadena de caracte-
sustituir cualquier ocurrencia de la expresión regular. Si
res se tomará como tal cuando coincida completamente.
os, por tanto el parámetro será de la clase
Parámetros: La cadena sobre la que se quiere aplicar los cambi
String.

Valor de retom o: El objeto de la clase Stri ng modificado.

Solución:
public class UsoString

public static String cambiaEs(String texto){


return texto.replaceAll("es". "no por"):

public static String cambiaDigitos(String texto){ Utiliza una expresión regular que
return texto. replaceAll( "\ \d+". "*"); ...,"-- --11 significa un dígito o más.

public static void main(String[J args) {


String textoüriginal = "estol234es5678bueno900";

System.out.println(cambiaEs(textoüriginal)):
System.out.println(cambiaDigitos(textoüriginal)):

r consulte la documentación de la clase Pattern.


Come ntario : Para ver cómo definir una expresión regula
duplicar la barra hacia atrás. El resultado de este
Fíjese que para escribir la expresión regular \d+ hay que
programa es:

no porto1234no por5678bueno900
esto*es*bueno*

Ejerci cio 3.18:


cuántas veces aparece la misma en dicho texto.
Escriba un método que, dada una cadena de caracteres, cuente
de cuyo nombre no puedo acordarme", si se cuenta
Por ejemplo, para la cadena "En un lugar de la mancha,
s palabras acaban en o, debería indicar que son 3.
cuántas veces aparece "o ", o dicho de otra forma, cuánta
de caracteres se puede utilizar el método i ndexOf ( )
Plante amien to: Para buscar un texto dentro de una cadena
do dentro del original. Para busca rlo más de una vez
que devue lve la posici ón en que empie za el texto busca
permi te indicar a partir de qué posición empez ar a
se usa el mismo método donde el segundo argumento
buscar.
Ampliación de clases

Parámetros: La cadena en la que se quiere contar cuántas veces aparece el texto y el texto que se quiere
buscar. Por tanto, se necesitan dos objetos de la clase Stri ng.

Valor de retomo: El número de veces que aparece el segundo argumento en el primero, es decir, un valor del
tipo int.

Solución:
public class UsoString

public static int cuentaVeces(String texto. String busca){


int pos= O;
int veces= O;
while((pos = texto.indexOf(busca. pos))>= O){
pos+= busca.length();
veces++;

return veces;

public static void main(String[J args) {

System.out.println("Veces que aparece \"o \": " +


cuentaVeces("En un lugar de la mancha. de cuyo nombre no puedo acordarme".
"o ")):

Ejercicio 3.19:
Escriba un método que cuente el número de palabras que contiene un texto.

Planteamiento: Para contar el número de palabras se puede utilizar de la clase String el método split() que
permite dividir una cadena de caracteres en fragmentos de acuerdo con una expresión regular, devolviendo un
array de String con todos los fragmentos del texto original. Para dividir por palabras, se utiliza como expresión
regular " +", un espacio y un signo más, que significa un espacio una o más veces. Antes de llamar a sp l i t ( ) se
llamará al método trim() para eliminar los espacios en blanco que pueda haber al principio y al final del texto.

Parámetros: La cadena de la que se quiere contar el número de palabras que tiene.

Valor d.e retomo: El número de palabras de la cadena de caracteres, es decir, un valor del tipo i nt.

Solución:
public class UsoString

public static int cuentaPalabras(String texto){


String[J palabras= texto.trimO .split(" +"):-<t:---- -11 Utiliza una expresión regular que
significa un espacio o más.
return palabras.length;

public static void main(String[J args) {


System.out.println("Número de palabras: "+
Programación en Java 2

e no puedo acordarme"));
cuentaPalabras("En un lugar de la mancha. de cuyo nombr

Ejercicio 3.20: ama


una perso na celebr a su cumpleaños en lunes. El progr
Escriba un progr ama que determine cuántas veces vida y el total de ellas.
en lunes los prime ros 40 años de su
debe imprimir las fechas en que el cumpleaños cae
el 4 de abril de 1965 y tiene 40 años.
Suponga el ejemplo de una perso na que nació

se construye la fecha deseada. Con un bucle for se


Planteamiento: Mediante la clase GregorianCalendar,
método ro 11 ( ) . Para cada fecha, se obtiene el día de la
recorren los 40 años, añadiendo cada año mediante el
en cuyo caso se imprime la fecha en formado día/mes/
semana y se compara si es lunes (Calendar .MONDAY),
años. Además, se proporcionará un contador

Solución:
import java.util.GregorianCalendar:
import java.util.Calendar:

public class CuentaDías {

public static void main(String[J args) {


int cuentalunes = O:
ar.APRIL. 4):
GregorianCalendar ge= new GregorianCalendar(l965. Calend

for (int i = O: i < 40; i++) {


ge. rol 1( Calendar. YEAR. 1): -41 (-- --- --- --- --- --- ((1 Avanza un año. ]]

if (gc.get(Calendar.OAY_OF_WEEK) = Calendar.MONDAY)
{
cuentalunes++:
) +
System.out.println("El "+ gc.get (Calendar.DAY_OF_MONTH
"/" + (gc.get (Calendar.MONTH)+l) + ""'. ,_ _ _ ___,
"/" + gc.get (Calendar.YEAR) + 1
" es l unes" ) : Los meses se representan desde O
(enero) a 11 (diciembre).

cuentalunes +" lunes"):


System.out.println ("El cumpleaños se celebra en"+

Comentario: La salida del programa es:

El 4/4/1966 es lunes
El 4/4/1977 es lunes
El 4/4/1983 es lunes
El 4/4/1988 es lunes
El 4/4/1994 es lunes
El 4/4/2005 es lunes
El cumpleaños se celebra en 6 lunes
Ampliación de clases

Aviso: El bucle for primero incrementa el año (método ro 11) porque se considera que el día de nacimiento no
se celebra el cumpleaños.
Hay que tener cuidado con los meses, pues Calendar considera el Ocomo enero y el 11 como diciembre. Si
se escribe GregorianCalendar(l965. 4. 4), se especifica el 4 de mayo de 1965.

IMPORTAC IÓN ESTÁTICA

Ejercicio 3.21:
Escriba un método que dado un ángulo en radianes, lo escriba en pantalla en grados, así como los valores del
seno, el coseno y la tangente. Las funciones de Math han de importarse de forma estática. Haga un programa
que imprima los valores de esas tres funciones para los valores O, 11f4, 1t:/2, y 11: en radianes.

Planteamien to: Al importar de forma estática, no se requiere anteponer el nombre de la clase. Entonces se
importa toda la clase Math. El ángulo, cuando no se dice nada, se supone que está en radianes. El método
toDegrees ( ) lo pasa a grados.

Parámetros: Un doub le con el ángulo.

Valor de retorno: El resultado del método es escribir en pantalla. El método no necesita devolver ningún valor
de retorno por lo que se utiliza la cláusula voi d.

Solución:
Importación estática de todos los
import static java.lang.Math.*; 1,~---~1
métodos de la clase Math.
public class Trigonometría {

static void funciones(double alfa)


System.out.println(toDegrees(alfa) +" "+ sin(alfa) +
"" + cos(alfa) +" "+ tan(alfa));

public static void main(String args[])


funciones (O) ;
funciones(PI / 4);
funciones(PI / 2);
funciones(PI);

Comentario: La salida del programa quedaría como sigue:

O.O O.O 1.0 O.O


45.0 0.7071067811865475 0.7071067811865476 0.9999999999999999
90.0 1.0 6.123233995736766E-17 l.633123935319537El6
180.0 l.2246467991473532E-16 -1.0 -l.2246467991473532E-16

Aviso: El código queda más simple, pero no siempre mejora la legibilidad del programa, porque se olvida de
dónde proceden los métodos.
Estructuras de control

4. 1 ESTRUCTURAS DE SELECCIÓN
4. 1. 1 Estructura i f
La estructura i f se escribe de la siguiente forma:

if (condición)
sentencias

La condición se escribe siempre entre paréntesis. La condición es una expresión que evalúa un valor de tipo
boolean (booleano) como las expresiones aritmético-lógicas vistas en el Capítulo l. Si la condición devuelve se
ejecuta el conjunto de sentencias dentro del bloque del i f.
Un bloque de sentencias está delimitado por llaves, por lo que la estructura i f está asociada a todo el bloque de
sentencias. Si la estructura i f lleva asociada sólo una sentencia, se puede poner sin llaves, pero ,~:rec~ll;li!:!Q~a
añadirlas aunque sea redundante. Esto mismo es aplicable al resto de estructuras que se describen en las siguientes
secciones.
Por ejemplo, suponga que en un programa existe una variable velocidad de tipo i nt cuyo

if (velocidad<= 90){
System.out.println("La velocidad es menor o igual que 90.");

Como la condición vale true, se escribe por pantalla el mensaje de la sentencia dentro del blpque if.

4. 1. 2 Estructura i f-e l se
La estructura i f-e l se se escribe de la siguiente forma:

if (condición)
sentencias
Programación en Java 2

} else {
sentencias

, es decir, se evalúa
La condición es una expresión lógica como en la sección anterior. Si la condición es verdadera
continuac ión del i f. Seguidamente, el
a true, se ejecuta la sentencia o bloque de instrucciones que se encuentra a
mente posterior a toda esta estruc-
programa continuaría su ejecución de forma secuencial con la sentencia inmediata
o el bloque de sentencia s que se
tura. Si, por el contrario, la condición se evalúa a false, se ejecuta la sentencia
encuentra a continuación del e1se y el programa continuaría su ejecución.
valor es 110:
Por ejemplo, suponga que en un programa existe una variable velocidad de tipo int cuyo

if (velocidad<= 90) {
System.out.println("La velocidad es menor o igual que 90."):
} else {
System.out.println("Velocidad excesiva. Supera los 90."):

4. 1. 3 Operador condicional
la condición a la izquier-
El operador condicio nal(?:) está relacionado con la estructura i f-el se. El operador evalúa
haya entre el? y el : . Si la condición
da del símbolo? . Si la condición vale true devuelve el valor de la expresión que
para escribir el mayor de tres números
vale false se devuelve el valor de la expresión tras el símbolo : . Por ejemplo,
se puede escribir.

System.out.print("El número mayor es el de valor"):


System.out.println(a > b? a : b):

4.1.4 Estructura switch


caso opcional default. La
La estructura switch consta de una expresión y una serie de etiquetas case con un
sentencia switch se escribe de la siguiente forma:

switch (expresión){
case valorl:
sentencias:
break:
case valor2:
case valor3:
sentencias:
break:

default:
sentencias:
break:
Estructuras de control

La expresión, que es obligatorio que esté entre paréntesis, tiene que evaluarse a un
rado o un boolean. A continuación, en cada case aparece un valor que únicamente
es decir, una expresión cuyo valor se puede conocer antes de empezar a ejecutar el
expresión del switch. Después de cada case se puede poner una única sentencia o un
asociados en cada case se comparan en el orden en que están escritos. Cuando se
sentencias se utiliza la sentencia break que hace que el control del programa termine e
la sentencia que se encuentre después de esta estructura. Si no coincide el valor de ningún
expresión, se ejecuta la parte default.
Si ningún valor de los case coincide con el resultado de la expresión y la parte default
opcional, no se ejecuta nada de la estructura switch.
Por ejemplo, suponga que desea conocer el número de días de un mes dado. Un switch es
seleccionar cómo calcular cuántos días le corresponden a cada mes.

public class DíasDelMes {


enum Mes {Enero. Febrero. Marzo. Abril.
Mayo. Junio, Julio. Agosto.
Septiembre. Octubre. Noviembre. Diciembre}

public static void main(String[] args) {


int días;
Mes mes= Mes.Noviembre:
switch (mes) {
case Abril:
case Junio:
case Septiembre:
case Noviembre:
días= 30;
break;
case Febrero: // no se conoce el año
días= 28;
break;
default:
días= 31:
break:

System.out.println("El mes " +mes+ " tiene " +días+ " días.");

4. 2 ESTRUCTURAS DE REPETICIÓN
4. 2. 1 Estructura whi 1e
La estructura de repetición whi le sigue el siguiente esquema:

while (condición){
sentencias
Programación en Java 2

la condi-
La condición tiene que estar obligatoriamente entre paréntesis. La condición es una expresión lógica. Si
la ejecución de las instruccion es
ción vale true, se ejecutan las sentencias que componen el bucle. Cuando concluye
a ejecutar las instruccion es
del bucle se vuelve a evaluar la condición. De nuevo, si la condición es cierta se vuelven
el programa
del bucle. En algún momento la condición valdrá false, en cuyo caso finaliza la ejecución del bucle y
continúa ejecutándose por la sentencia que se encuentre a continuación de la estructura whi le.
primo.
Por ejemplo, el siguiente método devuelve true si el número introducido por parámetro es un número

public boolean primo(int numero){


int divisor=2;
boolean primo= true;

while ((divisor* divisor<= numero) && primo) {


if (numero% divisor= O)
primo = false:
divisor++;

return primo:

4. 2. 2 Estructura do-whi le
La sentencia do-whi le tiene la siguiente estructura:

do {
sentencias
} while (condición);
la
Cuando en un programa se llega a una estructura do-wh i l e se empiezan a ejecutar las sentencias que componen
vale true, se ejecutan de nuevo las
estructura. Cuando se terminan de ejecutar se evalúa la condición. Si la condición
vale false.
sentencias que componen la estructura. El bucle deja de repetirse cuando, tras evaluarse la condición, ésta
Como ocurría con la estructura whi le es necesario que dentro del bucle, en algún momento, la condición valga false
para evitar que el bucle se ejecute indefinidamente.
Al
Suponga que se desea realizar un programa que solicite al usuario un número entre O y 100, ambos inclusive.
introducido no está dentro del intervalo,
terminar debe imprimir por pantalla el número introducido. Si el número
debe dar un mensaje de error. Un posible programa sería el que se muestra en el siguiente ejemplo:

import java.util.Scanner:

public class PedirNumero {


public static void main(String[J args) {
int numero;
String linea;

Scanner teclado= new Scanner(System.in);

do {
System.out.print("Introduzca un número entre O y 100: ");
Estructuras de control

numero= teclado.nextlnt():
} while (numero< O 11 numero> 100):

System. out. pri nt l n("El número introducido es: " + numero) ;

4. 2. 3 Estructura for
La estructura for tiene dos formas. La más habitual es:

for (inicialización: condición: actualización){


sentencias

Los elementos de que consta son los siguientes:

.. La i ni ci ali zaci ón es una sentencia que permite inicializar el bucle, puede ser la
de las variables que se utilizan en el bucle. Esta sentencia de inicialización se ejecuta ún!ícairneitttt':l
la primera ejecución del bucle.
.. La candi ci ón es la condición para continuar la ejecución del bucle. La condición se evaláa
empezar a ejecutar el bucle. Si la condición es cierta, se ejecutan las sentencias del
.. Después de ejecutar las sentencias del bucle y antes de volver a evaluar la condición se ejecuta la
ci ón. Esta parte se suele utilizar para modificar el valor de las variables que forman parte dé la ce1!1di1bi~1n.

Todos los elementos que se acaban de describir del bucle for son opcionales, es decir, pueden
ejemplo, para escribir por pantalla 5 veces el mensaje "Hola a todos" con el número de vez, se puede escribir:

for (int i = O: i < 5: i++) {


System.out.print(i + 1):
System.out.println(" Hola a todos."):

La segunda estructura de un bucle for es la siguiente:

for (variable : estructura){


sentencias

donde la variable indicada entre paréntesis, que se puede declarar en ese mismo lugar, va toman~o el v~or de tpdas
las variables de la estructura indicada, repitiéndose el bucle para todos los valores. Por ejemplo, para escribir por
pantalla todos los elementos de un array de String se puede escribir:

for(String a : miArrayDeString){
System.out.println(a):
Programación en Java 2

4.2.4 Uso de las estructura s de repetición


Es importante utilizar el tipo de bucle más apropiado en cada parte de un programa. En la Tabla 4.1 se pueden ver las
reglas a tener en cuenta para usar una u otra estructura de repetición.

Tabla 4.1. Reglas de uso de las estructuras de repetición.

do-while Si la parte de ejecución del bucle se ha de hacer al menos una vez.


for Se sabe el número de veces que se ha de repetir el bucle.

Si utilizar la inicialización y la actualización del bucle permite escribir el código


de forma más clara.

Se realiza un recorrido en una estructura de almacenamiento.

Si la estructura de almacenamiento se va a recorrer completa realizando operacio-


nes con sus valores, se utilizará la segunda versión del far.

4.3 ESTRUCTURAS DE SALTO


4.3.1 Sentencia break
La sentencia break se utiliza para terminar inmediatamente la ejecución de una estructura de repetición o de un
switch. Una vez se ha ejecutado la sentencia break, la ejecución continúa tras la estructura de repetición o switch
donde se ha ejecutado break.

4.3 .. 2 Sentencia continue


La sentencia continue únicamente puede aparecer dentro de una estructura de repetición. El efecto que produce es
que se deja de ejecutar el resto del bucle para volver a evaluar la condición del bucle, continuando con la siguiente
iteración si el bucle lo permite.

4.4 EXCEPCIONES
4.4. 1 Captura
La estructura de captura de excepciones es try-catch-fi na l ly.

try {
sentencias
catch (ClaseException e) {
sentencias
catch (ClaseException e)
Estructuras de control

sentencias
catch (ClaseException e)
sentencias
finally {
sentencias

En la estructura try-catch-fi na l ly, la parte catch puede repetirse tantas veces como excepciones di:fei;entes se
deseen capturar. La parte fina 11 y es opcional y sólo puede aparecer una vez.
Para ver cómo funciona esta estructura en el siguiente ejemplo se presenta un programa que pide al Wl
número entre Oy 100, con manejo de excepciones.

import java.io.*;

public class PedirNumero2


public static void main(String[J args) {
int numero= -1:
int intentos= O:
String linea;

BufferedReader teclado= new BufferedReader(new InputStreamReader(System.in));

do {
try{
System.out. print( "Introduzca un número entre O y 100: ");
linea = teclado.readline();
numero= Integer.parseint(linea);
}catch(IOException e){
System.out.println("Error al leer del teclado.");
}catch(NumberFormatException e){
System. out. pri nt l n( "Debe introducir un número entero entre Oy 100. ");
}finally{
intentos++;

} while (numero< O 11 numero> 100);

System.out.println("El número introducido es: " + numero);


System.out.println("Numero de intentos: "+ intentos);

En este programa se pide repetidamente un número utilizando una estructura do-whi le, mientras el número sea
menor que Oo sea mayor que 100. Dentro de esta estructura do-whi le es donde se solicita el número al usuario. El
método readl i ne() de la clase BufferedReader puede lanzar la excepción IOExcepti on. Si no se hace nada con ella,
cuando se produce el programa termina. Así mismo, la llamada al método parseint() puede lanzar la excepción
NumberFormatException. Esta excepción se lanza cuando parseint() no puede convertir el texto en un número
entero.
Cuando se produce una excepción se compara si coincide con la excepción del primer catch. Si no coincide se
compara con la excepción del segundo catch, y así sucesivamente. Cuando se encuentra un catch cuya excepción
coincide con la que se ha lanzado, se ejecuta el bloque de sentencias de ese catch.
Programación en Java 2

Si ningún bloque catch coincide con la excepción lanzada, dicha excepción se lanza fuera de la estructura
try-
catch- fina 11 y. Si no se captura en el método, se debe lanzar delegándola. Para ello debe declararlo en la cabecera del
método.
El bloque f i na 11 y se ejecuta tanto si t ry terminó normalmente como si se capturó una excepción en algún
bloque
catch. Es decir, el bloque final l y se ejecuta siempre.

4.4.2 Delegación
Se produce una delegación de excepciones cuando un método utiliza una sentencia que puede generar una
excepción,
pero la excepción que se puede generar no la captura y la trata, sino que la delega a quien le llamó.
Para ello,
simplemente, declara en la cabecera que la excepción que se puede producir durante la ejecución del método
la puede
generar dicho método de la siguiente forma:

public class Alumno {

public int leeAño(BufferedReader lector) throws IOException. NumberFormatException {


String linea= teclado.readline();
Return Integer.parseint(linea);

De esta forma si al leer del Buffered.Reader que recibe en el parámetro se encuentra con algo que no es
un entero,
se generará una excepción y en lugar de devolver el entero, se enviará la excepción a donde se llamó a
este método.

4.4. 3 Definición de excepciones de usuario


Una excepción es una clase. Para crear una excepción se deriva de la clase Except ion. Para más detalles
sobre
derivación de clases y herencia véase el Capítulo 5. Si se desea tener una excepción que indique un
año fuera de
rango, se puede hacer de la siguiente forma:

public class AñoFueraDeRangoException extends Exception


public AñoFueraDeRangoException(String texto) {
super(texto);

Al crear la excepción, se ha añadido un constructor que acepta un String. De esta forma se puede
añadir un
mensaje al crear la excepción que dé detalles adicionales sobre el problema que ha generado la excepción.
A partir de
este momento se dispone de una excepción que se puede lanzar cuando sea necesario.

4.4.4 lanzam iento de excepciones de usuario y redefin kión


Si se dispone de la excepción declarada en el apartado anterior en una posible clase Alumno,
el método
ponAñoDeNaci miento() quedaría:

public class Alumno


Estructuras de control

public void ponAñoDeNacimiento(int año) throws AñoFueraDeRangoException {


if (año< 1900 11 año> 1990)
throw new AñoFueraDeRangoException("Demasiado joven o demasiado
añoDeNacimiento = año:

De esta forma, si al llamar al método se utiliza un valor de año anterior a 1900 o


asigna ese año al alumno, sino que lanza una excepción indicando que ese año no tien
lanzar una excepción se utiliza la sentencia throw con el objeto excepción que se desea
mismo paso la creación y lanzamiento de la excepción.
Para capturar dicha excepción desde donde se llamó al método ponAñoDeNacimientoO,
siguiente forma:

try {

alumno.ponAñoDeNacimiento(unAño);

catch (AñoFueraDeRangoException e) {
//manejarla excepción de poner el año

4.5 ASERCIONES
4.5.1 Aserciones como comprobación de invariantes
Una aserción tiene la siguiente sintaxis:

assert condicion;

assert condicion : mensaje:

donde la condición es una expresión lógica que debe cumplirse en el momento en que se
condición no se cumple, el programa termina con un error. Tras el operador dos puntos puede.pon~~ un Sttmg .con
el mensaje que se devuelve como error.

4.5.2 Aserciones como precondidones


Como convenio, las precondiciones de un método público en Java es preferible que se comprueben mediante una
condición y lancen la excepción I 11 ega 1ArgumentExcept ion o la excepción apropiada de acuerdo con el error encon-
trado, como en el siguiente ejemplo:

public void ponEdad(int edad) throws Exception{


Programación en Java 2

if(edad < O 11 edad> 150)


throw new Exception("Edad no válida."):

I Iresto del método

Sin embargo, en un método no público sí se puede sustituir esa comprobación, en muchos casos redundante, por
una comprobación que asegure que el método se utiliza de forma consistente en la clase, como en el siguiente ejemplo.

prívate void fijaintervalo(int intervalo){


assert intervalo> O && intervalo<= MAX_INTERVALO:

//resto del método

Si al llamar al método fijalntervalo(), el valor del parámetro no está dentro del intervalo establecido, al no
cumplirse la condición de la aserción, el programa terminará con un error.

4.5.3 Aserciones como postcondiciones


En este caso sí se recomienda el uso de aserciones para la comprobación de las postcondiciones de un método, pues se
supone que el método se encuentra bien implementado. En este caso, el uso de postcondiciones permite asegurar que
se cumplen en todas las ejecuciones que se hacen del método.

public void ordenar(int[J datos){


//algoritmo de ordenación

boolean desordenado= false:


for(int i=O: i<datos. length-1: i++)
desordenado= desordenado 11 datos[iJ>datos[i+l]:
assert !desordenado : "Ordenar: array no ordenado.":

El método anterior es un método de ordenación de números enteros. Al finalizar el método debe asegurarse que el
array termina con todos sus datos ordenados. Como esta comprobación es compleja se ha añadido unas líneas de
código que hacen la comprobación. En la aserción se ha utilizado la versión completa, en la que si la condición no se
cumple, se evalúa la parte que hay tras los dos puntos y con ello se construye el error AsertionError. Cuando el
programa termina, aparecerá en pantalla el mensaje que se ha puesto tras los dos puntos.

4.5.4 Aserciones como invariantes


Las aserciones como invariantes permiten comprobar en cualquier parte del código de un método que se cumplen los
invariantes establecidos. Su uso es el mismo que para las postcondiciones.
Estructuras de control

ESTRUCTURAS DE SELECCIÓN

Ejercicio 4.1:
Escriba un método, de nombre mayorDeEdad, que reciba una edad como entero por parámetro y muestre un
mensaje por pantalla si es mayor de edad o no.

Planteamiento: El método debe escribir "La persona es mayor de edad" o "La persona no es mayor de edad".
Se utilizará la estructura i f para añadir dentro del mensaje de salid