libro java2 ver 3

409
UNIVERSIDAD NACIONAL DEL CENTRO DEL PERÚ PROGRAMACION CON JAVA 2 ABRAHAM GAMARRA MORENO JOB DANIEL GAMARRA MORENO JUAN GAMARRA MORENO

Upload: juan-carlos-salazar-quispe

Post on 09-Dec-2015

179 views

Category:

Documents


13 download

DESCRIPTION

libro de programacion en java

TRANSCRIPT

UNIVERSIDAD NACIONAL DEL CENTRO DEL PERÚ

PROGRAMACION CON JAVA 2

ABRAHAM GAMARRA MORENO

JOB DANIEL GAMARRA MORENO

JUAN GAMARRA MORENO

CONTENIDO

INTRODUCCION........................................................................................................................................... 1

CAPITULO UNO............................................................................................................................................ 3

FUNDAMENTOS DEL JAVA....................................................................................................................... 3 1.1. ¿QUE ES JAVA?............................................................................................................................ 3 1.2. HISTORIA DE JAVA .................................................................................................................... 4 1.3. ¿POR QUÉ APRENDER JAVA?................................................................................................... 5 1.4. JAVA(TM) 2 SDK, STANDARD EDITION VERSION 1.4.0. ..................................................... 6

1.4.1. INSTALACION DEL JAVA(TM) 2 SDK, STANDARD EDITION VERSION 1.4.0.................... 6 1.4.2. ESTRUCTURA DE ARCHIVOS DEL JAVA 2 SDK .................................................................. 6

1.5. EL EDITOR JCREATOR............................................................................................................. 10 1.5.1. REQUERIMIENTOS DEL SISTEMA ...................................................................................... 10 1.5.2. INSTALACION DE JCREATOR.............................................................................................. 10

1.6. ESTRUCTURA DE UN PROGRAMA EN JAVA....................................................................... 11 1.7. COMO CREAR UN PROGRAMA.............................................................................................. 12

1.7.1. CREACION DE UNA APLICACIÓN EN EL JCREATOR....................................................... 12 1.8. USO DE COMENTARIOS .......................................................................................................... 14 1.9. PALABRAS CLAVES................................................................................................................. 15 1.10. IDENTIFICADORES .................................................................................................................. 16 1.11. VARIABLES ............................................................................................................................... 16 1.12. TIPOS DE DATOS....................................................................................................................... 17

1.12.1. TIPOS DE DATOS PRIMITIVOS ....................................................................................... 17 1.12.2. TIPOS DE DATOS REFERENCIA ..................................................................................... 18

1.13. LITERALES................................................................................................................................. 19 1.14. OPERADORES............................................................................................................................ 20

1.14.1. OPERADORES ARITMÉTICOS......................................................................................... 21 1.14.2. Operadores Relacionales.................................................................................................... 21 1.14.3. Operadores Condicionales ................................................................................................. 22 1.14.4. Operadores Lógicos y de Corrimiento (shift) ..................................................................... 22 1.14.5. Operadores de Asignación.................................................................................................. 23 1.14.6. Otros Operadores ............................................................................................................... 23

1.15. ENTRADA Y SALIDA BASICA ................................................................................................ 24 1.15.1. FLUJOS DE ENTRADA DE BYTE Y CHAR (ENTRADA POR EL TECLADO) ................ 27 1.15.2. FLUJOS DE SALIDA DE BYTE Y CHAR (SALIDA POR EL MONITOR)......................... 28 1.15.3. USO DE EXCEPCIONES EN LA ENTRADA Y SALIDA DE DATOS................................ 30

1.16. ENTRADA Y SALIDA UTILIZANDO TIPOS DE DATOS PRIMITIVOS ............................... 32 1.16.1. FLUJOS DE ENTRADA A TRAVES DE BUFFEREDREADER (ENTRADA POR EL TECLADO) 33 1.16.2. FLUJOS DE SALIDA A TRAVÉS DE LA SUBCLASE PRINTSTREAM (SALIDA POR EL MONITOR) 34 1.16.3. MANEJO DE LOS TIPOS DE DATOS PRIMITIVOS ........................................................ 35

1.17. LA CLASE MATH....................................................................................................................... 44 1.18. EXPRESIONES, SENTENCIAS Y BLOQUES ....................................................................................... 48 1.19. SENTENCIAS DE CONTROL DE FLUJO ................................................................................. 49

1.19.1. Sentencia if.......................................................................................................................... 49 1.19.2. Anidamiento de sentencias if .............................................................................................. 52 1.19.3. Sentencia switch.................................................................................................................. 61 1.19.4. Sentencia while ................................................................................................................... 68 1.19.5. Sentencia do-while.............................................................................................................. 85 1.19.6. SENTENCIA for.................................................................................................................. 93 1.19.7. SENTENCIA break ........................................................................................................... 101 1.19.8. SENTENCIA continue....................................................................................................... 102 1.19.9. break etiquetado ............................................................................................................... 104

ii Mg. ABRAHAM GAMARRA MORENO

CAPITULO DOS .........................................................................................................................................107

ARREGLOS (ARRAY) Y CADENAS .......................................................................................................107 2.1. DECLARAR Y CREAR UN ARRAY ........................................................................................107 2.2. INICIALIZAR Y USAR LOS ELEMENTOS DEL ARRAY .....................................................108 2.3. ARRAYS MULTIDIMENSIONALES.......................................................................................111 2.4. GESTIÓN DE CADENAS..........................................................................................................114

2.4.1. Constructores .........................................................................................................................116 2.4.2. Sintaxis de cadenas especial ..................................................................................................116 2.4.3. Extracción de caracteres........................................................................................................119 2.4.4. Comparación..........................................................................................................................120 2.4.5. otros métodos .........................................................................................................................122 2.4.6. LA CLASE String....................................................................................................................123

CAPITULO THREE....................................................................................................................................131

MÉTODOS CREADOS POR EL USUARIO............................................................................................131 3.1. DEFINICIÓN DE UN MÉTODO ...............................................................................................132

CAPITULO CUATRO ................................................................................................................................139

CLASES Y PROGRAMACION ORIENTADO A OBJETOS ................................................................139 4.1. ATRIBUTOS ..............................................................................................................................140 4.2. COMPORTAMIENTO......................................................................................................................140 4.3. UNA CLASE EN JAVA .............................................................................................................141

4.3.1. LOS MIEMBROS DATO ........................................................................................................141 4.3.2. LAS FUNCIONES MIEMBRO ...............................................................................................142 4.3.3. Los conStructores...................................................................................................................147

4.4. LOS OBJETOS ...............................................................................................................................149 4.4.1. Acceso a los miembros ...........................................................................................................150

4.5. LA VIDA DE UN OBJETO................................................................................................................151 4.6. IDENTIFICADORES........................................................................................................................155 4.7. MODIFICADORES DE ACCESO A LOS MIEMBROS DE UNA CLASE ........................................156

4.7.1. Miembros públicos .................................................................................................................157 4.7.2. Miembros privados.................................................................................................................157 4.7.3. Por defecto (a nivel de paquete).............................................................................................157

4.8. EJEMPLOS DEL USO DE CLASES..........................................................................................165 4.9. SOBRECARGA DE UN MÉTODO ..........................................................................................184 4.10. REFERENCIA THIS ....................................................................................................................187

4.10.1. UTILIZACION DE this EN UN CONSTRUCTOR ............................................................189 4.10.2. this Y MÚLTIPLE CONSTRUCTORES.............................................................................189 4.10.3. Otra vez this.......................................................................................................................192

4.11. ARREGLO DE OBJETOS..........................................................................................................196 4.12. VARIABLES DE CLASE (VARIABLE ESTÁTICA) ...............................................................199

4.12.1. ACCEDIENDO A LAS VARIABLES DE CLASE...............................................................200 4.13. Y LAS VARIABLES GLOBALES ???.......................................................................................202 4.14. CONSTANTES: OTRO EJEMPLO DE VARIABLES DE CLASE...........................................203 4.15. EJEMPLOS DE VARIABLES DE CLASE ................................................................................203 4.16. MÉTODOS DE CLASE (MÉTODOS ESTÁTICOS).................................................................206

4.16.1. Sin this ...............................................................................................................................206 4.16.2. Un método de clase para Circulo .................................................................................206

4.17. DESTRUCCIÓN DE LOS OBJETOS ........................................................................................214 4.17.1. El recolector de basura (Garbage Collector)....................................................................214

4.18. LA REFERENCIA NULL .............................................................................................................215 4.19. HERENCIA ................................................................................................................................217

4.19.1. La clase base .....................................................................................................................220

iii

4.19.2. Objetos de la clase base.................................................................................................... 222 4.19.3. La clase derivada.............................................................................................................. 223 4.19.4. Objetos de la clase derivada............................................................................................. 225

4.20. MODIFICADORES DE ACCESO Y HERENCIA .................................................................... 227 4.21. LA JERARQUÍA DE CLASES QUE DESCRIBEN LAS FIGURAS PLANAS............................................... 229

4.21.1. La clase Figura................................................................................................................. 230 4.21.2. La clase Rectangulo.......................................................................................................... 230 4.21.3. La clase Circulo................................................................................................................ 231

4.22. USO DE LA JERARQUÍA DE CLASES............................................................................................... 232 4.23. ENLACE DINÁMICO...................................................................................................................... 232

CAPITULO CINCO.................................................................................................................................... 235

GESTION DE EXCEPCIONES ................................................................................................................ 235 5.1. LAS EXCEPCIONES ESTÁNDAR........................................................................................... 235

5.1.1. Las excepciones ..................................................................................................................... 236 5.1.2. Captura de las excepciones ................................................................................................... 238 5.1.3. Manejando varias excepciones.............................................................................................. 239

5.2. LAS EXCEPCIONES PROPIAS ......................................................................................................... 241 5.2.1. La clase que describe la excepción........................................................................................ 241 5.2.2. El método que puede lanzar una excepción........................................................................... 242 5.2.3. Captura de las excepciones ................................................................................................... 242 5.2.4. Una función que que puede lanzar varias excepciones ......................................................... 244

CAPITULO SEIS ........................................................................................................................................ 247

PAQUETES ................................................................................................................................................. 247 6.1. PAQUETES ............................................................................................................................... 247

6.1.1. La sentencia package (paquete) ............................................................................................ 248 6.1.2. Compilación de clases en paquetes ....................................................................................... 248 6.1.3. La sentencia import ............................................................................................................... 250 6.1.4. Protección de accesos ........................................................................................................... 251 6.1.5. Los paquetes estándar ........................................................................................................... 253

6.2. EJEMPLOS DE USO DE PAQUETES ...................................................................................... 253 CAPITULO SIETE ..................................................................................................................................... 257

INTERFACES ............................................................................................................................................. 257 7.1. ¿QUÉ ES UN INTERFACE? ..................................................................................................... 257 7.2. DIFERENCIAS ENTRE UN INTERFACE Y UNA CLASE ABSTRACTA................................................... 258 7.3. LOS INTERFACES Y EL POLIMORFISMO......................................................................................... 259

7.3.1. Herencia simple..................................................................................................................... 260 7.3.2. Interfaces ............................................................................................................................... 261

CAPITULO OCHO..................................................................................................................................... 267

ENTRADA/SALIDA PARA EL MANEJO DE ARCHIVOS.................................................................. 267 8.1. ARCHIVOS Y DIRECTORIOS................................................................................................. 267

8.1.1. La clase File .......................................................................................................................... 267 8.1.2. Creación de un filtro.............................................................................................................. 270

8.2. FLUJOS DE DATOS........................................................................................................................ 273 8.2.1. Las jerarquías de clases ........................................................................................................ 274 8.2.2. Lectura................................................................................................................................... 276 8.2.3. Escritura................................................................................................................................ 277

8.3. ENTRADA/SALIDA ESTÁNDAR...................................................................................................... 277 8.3.1. Los objetos System.in y System.out........................................................................................ 277 8.3.2. La clase Reader ..................................................................................................................... 278

iv Mg. ABRAHAM GAMARRA MORENO

8.4. ENTRADA/SALIDA A UN ARCHIVO EN DISCO.................................................................................281 8.4.1. Lectura de un archivo ............................................................................................................281 8.4.2. Lectura/escritura....................................................................................................................283

8.5. LEER Y ESCRIBIR DATOS PRIMITIVOS ...........................................................................................285 8.5.1. Los flujos de datos DataInputStream y DataOutputStream ...................................................285 8.5.2. Ejemplo: un pedido ................................................................................................................287 8.5.3. El final del archivo.................................................................................................................290

8.6. LEER Y ESCRIBIR OBJETOS ..................................................................................................292 8.6.1. El interface Serializable .........................................................................................................293 8.6.2. Lectura/escritura....................................................................................................................294 8.6.3. El modificador transient.........................................................................................................298 8.6.4. Objetos compuestos................................................................................................................302 8.6.5. La herencia ............................................................................................................................306 8.6.6. Serialización personalizada ...................................................................................................311

CAPITULO NUEVE....................................................................................................................................313

APPLETS......................................................................................................................................................313 9.1. DEFINICIÓN DE APPLET ........................................................................................................313 9.2. EL APPLET MÍNIMO................................................................................................................314 9.3. EL PRIMER APPLET.......................................................................................................................314 9.4. INSERTANDO UN APPLET EN UNA PÁGINA WEB.............................................................................316 9.5. FUNCIONES GRÁFICAS..........................................................................................................319

9.5.1. El contexto gráfico .................................................................................................................324 9.5.2. Establecer un color ................................................................................................................326 9.5.3. Dibujar una línea ...................................................................................................................326 9.5.4. Dibujar un rectángulo............................................................................................................326 9.5.5. Dibujar un arco......................................................................................................................327 9.5.6. Dibujar un polígono...............................................................................................................327 9.5.7. Dibujar una imagen ...............................................................................................................328

9.6. LAS CLASES COLOR, FONT Y FONTMETRICS................................................................................331 9.6.1. La clase Color ........................................................................................................................331 9.6.2. La clase Font..........................................................................................................................335 9.6.3. La clase FontMetrics..............................................................................................................336

9.7. INTERFAZ GRAFICA CON EL USUARIO (GUI) Y COMPONENTES BASICOS................344 9.7.1. COMPONENTES ...................................................................................................................345 9.7.2. ROTULOS (Label) .................................................................................................................346 9.7.3. ADMINISTRADOR DE DISEÑOS GRIDLAYOUT................................................................365 9.7.4. BOTONES PARA PULSAR (BUTTON) .................................................................................369

9.8. LOS GESTORES FLOWLAYOUT, BORDERLAYOUT Y GRIDLAYOUT ..............................................375 9.8.1. El gestor FlowLayout .............................................................................................................375 9.8.2. El gestor BorderLayout..........................................................................................................377 9.8.3. El gestor GridLayout..............................................................................................................379

9.9. EL GESTOR DE DISEÑO GRIDBAGLAYOUT ...................................................................................381 9.9.1. Ejemplo: diseño de una ficha .................................................................................................381 9.9.2. El panel ..................................................................................................................................382 9.9.3. El applet .................................................................................................................................383 9.9.4. El gestor de diseño GridBagLayout .......................................................................................384 9.9.5. Añadir los componentes al applet ..........................................................................................384

CAPITULO DIEZ........................................................................................................................................389

HILO Y SINCRONIZACIÓN ....................................................................................................................389 10.1. EL MODELO DE HILO DE JAVA ......................................................................................................389

10.1.1. Prioridades de hilo ............................................................................................................390 10.1.2. Sincronización ...................................................................................................................390 10.1.3. Intercambio de mensajes ...................................................................................................391

v

10.2. THREAD ...................................................................................................................................... 391 10.3. RUNNABLE.................................................................................................................................. 391 10.4. PRIORIDADES DE LOS HILOS ........................................................................................................ 393 10.5. SINCRONIZACIÓN ........................................................................................................................ 393

10.5.1. La sentencia synchronized ................................................................................................ 394 10.6. COMUNICACIÓN ENTRE HILOS ..................................................................................................... 395

10.6.1. Bloqueos ........................................................................................................................... 397 10.7. RESUMEN DE LA INTERFAZ DE PROGRAMACIÓN (API) DE HILOS ................................................. 397

10.7.1. Métodos de clase............................................................................................................... 397 10.7.2. Métodos de instancia ........................................................................................................ 398

PROGRAMACION CON JAVA 2 1

INTRODUCCION

La evolución de los lenguajes de programación y la capacidad de procesamiento de los ordenadores en la actualidad ha dado origen a la Programación orientada Objetos. La búsqueda de una mejor portabilidad de los programas de aplicación, así como la necesidad del desarrollo de programas para Internet ha hecho que el Lenguaje Java sea uno de los más utilizados. El lenguaje Java es un lenguaje de programación FreeWare, es decir no se requiere comprar la licencia del software por lo que nos facilita la implementación de neutro código sin costo alguno.

Este libro trata sobre el desarrollo de programas combinando las técnicas de programación tradicionales y las nuevas téc-nicas de programación orientada a objetos.

Para el desarrollo de los programas se utilizara el editor integrado JCreator Pro y Lenguaje de Programación Java 2 SDK, Standard Edition, versión 1.4.0.03 de la Empresa Sun Micro-systems(TM), Inc.

El primer Capitulo I trata sobre las características del len-guaje de programación Java: la descripción de los directorios del lenguaje de programación, la estructura de un programa, los tipos de datos usados, entrada y salida básica, las sen-tencias de control, y. En el Capitulo II detalla sobre los arreglos y la gestión de de cadenas. El Capitulo III se deta-lla las características de la Programación Orientada a Obje-

2 Mg. ABRAHAM GAMARRA MORENO

tos. El Capítulo IV contempla el tratamiento de errores en tiempo de compilación conocido también como gestión de excep-ciones. El Capítulo V tratao sobre el uso de paquetes en Ja-va. El Capítulo VI muestra el uso de interfaces. El capítulo VII muestra la entrada/salida para el manejo de archivos. En el Capitulo VIII se trata sobre la elaboración de programas para Internet utilizando Applets y la interfase gráfica del lenguaje de programación Java. En el Capitulo IX se detallan las características de la programación multihilos que permi-tirán usar concurrentemente los recursos de un ordenador.

PROGRAMACION CON JAVA 2 3

CAPITULO UNO

FUNDAMENTOS DEL JAVA

1.1. ¿QUE ES JAVA?

Java es un lenguaje de programación de alto nivel con el que se pueden escribir tanto programas convenciona-les como para Internet.

Una de las ventajas significativas de Java sobre otros lenguajes de programación es que es independiente de la plataforma tanto en código fuente como en binario. Esto quiere decir que el código producido por el com-pilador Java puede transportarse a cualquier platafor-ma (Intel, Sparc. Motorola, etc.) que tenga instalada una máquina virtual Java y ejecutarse. Pensando en in-ternet esta característica es crucial ya que esta red conecta ordenadores muy distintos. En cambio, C++, por ejemplo, es independiente de la plataforma sólo en có-digo fuente, lo cual significa que cada plataforma di-ferente debe proporcionar el compilador adecuado para obtener el código máquina que tiene que ejecutarse.

Según lo expuesto. Java incluye dos elementos: un com-pilador y un intérprete. El compilador produce un có-digo de bytes que se almacena en un fichero para ser ejecutado por el intérprete Java denominado máquina virtual de Java.

4 Mg. ABRAHAM GAMARRA MORENO

Los códigos de bytes de Java son un conjunto de ins-trucciones correspondientes a un lenguaje máquina que no es específico de ningún procesador, sino de la má-quina virtual de Java. ¿Dónde se consigue esta máquina virtual? Hoy en día casi todas las compañías de siste-mas operativos y de navegadores han implementado má-quinas virtuales según las especificaciones publicadas por Sun Microsystems, propietario de Java, para que sean compatibles con el lenguaje Java. Para las apli-caciones de Internet (denominadas applets) la máquina virtual está incluida en el navegador y para las apli-caciones Java convencionales, puede venir con el sis-tema operativo, con el paquete Java, o bien puede ob-tenerla a través de Internet.

1.2. HISTORIA DE JAVA

El lenguaje de programación Java fue desarrollado por Sun Microsystems en 1991. Nace como parte de un pro-yecto de investigación para desarrollar software para comunicación entre aparatos electrónicos de consumo como vídeos, televisores, equipos de música. etc. Du-rante la fase de investigación surgió un problema que dificultaba enormemente el proyecto iniciado: cada aparato tenía un microprocesador diferente y muy poco espacio de memoria: esto provocó un cambio en el rumbo de la investigación que desembocó en la idea de escri-bir un nuevo lenguaje de programación independiente del dispositivo que fue bautizado inicialmente como Oak.

La explosión de internet en 1994, gracias al navegador gráfico Mosaic para la Word Wide Web (WWW), no pasó desapercibida para el grupo investigador de Sun. Se dieron cuenta de que los logros alcanzados en su pro-yecto de investigación eran perfectamente aplicables a Internet. Comparativamente, Internet era como un gran conjunto de aparatos electrónicos de consumo, cada uno con un procesador diferente. Y es cierto básicamente, Internet es una gran red mundial que conecta múltiples ordenadores con diferentes sistemas operativos y dife-rentes arquitecturas de microprocesadores, pero todos tienen en común un navegador que utilizan para comuni-

Programa escrito en Java

Compilador

Código de bytes

Máquina virtual de Java

PROGRAMACION CON JAVA 2 5

carse entre sí. Esta idea hizo que el grupo investiga-dor abandonara el proyecto de desarrollar un lenguaje que permitiera la comunicación entre aparatos electró-nicos de consumo y dirigiera sus investigaciones hacia el desarrollo de un lenguaje que permitiera crear aplicaciones que se ejecutaran en cualquier ordenador de Internet con el único soporte de un navegador.

A partir de aquí va todo es conocido. Se empezó a hablar de Java y de sus aplicaciones, conocidas como applets. Un applet es un programa escrito en Java que se ejecuta en el contexto de una página Web en cual-quier ordenador, independientemente de su sistema ope-rativo y de la arquitectura de su procesador. Para ejecutar un applet sólo se necesita un navegador que soporte la máquina virtual de Java como, por ejemplo. Microsoft Internet Explorer o Netscape. Utilizando un navegador de éstos, se puede descargar la página Web que contiene el applet y ejecutarlo. Precisamente en este campo, es donde Java como lenguaje de programa-ción no tiene competidores. No obstante, con Java se puede programar cualquier cosa, razón por la que tam-bién puede ser considerado como un lenguaje de propó-sito general: pero desde este punto de vista, hoy por hoy, Java tiene muchos competidores que le sobrepasan con claridad; por ejemplo C++.

1.3. ¿POR QUÉ APRENDER JAVA?

Una de las ventajas más significativas de Java es su independencia de la plataforma. En el caso de que ten-ga que desarrollar aplicaciones que tengan que ejecu-tarse en sistemas diferentes esta característica es fundamental.

Otra característica importante de Java es que es un lenguaje de programación orientado a objetos (POO).

Además de ser transportable y orientado a objetos. Ja-va es un lenguaje fácil de aprender. Tiene un tamaño pequeño que favorece el desarrollo y reduce las posi-bilidades de cometer errores: a la vez es potente y flexible.

Java está fundamentado en C++. Quiere esto decir que mucha de la sintaxis y diseño orientado a objetos se tomó de este lenguaje. Por lo tanto, a los lectores que estén familiarizados con C++ y la POO les será muy fácil aprender a desarrollar aplicaciones con Java. Se

6 Mg. ABRAHAM GAMARRA MORENO

advierte a los potenciales usuarios de Java que en es-te lenguaje no existen punteros ni aritmética de pun-teros, las cadenas de caracteres son objetos y la ad-ministración de memoria es automática, lo que elimina la problemática que presenta C++ con las lagunas de memoria al olvidar liberar bloques de la misma que fueron asignados dinámicamente.

1.4. JAVA(TM) 2 SDK, STANDARD EDITION VERSION 1.4.0.

1.4.1. INSTALACION DEL JAVA(TM) 2 SDK, STAN-DARD EDITION VERSION 1.4.0.

Ejecutar el archivo JAVA\j2sdk-1_4_0_03-windows-i586.exe desde el CD-ROM para insta-lar el Java2 y prosiga con el asistente de instalación.

1.4.2. ESTRUCTURA DE ARCHIVOS DEL JAVA 2 SDK

El siguiente gráfico muestra los directorios más importantes para el desarrollo de aplica-ciones de la plataforma Java (se asume que el Java esta instalado en c:\j2sdk1.4.0).

c:\j2sdk1.4.0

El directorio raíz del software SDK. Contiene copyright, licencia y archivos README. Tam-bién contiene el archivo src.jar del código fuente para la plataforma Java 2.

PROGRAMACION CON JAVA 2 7

c:\j2sdk1.4.0\bin

Los archivos ejecutables para el desarrollo de programas contenidos en el Kit de desarro-llo de Java (Java Development Kit).

La variable de entorno PATH debe contener una entrada para este directorio:

path=%path%;c:\jdk1.3\bin

c:\j2sdk1.4.0\lib

Los archivos utilizados por las herramientas de desarrollo. Estos incluyen tools.jar, que contiene clases no esenciales como apoyo de las herramientas y utilidades dentro del SDK. También incluye dt.jar que llaman al entorno de desarrollo interactivo (IDE).

c:\j2sdk1.4.0\jre

El directorio raíz del entorno en tiempo de ejecución del Java (Java Runtime Environment) utilizado por las herramientas de desarrollo SDK. El entorno en tiempo de ejecución es una implementación de la plataforma Java 2. Este es el directorio representado por la posesión del java.home.

c:\j2sdk1.4.0\jre\bin

Archivos ejecutables y DLLs para herramientas y librerías utilizadas por la plataforma Ja-va. Los archivos ejecutables son idénticos a los archivos en /j2sdk1.4.0/bin. La herra-mienta java launcher sirve coo una aplicación de lanzamiento, en lugar de el Viejo jre que se enviaba con la versión 1.1 del software SDK. Este directorio no necesita estar dentro de la variable de entorno PATH.

c:\j2sdk1.4.0\jre\bin\classic

Contiene los archivos DLL utilizados por la Máquina Virtual Clásica Java 2 (Java 2 Clas-sic Virtual Machine). Estos archivos están presentes sólo en el Java 2 SDK. Ellos no es-

8 Mg. ABRAHAM GAMARRA MORENO

tán incluidos con el Java 2 Runtime Environ-ment.

c:\j2sdk1.4.0\jre\bin\hotspot

Contiene los archivos DLL utlizados por el Java HotSpotTM Client Virtual Machine, que es implementado con la tecnología Java HotSpot.

c:\j2sdk1.4.0\jre\lib

Librerías, configuración de propiedades y ar-chivos de recursos utilizados por el Java runtime environment. Incluye:

• rt.jar – las clases de la secuencia de arranque (bootstrap).

• i18n.jar – las clases de conversión de caracteres y otros archivos asociados con la localización e internacionaliza-ción.

Aparte del subdirectorio ext (descrito antes) hay varios subdirectorios de recursos adicio-nales no descritos aquí.

c:\j2sdk1.4.0\jre\lib\ext

Directorio de instalación por defecto de las extensiones para la plataforma Java. Por ejemplo este es el directorio donde el archi-vo JavaHelp jar va cuando este es instalado.

c:\j2sdk1.4.0\jre\lib\security

Contiene archivos utilizados para la adminis-tración de la seguridad. Estos incluyen las políticas de seguridad (java.policy) y los archivos de las propiedades de seguridad (ja-va.security).

c:\j2sdk1.4.0\jre\lib\applet

Los archivos Jar conteniendo clases de apoyo para applets pueden ser colocados en el di-rectorio lib/applet/. Este reduce el tiempo de inicio para applets grandes, permitiendo a las clases applet ser pre cargados desde el

PROGRAMACION CON JAVA 2 9

sistema de archivos local teh, con el carga-dor de clases applet, proporcionando las mis-mas protecciones tal como si ellos han sido descargados desde la red.

A continuación se describen los archivos y directorios adicionales: demos, codigo fuente Java y archivos de cabecera C.

c:\j2sdk1.4.0\src.jar

Archivos conteniendo código fuente para la plataforma Java 2.

c:\j2sdk1.4.0\demo

Ejemplos con código fuente que muestran como programar en la plataforma Java.

c:\j2sdk1.4.0\demo\applets

Applets que pueden utilizarse en una página Web.

c:\j2sdk1.4.0\demo\jfc

Ejemplos que utilizan Java 2DTM y fiuncionali-dad JFC\Swing.

c:\j2sdk1.4.0\demo\jpda

Ejemplos de uso del Java Platform Debugging Architecture. Incluye código fuente para las utilidades javadt y jdb.

c:\j2sdk1.4.0\demo\sound

10 Mg. ABRAHAM GAMARRA MORENO

Contiene código fuente con demos de sonido Java.

c:\j2sdk1.4.0\include

Archivos de cabecera del lenguaje C que apo-yan la programación de código nativo utili-zando el Java Native Interface y el Java Vir-tual Machine Debugger Interface.

c:\j2sdk1.4.0\include-old

Archivos de cabecera que apoyan la programa-ción de código nativo utilizando interfaces antiguas. Estos archivos de cabecera son pro-porcionados sólo por compatibilidad hacia atrás. Estas interfaces son desaprobadas, in-seguras y no disponibles en todas las máqui-nas virtuales Java.

1.5. EL EDITOR JCREATOR

JCreator Pro Release V2.00 build 004 (32 bit) for Win 95/98/NT/2000.

Jcreator es un poderoso Entorno de Desarrollo Integra-do (Integrated Development Environment: IDE), para Ja-va, que proporciona al usuario un amplio rango de fun-cionalidades tales como: Administración de proyectos, plantillas, navegador para clases, elaboración de có-digo, interfaz de depuración, resaltado de sintaxis, asistente y una interfaz de usuario configurable.

JCreator esta escrito enteramente en C++, el cual lo hace a este rápido y eficiente comparado con los IDEs basados en Java.

1.5.1. REQUERIMIENTOS DEL SISTEMA

• Windows 95/98/NT4/2000 o superior.

• Internet Explorer 4 o superior (opcio-nal)

1.5.2. INSTALACION DE JCREATOR

Descomprimir el fichero de instalación JCREA-TORPRO2\JCREATORSETUP.EXE en un directorio

PROGRAMACION CON JAVA 2 11

temporal y correr el ejecutable. El asistente de instalación realizará el resto.

1.6. ESTRUCTURA DE UN PROGRAMA EN JAVA

Un programa es un conjunto de instrucciones, escritas en un lenguaje de programación, que sirven para resol-ver un tipo determinado de problema o para cumplir me-tas bien definidas. Un programa de Java contiene una o más clases. Éstas describen objetos, entidades de software que interactúan al momento de la ejecución para realizar tareas específicas. Los objetos se uti-lizan para modelar entidades reales o lógicas en el dominio del problema. Un aspecto importante de la POO es identificar estas entidades y sus interacciones en el proceso de solución.

Por lo general una clase contiene miembros que pueden ser campos y métodos. Los primeros son variables que almacenan datos y objetos. Los segundos son funciones que codifican operaciones. Es así que ellos reciben argumentos, realizan cálculos predefinidos y devuelven resultados.

La estructura de un programa se puede representar de la siguiente manera:

Class . . .

{

< campos o atributos >

. .

< métodos >

}

Se debe tener un método main para que se pueda ejecu-tar la aplicación

En Java, las clases contienen a todos los métodos, no se les permite no estar anexados y eso también sucede con las funciones. Un mensaje enviado a un objeto ac-tiva (o invoca) un método de ese objeto, le pasa argu-mentos y obtiene el valor que devuelve. Los objetos interactúan al enviar y recibir mensajes.

12 Mg. ABRAHAM GAMARRA MORENO

Una clase proporciona el nombre bajo el que se reúnen los miembros para formar una unidad de cálculo que puede operar con independencia de otras partes del programa. Con objetos, puede construirse un programa grande con muchas unidades pequeñas, independientes y que interactúan entre si. La orientación a objetos puede reducir significativamente la complejidad del programa, aumentar su flexibilidad y mejorar las posi-bilidades de volver a usarlo. Un programa de Java pue-de definir sus propias clases, utilizarlas ya integra-das y emplear las que han sido creadas por otros.

Las clases pueden estar organizadas en paquetes con un nombre. Cada paquete puede contener uno o más archivos de código fuente.

1.7. COMO CREAR UN PROGRAMA

Un programa es una aplicación o un applet y puede crearse con algún editor de textos (Block de notas o el Edit) el programa. Pero se recomienda utilizar un IDE, tal como el JCreator.

1.7.1. CREACION DE UNA APLICACIÓN EN EL JCREATOR

Para mostrar este ejemplo, utilizaremos el IDE JCreator para crear nuestras aplicacio-nes.

Escriba el siguiente código en el IDE JCrea-tor:

Ejemplo ( 1): Programa que imprime un mensa-je.

class programa1 { public static void main (String[] args) { System.out.println("Mi primer progra-ma!!!"); } } Para crear el programa elija File (Menú prin-cipal), New, elija la ficha Files , Java Fi-le, ingrese el nombre del archivo en Filena-me, elija la carpeta donde se alojará el ar-

PROGRAMACION CON JAVA 2 13

chivo en Location y presione el clic en Acep-tar, tal como se muestra en la figura:

El código en el IDE JCreator queda:

Para compilar el programa presione clic sobre

el icono , luego presione para ejecutar el programa.

Usted ahora tiene el siguiente resultado:

14 Mg. ABRAHAM GAMARRA MORENO

El programa anterior muestra en pantalla el mensaje Mi primer programa!!!, el cual se imprime debido al uso de la clase System, ampliaremos este tema en las si-guientes secciones. Nótese que el nombre de la clase debe ser igual al nombre del archivo, pero el archivo tiene la extensión .java.

1.8. USO DE COMENTARIOS

En Java hay tres tipos de comentarios:

// comentarios de una sola línea

/*

comentarios de una o más líneas

*/

/** comentario de documentación, que pueden ser de una o más líneas y pueden contener palabras claves que co-mienzan con @ para destacar cierta información, por ejemplo: @version 1.0 (06/11/2000) @author Gustavo A. Scrigna @author Lisandro A. Palermo */

Los dos primeros tipos de comentarios son los más conocidos, ya que son los heredados del lenguaje C y C++, y se utilizan del mismo modo. Los comentarios de documentación indican que ese comentario ha de ser colocado en la documentación que se genera automáticamente cuando se utiliza la herramienta del JDK, javadoc. Dichos comentarios sirven como descripción del elemento declarado permitiendo generar una documentación de las clases que se van construyendo al mismo tiempo que se genera el código de la aplicación. En este tipo de comentario para documentación, se permite la introducción de algunas palabras claves, que harán que la información aparezca

PROGRAMACION CON JAVA 2 15

destacada, permitiendo la incorporación de información útil, que luego se podrá ver en formato HTML sobre cualquier navegador. Aunque posteriormente se verán en detalle algunas de las palabras claves que soporta javadoc, hay que tener en cuenta a la hora de utilizar este tipo de comentarios, que javadoc solamente procesarán la documentación para miembros public y protected, los comentarios para miembros private y package serán ignorados.

Algunas de las palabras claves más utilizadas son:

• @author: Información del autor

• @param: Parámetro y descripción

• @exception: Nombre de la clase y descripción

• @version: Información de la versión

• @see: Referencia a otra clase

• @return: Significado del valor de retorno

• @deprecated: Aviso de clase obsoleta

1.9. PALABRAS CLAVES

Las siguientes son las palabras claves que están defi-nidas en el lenguaje Java y que no pueden utilizarse como identificadores:

abstract double int strictfp **

boolean else interface super

break Extendí long switch

byte final native synchronized

case finally new this

16 Mg. ABRAHAM GAMARRA MORENO

catch float package throw

char for private throws

class goto * protected transient

const * if public try

continue implements return void

default import short volatile

do instanceof static while

* indica una palabra clave que no esta siendo utiliza-da en la actualidad

** indica una palabra clave que fue agregada desde Ja-va 2

También son palabras reservadas (aunque no son pala-bras claves) las siguientes: true, false y null, y por lo tanto no pueden ser utilizadas como identificado-res.

1.10. IDENTIFICADORES

Los identificadores se utilizan como nombres de clase, método y variable. Un identificador puede ser cual-quier sentencia descriptiva de letras en mayúscula o minúscula, números y los caracteres subrayado (_) y signo de dólar ($). No se deban comenzar por número. Java diferencia entre mayúsculas/minúsculas, lo que significa que VALOR es un identificador diferente de Valor.

1.11. VARIABLES

Una variable es un ítem de datos nombrado por un iden-tificador. Debemos explícitamente suministrar un nom-

PROGRAMACION CON JAVA 2 17

bre y un tipo para cada variable que quisiéramos usar en nuestro programa. El nombre de la variable debe ser un identificador válido --una serie de caracteres Uni-code que comienzan con una letra. Utilizamos el nombre de la variable para referirnos al dato que la variable contiene. El tipo de la variable determina el conjunto de valores que se pueden almacenar en esa variable y el tipo de operaciones que se pueden realizar con ella. Para dar a una variable un tipo y un nombre, es-cribimos una declaración de variable, que en general se verá de la siguiente forma:

tipo nombre;

o también:

tipo nombre1 [ = valor][,nombre2 [= valor] ...];

en este último caso mostramos como podemos inicializar una variable en el momento de su declaración.

Además del nombre y tipo que explícitamente le damos a la variable, una variable tiene un alcance (scope). La sección de código donde puede ser utilizado el nombre de la variable es el alcance de la variable. El alcan-ce de la variable es determinado implícitamente por la ubicación de la declaración de la variable, es decir, donde aparece la declaración en relación a otros ele-mentos del código. Se ampliará cuando se utilice fun-ciones.

1.12. TIPOS DE DATOS

Cada variable debe tener un tipo de datos. El lenguaje de programación Java tiene dos categorías de tipos de datos: primitivo y referencia.

1.12.1. TIPOS DE DATOS PRIMITIVOS

Una variable de tipo primitivo contiene un único valor de tamaño y formato apropiados para su tipo: un número, un carácter, un va-lor booleano. Por ejemplo, el valor de un en-tero (int) es de 32 bits de datos en un for-mato conocido como complemento a 2, el valor de un carácter (char) es de 16 bits de datos formateados como un carácter Unicode, etc.

18 Mg. ABRAHAM GAMARRA MORENO

En la tabla siguiente listamos todos los ti-pos de datos primitivos soportados por Java, junto con sus tamaños y formatos, y una breve descripción de cada uno de ellos.

Tipo

Descripción

boolean Tiene dos valores true o false.

char

Caracteres Unicode de 16 bits. Los caracteres alfa-numéricos son los mismos que los ASCII con el bit alto puesto a 0. El intervalo de valores va desde 0 hasta 65535 (valores de 16-bits sin signo).

byte Tamaño 8 bits. El intervalo de valores va desde -27 has-ta 27 -1 (-128 a 127)

short Tamaño 16 bits. El intervalo de valores va desde -215

hasta 215-1 (-32768 a 32767)

int Tamaño 32 bits. El intervalo de valores va desde -231

hasta 231-1 (-2147483648 a 2147483647)

long Tamaño 64 bits. El intervalo de valores va desde -263

hasta 263-1 (-9223372036854775808 a 9223372036854775807)

float Tamaño 32 bits. Números en coma flotante de simple pre-cisión. Estándar IEEE 754-1985 (de 1.40239846e–45f a 3.40282347e+38f)

double Tamaño 64 bits. Números en coma flotante de doble preci-sión. Estándar IEEE 754-1985. (de 4.94065645841246544e–324d a 1.7976931348623157e+308d.)

Los tipos básicos que utilizaremos en la ma-yor parte de los programas serán boolean, int y double.

1.12.2. TIPOS DE DATOS REFERENCIA

Los arreglos, las clases y las interfaces son tipos referencia. El valor de una variable de tipo referencia, en contraste con la de tipo primitivo, es una referencia a (la dirección de) el valor o conjunto de valores represen-tados por la variable.

Una referencia es denominada un puntero, o una dirección de memoria en otros lenguajes.

PROGRAMACION CON JAVA 2 19

El lenguaje de programación Java no soporta el uso explícito de direcciones como en otros lenguajes. Utilizamos en cambio el nombre de la variable:

1.13. LITERALES

Un valor constante en Java se crea utilizando una re-presentación literal de él. Java utiliza cinco tipos de elementos: enteros, reales en coma flotante, boo-leanos, caracteres y cadenas, que se pueden poner en cualquier lugar del código fuente de Java. Cada uno de estos literales tiene un tipo correspondiente asociado con él.

A continuación se tiene el ejemplo de valores litera-les y sus tipos de datos:

Literal Tipo de Datos

178 Int

8864L Long

37.266 Double

37.266D double

87.363F float

26.77e3 double

'c' char

true boolean

false boolean

"Hola" String

Nombre del objeto

ReferenciaUn objeto o un array

20 Mg. ABRAHAM GAMARRA MORENO

1.14. OPERADORES

Un operador realiza una función en uno, dos o tres operandos. Un operador que requiere un solo operando se denomina operador unario. Por ejemplo, ++ es un operador unario que incrementa el valor de su operando en 1. Un operador que requiere de dos operandos es un operador binario. Por ejemplo, = es un operador bina-rio que asigna el valor del operando de la derecha al operando de la izquierda. Y, finalmente, el operador ternario el que requiere tres operandos. El lenguaje de programación Java tiene un operador ternario, ?:, que es un atajo de la sentencia if-else, el cual se analizará más adelante .

Los operadores unarios soportan tanto la notación pre-fija como postfija. La notación prefija significa que el operador aparece antes que el operando:

operador op //notación prefija

La notación postfija significa que el operador aparece después que el operando:

op operador //notación postfija

Todos los operadores binarios utilizan notación infi-ja, que significa que el operador aparece entre sus operandos:

op1 operador op2 //notación infija

El operador ternario es también infijo; cada componen-te del operador aparece entre operandos:

op1 ? op2 : op3 //notación infija

Además de realizar la operación, el operador devuelve un valor. El valor de retorno y su tipo depende del operador y del tipo de sus operandos. Por ejemplo, el operador aritmético, que realiza operaciones aritméti-cas básicas como suma y resta, devuelve números (el resultado de la operación aritmética). El tipo de dato devuelto por un operador aritmético depende del tipo de sus operandos: Si sumamos dos enteros, obtenemos un entero. Una operación se dice que se evalúa a su re-sultado.

PROGRAMACION CON JAVA 2 21

1.14.1. OPERADORES ARITMÉTICOS

Operador Uso Descripción

+ op1 + op2 Suma op1 y op2

- op1 - op2 Resta op2 de op1

* op1 * op2 Multiplica op1 por op2

/ op1 / op2 Divide op1 por op2

% op1 % op2 Calcula el resto de la división de op1 por op2

Operador Uso Descripción

++ op++ Incrementa op en 1; se evalúa el valor de op antes de ser incrementado

++ ++op Incrementa op en 1; se evalúa el valor de op después de ser incrementado

-- op-- Decrementa op en 1; se evalúa el valor de op antes de ser decrementado

-- --op Decrementa op en 1; se evalúa el valor de op des-pués de ser decrementado

1.14.2. OPERADORES RELACIONALES

Operador Uso Devuelve true si

> op1 > op2 op1 es mayor que op2

>= op1 >= Op2 op1 es mayor o igual que op2

< op1 < op2 op1 es menor que op2

<= op1 <= op2 op1 es menor o igual que op2

== op1 == op2 op1 y op2 son iguales

!= Op1 != op2 op1 y op2 son distintos

22 Mg. ABRAHAM GAMARRA MORENO

1.14.3. OPERADORES CONDICIONALES

Operador Uso Devuelve true si

&& op1 && op2

op1 y op2 son ambos true, evalúa condicionalmente op2

|| op1 || op2

Cualquiera de op1 u op2 es true, evalúa condicio-nalmente op2

! ! op op es false

& op1 & op2 op1 y op2 son ambos true, siempre evalúa op1 y op2

| op1 | op2

Cualquiera de op1 u op2 es true, siempre evalúa op1 y op2

^ op1 ^ op2

Si op1 y op2 son diferentes. Esto es si uno u otro de los operandos es true, pero no ambos.

1.14.4. OPERADORES LÓGICOS Y DE CORRIMIENTO (SHIFT)

Operador Uso Operación

& op1 & op2 "AND" de Bits

| op1 | op2 "OR" de Bits

^ op1 ^ op2 "XOR" de Bits

~ ~op2 Complemento Binario

Operador Uso Operación

>> op1 >> op2

Corrimiento de bits de op1 hacia la derecha por la distancia de op2

<< op1 << op2

Corrimiento de bits de op1 hacia la izquierda por la distancia de op2

>>> op1 >>> op2

Corrimiento de bits de op1 hacia la derecha por la distancia de op2 (sin signo)

PROGRAMACION CON JAVA 2 23

1.14.5. OPERADORES DE ASIGNACIÓN

Operador Uso Equivalente a

+= op1 += op2 op1 = op1 + op2

-= op1 -= op2 op1 = op1 - op2

*= op1 *= op2 op1 = op1 * op2

/= op1 /= op2 op1 = op1 / op2

%= op1 %= op2 op1 = op1 % op2

&= op1 &= op2 op1 = op1 & op2

|= op1 |= op2 op1 = op1 | op2

^= op1 ^= op2 op1 = op1 ^ op2

<<= op1 <<= op2 op1 = op1 << op2

>>= op1 >>= op2 op1 = op1 >> op2

>>>= op1 >>>= op2 op1 = op1 >>> op2

1.14.6. OTROS OPERADORES

Operador Uso Descripción

?: op1 ? op2 : op3 Si op1 es verdadero, devuelve op2. De lo contrario, devuelve op3.

[] tipo [] Declara un array de tamaño desconocido, que contiene elementos tipo.

tipo[ op1 ] Crea un array de op1 elementos. Debe ser declarado con el operador new.

op1[ op2 ]

Accede al elemento de la posición op2 de-ntro del array op1. El índice comienza en 0 y se extiende hasta la longitud del array menos uno.

. op1.op2 Es una referencia al miembro op2 de op1.

() op1(parámetros)

Declara o llama al método denominado op1 con los parámetros especificados. La lista de parámetros puede ser una lista vacía. La lista esta separada por comas.

24 Mg. ABRAHAM GAMARRA MORENO

(tipo) (tipo) op1 Convierte (cast) op1 a tipo. Una excepción será lanzada si el tipo de op1 es incompa-tible con tipo.

new new op1 Crea un nuevo objeto o array. op1 puede ser una llamada a un constructor o la es-pecificación de un array.

Instanceof op1 instanceof op2

Devuelve verdadero si op1 es una instan-cia de op2

1.15. ENTRADA Y SALIDA BASICA

Con frecuencia los programas necesitan ingresar infor-mación desde una fuente externa o enviar información hacia un destino externo. La información puede estar en cualquier lado: en un archivo, en disco, en algún lugar de la red, en memoria, o en otro programa. Tam-bién puede ser de cualquier tipo: objetos, caracteres, imágenes, o sonidos.

Para ingresar información, un programa abre un flujo en una fuente de información (source: un archivo, me-moria, un socket) y lee la información en serie, de esta manera:

De la misma forma, un programa puede enviar informa-ción a un destino externo abriendo un flujo hacia el destino y escribiendo la información en serie, de esta manera:

PROGRAMACION CON JAVA 2 25

No importa de donde viene la información o hacia donde va y no importa que tipo de datos se está leyendo o escribiendo, los algoritmos para leer y escribir datos son en general siempre iguales.

Reading (Lectura) Writing (Escritura)

Abrir el flujo

Mientras haya más información

escribir información

cerrar el flujo

Abrir el flujo

Mientras haya más información

leer la información

cerrar el flujo

El paquete java.io contiene una colección de clases de flujos que soportan estos algoritmos para lectura y escritura. Estas clases están divididas en dos jerar-quías de clases basados en el tipo de datos (si son caracteres o bytes) con el que operan.

Hay veces que es más conveniente agrupar a las clases por su propósito en vez de por el tipo de datos que

Flujo de carácter Flujo de byte

26 Mg. ABRAHAM GAMARRA MORENO

leen o escriben. Así, podemos cruzar los grupos de flujos de acuerdo a como leen y escriben hacia almace-nes de datos o procesan la información a medida que se va leyendo o escribiendo.

Las clases del paquete java.io están divididas en dos grupos distintos, ambos derivados de la clase Object del paquete java.lang, según se muestra en la figura siguiente. El grupo de la izquierda ha sido diseñado para trabajar con datos de tipo byte y el de la dere-cha con datos de tipo char. Ambos grupos presentan clases análogas que tienen interfaces casi idénticas, por lo que se utilizan de la misma manera (Fig.1.1.).

Figura 1.1 La clase Object y sus derivados

Las clases en negrita son clases abstractas. Una clase abstracta no permite que se creen objetos de ella. Su

Flujo de carácter Flujo de byte

Flujo sumidero de datos

Flujo de procesa-miento

PROGRAMACION CON JAVA 2 27

misión es proporcionar miembros comunes que serán com-partidos por todas sus subclases.

1.15.1. FLUJOS DE ENTRADA DE BYTE Y CHAR (ENTRADA POR EL TECLADO)

La clase InputStream es una clase abstracta que es superclase de todas las clases que re-presentan un flujo en el que un destino lee bytes de un origen. Cuando una aplicación de-fine un flujo de entrada, la aplicación es destino de ese flujo de bytes, y es todo lo que se necesita saber.

El método más importante de esta clase es read. Este método se presenta de tres formas:

public abstract int read() throws IOException

public int read(byte[] b) throws IOException

public int read(byte[] b, int off, int len) throws IOException

La primera versión de read simplemente lee bytes individuales de un flujo de entrada; concretamente lee el siguiente byte de datos disponible. Devuelve un entero (int) corres-pondiente al valor ASCII del carácter leído.

La segunda versión del método read lee un nú-mero de bytes de un flujo de entrada y los almacena en una matriz b (más adelante anali-zaremos las matrices de datos). Devuelve un entero correspondiente al número de bytes leídos, o bien —l si no hay bytes disponibles para leer porque se ha alcanzado el final del flujo.

La tercera versión del método read lee un máximo de len bytes a partir de la posición off de un flujo de entrada y los almacena en una matriz b.

28 Mg. ABRAHAM GAMARRA MORENO

La biblioteca de Java proporciona el flujo estándar de entrada, manipulado por la clase system del paquete ja-va.lang, que es automáticamente abier-to cuando se inicia un programa y ce-rrado cuando este finaliza; este es denominado system.in.

Se puede utilizar el método read a través de clase system de la siguiente forma:

Variable = System.in.read()

Análogamente, la clase Reader es una clase abstracta que es superclase de todas las cla-ses que representan un flujo para leer carac-teres desde un origen. Sus métodos son análo-gos a los de la clase InputStream, con la di-ferencia de que utilizan parámetros de tipo char en lugar de byte.

En nuestros ejemplos utilizaremos la clase InputStream a través de System.

1.15.2. FLUJOS DE SALIDA DE BYTE Y CHAR (SALIDA POR EL MONITOR)

La clase OutputStream es una clase abstracta que es superclase de todas las clases que re-presentan un flujo en el que un origen escri-be bytes en un destino. Cuando una aplicación define un flujo de salida, la aplicación es origen de ese flujo de bytes (es la que envía los bytes).

El método más importante de esta clase es write, Este método se presenta de tres for-mas:

public abstract void write(int b) throws IOException

PROGRAMACION CON JAVA 2 29

public void write(byte[] b) throws IOException

public void write(byte[] b, int off, int len) throws IOException

La primera versión de write simplemente es-cribe el byte especificado en un flujo de sa-lida. Puesto que su parámetro es de tipo int, lo que se escribe es el valor correspondiente a los 8 bits menos significativos, el resto son ignorados.

La segunda versión del método write escribe los bytes almacenados en la matriz b en un flujo de salida (más adelante analizaremos las matrices de datos).

La tercera versión del método write escribe un máximo de len bytes de una matriz b a par-tir de su posición off, en un flujo de sali-da.

Cada uno de estos métodos ha sido escrito pa-ra que bloquee la ejecución del programa que los invoque hasta que toda la salida solici-tada haya sido escrita.

De manera análoga a read utilizaremos la cla-se System para llamar al método write, de la siguiente forma:

System.out.write(parametro)

Análogamente, la clase Writer (tal como se muestra en la Fig 1.1.) es una clase abstrac-ta que es superclase de todas las clases que representan un flujo para escribir caracteres a un destino. Sus métodos son análogos a los de la clase OutputStream, con la diferencia de que utilizan parámetros de tipo char en lugar de byte.

30 Mg. ABRAHAM GAMARRA MORENO

1.15.3. USO DE EXCEPCIONES EN LA ENTRADA Y SALIDA DE DATOS

Cuando durante la ejecución de un programa ocurre un error que impide su continuación, por ejemplo, una entrada incorrecta de datos o una división por cero. Java lanza una ex-cepción, que cuando no se captura da lugar a un mensaje acerca de lo ocurrido y detiene su ejecución (las excepciones se lanzan, no ocu-rren). Ahora, si lo que deseamos es que la ejecución del programa no se detenga, habrá que capturarla y manejarla adecuadamente en un intento de reanudar la ejecución.

Las excepciones en Java son objetos de sub-clases de Throwable. Por ejemplo, el paquete java.io define una clase de excepción general denominada IOException para excepciones de entrad y salida.

Puesto que en Java hay muchas clases de ex-cepciones, un método puede indicar los tipos de excepciones que posiblemente puede lanzar. Por ejemplo, puede observar que los métodos read y write que acabamos de exponer lanzan excepciones del tipo IOException. Entonces, cuando utilicemos alguno de esos métodos hay que escribir el código necesario para captu-rar las posibles excepciones que pueden lan-zar. Esto es algo a lo que nos obliga el com-pilador Java, del mismo modo que él verifica si una variable ha sido iniciada antes de ser utilizada, o si el número y tipo de argumen-tos utilizados con un método son correctos, con la única intención de minimizar los posi-bles errores que puedan ocurrir.

La forma básica de evitar escribir el código, cuando se produce una excepción, es utilizar la siguiente línea en el main:

public static void main (String[] args) throws IOEx-ception

PROGRAMACION CON JAVA 2 31

En secciones posteriores analizaremos con más detenimiento las excepciones.

A continuación se presenta un ejemplo del uso del read y write para leer y escribir un byte respectivamente.

Ejemplo ( 2):

//archivo: lecturabytes.java import java.io.*; class lecturabytes { public static void main (String[] args) throws IOException { // declaración de las variables int n; //lee un byte n=System.in.read(); //escribe un byte System.out.write(n); //escribe un salto de línea System.out.write('\n'); } }

La ejecución del programa se muestra de la siguiente manera:

Una característica aún no mencionada es:

import java.io.*;

el cual le indica al compilador que importe las clases necesarias del paquete java.io, para poder utilizar la entrada y salida de Java. El comodín * sustituye a cualquier nom-bre del paquete.

32 Mg. ABRAHAM GAMARRA MORENO

Nota: Cuando ejecute el programa usted debe ingresar el carácter por el teclado y luego presionar [ENTER].

1.16. ENTRADA Y SALIDA UTILIZANDO TIPOS DE DATOS PRIMITIVOS

La sección anterior permitía la entrada y salida de un byte o un carácter; pero ahora mostraremos como se puede manejar la entrada y salida de los tipos de da-tos primitivos mostrados en la sección 1.12.1.

Antes de mencionar el uso de los datos primitivos ubi-quémonos en la jerarquía de clases que se muestra en la figura 1.2.

Figura 1.2 Clases y subclases derivados de la clase Object

En la figura anterior se pueden observar las clases abstractas en los recuadros con líneas diagonales y sus derivadas; una línea discontinua indica que esa clase no se deriva directamente de Object; esto es, entre Object y la clase hay otras clases.

Además debemos observar que para la lectura se puede utilizar la subclase BufferedInputStream (derivada de InputStream) para leer bytes; esta clase hereda el mé-todo read, ya explicado anteriormente, el cual no es muy conveniente para trabajar con tipos de datos pri-

OutputStream Writer

ReaderInputStream

PROGRAMACION CON JAVA 2 33

mitivos; por lo tanto sugerimos utilizar las subclases derivadas de Reader, que leen cadena de caracteres.

Para leer una cadena de caracteres del flujo in y al-macenarlo en un objeto String, lo tenemos que hacer desde un flujo de la clase BufferedReader y para es-cribir en el flujo out tenemos los métodos proporcio-nados por la clase PrintStream o bien PrintWriter, que permiten escribir cualquier valor de cualquier tipo primitivo o referenciado.

1.16.1. FLUJOS DE ENTRADA A TRAVES DE BUFFEREDREADER (ENTRADA POR EL TECLADO)

Para realizar la lectura utilizaremos una combinación de InputStreamReader y BuffereadReader, de la siguiente forma:

InputStreamReader isr = new InputStreamReader(System.in);

BufferedReader flujoE = new BufferedReader(isr);

La clase InputStreamReader establece un puen-te para pasar flujos de bytes a flujos de ca-racteres tal como se muestra en la figura 1.3. Para ello debemos definir el flujo que hemos denominado isr como se muestra en el código anterior.

Además el código anterior indica que el flujoE dirigirá todas las invocaciones de sus métodos al flujo subyacente isr; este flujo, en el caso de que el origen sea el teclado (dispositivo vinculado con System.in), deberá convertir los bytes leídos del teclado en caracteres. De esta forma flujoE podrá suministrar un flujo de caracteres al programa destino de los datos.

34 Mg. ABRAHAM GAMARRA MORENO

Figura 1.3

Para realizar la lectura de las cadenas uti-lizaremos el método readLine, el cual nos permite leer una línea de texto. El método readLine tiene la siguiente sintaxis:

public String readLine() throws IOException

1.16.2. FLUJOS DE SALIDA A TRAVÉS DE LA SUBCLASE PRINTSTREAM (SALIDA POR EL MONITOR)

La clase PrintStream se deriva indirectamente de OutputStream, por lo tanto hereda todos los miembros de ésta: por ejemplo el método write expuesto anteriormente. Otros métodos de interés que aporta esta clase son: print y println. La sintaxis para estos métodos es la siguiente:

print (tipo argumento);

println ([tipo argumento]);

Los métodos print y println son esencialmente los mismos; ambos escriben su argumento en el flujo de salida. La única diferencia entre ellos es que println añade un carácter ‘\n‘ (avance a la línea siguiente) al final de su salida, y print no.

Programa flujoE isr in Teclado

caracteresbytes

PROGRAMACION CON JAVA 2 35

Ejemplo ( 3): Programa que lee e imprime una cadena.

//archivo: lecturacadenas.java import java.io.*; class lecturacadenas { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStream-Reader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una //línea de texto System.out.print("Introduzca un texto: "); sdato = flujoE.readLine(); // leer una línea de //texto System.out.print("el texto leido es: "); System.out.println(sdato); // escribir la //línea leída } }

La ejecución muestra la siguiente pantalla:

1.16.3. MANEJO DE LOS TIPOS DE DATOS PRIMITIVOS

Evidentemente, cualquier operación aritmética requiere de valores numéricos; pero, según lo expuesto en el mejor de los casos sólo se

36 Mg. ABRAHAM GAMARRA MORENO

puede obtener una cadena de bytes. Ahora bien, para que esa cadena de caracteres pueda ser utilizada en una expresión aritmética, tiene que adquirir la categoría de valor nu-mérico, lo que implica convertirla a un valor de alguno de los tipos primitivos. Esto puede hacerse utilizando los métodos proporcionados por las clases que encapsulan los tipos pri-mitivos.

Class Integer

La clase Integer cubre un valor del tipo de dato primitivo int dentro de un objeto.

Además, esta clase proporciona varios métodos para convertir un int a String y un String a int, así como otras constantes y métodos úti-les cuando tratan con un int.

A continuación se tiene algunos atributos y métodos principales de la clase Integer:

Atributos

Static int MAX_VALUE Una constante que contiene el máximo va-lor en un int: 231-1.

Static int MIN_VALUE Una constante que contiene el minimo va-lor en un int: -231.

Constructores

Integer(int value) Construye un objeto Integer que representa el va-lor especifico del int.

Integer(String s) Construye un objeto Integer que representa el va-lor int indicado por el parámetro String.

Ahora mostramos en el idioma original los Mé-todos de la clase Integer1

Métodos

1 Fuente: JDK HELP

PROGRAMACION CON JAVA 2 37

byte byteValue() Returns the value of this Integer as a byte.

int compareTo(Integer anotherInteger) Compares two Integer objects numeri-cally.

int compareTo(Object o) Compares this Integer object to another object.

static Integer decode(String nm) Decodes a String into an Integer.

double doubleValue() Returns the value of this Integer as a double.

boolean equals(Object obj) Compares this object to the specified object.

float floatValue() Returns the value of this Integer as a float.

static Integer getInteger(String nm) Determines the integer value of the system property with the specified name.

static Integer getInteger(String nm, int val) Determines the integer value of the system property with the specified name.

static Integer getInteger(String nm, Integer val) Returns the integer value of the sys-tem property with the specified name.

int hashCode() Returns a hash code for this Integer.

int intValue() Returns the value of this Integer as an int.

long longValue() Returns the value of this Integer as a long.

static int parseInt(String s) Parses the string argument as a signed decimal integer.

static int parseInt(String s, int radix) Parses the string argument as a signed integer in the radix specified by the second ar-gument.

38 Mg. ABRAHAM GAMARRA MORENO

short shortValue() Returns the value of this Integer as a short.

static String toBinaryString(int i) Returns a string representation of the integer argument as an unsigned integer in ba-se 2.

static String toHexString(int i) Returns a string representation of the integer argument as an unsigned integer in ba-se 16.

static String toOctalString(int i) Returns a string representation of the integer argument as an unsigned integer in ba-se 8.

String toString() Returns a String object representing this Integer's value.

static String toString(int i) Returns a String object representing the specified integer.

static String toString(int i, int radix) Returns a string representation of the first argument in the radix specified by the se-cond argument.

static Integer valueOf(String s) Returns an Integer object holding the value of the specified String.

static Integer valueOf(String s, int radix) Returns an Integer object holding the value extracted from the specified String when parsed with the radix given by the second argu-ment.

Class Float

La clase Float cubre un valor del tipo de da-to primitivo float dentro de un objeto.

Además, esta clase proporciona varios métodos para convertir un float a String y un String a float, así como otras constantes y métodos útiles cuando tratan con un float.

PROGRAMACION CON JAVA 2 39

A continuación se tiene algunos atributos y métodos principales de la clase Float2:

Atributos

static float MAX_VALUE A constant holding the largest positive finite value of type float.

static float MIN_VALUE A constant holding the smallest positive nonzero value of type float.

static float NaN A constant holding a Not-a-Number (NaN) value of type float.

static float NEGATIVE_INFINITY A constant holding the negative infinity of type float.

static float POSITIVE_INFINITY A constant holding the positive infinity of type float.

static Class TYPE The Class instance representing the pri-mitive type float.

Constructores

Float(double value) Constructs a newly allocated Float object that re-presents the argument converted to type float.

Float(float value) Constructs a newly allocated Float object that re-presents the primitive float argument.

Float(String s) Constructs a newly allocated Float object that represents the floating-point value of type float repre-sented by the string.

Métodos

byte byteValue() Returns the value of this Float as a byte (by casting to a byte).

static int compare(float f1, float f2) Compares the two specified float val-

2 Fuente: HELP JDK 2 Ver 1.4 (Idioma Original)

40 Mg. ABRAHAM GAMARRA MORENO

ues.

int compareTo(Float anotherFloat) Compares two Float objects numerically.

int compareTo(Object o) Compares this Float object to another object.

double doubleValue() Returns the double value of this Float object.

boolean equals(Object obj) Compares this object against the spe-cified object.

static int floatToIntBits(float value) Returns a representation of the speci-fied floating-point value according to the IEEE 754 floating-point "single format" bit layout.

static int floatToRawIntBits(float value) Returns a representation of the speci-fied floating-point value according to the IEEE 754 floating-point "single format" bit layout, preserving Not-a-Number (NaN) values.

float floatValue() Returns the float value of this Float object.

int hashCode() Returns a hash code for this Float ob-ject.

static float intBitsToFloat(int bits) Returns the float value corresponding to a given bit represention.

int intValue() Returns the value of this Float as an int (by casting to type int).

boolean isInfinite() Returns true if this Float value is in-finitely large in magnitude, false otherwise.

static boolean isInfinite(float v) Returns true if the specified number is infinitely large in magnitude, false otherwise.

boolean isNaN() Returns true if this Float value is a Not-a-Number (NaN), false otherwise.

static boolean isNaN(float v) Returns true if the specified number is

PROGRAMACION CON JAVA 2 41

a Not-a-Number (NaN) value, false otherwise.

long longValue() Returns value of this Float as a long (by casting to type long).

static float parseFloat(String s) Returns a new float initialized to the value represented by the specified String, as performed by the valueOf method of class Float.

short shortValue() Returns the value of this Float as a short (by casting to a short).

String toString() Returns a string representation of this Float object.

static String toString(float f) Returns a string representation of the float argument.

static Float valueOf(String s) Returns a Float object holding the floatvalue represented by the argument string s.

Ejemplo( 4): Programa que lee y visualiza un entero y un float.

//archivo: lecturanumeros.java import java.io.*; //import java.lang.*; class lecturanumeros { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStream-Reader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una // línea de texto int nume; //variable que almacena un número //entero float numf; //variable que almacena un número //float // lectura e impresion de un numero entero System.out.print("Introduzca un numero entero: ");

42 Mg. ABRAHAM GAMARRA MORENO

sdato = flujoE.readLine(); // leer una línea de // texto nume=Integer.parseInt(sdato);//convierte cadena a // entero nume=nume+5; System.out.println("el numero + 5 es : "+nume); // lectura e impresion de un numero float System.out.print("Introduzca un numero real: "); sdato = flujoE.readLine(); // leer una línea de //texto numf=Float.parseFloat(sdato);//convierte cadena a //float numf=numf+5; System.out.println("el numero + 5 es : "+numf); } }

La salida del programa es:

PROGRAMACION CON JAVA 2 43

Ejemplo ( 5): Programa que calcula el área de un triángulo.

//archivo: operarit.java import java.io.*; class operarit { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStream-Reader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una //línea de texto float b,h; //base y altura float area; System.out.print("Introduzca base: "); sdato = flujoE.readLine(); // leer una línea de // texto b=Float.parseFloat(sdato);//convierte cadena a //float System.out.print("Introduzca altura: "); sdato = flujoE.readLine(); // leer una línea de //texto h=Float.parseFloat(sdato);//convierte cadena a //float //calcula el area del triangulo area=b*h/2; System.out.println("el area es : "+area); } }

La salida del programa es:

44 Mg. ABRAHAM GAMARRA MORENO

1.17. LA CLASE MATH

java.lang.Object | +--java.lang.Math

La clase Math contiene métodos para desarrollar opera-ciones numéricas básicas tal como la potenciación, lo-garitmo, raíz cuadrada y las funciones trigonométri-cas.

A continuación se muestran los atributos y métodos de la clase Math (versión original).

Atributos static double E

The double value that is closer than any other to e, the base of the natural logarithms.

static double PI The double value that is closer than any other to pi, the ratio of the circumference of a circle to its diameter.

Métodos static double abs(double a)

Returns the absolute value of a double value.

static float abs(float a) Returns the absolute value of a float value.

static int abs(int a) Returns the absolute value of an int value.

static long abs(long a) Returns the absolute value of a long va-lue.

static double acos(double a) Returns the arc cosine of an angle, in the range of 0.0 through pi.

static double asin(double a) Returns the arc sine of an angle, in the range of -pi/2 through pi/2.

PROGRAMACION CON JAVA 2 45

static double atan(double a) Returns the arc tangent of an angle, in the range of -pi/2 through pi/2.

static double atan2(double y, double x) Converts rectangular coordinates (x, y) to polar (r, theta).

static double ceil(double a) Returns the smallest (closest to nega-tive infinity) double value that is not less than the argument and is equal to a mathematical inte-ger.

static double cos(double a) Returns the trigonometric cosine of an angle.

static double exp(double a) Returns Euler's number e raised to the power of a double value.

static double floor(double a) Returns the largest (closest to posi-tive infinity) double value that is not greater than the argument and is equal to a mathematical integer.

static double IEEEremainder(double f1, double f2) Computes the remainder operation on two arguments as prescribed by the IEEE 754 standard.

static double log(double a) Returns the natural logarithm (base e) of a double value.

static double max(double a, double b) Returns the greater of two double val-ues.

static flota max(float a, float b) Returns the greater of two float values.

static int max(int a, int b) Returns the greater of two int values.

static long max(long a, long b) Returns the greater of two long values.

static double min(double a, double b) Returns the smaller of two double val-ues.

static flota min(float a, float b) Returns the smaller of two float values.

static int min(int a, int b) Returns the smaller of two int values.

46 Mg. ABRAHAM GAMARRA MORENO

static long min(long a, long b) Returns the smaller of two long values.

static double pow(double a, double b) Returns of value of the first argument raised to the power of the second argument.

static double random() Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.

static double rint(double a) Returns the double value that is closest in value to the argument and is equal to a mathe-matical integer.

static long round(double a) Returns the closest long to the argu-ment.

static int round(float a) Returns the closest int to the argu-ment.

static double sin(double a) Returns the trigonometric sine of an angle.

static double sqrt(double a) Returns the correctly rounded positive square root of a double value.

static double tan(double a) Returns the trigonometric tangent of an angle.

static double toDegrees(double angrad) Converts an angle measured in radians to an approximately equivalent angle measured in degrees.

static double toRadians(double angdeg) Converts an angle measured in degrees to an approximately equivalent angle measured in radians.

PROGRAMACION CON JAVA 2 47

Ejemplo ( 6): Escriba un programa que con-vierta coordenadas polares a coordenadas car-tesianas.

( )θcos*rx =

( )θsenry *=

//archivo: cartepola.java import java.io.*; import java.lang.Math; class cartepola { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto float r,teta; //radio, angulo double x,y; // (x,y) coordenada cartesiana System.out.println("Ingrese coordenada polar : "); System.out.print("Introduzca radio: "); sdato = flujoE.readLine(); // leer una línea de texto r=Float.parseFloat(sdato);//convierte cadena a float System.out.print("Introduzca angulo: ");

(X,Y)

θ

r

48 Mg. ABRAHAM GAMARRA MORENO

sdato = flujoE.readLine(); // leer una línea de texto teta=Float.parseFloat(sdato);//convierte cadena a float //convertimos el angulo a radianes teta=(float) Math.toRadians(teta); //transformamos las coordenadas x=r*Math.cos(teta); y=r*Math.sin(teta); System.out.print("la coordenada cartesiana es : "); System.out.println("("+x+","+y+")"); } }

La salida es:

1.18. EXPRESIONES, SENTENCIAS Y BLOQUES

Los programas en Java se componen de sentencias, que a su vez están compuestas en base a expresiones. Una ex-presión esta formada por una combinación de operadores y operandos que se evalúan para obtener un resultado particular. Los operandos pueden ser variables, cons-tantes o llamadas a métodos. Una llamada a un método evalúa el valor devuelto por el método y el tipo de una llamada a un método es el tipo devuelto por ese método.

Una expresión es una serie de variables, operadores y llamadas a métodos (construidas de acuerdo a la sin-taxis del lenguaje) que se evalúan a un único valor. Podemos escribir expresiones compuestas combinando ex-presiones simples. Cuando escribimos expresiones com-puestas, debemos ser explícitos e indicar con parénte-sis que operadores se deben evaluar primero. Si elegi-mos no utilizar paréntesis, luego la plataforma Java evaluará la expresión compuesta en el orden dictado por la precedencia de los operadores.

Una sentencia forma una unidad completa de ejecución y es terminada con un (;). Hay tres tipos de sentencias: sentencias de expresión, sentencias de declaración, y sentencias de control de flujo. Podemos agrupar cero o

PROGRAMACION CON JAVA 2 49

más sentencias juntas en un bloque con llaves ( { y } ). Aunque no se requiere, recomendamos utilizar blo-ques con las sentencias de control de flujo, aún cuan-do haya una sola sentencia en el bloque.

1.19. SENTENCIAS DE CONTROL DE FLUJO

Las sentencias de control de flujo se usan para condi-cionar la ejecución del código, para hacer loops sobre un conjunto de líneas de código o para saltar de una parte del programa a otra. A continuación veremos como controlar el flujo del programa con estas sentencias.

1.19.1. SENTENCIA if

Nos permite ejecutar una parte u otra del có-digo dependiendo de la evaluación.

La sintaxis es la siguiente:

if (expresión booleana) { // bloque por true sentencia v1; sentencia v2; ... sentencia vn; } else { // bloque por false sentencia f1; sentencia f2; ... sentencia fn; }

expresión es una evaluación lógica, es decir, debe evaluar true o false. Por true se ejecu-ta el primer bloque de sentencias y por false el segundo.

Una forma abreviada es cuando tenemos una so-la sentencia, caso en el cual no hace falta poner las llaves.

if (expresión booleana) sentencia por true; else sentencia por false;

50 Mg. ABRAHAM GAMARRA MORENO

Se puede obviar la sentencia else.

Ejemplo ( 7): Hacer un programa que obtenga el valor absoluto de un número (Versión1).

//archivo: valabsoluto.java import java.io.*; class valabsoluto { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto int num,valabs; System.out.print("Ingrese un numero : "); sdato = flujoE.readLine(); // leer una línea de texto num=Integer.parseInt(sdato);//convierte cadena a int

PROGRAMACION CON JAVA 2 51

// calcular el valor absoluto if (num<0) valabs=-1*num; else valabs=num; System.out.println("el valor absoluto es: "+valabs); } }

La salida será:

Ejemplo( 8): Hacer un programa que obtenga el valor absoluto de un número (Versión 2).

52 Mg. ABRAHAM GAMARRA MORENO

//archivo: valabsoluto2.java import java.io.*; class valabsoluto2 { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto int num; System.out.print("Ingrese un numero : "); sdato = flujoE.readLine(); // leer una línea de texto num=Integer.parseInt(sdato);//convierte cadena a int // calcular el valor absoluto if (num<0) num=-1*num; System.out.println("el valor absoluto es: "+num); } }

La salida del programa es:

1.19.2. ANIDAMIENTO DE SENTENCIAS if

A continuación de la sentencia if (cuando la condición tiene el valor verdadero), se puede tener otra sentencia if anidada. De igual forma se puede anidar una sentencia if luego del else. Inclusive se puede tener más sen-tencias if dentro de estos if anidados.

PROGRAMACION CON JAVA 2 53

if (expresión booleana) if (expresión booleana) sentencia por true; else sentencia por false;

else if (expresión booleana) sentencia por true; else sentencia por false;

Cuando no se utilizan las llaves para agrupar expresiones las sentencias else se emparejan con el if más cercano.

Ejemplo ( 9): Escriba un programa que lea 3 números enteros e imprima el mayor.

54 Mg. ABRAHAM GAMARRA MORENO

//archivo: mayor.java import java.io.*; class mayor { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto int n1,n2,n3;//numeros int mayor;// número mayor // lectura de los 3 numeros System.out.print("Ingrese 1er numero : "); sdato = flujoE.readLine(); // leer una línea de texto n1=Integer.parseInt(sdato);//convierte cadena a int System.out.print("Ingrese 2do numero : "); sdato = flujoE.readLine(); // leer una línea de texto n2=Integer.parseInt(sdato);//convierte cadena a int System.out.print("Ingrese 3er numero : "); sdato = flujoE.readLine(); // leer una línea de texto n3=Integer.parseInt(sdato);//convierte cadena a int // calcular el mayor if (n1>n2) if (n1>n3) mayor=n1; else mayor=n3; else if (n2>n3) mayor=n2; else mayor=n3; System.out.println("el numero mayor es: "+mayor); } }

La salida es:

PROGRAMACION CON JAVA 2 55

Ejemplo ( 10): Escriba un programa que calcu-le la división de 2 números.

//archivo: division.java import java.io.*; class division { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto float num,den,div;//numerador, denominador y division // lectura de los numeros System.out.print("Ingrese numerador : "); sdato = flujoE.readLine(); // leer una línea de texto num=Float.parseFloat(sdato);//convierte cadena System.out.print("Ingrese denominador : "); sdato = flujoE.readLine(); // leer una línea de texto den=Float.parseFloat(sdato);//convierte cadena

56 Mg. ABRAHAM GAMARRA MORENO

// calcular la division if (den==0) if (num==0) System.out.println("La divison es: Inde-terminado"); else System.out.println("La divison es: Infi-nito"); else { div=num/den; System.out.println("La division : "+div); } } }

Ejemplo ( 11): Elaborar un programa donde se ingrese el sueldo de un trabajador, su res-pectiva categoría (A,B,C) y su año de ingre-so. Luego se calcule e imprima su nuevo suel-do si el incremento es:

a) Categoría "A" 15% para los que ingresaron a trabajar antes de 1980 y 12% para el resto.

PROGRAMACION CON JAVA 2 57

b) Categoría "B" 20% para los que ingresaron a trabajar antes de 1980 y 17% para el resto.

c) Categoría "C" 25% para los que ingresaron a trabajar antes de 1980 y 22% para el resto.

//archivo: sueldo.java import java.io.*;

58 Mg. ABRAHAM GAMARRA MORENO

class sueldo { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto double su;//sueldo char cat;//categoría int ing;//año de ingreso // lectura de los 3 numeros System.out.print("Ingrese sueldo : "); sdato = flujoE.readLine(); // leer una línea de texto su=Float.parseFloat(sdato);//convierte cadena a float System.out.print("Ingrese categoria (a , b o c): "); cat = (char) flujoE.read(); // leer caracter // la siguiente línea evita errores en el flujo de entrada, // permite saltar '\r\n'(retorno de carro y nueva línea) que // quedarón pendientes y no fuerón leídos por read(). flujoE.skip(2); System.out.print("Ingrese año de ingreso : "); sdato = flujoE.readLine(); // leer una línea de texto ing=Integer.parseInt(sdato);//convierte cadena // if (ing<1980) { if (cat=='a') su=su*1.15; if (cat=='b') su=su*1.20; if (cat=='c') su=su*1.25; } else //en otro caso ing>=1980 { if (cat=='a') su=su*1.12; if (cat=='b') su=su*1.17; if (cat=='c') su=su*1.22; } System.out.println("el nuevo sueldo es: "+su); } }

PROGRAMACION CON JAVA 2 59

Nota: flujoE.skip(2), evita errores cuando se realiza la lectura de datos a través del flu-jo de entrada; porque permite saltar '\r\n'(el retorno de carro y nueva línea) que quedarón pendientes y no fuerón leídos por read().

Si usted no lo utiliza no podrá leer el año de ingreso.

Ejemplo ( 12): La comisión sobre las ventas totales de un empleado es como sigue:

• Si ventas < 50.00 unidades monetarias (u.m.) entonces no hay comisión.

• Si esta entre 50.00 u.m. y 500.00 u.m. incluidos, entonces la comisión es 10% de las ventas.

• Si las Ventas > 500.00, entonces la co-misión es 50.00 u.m. mas 8% de las ven-tas superiores a 500.00.

El programa calcula la comisión cuando se in-gresa las ventas.

60 Mg. ABRAHAM GAMARRA MORENO

//archivo: ventas.java import java.io.*; public class ventas { public static void main(String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto double ventas,comision=0; System.out.print("Ventas totales : "); sdato = flujoE.readLine(); // leer una línea de texto ventas=Double.parseDouble(sdato);//convierte cadena

PROGRAMACION CON JAVA 2 61

if(ventas<50) comision=0; else if(ventas>=50&&ventas<=500) comision=ventas*0.10; else if(ventas>500) comision=50+(ventas-500)*0.08; System.out.println("Comision: "+comision); } }

1.19.3. SENTENCIA switch

La sentencia switch permite ejecutar una de varias acciones, en función del valor de una expresión. Es una sentencia especial para de-cisiones múltiples.

Switch (expresion) { case expresión_constante_1: [sentencia1;] case expresión_constante_2: [sentencia2;] ... [default:] sentencia n; }

donde expresión es una expresión entera de tipo char, byte, short o int y expresión_constante es una constante también entera y de los mismos tipos. Tanto la expresión como las expresiones constantes son convertidas implícitamente a int. Por último, sentencia es una sentencia simple o compuesta. En el caso de tratarse de una sentencia compuesta, no hace falta incluir las sentencias simples entre { }.

La sentencia switch evalúa la expresión entre paréntesis y compara su valor con las cons-tantes de cada case. La ejecución de las sen-tencias del bloque de la sentencia switch, comienza en el case cuya constante coincida

62 Mg. ABRAHAM GAMARRA MORENO

con el valor de la expresión y continúa hasta el final del bloque o hasta una sentencia que transfiera el control fuera del bloque de switch; por ejemplo, break. La sentencia switch puede incluir cualquier número de cláusulas case.

Si no existe una constante igual al valor de la expresión, entonces se ejecutan las sen-tencias que están a continuación de default, si esta cláusula ha sido especificada. La cláusula default puede colocarse en cualquier parte del bloque y no necesariamente al fi-nal.

La sentencia break finaliza la ejecución de la sentencia switch.

Ejemplo (13): Escribir un programa que lea un carácter e identifique si es vocal o conso-nante.

PROGRAMACION CON JAVA 2 63

//archivo: vocales.java import java.io.*; class vocales { public static void main (String[] args) throws IOException { char c;//caracter // lectura System.out.print("Ingrese letra : "); c=(char) System.in.read();//lee caracter //convertir a mayusculas c=Character.toUpperCase(c); // verificar si es letra if (Character.isLetter(c)) switch (c) { case 'A': case 'E': case 'I': case 'O': case 'U':System.out.println(c+" es vocal"); break; default : System.out.println(c+" no es vocal"); } else System.out.println(c+" no es letra"); } }

Ejemplo (14) : Programa que lee un número de 1 a 12 e imprime el nombre del mes.

64 Mg. ABRAHAM GAMARRA MORENO

PROGRAMACION CON JAVA 2 65

//archivo: mes.java import java.io.*; class mes { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto int mes;//mes // lectura de los numeros System.out.print("Ingrese numero de mes : "); sdato = flujoE.readLine(); // leer una línea de texto mes=Integer.parseInt(sdato);//convierte cadena switch (mes) { case 1: System.out.println("Enero"); break; case 2: System.out.println("Febrero"); break; case 3: System.out.println("Marzo"); break; case 4: System.out.println("Abril"); break; case 5: System.out.println("Mayo"); break; case 6: System.out.println("Junio"); break; case 7: System.out.println("Julio"); break; case 8: System.out.println("Agosto"); break; case 9: System.out.println("Septiembre"); break; case 10: System.out.println("Octubre"); break; case 11: System.out.println("Noviembre"); break; case 12: System.out.println("Diciembre"); break; default: System.out.println("Error en el mes"); break; } }//fin main }

Lo que hace es evaluar mes y en función de su valor ejecuta las sentencias correspondien-tes. Cabe destacar la presencia de break, la cual es una palabra clave que interrumpe el flujo de ejecución enviándolo a la primera línea a continuación del cierre del switch. Podemos observar también la palabra clave de-fault en último lugar, la cual se ejecutará si mes no ha coincidido con ningún valor ex-plicitado, default no es obligatorio y por lo tanto puede no estar.

66 Mg. ABRAHAM GAMARRA MORENO

Ejemplo (15): Programa que calcula el monto a pagar por el consumo de energía eléctrica, si durante su ejecución se ingresa el consumo y el tipo de tarifa. Las tarifas son:

TIPO DE TARIFA

COSTO (U.M./Kw-h)

1 2.30 2 8.25 3 6.42 4 5.80 5 9.65

PROGRAMACION CON JAVA 2 67

//archivo: tarifa.java import java.io.*; public class tarifa { public static void main(String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE

68 Mg. ABRAHAM GAMARRA MORENO

InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de //texto double consumo,tarifa,monto; int tipo; System.out.print("Consumo: "); sdato = flujoE.readLine(); // leer una línea de texto consumo=Float.parseFloat(sdato);//convierte cadena System.out.print("Tipo de tarifa (1 al 5): "); sdato = flujoE.readLine(); // leer una línea de texto tipo=Integer.parseInt(sdato);//convierte cadena switch(tipo) { case 1:tarifa=2.3;break; case 2:tarifa=8.25;break; case 3:tarifa=6.42;break; case 4:tarifa=5.80;break; case 5:tarifa=9.65;break; default:tarifa=0;break; } if(tarifa!=0) { monto=consumo*tarifa; System.out.println("\nMonto a pagar: "+monto); } else System.out.println("\nTarifa incorrecta"); } }

1.19.4. SENTENCIA while

Sirve para ejecutar continuamente un bloque de código, mientras que una condición perma-nezca en true.

La sintaxis general es:

PROGRAMACION CON JAVA 2 69

while (expresión booleana) { sentencia 1; sentencia 2; ... sentencia 3; }

o bien:

while (expresión booleana)

sentencia;

while no ejecutará el código (ni siquiera una vez) a menos que la expresión booleana sea true.

La ejecución de la sentencia while sucede así:

1. Se evalúa la condición.

2. Si el resultado de la evaluación es false (falso), la sentencia no se ejecuta y se pasa el control a la siguiente sentencia en el programa.

3. Si el resultado de la evaluación es true (verdadero), se ejecuta la sentencia y el proceso descrito se repite desde el punto 1.

Uso de acumuladores en las sentencias repeti-tivas

Ejemplo (16): Realizar un programa que determine los divisores de un número.

Para poder encontrar los divisores de este número, se utilizará una variable que se com-porte como un contador. Un contador es una variable con el siguiente formato:

Contador = Contador operador constante

Para el programa d es un contador que tiene la siguiente forma:

70 Mg. ABRAHAM GAMARRA MORENO

d = d + 1

Cada vez que se ejecute el ciclo repetitivo, esta variable permitirá incrementar a d en una unidad.

PROGRAMACION CON JAVA 2 71

//archivo: divisores.java import java.io.*; class divisores { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto int num,d; //numero y divisor int r;//resto System.out.print("Introduzca un numero : "); sdato = flujoE.readLine(); // leer una línea de texto num=Integer.parseInt(sdato);//convierte cadena a int System.out.println("Los divisores son: "); //obtiene los divisores d=1; while (d<=num) { r=num%d; if (r==0) System.out.println(d); d++; } } }

72 Mg. ABRAHAM GAMARRA MORENO

Ejemplo (17): Programa que calcula la suma de las cifras de un número.

Para encontrar la suma de las cifras de un número, se utilizará una variable que se com-porte como un acumulador. Un acumulador es una variable con el siguiente formato:

Acumulador = Acumulador operador variable

Para el programa s es un acumulador que tiene la siguiente forma:

s = s + r

Cada vez que se ejecute el ciclo repetitivo, esta variable s, permitirá acumular la suma de los valores que tenga la variable r.

PROGRAMACION CON JAVA 2 73

//archivo: sumacifras.java import java.io.*;

74 Mg. ABRAHAM GAMARRA MORENO

class sumacifras { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto int num,r; //numero y resto int s;//acumula suma de las cifras System.out.print("Introduzca un numero : "); sdato = flujoE.readLine(); // leer una línea de texto num=Integer.parseInt(sdato);//convierte cadena a int //obtiene las cifras s=0; while (num!=0) { r=num%10; s=s+r; num=num/10; } System.out.println("La suma de las cifras es: "+s); } }

Se puede colocar un while dentro de otro whi-le (while’s anidados)

Ejemplo (18): Escribir un programa que permi-ta calcular el promedio de los números posi-tivos ingresados por el teclado, el ingreso termina cuando el número ingresado es CERO. (Usar while)

Ejemplo:

PROGRAMACION CON JAVA 2 75

Ingrese un número: 6 <ENTER>

Ingrese un número: -3 <ENTER>

Ingrese un número: 10 <ENTER>

Ingrese un número: 2 <ENTER>

Ingrese un número: 0 <ENTER>

El promedio de los números positivos ingresa-dos es: 6

76 Mg. ABRAHAM GAMARRA MORENO

//archivo: promposi.java // respuesta pregunta 1 examen 1 2003-1 import java.io.*; class promposi { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto float num; //numero float s;//suma de los números int n;//cantidad de números float p;//promedio de los números //lee numeros n=0; s=0; System.out.print("Ingrese un numero (cero para finalizar): "); sdato = flujoE.readLine(); // leer una línea de texto num=Float.parseFloat(sdato);//convierte cadena while(num!=0) { if(num>0) { s=s+num; n++; } System.out.print("Ingrese un numero (cero para finalizar): "); sdato = flujoE.readLine(); // leer una línea de //texto num=Float.parseFloat(sdato);//convierte cadena } p=s/n; System.out.println("El promedio es: "+p); }//fin de main }//fin de la clase

PROGRAMACION CON JAVA 2 77

Ejemplo (19): Realice el diagrama de activi-dades y el programa en java, para un programa que lea caracteres. El programa debe contar cuantas vocales de cada uno existen; también debe contar cuantos caracteres que no son vo-cales se ingresaron. La lectura de los carac-teres finaliza cuando se ingresa ‘*’. Sólo debe mostrar el total de los caracteres que son mayores que cero. El ‘*’ no se debe tomar en cuenta como carácter ingresado. (usar whi-le)

Ejemplo:

Ingrese carácter (* para finalizar): a <ENTER>

Ingrese carácter (* para finalizar): e <ENTER>

Ingrese carácter (* para finalizar): n <ENTER>

Ingrese carácter (* para finalizar): p <ENTER>

Ingrese carácter (* para finalizar): * <ENTER>

a existe 1 vez(ces)

e existe 1 vez(ces)

caracteres que no son vocales existe(n) 2 vez(ces)

78 Mg. ABRAHAM GAMARRA MORENO

PROGRAMACION CON JAVA 2 79

//archivo: exa1p120032.java // respuesta pregunta 1 examen 1 2003-2 import java.io.*; class exa1p120032 { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); int a=0,e=0,i=0,o=0,u=0,nv=0;//contadores char car; System.out.print("Ingrese caracter (* para finalizar): "); car = (char) flujoE.read(); // leer un carácter flujoE.skip(2); while(car!='*') { switch (car) { case 'a': a++;break; case 'e': e++;break; case 'i': i++;break; case 'o': o++;break; case 'u': u++;break; default : nv++; } System.out.print("Ingrese caracter (* para finalizar):"); car = (char) flujoE.read(); // leer un carácter flujoE.skip(2); }//fin de while if(a>0) System.out.println("a existe "+a+" vez(ces)"); if(e>0) System.out.println("e existe "+e+" vez(ces)"); if(i>0) System.out.println("i existe "+i+" vez(ces)"); if(o>0) System.out.println("o existe "+o+" vez(ces)"); if(u>0) System.out.println("u existe "+u+" vez(ces)"); if(nv>0) System.out.println("caracteres que no son vocales existen "+ nv+ " vez(ces)"); }//fin de main }//fin de la clase

80 Mg. ABRAHAM GAMARRA MORENO

PROGRAMACION CON JAVA 2 81

Ejemplo (20): Realice el diagrama de activi-dades y el programa en java, para un programa que lea un número en base 10 y lo convierta a otra base mayor que 10. La base mayor que 10 será leído por el teclado. (usar while).

82 Mg. ABRAHAM GAMARRA MORENO

PROGRAMACION CON JAVA 2 83

//archivo: exa1p220032.java // respuesta pregunta 1 examen 1 2003-2 import java.io.*; class exa1p220032 { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); boolean c1=false,c2=false,c3=false,c4=false,c5=false; int cif=0, e=0, s=0;//cif=cantidad de cifras, e=exponente //s= acumulador int num,base;//num=número en base 10, base=base mayor que 10 int r; String sdato; System.out.print("Ingrese numero en base 10: "); sdato=flujoE.readLine(); num=Integer.parseInt(sdato); System.out.print("base mayor que 10: "); sdato=flujoE.readLine(); base=Integer.parseInt(sdato); while(num!=0) { r=num%base; cif=cif+1; if (r>=10) { switch (cif) { case 1: c1=true;break; case 2: c2=true;break; case 3: c3=true;break; case 4: c4=true;break; case 5: c5=true;break; }//fin de switch r=r-10; }//fin de if s=s+r*(int) Math.pow(10,e); e=e+1; num=num/base; }//fin de whilw System.out.print("EL numero en base "+base+" es:"); e=e-1; while(s!=0) { r=s/(int) Math.pow(10,e); s=s%(int) Math.pow(10,e); e=e-1;

84 Mg. ABRAHAM GAMARRA MORENO

if (cif==1 && c1==true) r=r+10; if (cif==2 && c2==true) r=r+10; if (cif==3 && c3==true) r=r+10; if (cif==4 && c4==true) r=r+10; if (cif==5 && c5==true) r=r+10; switch (r) { case 10: System.out.print("A");break; case 11: System.out.print("B");break; case 12: System.out.print("C");break; case 13: System.out.print("D");break; case 14: System.out.print("E");break; case 15: System.out.print("F");break; default: System.out.print(r);break; } cif=cif-1; } System.out.print("\n"); }//fin de main }//fin de la clase

PROGRAMACION CON JAVA 2 85

1.19.5. SENTENCIA do-while

La diferencia con while es que en do-while se asegura la ejecución de las sentencias al me-nos 1 vez, ya que primero se ejecuta y luego se evalúa.

La sentencia do ... while ejecuta una senten-cia, simple o compuesta, una o mas veces de-pendiendo del valor de una expresión. Su sin-taxis es la siguiente:

do { sentencia 1; sentencia 2; sentencia 3; ... sentencia n; } while (expresión booleana);

o bien:

do sentencia 1; while (expresión booleana);

Observe que la estructura do ... while fina-liza con un punto y coma.

La ejecución de una sentencia do .. while su-cede de la siguiente forma:

1. Se ejecuta el bloque (sentencia simple o compuesta) de do.

2. Se evalúa la expresión correspondiente a la condición de finalización del bucle.

3. Si el resultado de la evaluación es false (falso), se pasa el control a la siguiente sentencia en el programa.

86 Mg. ABRAHAM GAMARRA MORENO

4. Si el resultado de la evaluación es true (verdadero), el proceso descrito se repite desde el punto 1.

Ejemplo (21): Escribir un programa que permi-ta calcular la suma de la siguiente serie, para N términos; siendo N ingresado por te-clado: (Usar sólo do… while)

...!8

8

!7

7

!6

6

!5

5

!4

4

!3

3

!2

21 +−+−+−+−=S

N términos

PROGRAMACION CON JAVA 2 87

//archivo: serie.java import java.io.*;

88 Mg. ABRAHAM GAMARRA MORENO

class serie { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto float fact; //factorial float s;//suma de los términos int n;//cantidad de términos int i;//contador //lee numeros i=0; s=0; System.out.print("Cantidad de terminos : "); sdato = flujoE.readLine(); // leer una línea de texto n=Integer.parseInt(sdato);//convierte cadena fact=1; do { i++; //calcula el factorial de i fact=fact*i; if (i%2==0) //i es par s=s-i/fact; else //i es impar s=s+i/fact; }while(n!=i); System.out.println("La suma es: "+s); }//fin de main }//fin de la clase

Ejemplo (22): Programa que determina si un número es perfecto. Un numero perfecto es un entero positivo que es igual a la suma de sus divisores, excluido si mismo.

PROGRAMACION CON JAVA 2 89

//archivo: perfecto.java import java.io.*; class perfecto { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto

90 Mg. ABRAHAM GAMARRA MORENO

int num,r; //numero y resto int s;//acumula suma de los divisores int d;//divisor System.out.print("Introduzca un numero : "); sdato = flujoE.readLine(); // leer una línea de texto num=Integer.parseInt(sdato);//convierte cadena a int //determina si un número es perfecto s=0; d=1; do { r=num%d; if (r==0) s=s+d; d++; } while (d<num); if (s==num) System.out.println("El numero es perfecto"); else System.out.println("El numero no es perfecto"); } }

Ejemplo (23): Escribir un programa que impri-ma los “n” primeros números perfectos, si “n” es ingresado por el teclado.

PROGRAMACION CON JAVA 2 91

92 Mg. ABRAHAM GAMARRA MORENO

//archivo: nperfectos.java import java.io.*; class nperfectos { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto int num,r; //numero y resto int s;//acumula suma de los divisores int d;//divisor int n;//variable para mostrar los "n" perfectos int c;//contador de números perfectos System.out.print("Cuantos numeros perfectos : "); sdato = flujoE.readLine(); // leer una línea de texto n=Integer.parseInt(sdato);//convierte cadena a int //determina los n perfectos c=0; num=1; do { //determina si un número es perfecto s=0; d=1; num++; do { r=num%d; if (r==0) s=s+d; d++; } while (d<num); if (s==num) { c++; System.out.println(num); } } while(c<n); } }

PROGRAMACION CON JAVA 2 93

1.19.6. SENTENCIA for

La sentencia for permite ejecutar una senten-cia simple o compuesta, repetidamente un nú-mero de veces conocido. Su sintaxis es la si-guiente:

for ([v1=e1 [, v2=e2] …]; [condición]; [progresión condición])

{

sentencia 1;

sentencia 1;

sentencia 1;

...

sentencia 1;

}

o bien:

for ([v1=e1 [, v2=e2] …]; [condición]; [pro-gresión condición])

sentencia;

Donde:

• v1, v2, …, representan variables de con-trol que serán iniciadas con los valores de las expresiones el, e2, …;

• condición es una expresión booleana que si se omite, se supone verdadera;

• progresión condición, es una o más ex-presiones separadas por comas cuyos va-lores evolucionan en el sentido de que se cumpla la condición para finalizar la ejecución de la sentencia for;

• sentencia es una sentencia simple o Com-puesta,

94 Mg. ABRAHAM GAMARRA MORENO

La ejecución de la sentencia for sucede de la siguiente forma:

1. Se inician las variables vi, v2,…

2. Se evalúa la condición:

a) Si el resultado es true (verdadero), se ejecuta el bloque de sentencias, se evalúa la expresión que da lugar a la progresión de la condición y se vuelve al punto 2.

b) Si el resultado es false (falso), la ejecución de la sentencia for se da por finalizada y se pasa el control a la si-guiente sentencia del programa.

Por ejemplo, la siguiente sentencia for im-prime los números del 1 al 100. Literalmente dice: desde i igual a 1, mientras i sea menor o igual que 100, incrementado la i de uno en uno, escribir el valor de i.

int i; for (i = 1; i <= 100; i++)

System.out.print(i + “ “);

El siguiente ejemplo imprime los múltiplos de 7 que hay entre 7 y 112. Se puede observar que, en este caso, la variable se ha declara-do e iniciado en la propia sentencia for (es-to no se puede hacer en una sentencia while; las variables que intervienen en la condición de una sentencia while deben haber sido de-claradas e iniciadas antes de que se procese la condición por primera vez).

for (int k = 7; k <= 112; k += 7) System.out.print(k + “ ”);

En el siguiente ejemplo se puede observar la utilización de la coma como separador de las variables de control y de las expresiones que hacen que evolucionen los valores que inter-vienen en la condición de finalización.

PROGRAMACION CON JAVA 2 95

int f, c; for (f = 3, c = 6; f + c < 40; f++, c+=2)

System.out.print(“f= ”+ f + “ c= “+ c);

Este otro ejemplo que ve a continuación, im-prime los valores desde 1 hasta 10 con incre-mentos de 0.5.

for (float i=1; i <= 10; i += 0.5) System.out.print(i + “ “);

El siguiente ejemplo imprime las letras del abecedario en orden inverso.

char car; for (car=‘z’ ; car >= ‘a’; car--)

System.out.print(car + “ “);

El ejemplo siguiente indica cómo realizar un bucle infinito. Para salir de un bucle infi-nito tiene que pulsar las teclas Ctrl+C.

for (;;)

x++;

Ejemplo ( 24): Escribir un programa que per-mita leer un número en base “m” y lo convier-ta a otro número en base “n”. El programa de-be imprimir el número en base “n”. Los valo-res de m y n son menores que 10 (Usar sólo for)

96 Mg. ABRAHAM GAMARRA MORENO

//archivo: basemton.java import java.io.*;

PROGRAMACION CON JAVA 2 97

class basemton { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto int numm;//numero en base m int numn;//numero en base n int num10;//numero en base 10 int m, n;//base m y n int i;//contador int r;//resto System.out.print("Ingrese base m: "); sdato = flujoE.readLine(); // leer una línea de texto m=Integer.parseInt(sdato);//convierte cadena System.out.print("Ingrese un numero en base "+m+": "); sdato = flujoE.readLine(); // leer una línea de texto numm=Integer.parseInt(sdato);//convierte cadena System.out.print("Ingrese base n: "); sdato = flujoE.readLine(); // leer una línea de texto n=Integer.parseInt(sdato);//convierte cadena //cambiar numero de base m a base 10 num10=0; i=0; for(;numm!=0;) { r=numm%10; num10=num10+r*(int) Math.pow(m,i); numm=numm/10; i++; } System.out.println("El numero en base 10 es: "+num10); //cambiar numero de base 10 a base n numn=0; i=0; for(;num10!=0;) { r=num10%4; numn=numn+r*(int) Math.pow(10,i); num10=num10/4; i++; } System.out.println("El numero en base "+n+" es: "+numn);

98 Mg. ABRAHAM GAMARRA MORENO

}//fin de main }//fin de la clase

Ejemplo(25): Programa que imprime el facto-rial de un número.

PROGRAMACION CON JAVA 2 99

//archivo: factorial.java import java.io.*; class factorial { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto int fact,n; //factorial e incremento de números int i; //contador System.out.print("Introduzca un numero : "); sdato = flujoE.readLine(); // leer una línea de texto n=Integer.parseInt(sdato);//convierte cadena System.out.print("El factorial de "+n); System.out.print(" es "); //determina el factorial de un número fact=1; for(i=1;i<=n;i++) { System.out.print(i); if(i!=n) System.out.print("*"); fact=fact*i; } System.out.println(" = "+fact); } }

Ejemplo (26): Programa que imprime el facto-rial de 1 hasta el factorial de “num”.

100 Mg. ABRAHAM GAMARRA MORENO

//archivo: nfactorial.java import java.io.*; class nfactorial {

PROGRAMACION CON JAVA 2 101

public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto int fact,n,num; int i; //contador System.out.print("Introduzca un numero : "); sdato = flujoE.readLine(); // leer una línea de texto num=Integer.parseInt(sdato);//convierte cadena for(n=1;n<=num;n++) { System.out.print("El factorial de "+n); System.out.print(" es "); //determina el factorial de un número fact=1; for(i=1;i<=n;i++) { System.out.print(i); if(i!=n) System.out.print("*"); fact=fact*i; } System.out.println(" = "+fact); }//fin de for externo } }

1.19.7. SENTENCIA break

Anteriormente vimos que la sentencia break finaliza la ejecución de una sentencia switch. Cuando se utiliza break en el bloque correspondiente a una sentencia while, do, o for, hace lo mismo: finaliza la ejecución del bucle.

Cuando las sentencias switch, while, do, o for estén anidadas, la sentencia break sola-

102 Mg. ABRAHAM GAMARRA MORENO

mente finaliza la ejecución del bucle donde esté incluida.

1.19.8. SENTENCIA continue

La sentencia continue obliga a ejecutar la siguiente iteración del bucle while, do, o for, en el que está contenida. Su sintaxis es:

continue;

Ejemplo (27): Escribir un programa que permi-ta calcular el MCD (Máximo común divisor) de dos números utilizando el algoritmo de Eucli-des.

Dividir n1 entre n2 hasta que el residuo sea cero, entonces el MCD es el ultimo valor de n2. Luego de cada división si el residuo es diferente de cero asigne n1=n2 y n2=r, antes de realizar la siguiente división.

MCD (60,36)=12

Número mayor (n1) 60 36 24

Número menor (n2) 36 24 12

Residuo (r) 24 12 0

Cociente (q) 1 1 2

Dado que r=0, se tiene que el MCD=12=n2.

MCD (70,12)=2

Número mayor (n1) 70 12 10

Número menor (n2) 12 10 2

Residuo (r) 10 2 0

Cociente (q) 5 1 5

Dado que r=0, se tiene que el MCD=2=n2.

PROGRAMACION CON JAVA 2 103

//archivo: mcd.java import java.io.*; class mcd { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto

104 Mg. ABRAHAM GAMARRA MORENO

int n1,n2; //numero mayor y menor int r,q; //residuo y cociente int mcd;//máximo común divisor System.out.print("Introduzca numero mayor : "); sdato = flujoE.readLine(); // leer una línea de texto n1=Integer.parseInt(sdato);//convierte cadena System.out.print("Introduzca numero menor : "); sdato = flujoE.readLine(); // leer una línea de texto n2=Integer.parseInt(sdato);//convierte cadena for( ; ; ) { r=n1%n2; if (r==0) //sale del for { mcd=n2; break;// n2 es mcd } n1=n2; n2=r; } System.out.println("El MCD es "+mcd); } }

1.19.9. break ETIQUETADO

La sentencia break tiene 2 formas: sin eti-queta y etiquetado.

Hemos visto la versión sin etiquetar usada en switch. Como pudimos ver en ese momento, break interrumpe el flujo normal y transfiere el control a la primera línea después del co-mando switch. La sentencia break también se puede usar para salir de un for, while o do-while, transfiriendo siempre el control a la primera línea posterior a cada uno de los bu-cles.

PROGRAMACION CON JAVA 2 105

La versión etiquetada es similar a la ante-rior, con la diferencia que se usa para salir de un bucle que tiene una etiqueta. Veamos un ejemplo:

Ejemplo: break etiquetado - Código parcial

... busqueda: for (; i < maximo; i++) { for (; j < maximo; j++) { ... ... break busqueda; } }

En el ejemplo, cuando se llegue al punto de la ejecución de break busqueda; se saldrá del for externo, donde figura la etiqueta busque-da.

PROGRAMACION CON JAVA 2 107

CAPITULO DOS

ARREGLOS (ARRAY) Y CADENAS

Un array es un medio de guardar un conjunto de objetos de la misma clase. Se accede a cada elemento individual del array mediante un número entero denominado índice. 0 es el índice del primer elemento y n-1 es el índice del último elemento, siendo n, la dimensión del array. Los arrays son objetos en Java y como tales vamos a ver los pasos que hemos de seguir para usarlos convenientemente

• Declarar el array

• Crear el array

• Inicializar los elementos del array

• Usar el array

2.1. DECLARAR Y CREAR UN ARRAY

Para declarar un array se escribe

tipo_de_dato[] nombre_del_array;

o

tipo_de_dato nombre_del_array[];

108 Mg. ABRAHAM GAMARRA MORENO

Para declarar un array de enteros escribimos

int[] numeros;

o int numeros[];

Para crear un array de 4 números enteros escribimos

nombre=new tipo[tamaño];

numeros=new int[4];

El array creado será:

numeros[0] Numeros[1] numeros[2] numeros[3]

La declaración y la creación del array se pueden hacer en una misma línea. Utilice el siguiente formato:

tipo[] nombre=new tipo[tamaño]

por ejemplo:

int[] numeros =new int[4];

2.2. INICIALIZAR Y USAR LOS ELEMENTOS DEL ARRAY

Para utilizar el array de 4 enteros escribimos

numeros[0]=2;

numeros[1]=-4;

numeros[2]=15;

numeros[3]=-25;

Se pueden inicializar en un bucle for como resultado de alguna operación

for(int i=0; i<4; i++)

{ numeros[i]=i*i+4; }

PROGRAMACION CON JAVA 2 109

No necesitamos recordar el número de elementos del array, este tiene un dato miembro llamado length que nos proporciona la dimensión del array. Escribimos de forma equivalente

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

{ numeros[i]=i*i+4;

}

Los arrays se pueden declarar, crear e inicializar en una misma línea, del siguiente modo

int[] numeros={2, -4, 15, -25};

String[] nombres={"Juan", "José", "Miguel", "Anto-nio"};

Para imprimir a los elementos de array nombres se es-cribe

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

{ System.out.println(nombres[i]);

}

Java verifica que el índice no sea mayor o igual que la dimensión del array, lo que facilita mucho el tra-bajo al programador.

Ejemplo (28): Programa que lee la temperatura de los “n” últimos días y calcula el promedio.

110 Mg. ABRAHAM GAMARRA MORENO

//Archivo: temperatura.java import java.io.*; public class temperatura { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto double s=0;//acumulador que suma las temperaturas int tam;//tamaño del arreglo System.out.print("Cuantos dias?: ");

PROGRAMACION CON JAVA 2 111

sdato = flujoE.readLine(); // leer una línea de texto tam=Integer.parseInt(sdato);//convierte cadena //arreglo que almacena la temperatura double[] t= new double[tam]; // lectura de los elementos del arreglo for (int i=0; i < t.length; i++) { System.out.print("Ingrese temperatura: "); sdato = flujoE.readLine(); t[i]=Double.parseDouble(sdato);//convierte cadena } System.out.println("Las temperaturas leidas son:"); for (int i=0; i < t.length; i++) { System.out.println(t[i]); s=s+t[i]; } System.out.println("El promedio es: "+ (s/t.length)); }// fin de main }//fin de class

2.3. ARRAYS MULTIDIMENSIONALES

Una matriz bidimensional puede tener varias filas, y en cada fila no tiene por qué haber el mismo número de elementos o columnas. Por ejemplo, podemos declarar e inicializar la siguiente matriz bidimensional

double[][] matriz= {{1,2,3,4},{5,6},{7,8,9,10,11, 12},{13}};

• La primer fila tiene cuatro elementos {1,2,3,4}

• La segunda fila tiene dos elementos {5,6}

• La tercera fila tiene seis elementos {7,8,9,10,11,12}

• La cuarta fila tiene un elemento {13}

Para mostrar los elementos de este array bidimensional escribimos el siguiente código

112 Mg. ABRAHAM GAMARRA MORENO

for (int i=0; i < matriz.length; i++) { for (int j=0; j < matriz[i].length; j++) { System.out.print(matriz[i][j]+"\t"); } System.out.println(""); }

Como podemos apreciar, matriz.length nos proporciona el número de filas (cuatro), y matriz[i].length, nos proporciona el número de elementos en cada fila.

Mostramos los elementos de una fila separados por un tabulador usando la función print. Una vez completada una fila se pasa a la siguiente mediante println.

Los arrays bidimensionales nos permiten guardar los elementos de una matriz. Queremos crear y mostrar una matriz cuadrada unidad de dimensión 4. Recordaremos que una matriz unidad es aquella cuyos elementos son ceros excepto los de la diagonal principal i==j, que son unos. Mediante un doble bucle for recorremos los elementos de la matriz especificando su fila i y su columna j. En el siguiente programa

• Se crea una matriz cuadrada de dimensión cuatro

• Se inicializa los elementos de la matriz (matriz unidad)

• Se muestra la matriz una fila debajo de la otra separando los elementos de una fila por tabulado-res.

Ejemplo(29): Creación de la matriz unidad

PROGRAMACION CON JAVA 2 113

114 Mg. ABRAHAM GAMARRA MORENO

//Archivo: MatrizUnidadApp.java public class MatrizUnidadApp { public static void main (String[] args) { double[][] mUnidad= new double[4][4]; for (int i=0; i < mUnidad.length; i++) { for (int j=0; j < mUnidad[i].length; j++) { if (i == j) { mUnidad[i][j]=1.0; } else { mUnidad[i][j] = 0.0; } } } for (int i=0; i < mUnidad.length; i++) { for (int j=0; j < mUnidad[i].length; j++) { System.out.print(mUnidad[i][j]+"\t"); } System.out.println(""); } } }

2.4. GESTIÓN DE CADENAS

Una cadena es una secuencia de caracteres. Para decla-rar e inicializar una array de caracteres (arreglos de caracteres o cadena), utilice el siguiente formato:

char Cad[] = { 'a','b','c'};

la instrucción anterior permitirá generar el siguiente arreglo:

Cad[0] Cad[1] Cad[2]

'a' 'b' 'c'

PROGRAMACION CON JAVA 2 115

Ejemplo (30): Programa que imprime una cadena en forma invertida

//Archivo: cadena.java import java.io.*; public class cadena { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); char[] cad={'F','I','S','-','U','N','C','P'}; int i;//contador System.out.println("La cadena original es: "); for (i=0; i <cad.length; i++) System.out.print(cad[i]); System.out.println(""); System.out.println("La cadena invertida es: "); for (i=cad.length-1; i >=0; i--) System.out.print(cad[i]); System.out.println(""); }// fin de main }//fin de class

Las cadenas son una parte fundamental de la mayoría de los programas, así pues Java tiene varias caracterís-ticas incorporadas que facilitan la manipulación de cadenas.

Java tiene una clase incorporada en el paquete ja-va.lang que encapsula las estructuras de datos de una

116 Mg. ABRAHAM GAMARRA MORENO

cadena. Esta clase, llamada String es la representa-ción como objeto de una matriz de caracteres que no se puede cambiar.

Hay una clase que la acompaña, llamada StringBuffer, que se utiliza para crear cadenas que pueden ser mani-puladas después de ser creadas.

2.4.1. CONSTRUCTORES

Se pueden crear instancias de String con el operador new.

String s = new String();

El ejemplo anterior creara una instancia de String sin caracteres en ella. Para crear un String inicializado con caracteres hay que pasarle una matriz de char al constructor. Veamos un ejemplo:

char chars[] = { 'a','b','c'};

String s = new String(chars);

// s es la cadena "abc"

Si se tiene una matriz de la que solo un ran-go nos interesa existe un constructor que permite especificar el índice de comienzo y el número de caracteres a utilizar.

char chars[] = {'a','b','c','d','e','f'};

String s = new String(chars, 2, 3); // s es la cadena "cde"

También existen constructores para caracteres ASCII (caracteres de 8 bits) frente a los ca-racteres Unicode de Java (caracteres de 16 bits).

2.4.2. SINTAXIS DE CADENAS ESPECIAL

Java incluye algunas ayudas sintácticas con el fin de ayudar a los programadores a reali-zar las operaciones más habituales con cade-nas.

PROGRAMACION CON JAVA 2 117

Creación de cadenas

Dado que los Strings son valores constantes, Java incluye un atajo para un literal de ca-dena estándar, en el que un valor de cadena se puede encerrar entre comillas dobles:

String s = "abad";

uno de los métodos mas habituales que se uti-lizan en un String es length, que devuelve el número de caracteres de una cadena:

String s = "abc";

System.out.println(s.length());//imprimiría 3

Un punto interesante en Java es que se crea una instancia de objeto para cada literal String, por lo que se puede llamar a los mé-todos directamente con una cadena entre comi-llas, como si fuera una referencia a objeto, con este ejemplo se volvería a imprimir un 3:

String s = "abc";

System.out.println("abc".lenght());

Concatenación de cadenas

El único operador que utiliza Java es +, y en los objetos String. El + actúa como operador de concatenación en este caso en concreto pa-ra mejorar la legibilidad, por ser operación muy común.

String s = "El tiene " + edad + " años";

esta mucho más claro que

String s = new StringBuffer("El tiene ")

.append (edad)

.append (" años")

.toString();

que es lo que sucede cuando se ejecuta este código. append añade cosas al final de

118 Mg. ABRAHAM GAMARRA MORENO

StringBuffer, y toString convierte a cadenas el StringBuffer. Trataremos con detalle ap-pend y toString mas adelante en este capítu-lo.

Aspectos de precedencia de operadores

Debe tener cuidado cuando mezcle expresiones enteras con expresiones de concatenación de cadenas por que puede obtener resultados sor-prendentes.

String s = "cuatro: " + 2 + 2;

Se podría esperar que el valor de s sea "cua-tro: 4", pero la procedencia de operadores provoco que se evaluase primero la subexpre-sión "cuatro: " + 2, y después "cuatro: 2" + 2, donde como resultado "cuatro: 22". Si se desea realizar primero la expresión entera, hay que utilizar paréntesis, como aquí:

String s = "cuatro: " + (2+2);

Conversión de cadenas

StringBuffer tiene una versión sobrecargada de append para cada tipo posible. Por lo tanto, cuando se utiliza `+' para concatenar una variable, se llama a la versión adecuada de append para esa variable. El método append realmente llama a un método estático de String llamado valueOf para construir la representación tipo cadena. Para tipos simples, valueOf crea simplemente una representación de cada int o float. Para objetos, valueOf llama al método to String con ese objeto. Cada clase implementa toString, con una implementación por defecto que se encuentra en la clase Object. Es bueno el sobrescribir toString y presentar una versión propia de cadena para las clases. El ejemplo siguiente muestra una clase que sobrescribe toString para mostrar los valores de sus variables de instancia.

class Point { int x, y; Point(int x, int y) {

PROGRAMACION CON JAVA 2 119

this.x = x; this.y = y; } public String toString() { return "Punto[" + x + "," + y + "]"; } } class toStringDemo { public static void main(String args[]) { Point p = new Point(10, 20); System.out.println("p = " + p); } }

Esta versión de la clase Point incluye una versión con la que se sobrescribe el método toString del objeto, y que da formato a la cadena que contiene los valores de x y de y de cada instancia de Point. La salida de este programa es la siguiente:

p = Punto[10, 20 ]

2.4.3. EXTRACCIÓN DE CARACTERES

Para extraer un único carácter de una cadena, se puede referir a un carácter indexado me-diante el método charAt:

"abc".charAt(1) // devolverá 'b'

Si se necesita extraer más de un carácter a la vez, puede utilizar el método gerChars, que le permite especificar el índice del pri-mer carácter y del último más uno que se de-sean copiar, además de la matriz char donde se desean colocar dichos caracteres.

String s = "Esto no es una canción";

char buf[] = new char[2];

s.getChars(5, 7, buf, 0);

// buf ahora tendrá el valor 'no'

120 Mg. ABRAHAM GAMARRA MORENO

También existe una función útil llamada to-CharArray, que devuelve una matriz de char que contiene la cadena completa.

2.4.4. COMPARACIÓN

Si se desean comparar dos cadenas para ver si son iguales, puede utilizar el método equals de String. Devolverá true si el único paráme-tro está compuesto de los mismos caracteres que el objeto con el que se llama a equals. Una forma alternativa de equals llamada equalsIgnoreCase ignora si los caracteres de las cadenas que se comparan están en mayúscu-las o minúsculas.

La clase String ofrece un par de métodos úti-les que son versiones especializadas de equals. El método regionMatches se utiliza para comparar una región específica que se parte de una cadena con otra región de otra cadena. Hay dos variantes de regionMatches, una le permite controlar si es importante la diferenciación entre mayúsculas/minúsculas; la otra asume que si lo es.

boolean regionMatches (int toffset, String otra, int ooffset, int longitud);

// si importa la diferencia

boolean regionMatches (boolean ignorarMaysc,int toffset, String otra, int ooffset, int longitud);

// no importa la diferencia

En estas dos versiones de regionMatches, el parámetro toffset indica el desplazamiento en caracteres en el objeto String sobre el que estamos llamando el método. La cadena con la que estamos comparando se llama otra, y el desplazamiento dentro de esa cadena se llama ooffset. Se comparan longitud caracteres de las dos cadenas comenzando a partir de los dos desplazamientos.

PROGRAMACION CON JAVA 2 121

Igualdad

El método equals y el operador = = hacen dos pruebas completamente diferentes para la igualdad. Mientras que el método equals com-para los caracteres contenidos en una String, el operador = = compara dos referencias de objeto para ver si se refieren a la misma instancia.

Ordenación

A menudo no basta con conocer si dos cadenas son idénticas o no. Para aplicaciones de or-denación, necesitamos conocer cuál es menor que, igual que o mayor que la siguiente. El método de String compareTo se puede utilizar para determinar la ordenación. Si el resulta-do entero de compareTo es negativo, la cadena es menor que el parámetro, y si es positivo, la cadena es mayor. Si compareTo devuelve 0, entonces las dos cadenas son iguales. Ahora ordenaremos una matriz de cadenas utilizando compareTo para determinar el criterio de or-denación mediante una Ordenación en burbuja.

//archivo: SortString class SortString { static String arr[] = { "Ahora", "es", "el ", "momento", "de", "actuar"}; public static void main(String args[]) { System.out.println("La cadena inicial es"); for (int j = 0; j < arr.length; j++) System.out.print(arr[j]+" "); System.out.println("\n"); System.out.println("La cadena final es"); for (int j = 0; j < arr.length; j++) { for (int i = j + 1; i < arr.length; i++) { if (arr[i].compareTo(arr[j]) < 0) { String t = arr[j]; arr[j] = arr[i]; arr[i] = t; } } System.out.print(arr[j]+" ");

122 Mg. ABRAHAM GAMARRA MORENO

} System.out.println("\n"); } }

2.4.5. OTROS MÉTODOS

valueOf

Si se tiene algún tipo de datos y se desea imprimir su valor de una forma legible, pri-mero hay que convertirlo a String. El método valueOf está sobrecargado en todos los tipos posibles de Java, por lo que cada tipo se puede convertir correctamente en una String. Cualquier objeto que se le pase a valueOf de-volverá el resultado de llamar al método toS-tring del objeto. De hecho, se podría llamar directamente a toString y obtener el mismo resultado.

StringBuffer

StringBuffer es una clase gemela de String que proporciona gran parte de la funcionali-dad de la utilización habitual de las cade-nas. StringBuffer representa secuencias de caracteres que se pueden ampliar y modificar. Java utiliza ambas clases con frecuencia, pe-ro muchos programadores sólo tratan con String y permiten que Java manipule String-Buffer por su cuenta mediante el operador so-brecargado '+'.

append

Al método append de StringBuffer se le llama a menudo a través del operador +. Tiene ver-

PROGRAMACION CON JAVA 2 123

siones sobrecargadas para todos los tipos. Se llama a String.valueOf para cada parámetro y el resultado se aóade al StringBuffer actual. Cada versión de append devuelve el propio buffer.

2.4.6. LA CLASE String

La clase String representa una cadena de ca-racteres.

La clase String es constante

String str = "abc";

es equivalente a:

char data[] = {'a', 'b', 'c'};

String str = new String(data);

A continuación se muestra algunos ejemplos para la utilización de las cadenas:

System.out.println("abc");

String cde = "cde";

System.out.println("abc" + cde);

String c = "abc".substring(2,3);

String d = cde.substring(1, 2);

La clase Sring incluye metodos que evaluan los caracteres en forma individual tal como compararción, búsqueda, extracción de subca-denas o para crear una copia de una cadena co todos los caracteres cambiados a mayúsculas o minúsculas.

A continuación se muestran los costructores y métodos de la clase String.

Constructores String() Initializes a newly created String object so that it represents an empty character sequence.

124 Mg. ABRAHAM GAMARRA MORENO

String(byte[] bytes) Constructs a new String by decoding the specified array of bytes using the platform's default charset.

String(byte[] ascii, int hibyte) Deprecated. This method does not properly convert bytes into characters. As of JDK 1.1, the preferred way to do this is via the String constructors that take a charset name or that use the platform's default charset.

String(byte[] bytes, int offset, int length) Constructs a new String by decoding the specified subarray of bytes using the platform's default charset.

String(byte[] ascii, int hibyte, int offset, int count) Deprecated. This method does not properly convert bytes into characters. As of JDK 1.1, the preferred way to do this is via the String constructors that take a charset name or that use the platform's default charset.

String(byte[] bytes, int offset, int length, String charsetName) Constructs a new String by decoding the specified subarray of bytes using the specified charset.

String(byte[] bytes, String charsetName) Constructs a new String by decoding the specified array of bytes using the specified charset.

String(char[] value) Allocates a new String so that it represents the sequence of characters currently contained in the character array argument.

String(char[] value, int offset, int count) Allocates a new String that contains characters from a subarray of the character array argument.

String(String original) Initializes a newly created String object so that it represents the same sequence of characters as the argu-ment; in other words, the newly created string is a copy of the argument string.

String(StringBuffer buffer) Allocates a new string that contains the sequence of characters currently contained in the string buffer argu-ment.

Métodos char charAt(int index)

Returns the character at the specified

PROGRAMACION CON JAVA 2 125

index.

int compareTo(Object o) Compares this String to another Object.

int compareTo(String anotherString) Compares two strings lexicographically.

int compareToIgnoreCase(String str) Compares two strings lexicographically, ignoring case considerations.

String concat(String str) Concatenates the specified string to the end of this string.

boolean contentEquals(StringBuffer sb) Returns true if and only if this String represents the same sequence of characters as the specified StringBuffer.

static String copyValueOf(char[] data) Returns a String that represents the character sequence in the array specified.

static String copyValueOf(char[] data, int offset, int count) Returns a String that represents the character sequence in the array specified.

boolean endsWith(String suffix) Tests if this string ends with the spe-cified suffix.

boolean equals(Object anObject) Compares this string to the specified object.

boolean equalsIgnoreCase(String anotherString) Compares this String to another String, ignoring case considerations.

byte[] getBytes() Encodes this String into a sequence of bytes using the platform's default charset, stor-ing the result into a new byte array.

void getBytes(int srcBegin, int srcEnd, byte[] dst, int dstBegin) Deprecated. This method does not prop-erly convert characters into bytes. As of JDK 1.1, the preferred way to do this is via the the getBytes() method, which uses the platform's default charset.

byte[] getBytes(String charsetName) Encodes this String into a sequence of bytes using the named charset, storing the result

126 Mg. ABRAHAM GAMARRA MORENO

into a new byte array.

void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) Copies characters from this string into the destination character array.

int hashCode() Returns a hash code for this string.

int indexOf(int ch) Returns the index within this string of the first occurrence of the specified character.

int indexOf(int ch, int fromIndex) Returns the index within this string of the first occurrence of the specified character, starting the search at the specified index.

int indexOf(String str) Returns the index within this string of the first occurrence of the specified substring.

int indexOf(String str, int fromIndex) Returns the index within this string of the first occurrence of the specified substring, starting at the specified index.

String intern() Returns a canonical representation for the string object.

int lastIndexOf(int ch) Returns the index within this string of the last occurrence of the specified character.

int lastIndexOf(int ch, int fromIndex) Returns the index within this string of the last occurrence of the specified character, searching backward starting at the specified in-dex.

int lastIndexOf(String str) Returns the index within this string of the rightmost occurrence of the specified sub-string.

int lastIndexOf(String str, int fromIndex) Returns the index within this string of the last occurrence of the specified substring, searching backward starting at the specified in-dex.

int length() Returns the length of this string.

boolean matches(String regex)

PROGRAMACION CON JAVA 2 127

Tells whether or not this string mat-ches the given regular expression.

boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) Tests if two string regions are equal.

boolean regionMatches(int toffset, String other, int ooffset, int len) Tests if two string regions are equal.

String replace(char oldChar, char newChar) Returns a new string resulting from re-placing all occurrences of oldChar in this string with newChar.

String replaceAll(String regex, String replacement) Replaces each substring of this string that matches the given regular expression with the given replacement.

String replaceFirst(String regex, String replacement) Replaces the first substring of this string that matches the given regular expression with the given replacement.

String[] split(String regex) Splits this string around matches of the given regular expression.

String[] split(String regex, int limit) Splits this string around matches of the given regular expression.

boolean startsWith(String prefix) Tests if this string starts with the specified prefix.

boolean startsWith(String prefix, int toffset) Tests if this string starts with the specified prefix beginning a specified index.

CharSequence subSequence(int beginIndex, int endIndex) Returns a new character sequence that is a subsequence of this sequence.

String substring(int beginIndex) Returns a new string that is a sub-string of this string.

String substring(int beginIndex, int endIndex) Returns a new string that is a sub-string of this string.

char[] toCharArray() Converts this string to a new character array.

128 Mg. ABRAHAM GAMARRA MORENO

String toLowerCase() Converts all of the characters in this String to lower case using the rules of the de-fault locale.

String toLowerCase(Locale locale) Converts all of the characters in this String to lower case using the rules of the given Locale.

String toString() This object (which is already a string!) is itself returned.

String toUpperCase() Converts all of the characters in this String to upper case using the rules of the de-fault locale.

String toUpperCase(Locale locale) Converts all of the characters in this String to upper case using the rules of the given Locale.

String trim() Returns a copy of the string, with lea-ding and trailing whitespace omitted.

static String valueOf(boolean b) Returns the string representation of the boolean argument.

static String valueOf(char c) Returns the string representation of the char argument.

static String valueOf(char[] data) Returns the string representation of the char array argument.

static String valueOf(char[] data, int offset, int count) Returns the string representation of a specific subarray of the char array argument.

static String valueOf(double d) Returns the string representation of the double argument.

static String valueOf(float f) Returns the string representation of the float argument.

static String valueOf(int i) Returns the string representation of the int argument.

static String valueOf(long l)

PROGRAMACION CON JAVA 2 129

Returns the string representation of the long argument.

static String valueOf(Object obj) Returns the string representation of the Object argument.

PROGRAMACION CON JAVA 2 131

CAPITULO THREE

MÉTODOS CREADOS POR EL USUARIO

La mayoría de los programas tienen gran cantidad de líneas de código y son grandes por lo que deberíamos de construirlo a partir de piezas más pequeñas o módulos; además estos serán manejados desde un programa principal.

Los módulos de un programa en Java se llaman métodos y cla-ses. Los programas que se escriben en Java tienen métodos creados por el usuario y métodos “preempacados” del lenguaje que están en la biblioteca de clases de Java (algunos de es-tos métodos se mostraron en la clase Integer, Float, Math, String, etc).

Los métodos permiten al programador modularizar sus programas y reutilizar su código. Cuando un método esta creado y se tiene acceso a él, podremos ejecutarlo desde varios puntos de un programa con sólo invocarlo.

Los métodos en la Programación Orientada a Objetos suelen co-nocerse también como funciones miembro. Usted debe notar que las funciones se utilizan también en el Lenguaje C++. En ca-pítulos posteriores utilizaremos lós métodos con la denomina-ción de funciones miembro.

132 Mg. ABRAHAM GAMARRA MORENO

3.1. DEFINICIÓN DE UN MÉTODO Un método será definido utilizando la siguiente sin-taxis.

[modificador] tipo_devuelto nombreMétodo(tipo parm1, tipo parm2, tipo parm3, . . .)

{ declaraciones de variables locales;

//...sentencias

[return[(]expresión[)]];

}

nombreMétodo: es cualquier identificador válido.

tipo_devuelto: es el tipo de datos del resultado que el método devuelve al invocador (int, float, etc ). El tipo_devuelto void indica que el método no devuelve ningún valor.

Tipo parm1, tipo parm2, tipo parm3, . . .: es una lis-ta separada por comas que contiene las declaraciones de los parámetros que el método recibe cuando se le invoca. Si un método no recibe valores la lista de pa-rámetros esta vacía, es decir se coloca los paréntesis sin parámetros.

Hay dos formas de devolver el control al punto en el que se invocó un método:

• La primera forma de devolver el control, es cuan-do se llega a la llave que cierra el final del cuerpo de la función; en este caso no se utiliza return.

• La segunda forma de devolver el control, es cuan-do se ejecuta la sentencia return. La sentencisa return tiene la siguiente sintaxis:

return [(expresión)];

Los corchetes indican que ese ítem es opcional, es decir se puede utilizar return de la siguiente forma:

PROGRAMACION CON JAVA 2 133

return (expresión);

return ;

Por supuesto que la última forma no devuelve nin-gún valor; pero el control regresa de inmediato al punto en el que se invocó el método.

Para llamar a un método se escribe

retorno=nombreMétodo (arg1, arg2, arg3);

Cuando se llama al método, los argumentos arg1, arg2, arg3 se copian en los parámetros parm1, parm2, parm3 y se ejecutan las sentencias dentro de la función.

Cuando se llama al método, el valor devuelto mediante la sentencia return se asigna a la variable retorno.

Cuando un método no devuelve nada se dice que es de tipo void. Para llamar a este método, se escribe

nombreMétodo(arg1, arg2, arg3);

Ejemplo (31): Uso del método hipotenusa para calcular la hipotenusa de un triángulo. Notese que en el llama-do

//llamado al método hipotenusa hip=hipotenusa(ca,cb);

estamos enviando valores a través de las variables ca y cb (valores de los catetos) y se esta recibiendo en hip el retorno que ofrece el método.

// Archivo Hipotenusa.java

import java.io.*; class Hipotenusa { public static void main (String[] args) throws IOException {

134 Mg. ABRAHAM GAMARRA MORENO

// Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto float ca,cb; //catetos float hip;//almacena la hipotenusa //lectura de datos System.out.print("Introduzca primer cateto: "); sdato = flujoE.readLine(); // leer una línea de texto ca=Float.parseFloat(sdato);//convierte cadena a float System.out.print("Introduzca segundo cateto: "); sdato = flujoE.readLine(); // leer una línea de texto cb=Float.parseFloat(sdato);//convierte cadena a float //llamado al método hipotenusa hip=hipotenusa(ca,cb); System.out.println("La hipotenusa es : "+hip); } public static float hipotenusa(float a, float b) { //definición de variables locales float h; //sentencias internas del método h=(float) Math.sqrt(a*a+b*b); //retorno de un valor return h; } }

Ejemplo (32): Uso del método hipotenusa para calcular la hipotenusa de un triángulo. Notese que en el llama-do

//llamado al método hipotenusa hipotenusa(ca,cb);

PROGRAMACION CON JAVA 2 135

estamos enviando valores a través de las variables ca y cb (valores de los catetos) y no se recibe ningún retorno desde el método.

// Archivo Hipotenusa1.java

import java.io.*; class Hipotenusa1 { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto float ca,cb; //catetos float hip;//almacena la hipotenusa //lectura de datos System.out.print("Introduzca primer cateto: "); sdato = flujoE.readLine(); // leer una línea de texto ca=Float.parseFloat(sdato);//convierte cadena a float System.out.print("Introduzca segundo cateto: "); sdato = flujoE.readLine(); // leer una línea de texto cb=Float.parseFloat(sdato);//convierte cadena a float //llamado al método hipotenusa hipotenusa(ca,cb); } public static void hipotenusa(float a, float b) { //definición de variables locales float h; //sentencias internas del método h=(float) Math.sqrt(a*a+b*b); System.out.println("La hipotenusa es : "+h); } }

136 Mg. ABRAHAM GAMARRA MORENO

Ejemplo (33): Uso de un método para simular el opera-dor AND. Notese el uso de throws IOException en los métodos main y leer_vector, para evitar de este modo utilizar try . . . catch. Observe además como se uti-liza el tipo de dato int[] en el método and, para de-volver un arreglo desde este método.

// Archivo vectores.java

import java.io.*; class vectores { public static void main (String[] args) throws IOException { int [] v1= new int [4];//primer vector int [] v2= new int [4];//segundo vector int [] vs= new int [4];//vector que almacena el resultado leer_vector(v1); escribir_vector(v1); leer_vector(v2); escribir_vector(v2); vs=and(v1,v2); System.out.println("Contenido del vector AND:"); escribir_vector(vs); } public static void leer_vector(int va[]) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto for(int i=0; i<va.length;i++) { //lectura de datos System.out.print("Introduzca valor (0 o 1): "); sdato = flujoE.readLine(); // leer una línea de texto va[i]=Integer.parseInt(sdato);//convierte cadena } }//fin de leer_vector

PROGRAMACION CON JAVA 2 137

public static void escribir_vector(int va[]) { System.out.println("El contenido del vector es: "); for(int i=0; i<va.length;i++) { System.out.print(va[i]+"\t"); } System.out.println(""); }//fin de escribir_vector public static int [] and(int va[], int vb[]) { int [] s= new int [4];//vector que almacena el resultado // si ambas cifras son 1 el resultado es 1 // de lo contario es cero for(int i=0; i<va.length;i++) { if (va[i]==1 && vb[i]==1) s[i]=1; else s[i]=0; } return s; //retorna un arreglo }//fin de escribir_vector }

En el capítulo siguiente se analiza el uso de métodos en clases.

PROGRAMACION CON JAVA 2 139

CAPITULO CUATRO

CLASES Y PROGRAMACION ORIENTADO A OBJETOS

Cuando se escribe un programa en un lenguaje orientado a ob-jetos, definimos una plantilla o clase que describe las ca-racterísticas y el comportamiento de un conjunto de objetos similares. La clase automóvil describe las características comunes de todos los automóviles: sus atributos y su compor-tamiento (fig. 4.1). Los atributos o propiedades se refieren a la marca o fabricante, el color, las dimensiones, si tienen dos, tres, cuatro o más puertas, la potencia, si utiliza como combustible la gasolina o gasoil, etc. El comportamiento se refiere a la posibilidad de desplazarse por una carretera, frenar, acelerar, cambiar de marcha, girar, etc.

Luego, tenemos automóviles concretos, por ejemplo el automó-vil propio de una determinada marca, color, potencia, etc, el automóvil del vecino de otra marca, de otro color, etc, el automóvil de un amigo, etc.

Una clase es por tanto una plantilla implementada en software que describe un conjunto de objetos con atributos y comporta-miento similares.

Una instancia u objeto de una clase es una representación concreta y específica de una clase y que reside en la memoria del ordenador.

140 Mg. ABRAHAM GAMARRA MORENO

Figura 4.1 Clases y objetos

4.1. ATRIBUTOS

Los atributos son las características individuales que diferencian un objeto de otro y determinan su aparien-cia, estado u otras cualidades. Los atributos se guar-dan en variables denominadas de instancia, y cada ob-jeto particular puede tener valores distintos para es-tas variables.

Las variables de instancia también denominados miem-bros dato, son declaradas en la clase pero sus valores son fijados y cambiados en el objeto.

Además de las variables de instancia hay variables de clase, las cuales se aplican a la clase y a todas sus instancias. Por ejemplo, el número de ruedas de un au-tomóvil es el mismo cuatro, para todos los automóvi-les.

4.2. COMPORTAMIENTO

El comportamiento de los objetos de una clase se im-plementa mediante funciones miembro o métodos. Un mé-todo es un conjunto de instrucciones que realizan una

PROGRAMACION CON JAVA 2 141

determinada tarea y son similares a las funciones de los lenguajes estructurados.

Del mismo modo que hay variables de instancia y de clase, también hay métodos de instancia y de clase. En el primer caso, un objeto llama a un método para rea-lizar una determinada tarea, en el segundo, el método se llama desde la propia clase.

4.3. UNA CLASE EN JAVA

Para crear una clase se utiliza la palabra reservada class y a continuación el nombre de la clase. La defi-nición de la clase se pone entre las llaves de apertu-ra y cierre. El nombre de la clase empieza con una le-tra mayúscula.

class NombreClase{

//miembros dato o datos miembro

//funciones miembro

}

4.3.1. LOS MIEMBROS DATO

Los valores de los atributos se guardan en los miembros dato o variables de instancia. Los nombres de dichas variables comienzan por letra minúscula.

Vamos a crear una clase denominada Rectangulo, que describa las características comunes a estas figuras planas que son las siguientes:

• El origen del rectángulo: el origen o posición de la esquina superior izquier-da del rectángulo en el plano determina-do por dos números enteros x e y.

• Las dimensiones del rectángulo: ancho y alto, otros dos números enteros.

142 Mg. ABRAHAM GAMARRA MORENO

class Rectangulo { int x; int y; int ancho; int alto; //faltan las funciones miembro }

4.3.2. LAS FUNCIONES MIEMBRO

En el lenguaje Java las funciones miembro o métodos se definen y se llaman.

El nombre de las funciones miembro o métodos comienza por letra minúscula y deben sugerir acciones (mover, calcular, etc.). La defini-ción de una función tiene el siguiente forma-to:

[modificador] tipo nombreFuncion(tipo parm1, tipo parm2, tipo parm3, . . .)

{ declaraciones de variables locales;

//...sentencias

[return[(]expresión[)]];

}

Entre las llaves de apertura y cierre se co-loca la definición de la función, tipo indica el tipo de dato que puede ser predefinido int, double, etc, o definido por el usuario, una clase cualquiera.

PROGRAMACION CON JAVA 2 143

Un modificador es una palabra clave que modi-fica el nivel de protección predeterminado del método o función miembro (este tema se analizará más adelante).

Para llamar a una función miembro o método se escribe

retorno=objeto.nombreFuncion (arg1, arg2, arg3);

Cuando se llama a la función, los argumentos arg1, arg2, arg3 se copian en los parámetros parm1, parm2, parm3 y se ejecutan las senten-cias dentro de la función. La función finali-za cuando se llega al final de su bloque de definición o cuando encuentra una sentencia return.

Cuando se llama a la función, el valor de-vuelto mediante la sentencia return se asigna a la variable retorno.

Cuando una función no devuelve nada se dice que es de tipo void. Para llamar a la fun-ción, se escribe

objeto.nombreFuncion (arg1, arg2, arg3);

Una función suele finalizar cuando llega al final del bloque de su definición

void funcion(....) { //sentencias... }

Una función puede finalizar antes del llegar al final de su definición

144 Mg. ABRAHAM GAMARRA MORENO

void funcion(....) { //sentencias... if(condicion) return; //sentencias.. }

Una función puede devolver un valor (un tipo de dato primitivo o un objeto).

double funcion(....) { double suma=0.0; //sentencias... return suma; }

Cualquier variable declarada dentro de la función tiene una vida temporal, existiendo en memoria, mientras la función esté activa. Se trata de variables locales a la función. Por ejemplo:

void nombreFuncion(int parm){ //... int i=5; //... }

La variable parm, existe desde el comienzo hasta el final de la función. La variable lo-cal i, existe desde el punto de su declara-ción hasta el final del bloque de la función.

Se ha de tener en cuenta que las funciones miembro tienen acceso a los miembros dato, por tanto, es importante en el diseño de una clase decidir qué variables son miembros da-to, qué variables son locales a las funciones miembro, y qué valores les pasamos a dichas funciones.

Hemos definido los atributos o miembros dato de la clase Rectangulo, ahora le vamos añadir un comportamiento: los objetos de la clase Rectangulo o rectángulos sabrán calcular su

PROGRAMACION CON JAVA 2 145

área, tendrán capacidad para trasladarse a otro punto del plano, sabrán si contienen en su interior un punto determinado del plano.

La función que calcula el área realizará la siguiente tarea, calculará el producto del ancho por el alto del rectángulo y devolverá el resultado. La función devuelve un entero es por tanto, de tipo int. No es necesario pasarle datos ya que tiene acceso a los miem-bros dato ancho y alto que guardan la anchura y la altura de un rectángulo concreto.

class Rectangulo{ int x; int y; int ancho; int alto; int calcularArea(){ return (ancho*alto); } }

A la función que desplaza el rectángulo hori-zontalmente en dx, y verticalmente en dy, le pasamos dichos desplazamientos, y a partir de estos datos actualizará los valores que guar-dan sus miembros dato x e y. La función no devuelve nada es de tipo void.

class Rectangulo{ int x; int y; int ancho; int alto; void desplazar(int dx, int dy){ x+=dx; y+=dy; } }

La función que determina si un punto está o no en el interior del rectángulo, devolverá true si el punto se encuentra en el interior del rectángulo y devolverá false si no se en-cuentra, es decir, será una función del tipo boolean. La función necesitará conocer las

146 Mg. ABRAHAM GAMARRA MORENO

coordenadas de dicho punto. Para que un punto de coordenadas x1 e y1 esté dentro de un rec-tángulo cuyo origen es x e y, y cuyas dimen-siones son ancho y alto, se deberá cumplir a la vez cuatro condiciones

x1>x y a la vez x1<x+ancho

También se debe cumplir

y1>y y a la vez y1<y+alto

Como se tienen que cumplir las cuatro condi-ciones a la vez, se unen mediante el operador lógico AND simbolizado por &&.

class Rectangulo { int x; int y; int ancho; int alto; boolean estaDentro(int x1, int y1) { if((x1>x)&&(x1<x+ancho)&&(y1>y)&&(y1<y+ ancho))

{ return true; } return false; } }

En el lenguaje Java, si la primera condición es falsa no se evalúan las restantes expre-siones ya que el resultado es false. Ahora bien, si la primera es verdadera true, se pa-sa a evaluar la segunda, si ésta el falsa el resultado es false, y así sucesivamente.

PROGRAMACION CON JAVA 2 147

4.3.3. LOS CONSTRUCTORES

Un objeto de una clase se crea llamando a una función especial denominada constructor de la clase. El constructor se llama de forma auto-mática cuando se crea un objeto, para situar-lo en memoria e inicializar los miembros dato declarados en la clase. El constructor tiene el mismo nombre que la clase. Lo específico del constructor es que no tiene tipo de re-torno.

class Rectangulo{ int x; int y; int ancho; int alto; Rectangulo(int x1, int y1, int w, int h){ x=x1; y=y1; ancho=w; alto=h; } }

El constructor recibe cuatro números que guardan los parámetros x1, y1, w y h, y con ellos inicializa los miembros dato x, y, an-cho y alto.

Una clase puede tener más de un constructor. Por ejemplo, el siguiente constructor crea un rectángulo cuyo origen está en el punto (0, 0).

class Rectangulo{ int x; int y; int ancho; int alto; Rectangulo(int w, int h){ x=0; y=0; ancho=w; alto=h; } }

148 Mg. ABRAHAM GAMARRA MORENO

Este constructor crea un rectángulo de dimen-siones nulas situado en el punto (0, 0),

class Rectangulo{ int x; int y; int ancho; int alto; Rectangulo(){ x=0; y=0; ancho=0; alto=0; } }

Con estas porciones de código definimos la clase, y la guardamos en un archivo que tenga el mismo nombre que la clase Rectangulo y con extensión .java.

public class Rectangulo { int x; int y; int ancho; int alto; public Rectangulo() { x=0; y=0; ancho=0; alto=0; } public Rectangulo(int x1, int y1, int w, int h) { x=x1; y=y1; ancho=w; alto=h; } public Rectangulo(int w, int h) { x=0; y=0; ancho=w; alto=h; }

PROGRAMACION CON JAVA 2 149

int calcularArea() { return (ancho*alto); } void desplazar(int dx, int dy) { x+=dx; y+=dy; } boolean estaDentro(int x1, int y1) { if((x1>x)&&(x1<x+ancho)&&(y1>y)&&(y1<y+ancho)) { return true; } return false; } }

4.4. LOS OBJETOS

Para crear un objeto de una clase se usa la palabra reservada new.

Por ejemplo,

Rectangulo rect1=new Rectangulo(10, 20, 40, 80);

new reserva espacio en memoria para los miembros dato y devuelve una referencia que se guarda en la variable rect1 del tipo Rectangulo que denominamos ahora obje-to. Dicha sentencia, crea un objeto denominado rect1 de la clase Rectangulo llamando al segundo constructor en el listado. El rectángulo estará situado en el pun-to de coordenadas x=10, y=20; tendrá una anchura de ancho=40 y una altura de alto=80.

Rectangulo rect2=new Rectangulo(40, 80);

Crea un objeto denominado rect2 de la clase Rectangulo llamando al tercer constructor, dicho rectángulo esta-rá situado en el punto de coordenadas x=0, y=0; y ten-drá una anchura de ancho=40 y una altura de alto=80.

Rectangulo rect3=new Rectangulo();

Crea un objeto denominado rect3 de la clase Rectangulo llamando al primer constructor, dicho rectángulo esta-

150 Mg. ABRAHAM GAMARRA MORENO

rá situado en el punto de coordenadas x=0, y=0; y ten-drá una anchura de ancho=0 y una altura de alto=0.

4.4.1. ACCESO A LOS MIEMBROS

Desde un objeto se puede acceder a los miem-bros mediante la siguiente sintaxis

objeto.miembro;

Por ejemplo, podemos acceder al miembro dato ancho, para cambiar la anchura de un objeto rectángulo.

rect1.ancho=100;

El rectángulo rect1 que tenía inicialmente una anchura de 40, mediante esta sentencia se la cambiamos a 100.

Desde un objeto llamamos a las funciones miembro para realizar una determinada tarea. Por ejemplo, desde el rectángulo rect1 llama-mos a la función calcularArea para calcular el área de dicho rectángulo.

rect1.calcularArea();

La función miembro area devuelve un entero, que guardaremos en una variable entera medidaArea, para luego usar este dato.

int medidaArea=rect1.calcularArea();

System.out.println("El área del rectángulo es "+medidaArea);

Para desplazar el rectángulo rect2, 10 unida-des hacia la derecha y 20 hacia abajo, escri-biremos

rect2.desplazar(10, 20);

Podemos verificar mediante el siguiente códi-go si el punto (20, 30) está en el interior del rectángulo rect1.

PROGRAMACION CON JAVA 2 151

if(rect1.estaDentro(20,30)) { System.out.println("El punto está dentro del rectángulo"); }else { System.out.println("El punto está fuera del rectángulo"); }

rect1.dentro() devuelve true si el punto (20, 30) que se le pasa a dicha función miembro está en el interior del rectángulo rect1, ejecutándose la primera sentencia, en caso contrario se ejecuta la segunda.

Como veremos más adelante no siempre es posi-ble acceder a los miembros, si establecemos controles de acceso a los mismos.

public class RectanguloApp1 { public static void main(String[] args) { Rectangulo rect1=new Rectangulo(10, 20, 40, 80); Rectangulo rect2=new Rectangulo(40, 80); Rectangulo rect3=new Rectangulo(); int medidaArea=rect1.calcularArea(); System.out.println("El área del rectángulo es "+medidaArea); rect2.desplazar(10, 20); if(rect1.estaDentro(20,30)) { System.out.println("El punto está dentro del rec-tángulo"); } else { System.out.println("El punto está fuera del rec-tángulo"); } }//fin main }

4.5. LA VIDA DE UN OBJETO

En el lenguaje C++, los objetos que se crean con new se han de eliminar con delete, new reserva espacio en memoria para el objeto y delete libera dicha memoria.

152 Mg. ABRAHAM GAMARRA MORENO

En el lenguaje Java no es necesario liberar la memoria reservada, el recolector de basura (garbage collector) se encarga de hacerlo por nosotros, liberando al pro-gramador de una de las tareas que más quebraderos de cabeza le producen, olvidarse de liberar la memoria reservada.

Veamos un ejemplo

public class UnaClase { public static void main(String[] args) { Image granImagen=creaImagen(); mostrar(graImagen); while(condicion) { calcular(); } } }

El objeto granImagen, continua en memoria hasta que se alcanza el final de la función main, aunque solamente es necesario hasta el bucle while. En C o en C++ eli-minariamos dicho objeto liberando la memoria que ocupa mediante delete. El equivalente en Java es el de asig-nar al objeto granImagen el valor null.

public class UnaClase { public static void main(String[] args) { Image granImagen=creaImagen(); mostrar(graImagen); granImagen=null; while(condicion) { calcular(); } } }

A partir de la sentencia marcada en letra negrita el recolector de basura se encargará de liberar la memo-ria ocupada por dicha imagen. Así pues, se asignará el valor null a las referencias a objetos temporales que

PROGRAMACION CON JAVA 2 153

ocupen mucha memoria tan pronto como no sean necesa-rios.

Creamos dos objetos de la clase rectángulo, del mismo modo que en el apartado anterior

Rectangulo rect1=new Rectangulo(10, 20, 40, 80);

Rectangulo rect3=new Rectangulo();

Si escribimos

rect3=rect1;

En rect3 se guarda la referencia al objeto rect1. La referencia al objeto rect3 se pierde. El recolector se encarga de liberar el espacio en memoria ocupado por el objeto rect3.

La destrucción de un objeto es una tarea (thread) de baja prioridad que lleva a cabo la Máquina Virtual Ja-va (JVM). Por tanto, nunca podemos saber cuando se va a destruir un objeto.

Puede haber situaciones en las que es necesario reali-zar ciertas operaciones que no puede realizar el reco-lector de basura (garbage collector) cuando se destru-ye un objeto. Por ejemplo, se han abierto varios ar-chivos durante la vida de un objeto, y se desea que los archivos estén cerrados cuando dicho objeto des-aparece. Se puede definir en la clase un método deno-minado finalize que realice esta tarea. Este método es llamado por el recolector de basura inmediatamente an-tes de que el objeto sea destruido.

Ejemplo (34): Manejo de la clase rectángulo.

//archivo Rectangulo.java public class Rectangulo { int x; int y; int ancho; int alto; public Rectangulo() { x=0; y=0; ancho=0; alto=0; }

154 Mg. ABRAHAM GAMARRA MORENO

public Rectangulo(int x1, int y1, int w, int h) { x=x1; y=y1; ancho=w; alto=h; } public Rectangulo(int w, int h) { x=0; y=0; ancho=w; alto=h; } int calcularArea() { return (ancho*alto); } void desplazar(int dx, int dy) { x+=dx; y+=dy; } boolean estaDentro(int x1, int y1) { if((x1>x)&&(x1<x+ancho)&&(y1>y)&&(y1<y+ancho)) { return true; } return false; } }

__________________________________

//archivo: RectanguloApp1.java public class RectanguloApp1 { public static void main(String[] args) { Rectangulo rect1=new Rectangulo(10, 20, 40, 80); Rectangulo rect2=new Rectangulo(40, 80); Rectangulo rect3=new Rectangulo(); int medidaArea=rect1.calcularArea(); System.out.println("El area del rectangulo 1 es "+medidaArea); rect2.desplazar(10, 20);

PROGRAMACION CON JAVA 2 155

System.out.println("Las nuevas coordenadas del rectangulo 2 es: "); System.out.println("x= "+ rect2.x+" y="+rect2.y); if(rect1.estaDentro(20,30)) { System.out.println("El punto (20,30) esta dentro del rectangulo 1"); } else { System.out.println("El punto (20,30) esta fuera del rectangulo 1"); } }//fin main }

4.6. IDENTIFICADORES

Cómo se escriben los nombres de las variables, de las clases, de las funciones, etc., es un asunto muy im-portante de cara a la comprensión y el mantenimiento de código. En la introducción a los fundamentos del lenguaje Java hemos tratado ya de los identificadores.

El código debe de ser tanto más fácil de leer y de en-tender como sea posible. Alguien que lea el código, incluso después de cierto tiempo, debe ser capaz de entender lo que hace a primera vista, aunque los deta-lles internos, es decir, cómo lo hace, precise un es-tudio detallado.

Vemos primero un ejemplo que muestra un código poco legible y por tanto, muy difícil de mantener

public class Cuen { private int ba; public void dep(int i) { ba+=i; }

156 Mg. ABRAHAM GAMARRA MORENO

public void ret(int i) { ba-=i; } public int get() { return ba; } }

Las abreviaciones empleadas solamente tienen signifi-cado para el programador en el momento de escribir el código, ya que puede olvidarse de su significado con el tiempo. Otros programadores del grupo tienen que descifrar el significado del nombre de cada variable o de cada función. El tiempo extra que se gasta en es-cribir con claridad el nombre de los diversos elemen-tos que entran en el programa, se ahorra más adelante durante su desarrollo, depuración, y mejora, es decir, durante todo el ciclo de vida del programa.

public class CuentaBancaria { private int balance; public void depositar(int cantidad) { balance+=cantidad; } public void retirar(int cantidad) { balance-=cantidad; } public int obtenerBalance() { return balance; } }

4.7. MODIFICADORES DE ACCESO A LOS MIEMBROS DE UNA CLASE

Una faceta importante de los lenguajes de Programación Orientada a Objetos se denomina encapsulación. El ac-ceso a los miembros de una clase está controlado. Para usar una clase, solamente necesitamos saber que fun-ciones miembro se pueden llamar y a qué datos podemos acceder, no necesitamos saber como está hecha la cla-

PROGRAMACION CON JAVA 2 157

se, como son sus detalles internos. Una vez que la clase está depurada y probada, la clase es como una caja negra. Los objetos de dicha clase guardan unos datos, y están caracterizados por una determinada con-ducta. Este ocultamiento de la información niega a las entidades exteriores el acceso a los miembros privados (private) de un objeto. De este modo, las entidades exteriores acceden a los datos de una manera controla-da a través de algunas funciones miembro. Para acceder a un miembro público (public), sea dato o función bas-ta escribir:

objeto_de_la_clase.miembro_público_no_estático clase.miembro_público_estático

La segunda representación se ampliará cuando veamos miembros dato estático y métodos estático.

4.7.1. MIEMBROS PÚBLICOS

Los miembros públicos son aquellos que tienen delante la palabra public, y se puede acceder a ellos sin ninguna restricción.

4.7.2. MIEMBROS PRIVADOS

Los miembros privados son aquellos que tienen delante la palabra private, y se puede acce-der a ellos solamente dentro del ámbito de la clase.

4.7.3. POR DEFECTO (A NIVEL DE PAQUETE)

Cuando no se pone ningún modificador de acce-so delante de los miembros, se dice que son accesibles dentro del mismo paquete (packa-ge). Esto es lo que hemos utilizado en algu-nos de los ejemplos estudiados antes.

package es la primera sentencia que se pone en un archivo .java. El nombre del paquete es el mismo que el nombre del subdirectorio que contiene los archivos .java. Cada archivo .java contiene habitualmente una clase. Si tiene más de una solamente una de ellas es pública. El nombre de dicha clase coincide

158 Mg. ABRAHAM GAMARRA MORENO

con el nombre del archivo. El uso de paquetes se estudiará más adelante.

Como se habrá dado cuenta hay una correspondencia en-tre archivos y clases, entre paquetes y subdirecto-rios. El Entorno Integrado de Desarrollo (IDE) en el que creamos los programas facilita esta tarea sin que el usuario se aperciba de ello.

Ejemplo (35): Uso de los modificadores de acceso pac-kage

//archivo: Linea.java

import java.io.*; class Linea { //coordenada 1er punto, modificador de acceso:package int x1,y1; //coordenada 2do punto, modificador de acceso:package int x2,y2; void leer() //modificador de acceso:package { try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto //lectura System.out.println("Introduzca 1er punto: "); System.out.print("x1: "); sdato = flujoE.readLine(); // leer una línea de texto x1=Integer.parseInt(sdato);//convierte cadena System.out.print("y1: "); sdato = flujoE.readLine(); // leer una línea de texto y1=Integer.parseInt(sdato);//convierte cadena System.out.println("Introduzca 2do punto: "); System.out.print("x2: "); sdato = flujoE.readLine(); // leer una línea de texto x2=Integer.parseInt(sdato);//convierte cadena System.out.print("y2: "); sdato = flujoE.readLine(); // leer una línea de texto y2=Integer.parseInt(sdato);//convierte cadena } catch (IOException ignorada) {} }

PROGRAMACION CON JAVA 2 159

void escribir() //modificador de acceso:package { System.out.println("Puntos de la recta : "); System.out.println("x1="+x1+" y1="+y1); System.out.println("x2="+x2+" y2="+y2); } }

// Archivo LineaAppl.java

import java.io.*; class LineaAppl { public static void main (String[] args) { //Creación de un objeto recta: r1 Linea r1=new Linea(); // uso del objeto r1 //como el modificador de acceso es package //y la clase Linea esta en el mismo directorio //entonces main() puede utilizar los métodos //leer() y escribir() r1.leer(); r1.escribir(); } }

160 Mg. ABRAHAM GAMARRA MORENO

Ejemplo (36): Uso del modificador de acceso privado (private). El siguiente programa es similar al ante-rior salvo que los métodos de la clase Linea son pri-vate.

//archivo: Linea1.java

import java.io.*; class Linea1 { //coordenada 1er punto, modificador de acceso:package int x1,y1; //coordenada 2do punto, modificador de acceso:package int x2,y2; private void leer() //modificador de acceso:privado { try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto //lectura System.out.println("Introduzca 1er punto: "); System.out.print("x1: "); sdato = flujoE.readLine(); // leer una línea de texto x1=Integer.parseInt(sdato);//convierte cadena System.out.print("y1: "); sdato = flujoE.readLine(); // leer una línea de texto y1=Integer.parseInt(sdato);//convierte cadena System.out.println("Introduzca 2do punto: "); System.out.print("x2: "); sdato = flujoE.readLine(); // leer una línea de texto x2=Integer.parseInt(sdato);//convierte cadena System.out.print("y2: "); sdato = flujoE.readLine(); // leer una línea de texto y2=Integer.parseInt(sdato);//convierte cadena } catch (IOException ignorada) {} } private void escribir() //modificador de acceso:privado { System.out.println("Puntos de la recta : "); System.out.println("x1="+x1+" y1="+y1); System.out.println("x2="+x2+" y2="+y2); } }

PROGRAMACION CON JAVA 2 161

// Archivo Linea1Appl.java

import java.io.*; class Linea1Appl { public static void main (String[] args) { //Creación de un objeto recta: r1 Linea1 r1=new Linea1(); // uso del objeto r1 //como el modificador de acceso de los metodos //de la clase Linea es privado //entonces main() no puede utilizar los métodos //leer() y escribir() r1.leer(); r1.escribir(); } }

NOTA: Este programa no ejecuta porque el compilador protesta mostrando el siguiente mensaje:

\Linea1Appl.java:18: leer() has private access in Linea1 r1.leer(); ^ \Linea1Appl.java:19: escribir() has private access in Li-nea1 r1.escribir(); ^ 2 errors

Ejemplo (37): Uso del modificador private y public. Notese como la función main(), puede acceder a los mé-todos públicos de la clase Linea2.

//archivo: Linea2.java

import java.io.*; class Linea2 { //coordenada 1er punto, modificador de acceso:privado private int x1,y1; //coordenada 2do punto, modificador de acceso:privado private int x2,y2; //los datos miembro solo seran accedidos por su métodos //por ser privados public void leer() //modificador de acceso:público { try

162 Mg. ABRAHAM GAMARRA MORENO

{ // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto //lectura System.out.println("Introduzca 1er punto: "); System.out.print("x1: "); sdato = flujoE.readLine(); // leer una línea de texto x1=Integer.parseInt(sdato);//convierte cadena System.out.print("y1: "); sdato = flujoE.readLine(); // leer una línea de texto y1=Integer.parseInt(sdato);//convierte cadena System.out.println("Introduzca 2do punto: "); System.out.print("x2: "); sdato = flujoE.readLine(); // leer una línea de texto x2=Integer.parseInt(sdato);//convierte cadena System.out.print("y2: "); sdato = flujoE.readLine(); // leer una línea de texto y2=Integer.parseInt(sdato);//convierte cadena } catch (IOException ignorada) {} } public void escribir() //modificador de acceso:público { System.out.println("Puntos de la recta : "); System.out.println("x1="+x1+" y1="+y1); System.out.println("x2="+x2+" y2="+y2); } }

// Archivo Linea2Appl.java

import java.io.*; class Linea2Appl { public static void main (String[] args) { //Creación de un objeto recta: r1 Linea2 r1=new Linea2(); // uso del objeto r1 //como el modificador de acceso de los métodos //de la clase Linea es public //entonces main() puede utilizar los métodos //leer() y escribir()

PROGRAMACION CON JAVA 2 163

r1.leer(); r1.escribir(); } }

Ejemplo (38) Uso del modificador public. Notese como la función main(), puede acceder a los datos y métodos públicos.

//archivo: Linea3.java

import java.io.*; class Linea3 { //coordenada 1er punto, modificador de acceso:público public int x1,y1; //coordenada 2do punto, modificador de acceso:público public int x2,y2; //los datos miembro solo seran accedidos por su métodos //por ser privados public void leer() //modificador de acceso:público { try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto //lectura System.out.println("Introduzca 1er punto: "); System.out.print("x1: "); sdato = flujoE.readLine(); // leer una línea de texto x1=Integer.parseInt(sdato);//convierte cadena System.out.print("y1: ");

164 Mg. ABRAHAM GAMARRA MORENO

sdato = flujoE.readLine(); // leer una línea de texto y1=Integer.parseInt(sdato);//convierte cadena System.out.println("Introduzca 2do punto: "); System.out.print("x2: "); sdato = flujoE.readLine(); // leer una línea de texto x2=Integer.parseInt(sdato);//convierte cadena System.out.print("y2: "); sdato = flujoE.readLine(); // leer una línea de texto y2=Integer.parseInt(sdato);//convierte cadena } catch (IOException ignorada) {} } public void escribir() //modificador de acceso:público { System.out.println("Puntos de la recta : "); System.out.println("x1="+x1+" y1="+y1); System.out.println("x2="+x2+" y2="+y2); } } // Archivo Linea3Appl.java

import java.io.*; class Linea3Appl { public static void main (String[] args) { //Creación de un objeto recta: r1 Linea3 r1=new Linea3(); // uso del objeto r1 //como el modificador de acceso de los datos //de la clase Linea es public //entonces main() puede accesar a los datos //sin necesidad de utilizar sus métodos System.out.println("Valores inciales de la recta:"); r1.x1=10;r1.y1=11; r1.x2=100;r1.y2=101; System.out.println("x1="+r1.x1+" y1="+r1.y1); System.out.println("x2="+r1.x2+" y2="+r1.y2); //como el modificador de acceso de los métodos //de la clase Linea es public //entonces main() puede accesar a //leer() y escribir(), para modificar sus datos //miembro System.out.println("Valores para modificar la recta:"); r1.leer(); r1.escribir(); } }

PROGRAMACION CON JAVA 2 165

4.8. EJEMPLOS DEL USO DE CLASES

Ejemplo (39): Realice un programa que maneje la clase tiempo. Esta clase debe tener las siguientes caracte-rísticas:

• La clase tiene los datos miembro hora, min , seg; los cuales guardan las horas, minutos y segundos respectivamente.

• Los métodos (funciones miembro) a implementar son:

void leer_tiempo() : que asigna valores a hora, min , seg. (2 PTOS)

void escribir_tiempo() : Permite visualizar el valor de hora, min , seg (2 PTOS)

tiempo tiempo_transcurrido(tiempo nuevotiempo) : re-torna un objeto de la clase tiempo, que contiene el tiempo transcurrido con respecto al parámetro recibido (4 PTOS).

• La clase que contiene al método principal main(), debe manipular estos métodos. (2 PTOS)

//archivo tiempo.java import java.io.*; class tiempo

166 Mg. ABRAHAM GAMARRA MORENO

{ //hora minutos y segundos private int hora,min,seg; public void leer_tiempo() throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto System.out.print("hora (0-23): "); sdato = flujoE.readLine(); // leer una línea de texto hora=Integer.parseInt(sdato);//convierte cadena System.out.print("minutos (0-59): "); sdato = flujoE.readLine(); // leer una línea de texto min=Integer.parseInt(sdato);//convierte cadena System.out.print("segundos (0-59): "); sdato = flujoE.readLine(); // leer una línea de texto seg=Integer.parseInt(sdato);//convierte cadena } public void escribir_tiempo() { System.out.println(hora+":"+min+":"+seg); } public tiempo tiempo_transcurrido(tiempo nt) //se recibe el tiempo nuevo { int tseg=0;//guarda los segundos del tiempo anterior int ntseg=0;//guarda los segundos del tiempo nuevo int transeg;//guarda los segundos del tiempo transcurrido tiempo dif=new tiempo(); //convertir los tiempos a seg //con el tiempo anterior tseg=tseg+hora*3600;tseg=tseg+min*60;tseg=tseg+seg; //con el tiempo nuevo nt ntseg=ntseg+nt.hora*3600;ntseg=ntseg+nt.min*60; ntseg=ntseg+nt.seg; //hallar los segundos transcurridos transeg=ntseg-tseg; //convertir a horas, minutos y segundos dif.hora=transeg/3600; transeg=transeg%3600; dif.min=transeg/60;transeg=transeg%60; dif.seg=transeg; return dif; } }

PROGRAMACION CON JAVA 2 167

//archivo: exa2p120032App.java import java.io.*; class exa2p120032App { public static void main (String[] args) throws IOException { tiempo t1=new tiempo();tiempo t2=new tiempo(); tiempo trans=new tiempo(); System.out.println("Ingrese tiempo :"); t1.leer_tiempo(); t1.escribir_tiempo(); System.out.println("Ingrese nuevo tiempo :"); t2.leer_tiempo(); t2.escribir_tiempo(); System.out.println("Tiempo transcurrido :"); trans=t1.tiempo_transcurrido(t2); trans.escribir_tiempo(); } }

Ejemplo (40): Uso de la clase complejo.

// Archivo: Complejo.java import java.lang.Math; class Complejo { private float real; private float imaginario;

Complejo() { real=0; imaginario=0; } public void asignar(float r, float i) { real=r; imaginario=i; }

168 Mg. ABRAHAM GAMARRA MORENO

public void escribir() { System.out.println("El complejo es: "+real+" + "+imaginario+" i"); } public float absoluto(Complejo c) { float va; va=c.real*c.real+c.imaginario*c.imaginario; va=(float) Math.sqrt(va); return va; }

}

_________________________________________ // Archivo ComplejoAppl.java import java.io.*; class ComplejoAppl { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto float re,im; //real, imaginario float valabs;//valor absoluto //Creación de un objeto complejo: c1 Complejo c1=new Complejo(); //lectura de datos System.out.print("Introduzca parte real: "); sdato = flujoE.readLine(); // leer una línea de texto re=Float.parseFloat(sdato);//convierte cadena a float System.out.print("Introduzca parte imaginaria: "); sdato = flujoE.readLine(); // leer una línea de texto im=Float.parseFloat(sdato);//convierte cadena a float // uso del objeto c1 c1.asignar(re,im); c1.escribir(); valabs=c1.absoluto(c1); System.out.println("El valor absoluto es : "+valabs); } }

PROGRAMACION CON JAVA 2 169

Ejemplo (41): Clase quebrado

//archivo: quebrado.java

import java.io.*; class quebrado { private int n;//numerador private int d;//denominador public void leer() { try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto //lectura System.out.print("Introduzca numerador: "); sdato = flujoE.readLine(); // leer una línea de texto n=Integer.parseInt(sdato);//convierte cadena System.out.print("Introduzca denominador: "); sdato = flujoE.readLine(); // leer una línea de texto d=Integer.parseInt(sdato);//convierte cadena } catch (IOException ignorada) {} } public void escribir() { System.out.print("El quebrado es: "); if (d!=1) System.out.println(n+"/"+d); else System.out.println(n); } public quebrado sumar(quebrado r)

170 Mg. ABRAHAM GAMARRA MORENO

{ quebrado s=new quebrado(); s.n=n*r.d+d*r.n; s.d=d*r.d; return(s); } public quebrado simplificar(quebrado r) { int i; i=2; while(i<=r.n && i<=r.d) { while(r.n%i==0 && r.d%i==0) { r.n=r.n/i; r.d=r.d/i; } i++; } return(r); } }

//archivo: quebradoAppl.java

public class quebradoAppl { public static void main(String[] args) { quebrado q1=new quebrado(); quebrado q2=new quebrado(); quebrado q=new quebrado(); q1.leer(); q1.escribir(); q2.leer(); q2.escribir(); System.out.println("La suma es: "); q=q1.sumar(q2); q=q.simplificar(q); q.escribir(); }//fin main }

PROGRAMACION CON JAVA 2 171

Ejemplo (42): Clase cuenta (Versión 1). Muestra el uso de las funciones miembro con parámetros, por lo que se debe pasar valores a estas funciones.

// Archivo: Cuenta.java

import java.lang.Math; class Cuenta { private float saldo; public void asignar(float s) { saldo=s; } public void escribir() { System.out.println("El saldo es: "+saldo); } public void deposito(float d) { saldo=saldo+d; } public void retiro(float r) { // no se verifica si el saldo es mayor que el retiro saldo=saldo-r; } }

// Archivo CuentaAppl.java

import java.io.*; class CuentaAppl { public static void main (String[] args)

172 Mg. ABRAHAM GAMARRA MORENO

throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto float sal,dep,ret; //saldo inicial, depósito y retiro //Creación de un objeto Cuenta: c Cuenta c=new Cuenta(); //lectura de datos System.out.print("Introduzca saldo inicial: "); sdato = flujoE.readLine(); // leer una línea de texto sal=Float.parseFloat(sdato);//convierte cadena a float c.asignar(sal); c.escribir(); System.out.print("Introduzca deposito: "); sdato = flujoE.readLine(); // leer una línea de texto dep=Float.parseFloat(sdato);//convierte cadena a float c.deposito(dep); c.escribir(); System.out.print("Introduzca retiro: "); sdato = flujoE.readLine(); // leer una línea de texto ret=Float.parseFloat(sdato);//convierte cadena a float c.retiro(ret); c.escribir(); } }

Ejemplo (43): Clase cuenta (Versión 2). Muestra el uso de las funciones miembro sin parámetros, por lo que se debe leer los valores desde la misma función. Observe el uso de throws IOException en las funciones.

PROGRAMACION CON JAVA 2 173

// Archivo: Cuenta1.java

import java.io.*; class Cuenta1 { private float saldo; public void asignar() throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto //lectura de datos System.out.print("Introduzca saldo inicial: "); sdato = flujoE.readLine(); // leer una línea de texto saldo=Float.parseFloat(sdato);//convierte cadena a float } public void escribir() { System.out.println("El saldo es: "+saldo); } public void deposito() throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto float dep; System.out.print("Introduzca deposito: "); sdato = flujoE.readLine(); // leer una línea de texto dep=Float.parseFloat(sdato);//convierte cadena a float saldo=saldo+dep; } public void retiro() throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto float ret; System.out.print("Introduzca retiro: "); sdato = flujoE.readLine(); // leer una línea de texto ret=Float.parseFloat(sdato);//convierte cadena a float // no se verifica si el saldo es mayor que el retiro saldo=saldo-ret; } }

174 Mg. ABRAHAM GAMARRA MORENO

// Archivo Cuenta1Appl.java

import java.io.*; class Cuenta1Appl { public static void main (String[] args) throws IOException { //Creación de un objeto Cuenta1 Cuenta1 c=new Cuenta1(); c.asignar(); c.escribir(); c.deposito(); c.escribir(); c.retiro(); c.escribir(); } }

Ejemplo (44): Clase cuenta (Versión 3). Muestra el uso de las funciones miembro sin parámetros, por lo que se debe leer los valores desde la misma función. Observe el uso de try. . .catch en lugar de throws IOException en las funciones.

// Archivo: Cuenta2.java

import java.io.*; class Cuenta2 { private float saldo; public void asignar() { try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr);

PROGRAMACION CON JAVA 2 175

String sdato; // variable para almacenar una línea de //texto //lectura de datos System.out.print("Introduzca saldo inicial: "); sdato = flujoE.readLine(); // leer una línea de texto saldo=Float.parseFloat(sdato);//convierte cadena a float } catch (IOException ignorada) {} } public void escribir() { System.out.println("El saldo es: "+saldo); } public void deposito() { try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de //texto float dep; System.out.print("Introduzca deposito: "); sdato = flujoE.readLine(); // leer una línea de texto dep=Float.parseFloat(sdato);//convierte cadena a float saldo=saldo+dep; } catch (IOException ignorada) {} } public void retiro() { try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de //texto float ret; System.out.print("Introduzca retiro: "); sdato = flujoE.readLine(); // leer una línea de texto ret=Float.parseFloat(sdato);//convierte cadena a float // no se verifica si el saldo es mayor que el retiro saldo=saldo-ret; } catch (IOException ignorada) {} } }

176 Mg. ABRAHAM GAMARRA MORENO

// Archivo Cuenta2Appl.java

import java.io.*; class Cuenta2Appl { public static void main (String[] args) { //Creación de un objeto Cuenta2: c Cuenta2 c=new Cuenta2(); c.asignar(); c.escribir(); c.deposito(); c.escribir(); c.retiro(); c.escribir(); } }

Ejemplo (45): Clase Conjunto (Versión 1). Muestra el uso de la funcion miembro union con un parámetro. Ob-serve el uso de try. . .catch en lugar de throws IOEx-ception en la función leer().

//archivo: Conjunto.java

import java.io.*; import java.lang.String.*; class Conjunto { private char [] e;//elemento del conjunto public void leer() {//la lectura no verifica que existan elementos repetidos try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr);

PROGRAMACION CON JAVA 2 177

String sdato; // variable para almacenar una línea de texto //lectura System.out.print("Elementos del conjunto como cadena: "); sdato = flujoE.readLine(); // leer una línea de texto //crear un arreglo de caracteres e=sdato.toCharArray(); } catch (IOException ignorada) {} } public void escribir() { System.out.print("Los elementos del Conjun-to son : {"); for(int i=0;i<e.length;i++) if (i!=e.length) System.out.print(e[i]+","); else System.out.print(e[i]); System.out.println("}"); } public Conjunto union(Conjunto c1) { int i,j; //contadores //tam guarda el tamaño de los dos conjuntos int tam=e.length+c1.e.length; //conjunto union Conjunto u=new Conjunto(); //el conjunto union supone que no va a existir //elementos que puedan repetirse en ambos conjuntos //inicializa elementos del conjunto union u.e=new char [tam]; //añade elementos del primer conjunto for(i=0;i<e.length;i++) u.e[i]=e[i]; //añade elementos del segundo conjunto j=i; for(i=0;i<c1.e.length;i++) {u.e[j]=c1.e[i]; j++; } return u; } }

178 Mg. ABRAHAM GAMARRA MORENO

//archivo: ConjuntoAppl.java

public class ConjuntoAppl { public static void main(String[] args) { Conjunto c=new Conjunto(); Conjunto c1=new Conjunto(); Conjunto c2=new Conjunto(); c1.leer(); c1.escribir(); c2.leer(); c2.escribir(); System.out.println("Conjunto union"); c=c1.union(c2); c.escribir(); }//fin main }

Ejemplo (46): Clase Conjunto (Versión 2). Muestra el uso de la funcion miembro union con dos parámetros. Observe el uso de try. . .catch en lugar de throws IOException en la función leer().

//archivo: Conjunto1.java

import java.io.*; import java.lang.String.*; class Conjunto1 { private char [] e;//elemento del conjunto public void leer() {//la lectura no verifica que existan elementos repetidos try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr);

PROGRAMACION CON JAVA 2 179

String sdato; // variable para almacenar una línea de texto //lectura System.out.print("Elementos del conjunto como cadena: "); sdato = flujoE.readLine(); // leer una línea de texto //crear un arreglo de caracteres e=sdato.toCharArray(); } catch (IOException ignorada) {} } public void escribir() { System.out.print("Los elementos del Conjunto son : {"); for(int i=0;i<e.length;i++) if (i!=e.length) System.out.print(e[i]+","); else System.out.print(e[i]); System.out.println("}"); } public Conjunto1 union(Conjunto1 c1, Conjunto1 c2) { int i,j; //contadores //tam guarda el tamaño de los dos conjuntos int tam=c1.e.length+c2.e.length; //conjunto union Conjunto1 u=new Conjunto1(); //el conjunto union supone que no va a existir //elementos que puedan repetirse en ambos conjuntos //inicializa elementos del conjunto union u.e=new char [tam]; //añade elementos del primer conjunto for(i=0;i<c1.e.length;i++) u.e[i]=c1.e[i]; //añade elementos del segundo conjunto j=i; for(i=0;i<c2.e.length;i++) {u.e[j]=c2.e[i]; j++; } return u; } }

180 Mg. ABRAHAM GAMARRA MORENO

//archivo: Conjunto1Appl.java

public class Conjunto1Appl { public static void main(String[] args) { Conjunto1 c=new Conjunto1(); Conjunto1 c1=new Conjunto1(); Conjunto1 c2=new Conjunto1(); c1.leer(); c1.escribir(); c2.leer(); c2.escribir(); System.out.println("Conjunto union"); c=c.union(c1,c2); c.escribir(); }//fin main }

PROGRAMACION CON JAVA 2 181

Ejemplo (47): Realice un programa que maneje la clase enterazo. Esta clase permite almacenar los dígitos de un número en base diez, en cada posición de un arre-glo:

• La clase tiene los siguientes datos miembros: va-lor[ ]: arreglo que almacena los dígitos del núme-ro.

• Los métodos (funciones miembro) a implementar son:

void asignar(): Define el valor almacenar del dato miembro. (No usar charToArray()) (2 PTOS)

void mostrar(): Muestra el contenido del dato miembro. (2 PTOS)

enterazo multiplicar(enterazo numero2): Recibe un objeto de la clase enterazo y lo multiplica con el enterazo de la clase actual. Esta función devuelve un objeto enterazo que contiene la multiplicación de esos dos números. (4 PTOS)

• La clase que contiene al método principal main(), debe manipular estos métodos. (2 PTOS)

//archivo enterazo.java import java.io.*; class enterazo { //arreglo que almacena los dígitos de un número //consideremos tres cifras private int[] valor; public void asignar() throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto valor= new int[3]; System.out.println("Ingrese cifra por cifra del numero: "); for (int i=0;i<valor.length;i++) { sdato = flujoE.readLine(); // leer una línea de texto valor[i]=Integer.parseInt(sdato);//convierte cadena }

182 Mg. ABRAHAM GAMARRA MORENO

} public void mostrar() { for (int i=0;i<valor.length;i++) System.out.print(valor[i]); System.out.println(""); } public enterazo multiplicar(enterazo ent2) { int tam=valor.length+ent2.valor.length; int[]n1=new int[tam]; int[]n2=new int[tam]; int[]n3=new int[tam]; enterazo mult=new enterazo(); mult.valor= new int[tam]; int in;//contador para 1er, 2do y 3er termino de la suma int j;//cifra derecha del 1er enterazo int i;//cifra derecha del 1er enterazo int aux,acarreo=0; // Recorre las cifras del segundo número y // lo almacena en 1er término suma n1[] in=tam-1;//derecha del 1er término de la suma j=ent2.valor.length-1;// cifra derecha 2do enterazo for(i=valor.length-1;i>=0;i--) { aux=valor[i]*ent2.valor[j]+acarreo; n1[in]=aux%10; acarreo=aux/10; in--; } n1[in]=acarreo; acarreo=0; // Recorre las cifras del segundo número y // lo almacena en 2do término suma n2[] in=tam-2;//derecha del 2do término de la suma j=ent2.valor.length-2;// cifra 2do enterazo for(i=valor.length-1;i>=0;i--) { aux=valor[i]*ent2.valor[j]+acarreo; n2[in]=aux%10; acarreo=aux/10; in--; } n2[in]=acarreo; acarreo=0; // Recorre las cifras del segundo número y // lo almacena en 3er término suma n3[] in=tam-3;//derecha del 3er término de la suma j=ent2.valor.length-3;// cifra derecha 2do enterazo

PROGRAMACION CON JAVA 2 183

for(i=valor.length-1;i>=0;i--) { aux=valor[i]*ent2.valor[j]+acarreo; n3[in]=aux%10; acarreo=aux/10; in--; } n3[in]=acarreo; acarreo=0; //suma de los tres términos for(i=n1.length-1;i>=0;i--) { aux=n1[i]+n2[i]+n3[i]+acarreo; mult.valor[i]=aux%10; acarreo=aux/10; } return mult; } } //archivo: exa2p220032App.java import java.io.*; class exa2p220032App { public static void main (String[] args) throws IOException { enterazo e1=new enterazo();enterazo e2=new enterazo(); enterazo em=new enterazo(); e1.asignar(); System.out.println("primer numero: ");e1.mostrar(); e2.asignar(); System.out.println("segundo numero: ");e2.mostrar(); em=e1.multiplicar(e2); System.out.println("multiplicacion: ");em.mostrar(); } }

184 Mg. ABRAHAM GAMARRA MORENO

4.9. SOBRECARGA DE UN MÉTODO

Es posible y a menudo deseable crear más de un método con el mismo nombre, pero con listas de parámetros distintas. A esto se le llama sobrecarga de método. Se sobrecarga un método siempre que se crea un método en una clase que ya tiene un método con el mismo nombre. Aquí presentamos una versión de la clase quebrado (ejemplo mostrado antes) que utiliza sobrecarga de mé-todo para sumar 2 y 3 quebrados. A diferencia del ejemplo con la clase quebrado anterior este no utiliza un solo parámetro en la suma sino 2 y tres parámetros. Sugerimos analizar las diferencias.

Ejemplo(48): Sobrecarga del método sumar(...), de la clase quebrado1.

//archivo: quebrado1.java

import java.io.*; class quebrado1 { private int n;//numerador private int d;//denominador public void leer() { try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto //lectura System.out.print("Introduzca numerador: "); sdato = flujoE.readLine(); // leer una línea de texto n=Integer.parseInt(sdato);//convierte cadena System.out.print("Introduzca denominador: "); sdato = flujoE.readLine(); // leer una línea de texto d=Integer.parseInt(sdato);//convierte cadena } catch (IOException ignorada) {} } public void escribir() { System.out.print("El quebrado es: "); if (d!=1) System.out.println(n+"/"+d); else

PROGRAMACION CON JAVA 2 185

System.out.println(n); } public quebrado1 sumar(quebrado1 r1, quebrado1 r2) { quebrado1 r=new quebrado1(); r.n=r1.n*r2.d+r1.d*r2.n; r.d=r1.d*r2.d; return(r); } public quebrado1 sumar(quebrado1 r1,quebrado1 r2,quebrado1 r3) { quebrado1 r=new quebrado1(); r.n=r1.n*r2.d*r3.d+r2.n*r1.d*r3.d+r3.n*r1.d*r2.d; r.d=r1.d*r2.d*r3.d; return(r); } public quebrado1 simplificar(quebrado1 r) { int i; i=2; while(i<=r.n && i<=r.d) { while(r.n%i==0 && r.d%i==0) { r.n=r.n/i; r.d=r.d/i; } i++; } return(r); } }

186 Mg. ABRAHAM GAMARRA MORENO

//archivo: quebrado1Appl.java

public class quebrado1Appl { public static void main(String[] args) { quebrado1 q1=new quebrado1(); quebrado1 q2=new quebrado1(); quebrado1 q3=new quebrado1(); quebrado1 q=new quebrado1(); q1.leer(); q1.escribir(); q2.leer(); q2.escribir(); q3.leer(); q3.escribir(); System.out.println("La suma de los dos primeros es: "); q=q.sumar(q1,q2); q=q.simplificar(q); q.escribir(); System.out.println("La suma de los tres primeros es: "); q=q.sumar(q1,q2,q3); q=q.simplificar(q); q.escribir(); }//fin main }

PROGRAMACION CON JAVA 2 187

4.10. REFERENCIA this

Cada objeto mantiene su propia copia de los atributos pero no de los métodos de su clase, de los cuales sólo existe una copia para todos los objetos de esa clase. Esto es, cada objeto almacena sus propios datos, pero para acceder y operar con ellos, todos comparten los mismos métodos definidos en su clase. Por lo tanto, para que un método conozca la identidad del objeto particular para el que ha sido invocado, Java propor-ciona una referencia al objeto denominada this.

Ejemplo: Clase Circulo (Parcialmente definida)

public class Circulo { // Atributos private double x, y; // coordenadas del centro private double r; // el radio //Métodos que devuelven la circunferencia y el área double circunferencia() { return 2*3.14159*r; } double area() { return 3.14159*r*r; } }

Recordemos que la sintaxis para acceder a los atribu-tos de un objeto es la siguiente:

//Inicializamos nuestro círculo para tener centro en (2, 2) y // radio 1 c.x = 2.0; c.y = 2.0; c.r = 1.0;

Además recordamos que para acceder a los métodos de un objeto usamos la misma sintaxis que para acceder a los atributos de un objeto:

188 Mg. ABRAHAM GAMARRA MORENO

double a;

… a = c.area();

Miremos nuevamente esta última línea:

a = c.area();

Esto es porque lo importante aquí es el objeto, no la llamada a función. Notemos también que no estamos pa-sando ningún argumento a c.area(). El objeto con el que estamos operando, c, está implícito en la sin-taxis.

En realidad hay un argumento, llamado this, el cual está implícito y hace referencia al objeto que estamos manipulando.

Por ejemplo, podríamos haber escrito el método area():

public double area() { return 3.14159 * this.r * this.r; }

En un método simple, no es necesario explicitarlo. En casos más complicados, sin embargo, podemos ver que esto aclara el código, inclusive cuando no es estric-tamente necesario.

Hay casos donde el uso del this es necesario. Uno es cuando el argumento de un método tiene el mismo nombre que uno de los atributos de la clase.

Miremos cómo se crea nuestro objeto círculo:

Circulo c = new Circulo();

La forma en que trabaja es la siguiente: la palabra clave new crea una nueva instancia de la clase. Es ahí cuando se llama al constructor, pasándole al construc-tor el nuevo objeto implícitamente (this, como vimos anteriormente), y pasándole también los argumentos es-pecificados explícitamente entre paréntesis, si es que los hubiera.

PROGRAMACION CON JAVA 2 189

4.10.1. UTILIZACION DE this EN UN CONSTRUC-TOR

Hagamos un constructor para nuestra clase círculo. En el ejemplo siguiente, se muestra un constructor que nos deja especificar los valores iniciales para el centro y el radio de nuestro nuevo objeto Circulo. Aprovechemos el ejemplo para ver el uso de la palabra cla-ve this.

Ejemplo : Un constructor para la clase Circu-lo

public class Circulo { // Atributos private double x, y, r; //El centro y el radio de //nuestro circulo // Constructor public Circulo (double x, double y, double r) { this.x = x; this.y = y; this.r = r; } // Métodos public double circunferencia() { return 2*3.14159*r; } public double area() { return 3.14159*r*r; } }

Por lo tanto, para poder crear un objeto de centro (x, y) en el punto (3.33, 4.75) y de radio 2.25 y usando nuestro nuevo constructor tenemos el siguiente código:

Circulo c = new Circulo (3.33, 4.75, 2.25);

4.10.2. this Y MÚLTIPLE CONSTRUCTORES

Veamos el ejemplo siguiente, en el cual figu-ra el código de 3 constructores y algunos utilizan this.

Ejemplo : Múltiple constructores para la cla-se Circulo

190 Mg. ABRAHAM GAMARRA MORENO

public class Circulo { // Atributos private double x, y, r; // Nuestro constructor anterior public Circulo (double x, double y, double r) { this.x = x; this.y = y; this.r = r; } // Más constructores !!! public Circulo (double r) { x = 0.0; y = 0.0; this.r = r; } public Circulo (Circulo c) { x = c.x; y = c.y; r = c.r; } public Circulo () { x = 0.0; y = 0.0; r = 1.0; } //Métodos public double circunferencia() { return 2*3.14159*r; } public double area() { return 3.14159*r*r; } }

PROGRAMACION CON JAVA 2 191

Ejemplo(49): Programa completo de la clase circulo.

//archivo Circulo.java

class Circulo { // Atributos private double x, y, r; // Nuestro constructor anterior public Circulo (double x, double y, double r) { this.x = x; this.y = y; this.r = r; } // Más constructores !!! public Circulo (double r) { x = 0.0; y = 0.0; this.r = r; } public Circulo (Circulo c) { x = c.x; y = c.y; r = c.r; } public Circulo () { x = 0.0; y = 0.0; r = 1.0; } //Métodos public double circunferencia() { return 2*3.14159*r; } public double area() { return 3.14159*r*r; } }

192 Mg. ABRAHAM GAMARRA MORENO

// Archivo CirculoApp.java

import java.io.*; class CirculoApp { public static void main (String[] args) { Circulo c1=new Circulo(); System.out.print("Circunferencia del circulo 1: "); System.out.println(c1.circunferencia()); System.out.print("Area del circulo 1: "); System.out.println(c1.area()); Circulo c2=new Circulo(2,5,100); System.out.print("Circunferencia del circulo 2: "); System.out.println(c2.circunferencia()); System.out.print("Area del circulo 2: "); System.out.println(c2.area()); Circulo c3=new Circulo(10); System.out.print("Circunferencia del circulo 3: "); System.out.println(c3.circunferencia()); System.out.print("Area del circulo 3: "); System.out.println(c3.area()); } }

4.10.3. OTRA VEZ this

Hay un uso especializado para la palabra cla-ve this que toma mayor importancia cuando una clase tiene múltiple constructores, y es que un constructor puede ser usado desde otro constructor de la misma clase. Vamos a res-cribir el código anterior usando esta técni-ca:

public class Circulo1

PROGRAMACION CON JAVA 2 193

{ // Atributos private double x, y, r; // Nuestro constructor anterior (1) public Circulo1 (double x, double y, double r) { this.x = x; this.y = y; this.r = r; } // Más constructores !!! public Circulo1 (double r) { this (0.0, 0.0, r); //Estamos llamando a (1) } public Circulo1 (Circulo1 c) { this (c.x, c.y, c.r); //Estamos llamando a (1) } public Circulo1 () { this (0.0, 0.0, 1.0); //Estamos llamando a (1) } //Métodos public double circunferencia() { return 2*3.14159*r; } public double area() { return 3.14159*r*r; } }

La llamada a this() tiene como restricción que puede hacerse sólo en la 1ra línea del constructor, el cual puede tener más líneas a continuación.

194 Mg. ABRAHAM GAMARRA MORENO

Ejemplo (50): Programa completo de la clase Circulo1.

//Archivo Circulo1.java

class Circulo1 { // Atributos private double x, y, r; // Nuestro constructor anterior (1) public Circulo1 (double x, double y, double r) { this.x = x; this.y = y; this.r = r; } // Más constructores !!! public Circulo1 (double r) { this (0.0, 0.0, r); //Estamos llamando a (1) } public Circulo1 (Circulo1 c) { this (c.x, c.y, c.r); //Estamos llamando a (1) } public Circulo1 () { this (0.0, 0.0, 1.0); //Estamos llamando a (1) } //Métodos public double circunferencia() { return 2*3.14159*r; } public double area() { return 3.14159*r*r; } }

PROGRAMACION CON JAVA 2 195

// Archivo Circulo1App.java

import java.io.*; class Circulo1App { public static void main (String[] args) { Circulo c1=new Circulo(); System.out.print("Circunferencia del circulo 1: "); System.out.println(c1.circunferencia()); System.out.print("Area del circulo 1: "); System.out.println(c1.area()); Circulo c2=new Circulo(2,5,100); System.out.print("Circunferencia del circulo 2: "); System.out.println(c2.circunferencia()); System.out.print("Area del circulo 2: "); System.out.println(c2.area()); Circulo c3=new Circulo(10); System.out.print("Circunferencia del circulo 3: "); System.out.println(c3.circunferencia()); System.out.print("Area del circulo 3: "); System.out.println(c3.area()); } }

196 Mg. ABRAHAM GAMARRA MORENO

4.11. ARREGLO DE OBJETOS Supongamos que se tiene la clase persona definida de la siguiente forma:

class Persona { private String nombre; private float sueldo; public void leer() { . . . } public void escribir() { . . . } public float obtener_sueldo() { . . . } }

y se desea utilizar no solamente un objeto persona si-no un conjunto de objetos persona; para lograr este objetivo, debemos definir un arreglo de objetos de la siguiente forma:

//declara y crea el arreglo de objetos Persona[] p=new Persona[5];

La instrucción anterior permite crear un arreglo de objetos tal como se muestra en la figura:

Persona[0] Persona[1] Persona[2] Persona[3] Persona[4]

Debemos aclarar que cada posición del arreglo tiene los atributos miembro nombre, sueldo y todos comparten los métodos de la clase.

El acceso a los miembros del objeto se realiza de la siguiente manera:

PROGRAMACION CON JAVA 2 197

p[i]=new Persona();

p[i].leer();

p[i].escribir();

Ejemplo(51): Uso de la clase persona con arreglos.

//Archivo: Personaa.java

import java.io.*; class Personaa { private String nombre; private float sueldo; public void leer() { try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto //lectura System.out.print("nombre: "); nombre= flujoE.readLine(); // leer una línea de texto System.out.print("sueldo: "); sdato = flujoE.readLine(); // leer una línea de texto sueldo=Float.parseFloat(sdato);//convierte cadena } catch (IOException ignorada) {} } public void escribir() { System.out.println("Nombre : "+nombre); System.out.println("Sueldo : "+sueldo); } public float obtener_sueldo() { return sueldo; } }

198 Mg. ABRAHAM GAMARRA MORENO

//archivo: PersonaaApp.java

import java.io.*; class PersonaApp { public static void main (String[] args) throws IOException { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto int n; //lectura de tamaño del arreglo System.out.print("# de personas: "); sdato = flujoE.readLine(); // leer una línea de texto n=Integer.parseInt(sdato);//convierte cadena //declara y crea el arreglo de objetos Persona[] p=new Persona[n]; //otras variables int i;//contador float prom;//promedio de los sueldos float sueldos=0;//acumulador de los sueldos //inicializaciòn de objetos for (i=0;i<p.length;i++) p[i]=new Persona(); //lectura de datos System.out.println("Ingrese datos de las personas: "); for (i=0;i<p.length;i++) p[i].leer(); //Impresión de datos System.out.println("Datos de las personas: "); for (i=0;i<p.length;i++) { System.out.println("Persona No. "+i); p[i].escribir(); sueldos+=p[i].obtener_sueldo(); } //Imprime el promedio de los sueldos prom=sueldos/p.length; System.out.println("El promedio es: "+prom); } }

PROGRAMACION CON JAVA 2 199

4.12. VARIABLES DE CLASE (VARIABLE ESTÁTICA)

En nuestra definición de la clase Circulo hemos decla-rado 3 variables de instancias (x, y, r). Variable de instancia significa que cada clase (cada círculo) tie-ne su propia copia de esas 3 variables. Pero hay veces que necesitamos una variable de la cual haya una sola copia, algo así como una variable global.

El problema es que Java no soporta variables globales (A modo de comentario, esto no se considera un proble-ma sino una ventaja). Cada variable en Java debe de-clararse dentro de una clase. Así que Java utiliza la palabra clave static para indicar que una variable particular es una variable de clase en lugar de una variable de instancia. Las variables de clase existen independientemente del número de instancias creadas de la clase, existen y pueden usarse inclusive si la cla-se nunca se inicializó.

Este tipo de variable, declarada con la palabra clave static se llama a menudo variable estática. Pero es preferible, y de ahora en adelante lo vamos a hacer así, llamarlas variables de clase, porque de esta ma-nera es fácilmente distinguible de su opuesta, varia-bles de instancia.

200 Mg. ABRAHAM GAMARRA MORENO

Ejemplo: Ejemplo de uso variable estática

public class Circulo2 { static int numCirculos = 0; //variable de clase: contador de círculos creados public double x, y, r; //variable de instancia: centro y radio del circulo // Constructores public Circulo2 (double x, double y, double r) { this.x = x; this.y = y; this.r = r; numCirculos++; } public Circulo2 (double r) { this (0.0, 0.0, r); } public Circulo2 (Circulo2 c) { this (c.x, c.y, c.r); } public Circulo2 () { this (0.0, 0.0, 1.0); } //Métodos public double circunferencia() { return 2*3.14159*r; } public double area() { return 3.14159*r*r; } }

4.12.1. ACCEDIENDO A LAS VARIABLES DE CLASE

Ahora que sabemos el número de objetos Circu-lo creados, ¿cómo podemos acceder a esa in-formación? Porque las variables de clase es-tán asociadas con la clase antes que con una instancia, accedemos a ellas a través de la clase. Por lo tanto, debemos escribir:

PROGRAMACION CON JAVA 2 201

System.out.println ("Número de círculos creados: " + Circulo2.numCirculos);

Podemos notar que en uno de los constructores usamos la variable escribiendo numCirculos, en lugar de Circulo.numCirculos. Podemos hacer esto dentro de la definición de la mis-ma clase.

Ejemplo(52): Programa completo de la clase Circulo2

//Archivo Circulo2.java

public class Circulo2 { static int numCirculos = 0; //variable de clase: contador de círculos creados public double x, y, r; //variable de instancia: centro y radio del circulo // Constructores public Circulo2 (double x, double y, double r) { this.x = x; this.y = y; this.r = r; numCirculos++; } public Circulo2 (double r) { this (0.0, 0.0, r); } public Circulo2 (Circulo2 c) { this (c.x, c.y, c.r); } public Circulo2 () { this (0.0, 0.0, 1.0); } //Métodos public double circunferencia() { return 2*3.14159*r; } public double area() { return 3.14159*r*r; } }

202 Mg. ABRAHAM GAMARRA MORENO

// Archivo Circulo2App.java

import java.io.*; class Circulo2App { public static void main (String[] args) throws IOException { Circulo2 c1=new Circulo2(); System.out.print("Circunferencia del circulo 1: "); System.out.println(c1.circunferencia()); System.out.print("Area del circulo 1: "); System.out.println(c1.area()); Circulo2 c2=new Circulo2(2,5,100); System.out.print("Circunferencia del circulo 2: "); System.out.println(c2.circunferencia()); System.out.print("Area del circulo 2: "); System.out.println(c2.area()); Circulo2 c3=new Circulo2(10); System.out.print("Circunferencia del circulo 3: "); System.out.println(c3.circunferencia()); System.out.print("Area del circulo 3: "); System.out.println(c3.area()); System.out.print("El numero de circulos creados es: "); System.out.println( Circulo2.numCirculos); } }

4.13. Y LAS VARIABLES GLOBALES ??? Java no soporta variables globales, aunque Circulo.numCirculos se comporta como si lo fuera. La diferencia con el lenguaje C es que aquí no hay posibilidad de conflictos de nombres. Si usamos otra clase con una variable de clase llamada numCirculos, no hay colisión porque ambas deben ser referenciadas por sus nombres de clases.

PROGRAMACION CON JAVA 2 203

4.14. CONSTANTES: OTRO EJEMPLO DE VARIABLES DE CLASE

Intentemos un ejemplo un poco más complicado. Cuando calculamos el área y la circunferencia usamos el valor de π. Dado que usamos ese valor con frecuencia, no queremos tipear 3.14159 cada vez que lo usamos, por lo que podemos ponerlo en una variable.

public class Circulo { public static final double PI = 3.14159265358979323846; public double x, y, r; // etc... }

Además del uso de static, el cual ya lo hemos visto, en el ejemplo usamos la palabra clave final, la cual significa que la variable no puede cambiar su valor. Esto previene de hacer una estupidez, como la siguien-te:

Circulo.PI = 4;

El compilador Java es hábil respecto de las variables declaradas static y final, ya que sabe que tienen va-lores constantes. Por lo que cuando escribimos código como el siguiente:

double circunferencia = 2 * Circulo.PI * radio;

el compilador precalcula el valor 2 * Circulo.PI, en lugar de dejarlo para el intérprete.

4.15. EJEMPLOS DE VARIABLES DE CLASE

Ejemplo(53): Realice un programa que calcule el total de la compra de 3 libros. Debe tener en cuenta lo si-guiente:

• Utilizar la clase libro que tiene los datos miem-bro titulo, autor y precio. Además la clase li-bro tiene los métodos: void leer_datos ( ), y void escribir_total_compra ( ). El método void leer_datos ( ) permite leer los datos miembros de los libros y la vez calcula el total de la com-pra. El método void escribir_total_compra ( )

204 Mg. ABRAHAM GAMARRA MORENO

permite escribir el total de la compra para los tres libros. (5 PTOS)

• Debe utilizar variables de clase (variables está-ticas), las que usted considere conveniente, para almacenar la cantidad de libros comprados, así como para calcular el total de la compra.(5 PTOS).

//archivo: Libro.java

import java.io.*; class Libro { //variables de clase static int cantidad; static float total=0; //datos miembro private String titulo; private float precio; //funciones miembro public void leer_datos() { try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStream-Reader(System.in); BufferedReader flujoE = new BufferedReader(isr); String sdato; // variable para almacenar una línea de texto //lectura System.out.print("Introduzca titulo: ");

PROGRAMACION CON JAVA 2 205

titulo = flujoE.readLine(); // leer una línea de texto System.out.print("Introduzca precio: "); sdato = flujoE.readLine(); // leer una línea de texto precio=Float.parseFloat(sdato);//convierte cadena System.out.print("Cantidad de libros a comprar: "); sdato = flujoE.readLine(); // leer una línea de texto cantidad=Integer.parseInt(sdato);//convierte cadena } catch (IOException ignorada) {} total=total+precio*cantidad; }//fin leer public void escribir_total_compra() { System.out.println("El total de la compra es: "+total); }//fin escribir_total_compra } // Archivo LibroAppl.java class LibroAppl { public static void main (String[] args) { //Creación de los objetos libro: li1,li2,li3 Libro li1=new Libro(); Libro li2=new Libro(); Libro li3=new Libro(); System.out.println("Ingrese datos del primer libro"); li1.leer_datos(); System.out.println("Ingrese datos del segundo libro"); li2.leer_datos(); System.out.println("Ingrese datos del tercer libro"); li3.leer_datos(); //escribe el total //puede utilizar cualquiera de los objetos li1.escribir_total_compra(); } }

206 Mg. ABRAHAM GAMARRA MORENO

4.16. MÉTODOS DE CLASE (MÉTODOS ESTÁTICOS) El uso de Math.sqrt(4), permite encontrar la raiz cua-drada de 4; lo que está pasando aquí es que Math es el nombre de una clase, sqrt() es el nombre de un método de clase (método estático) definido en Math, a dife-rencia con los métodos de instancia, tales como area() y circunferencia() en la clase Circulo, que son los que hemos visto ahora.

Características:

• Los métodos de clase se declaran con la palabra clave static.

• A los métodos de clase los podemos ver también como métodos estáticos.

• Los métodos de clase se invocan a través de la clase en lugar de una instancia (objeto).

• Los métodos de clase son lo más parecido a méto-dos globales. Como a ellos se hacen referencia a través de la clase, no hay peligro de conflicto de nombres.

4.16.1. SIN THIS

Los métodos de clases difieren de los métodos de instancias en un punto importante: no pa-san la referencia implícita this. De esta ma-nera, los métodos sin this no están asociados con ninguna instancia de la clase y no pueden hacer referencia a ninguna variable de ins-tancia o invocar métodos de instancia.

4.16.2. UN MÉTODO DE CLASE PARA Circulo

El siguiente ejemplo, muestra dos definicio-nes de un método para nuestra clase Circulo. Una es un método de instancia y la otra es un método de clase.

Ejemplo: Un método de clase y un método de instancia

PROGRAMACION CON JAVA 2 207

public class Circulo3 { public double x, y, r; //.... //MÉTODO DE INSTANCIA. DEVUELVE EL MAYOR DE LOS DOS CÍRCULOS public Circulo3 elMayor (Circulo3 c) { if (c.r > r) return c; else return this; } //MÉTODO DE CLASE. DEVUELVE EL MAYOR DE LOS DOS CÍRCULOS public static Circulo3 elMayor (Circulo3 a, Circulo3 b) { if (a.r > b.r) return a; else return b; } //.... }

Podemos invocar el método de instancia de la siguiente manera:

Circulo3 a = new Circulo3 (2.0); Circulo3 b = new Circulo3 (3.0); Circulo3 c = a.elMayor(b);

y el método de clase así:

Circulo3 a = new Circulo3 (2.0); Circulo3 b = new Circulo3 (3.0); Circulo3 d = Circulo3.elMayor(a,b);

Ejemplo(54): Programa completo de la clase Circulo3

//archivo: Circulo3.java

public class Circulo3 { //variable de instancia: centro y radio del circulo private double x, y, r; // Constructores Circulo3 (double x, double y, double r) { this.x = x; this.y = y; this.r = r; }

208 Mg. ABRAHAM GAMARRA MORENO

Circulo3 (double r) { this (0.0, 0.0, r); } public void escribir() { System.out.println("x= "+x+" y= "+y+" r= "+r); } //Métodos: //MÉTODO DE INSTANCIA. DEVUELVE EL MAYOR DE LOS DOS CÍRCULOS public Circulo3 elMayor (Circulo3 c) { if (c.r > r) return c; else return this; } //MÉTODO DE CLASE. DEVUELVE EL MAYOR DE LOS DOS CÍRCULOS public static Circulo3 elMayor (Circulo3 a, Circulo3 b) { if (a.r > b.r) return a; else return b; } }

// Archivo Circulo3App.java

import java.io.*; class Circulo3App { public static void main (String[] args) throws IOException { Circulo3 a=new Circulo3(50); System.out.println("primer circulo:"); a.escribir(); Circulo3 b=new Circulo3(100); System.out.println("segundo circulo:"); b.escribir(); System.out.println("Utilizando el metodo de instancia se tiene:"); Circulo3 c = a.elMayor(b); System.out.println("Circulo mayor:"); c.escribir();

PROGRAMACION CON JAVA 2 209

System.out.println("Utilizando el metodo de clase se tie-ne:"); Circulo3 d = Circulo3.elMayor(a,b); System.out.println("Circulo mayor:"); c.escribir(); } }

Ejemplo(55): Programa que utiliza métodos estaticos para calcular la matriz inversa.

Solución:

La inversa de una matriz dada es otra matriz tal que multiplicada a la derecha o a la izquierda por la ma-triz dada, da la matriz unidad. Veamos como se obtiene la matriz inversa de una matriz 4 x 4, y luego genera-lizaremos para una matriz cuadrada de dimensión n.

El producto de las dos matrices da lugar a los si-guientes sistemas de cuatro ecuaciones con cuatro in-cógnitas. Los términos independientes bij son todos ceros excepto los de la diagonal principal b00=b11=b22=b33=1.

Primera columna:

210 Mg. ABRAHAM GAMARRA MORENO

Segunda columna:

Tercera columna

Cuarta columna

Para el cálculo de la matriz inversa, deberemos trans-formar la matriz a, los términos independientes b (ca-da una de las columnas de la matriz unidad), y calcu-lar las n2 incógnitas x.

La matriz de los términos independientes b es la ma-triz unidad, cuyos elementos son todos cero, excepto los de la diagonal principal que son unos.

for(int i=0; i<n; i++){ b[i][i]=1.0; }

PROGRAMACION CON JAVA 2 211

El código de la transformación de los elementos de la matriz es el mismo que nos sirvió para calcular el determinante de una matriz cuadrada. Le añadimos el código de la transformación de los términos

independientes ( a la derecha en las fórmulas que siguen) para cada uno de los cuatro sistemas de ecuaciones s=0, 1, 2, 3

k=0

k=1

k=2

for(int k=0; k<n-1; k++){ for(int i=k+1; i<n; i++){ //términos independientes for(int s=0; s<n; s++){ b[i][s]-=a[i][k]*b[k][s]/a[k][k]; } //elementos de la matriz for(int j=k+1; j<n; j++){ a[i][j]-=a[i][k]*a[k][j]/a[k][k]; } } }

Una vez realizadas las transformaciones, se calcula las n2 incógnitas x en orden inverso y las guardamos en la matriz c . Primero, la última incógnita y luego todas las n-1 restantes. De nuevo, el índice s repre-senta la columna de la matriz b de los términos inde-pendientes, y de la matriz c de las incógnitas.

212 Mg. ABRAHAM GAMARRA MORENO

for(int s=0; s<n; s++){ c[n-1][s]=b[n-1][s]/a[n-1][n-1]; for(int i=n-2; i>=0; i--){ c[i][s]=b[i][s]/a[i][i]; for(int k=n-1; k>i; k--){ c[i][s]-=a[i][k]*c[k][s]/a[i][i]; } } }

Si queremos mantener la matriz original d, hacemos una copia a de dicha matriz en el cuerpo de la función in-versa y realizamos las operaciones con la matriz copia dejando la original sin modificar.

double [][] a=d;

El código completo de esta función estática inversa que halla la matriz inversa de una matriz cuadrada es el siguiente.

Archivo Matriz.java

class Matriz { public static double [][] inversa(double d[][]) { int n=d.length; //dimensión de la matriz double [][] a=d; //La matriz a es una copia de d double [][] b=new double [n][n]; //matriz de los términos independientes double [][] c=new double [n][n]; //matriz de las incógnitas //matriz unidad for(int i=0; i<n; i++) { b[i][i]=1.0; } //transformación de la matriz y de los términos independientes for(int k=0; k<n-1; k++) { for(int i=k+1; i<n; i++) { //términos independientes for(int s=0; s<n; s++) { b[i][s]-=a[i][k]*b[k][s]/a[k][k]; }

PROGRAMACION CON JAVA 2 213

//elementos de la matriz for(int j=k+1; j<n; j++) { a[i][j]-=a[i][k]*a[k][j]/a[k][k]; } } } //cálculo de las incógnitas, elementos de la matriz inversa for(int s=0; s<n; s++) { c[n-1][s]=b[n-1][s]/a[n-1][n-1]; for(int i=n-2; i>=0; i--) { c[i][s]=b[i][s]/a[i][i]; for(int k=n-1; k>i; k--) { c[i][s]-=a[i][k]*c[k][s]/a[i][i]; } } } return c; } public static void mostrar(double m[][]) { System.out.println("\n\n"); for (int i=0; i < m.length; i++) { for (int j=0; j <m[i].length; j++) { System.out.print(m[i][j]+"\t"); } System.out.println(""); } System.out.println("\n\n"); } } Archivo MatrizAppl.java

class MatrizAppl { public static void main (String[] args) { double [][] m={{2,1,-3}, {-1,3,2}, {3,1,-3} }; double [][] m1= new double [3][3];

214 Mg. ABRAHAM GAMARRA MORENO

System.out.println("Matriz original"); Matriz.mostrar(m); System.out.println("Matriz inversa"); m1=Matriz.inversa(m); Matriz.mostrar(m1); } }

4.17. DESTRUCCIÓN DE LOS OBJETOS Ahora que ya hemos visto como crear y usar objetos, la pregunta obvia es: ¿cómo destruirlos?. La respuesta es: no hay que destruirlos. En Java no existe un méto-do destructor como en C++, acá Java se encarga de la destrucción de los objetos por nosotros, y nos permite concentrarnos en otras cosas más importantes, como el algoritmo en el que estemos trabajando.

4.17.1. EL RECOLECTOR DE BASURA (GARBAGE CO-LLECTOR)

La técnica que usa Java para deshacerse de los objetos una vez que ellos no se necesitan más es llamada garbage collection. El intér-prete Java conoce qué objetos tiene almacena-do. También puede resolver cuáles variables

PROGRAMACION CON JAVA 2 215

refieren a cuáles objetos y cuáles objetos refieren a otros objetos. De esta manera, puede resolver cuando un objeto almacenado ya no es referenciado por ningún objeto ni por ninguna variable. Cuando encuentra un objeto en esta situación, el garbage collector sabe que puede destruirlo, y lo hace. El garbage collector también puede detectar y destruir ciclos de objetos que refieren a cada uno, pero que no son referenciados por ningún otro objeto.

El garbage collector corre en un hilo (thread) de baja prioridad, y hace la mayoría de su trabajo cuando no se está ejecutando nada. Generalmente corre cuando el procesador se encuentra inactivo, por ejemplo esperando una entrada por teclado del usuario o un evento con el mouse. Pero hay un momento en que puede llegar a correr con alta prioridad, y haciendo caer un poco al sistema en grandes aplicaciones, y es cuando el intérprete se empieza a quedar sin memoria. Cabe aclarar que esto no ocurre seguido, ya que como el garbage collector se está ejecutando en un thread de baja prioridad ya viene recuperando memoria.

Todo este esquema si bien puede parecer algo pesado y poco económico, podemos asegurar que no lo es. Un buen garbage collector puede ser sorprendentemente eficiente.

4.18. LA REFERENCIA null En nuestras referencias a objetos, podemos tener el valor null. Este valor indica que no estamos apuntando a ningún objeto. El valor null puede ser devuelto por métodos que devuelvan referencias a objetos, para in-dicar que no existe el objeto requerido. Podemos pre-guntar si una referencia a un objeto es igual o dis-tinta a null, por ejemplo:

Circulo c = new Circulo(); if ( c != null ) System.out.println("El Circulo 'c' existe !"); Circulo b=null; // b referencia a null

216 Mg. ABRAHAM GAMARRA MORENO

if ( b == null ) System.out.println("El Circulo 'b' NO existe !");

El valor null puede asignarse a cualquier variable de referencia a objetos o arrays. Si una variable hace referencia a un objeto y luego le asignamos el valor null, lo que estamos haciendo es eliminar la referen-cia al objeto (esta variable ahora referencia a null), pero no el objeto en sí, por lo menos no directamente, de esto se encargará el garbage collector (recolector de basura). Si intentamos acceder a un miembro (atri-buto o método) con esa variable, el sistema de runtime lanzará una NullPointerException, ya que nuestra va-riable referencia a null. Por ejemplo

Circulo d = new Circulo(5); // Creamos un nuevo objeto Circulo System.out.println(d.area()); // mostramos su area d=null; // eliminamos la referencia al objeto Circulo d.circunferencia(); // Se lanza una NullPointerException // debido a que 'd' ya NO referencia // al objeto Circulo

PROGRAMACION CON JAVA 2 217

4.19. HERENCIA La herencia es una propiedad esencial de la Programa-ción Orientada a Objetos que consiste en la creación de nuevas clases a partir de otras ya existentes. Este término ha sido prestado de la Biología donde afirma-mos que un niño tiene la cara de su padre, que ha heredado ciertas facetas físicas o del comportamiento de sus progenitores.

La herencia es la característica fundamental que dis-tingue un lenguaje orientado a objetos, como el C++ o Java, de otro convencional como C, BASIC, etc. Java permite heredar a las clases características y conduc-tas de una o varias clases denominadas base. Las cla-ses que heredan de clases base se denominan derivadas, estas a su vez pueden ser clases bases para otras cla-ses derivadas. Se establece así una clasificación je-rárquica, similar a la existente en Biología con los animales y las plantas.

218 Mg. ABRAHAM GAMARRA MORENO

La herencia permite crear una clase (clase derivada) a partir de otras ya existentes, y ésta tendrá todos los atributos y los métodos de su 'superclase' (clase ba-se), y además se le podrán añadir otros atributos y métodos propios.

Se llama 'Superclase' (clase base) a la clase de la que desciende una clase.

Los objetos se definen en términos de clases. Se puede saber mucho acerca de un objeto conociendo su clase. Por ejemplo, aunque el nombre Tucker pueda no ser sig-nificativo, si se dice que Tucker fue un automóvil in-mediatamente sabremos varias de sus características, como ser que consta de cuatro ruedas, tiene un volan-te, tiene transmisión, etc.

Los sistemas orientados a objetos permiten que las clases se definan en términos de otras clases. Por ejemplo, camionetas, autos de carrera y autos de ca-lle, son diferentes clases de automóviles. En la ter-minología orientada a objetos, las camionetas, los au-tos de carrera y los autos de calle son subclases de la clase automóviles. De la misma manera la clase au-tomóviles es la superclase de las clases camionetas, autos de carrera y autos de calle.

Automóviles

Autos de carrera

Camionetas Autos de calle

PROGRAMACION CON JAVA 2 219

Cada subclase hereda el estado (en la forma de decla-ración de atributos) de la superclase. Las camionetas, los autos de carrera y los autos de calle comparten algunos de esos estados: tipo de ruedas, color del chasis, velocidad máxima, velocidad actual, cantidad de marchas, etc.

Cada subclase también hereda los métodos de su super-clase. Las camionetas, los autos de carrera y los au-tos de calle comparten algunos de los comportamientos: cambiarDeMarcha, acelerar, frenar, etc..

Sin embargo, las subclases (clase derivada) no están limitadas a los estados y comportamientos heredados de la superclase (clase base). Las subclases pueden agre-gar atributos y métodos a los heredados de la super-clase. Por ejemplo, las Camionetas pueden tener cúpu-las, los AutosDeCarreras pueden tener una marcha más y los AutosDeCalle pueden ser cupés.

Las subclases también pueden redefinir métodos hereda-dos y proveer implementaciones especializadas para esos métodos. Por ejemplo, si AutosDeCarrera posee una marcha más se puede redefinir el método cambiarDeMar-cha para que el corredor pueda utilizar ese cambio ex-tra.

No se está limitado a una sola capa de herencia. El árbol de herencia, o jerarquía de clases, puede ser tan profundo como sea necesario. Los métodos y los atributos se heredan bajando los niveles. En general, las clases que aparecen más abajo en la jerarquía de clases, poseen un comportamiento más especializado.

La herencia ofrece una ventaja importante, permite la reutilización del código. Una vez que una clase ha si-do depurada y probada, el código fuente de dicha clase no necesita modificarse. Su funcionalidad se puede cambiar derivando una nueva clase que herede la fun-cionalidad de la clase base y le añada otros comporta-mientos. Reutilizando el código existente, el progra-mador ahorra tiempo y dinero, ya que solamente tiene que verificar la nueva conducta que proporciona la clase derivada.

La programación en los entornos gráficos, en particu-lar Windows, con el lenguaje C++, es un ejemplo ilus-trativo. Los compiladores como los de Borland y Micro-soft proporcionan librerías cuyas clases describen el

220 Mg. ABRAHAM GAMARRA MORENO

aspecto y la conducta de las ventanas, controles, me-nús, etc. Una de estas clases denominada TWindow des-cribe el aspecto y la conducta de una ventana, tiene una función miembro denominada Paint, que no dibuja nada en el área de trabajo de la misma. Definiendo una clase derivada de TWindow, podemos redefinir en ella la función Paint para que dibuje una figura. Aprove-chamos de este modo la ingente cantidad y complejidad del código necesario para crear una ventana en un en-torno gráfico. Solamente, tendremos que añadir en la clase derivada el código necesario para dibujar un rectángulo, una elipse, etc.

En el lenguaje Java, todas las clases derivan implíci-tamente de la clase base Object, por lo que heredan las funciones miembro definidas en dicha clase. Las clases derivadas pueden redefinir algunas de estas funciones miembro como toString y definir otras nue-vas.

Para crear un applet, solamente tenemos que definir una clase derivada de la clase base Applet, redefinir ciertas funciones como init o paint, o definir otras como las respuestas a las acciones sobre los contro-les.

Los programadores crean clases base:

• Cuando se dan cuenta que diversos tipos tienen algo en común, por ejemplo en el juego del aje-drez peones, alfiles, rey, reina, caballos y to-rres, son piezas del juego. Creamos, por tanto, una clase base y derivamos cada pieza individual a partir de dicha clase base.

• Cuando se precisa ampliar la funcionalidad de un programa sin tener que modificar el código exis-tente.

4.19.1. LA CLASE BASE

Vamos a poner un ejemplo del segundo tipo, que simule la utilización de liberías de cla-ses para crear un interfaz gráfico de usuario como Windows 3.1 o Windows 95.

PROGRAMACION CON JAVA 2 221

Supongamos que tenemos una clase que describe la conducta de una ventana muy simple, aque-lla que no dispone de título en la parte su-perior, por tanto no puede desplazarse, pero si cambiar de tamaño actuando con el ratón en los bordes derecho e inferior.

La clase Ventana tendrá los siguientes miem-bros dato: la posición x e y de la ventana, de su esquina superior izquierda y las dimen-siones de la ventana: ancho y alto.

class Ventana { protected int x; protected int y; protected int ancho; protected int alto; public Ventana(int x, int y, int ancho, int alto) { this.x=x; this.y=y; this.ancho=ancho; this.alto=alto; } //... }

Las funciones miembros, además del construc-tor serán las siguientes: la función mostrar que simula una ventana en un entorno gráfico, aquí solamente nos muestra la posición y las dimensiones de la ventana.

public void mostrar() { System.out.println("posición : x="+x+", y="+y); System.out.println("dimensiones : w="+ancho+", h="+alto); }

La función cambiarDimensiones que simula el cambio en la anchura y altura de la ventana.

public void cambiarDimensiones(int dw, int dh){ ancho+=dw; alto+=dh; }

El código completo de la clase base Ventana, es el siguiente

222 Mg. ABRAHAM GAMARRA MORENO

class Ventana { protected int x; protected int y; protected int ancho; protected int alto; public Ventana(int x, int y, int ancho, int alto) { this.x=x; this.y=y; this.ancho=ancho; this.alto=alto; } public void mostrar(){ System.out.println("posición : x="+x+", y="+y); System.out.println("dimensiones : w="+ancho+", h="+alto); } public void cambiarDimensiones(int dw, int dh){ ancho+=dw; alto+=dh; } }

4.19.2. OBJETOS DE LA CLASE BASE

Como vemos en el código, el constructor de la clase base inicializa los cuatro miembros da-to. Llamamos al constructor creando un objeto de la clase Ventana

Ventana ventana=new Ventana(0, 0, 20, 30);

Desde el objeto ventana podemos llamar a las funciones miembro públicas

ventana.mostrar();

ventana.cambiarDimensiones(10, 10);

ventana.mostrar();

PROGRAMACION CON JAVA 2 223

4.19.3. LA CLASE DERIVADA

Incrementamos la funcionalidad de la clase Ventana definiendo una clase derivada denomi-nada VentanaTitulo. Los objetos de dicha cla-se tendrán todas las características de los objetos de la clase base, pero además tendrán un título, y se podran desplazar (se simula el desplazamiento de una ventana con el ra-tón).

La clase derivada heredará los miembros dato de la clase base y las funciones miembro, y tendrá un miembro dato más, el título de la ventana.

class VentanaTitulo extends Ventana { protected String titulo; public VentanaTitulo(int x, int y, int w, int h, String nombre) { super(x, y, w, h); titulo=nombre; }

extends es la palabra reservada que indica que la clase VentanaTitulo deriva, o es una subclase (clase derivada), de la clase Venta-na.

La primera sentencia del constructor de la clase derivada es una llamada al constructor de la clase base mediante la palabra reserva-da super. La llamada

super(x, y, w, h);

inicializa los cuatro miembros dato de la clase base Ventana: x, y, ancho, alto. A con-tinuación, se inicializa los miembros dato de la clase derivada, y se realizan las tareas

224 Mg. ABRAHAM GAMARRA MORENO

de inicialización que sean necesarias. Si no se llama explícitamente al constructor de la clase base Java lo realiza por nosotros, lla-mando al constructor por defecto si existe.

La función miembro denominada desplazar cam-bia la posición de la ventana, añadiéndoles el desplazamiento.

public void desplazar(int dx, int dy) { x+=dx; y+=dy; }

Redefine la función miembro mostrar para mos-trar una ventana con un título.

public void mostrar() { super.mostrar(); System.out.println("titulo : "+titulo); }

En la clase derivada se define una función que tiene el mismo nombre y los mismos pará-metros que la de la clase base. Se dice que redefinimos la función mostrar en la clase derivada. La función miembro mostrar de la clase derivada VentanaTitulo hace una llamada a la función mostrar de la clase base Venta-na, mediante

super.mostrar();

De este modo aprovechamos el código ya escri-to, y le añadimos el código que describe la nueva funcionalidad de la ventana por ejem-plo, que muestre el título.

Si nos olvidamos de poner la palabra reserva-da super llamando a la función mostrar, ten-dríamos una función recursiva. La función mostrar llamaría a mostrar indefinidamente.

public void mostrar() { //¡ojo!, función recursiva System.out.println("titulo : "+titulo); mostrar(); }

PROGRAMACION CON JAVA 2 225

La definición de la clase derivada VentanaTitulo, será la siguiente.

class VentanaTitulo extends Ventana { protected String titulo; public VentanaTitulo(int x, int y, int w, int h, String nombre) { super(x, y, w, h); titulo=nombre; } public void mostrar(){ super.mostrar(); System.out.println("titulo : "+titulo); } public void desplazar(int dx, int dy){ x+=dx; y+=dy; } }

4.19.4. OBJETOS DE LA CLASE DERIVADA

Creamos un objeto ventana de la clase deriva-da VentanaTitulo

VentanaTitulo ventana=new VentanaTitulo(0, 0, 20, 30, "Principal");

Mostramos la ventana con su título, llamando a la función mostrar, redefinida en la clase derivada

ventana.mostrar();

Desde el objeto ventana de la clase derivada llamamos a las funciones miembro definidas en dicha clase

ventana.desplazar(4, 3);

Desde el objeto ventana de la clase derivada podemos llamar a las funciones miembro defi-nidas en la clase base.

ventana.cambiarDimensiones(10, -5);

Para mostrar la nueva ventana desplazada y cambiada de tamaño escribimos

ventana.mostrar();

226 Mg. ABRAHAM GAMARRA MORENO

Ejemplo ( 56): Programa completo de la clase base Ventana y su clase derivada.

//Archivo: Ventana.java

class Ventana { protected int x; protected int y; protected int ancho; protected int alto; public Ventana(int x, int y, int ancho, int alto) { this.x=x; this.y=y; this.ancho=ancho; this.alto=alto; } public void mostrar() { System.out.println("posicion : x="+x+", y="+y); System.out.println("dimensiones : w="+ancho+", h="+alto); } public void cambiarDimensiones(int dw, int dh) { ancho+=dw; alto+=dh; } }

//Archivo: VentanaTitulo.java

class VentanaTitulo extends Ventana { protected String titulo; public VentanaTitulo(int x, int y, int w, int h, String nombre) { super(x, y, w, h); titulo=nombre; } public void mostrar() { System.out.println("titulo : "+titulo); super.mostrar(); } public void desplazar(int dx, int dy) { x+=dx; y+=dy;

PROGRAMACION CON JAVA 2 227

} }

//Archivo: VentanaApp.java

class VentanaApp { public static void main(String[] args) { VentanaTitulo ventana=new VentanaTitulo(0, 0, 20, 30, "Principal"); ventana.mostrar(); ventana.cambiarDimensiones(10, -5); ventana.desplazar(4, 3); System.out.println("************************"); ventana.mostrar(); } }

4.20. MODIFICADORES DE ACCESO Y HERENCIA Como hemos visto anteriormente, existen los modificadores de acceso public, private y así como el control de acceso por defecto a nivel de paquete, cuando no se especifica nada. En la herencia, surge un nuevo control de acceso denominado protected.

Hemos puesto protected delante de los miembros dato x e y de la clase base Ventana

class Ventana { protected int x; protected int y; //... }

228 Mg. ABRAHAM GAMARRA MORENO

En la clase derivada la función miembro desplazar ac-cede a dichos miembros dato

class VentanaTitulo extends Ventana { //... public void desplazar(int dx, int dy){ x+=dx; y+=dy; } } Si cambiamos el modificador de acceso de los miembros x e y de la clase base Ventana de protected a private, veremos que el compilador se queja diciendo que los miembro x e y no son accesibles.

Los miembros ancho y alto se pueden poner con acceso private sin embargo, es mejor dejarlos como protected ya que podrían ser utilizados por alguna función miem-bro de otra clase derivada de VentanaTitulo. Dentro de una jerarquía pondremos un miembro con acceso private, si estamos seguros de que dicho miembro solamente va a ser usado por dicha clase.

Como vemos hay cuatro modificadores de acceso a los miembros dato y a los métodos (funciones): private, protected, public y default (por defecto, o en ausen-cia de cualquier modificador). La herencia complica aún más el problema de acceso, ya que las clases dentro del mismo paquete tienen diferentes accesos que las clases de distinto paquete

Los siguientes cuadros tratan de aclarar este problema

Clases dentro del mismo paquete Modificador de acceso Heredado Accesible

Por defecto (sin modificador) Si Si

Private No No Protected Si Si Public Si Si

PROGRAMACION CON JAVA 2 229

Clases en distintos paquetes Modificador de acceso Heredado Accesible

Por defecto (sin modificador) No No

Private No No Protected Si No Public Si Si

Desde el punto de vista práctico, cabe reseñar que no se heredan los miembros privados, ni aquellos miembros (dato o función) cuyo nombre sea el mismo en la clase base y en la clase derivada.

4.21. LA JERARQUÍA DE CLASES QUE DESCRIBEN LAS FIGURAS PLANAS

Consideremos las figuras planas cerradas como el rec-tángulo, y el círculo. Tales figuras comparten carac-terísticas comunes como es la posición de la figura, de su centro, y el área de la figura, aunque el proce-dimiento para calcular dicha área sea completamente distinto. Podemos por tanto, diseñar una jerarquía de clases, tal que la clase base denominada Figura, tenga las características comunes y cada clase derivada las específicas. La relación jerárquica se muestra en la figura

La clase Figura es la que contiene las características comunes a dichas figuras concretas por tanto, no tiene forma ni tiene área. Esto lo expresamos declarando Fi-gura como una clase abstracta, declarando la función miembro area abstract.

230 Mg. ABRAHAM GAMARRA MORENO

Las clases abstractas solamente se pueden usar como clases base para otras clases. No se pueden crear ob-jetos pertenecientes a una clase abstracta. Sin embar-go, se pueden declarar variables de dichas clases.

En el juego del ajedrez podemos definir una clase base denominada Pieza, con las características comunes a todas las piezas, como es su posición en el tablero, y derivar de ella las características específicas de ca-da pieza particular. Así pues, la clase Pieza será una clase abstracta con una función abstract denominada mover, y cada tipo de pieza definirá dicha función de acuerdo a las reglas de su movimiento sobre el table-ro.

4.21.1. LA CLASE Figura

La definición de la clase abstracta Figura, contiene la posición x e y de la figura par-ticular, de su centro, y la función area, que se va a definir en las clases derivadas para calcular el área de cada figura en particu-lar.

abstract class Figura { protected int x; protected int y; public Figura(int x, int y) { this.x=x; this.y=y; } public abstract double area(); } 4.21.2. LA CLASE Rectangulo

Las clases derivadas heredan los miembros da-to x e y de la clase base, y definen la fun-ción area, declarada abstract en la clase ba-se Figura, ya que cada figura particular tie-ne una fórmula distinta para calcular su área. Por ejemplo, la clase derivada Rectan-gulo, tiene como datos, aparte de su posición (x, y) en el plano, sus dimensiones, es de-cir, su anchura ancho y altura alto.

class Rectangulo extends Figura { protected double ancho, alto; public Rectangulo(int x, int y, double ancho, double alto)

PROGRAMACION CON JAVA 2 231

{ super(x,y); this.ancho=ancho; this.alto=alto; } public double area() { return ancho*alto; } }

La primera sentencia en el constructor de la clase derivada es una llamada al constructor de la clase base, para ello se emplea la pa-labra reservada super. El constructor de la clase derivada llama al constructor de la clase base y le pasa las coordenadas del pun-to x e y. Después inicializa sus miembros da-to ancho y alto.

En la definición de la función area, se cal-cula el área del rectángulo como producto de la anchura por la altura, y se devuelve el resultado

4.21.3. LA CLASE Circulo

A contiuación se muestra la clase Circulo

class Circulo extends Figura { protected double radio; public Circulo(int x, int y, double radio) { super(x,y); this.radio=radio; } public double area() { return Math.PI*radio*radio; } }

Como vemos, la primera sentencia en el cons-tructor de la clase derivada es una llamada al constructor de la clase base empleando la palabra reservada super. Posteriormente, se inicializa el miembro dato radio, de la clase derivada Circulo.

En la definición de la función area, se cal-cula el área del círculo mediante la conocida fórmula π∗r2, o bien π*r*r. La constante

232 Mg. ABRAHAM GAMARRA MORENO

Math.PI es una aproximación decimal del núme-ro irracional π.

4.22. USO DE LA JERARQUÍA DE CLASES Creamos un objeto c de la clase Circulo situado en el punto (0, 0) y de 5.5 unidades de radio. Calculamos y mostramos el valor de su área.

Circulo c=new Circulo(0, 0, 5.5);

System.out.println("Area del círculo "+c.area());

Creamos un objeto r de la clase Rectangulo situado en el punto (0, 0) y de dimensiones 5.5 de anchura y 2 unidades de largo. Calculamos y mostramos el valor de su área.

Rectangulo r=new Rectangulo(0, 0, 5.5, 2.0);

System.out.println("Area del rectángulo "+r.area());

Veamos ahora, una forma alternativa, guardamos el va-lor devuelto por new al crear objetos de las clases derivadas en una variable f del tipo Figura (clase ba-se).

Figura f=new Circulo(0, 0, 5.5);

System.out.println("Area del círculo "+f.area());

f=new Rectangulo(0, 0, 5.5, 2.0);

System.out.println("Area del rectángulo "+f.area());

4.23. ENLACE DINÁMICO En el lenguaje C, los identificadores de la función están asociados siempre a direcciones físicas antes de la ejecución del programa, esto se conoce como enlace temprano o estático. Ahora bien, el lenguaje C++ y Ja-va permiten decidir a que función llamar en tiempo de ejecución, esto se conoce como enlace tardío o dinámi-co. Las 4 líneas de código anterior muestran el uso del enlace dinámico.

PROGRAMACION CON JAVA 2 233

Ejemplo(57): Programa completo del uso de la clase Fi-gura.

//Archivo: Figura.java

abstract class Figura { protected int x; protected int y; public Figura(int x, int y) { this.x=x; this.y=y; } public abstract double area(); } class Circulo extends Figura { protected double radio; public Circulo(int x, int y, double radio) { super(x,y); this.radio=radio; } public double area() { return Math.PI*radio*radio; } } class Rectangulo extends Figura { protected double ancho, alto; public Rectangulo(int x, int y, double ancho, double alto) { super(x,y); this.ancho=ancho; this.alto=alto; } public double area() { return ancho*alto; } }

//Archivo: FiguraApp.java

class FiguraApp { public static void main(String[] args)

234 Mg. ABRAHAM GAMARRA MORENO

{ //enlace temprano Circulo c=new Circulo(0, 0, 5.5); System.out.println("Utilizacion de enlace temprano"); System.out.println("Area del circulo "+c.area()); Rectangulo r=new Rectangulo(0, 0, 5.5, 2.0); System.out.println("Area del rectangulo "+r.area()); //enlace tardío System.out.println("Utilizacion de enlace tardio (dina-mico)"); Figura f=new Circulo(0, 0, 5.5); System.out.println("Area del circulo "+f.area()); f=new Rectangulo(0, 0, 5.5, 2.0); System.out.println("Area del rectangulo "+f.area()); } }

PROGRAMACION CON JAVA 2 235

CAPITULO CINCO

GESTION DE EXCEPCIONES

5.1. LAS EXCEPCIONES ESTÁNDAR Los programadores de cualquier lenguaje se esfuerzan por escribir programas libres de errores, sin embargo, es muy difícil que los programas reales se vean libres de ellos. En Java las situaciones que pueden provocar un fallo en el programa se denominan excepciones.

Java lanza una excepción en respuesta a una situación poco usual. El programador también puede lanzar sus propias excepciones. Las excepciones en Java son obje-tos de clases derivadas de la clase base Exception. Existen también los errores internos que son objetos de la clase Error. Ambas clases Error y Exception son clases derivadas de la clase base Throwable, tal como-se muestra en la figura 5.1.

Existe toda una jerarquía de clases derivada de la clase base Exception. Estas clases derivadas se ubican en dos grupos principales:

Las excepciones en tiempo de ejecución ocurren cuando el programador no ha tenido cuidado al escribir su có-digo. Por ejemplo, cuando se sobrepasa la dimensión de un array se lanza una excepción ArrayIndexOutOfBounds. Cuando se hace uso de una referencia a un objeto que no ha sido creado se lanza la excepción NullPointerEx-

236 Mg. ABRAHAM GAMARRA MORENO

ception. Estas excepciones le indican al programador que tipos de fallos tiene el programa y que debe arre-glarlo antes de proseguir.

Figura 5.1

El segundo grupo de excepciones, es el más interesan-te, ya que indican que ha sucedido algo inesperado o fuera de control.

5.1.1. LAS EXCEPCIONES

En la clase String, se tiene una función que convierte un string en un número. Esta fun-ción es muy usuada cuando creamos applets. Introducimos el número en un control de edi-ción, se obtiene el texto y se guarda en un string. Luego, se convierte el string en nú-mero entero mediante la función estática In-teger.parseInt, y finalmente, usamos dicho número.

String str=" 12 ";

int numero=Integer.parseInt(str);

Si se introducen caracteres no numéricos, o no se quitan los espacios en blanco al prin-cipio y al final del string, mediante la fun-ción trim, se lanza una excepción NumberFor-matException.

PROGRAMACION CON JAVA 2 237

El mensaje que aparece en la ventana nos in-dica el tipo de excepción NumberFormatExcep-tion, la función que la ha lanzado Inte-ger.parseInt, que se llama dentro de main.

Objeto no inicializado

Habitualmente, cuando llamamos desde un obje-to no inicializado, a una función miembro.

public static void main(String[] args)

{

String str;

str.length();

//...

}

El compilador se queja con el siguiente men-saje "variable str might not have been initi-lized". En otras ocasiones, se lanza una ex-cepción del tipo NulPointerException. Fijarse que en la porción de código que sigue, grafi-co es una variable de instancia que es ini-cializada por defecto a null.

class MiCanvas.... { Grafico grafico; public void paint(...) { grafico.dibuja(); //... } //... }

Como vemos en la porción de código, si al llamarse a la función paint, el objeto grafi-co no ha sido inicializado con el valor de-vuelto por new al crear un objeto de la clase Grafico o de alguna de sus clases derivadas, se lanza la excepción NullPointerException.

Entrada/salida

En otras situaciones el mensaje de error apa-rece en el momento en el que se compila el

238 Mg. ABRAHAM GAMARRA MORENO

programa. Así, cuando intentamos leer un ca-rácter del teclado, llamamos a la la función

System.in.read();

Cuando compilamos el programa, nos aparece un mensaje de error que no nos deja proseguir.

unreported exception: java.io.IOException; must be caught or declared to be thrown

5.1.2. CAPTURA DE LAS EXCEPCIONES

Empecemos por solucionar el error que se pro-duce en el programa durante la compilación. Tal como indica el mensaje que genera el com-pilador, se ha de poner la sentencia Sys-tem.in.read(); en un bloque try...catch, del siguiente modo.

try { System.in.read(); } catch (IOException ex) { }

Para solucionar el error que se produce en el programa durante su ejecución, se debe poner la llamada a Integer.parseInt en el siguiente bloque try...catch.

String str=" 12 "; int numero; try { numero=Integer.parseInt(str); } catch(NumberFormatException ex) { System.out.println("No es un número"); }

En el caso de que el string str contenga ca-racteres no numéricos como es éste el caso, el número 12 está acompañado de espacios en blanco, se produce una excepción del tipo NumberFormatException que es capturada y se imprime el mensaje "No es un número".

PROGRAMACION CON JAVA 2 239

En vez de un mensaje propio se puede imprimir el objeto ex de la clase NumberFormatExcep-tion

try { //... } catch(NumberFormatException ex) { System.out.println(ex); }

La clase base Throwable de todas las clases que describen las excepciones, redefine la función toString, que devuelve el nombre de la clase que describe la excepción acompañado del mensaje asociado, que en este caso es el propio string str.

java.lang.NumberFormatException: 12

Podemos extraer dicho mensaje mediante la función miembro getMessage, del siguiente mo-do

Try { //... } catch(NumberFormatException ex) { System.out.println(ex.getMessage()); }

5.1.3. MANEJANDO VARIAS EXCEPCIONES

Vamos a crear un programa que divida dos nú-meros. Supongamos que se introducen dos núme-ros, se obtiene el texto de cada uno y se guardan en dos strings. En esta situación se pueden producir dos excepciones NumberForma-tException, si se introducen caracteres no numéricos y ArithmeticException si se divide entre cero.

240 Mg. ABRAHAM GAMARRA MORENO

Ejemplo (58): Uso de varias excepciones.

//Archivo: ExcepcionApp.java class ExcepcionApp { public static void main(String[] args) { String str1="12"; String str2="0"; String respuesta; int numerador, denominador, cociente; try { numerador=Integer.parseInt(str1); denominador=Integer.parseInt(str2); cociente=numerador/denominador; respuesta=String.valueOf(cociente); } catch(NumberFormatException ex) { respuesta="Se han introducido caracteres no numeri-cos"; } catch(ArithmeticException ex) { respuesta="Division entre cero"; } System.out.println(respuesta); } }

Como vemos las sentencias susceptibles de lanzar una excepción se sitúan en un bloque try...catch. Si el denominador es cero, se produce una excepción de la clase Arithmeti-cException en la expresión que halla el co-ciente, que es inmediatamente capturada en el bloque catch que maneja dicha excepción, eje-cutándose las sentencias que hay en dicho bloque. En este caso se guarda en el string respuesta el texto "División entre cero".

Hay veces en las que se desea estar seguro de que un bloque de código se ejecute se produz-can o no excepciones. Se puede hacer esto añadiendo un bloque finally después del últi-mo catch. Esto es importante cuando accedemos

PROGRAMACION CON JAVA 2 241

a archivos, para asegurar que se cerrará siempre un archivo se produzca o no un error en el proceso de lectura/escritura.

try { //Este código puede generar una excepción }catch(Exception ex) { //Este código se ejecuta cuando se produce una excepción }finally { //Este código se ejecuta cuando se produzca o no una excep-ción }

5.2. LAS EXCEPCIONES PROPIAS El lenguaje Java proporciona las clases que manejan casi cualquier tipo de excepción. Sin embargo, podemos imaginar situaciones en la que producen excepciones que no están dentro del lenguaje Java. Siguiendo el ejemplo de la página anterior estudiaremos una situa-ción en la que el usuario introduce un valor fuera de un determinado intervalo, el programa lanza un excep-ción, que vamos a llamar ExcepcionIntervalo.

5.2.1. LA CLASE QUE DESCRIBE LA EXCEPCIÓN

Para crear y lanzar una excepción propia te-nemos que definir la clase ExcepcionIntervalo derivada de la clase base Exception.

public class ExcepcionIntervalo extends Exception { public ExcepcionIntervalo(String msg) { super(msg); } }

La definición de la clase es muy simple. Se le pasa un string msg, que contiene un mensa-je, en el único parámetro que tiene el cons-tructor de la clase derivada y éste se lo pa-sa a la clase base mediante super.

242 Mg. ABRAHAM GAMARRA MORENO

5.2.2. EL MÉTODO QUE PUEDE LANZAR UNA EXCEP-CIÓN

La función miembro que lanza una excepción tiene la declaración habitual que cualquier otro método pero se le añade a continuación la palabra reservada throws seguido de la ex-cepción o excepciones que puede lanzar.

static void rango(int num, int den)throws ExcepcionIntervalo { if((num>100)||(den<-5)) { throw new ExcepcionIntervalo("Números fuera del interva-lo"); } }

Cuando el numerador es mayor que 100 y el de-nominador es menor que 5 se lanza throw una excepción, un objeto de la clase ExcepcionIn-tervalo. Dicho objeto se crea llamando al constructor de dicha clase y pasándole un string que contiene el mensaje "Números fuera del intervalo".

5.2.3. CAPTURA DE LAS EXCEPCIONES

Al programa estudiado en la página anterior, añadimos la llamada a la función rango que verifica si los números están dentro del in-tervalo dado, y el bloque catch que captura la excepción que puede lanzar dicha función si los números no están en el intervalo espe-cificado.

Ejemplo (59): Uso de excepciones.

public class ExcepcionApp3 { public static void main(String[] args) { String str1="120"; String str2="3"; String respuesta; int numerador, denominador, cociente;

PROGRAMACION CON JAVA 2 243

try { numerador=Integer.parseInt(str1); denominador=Integer.parseInt(str2); rango(numerador, denominador); cociente=numerador/denominador; respuesta=String.valueOf(cociente); } catch(NumberFormatException ex) { respuesta="Se han introducido caracteres no numéri-cos"; } catch(ArithmeticException ex) { respuesta="División entre cero"; } catch(ExcepcionIntervalo ex) { respuesta=ex.getMessage(); } System.out.println(respuesta); } static void rango(int num, int den)throws ExcepcionInter-valo { if((num>100)||(den<-5)) { throw new ExcepcionIntervalo("Numeros fuera del inter-valo"); } } }

Como vemos el numerador que vale 120 tiene un valor fuera del intervalo especificado en la función rango, por lo que se lanza una excep-ción cuando se llega a la llamada a dicha función en el bloque try. Dicha excepción es capturada por el bloque catch correspondiente a dicha excepción, y se ejecutan las senten-cias de dicho bloque. En concreto, se obtiene mediante getMessage el texto del mensaje que

244 Mg. ABRAHAM GAMARRA MORENO

guarda el objeto ex de la clase ExcepcionIn-tervalo.

El ciclo de vida de una excepción se puede resumir del siguiente modo:

• Se coloca la llamada a la función sus-ceptible de producir una excepción en un bloque try...catch

• En dicha función se crea mediante new un objeto de la clase Exception o derivada de ésta

• Se lanza mediante throw el objeto recién creado

• Se captura en el correspondiente bloque catch

• En este bloque se notifica al usuario esta eventualidad imprimiendo el mensaje asociado a dicha excepción, o realizando una tarea específica.

5.2.4. UNA FUNCIÓN QUE QUE PUEDE LANZAR VA-RIAS EXCEPCIONES

Hay otra alternativa para el ejercicio ante-rior, que es la de definir una función deno-minada calcular, que devuelva el cociente en-tre el numerador y el denominador, cuando se le pasa los strings obtenidos de los respec-tivos controles de edición. La función calcu-lar, convierte los strings en números ente-ros, verifica el rango, calcula y devuelve el cociente entre el numerador y el denominador,

PROGRAMACION CON JAVA 2 245

Ejemplo (60): Uso de excepciones.

//Archivo: ExcepcionApp4.java public class ExcepcionApp4 { public static void main(String[] args) { String str1="220"; String str2="2"; String respuesta; int numerador, denominador, cociente; try { cociente=calcular(str1, str2); respuesta=String.valueOf(cociente); } catch(NumberFormatException ex) { respuesta="Se han introducido caracteres no numéri-cos"; } catch(ArithmeticException ex) { respuesta="División entre cero"; } catch(ExcepcionIntervalo ex) { respuesta=ex.getMessage(); } System.out.println(respuesta); } static int calcular(String str1, String str2)throws ExcepcionIntervalo, NumberFormatException, ArithmeticException { int num=Integer.parseInt(str1); int den=Integer.parseInt(str2); if((num>100)||(den<-5)) { throw new ExcepcionIntervalo("Números fuera del inter-valo"); } return (num/den); } }

Vemos que la función calcular puede lanzar, throws, tres tipos de excepciones. En el

246 Mg. ABRAHAM GAMARRA MORENO

cuerpo de la función se crea, new, y se lan-za, throw, explícitamente un objeto de la clase ExcepcionIntervalo, definida por el usuario, e implícitamente se crea y se lanza objetos de las clases NumberFormatException y ArithmeticException definidas en el lenguaje Java.

La sentencia que llama a la función calcular dentro del bloque try puede producir alguna de las tres excepciones que es capturada por el correspondiente bloque catch.

Podemos simplificar algo el codigo ahorrándo-nos la variable temporal cociente, escribien-do en vez de las dos sentencias

cociente=calcular(str1, str2);

respuesta=String.valueOf(cociente);

Una única sentencia

respuesta=String.valueOf(calcular(str1, str2));

PROGRAMACION CON JAVA 2 247

CAPITULO SEIS

PAQUETES

6.1. PAQUETES Un paquete es un conjunto de clases, lógicamente rela-cionadas entre sí, agrupadas bajo un nombre (por ejem-plo, el paquete java.io agrupa las clases que permiten a un programa realizar la entrada y salida de informa-ción); incluso, un paquete puede contener a otros pa-quetes.

Prácticamente son bibliotecas a las que el usuario puede acceder y que ofrecen varias funciones (méto-dos). Los usuarios pueden también crear paquetes in-formáticos, por ejemplo, haciendo que contengan todas las clases que ha definido para poner en marcha algu-nas funciones que luego usará en varios programas.

Los paquetes son los módulos de Java. Recipientes que contienen clases y que se utilizan tanto para mantener el espacio de nombres dividido en compartimentos más manejables como un mecanismo de restricción de visibi-lidad. Se pueden poner clases dentro de los paquetes restringiendo la accesibilidad a éstas en función de la localización de los otros miembros del paquete. Ca-da archivo .java tiene las mismas cuatro partes inter-nas y hasta ahora sólo hemos utilizado una de ellas en nuestros ejemplos. Esta es la forma general de un ar-chivo fuente de Java, una única sentencia de paquete

248 Mg. ABRAHAM GAMARRA MORENO

(opcional) las sentencias de importación deseadas (op-cional) una única declaración de clase pública las clases privadas de paquete deseadas (opcional).

6.1.1. LA SENTENCIA PACKAGE (PAQUETE)

Lo primero que se permite en un archivo Java es una sentencia package, que le dice al com-pilador en qué paquete se deberían definir las clases incluidas. Si se omite la senten-cia package, las clases terminan en el paque-te por defecto, que no tiene nombre. El com-pilador Java utiliza directorios de sistema de archivos para almacenar paquetes.

Si se declara que una clase está dentro de un paquete llamado MiPaquete, entonces el archi-vo fuente de esa clase se debe almacenar en un directorio llamado MiPaquete.

Recuerde que se diferencia entre mayúsculas y minúsculas y que el nombre del directorio de-be coincidir con el nombre exactamente. Esta es la forma general de la sentencia package.

package paq1[ .paq2 [ .paq3 ]];

Observe que se puede crear una jerarquía de paquetes dentro de paquetes separando los ni-veles por puntos. Esta jerarquía se debe re-flejar en el sistema de archivos de desarro-llo de Java. Un paquete declarado como

package java.awt.imagen;

se debe almacenar en java/awt/imagen, en ja-va\awt\imagen o en java:awt:imagen en los sistemas de archivo UNIX, Windows o Macin-tosh, respectivamente.

6.1.2. COMPILACIÓN DE CLASES EN PAQUETES

Cuando se intenta poner una clase en un pa-quete, el primer problema es que la estructu-ra de directorios debe coincidir con la je-rarquía de paquetes exactamente. No se puede renombrar un paquete sin renombrar el direc-torio en el cual están almacenadas las cla-

PROGRAMACION CON JAVA 2 249

ses. El otro problema que presenta la compi-lación es más sutil.

Cuando desee llamar a una clase que se encuentre en un paquete deberá prestar atención a su ubicación en la jerarquía de paquetes. Por ejemplo, si se crea una clase llamada PaquetePrueba en un paquete llamado prueba. Para ello se crea el directorio llamado prueba y se pone en él PaquetePrueba.java y se compila. Si intenta ejecutarlo, el intérprete no lo encontrará. Esto se debe a que esta clase se encuentra ahora en un paquete llamado prueba y no nos podemos referir a ella simplemente con PaquetePrueba, sin embargo si es posible referirse a cualquier paquete enumerando su jerarquía de paquetes, separando los paquetes por puntos. Por lo tanto, si intenta ejecutar ahora Java con prueba.PaquetePrueba, el intérprete tampoco lo encontrará.

El motivo de este nuevo fracaso se encuentra en la variable CLASSPATH. Probablemente con-tenga algo parecido a ".;C:\java\classes" que le dice al intérprete que busque en el direc-torio de trabajo actual y en el directorio de instalación del Equipo de herramientas de de-sarrollo de Java estándar. El problema es que no hay un directorio prueba en el directorio de trabajo actual porque usted ya está en el directorio prueba. Tiene dos opciones en este momento: cambiar de directorio un nivel arri-ba y ejecutar "java prueba.PaquetePrueba"3, o añadir el extremo de su jerarquía de clases de desarrollo a la variable de entorno CLASS-PATH. Después podrá utilizar "java prue-ba.PaquetePrueba" desde cualquier directorio y Java encontrará el archivo .class adecuado. Si trabaja con su código fuente en un direc-torio llamado C:\mijava, dé a CLASSPATH el valor ".;C:\mijava;C:\java\classes".

Para realizar modificaciones de CLASSPATH en el JCreator, que nos permita definir la ubi-cación de nuestros paquetes, debemos hacerlo utilizando Configure, Options, JDK Profiles,

3 La ejecución de la clase Paquete.Prueba se realiza desde la línea de comandos del DOS.

250 Mg. ABRAHAM GAMARRA MORENO

Edit, Add; tal como se muestra en la figura 5.1.

Figura 6.1.

6.1.3. LA SENTENCIA IMPORT

Lo siguiente que se pone después de una sen-tencia package y antes de las definiciones de clase en un archivo fuente en Java puede ser una lista de sentencias import. Todas las clases interesantes están almacenadas en al-gún paquete con nombre. Para no tener que in-troducir el largo nombre de trayecto de pa-quete para cada clase, Java incluye la sen-tencia import para que se puedan ver ciertas

PROGRAMACION CON JAVA 2 251

clases o paquetes enteros. La forma general de la sentencia import:

import paquete1.[ paquete2 ].( nombre_clase | * );

paquete1 es el nombre de un paquete de alto nivel, paquete2 es el nombre de un paquete opcional contenido en el paquete exterior se-parado por un punto (.). No hay ningún límite práctico a la profundidad de la jerarquía de paquetes.

Finalmente, nombre_clase explícito o un aste-risco (*) que indica que el compilador Java debería buscar este paquete completo.

import java.util.Date;

import java.io.*;

6.1.4. PROTECCIÓN DE ACCESOS

Java proporciona unos cuantos mecanismos para permitir un control de acceso entre clases en circunstancias diferentes.

Las tablas siguientes muestran el nivel de acceso que está permitido a cada uno de los especificadores:

Nivel de acceso

Clase Subclase (clase derivada)

paquete todos

private Sí No No No

protected Sí Sí Sí No

public Sí Sí Sí Sí

package Sí No Sí No

252 Mg. ABRAHAM GAMARRA MORENO

Un miembro declarado en una clase como: Puede ser accedido

desde Private

sin modifica-dor (default:

package) protected public

Su misma clase sí sí sí sí

Cualquier Clase o subclase del mismo pa-quete

no sí sí sí

Cualquier subclase de otro paque-te.

no no sí sí

Cualquier clase de otro paquete.

no no no sí

Una guía de uso indicaría tener en cuenta lo siguiente:

• Usar private para métodos y variables que solamente se utilicen dentro de la clase y que deberían estar ocultas para todo el resto.

• Usar public para métodos, constantes y otras variables importantes que deban ser vi-sibles para todo el mundo.

• Usar protected si se quiere que las clases del mismo paquete puedan tener acceso a estas variables o métodos.

• Usar la sentencia package para poder agru-par las clases en paquetes.

• No usar nada, dejar la visibilidad por de-fecto (default, package) para métodos y va-riables que deban estar ocultas fuera del pa-quete, pero que deban estar disponibles al acceso desde dentro del mismo paquete. Utili-zar protected en su lugar si se quiere que esos componentes sean visibles fuera del pa-quete.

PROGRAMACION CON JAVA 2 253

6.1.5. LOS PAQUETES ESTÁNDAR

Paquete Descripción

java.applet Contiene las clases necesarias para crear applets que se ejecutan en la ventana del navegador

java.awt Contiene clases para crear una aplicación GUI independiente de la plataforma

java.io Entrada/Salida. Clases que definen dis-tintos flujos de datos

java.lang Contiene clases esenciales, se importa impícitamente sin necesidad de una sen-tencia import.

java.net Se usa en combinación con las clases del paquete java.io para leer y escribir da-tos en la red.

java.util Contiene otras clases útiles que ayudan al programador

6.2. EJEMPLOS DE USO DE PAQUETES Ejemplo (61): El presente ejemplo permite asignar la clase Leer al paquete LeerDatos. La clase Leer permite obtener tipos de datos primitivos desde el teclado.

Para la implementación debemos considerrar que el ar-chivo Leer.java debe estar en la carpeta LeerDatos (el mismo nombre del paquete), dentro del directorio ac-tual.

//Archivo Leer.java

// Debe estar en la carpeta LeerDatos dentro del // directorio activo package LeerDatos; import java.io.*; public class Leer { public static String dato() { String sdato = ""; try { // Definir un flujo de caracteres de entrada: flujoE InputStreamReader isr = new InputStreamReader(System.in); BufferedReader flujoE = new BufferedReader(isr); // Leer. La entrada finaliza al pulsar la tecla Entrar

254 Mg. ABRAHAM GAMARRA MORENO

sdato = flujoE.readLine(); } catch(IOException e) { System.err.println("Error: " + e.getMessage()); } return sdato; // devolver el dato tecleado } public static short datoShort() { try { return Short.parseShort(dato()); } catch(NumberFormatException e) { return Short.MIN_VALUE; // valor más pequeño } } public static int datoInt() { try { return Integer.parseInt(dato()); } catch(NumberFormatException e) { return Integer.MIN_VALUE; // valor más pequeño } } public static long datoLong() { try { return Long.parseLong(dato()); } catch(NumberFormatException e) { return Long.MIN_VALUE; // valor más pequeño } } public static float datoFloat() { try { Float f = new Float(dato()); return f.floatValue(); } catch(NumberFormatException e) { return Float.NaN; // No es un Número; valor float. } }

PROGRAMACION CON JAVA 2 255

public static double datoDouble() { try { Double d = new Double(dato()); return d.doubleValue(); } catch(NumberFormatException e) { return Double.NaN; // No es un Número; valor double. } } }

El archivo LecturaDatos.java debe estar un nivel arriba, en el árbol de carpetas con respecto a la carpeta LeerDatos.

//Archivo: LecturaDatos.java

// Utiliza la clase Leer que debe de estar almacenada // en la carpeta LeerDatos (pauete LeerDatos) import LeerDatos.*; class LecturaDatos { public static void main(String[] args) { short dato_short = 0; int dato_int = 0; long dato_long = 0; float dato_float = 0; double dato_double = 0; System.out.print("Dato short: "); dato_short = Leer.datoShort(); System.out.print("Dato int: "); dato_int = Leer.datoInt(); System.out.print("Dato long: "); dato_long = Leer.datoLong(); System.out.print("Dato float: "); dato_float = Leer.datoFloat(); System.out.print("Dato double: "); dato_double = Leer.datoDouble();

Aquí se encuentra LecturaDatos.java

Aquí se encuentra Leer.java

256 Mg. ABRAHAM GAMARRA MORENO

System.out.println(dato_short); System.out.println(dato_int); System.out.println(dato_long); System.out.println(dato_float); System.out.println(dato_double); } }

PROGRAMACION CON JAVA 2 257

CAPITULO SIETE

INTERFACES

7.1. ¿QUÉ ES UN INTERFACE? Una interface Java es un dispositivo que permite in-teractuar a objetos no relacionados entre sí. Las in-terfaces Java en realidad definen un conjunto de men-sajes que se puede aplicar a muchas clases de objetos, a los que cada una de ellas debe responder de forma adecuada.

Un interface es una colección de declaraciones de mé-todos (sin definirlos) y también puede incluir cons-tantes.

Runnable es un ejemplo de interface en el cual se de-clara, pero no se implemementa, una función miembro run.

[public] interface Runnable { public abstract void run(); }

El modificador de acceso public indica que la Interfaz puede ser utilizada por cualquier clase de cualquier paquete.

258 Mg. ABRAHAM GAMARRA MORENO

Las clases que implementen (implements) el interface Runnable han de definir obligatoriamente la función run.

class Animacion implements Runnable { //.. public void run() { //define la función run } }

El papel del interface es el de describir algunas de las características de una clase. Por ejemplo, el hecho de que una persona sea un futbolista no define su personalidad completa, pero hace que tenga ciertas características que las distinguen de otras.

Clases que no están relacionadas pueden implementar el interface Runnable, por ejemplo, una clase que descri-ba una animación, y también puede implementar el in-terface Runnable una clase que realice un cálculo in-tensivo.

7.2. DIFERENCIAS ENTRE UN INTERFACE Y UNA CLASE ABSTRACTA

Un interface es simplemente una lista de métodos no implementados, además puede incluir la declaración de constantes. Una clase abstracta puede incluir métodos implementados y no implementados o abstractos, miem-bros dato, constantes y otros no constantes.

Ahora bien, la diferencia es mucho más profunda. Ima-ginemos que Runnable fuese una clase abstracta. Un ap-plet descrito por la clase MiApplet que moviese una figura por su área de trabajo, derivaría a la vez de la clase base Applet (que describe la funcionalidad mínima de un applet que se ejecuta en un navegador) y de la clase Runnable. Pero el lenguaje Java no tiene herencia múltiple.

En el lenguaje Java la clase MiApplet deriva de la clase base Applet e implementa el interface Runnable.

PROGRAMACION CON JAVA 2 259

class MiApplet extends Applet implements Runnable { //... //define la función run del interface public void run() { //... } //redefine paint de la clase base Applet public void paint(Graphics g) { //... } //define otras funciones miembro }

Una clase solamente puede derivar extends de una clase base, pero puede implementar varios interfaces. Los nombres de los interfaces se colocan separados por una coma después de la palabra reservada implements.

El lenguaje Java no fuerza por tanto, una relación je-rárquica, simplemente permite que clases no relaciona-das puedan tener algunas características de su compor-tamiento similares.

7.3. LOS INTERFACES Y EL POLIMORFISMO En el lenguaje C++, es posible la herencia múltiple, pero este tipo de herencia presenta dificultades. Por ejemplo, cuando dos clases B y C derivan de una clase base A, y a su vez una clase D deriva de B y C. Este problema es conocido con el nombre de diamante.

En el lenguaje Java solamente existe la herencia simple, pero las clases pueden im-plementar interfaces. Vamos a ver en este

260 Mg. ABRAHAM GAMARRA MORENO

apartado que la importancia de los interfaces no estriba en resolver los problemas inheren-tes a la herencia múltiple sin forzar rela-ciones jerárquicas, sino es el de incrementar el polimorfismo del lenguaje más allá del que proporciona la herencia simple.

7.3.1. HERENCIA SIMPLE

Creamos una clase abstracta denominada Animal de la cual deriva las clases Gato y Perro. Ambas clases redefinen la función habla de-clarada abstracta en la clase base Animal.

Ejemplo (62): Clase abstracta y Herencia sim-ple.

//Archivo Animal.java package polimorfismo; public abstract class Animal { public abstract void habla(); } class Perro extends Animal { public void habla() { System.out.println("¡Guau!"); } } class Gato extends Animal { public void habla() { System.out.println("¡Miau!"); } }

El polimorfismo nos permite pasar la referen-cia a un objeto de la clase Gato a una fun-ción hazleHablar que conoce al objeto por su clase base Animal

//Archivo: PoliApp.java package polimorfismo; public class PoliApp {

PROGRAMACION CON JAVA 2 261

public static void main(String[] args) { Gato gato=new Gato(); hazleHablar(gato);

} static void hazleHablar(Animal sujeto) { sujeto.habla(); } }

El compilador no sabe exactamente que objeto se le pasará a la función hazleHablar en el momento de la ejecución del programa. Si se pasa un objeto de la clase Gato se imprimirá ¡Miau!, si se pasa un objeto de la clase Pe-rro se imprimirá ¡Guau!. El compilador sola-mente sabe que se le pasará un objeto de al-guna clase derivada de Animal. Por tanto, el compilador no sabe que función habla será llamada en el momento de la ejecución del programa.

El polimorfismo nos ayuda a hacer el programa más flexible, por que en el futuro podemos añadir nuevas clases derivadas de Animal, sin que cambie para nada el método hazleHablar. Como ejercicio, se sugiere al lector añadir la clase Pajaro a la jerarquía, y pasar un objeto de dicha clase a la función hazleHa-blar para que se imprima ¡pio, pio, pio ..!.

7.3.2. INTERFACES

Vamos a crear un interface denominado Parlan-chin que contenga la declaración de una fun-ción denominada habla.

public interface Parlanchin { public abstract void habla(); }

262 Mg. ABRAHAM GAMARRA MORENO

Hacemos que la jerraquía de clases que deriva de Animal implemente el interface Parlanchin

public abstract class Animal1 implements Parlanchin { public abstract void habla(); } class Perro extends Animal1 { public void habla() { System.out.println("¡Guau!"); } } class Gato extends Animal1 { public void habla() { System.out.println("¡Miau!"); } }

Ahora veamos otra jerarquía de clases comple-tamente distinta, la que deriva de la clase base Reloj. Una de las clases de dicha jerar-quía Cucu implementa el interface Parlanchin y por tanto, debe de definir obligatoriamente la función habla declarada en dicho interfa-ce.

public abstract class Reloj { } class Cucu extends Reloj implements Parlanchin { public void habla() { System.out.println("¡Cucu, cucu, ..!"); } }

Definamos la función hazleHablar de modo que conozca al objeto que se le pasa no por una clase base, sino por el interface Parlanchin. A dicha función le podemos pasar cualquier objeto que implemente el interface Parlan-chin, este o no en la misma jerarquía de cla-ses.

public class PoliApp {

PROGRAMACION CON JAVA 2 263

public static void main(String[] args) { Gato gato=new Gato(); hazleHablar(gato); Cucu cucu=new Cucu(); hazleHablar(cucu); } static void hazleHablar(Parlanchin sujeto) { sujeto.habla(); } }

Al ejecutar el programa, veremos que se im-prime en la consola ¡Miau!, por que a la fun-ción hazleHablar se le pasa un objeto de la clase Gato, y después ¡Cucu, cucu, ..! por que a la función hazleHablar se le pasa un objeto de la clase Cucu.

Si solamente hubiese herencia simple, Cucu tendría que derivar de la clase Animal (lo que no es lógico) o bien no se podría pasar a la función hazleHablar. Con interfaces, cual-quier clase en cualquier familia puede imple-mentar el interface Parlanchin, y se podrá pasar un objeto de dicha clase a la función hazleHablar. Esta es la razón por la cual los interfaces proporcionan más polimorfismo que el que se puede obtener de una simple jerar-quía de clases.

Ejemplo (63): Programa completo de la inter-face Parlanchin

//Archivo: Parlanchin.java

public interface Parlanchin { public abstract void habla(); }

//Archivo Animal1.java

public abstract class Animal1 implements Parlanchin { public abstract void habla(); }

264 Mg. ABRAHAM GAMARRA MORENO

class Perro extends Animal1 { public void habla() { System.out.println("¡Guau!"); } } class Gato extends Animal1 { public void habla() { System.out.println("¡Miau!"); } }

//archivo: Reloj.java

public abstract class Reloj { } class Cucu extends Reloj implements Parlanchin { public void habla() { System.out.println("¡Cucu, cucu, ..!"); } }

//Archivo: PoliApp1.java

public class PoliApp1 { public static void main(String[] args) { Gato gato=new Gato(); System.out.println("Uso de hazlehablar() con el el objeto gato:\n"); hazleHablar(gato); Cucu cucu=new Cucu(); System.out.println("Uso de hazlehablar() con el el objeto cucu:\n"); hazleHablar(cucu); } static void hazleHablar(Parlanchin sujeto) { sujeto.habla(); } }

PROGRAMACION CON JAVA 2 265

PROGRAMACION CON JAVA 2 267

CAPITULO OCHO

ENTRADA/SALIDA PARA EL MANEJO DE ARCHIVOS

8.1. ARCHIVOS Y DIRECTORIOS

8.1.1. LA CLASE FILE

Antes de proceder al estudio de las clases que describen la entrada/salida vamos a estu-diar la clase File, que nos proporciona in-formación acerca de los archivos, de sus atributos, de los directorios, etc. También explicaremos como se crea un filtro mediante el interface FilenameFilter para obtener la lista de los archivos que tengan por ejemplo, la extensión .java.

La clase File tiene tres constructores

• File(String path)

• File(String path, String name)

• File(File dir, String name)

El parámetro path indica el camino hacia el directorio donde se encuentra el archivo, y name indica el nombre del archivo. Los méto-

268 Mg. ABRAHAM GAMARRA MORENO

dos más importantes que describe esta clase son los siguientes:

• String getName()

• String getPath()

• String getAbsolutePath()

• boolean exists()

• boolean canWrite()

• boolean canRead

• boolean isFile()

• boolean isDirectory()

• boolean isAbsolute()

• long lastModified()

• long length()

• boolean mkdir()

• boolean mkdirs()

• boolean renameTo(File dest);

• boolean delete()

• String[] list()

• String[] list(FilenameFilter filter)

Mediante un ejemplo explicaremos algunos de los métodos de la clase File.

Creamos un objeto fichero de la clase File, pasándole el nombre del archivo, en este ca-so, el nombre del archivo código fuente Ar-chivoApp1.java.

File fichero=new File("ArchivoApp1.java");

PROGRAMACION CON JAVA 2 269

Si este archivo existe, es decir, si la fun-ción exists devuelve true, entonces se obtie-ne información acerca del archivo:

• getName devuelve el nombre del archivo

• getPath devuelve el camino relativo

• getAbsolutePath devuelve el camino abso-luto.

• canRead nos indice si el archivo se pue-de leer.

• canWrite nos indica si el archivo se puede escribir

• length nos devuelve el tamaño del archi-vo, si dividimos la cantidad devuelta entre 1024 obtenemos el tamaño del ar-chivo en KB.

if(fichero.exists()) { System.out.println("Nombre del archivo "+fichero.getName()); System.out.println("Camino "+fichero.getPath()); System.out.println("Camino absoluto "+fichero.getAbsolutePath()); System.out.println("Se puede escribir "+fichero.canRead()); System.out.println("Se puede leer "+fichero.canWrite()); System.out.println("Tamaño "+fichero.length()); }

La salida del programa es la siguiente:

Nombre del arachivo ArchivoApp1.java Camino ArchivoApp1.java Camino absoluto c:\JBuilder2\myNumerico\archivo1\ArchivoApp1.java Se puede escribir true Se puede leer true Tamaño 1366

270 Mg. ABRAHAM GAMARRA MORENO

Para obtener la lista de los archivos del di-rectorio actual se crea un nuevo objeto de la clase File

fichero=new File(".");

Para obtener la lista de los archivos que contiene este directorio se llama a la fun-ción miembro list, la cual nos devuelve un array de strings.

String[] listaArchivos=fichero.list(); for(int i=0; i<listaArchivos.length; i++) { System.out.println(listaArchivos[i]); }

La salida es la siguiente

archivo1.jpr archivo1.html ArchivoApp1.java ArchivoApp1.~jav Filtro.java Filtro.~jav

8.1.2. CREACIÓN DE UN FILTRO

Un filtro es un objeto de una clase que im-plemente el interface FilenameFilter, y tiene que redefinir la única función del interface denominada accept. Esta función devuelve un dato de tipo boolean. En este caso, la hemos definido de forma que si el nombre del archi-vo termina con una determinada extensión de-vuelve true en caso contrario devuelve false. La función endsWith de la clase String reali-za esta tarea tal como se ve en la porción de código que viene a continuación. La extensión se le pasa al constructor de la clase Filtro para inicializar el miembro dato extension.

import java.io.*; public class Filtro implements FilenameFilter { String extension; Filtro(String extension) { this.extension=extension; }

PROGRAMACION CON JAVA 2 271

public boolean accept(File dir, String name) { return name.endsWith(extension); } }

Para obtener la lista de archivos con exten-sión .java en el directorio actual, creamos un objeto de la clase Filtro y se lo pasamos a la función list miembro de la clase File.

listaArchivos=fichero.list(new Filtro(".java")); for(int i=0; i<listaArchivos.length; i++) { System.out.println(listaArchivos[i]); }

La salida es ahora la siguiente

ArchivoApp1.java Filtro.java

Ejemplo (64): Programa completo para el uso de la cla-se File y Filtro.

//Archivo: Filtro.java

import java.io.*; public class Filtro implements FilenameFilter { String extension; Filtro(String extension) { this.extension=extension; } public boolean accept(File dir, String name) { return name.endsWith(extension); } }

//Archivo: ArchivoApp1.java

import java.io.*; public class ArchivoApp1

272 Mg. ABRAHAM GAMARRA MORENO

{ public static void main(String[] args) { File fichero=new File("ArchivoApp1.java"); if(fichero.exists()) { System.out.println("Nombre del archivo "+fichero.getName()); System.out.println("Camino "+fichero.getPath()); System.out.println("Camino absoluto "+fichero.getAbsolutePath()); System.out.println("Se puede escribir "+fichero.canRead()); System.out.println("Se puede leer "+fichero.canWrite()); System.out.println("Tamaño "+fichero.length()); //para calcular el tamaño del archivo en KB se divide entre 1024 System.out.println(" ******* lista de los archivos de este directorio *******"); fichero=new File("."); String[] listaArchivos=fichero.list(); for(int i=0; i<listaArchivos.length; i++) { System.out.println(listaArchivos[i]); } System.out.println(" ******* lista de los archivos con filtro *******"); listaArchivos=fichero.list(new Filtro(".txt")); for(int i=0; i<listaArchivos.length; i++) { System.out.println(listaArchivos[i]); } } } }

PROGRAMACION CON JAVA 2 273

8.2. FLUJOS DE DATOS Todos los datos fluyen a través del ordenador desde una entrada hacia una salida. Este flujo de datos se denomina también stream. Hay un flujo de entrada (fig. input stream) que manda los datos desde el exterior (normalmente el teclado) del ordenador, y un flujo de salida (output stream) que dirige los datos hacia los dispositivos de salida (la pantalla o un archivo).

274 Mg. ABRAHAM GAMARRA MORENO

El proceso para leer o escribir datos consta de tres pasos

• Abrir el flujo de datos

• Mientras exista más información (leer o escribir) los datos

• Cerrar el flujo de datos

8.2.1. LAS JERARQUÍAS DE CLASES

En el lenguaje Java los flujos de datos se describen mediante clases que forman jerar-quías según sea el tipo de dato char Unicode de 16 bits o byte de 8 bits. A su vez, las clases se agrupan en jerarquías según sea su función de lectura o de escritura.

La característica de internacionalización del lenguaje Java es la razón por la que existe una jerarquía separada de clases para la lec-tura y escritura de caracteres.

Todas estas clases se encuentran en el paquete java.io, por lo que al principio del código fuente tendremos que escribir la sen-tencia

import java.io.*;

PROGRAMACION CON JAVA 2 275

char Unicode, 16 bits

byte, 8 bits.

276 Mg. ABRAHAM GAMARRA MORENO

Reader y Writer son las clases bases de la jerarquía para los flujos de caracteres. Para leer o escribir datos binarios tales como imágenes o sonidos, se emplea otra jerarquía de clases cuyas clases base son InputStream y OutputStream.

8.2.2. LECTURA

Las clases Reader e InputStream son similares aunque se refieren a distintos tipos de datos, lo mismo ocurre con Writer y OutputSream.

Por ejemplo, Reader proporciona tres métodos para leer un carácter char o un array de ca-racteres

int read()

int read(char buf[])

int read(char buf[], int offset, int len)

InputStream proporciona métodos similares pa-ra leer un byte o un array de bytes.

int read()

int read(byte buf[])

int read(byte buf[], int offset, int len)

La primera versión lee un byte como entero del flujo de entrada, devuelve –1 si no hay más datos que leer. La segunda versión, lee un array de bytes devolviendo el número de bytes leídos. La tercera versión, lee tam-bién, un array de bytes, pero nos permite es-pecificar, la posición de comienzo del array en la que se empiezan a guardar los bytes, y el máximo número de bytes que se van a leer.

Dichas clases definen otras funciones miembro que no estudiaremos de momento.

PROGRAMACION CON JAVA 2 277

8.2.3. ESCRITURA

La clase Writer proporciona tres métodos para escribir un carácter char o un array de ca-racteres

int write(int c)

int write(char buf[])

int write(char buf[], int offset, int len)

La clase OutputStream proporciona métodos si-milares

int write(int c)

int write(byte buf[])

int write(byte buf[], int offset, int len)

8.3. ENTRADA/SALIDA ESTÁNDAR

8.3.1. LOS OBJETOS SYSTEM.IN Y SYSTEM.OUT

La entrada/salida estándar (normalmente el teclado y la pantalla, respectivamente) se definen mediante dos objetos que puede usar el programador sin tener que crear flujos es-pecíficos.

La clase System tiene un miembro dato denomi-nado in que es una instancia de la clase In-putStream que representa al teclado o flujo de entrada estándar. Sin embargo, el miembro out de la clase System es un objeto de la clase PrintStream, que imprime texto en la pantalla (la salida estándar).

Para leer un carácter solamente tenemos que llamar a la función read desde System.in.

try { System.in.read(); }catch (IOException ex) { }

278 Mg. ABRAHAM GAMARRA MORENO

Obligatoriamente, el proceso de lectura ha de estar en un bloque try..catch.

Esta porción de código se puede emplear para detener la ejecución de una aplicación hasta que se pulse la tecla RETORNO.

Para leer un conjunto de caracteres hasta que se pulse la tecla RETORNO escribimos

StringBuffer str=new StringBuffer(); char c; try { while ((c=(char)System.in.read())!='\n') { str.append(c); } }catch(IOException ex){}

La clase StringBuffer es una clase que nos permite crear strings. Contiene métodos para añadir nuevos caracteres a un buffer y con-vertir el resultado final en un string. Las principales funciones miembro son insert y append. Usamos una versión de esta última función para añadir un carácter al final de un objeto de la clase StringBuffer.

Para convertir un objeto str de la clase StringBuffer a String se usa la función miem-bro toString. Esta llamada se hace de forma implícita cuando dicho objeto se le pasa a System.out.println.

System.out.println(str);

Finalmente, se ha de hacer notar, que la función read miembro de InputStream devuelve un int que es promocionado a char.

8.3.2. LA CLASE READER

Existe la posibilidad de conectar el objeto System.in con un objeto de la clase InputS-treamReader para leer los caracteres teclea-dos por el usuario.

Esta conexión se realiza mediante la senten-cia

PROGRAMACION CON JAVA 2 279

Reader entrada=new InputStreamReader(System.in);

Para leer una sucesión de caracteres se em-plea un código similar (Vea el archivo Tecla-doApp2.java)

StringBuffer str=new StringBuffer(); char c; try { Reader entrada=new InputStreamReader(System.in); while ((c=(char)entrada.read())!='\n') { str.append(c); } }catch(IOException ex){}

Para imprimir los carcteres leídos se escribe como en la sección anterior

System.out.println(str);

Ejemplo (65): Programa completo para el uso de read.

//Archivo TecladoApp2.java import java.io.*; public class TecladoApp2 { public static void main(String[] args) { StringBuffer str=new StringBuffer(); char c; System.out.println("Ingrese cadena: "); try { Reader entrada=new InputStreamReader(System.in); // while ((c=(char)System.in.read())!='\n'){ while ((c=(char)entrada.read())!='\n') { str.append(c); } } catch(IOException ex) {} System.out.println(str); try { //espera la pulsación de una tecla y luego RETORNO System.in.read(); }catch (Exception e) { } } }

280 Mg. ABRAHAM GAMARRA MORENO

Podemos usar la segunda versión de la función read para leer el conjunto de caracteres te-cleados por el usuario. (Vea el archivo Te-cladoApp1.java)

char[] buffer=new char[255]; try { Reader entrada=new InputStreamReader(System.in); int numBytes=entrada.read(buffer); System.out.println("Número de bytes leídos "+numBytes); }catch(IOException ex){ }

En esta segunda porción de código, se lee un conjunto de caracteres hasta que se pulsa la tecla RETORNO, los caracteres se guardan en el array buffer. La función read devuelve el número de caracteres leídos.

Para imprimir los caracteres leídos se crea un objeto str de la clase String a partir de un array de caracteres buffer, empleando uno de los contructores de dicha clase. A continuación, se imprime el string str.

String str=new String(buffer);

System.out.println(str);

Ejemplo (66): Programa completo para el uso de read (versión 2).

//archivo: TecladoApp1.java import java.io.*; public class TecladoApp1 { public static void main(String[] args) { char[] buffer=new char[255];

PROGRAMACION CON JAVA 2 281

System.out.println("Introduce una linea de texto y pulsa RETORNO "); try { Reader entrada=new InputStreamReader(System.in); int numBytes=entrada.read(buffer); System.out.println("Numero de bytes leidos "+numBytes); }catch(IOException ex) { System.out.println("Error entrada/salida"); } System.out.println("La linea de texto que has escrito es "); String str=new String(buffer); System.out.println(str); try { //espera la pulsación de una tecla y luego RETORNO System.in.read(); }catch (Exception e) { } } }

8.4. ENTRADA/SALIDA A UN ARCHIVO EN DISCO

8.4.1. LECTURA DE UN ARCHIVO

El proceso de lectura de un archivo de texto es similar a la lectura desde el dispositivo estándar. Creamos un objeto entrada de la clase FileReader en vez de InputStreamReader. El final del archivo viene dado cuando la función read devuelve -1. El resto del código es similar.

FileReader entrada=null; StringBuffer str=new StringBuffer();

282 Mg. ABRAHAM GAMARRA MORENO

try { entrada=new FileReader("mensaje.txt"); int c; while((c=entrada.read())!=-1) { str.append((char)c); } }catch (IOException ex) {}

Para mostrar el archivo de texto en la panta-lla del monitor, se imprime el contenido del objeto str de la clase StringBuffer.

System.out.println(str);

Una vez concluído el proceso de lectura, es conveniente cerrar el flujo de datos, esto se realiza en una claúsula finally que siempre se llama independientemente de que se produz-can o no errores en el proceso de lectu-ra/escritura.

finally { if(entrada!=null) { try { entrada.close(); }catch(IOException ex){} } }

El código completo de este ejemplo es el si-guiente:

Ejemplo (67): Programa completo para la lec-tura de un archivo de texto.

// Archivo: ArchivoApp2.java import java.io.*; public class ArchivoApp2 { public static void main(String[] args) { FileReader entrada=null; StringBuffer str=new StringBuffer();

PROGRAMACION CON JAVA 2 283

try { entrada=new FileReader("mensaje.txt"); int c; while((c=entrada.read())!=-1) { str.append((char)c); } System.out.println(str); System.out.println("--------------------------------------"); }catch (IOException ex) { System.out.println(ex); } finally { //cerrar los flujos de datos if(entrada!=null) { try { entrada.close(); }catch(IOException ex){} } System.out.println("el bloque finally siempre se ejecuta"); } } }

8.4.2. LECTURA/ESCRITURA

Los pasos para leer y escribir en disco son los siguientes:

• Se crean dos objetos de las clases File-Reader y FileWriter, llamando a los res-pectivos constructores a los que se les pasa los nombres de los archivos o bien, objetos de la clase File, respectivamen-te

entrada=new FileReader("mensaje.txt"); salida=new FileWriter("copia.txt");

• Se lee mediante read los caracteres del flujo de entrada, hasta llegar al final (la función read devuelve entonces -1), y se escribe dichos caracteres en el flujo de salida mediante write.

284 Mg. ABRAHAM GAMARRA MORENO

while((c=entrada.read())!=-1) { salida.write(c); }

• Finalmente, se cierran ambos flujos lla-mando a sus respectivas funciones close en bloques try..catch

entrada.close(); salida.close();

El código completo de este ejemplo que crea un archivo copia del original, es el siguien-te:

Ejemplo (68): Programa completo para realizar la copia de un archivo de texto a otro.

// Archivo: ArchivoApp3.java import java.io.*; public class ArchivoApp3 { public static void main(String[] args) { FileReader entrada=null; FileWriter salida=null; //FileInputStream entrada=null; //FileOutputStream salida=null; try { entrada=new FileReader("mensaje.txt"); salida=new FileWriter("copia.txt"); //entrada=new FileInputStream("mensaje.txt"); //salida=new FileOutputStream("copia.txt"); int c; while((c=entrada.read())!=-1) { salida.write(c); } } catch (IOException ex) { System.out.println(ex); } finally { //cerrar los flujos de datos if(entrada!=null) { try { entrada.close();

PROGRAMACION CON JAVA 2 285

}catch(IOException ex){} } if(salida!=null) { try { salida.close(); }catch(IOException ex){} } System.out.println("el bloque finally siempre se ejecuta"); } } }

Cuando se trate de leer y escribir datos bi-narios se sustituye FileReader por FileIn-putStream y FileWriter por FileOutputStream. De hecho, si se realiza esta sustitución en el código fuente de este ejemplo, los resul-tados no cambian.

8.5. LEER Y ESCRIBIR DATOS PRIMITIVOS

8.5.1. LOS FLUJOS DE DATOS DATAINPUTSTREAM Y DATAOUTPUTSTREAM

La clase DataInputStream es útil para leer datos del tipo primitivo de una forma porta-ble. Esta clase tiene un sólo constructor que toma un objeto de la clase InputStream o sus derivadas como parámetro.

Se crea un objeto de la clase DataInputStream vinculándolo a un objeto FileInputStream para leer desde un archivo en disco denominado pe-dido.txt.

FileInputStream fileIn=new FileInputStream("pedido.txt"); DataInputStream entrada=new DataInputStream(fileIn));

o en una sola línea

DataInputStream entrada=new DataInputStream(new FileInputStream("pedido.txt"));

La clase DataInputStream define diversos mé-todos readXXX que son variaciones del método

286 Mg. ABRAHAM GAMARRA MORENO

read de la clase base para leer datos de tipo primitivo

boolean readBoolean();

byte readByte();

int readUnsignedByte();

short readShort();

int readUnsignedShort();

char readChar();

int readInt();

String readLine();

long readLong();

float readFloat();

double readDouble();

La clase DataOutputStream es útil para escri-bir datos del tipo primitivo de una forma portable. Esta clase tiene un sólo construc-tor que toma un objeto de la clase OutputS-tream o sus derivadas como parámetro.

Se crea un objeto de la clase DataOutputS-tream vinculándolo a un un objeto FileOut-putStream para escribir en un archivo en dis-co denominado pedido.txt..

FileOutputStream fileOut=new FileOutputStream("pedido.txt"); DataOutputStream salida=new DataOutputStream(fileOut));

o en una sola línea

DataOutputStream salida=new DataOutputStream(new FileOutputStream("pedido.txt"));

La clase DataOutputStream define diversos mé-todos writeXXX que son variaciones del método

PROGRAMACION CON JAVA 2 287

write de la clase base para escribir datos de tipo primitivo

void writeBoolean(boolean v);

void writeByte(int v);

void writeBytes(String s);

void writeShort(int v);

void writeChars(String s);

void writeChar(int v);

void writeInt(int v);

void writeLong(long v);

void writeFloat(float v);

void writeDouble(double v);

8.5.2. EJEMPLO: UN PEDIDO

En este ejemplo, se escriben datos a un ar-chivo y se leen del mismo, que corresponden a un pedido

• La descripción del item, un objeto de la clase String

• El número de unidades, un dato del tipo primitivo int

• El precio de cada item, un dato de tipo double.

Observamos en la tabla y en el código el nom-bre de las funciones que leen y escriben los distintos tipos de datos.

Escritura Lectura Un carácter writeChar readChar Un entero writeInt readInt Un número de-cimal writeDouble readDouble

Un string writeChars readLine

288 Mg. ABRAHAM GAMARRA MORENO

Veamos el código que escribe los datos a un archivo pedido.txt en disco

• Se parte de los datos que se guardan en los arrays denominados descripciones, unidades y precios

• Se crea un objeto de la clase DataOut-putStream vinculándolo a un un objeto FileOutputStream para escribir en un ar-chivo en disco denominado pedido.txt.

• Se escribe en el flujo de salida los distintos datos llamando a las distintas versiones de la función writeXXX según el tipo de dato (segunda columna de la tabla).

• Se cierra el flujo de salida, llamando a su función miembro close.

double[] precios={1350, 400, 890, 6200, 8730}; int[] unidades={5, 7, 12, 8, 30}; String[] descripciones={"paquetes de papel", "lápices", "bolí-grafos", "carteras", "mesas"}; DataOutputStream salida=new DataOutputStream(new FileOutput-Stream("pedido.txt")); for (int i=0; i<precios.length; i ++) { salida.writeChars(descripciones[i]); salida.writeChar('\n'); salida.writeInt(unidades[i]); salida.writeChar('\t'); salida.writeDouble(precios[i]); } salida.close();

Para leer bien los datos, el string ha de se-pararse del siguiente dato con un carácter nueva línea '\n'. Esto no es necesario si el string se escribe en el último lugar, después de los números. Por otra parte, el carácter tabulador como separador no es estrictamente necesario.

Veamos el código que lee los datos a un ar-chivo pedido.txt en disco

PROGRAMACION CON JAVA 2 289

• Se crea un objeto de la clase DataIn-putStream vinculándolo a un un objeto FileInputStream para leer en un archivo en disco denominado pedido.txt.

• Se lee el flujo de entrada los distintos datos en el mismo orden en el que han sido escritos, llamando a las distintas versiones de la función readXXX según el tipo de dato (tercera columna de la ta-bla).

• Se guardan los datos leídos en memoria en las variables denominadas descrip-cion, unidad y precio y se usan para distintos propósitos

• Se cierra el flujo de entrada, llamando a su función miembro close.

double precio; int unidad; String descripcion; double total=0.0; DataInputStream entrada=new DataInputStream(new FileInputStream("pedido.txt")); try { while ((descripcion=entrada.readLine())!=null) { unidad=entrada.readInt(); entrada.readChar(); //lee el carácter tabulador precio=entrada.readDouble(); System.out.println("has pedido "+unidad+" "+descripcion+" a "+precio+" soles."); total=total+unidad*precio; } }catch (EOFException e) {} System.out.println("por un TOTAL de: "+total+" soles."); entrada.close();

Como vemos en esta porción de código, según se van leyendo los datos del archivo, se im-primen y se calcula el precio total del pedi-do.

System.out.println("has pedido "+unidad+" "+descripcion+" a "+precio+" soles."); total=total+unidad*precio;

290 Mg. ABRAHAM GAMARRA MORENO

8.5.3. EL FINAL DEL ARCHIVO

El final del archivo se detecta cuando la función readLine devuelve null. Alternativamente, cuando se alcanza el final del archivo se produce una excepción del tipo EOFException. Podemos comprobarlo del siguiente modo, si escribimos la siguiente porción de código

try { while(true) { descripcion=entrada.readLine(); unidad=entrada.readInt(); entrada.readChar(); //lee el carácter tabulador precio=entrada.readDouble(); System.out.println("has pedido "+unidad+" "+descripcion+" a "+precio+" soles."); total=total+unidad*precio; } }catch (EOFException e) { System.out.println("Excepción cuando se alcanza el final del archivo"); }

Cuando se alcanza el final del archivo se produce una excepción del tipo EOFException que interrumpe la ejecución del bucle indefi-nido al ser capturada por el correspondiente bloque catch, el cual imprime en la pantalla el mensaje "Excepción cuando se alcanza el final del archivo".

Si escribimos la siguiente porción de código

try { while ((descripcion=entrada.readLine())!=null) { unidad=entrada.readInt(); entrada.readChar();//lee el carácter tabulador precio=entrada.readDouble(); System.out.println("has pedido "+unidad+" "+descripcion+" a "+precio+" soles."); total=total+unidad*precio; } System.out.println("Final del archivo"); }catch (EOFException e)

PROGRAMACION CON JAVA 2 291

{ System.out.println("Excepción cuando se alcanza el final del archivo"); }

Se imprime "Final de archivo" ya que cuando readLine toma el valor null (no hay más que leer) se sale del bucle while, y por tanto, no se lanza ninguna excepción.

Ejemplo (69): Programa completo para leer y escribir datos primitivos.

//Archivo: ArchivoApp7.java import java.io.*; public class ArchivoApp7 { public static void main(String[] args) throws IOException { // escribe los datos DataOutputStream salida=new DataOutputStream(new FileOut-putStream("pedido.txt")); double[] precios={1350, 400, 890, 6200, 8730}; int[] unidades={5, 7, 12, 8, 30}; String[] descripciones={"paquetes de papel", "lapices", "boligrafos", "carteras", "mesas"}; for (int i=0; i<precios.length; i ++) { salida.writeChars(descripciones[i]); salida.writeChar('\n'); salida.writeInt(unidades[i]); salida.writeChar('\t'); salida.writeDouble(precios[i]); } salida.close(); //leer los datos del archivo DataInputStream entrada=new DataInputStream(new FileIn-putStream("pedido.txt")); double precio; int unidad; String descripcion; double total=0.0; try { //while(true) while ((descripcion=entrada.readLine())!=null) { //descripcion=entrada.readLine(); unidad=entrada.readInt(); entrada.readChar();//lee el carácter tabulador precio=entrada.readDouble();

292 Mg. ABRAHAM GAMARRA MORENO

System.out.println("has pedido "+unidad+" "+descripcion+" a "+precio+" Soles."); total=total+unidad*precio; } System.out.println("Final del archivo"); } catch (EOFException e) { System.out.println("Excepción cuando se alcanza el fi-nal del archivo"); } System.out.println("por un TOTAL de: "+total+" soles."); entrada.close(); } }

8.6. LEER Y ESCRIBIR OBJETOS

Java ha añadido una interesante faceta al lenguaje de-nominada serialización de objetos que permite conver-tir cualquier objeto cuya clase implemente el interfa-ce Serializable en una secuencia de bytes que pueden ser posteriormente leídos para restaurar el objeto original. Esta característica se mantiene incluso a través de la red, por lo que podemos crear un objeto en un ordenador que corra bajo Windows 95/98, seriali-zarlo y enviarlo a través de la red a una estación de trabajo que corra bajo UNIX donde será correctamente reconstruido. No tenemos que procuparnos, en absoluto, de las diferentes representaciones de datos en los distintos ordenadores.

La serialización es una característica añadida al len-guaje Java para dar soporte a

• La invocación remota de objetos (RMI)

• La persistencia

PROGRAMACION CON JAVA 2 293

La invocación remota de objetos permite a los objetos que viven en otros ordenadores comportarse como si vi-vieran en nuestra propia máquina. La serialización es necesaria para transportar los argumentos y los valo-res de retorno.

La persistencia, es una característica importante de los JavaBeans. El estado de un componente es configu-rado durante el diseño. La serialización nos permite guardar el estado de un componente en disco, abandonar el Entorno Integrado de Desarrollo (IDE) y restaurar el estado de dicho componente cuando se vuelve a co-rrer el IDE.

8.6.1. EL INTERFACE SERIALIZABLE

Un objeto se puede serializar si implementa el interface Serializable. Este interface no declara ninguna función miembro, se trata de un interface vacío.

import java.io.*; public interface Serializable { }

Para hacer una clase serializable simplemente ha de implementar el interface Serializable, por ejemplo, si se tiene la clase Lista, se añade la implementación del interface

public class Lista implements java.io.Serializable { private int[] x; private int n; //otros miembros... }

No tenemos que escribir ningún otro método. El método defaultWriteObject de la clase Ob-jectOutputStream realiza la serialización de los objetos de una clase. Este método escribe en el flujo de salida todo lo necesario para reconstruir dichos objetos:

• La clase del objeto

• La firma de la clase (class signature)

294 Mg. ABRAHAM GAMARRA MORENO

• Los valores de los miembros que no ten-gan los modificadores static o tran-sient, incluyendo los miembros que se refieren a otros objetos.

El método defaultReadObject de la clase Ob-jectInputStream realiza la deserialización de los objetos de una clase. Este método lee el flujo de entrada y reconstruye los objetos de dicha clase.

8.6.2. LECTURA/ESCRITURA

Dos flujos de datos ObjectInputStream y Ob-jectOutputStream están especializados en la lectura y escritura de objetos. El comporta-miento de estos dos flujos es similar a sus correspondientes que procesan flujos de datos primitivos DataInputStream y DataOutputS-tream.

Escribir objetos al flujo de salida ObjectOutputStream es muy simple y requiere los siguientes pasos:

• Creamos un objeto de la clase Lista

Lista lista1= new Lista(new int[]{12, 15, 11, 4, 32});

• Creamos un flujo de salida a disco, pa-sándole el nombre del archivo en disco o un objeto de la clase File.

FileOutputStream fileOut=new FileOutputStream("media.obj");

• El flujo de salida ObjectOutputStream es el que procesa los datos y se ha de vin-cular a un objeto fileOut de la clase FileOutputStream .

ObjectOutputStream salida=new ObjectOutputStream(fileOut); o en una sóla línea ObjectOutputStream salida=new ObjectOutputStream(new FileOutputStream("media.obj"));

PROGRAMACION CON JAVA 2 295

• El método writeObject escribe los obje-tos al flujo de salida y los guarda en un archivo en disco. Por ejemplo, un string y un objeto de la clase Lista.

salida.writeObject("guardar este string y un objeto\n"); salida.writeObject(lista1);

• Finalmente, se cierran los flujos

salida.close();

Lista lista1= new Lista(new int[]{12, 15, 11, 4, 32}); ObjectOutputStream salida=new ObjectOutputStream(new FileOutputStream("media.obj")); salida.writeObject("guardar este string y un objeto\n"); salida.writeObject(lista1); salida.close();

El proceso de lectura es paralelo al proceso de escritura, por lo que leer objetos del flujo de entrada ObjectInputStream es muy simple y requiere los siguientes pasos:

• Creamos un flujo de entrada a disco, pa-sándole el nombre del archivo en disco o un objeto de la clase File.

FileInputStream fileIn=new FileInputStream("media.obj");

• El flujo de entrada ObjectInputStream es el que procesa los datos y se ha de vin-cular a un objeto fileIn de la clase Fi-leInputStream.

ObjectInputStream entrada=new ObjectInputStream(fileIn); o en una sóla línea

ObjectInputStream entrada=new ObjectInputStream(new FileInputStream("media.obj"));

296 Mg. ABRAHAM GAMARRA MORENO

• El método readObject lee los objetos del flujo de entrada, en el mismo orden en el que ha sido escritos. Primero un string y luego, un objeto de la clase Lista.

String str=(String)entrada.readObject(); Lista obj1=(Lista)entrada.readObject();

• Se realizan tareas con dichos objetos, por ejemplo, desde el objeto obj1 de la clase Lista se llama a la función miem-bro valorMedio, para hallar el valor me-dio del array de datos, o se muestran en la pantalla

System.out.println("Valor medio "+obj1.valorMedio()); System.out.println("-----------------------------"); System.out.println(str+obj1);

• Finalmente, se cierra los flujos

entrada.close();

ObjectInputStream entrada=new ObjectInputStream(new FileInputStream("media.obj")); String str=(String)entrada.readObject(); Lista obj1=(Lista)entrada.readObject(); System.out.println("Valor medio "+obj1.valorMedio()); System.out.println("-----------------------------"); System.out.println(str+obj1); System.out.println("-----------------------------"); entrada.close();

Ejemplo(70): Programa completo de la lectura/escritura del objeto de la clase lista

//Archivo: Lista.java public class Lista implements java.io.Serializable { private int[] x; //array de datos private int n; //dimensión public Lista(int[] x) { this.x=x; n=x.length; ordenar(); }

PROGRAMACION CON JAVA 2 297

public double valorMedio() { int suma=0; for(int i=0; i<n; i++) { suma+=x[i]; } return (double)suma/n; } public int valorMayor() { return x[n-1]; } public int valorMenor() { return x[0]; } private void ordenar() { int aux; for(int i=0; i<n-1; i++) { for(int j=i+1; j<n; j++) { if(x[i]>x[j]) { aux=x[j]; x[j]=x[i]; x[i]=aux; } } } } public String toString() { String texto=""; for(int i=0; i<n; i++) { texto+="\t"+x[i]; } return texto; } }

// Archivo: ArchivoApp4.java import java.io.*; import java.util.*; public class ArchivoApp4 { public static void main(String[] args) {

298 Mg. ABRAHAM GAMARRA MORENO

Lista lista1= new Lista(new int[]{12, 15, 11, 4, 32}); try { ObjectOutputStream salida=new ObjectOutputStream(new FileOutputStream("media.obj")); salida.writeObject("guardar este string y un objeto\n"); salida.writeObject(lista1); salida.close(); ObjectInputStream entrada=new ObjectInputStream(new FileInputStream("media.obj")); String str=(String)entrada.readObject(); Lista obj1=(Lista)entrada.readObject(); System.out.println("Valor medio "+obj1.valorMedio()); System.out.println("-----------------------------"); System.out.println(str+obj1); System.out.println("-----------------------------"); entrada.close(); //se puede fundir en una catch Exception }catch (IOException ex) { System.out.println(ex); }catch (ClassNotFoundException ex) { System.out.println(ex); } } }

8.6.3. EL MODIFICADOR TRANSIENT

Cuando un miembro dato de una clase contiene información sensible, hay disponibles varias técnicas para protegerla. Incluso cuando di-cha información es privada (el miembro dato tiene el modificador private) una vez que se ha enviado al flujo de salida alguien puede

PROGRAMACION CON JAVA 2 299

leerla en el archivo en disco o interceptarla en la red.

El modo más simple de proteger la información sensible, como una contraseña (password) es la de poner el modificador transient delante del miembro dato que la guarda.

La clase Cliente tiene dos miembros dato, el nombre del cliente y la contraseña o pass-word.

Redefine la función toString miembro de la clase base Object. Esta función devolverá el nombre del cliente y la contraseña. En el ca-so de que el miembro password guarde el valor null se imprimirá el texto (no disponible).

En el cuadro que sigue se muestra el código que define la clase Cliente.

public class Cliente implements java.io.Serializable { private String nombre; private transient String passWord; public Cliente(String nombre, String pw) { this.nombre=nombre; passWord=pw; } public String toString() { String texto=(passWord==null) ? "(no disponible)" : pass-Word; texto+=nombre; return texto; } }

En el cuadro siguiente se muestra los pasos para guardar un objeto de la clase Cliente en el archivo cliente.obj. Posterioremente, se lee el archivo para reconstruir el objeto obj1 de dicha clase.

• Se crea el objeto cliente de la clase Cliente pasándole el nombre del cliente "Angel" y la contraseña "xyz".

• Se crea un flujo de salida (objeto salida de la clase ObjectOutputStream) y se asocia con un objeto de la clase

300 Mg. ABRAHAM GAMARRA MORENO

FileOutputStream para guardar la información en el archivo cliente.obj.

• Se escribe el objeto cliente en el flujo de salida mediante writeObject.

• Se cierra el flujo de salida llamando a close.

Cliente cliente=new Cliente("Angel", "xyz"); ObjectOutputStream salida=new ObjectOutputStream(new FileOutputStream("cliente.obj")); salida.writeObject("Datos del cliente\n"); salida.writeObject(cliente); salida.close();

Para reconstruir el objeto obj1 de la clase Cliente se procede del siguiente modo:

• Se crea un flujo de entrada (objeto en-trada de la clase ObjectInputStream) y se asocia con un objeto de la clase Fi-leInputStream para leer la información que gurada el archivo cliente.obj.

• Se lee el objeto cliente en el flujo de salida mediante readObject.

• Se imprime en la pantalla dicho objeto llamando implícitamente a su función miembro toString.

• Se cierra el flujo de entrada llamando a close.

ObjectInputStream entrada=new ObjectInputStream(new FileInputStream("cliente.obj")); String str=(String)entrada.readObject(); Cliente obj1=(Cliente)entrada.readObject(); System.out.println("------------------------------"); System.out.println(str+obj1); System.out.println("------------------------------"); entrada.close();

Ejemplo(71): Programa completo del uso del modificador transient.

PROGRAMACION CON JAVA 2 301

// Archivo: Cliente.java public class Cliente implements java.io.Serializable { private String nombre; private transient String passWord; public Cliente(String nombre, String pw) { this.nombre=nombre; passWord=pw; } public String toString() { String texto=(passWord==null) ? "(no disponible)" : pass-Word; texto+=nombre; return texto; } }

// Archivo: ArchivoApp6.java import java.io.*; public class ArchivoApp6 { public static void main(String[] args) { Cliente cliente=new Cliente("Angel", "xyz"); try { ObjectOutputStream salida=new ObjectOutput-Stream(new FileOutputStream("cliente.obj")); salida.writeObject("Datos del cliente\n"); salida.writeObject(cliente); salida.close(); ObjectInputStream entrada=new ObjectInputStream(new FileInputStream("cliente.obj")); String str=(String)entrada.readObject(); Cliente obj1=(Cliente)entrada.readObject(); System.out.println("------------------------------"); System.out.println(str+obj1); System.out.println("------------------------------"); entrada.close(); //se puede fundir en una catch Exception } catch (IOException ex) { System.out.println(ex); } catch (ClassNotFoundException ex)

302 Mg. ABRAHAM GAMARRA MORENO

{ System.out.println(ex); } } }

La salida del programa es

Lo que nos indica que la información sensible guardada en el miembro dato password que tie-ne por modificador transient no ha sido guar-dada en el archivo. En la reconstrucción del objeto obj1 con la información guardada en el archivo el miembro dato password toma el va-lor null.

8.6.4. OBJETOS COMPUESTOS

Volvemos de nuevo al estudio de la clase Rec-tangulo que contiene un subobjeto de la clase Punto.

A dichas clases se les ha añadido la redefi-nición de la función toString miembro de la clase base Object (esta redefinición no es necesaria aunque es ilustrativa para explicar el comportamiento de un objeto compuesto). Como podemos apreciar, ambas clases implemen-tan el interface Serializable.

En el cuadro que sigue se muestra parte del código que define la clase Punto.

public class Punto implements java.io.Serializable { private int x; private int y; //otros miembros... public String toString() { return new String("("+x+", "+y+")"); } }

PROGRAMACION CON JAVA 2 303

La definición de la clase Rectangulo se mues-tra en el siguiente cuadro

public class Rectangulo implements java.io.Serializable { private int ancho ; private int alto ; private Punto origen; //otras funciones miembro... public String toString() { String texto=origen+" w:"+ancho+" h:"+alto; return texto; } }

Como podemos observar, en la definición de toString de la clase Rectangulo se hace una llamada implícita a la función toString miem-bro de la clase Punto. La composición como se ha estudiado permite reutilizar el código existente.

Para guardar en un archivo un objeto de la clase Rectangulo hay que seguir los mismos pasos que para guardar un objeto de la clase Lista o de la clase Cliente.

Rectangulo rect=new Rectangulo(new Punto(10,10), 30, 60); ObjectOutputStream salida=new ObjectOutputStream(new FileOutputStream("figura.obj")); salida.writeObject("guardar un objeto compuesto\n"); salida.writeObject(rect); salida.close();

Para reconstruir un objeto de la clase Rec-tangulo a partir de los datos guardados en el archivo hay que seguir los mismos pasos que en los dos ejemplos previos.

ObjectInputStream entrada=new ObjectInputStream(new FileInputStream("figura.obj")); String str=(String)entrada.readObject(); Rectangulo obj1=(Rectangulo)entrada.readObject(); System.out.println("------------------------------"); System.out.println(str+obj1); System.out.println("------------------------------"); entrada.close();

304 Mg. ABRAHAM GAMARRA MORENO

En el caso de que nos olvidemos de implemen-tar el interface Serializable en la clase Punto que describe el subobjeto de la clase Rectangulo, se lanza una excepción, impri-miéndose en la consola.

java.io.NotSerializableException: archivo5.Punto.

Ejemplo(72): Programa completo de escribir/leer obje-tos compuestos.

//Archivo: Punto.java public class Punto implements java.io.Serializable { private int x; private int y; public Punto(int x, int y) { this.x = x; this.y = y; } public Punto() { x=0; y=0; } public void desplazar(int dx, int dy) { x+=dx; y+=dy; } public String toString() { return new String("("+x+", "+y+")"); } } //Archivo: Rectangulo.java public class Rectangulo implements java.io.Serializable { private int ancho ; private int alto ; private Punto origen; public Rectangulo() { origen = new Punto(0, 0); ancho=0; alto=0; }

PROGRAMACION CON JAVA 2 305

public Rectangulo(Punto p) { this(p, 0, 0); } public Rectangulo(int w, int h) { this(new Punto(0, 0), w, h); } public Rectangulo(Punto p, int w, int h) { origen = p; ancho = w; alto = h; } public void desplazar(int dx, int dy) { origen.desplazar(dx, dy); } public int calcularArea() { return ancho * alto; } public String toString() { String texto=origen+" w:"+ancho+" h:"+alto; return texto; } } // Archivo: ArchivoApp5.java import java.io.*; public class ArchivoApp5 { public static void main(String[] args) { Rectangulo rect=new Rectangulo(new Punto(10,10), 30, 60); try { ObjectOutputStream salida=new ObjectOutput-Stream(new FileOutputStream("figura.obj")); salida.writeObject("guardar un objeto compues-to\n"); salida.writeObject(rect); salida.close(); ObjectInputStream entrada=new ObjectInputStream(new FileInputStream("figura.obj")); String str=(String)entrada.readObject();

306 Mg. ABRAHAM GAMARRA MORENO

Rectangulo obj1=(Rectangulo)entrada.readObject(); System.out.println("------------------------------"); System.out.println(str+obj1); System.out.println("------------------------------"); entrada.close(); //se puede fundir en una catch Exception } catch (IOException ex) { System.out.println(ex); } catch (ClassNotFoundException ex) { System.out.println(ex); } } }

8.6.5. LA HERENCIA

En el apartado anterior hemos examinado la composición, ahora examinemos la herencia. En el capítulo de la herencia examinamos una je-rarquía formada por una clase base denominada Figura y dos clases derivadas denominadas Circulo y Rectangulo.

Como podemos observar en el cuadro adjunto se han hecho dos modificaciones. La clase base Figura implementa el interface Serializable y en la clase Circulo en vez de usar el número PI proporcionado por la clase Math, definimos una constante estática PI con una aproxima-ción de 4 decimales. De este modo probamos el comportamiento de un miembro estático en el proceso de serialización.

Para serializar objetos de una jerarquía so-lamente la clase base tiene que implementar el interface Serializable

PROGRAMACION CON JAVA 2 307

public abstract class Figura implements java.io.Serializable { protected int x; protected int y; public Figura(int x, int y) { this.x=x; this.y=y; } public abstract double area(); } class Circulo extends Figura { protected double radio; private static final double PI=3.1416; public Circulo(int x, int y, double radio) { super(x,y); this.radio=radio; } public double area() { return PI*radio*radio; } } class Rectangulo extends Figura { protected double ancho, alto; public Rectangulo(int x, int y, double ancho, double alto) { super(x,y); this.ancho=ancho; this.alto=alto; } public double area() { return ancho*alto; } }

Vamos a serializar dos objetos uno de la cla-se Rectangulo y otro de la clase Circulo, y a continuación reconstruiremos dichos objetos. Una vez de que dispongamos de los objetos llamaremos a las funciones area para calcular el área de cada una de las figuras.

Para guardar en el archivo figura.obj un ob-jeto fig1 de la clase Rectangulo y otro obje-to fig2 de la clase Circulo, se siguen los mismos pasos que hemos estudiado en apartados anteriores

308 Mg. ABRAHAM GAMARRA MORENO

Figura fig1=new Rectangulo(10,15, 30, 60); Figura fig2=new Circulo(12,19, 60); ObjectOutputStream salida=new ObjectOutputStream(new FileOutputStream("figura.obj")); salida.writeObject("guardar un objeto de una clase derivada\n"); salida.writeObject(fig1); salida.writeObject(fig2); salida.close();

Fijarse que fig1 y fig2 son dos referencias de la clase base Figura en la que se guardan objetos de las clases derivadas Rectangulo y Circulo, respectivamente

Para leer los datos guardados en el archivo figura.obj y reconstruir dos objetos obj1 y obj2 de las clases Rectangulo y Circulo res-pectivamente, se procede de forma similar a la estudiada en los apartados previos.

ObjectInputStream entrada=new ObjectInputStream(new FileInputStream("figura.obj")); String str=(String)entrada.readObject(); Figura obj1=(Figura)entrada.readObject(); Figura obj2=(Figura)entrada.readObject(); System.out.println("------------------------------"); System.out.println(obj1.getClass().getName()+" origen ("+obj1.x+", "+obj1.y+")"+" area="+obj1.area()); System.out.println(obj2.getClass().getName()+" origen ("+obj2.x+", "+obj2.y+")"+" area="+obj2.area()); System.out.println("------------------------------"); entrada.close();

Fijarse que obj1 y obj2 son referencias a la clase base Figura. Sin embargo, cuando obj1 llama a la función area nos devuelve (correc-tamente) el área del rectángulo y cuando, obj2 llama a la función area devuelve el área del círculo.

Fijarse también que aunque PI es un miembro estático de la clase Circulo, se reconstruye el objeto obj2 con el valor del miembro está-tico con el que se calcula el área del círcu-lo.

PROGRAMACION CON JAVA 2 309

Ejemplo (73): Programa completo de escribir/leer obje-tos con herencia.

// Archivo: Figura.java public abstract class Figura implements java.io.Serializable { protected int x; protected int y; public Figura(int x, int y) { this.x=x; this.y=y; } public abstract double area(); } class Circulo extends Figura { protected double radio; private static final double PI=3.1416; public Circulo(int x, int y, double radio) { super(x,y); this.radio=radio; } public double area() { return PI*radio*radio; } } class Rectangulo extends Figura { protected double ancho, alto; public Rectangulo(int x, int y, double ancho, double alto) { super(x,y); this.ancho=ancho; this.alto=alto; } public double area() { return ancho*alto; } }

310 Mg. ABRAHAM GAMARRA MORENO

// Archivo: ArchivoApp8.java import java.io.*; public class ArchivoApp8 { public static void main(String[] args) { Figura fig1=new Rectangulo(10,15, 30, 60); Figura fig2=new Circulo(12,19, 60); try { ObjectOutputStream salida=new ObjectOutputStream(new FileOutputStream("figura.obj")); salida.writeObject("guardar un objeto de una clase derivada\n"); salida.writeObject(fig1); salida.writeObject(fig2); salida.close(); ObjectInputStream entrada=new ObjectInputStream(new FileInputStream("figura.obj")); String str=(String)entrada.readObject(); Figura obj1=(Figura)entrada.readObject(); Figura obj2=(Figura)entrada.readObject(); System.out.println("------------------------------"); System.out.println(obj1.getClass().getName()+" origen ("+obj1.x+", "+obj1.y+")"+" area="+obj1.area()); System.out.println(obj2.getClass().getName()+" origen ("+obj2.x+", "+obj2.y+")"+" area="+obj2.area()); System.out.println("------------------------------"); entrada.close(); //se puede fundir en una catch Exception } catch (IOException ex) { System.out.println(ex); } catch (ClassNotFoundException ex) { System.out.println(ex); } } }

PROGRAMACION CON JAVA 2 311

8.6.6. SERIALIZACIÓN PERSONALIZADA

El proceso de serialización proporcionado por el lenguaje Java es suficiente para la mayor parte de las clases, ahora bien, se puede personalizar para aquellos casos específicos.

Para personalizar la serialización, es necesario definir dos funciones miembros writeObject y readObject. El primero, controla que información es enviada al flujo de salida. La segunda, lee la información escrita por writeObject .

La definición de writeObject ha de ser la si-guiente

private void writeObject (ObjectOutputStream s) throws IOException { s.defaultWriteObject(); //...código para escribir datos }

La función readObject ha de leer todo lo que se ha escrito con writeObject en el mismo or-den en el que se ha escrito. Además, puede realizar otras tareas necesarias para actua-lizar el estado del objeto.

private void readObject (ObjectInputStream s) throws IOException { s.defaultReadObject(); //...código para leer datos //... //actualización del estado del objeto, si es necesario }

Para un control explícito del proceso de se-rialización la clase ha de implementar el in-terface Externalizable. La clase es responsa-

312 Mg. ABRAHAM GAMARRA MORENO

ble de escribir y de leer su contenido, y ha de estar coordinada con sus clases base para hacer esto.

La definición del interface Externalizable es la siguiente

package java.io; 1 public interface Externalizable extends Serializable { public void writeExternal(ObjectOutput out) throws IOException; public void readExternal(ObjectOutput in) throws IOException, java.lang.ClassNotFoundException;; }

PROGRAMACION CON JAVA 2 313

CAPITULO NUEVE

APPLETS

En este capítulo vamos a tratar de ver todo lo que necesita-mos para saber escribir un applet Java. Dado que los applets pueden usar una gran cantidad de clases del API de Java, ve-remos muchas características que no hemos explicado en forma completa, las cuales iremos aprendiendo junto a los applets.

9.1. DEFINICIÓN DE APPLET El lenguaje Java se puede usar para crear dos tipos de programas: los applets y las aplicaciones. Un applet es un elemento más de una página web, como una imagen o una porción de texto. Cuando el navegador carga la página web, el applet insertado en dicha página se carga y se ejecuta.

Mientras que un applet puede transmitirse por la red Internet una aplicación reside en el disco duro local. Una aplicación Java es como cualquier otra que está instalada en el ordenador. La otra diferencia es que un applet no está autorizado a acceder a archivos o directorios del ordenador cliente si no es un applet completamente fiable.

La definición más extendida de applet, es que un ap-plet es "una pequeña aplicación accesible en un servi-dor de Internet, que se transporta por la red, se ins-tala automáticamente y se ejecuta in situ como parte

314 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

de un documento web". Claro que así la definición es-tablece el entorno (Internet, Web, etc.). En realidad, un applet es una aplicación pretendidamente corta (na-da impide que ocupe más de un gigabyte, a no ser el pensamiento de que se va a transportar por la red) ba-sada en un formato gráfico sin representación indepen-diente: es decir, se trata de un elemento a incluir en otras aplicaciones; es un componente en su sentido es-tricto.

9.2. EL APPLET MÍNIMO Lo primero que apreciamos a continuación es que la nueva clase Applet1 deriva de la clase base Applet

public class Applet1 extends Applet { //... }

Y en segundo lugar, que tiene un método denominado init, que se llama cuando se carga el applet en el na-vegador.

public class Applet1 extends Applet { public void init() { //... } }

9.3. EL PRIMER APPLET Para crear un applet tenemos que definir una clase de-nominada Applet1 derivada de Applet. La primera sen-tencia import nos proporciona información acerca de las clases del paquete applet. Dicho paquete contiene las clases necesarias para crear applets que se ejecu-tan en la ventana del navegador, entre las cuales está la clase base Applet.

import java.applet.*; public class Applet1 extends Applet { }

PROGRAMACION CON JAVA 2 315

El siguiente paso es dar funcionalidad a la clase, de-finir nuestras propias funciones miembro o redefinir funciones de la clase base Applet.

Definimos la función init para establecer el color de fondo del applet mediante setBackground. La función init se llama cuando se carga el applet.

public class Applet1 extends Applet { public void init() { setBackgroung(Color.cyan); } //... }

A continuación, vamos a mostrar un mensaje, para ello definimos el método paint. El método paint nos sumi-nistra el contexto gráfico g, un objeto de la clase Graphics con el cual podemos dibujar en el área de trabajo del componente llamando desde dicho objeto g a las funciones definidas en la clase Graphics.

Para mostrar un mensaje, llamamos desde el objeto g a la función miembro drawString, el primer argumento es el string que deseamos mostrar, y los dos números in-dican las coordendas de la línea base del primer ca-rácter.

import java.applet.*; public class Applet1 extends Applet { public void init() { setBackgroung(Color.cyan); } public void paint(Graphics g) { g.drawString("Primer applet", 10, 10); } }

Un applet, no es como una aplicación que tiene un mé-todo main. El applet está insertado en una página web que se muestra en la ventana del navegador. El navega-dor toma el control del applet llamando a algunos de sus métodos, uno de estos es el método paint que se

316 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

llama cada vez que se necesita mostrar el applet en la ventana del navegador.

Cuando el applet se carga, el navegador llama a su mé-todo init. En este método el programador realiza ta-reas de inicialización, por ejemplo, establecer las propiedades de los controles, disponerlos en el ap-plet, cargar imágenes, etc.

El método init se llama una sóla vez. Después, el na-vegador llama al método paint.

A continuación, se llama al método start. Este método se llama cada vez que se accede a la página que con-tiene el applet. Esto quiere decir, que cuando dejamos la página web que contiene el applet y regresamos de nuevo pulsando en el botón "hacia atrás" el método start vuelve a llamarse de nuevo, pero no se llama el método init.

Cuando dejamos la página web que contiene el applet, por ejemplo, pulsando en un enlace, se llama al método stop.

Finalmente, cuando salimos del navegador se llama al método destroy.

Métodos fundamentales

public class Simple extends Applet { . . . public void init() { . . . } public void start() { . . . } public void stop() { . . . } public void destroy() { . . . } . . . }

9.4. INSERTANDO UN APPLET EN UNA PÁGINA WEB Las etiquetas HTML como <H1>, <TABLE>, <IMG>, etc. se-ñalan el tamaño y la disposición del texto y las figu-ras en la ventana del navegador. Cuando Sun Microsys-tems desarrolló el lenguaje Java, se añadió la etique-ta que permite insertar applets en las páginas web. Como otras etiquetas tiene un comienzo <APPLET> y un final señalado por </APPLET>

PROGRAMACION CON JAVA 2 317

En el Entorno Integrado de Desarrollo (IDE) de JCrea-tor creamos un applet. Con JCreator generamos la clase que describe el applet con algunos métodos y lo guar-damos en un archivo cuyo nombre es el mismo que el de la clase y con extensión .java. Generamos también, un archivo HTML de la página que contiene el applet tal como se ve a continuación:

<!--Archivo: applet1.htm --> <HTML> <HEAD> <TITLE> Applet en Java </TITLE> </HEAD> <BODY> Esta es la salida del primer applet Java: <APPLET CODE="Applet1.class" WIDTH=300 HEIGHT=150> </APPLET> </BODY> </HTML>

Cuado se compila el applet se producen archivos cuya extensión es .class. Uno de estos archivos es el que resulta de la compilación de la clase que describe el applet, en nuestro caso Applet1.class.

Si queremos insertar un applet en una página web, uti-lice <APPLET> ... </APPLET> en su página.

Dentro de la etiqueta applet el parámetro más impor-tante es CODE que señala el nombre del archivo cuya extensión es .class, y cuyo nombre coincide con el de la clase que describe el applet.

Los valores de los parámetros WIDTH y HEIGHT determi-nan las dimensiones del applet. En este caso el applet tiene una anchura de 300 y una altura de 150.

El nombre del applet, parámetro NAME, es importante cuando se pretende comunicar los applets insertados en una página web.

Luego de haber compilado el Applet1.java, ubique el archivo applet1.htm y realice doble clic para ejecutar la página que contiene al applet. Usted verá la si-guiente salida:

318 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

Ejemplo(74): Programa completo del uso de un applet.

//Archivo: Applet1.java

import java.awt.*; import java.awt.event.*; import java.applet.*; public class Applet1 extends Applet { public void init() { setBackground(Color.cyan); } public void paint(Graphics g) { g.drawString("Primer applet", 10, 25); } }

<!--Archivo: applet1.htm -->

<!--Archivo: applet1.htm --> <HTML> <HEAD> <TITLE> Applet en Java </TITLE>

PROGRAMACION CON JAVA 2 319

</HEAD> <BODY> Esta es la salida del primer applet Java: <br> <APPLET CODE="Applet1.class" WIDTH=300 HEIGHT=150> </APPLET> </BODY> </HTML>

9.5. FUNCIONES GRÁFICAS Hemos introducido la noción de contexto gráfico en las páginas anteriores, cuando se ha creado el primer ap-plet, que muestra un mensaje. En este capítulo se es-tudiarán algunas funciones gráficas definidas en la clase Graphics, y tres clases que sirven de apoyo para dibujar en el contexto gráfico: la clase Color que describe los colores, la clase Font que nos permite crear fuentes de texto y la clase FontMetrics que nos proporciona sus características.

A continuación se tienen los constructores y métodos de la clase graphics (tomado del JDK HELP):

java.lang.Object | +--java.awt.Graphics

Resumén del Constructor protected Graphics()

Constructs a new Graphics object.

Resumén de los Métodos abstract

void clearRect(int x, int y, int width, int height) Clears the specified rectangle by fill-ing it with the background color of the current drawing surface.

abstract void

clipRect(int x, int y, int width, int height) Intersects the current clip with the specified rectangle.

abstract void

copyArea(int x, int y, int width, int height, int dx, int dy) Copies an area of the component by a distance specified by dx and dy.

320 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

abstract Graphics

create() Creates a new Graphics object that is a copy of this Graphics object.

Graphics create(int x, int y, int width, int height) Creates a new Graphics object based on this Graphics object, but with a new translation and clip area.

abstract void

dispose() Disposes of this graphics context and releases any system resources that it is using.

void draw3DRect(int x, int y, int width, int height, boo-lean raised) Draws a 3-D highlighted outline of the specified rectangle.

abstract void

drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) Draws the outline of a circular or el-liptical arc covering the specified rectangle.

void drawBytes(byte[] data, int offset, int length, int x, int y) Draws the text given by the specified byte array, using this graphics context's current font and color.

void drawChars(char[] data, int offset, int length, int x, int y) Draws the text given by the specified character array, using this graphics context's cu-rrent font and color.

abstract boolean

drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) Draws as much of the specified image as is currently available.

abstract boolean

drawImage(Image img, int x, int y, ImageObserver observer) Draws as much of the specified image as is currently available.

abstract boolean

drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) Draws as much of the specified image as has already been scaled to fit inside the speci-fied rectangle.

abstract boolean

drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) Draws as much of the specified image as has already been scaled to fit inside the speci-fied rectangle.

PROGRAMACION CON JAVA 2 321

abstract boolean

drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) Draws as much of the specified area of the specified image as is currently available, scaling it on the fly to fit inside the specified area of the destination drawable surface.

abstract boolean

drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) Draws as much of the specified area of the specified image as is currently available, scaling it on the fly to fit inside the specified area of the destination drawable surface.

abstract void

drawLine(int x1, int y1, int x2, int y2) Draws a line, using the current color, between the points (x1, y1) and (x2, y2) in this graphics context's coordinate system.

abstract void

drawOval(int x, int y, int width, int height) Draws the outline of an oval.

abstract void

drawPolygon(int[] xPoints, int[] yPoints, int nPoints) Draws a closed polygon defined by arrays of x and y coordinates.

void drawPolygon(Polygon p) Draws the outline of a polygon defined by the specified Polygon object.

abstract void

drawPolyline(int[] xPoints, int[] yPoints, int nPoints) Draws a sequence of connected lines de-fined by arrays of x and y coordinates.

void drawRect(int x, int y, int width, int height) Draws the outline of the specified rec-tangle.

abstract void

drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) Draws an outlined round-cornered rectan-gle using this graphics context's current color.

abstract void

drawString(AttributedCharacterIterator iterator, int x, int y) Draws the text given by the specified iterator, using this graphics context's current color.

abstract void

drawString(String str, int x, int y) Draws the text given by the specified string, using this graphics context's current font and color.

322 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

void fill3DRect(int x, int y, int width, int height, boo-

lean raised) Paints a 3-D highlighted rectangle fi-lled with the current color.

abstract void

fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) Fills a circular or elliptical arc cov-ering the specified rectangle.

abstract void

fillOval(int x, int y, int width, int height) Fills an oval bounded by the specified rectangle with the current color.

abstract void

fillPolygon(int[] xPoints, int[] yPoints, int nPoints) Fills a closed polygon defined by arrays of x and y coordinates.

void fillPolygon(Polygon p) Fills the polygon defined by the speci-fied Polygon object with the graphics context's current color.

abstract void

fillRect(int x, int y, int width, int height) Fills the specified rectangle.

abstract void

fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) Fills the specified rounded corner rec-tangle with the current color.

void finalize() Disposes of this graphics context once it is no longer referenced.

abstract Shape

getClip() Gets the current clipping area.

abstract Rectangle

getClipBounds() Returns the bounding rectangle of the current clipping area.

Rectangle getClipBounds(Rectangle r) Returns the bounding rectangle of the current clipping area.

Rectangle getClipRect() Deprecated. As of JDK version 1.1, re-placed by getClipBounds().

abstract Color

getColor() Gets this graphics context's current co-lor.

abstract Font

getFont() Gets the current font.

PROGRAMACION CON JAVA 2 323

FontMetrics getFontMetrics()

Gets the font metrics of the current font.

abstract FontMetrics

getFontMetrics(Font f) Gets the font metrics for the specified font.

boolean hitClip(int x, int y, int width, int height) Returns true if the specified rectangu-lar area might intersect the current clipping area.

abstract void

setClip(int x, int y, int width, int height) Sets the current clip to the rectangle specified by the given coordinates.

abstract void

setClip(Shape clip) Sets the current clipping area to an ar-bitrary clip shape.

abstract void

setColor(Color c) Sets this graphics context's current co-lor to the specified color.

abstract void

setFont(Font font) Sets this graphics context's font to the specified font.

abstract void

setPaintMode() Sets the paint mode of this graphics context to overwrite the destination with this graphics context's current color.

abstract void

setXORMode(Color c1) Sets the paint mode of this graphics context to alternate between this graphics con-text's current color and the new specified color.

String toString() Returns a String object representing this Graphics object's value.

abstract void

translate(int x, int y) Translates the origin of the graphics context to the point (x, y) in the current coordi-nate system.

324 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

9.5.1. EL CONTEXTO GRÁFICO

La función paint y update nos suministran el contexto gráfico del applet o del componente, en otros casos, hemos de obtener el contexto gráfico del componente mediante la función getGraphics. Una vez obtenido el contexto gráfico podemos llamar desde este objeto a las funciones gráficas definidas en la clase Graphics.

public void paint(Graphics g) { //usar el contexto gráfico g } public void update(Graphics g) { //usar el contexto gráfico g } void funcion() { Graphics g=getGraphics(); //usar el contexto gráfico g g.dispose(); }

Como vemos en esta porción de código existe una sutil diferencia entre suministrar y ob-tener el contexto gráfico g. Solamente es ne-cesario liberar los recursos asociados al contexto g, mediante la llamada a la función dispose, cuando se obtiene el contexto gráfi-co mediante getGraphics.

La clase Graphics es abstracta por lo que no se pueden crear mediante new objetos de esta clase, pero se pueden guardar en una referen-cia g de la clase Graphics los contextos grá-ficos concretos de los distintos componentes.

Un contexto gráfico es como la hoja en blanco situada en un trazador (plotter). Para dibu-jar en dicha hoja se toma una pluma, se dibu-ja, se toma otra pluma de distinto color o grosor, se dibuja otra porción del gráfico, y así sucesivamente. Cuando no se selecciona explícitamente, se dibuja con una pluma que se establece por defecto.

PROGRAMACION CON JAVA 2 325

Las librerías gráficas como la de Windows, disponen de plumas de distinto grosor para dibujar líneas con distintos estilos, brochas para rellenar el interior de una figura ce-rrada con un color sólido, con una determina-da trama o figura, y fuentes de texto, para dibujar texto con distintas fuentes y esti-los. La librería gráfica que viene con la versión 1.1 de Java es muy limitada. No hay objetos pinceles, ni brochas. Las líneas tie-nen un único grosor y estilo, solamente se pueden cambiar de color, las figuras cerradas solamente se pueden rellenar con un color só-lido, y las fuentes de texto disponibles son muy pocas.

La clase Graphics describe el contexto gráfi-co y proporciona un conjunto de funciones pa-ra dibujar las siguientes figuras

• Líneas

• Círculos y elipses

• Rectángulos y polígones

• Imágenes

• Texto

El sistema de coordenadas que se usa en Java es si-milar a Windows. El área de trabajo del applet está compuesta por una matriz bidimensional de puntos o pixels. Decimos que un punto tiene coordenadas (x, y) cuando está en la columna x medida desde la izquierda, y está en la fila y, medida desde arri-ba.

La esquina superior izquierda es el ori-gen (0, 0).

La esquina inferior derecha viene de-terminada por las dimensiones del com-

X

Y

326 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

ponente. La función getSize nos devuel-ve un objeto de la clase Dimension cu-yos miembros width y height nos sumi-nistran la anchura y altura del compo-nente. int ancho=getSize().width; int alto=getSize().heigth;

No vamos a examinar completamente la clase Graphics, pero si vamos a mostrar mediante un applet el uso de algunas funciones de esta clase.

La función paint nos va a proporcionar el objeto g de la clase Graphics que denominamos contexto gráfico del componente (applet). Desde dicho objeto llamaremos a las funciones miembro de la clase Graphics.

9.5.2. ESTABLECER UN COLOR

El color negro es el color por defecto del contexto gráfico. Para establecer otro color, como veremos en la página siguiente, se uti-liza la función setColor, y se le pasa un co-lor predefinido o definido por el usuario.

g.setColor(Color.cyan);

9.5.3. DIBUJAR UNA LÍNEA

Para dibujar una línea recta se llama a la función drawLine, le pasamos el punto inicial y el punto final. Para dibujar una línea di-agonal desde el origen (0, 0) o esquina supe-rior izquierda, hasta la esquina inferior de-recha, obtenemos las dimensiones del applet mediante la función getSize, que devuelve un objeto de la clase Dimension. El miembro width nos sproporciona la anchura y el miem-bro height la altura.

g.drawLine(0, 0, getSize().width-1, getSize().height-1);

9.5.4. DIBUJAR UN RECTÁNGULO

Un rectángulo viene definido por un origen (esquina superior izquierda), su anchura y

PROGRAMACION CON JAVA 2 327

altura. La siguiente sentencia dibuja un rec-tángulo cuyo origen es el punto 50, 150, que tiene una anchura de 50, y una altura de 60. La función drawRect dibuja el contorno del color seleccionado, y fillRect dibuja el rec-tángulo pintando su interior del color selec-cionado, en este caso de color rojo.

g.setColor(Color.red); g.fillRect(50, 150, 50, 60);

9.5.5. DIBUJAR UN ARCO

Los elipses (oval), arcos (arc), se dibujan en el interior del rectángulo circundante. Una elipse de dibuja mediante drawOval o fillOval, con los mismos parámetros que el rectángulo. Un arco requiere dos parámetros más el ángulo inicial y el ángulo final. Las sentencias que vienen a continuación, dibujan un arco en el interior del rectángulo cuyo origen es el punto 10, 10, cuya anchura es 150, y cuya altura es 100. El ángulo inicial es 0 y el ángulo final es 270, expresado en grados.

g.setColor(Color.cyan); g.fillArc(10, 10, 150, 100, 0, 270); g.setColor(Color.black); g.drawArc(10, 10, 150, 100, 0, 270);

9.5.6. DIBUJAR UN POLÍGONO

Para dibujar un polígono, se requieren un array de puntos. Un polígono y una polilínea son parecidos, el primero es una figura ce-rrada mientas que una polilínea es un conjun-to de segmentos. Para formar un polígono a partir de una pililínea se une el punto ini-cial y el punto final. El polígono precisa de un array de abscisas x, un array de ordenadas y, y la dimensión del array.

int[] x={100, 150, 170, 190, 200}; int[] y={120, 280, 200, 250, 60}; g.setColor(Color.blue); g.drawPolygon(x, y, x.length);

328 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

Alternativamente, se puede usar un objeto de la clase Polygon, al cual se le añaden puntos mediante la función miembro addPoint.

Polygon poligono=new Polygon(); poligono.addPoint(100, 120); poligono.addPoint(150, 280); poligono.addPoint(170, 200); poligono.addPoint(190, 250); poligono.addPoint(200, 60);

Para dibujar el polígono con su interior pin-tado del color seleccionado se llama a la función fillPolygon y se le pasa el objeto poligono de la clase Polygon.

g.setColor(Color.yellow); g.fillPolygon(poligono);

Veremos en el applet un polígono cuyo contor-no está dibujado en azul y su interior en amarillo.

9.5.7. DIBUJAR UNA IMAGEN

Para dibujar una imagen se requieren dos pa-sos:

• Cargar la imagen y crear un objeto de la clase Image

• Dibujar dicho objeto en el contexto grá-fico

Para crear una imagen u objeto disco de la clase Image a partir del archivo disco.gif se usa la función getImage. Le hemos de indicar la ubicación de dicho archivo relativa a la página web que contiene el applet o al código compilado. En nuestro caso, hemos situado la imagen en el mismo subdirectorio que la pági-na web que contiene al applet. El lugar más adecuado para cargar la imagen es en la fun-ción init, ya que como se ha mencionado se llama una sola vez.

public void init() { disco=getImage(getDocumentBase(), "disco.gif"); }

PROGRAMACION CON JAVA 2 329

Para dibujar la imagen en el contexto gráfico g, se llama a la función drawImage. Hay va-rias versiones de esta función, la más simple es aquella a la que se le proporciona el ob-jeto disco de la clase Image, las coordenadas de su esquina superior izquierda (250, 50), y el observador, el propio applet o this.

g.drawImage(disco, 250, 50, this);

Si deseamos obtener las dimensiones del obje-to disco de la clase Image, llamamos a dos funciones de esta clase getWidth y getHeight

int ancho=disco.getWidth(this); int alto=disco.getHeight(this);

Ejemplo(75): Programa completo del uso de las funcio-nes gráficas

// Archivo: FuncionesApplet.java import java.awt.*; import java.awt.event.*; import java.applet.*; public class FuncionesApplet extends Applet { Image disco; public void init() { try { jbInit(); } catch (Exception e) { e.printStackTrace(); } } private void jbInit() throws Exception { setBackground(Color.white); this.setSize(400,300); disco=getImage(getDocumentBase(), "disco.gif"); } public void paint(Graphics g) { g.drawLine(0, 0, getSize().width-1, getSize().height-1); g.setColor(Color.red); g.fillRect(50, 150, 50, 60);

330 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

g.setColor(Color.cyan); g.fillArc(10, 10, 150, 100, 0, 270); g.setColor(Color.black); g.drawArc(10, 10, 150, 100, 0, 270); Polygon poligono=new Polygon(); poligono.addPoint(100, 120); poligono.addPoint(150, 280); poligono.addPoint(170, 200); poligono.addPoint(190, 250); poligono.addPoint(200, 60); g.setColor(Color.yellow); g.fillPolygon(poligono); int[] x={100, 150, 170, 190, 200}; int[] y={120, 280, 200, 250, 60}; g.setColor(Color.blue); g.drawPolygon(x, y, x.length); g.drawImage(disco, 250, 50, this); } } <!--Archivo: applet2.htm --> <HTML> <HEAD> <TITLE> Applet en Java </TITLE> </HEAD> <BODY> <APPLET CODE="FuncionesApplet.class" WIDTH=700 HEIGHT=750> </APPLET> </BODY> </HTML>

PROGRAMACION CON JAVA 2 331

9.6. LAS CLASES Color, Font Y Fontmetrics

9.6.1. LA CLASE Color

Los colores primarios son el rojo, el verde y el azul. Java utiliza un modelo de color de-nominado RGB, que significa que cualquier co-lor se puede describir dando las cantidades de rojo (Red), verde (Green), y azul (Blue). Estas cantidades son números enteros comprendidos entre 0 y 255, o bien, números reales comprendidos entre 0.0 y 1.0. La siguiente tabla nos proporciona los colores más comunes y sus valores RGB.

Nombre Red (rojo) Green (verde)

Blue (azul)

white 255 255 255 lightGray 192 192 192 gray 128 128 128 drakGray 64 64 64 black 0 0 0 red 255 0 0 pink 255 175 175 orange 255 200 0 yellow 255 255 0 green 0 255 0 magenta 255 0 255 cyan 0 255 255 blue 0 0 255

Para crear un objeto de la clase Color, se pasan tres números a su constructor que indi-can la cantidad de rojo, verde y azul.

Color colorRosa=new Color(255, 175, 175);

Mediante la función setColor, cambiamos color con el que dibujamos una línea, un texto o rellenamos una figura cerrada en el contexto gráfico g.

g.setColor(colorRosa);

332 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

No es necesario tener a mano la tabla de las componentes RGB de cada color. La clase Color nos proporciona un conjunto de colores prede-finidos en forma de miembros estáticos de di-cha clase. Podemos escribir alternativamente

g.setColor(Color.pink);

Los colores predefinidos son los siguientes

Color.white Color.black Color.yellow Color.lightGray Color.red Color.green Color.gray Color.pink Color.magenta Color.darkGray Color.orange Color.cyan Color.blue

Ejemplo(76): Programa que imprime un rectan-gulo

// Archivo: PaintRect.java import java.awt.*; import java.awt.event.*; import java.applet.*; public class PaintRect extends Applet { public void init() { setBackground(Color.yellow); } public void paint(Graphics g) { g.setColor(Color.red); g.drawRect(10,20,300,200); } } <!--Archivo: applet3a.htm --> <HTML> <HEAD> <TITLE> Applet en Java </TITLE> </HEAD> <BODY> <APPLET CODE="PaintRect.class" WIDTH=700 HEIGHT=750> </APPLET> </BODY> </HTML>

PROGRAMACION CON JAVA 2 333

El color de fondo del componente se establece con setBackground y se obtiene con getBack-ground. En el siguiente applet observamos có-mo se utiliza esta segunda función para crear una diana. En la función init establecemos el color de fondo en blanco mediante setBack-ground. En la función miembro paint obtenemos el color de fondo mediante getBackground. Los círculos se pintan de mayor a menor radio. Se pinta un círculo de color rojo y se borra parte de su interior con el color de fondo, de este modo se crea un anillo, luego otro y así sucesivamente, hasta completar cuatro anillos de color rojo con la apariencia de una diana.

En el programa, también podemos apreciar que la función paint suministra el contexto grá-fico g del componente (applet) en el cual po-demos dibujar. El objeto g llama a setColor para establecer el color, y a fillOval para dibujar un círculo pintado de dicho color.

Las función getSize nos devuelve el tamaño del componente (applet), de modo que los diá-metros de la elipse mayor son respectivamete la anchura y altura del applet.

Ejemplo(77): Programa completo del uso de Co-lor

// Archivo: PaintApplet.java import java.awt.*; import java.awt.event.*; import java.applet.*; public class PaintApplet extends Applet { public void init() { setBackground(Color.white); } public void paint(Graphics g) { int x, y, ancho, alto; int appletAlto = getSize().height; int appletAncho = getSize().width; for (int i=8; i>=0; i--) { if ((i % 2)==0) g.setColor(Color.red); else g.setColor(getBackground());

334 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

alto = appletAlto*i/8; ancho = appletAncho*i/8; x=appletAncho/2-i*appletAncho/16; y=appletAlto/2-i*appletAlto/16; g.fillOval(x, y, ancho, alto); } } } <!--Archivo: applet3.htm --> <HTML> <HEAD> <TITLE> Applet en Java </TITLE> </HEAD> <BODY> <APPLET CODE="PaintApplet.class" WIDTH=700 HEIGHT=750> </APPLET> </BODY> </HTML>

PROGRAMACION CON JAVA 2 335

9.6.2. LA CLASE Font

Para crear una fuente de texto u objeto de la clase Font llamamos a su constructor, y le pasamos el nombre de la fuente de texto, el estilo y el tamaño. Por ejemplo,

Font fuente=new Font("TimesRoman", Font.BOLD, 12);

Esta sentencia, crea una fuente de texto Ti-mes Roman, en letra negrita, de 12 puntos.

Los estilos vienen datos por constantes (miembros estáticos de la clase Font), Font.BOLD establece el estilo negrita, Font.ITALIC, el estilo cursiva, y Font.PLAIN, el estilo normal. Se pueden combinar las constantes Font.BOLD+Font.ITALIC para esta-blecer el estilo negrita y cursiva a la vez.

La función setFont de la clase Graphics esta-blece la fuente de texto en el contexto grá-fico g.

g.setFont(fuente);

La función getFont obtiene la fuente de texto actual de dicho contexto gráfico. La función drawString dibuja el string guardado en el objeto texto de la clase String, y lo sitúa en la posición cuyas coordenadas vienen dadas por los dos números enteros que le siguen.

En la siguiente porción de código, establece-mos una fuente de texto, dibujamos el texto, y reestablecemos la fuente de texto por de-fecto, una operación habitual que se realiza al programar un applet.

Font oldFont=getFont(); Font fuente=new Font("Monospaced", Font.BOLD, 36); g.setFont(fuente); g.drawString(texto, 100, 50); g.setFont(oldFont); g.drawString(otroTexto, 100, 70);

Para obtener el nombre de las fuentes de tex-to disponibles se escribe el siguiente código

336 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

String[] nombreFuentes=getToolkit().getFontList(); for(int i=0; i<nombreFuentes.length; i++){ System.out.println(nombreFuentes[i]); }

9.6.3. LA CLASE FontMetrics

La clase FontMetrics nos permite conocer las características de una fuente de texto.

Desde el contexto gráfico g, llamamos a la función getFontMetrics para obtener un objeto fm de la clase FontMetrics que nos describe las características de una fuente determinada o de la fuente actualmente seleccionada. En el primer caso escribimos

Font fuente=new Font("Dialog", Font.BOLD, 36); FontMetrics fm=g.getFontMetrics(fuente);

En el segundo caso, escribimos

Font fuente=new Font("Courier", Font.BOLD, 36); g.setFont(fuente); FontMetrics fm=g.getFontMetrics();

En el applet mostramos las características de una fuente de texto: Ascent es la distancia entre línea horizontal de color azul (baseli-ne) y la línea horizontal de color rojo. Des-cent es la distancia entre la línea horizon-tal de color azul (baseline) y la línea hori-zontal de color verde. Leading sería la dis-tancia entre las línea de color verde (des-cent) y la línea roja (ascent) de la siguien-te línea de texto.

PROGRAMACION CON JAVA 2 337

Para obtener la altura de una fuente de texto, llamamos a la función getHeight miembro de FontMetrics. La altura de una fuente de texto, es la distancia entre dos líneas base (base-line) consecutivas, y es la suma de el as-cent, descent y lea-ding.

Tres funciones que comienzan por get devuelven los valores de estos tres atributos de una fuente de tex-to: getAscent, getDescent, y ge-tLeading.

Para escribir dos líneas de texto, una debajo de otra escribimos

FontMetrics fm=g.getFontMetrics(); String texto="La cigüeña vendrá"; g.drawString(texto, 10, 50); int hFont=fm.getHeight(); texto=new String("serÁ en primavera"); g.drawString(texto, 10, 50+hFont);

La primera línea de texto, se sitúa en el punto (10, 50), la ordenada 50, señala la po-sición vertical de la línea base de la fuente de texto, véase la figura. La segunda línea de texto tiene una línea base cuya posición vertical se obtiene sumando a 50 la altura hFont de la fuente de texto.

Otro valor interesante, es la anchura de un texto, que se obtiene mediante la función miembro stringWidth, y se le pasa el texto. Por ejemplo, para centrar horizontalmente un texto en el applet escribimos.

String texto="La cigüeña vendrá"; int ancho=fm.stringWidth(texto); g.drawString(texto, (anchoApplet-ancho)/2, 50);

338 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

La función getSize().width obtiene la anchura del componente (applet), y la variable ancho, guarda la anchura del string texto.

Un poco más difícil es centrar un texto ver-ticalmente, en una determinada posición. Te-niendo en cuanta, que las coordendas que se le pasan a la función drawString se refieren a la línea base del primer carácter, tal como se ve en la figura. La fórmula de centrado vertical en un punto de ordenada y sería: la ordenada y de la línea base menos descent más la mitad de la altura de los caracteres hFont. Se ha de tener en cuenta que la orde-nada y aumenta de arriba hacia abajo.

g.drawLine(0, y, anchoApplet, y); g.setColor(Color.red); texto="Centrado: a, p, ñ, á, Á "; g.drawString(texto, 10, y+hFont/2-descent);

Como los caracteres pueden estar o no acen-tuados, escritos en mayúsculas o minúsculas, etc, la fórmula para mostrar un texto centra-do verticamente no es única, se sugiere pro-bar estas dos dadas por otros autores

g.drawString(texto, 10, y+ascent/4); g.drawString(texto, 10, y-hFont/2+ascent);

El código completo de este ejemplo es, el si-guiente:

Ejemplo(78): Ejemplo del uso de Font y Font-Metrics

// Archivo: FontApplet2.java import java.awt.*; import java.awt.event.*; import java.applet.*; public class FontApplet2 extends Applet { public FontApplet2() { } //Initialize the applet

PROGRAMACION CON JAVA 2 339

public void init() { try { jbInit(); } catch (Exception e) { e.printStackTrace(); } } private void jbInit() throws Exception { int ancho = Integer.parseInt(this.getParameter("WIDTH")); int alto = Integer.parseInt(this.getParameter("HEIGHT")); this.setSize(new Dimension(ancho, alto)); setBackground(Color.white); } public void paint(Graphics g) { int anchoApplet=getSize().width; Font oldFont=getFont(); Font fuente=new Font("Monospaced", Font.BOLD, 36); g.setFont(fuente); FontMetrics fm=g.getFontMetrics(); String texto="La cigüeña vendrá"; int ancho=fm.stringWidth(texto); int y=50; g.drawString(texto, (anchoApplet-ancho)/2, y); texto=new String("serÁ en primavera"); ancho=fm.stringWidth(texto); //características de las fuentes de texto int hFont=fm.getHeight(); int ascent=fm.getAscent(); int descent=fm.getDescent(); int leading=fm.getLeading(); g.drawString(texto, (anchoApplet-ancho)/2, y+hFont); //dibuja línea base g.setColor(Color.blue); g.drawLine(0, y, getSize().width, y); g.drawLine(0, y+hFont, anchoApplet, y+hFont); //dibuja ascent g.setColor(Color.red); g.drawLine(0, y-ascent, anchoApplet, y-ascent); g.drawLine(getSize().width/2, y+hFont-ascent, anchoApplet, y+hFont-ascent); //dibuja descent g.setColor(Color.green); g.drawLine(0, y+descent, anchoApplet/2, y+descent); g.drawLine(0, y+hFont+descent, anchoApplet, y+hFont+descent); //texto centrado verticalmente en la posición y y+=2*hFont; g.setColor(Color.black);

340 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

g.drawLine(0, y, anchoApplet, y); g.setColor(Color.red); texto="Centrado: a, p, ñ, 5, Á "; g.drawString(texto, 10, y+hFont/2-descent); //Escribe tres líneas de texto en la fuente de texto por defecto. g.setFont(oldFont); fm=g.getFontMetrics(); hFont=fm.getHeight(); y+=3*hFont; g.setColor(Color.black); texto="leading ="+leading; g.drawString(texto, 10, y); texto="ascent ="+ascent; y+=hFont; g.drawString(texto, 10, y); texto="descent ="+descent; y+=hFont; g.drawString(texto, 10, y); texto="altura=ascent+descent+leading= "+(ascent+descent+leading); y+=hFont; g.drawString(texto, 10, y); } }

<!--Archivo: applet4.htm --> <HTML> <HEAD> <TITLE> Applet en Java </TITLE> </HEAD> <BODY> <APPLET CODE="FontApplet2.class" WIDTH=700 HEIGHT=750> </APPLET> </BODY> </HTML>

PROGRAMACION CON JAVA 2 341

Ejemplo(79): Programa que grafica una parabo-la.

// Archivo: GraficaParabola.java import java.awt.*; import java.awt.event.*; import java.applet.*; import java.lang.Math; public class GraficaParabola extends Applet { public void init() { setBackground(Color.yellow); } public void paint(Graphics g) { double x,y; //(x, y) : coordenadas cartesianas int x0,y0; //(x0, y0): origen de las coordenadas carte-sianas // en la pantalla int xp,yp; //(xp, yp) : coordenadas de pantalla x0 = 200; y0 = 200; //dibuja ejes g.drawLine(0,y0,400,y0); g.drawLine(x0,0,x0,400); //dibuja parabola for(x=-300;x<=300;x++)

342 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

{ y=x*x; //convertir a coordenadas de pantalla xp=(int)(x0+x); yp=(int)(y0-y); //dibujar punto g.drawOval(xp,yp,2,2); } } }

<!--Archivo: applet4a.htm -->

<HTML> <HEAD> <TITLE> Applet en Java </TITLE> </HEAD> <BODY> <APPLET CODE="GraficaParabola.class" WIDTH=500 HEIGHT=750> </APPLET> </BODY> </HTML>

PROGRAMACION CON JAVA 2 343

Ejemplo(80): Programa que grafica la función seno.

// Archivo: GraficaSeno.java import java.awt.*; import java.awt.event.*; import java.applet.*; import java.lang.Math; public class GraficaSeno extends Applet { public void init() { setBackground(Color.yellow); } public void paint(Graphics g) { double x,y; //(x, y) : coordenadas cartesianas int x0,y0; //(x0, y0): origen de las coordenadas carte-sianas // en la pantalla double xp,yp; //(xp, yp) : coordenadas de pantalla double angrad; x0 = 400; y0 = 200; //dibuja ejes g.drawLine(0,y0,800,y0); g.drawLine(x0,0,x0,400); //dibuja parabola for(x=-400;x<=400;x++) { angrad=Math.toRadians(x); y=100*Math.sin(angrad); //convertir a coordenadas de pantalla xp=x0+x; yp=y0-y; //dibujar punto g.drawOval((int) xp,(int) yp,2,2); } } } <!--Archivo: applet4b.htm --> <HTML> <HEAD> <TITLE> Applet en Java </TITLE> </HEAD> <BODY> <APPLET CODE="GraficaSeno.class" WIDTH=1000 HEIGHT=400> </APPLET> </BODY> </HTML>

344 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

9.7. INTERFAZ GRAFICA CON EL USUARIO (GUI) Y COMPONENTES BASICOS

Toda interfaz gráfica con el usuario (GUI, graphical user interface) presenta una interfaz de imagenes con un programa. Esta interfaz permite al usuario reducir el tiempo de ingreso de los datos, así como el manejo de un programa.

Las GUI se construyen a partir de componentes de GUI (llamados widgets). Un componente de GUI es un objeto visual con el que el usuario puede interactuar a tra-vés del teclado o el mouse.

Las clases para crear los componentes de GUI estan en el paquete java.awt(Another Windowing Toolkit, otro juego de herramientas para manejar ventanas). Para utilizar este paquete debemos importarlo de la si-guiente manera:

import java.awt.*;

PROGRAMACION CON JAVA 2 345

9.7.1. COMPONENTES

Hay dos tipos de componentes:

• los controles

• los paneles

Los controles derivan de la clase Component, y los paneles derivan de la clase Container. Los paneles (un applet es un panel especiali-zado) pueden contener otros componentes (pa-neles y controles). La jerarquía de clases se muestra en la figura

La librería AWT no es muy rica en componen-tes, tal como se ve en la figura. Sin embar-go, hemos de tener cuidado en usar solamente componentes AWT para los applets que vayamos a publicar en Internet. Los navegadores no ejecutan applets que utilicen componentes no estándar.

346 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

Por debajo de los controles AWT están los controles nativos, esto presenta algunas di-ficultades, por ejemplo, los controles son siempre rectangulares y opacos. La versión Java 2.0 sustituye la libería AWT por la de-nominada Swing en la que se elimina la depen-dencia de los controles nativos, el número y el tipo de componentes puede satisfacer con creces las aspiraciones de cualquier progra-mador exigente. Además, podemos crear nues-tros propios controles, comprarlos o encar-garlos a medida, y situarlos en la paleta de componentes.

9.7.2. ROTULOS (Label)

Un rótulo es una area donde se exhibe una so-la línea de texto estatico (sólo de lectura). El texto no puede ser modificado por el usua-rio cuando se esta ejecutando el programa. Los rotulos se crean con la clase Label que deriva de la clase Component.

java.lang.Object | +--java.awt.Component | +--java.awt.Label

Los atributos, constructores y métodos de Label se muestran a continuación(Tomado del JDK HELP):

Resumén de atributos static int CENTER

Indicates that the label should be cen-tered.

static int LEFT Indicates that the label should be left justified.

static int RIGHT Indicates that the label should be right justified.

PROGRAMACION CON JAVA 2 347

Resumén de Constructores Label() Constructs an empty label.

Label(String text) Constructs a new label with the specified string of text, left justified.

Label(String text, int alignment) Constructs a new label that presents the specified string of text with the specified alignment.

Resumén de Métodos void addNotify()

Creates the peer for this label.

AccessibleContext getAccessibleContext() Gets the AccessibleContext associ-ated with this Label.

int getAlignment() Gets the current alignment of this label.

String getText() Gets the text of this label.

protected String paramString() Returns a string representing the state of this Label.

void setAlignment(int alignment) Sets the alignment for this label to the specified alignment.

void setText(String text) Sets the text for this label to the specified text.

Métodos que heredados de la clase java.awt.Component action, add, addComponentListener, addFocusListener, addHierarchyBoundsListener, addHierarchyListener, addInputMethodListener, addKeyListener, addMouseListener, addMouseMotionListener, addMouseWheelListener, addPropertyChangeListener, addPropertyChangeListener, applyComponentOrientation, areFocusTraversalKeysSet, bounds, checkImage, checkImage, coalesceEvents, contains, contains, createImage, createImage, createVolatileImage, createVolatileImage, deliverEvent, disable, disableEvents, dispatchEvent, doLayout, enable, enable, enableEvents, enableInputMethods, firePropertyChange, firePropertyChange, firePropertyChange, getAlignmentX, getAlignmentY, getBackground, getBounds, getBounds,

348 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

getColorModel, getComponentAt, getComponentAt, getComponentListeners, getComponentOrientation, getCursor, getDropTarget, getFocusCycleRootAncestor, getFocusListeners, getFocusTraversalKeys, getFocusTraversalKeysEnabled, getFont, getFontMetrics, getForeground, getGraphics, getGraphicsConfiguration, getHeight, getHierarchyBoundsListeners, getHierarchyListeners, getIgnoreRepaint, getInputContext, getInputMethodListeners, getInputMethodRequests, getKeyListeners, getListeners, getLocale, getLocation, getLocation, getLocationOnScreen, getMaximumSize, getMinimumSize, getMouseListeners, getMouseMotionListeners, getMouseWheelListeners, getName, getParent, getPeer, getPreferredSize, getPropertyChangeListeners, getPropertyChangeListeners, getSize, getSize, getToolkit, getTreeLock, getWidth, getX, getY, gotFocus, handleEvent, hasFocus, hide, imageUpdate, inside, invalidate, isBackgroundSet, isCursorSet, isDisplayable, isDoubleBuffered, isEnabled, isFocusable, isFocusCycleRoot, isFocusOwner, isFocusTraversable, isFontSet, isForegroundSet, isLightweight, isOpaque, isShowing, isValid, isVisible, keyDown, keyUp, layout, list, list, list, list, list, locate, location, lostFocus, minimumSize, mouseDown, mouseDrag, mouseEnter, mouseExit, mouseMove, mouseUp, move, nextFocus, paint, paintAll, postEvent, preferredSize, prepareImage, prepareImage, print, printAll, processComponentEvent, processEvent, processFocusEvent, processHierarchyBoundsEvent, processHierarchyEvent, processInputMethodEvent, processKeyEvent, processMouseEvent, processMouseMotionEvent, processMouseWheelEvent, remove, removeComponentListener, removeFocusListener, removeHierarchyBoundsListener, removeHierarchyListener, removeInputMethodListener, removeKeyListener, removeMouseListener, removeMouseMotionListener, removeMouseWheelListener, removeNotify, removePropertyChangeListener, removePropertyChangeListener, repaint, repaint, repaint, repaint, requestFocus, requestFocus, requestFocusInWindow, requestFocusInWindow, reshape, resize, resize, setBackground, setBounds, setBounds, setComponentOrientation, setCursor, setDropTarget, setEnabled, setFocusable, setFocusTraversalKeys, setFocusTraversalKeysEnabled, setFont, setForeground, setIgnoreRepaint, setLocale, setLocation, setLocation, setName, setSize, setSize, setVisible, show, show, size, toString, transferFocus, transferFocusBackward, transferFocusUpCycle, update, validate

Los atributos, constructores y métodos de Component se muestran a continuación(Tomado del JDK HELP):

java.lang.Object | +--java.awt.Component

Resumén de atributos static float BOTTOM_ALIGNMENT

Ease-of-use constant for getAlignmentY.

static float CENTER_ALIGNMENT Ease-of-use constant for getAlignmentY and getAlignmentX.

PROGRAMACION CON JAVA 2 349

static float LEFT_ALIGNMENT Ease-of-use constant for getAlignmentX.

static float RIGHT_ALIGNMENT Ease-of-use constant for getAlignmentX.

static float TOP_ALIGNMENT Ease-of-use constant for getAlignmentY().

Resumén de Constructores protected Component()

Constructs a new component.

Resumen de Métodos boolean action(Event evt, Object what)

Deprecated. As of JDK version 1.1, should register this component as ActionListener on compo-nent which fires action events.

void add(PopupMenu popup) Adds the specified popup menu to the com-ponent.

void addComponentListener(ComponentListener l) Adds the specified component listener to receive component events from this component.

void addFocusListener(FocusListener l) Adds the specified focus listener to re-ceive focus events from this component when this component gains input focus.

void addHierarchyBoundsListener(HierarchyBoundsListener l) Adds the specified hierarchy bounds lis-tener to receive hierarchy bounds events from this component when the hierarchy to which this container belongs changes.

void addHierarchyListener(HierarchyListener l) Adds the specified hierarchy listener to receive hierarchy changed events from this component when the hierarchy to which this container belongs changes.

void addInputMethodListener(InputMethodListener l) Adds the specified input method listener to receive input method events from this component.

350 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

void addKeyListener(KeyListener l)

Adds the specified key listener to receive key events from this component.

void addMouseListener(MouseListener l) Adds the specified mouse listener to re-ceive mouse events from this component.

void addMouseMotionListener(MouseMotionListener l) Adds the specified mouse motion listener to receive mouse motion events from this component.

void addMouseWheelListener(MouseWheelListener l) Adds the specified mouse wheel listener to receive mouse wheel events from this component.

void addNotify() Makes this Component displayable by connect-ing it to a native screen resource.

void addPropertyChangeListener(PropertyChangeListener listener) Adds a PropertyChangeListener to the lis-tener list.

void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) Adds a PropertyChangeListener to the lis-tener list for a specific property.

void applyComponentOrientation(ComponentOrientation orientation) Sets the ComponentOrientation property of this component and all components contained within it.

boolean areFocusTraversalKeysSet(int id) Returns whether the Set of focus traversal keys for the given focus traversal operation has been explicitly defined for this Component.

Rectangle bounds() Deprecated. As of JDK version 1.1, re-placed by getBounds().

int checkImage(Image image, ImageObserver observer) Returns the status of the construction of a screen representation of the specified image.

int checkImage(Image image, int width, int height, ImageObserver observer) Returns the status of the construction of a screen representation of the specified image.

protected AWTEvent

coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent) Potentially coalesce an event being posted with an existing event.

PROGRAMACION CON JAVA 2 351

boolean contains(int x, int y)

Checks whether this component "contains" the specified point, where x and y are defined to be relative to the coordinate system of this component.

boolean contains(Point p) Checks whether this component "contains" the specified point, where the point's x and y coor-dinates are defined to be relative to the coordinate system of this component.

Image createImage(ImageProducer producer) Creates an image from the specified image producer.

Image createImage(int width, int height) Creates an off-screen drawable image to be used for double buffering.

VolatileImage

createVolatileImage(int width, int height) Creates a volatile off-screen drawable im-age to be used for double buffering.

VolatileImage

createVolatileImage(int width, int height, ImageCapabilities caps) Creates a volatile off-screen drawable im-age, with the given capabilities.

void deliverEvent(Event e) Deprecated. As of JDK version 1.1, re-placed by dispatchEvent(AWTEvent e).

void disable() Deprecated. As of JDK version 1.1, re-placed by setEnabled(boolean).

protected void

disableEvents(long eventsToDisable) Disables the events defined by the speci-fied event mask parameter from being delivered to this component.

void dispatchEvent(AWTEvent e) Dispatches an event to this component or one of its sub components.

void doLayout() Prompts the layout manager to lay out this component.

void enable() Deprecated. As of JDK version 1.1, re-placed by setEnabled(boolean).

void enable(boolean b) Deprecated. As of JDK version 1.1, re-placed by setEnabled(boolean).

352 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

protected void

enableEvents(long eventsToEnable) Enables the events defined by the speci-fied event mask parameter to be delivered to this component.

void enableInputMethods(boolean enable) Enables or disables input method support for this component.

protected void

firePropertyChange(String propertyName, boolean oldValue, boo-lean newValue) Support for reporting bound property chan-ges for boolean properties.

protected void

firePropertyChange(String propertyName, int oldValue, int newValue) Support for reporting bound property chan-ges for integer properties.

protected void

firePropertyChange(String propertyName, Object oldValue, Object newValue) Support for reporting bound property chan-ges for Object properties.

AccessibleContext

getAccessibleContext() Gets the AccessibleContext associated with this Component.

float getAlignmentX() Returns the alignment along the x axis.

float getAlignmentY() Returns the alignment along the y axis.

Color getBackground() Gets the background color of this compo-nent.

Rectangle getBounds() Gets the bounds of this component in the form of a Rectangle object.

Rectangle getBounds(Rectangle rv) Stores the bounds of this component into "return value" rv and return rv.

ColorModel getColorModel() Gets the instance of ColorModel used to dis-play the component on the output device.

Component getComponentAt(int x, int y) Determines if this component or one of its immediate subcomponents contains the (x, y) loca-tion, and if so, returns the containing component.

Component getComponentAt(Point p) Returns the component or subcomponent that contains the specified point.

PROGRAMACION CON JAVA 2 353

ComponentListener[]

getComponentListeners() Returns an array of all the component lis-teners registered on this component.

ComponentOrienta-

tion

getComponentOrientation() Retrieves the language-sensitive orienta-tion that is to be used to order the elements or text within this component.

Cursor getCursor() Gets the cursor set in the component.

DropTarget getDropTarget() Gets the DropTarget associated with this Component.

Container getFocusCycleRootAncestor() Returns the Container which is the focus cycle root of this Component's focus traversal cy-cle.

FocusListener[]

getFocusListeners() Returns an array of all the focus listen-ers registered on this component.

Set getFocusTraversalKeys(int id) Returns the Set of focus traversal keys for a given traversal operation for this Component.

boolean getFocusTraversalKeysEnabled() Returns whether focus traversal keys are enabled for this Component.

Font getFont() Gets the font of this component.

FontMetrics

getFontMetrics(Font font) Gets the font metrics for the specified font.

Color getForeground() Gets the foreground color of this compo-nent.

Graphics getGraphics() Creates a graphics context for this compo-nent.

GraphicsConfigura-

tion

getGraphicsConfiguration() Gets the GraphicsConfiguration associated with this Component.

int getHeight() Returns the current height of this compo-nent.

354 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

HierarchyBoundsLis-

tener[]

getHierarchyBoundsListeners() Returns an array of all the hierarchy bounds listeners registered on this component.

HierarchyListener[]

getHierarchyListeners() Returns an array of all the hierarchy lis-teners registered on this component.

boolean getIgnoreRepaint()

InputContext

getInputContext() Gets the input context used by this compo-nent for handling the communication with input meth-ods when text is entered in this component.

InputMethodListe-

ner[]

getInputMethodListeners() Returns an array of all the input method listeners registered on this component.

InputMethodRequests

getInputMethodRequests() Gets the input method request handler which supports requests from input methods for this component.

KeyListener[]

getKeyListeners() Returns an array of all the key listeners registered on this component.

EventListener[]

getListeners(Class listenerType) Returns an array of all the objects cur-rently registered as FooListeners upon this Component.

Locale getLocale() Gets the locale of this component.

Point getLocation() Gets the location of this component in the form of a point specifying the component's top-left corner.

Point getLocation(Point rv) Stores the x,y origin of this component into "return value" rv and return rv.

Point getLocationOnScreen() Gets the location of this component in the form of a point specifying the component's top-left corner in the screen's coordinate space.

Dimension getMaximumSize() Gets the maximum size of this component.

Dimension getMinimumSize() Gets the mininimum size of this component.

MouseList getMouseListeners()

PROGRAMACION CON JAVA 2 355

ener[] Returns an array of all the mouse listen-ers registered on this component.

MouseMotionListe-

ner[]

getMouseMotionListeners() Returns an array of all the mouse motion listeners registered on this component.

MouseWheelListe-ner[]

getMouseWheelListeners() Returns an array of all the mouse wheel listeners registered on this component.

String getName() Gets the name of the component.

Container getParent() Gets the parent of this component.

ja-va.awt.peer.Componen

tPeer

getPeer() Deprecated. As of JDK version 1.1, pro-grams should not directly manipulate peers; replaced by boolean isDisplayable().

Dimension getPreferredSize() Gets the preferred size of this component.

PropertyChangeLis-tener[]

getPropertyChangeListeners() Returns an array of all the property chan-ge listeners registered on this component.

PropertyChangeLis-tener[]

getPropertyChangeListeners(String propertyName) Returns an array of all the listeners which have been associated with the named property.

Dimension getSize() Returns the size of this component in the form of a Dimension object.

Dimension getSize(Dimension rv) Stores the width/height of this component into "return value" rv and return rv.

Toolkit getToolkit() Gets the toolkit of this component.

Object getTreeLock() Gets this component's locking object (the object that owns the thread sychronization monitor) for AWT component-tree and layout operations.

int getWidth() Returns the current width of this compo-nent.

int getX() Returns the current x coordinate of the components origin.

356 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

int getY()

Returns the current y coordinate of the components origin.

boolean gotFocus(Event evt, Object what) Deprecated. As of JDK version 1.1, repla-ced by processFocusEvent(FocusEvent).

boolean handleEvent(Event evt) Deprecated. As of JDK version 1.1 replaced by processEvent(AWTEvent).

boolean hasFocus() Returns true if this Component is the focus owner.

void hide() Deprecated. As of JDK version 1.1, re-placed by setVisible(boolean).

boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) Repaints the component when the image has changed.

boolean inside(int x, int y) Deprecated. As of JDK version 1.1, re-placed by contains(int, int).

void invalidate() Invalidates this component.

boolean isBackgroundSet() Returns whether the background color has been explicitly set for this Component.

boolean isCursorSet() Returns whether the cursor has been ex-plicitly set for this Component.

boolean isDisplayable() Determines whether this component is dis-playable.

boolean isDoubleBuffered() Returns true if this component is painted to an offscreen image ("buffer") that's copied to the screen later.

boolean isEnabled() Determines whether this component is en-abled.

boolean isFocusable() Returns whether this Component can be fo-cused.

PROGRAMACION CON JAVA 2 357

boolean isFocusCycleRoot(Container container) Returns whether the specified Container is the focus cycle root of this Component's focus tra-versal cycle.

boolean isFocusOwner() Returns true if this Component is the focus owner.

boolean isFocusTraversable() Deprecated. As of 1.4, replaced by isFocus-able().

boolean isFontSet() Returns whether the font has been explic-itly set for this Component.

boolean isForegroundSet() Returns whether the foreground color has been explicitly set for this Component.

boolean isLightweight() A lightweight component doesn't have a na-tive toolkit peer.

boolean isOpaque() Returns true if this component is com-pletely opaque, returns false by default.

boolean isShowing() Determines whether this component is show-ing on screen.

boolean isValid() Determines whether this component is va-lid.

boolean isVisible() Determines whether this component should be visible when its parent is visible.

boolean keyDown(Event evt, int key) Deprecated. As of JDK version 1.1, repla-ced by processKeyEvent(KeyEvent).

boolean keyUp(Event evt, int key) Deprecated. As of JDK version 1.1, repla-ced by processKeyEvent(KeyEvent).

void layout() Deprecated. As of JDK version 1.1, re-placed by doLayout().

void list() Prints a listing of this component to the standard system output stream System.out.

358 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

void list(PrintStream out)

Prints a listing of this component to the specified output stream.

void list(PrintStream out, int indent) Prints out a list, starting at the speci-fied indentation, to the specified print stream.

void list(PrintWriter out) Prints a listing to the specified print writer.

void list(PrintWriter out, int indent) Prints out a list, starting at the speci-fied indentation, to the specified print writer.

Component locate(int x, int y) Deprecated. As of JDK version 1.1, repla-ced by getComponentAt(int, int).

Point location() Deprecated. As of JDK version 1.1, re-placed by getLocation().

boolean lostFocus(Event evt, Object what) Deprecated. As of JDK version 1.1, repla-ced by processFocusEvent(FocusEvent).

Dimension minimumSize() Deprecated. As of JDK version 1.1, re-placed by getMinimumSize().

boolean mouseDown(Event evt, int x, int y) Deprecated. As of JDK version 1.1, repla-ced by processMouseEvent(MouseEvent).

boolean mouseDrag(Event evt, int x, int y) Deprecated. As of JDK version 1.1, repla-ced by processMouseMotionEvent(MouseEvent).

boolean mouseEnter(Event evt, int x, int y) Deprecated. As of JDK version 1.1, repla-ced by processMouseEvent(MouseEvent).

boolean mouseExit(Event evt, int x, int y) Deprecated. As of JDK version 1.1, repla-ced by processMouseEvent(MouseEvent).

boolean mouseMove(Event evt, int x, int y) Deprecated. As of JDK version 1.1, repla-ced by processMouseMotionEvent(MouseEvent).

boolean mouseUp(Event evt, int x, int y) Deprecated. As of JDK version 1.1, repla-ced by processMouseEvent(MouseEvent).

PROGRAMACION CON JAVA 2 359

void move(int x, int y)

Deprecated. As of JDK version 1.1, repla-ced by setLocation(int, int).

void nextFocus() Deprecated. As of JDK version 1.1, re-placed by transferFocus().

void paint(Graphics g) Paints this component.

void paintAll(Graphics g) Paints this component and all of its sub-components.

protected String

paramString() Returns a string representing the state of this component.

boolean postEvent(Event e) Deprecated. As of JDK version 1.1, re-placed by dispatchEvent(AWTEvent).

Dimension preferredSize() Deprecated. As of JDK version 1.1, re-placed by getPreferredSize().

boolean prepareImage(Image image, ImageObserver observer) Prepares an image for rendering on this component.

boolean prepareImage(Image image, int width, int height, ImageObserver observer) Prepares an image for rendering on this component at the specified width and height.

void print(Graphics g) Prints this component.

void printAll(Graphics g) Prints this component and all of its sub-components.

protected void

processComponentEvent(ComponentEvent e) Processes component events occurring on this component by dispatching them to any registered ComponentListener objects.

protected void

processEvent(AWTEvent e) Processes events occurring on this compo-nent.

protected void

processFocusEvent(FocusEvent e) Processes focus events occurring on this component by dispatching them to any registered Fo-cusListener objects.

360 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

protected void

processHierarchyBoundsEvent(HierarchyEvent e) Processes hierarchy bounds events occur-ring on this component by dispatching them to any registered HierarchyBoundsListener objects.

protected void

processHierarchyEvent(HierarchyEvent e) Processes hierarchy events occurring on this component by dispatching them to any registered HierarchyListener objects.

protected void

processInputMethodEvent(InputMethodEvent e) Processes input method events occurring on this component by dispatching them to any registered InputMethodListener objects.

protected void

processKeyEvent(KeyEvent e) Processes key events occurring on this component by dispatching them to any registered Key-Listener objects.

protected void

processMouseEvent(MouseEvent e) Processes mouse events occurring on this component by dispatching them to any registered Mou-seListener objects.

protected void

processMouseMotionEvent(MouseEvent e) Processes mouse motion events occurring on this component by dispatching them to any registered MouseMotionListener objects.

protected void

processMouseWheelEvent(MouseWheelEvent e) Processes mouse wheel events occurring on this component by dispatching them to any registered MouseWheelListener objects.

void remove(MenuComponent popup) Removes the specified popup menu from the component.

void removeComponentListener(ComponentListener l) Removes the specified component listener so that it no longer receives component events from this component.

void removeFocusListener(FocusListener l) Removes the specified focus listener so that it no longer receives focus events from this component.

void removeHierarchyBoundsListener(HierarchyBoundsListener l) Removes the specified hierarchy bounds listener so that it no longer receives hierarchy bounds events from this component.

PROGRAMACION CON JAVA 2 361

void removeHierarchyListener(HierarchyListener l)

Removes the specified hierarchy listener so that it no longer receives hierarchy changed events from this component.

void removeInputMethodListener(InputMethodListener l) Removes the specified input method lis-tener so that it no longer receives input method events from this component.

void removeKeyListener(KeyListener l) Removes the specified key listener so that it no longer receives key events from this compo-nent.

void removeMouseListener(MouseListener l) Removes the specified mouse listener so that it no longer receives mouse events from this component.

void removeMouseMotionListener(MouseMotionListener l) Removes the specified mouse motion lis-tener so that it no longer receives mouse motion events from this component.

void removeMouseWheelListener(MouseWheelListener l) Removes the specified mouse wheel listener so that it no longer receives mouse wheel events from this component.

void removeNotify() Makes this Component undisplayable by de-stroying it native screen resource.

void removePropertyChangeListener(PropertyChangeListener listener) Removes a PropertyChangeListener from the listener list.

void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) Removes a PropertyChangeListener from the listener list for a specific property.

void repaint() Repaints this component.

void repaint(int x, int y, int width, int height) Repaints the specified rectangle of this component.

void repaint(long tm) Repaints the component.

void repaint(long tm, int x, int y, int width, int height) Repaints the specified rectangle of this component within tm milliseconds.

362 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

void requestFocus() Requests that this Component get the input focus, and that this Component's top-level ancestor become the focused Window.

protected boolean

requestFocus(boolean temporary) Requests that this Component get the input focus, and that this Component's top-level ancestor become the focused Window.

boolean requestFocusInWindow() Requests that this Component get the input focus, if this Component's top-level ancestor is al-ready the focused Window.

protected boolean

requestFocusInWindow(boolean temporary) Requests that this Component get the input focus, if this Component's top-level ancestor is al-ready the focused Window.

void reshape(int x, int y, int width, int height) Deprecated. As of JDK version 1.1, re-placed by setBounds(int, int, int, int).

void resize(Dimension d) Deprecated. As of JDK version 1.1, re-placed by setSize(Dimension).

void resize(int width, int height) Deprecated. As of JDK version 1.1, repla-ced by setSize(int, int).

void setBackground(Color c) Sets the background color of this compo-nent.

void setBounds(int x, int y, int width, int height) Moves and resizes this component.

void setBounds(Rectangle r) Moves and resizes this component to con-form to the new bounding rectangle r.

void setComponentOrientation(ComponentOrientation o) Sets the language-sensitive orientation that is to be used to order the elements or text within this component.

void setCursor(Cursor cursor) Sets the cursor image to the specified cursor.

void setDropTarget(DropTarget dt) Associate a DropTarget with this component.

PROGRAMACION CON JAVA 2 363

void setEnabled(boolean b)

Enables or disables this component, de-pending on the value of the parameter b.

void setFocusable(boolean focusable) Sets the focusable state of this Component to the specified value.

void setFocusTraversalKeys(int id, Set keystrokes) Sets the focus traversal keys for a given traversal operation for this Component.

void setFocusTraversalKeysEnabled(boolean focusTraversalKeysEnabled) Sets whether focus traversal keys are en-abled for this Component.

void setFont(Font f) Sets the font of this component.

void setForeground(Color c) Sets the foreground color of this compo-nent.

void setIgnoreRepaint(boolean ignoreRepaint) Sets whether or not paint messages re-ceived from the operating system should be ignored.

void setLocale(Locale l) Sets the locale of this component.

void setLocation(int x, int y) Moves this component to a new location.

void setLocation(Point p) Moves this component to a new location.

void setName(String name) Sets the name of the component to the spe-cified string.

void setSize(Dimension d) Resizes this component so that it has width d.width and height d.height.

void setSize(int width, int height) Resizes this component so that it has width width and height height.

void setVisible(boolean b) Shows or hides this component depending on the value of parameter b.

void show() Deprecated. As of JDK version 1.1, re-placed by setVisible(boolean).

364 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

void show(boolean b)

Deprecated. As of JDK version 1.1, re-placed by setVisible(boolean).

Dimension size() Deprecated. As of JDK version 1.1, re-placed by getSize().

String toString() Returns a string representation of this component and its values.

void transferFocus() Transfers the focus to the next component, as though this Component were the focus owner.

void transferFocusBackward() Transfers the focus to the previous compo-nent, as though this Component were the focus owner.

void transferFocusUpCycle() Transfers the focus up one focus traversal cycle.

void update(Graphics g) Updates this component.

void validate() Ensures that this component has a valid layout.

Ejemplo (81): Programa completo para el uso de Label.

// Archivo: UsoLabel.java import java.awt.*; import java.awt.event.*; import java.applet.*; public class UsoLabel extends Applet { public void init() { setBackground(Color.yellow); //declaración e inicialización de un objeto Font Font f1=new Font("Courier",Font.BOLD,24); //declaración e inicialización de un objeto Label Label textolabel1=new Label("PROGRAMACION EN JAVA 2"); //define el font para el Label //usa el método setFont de la clase Component textolabel1.setFont(f1); add(textolabel1);

PROGRAMACION CON JAVA 2 365

//declaración e inicialización de un objeto Font Font f2=new Font("Script",Font.BOLD,34); //declaración e inicialización de un objeto Label Label textolabel2=new Label(); //define el font para el Label //usa el método setFont de la clase Component textolabel2.setFont(f2); //define el contenito del rótulo textolabel2.setText("APLICACIONES"); add(textolabel2); } public void paint(Graphics g) { } } <!--Archivo: applet5.htm --> <HTML> <HEAD> <TITLE> Applet en Java </TITLE> </HEAD> <BODY> <APPLET CODE="UsoLabel.class" WIDTH=700 HEIGHT=750> </APPLET> </BODY> </HTML>

Por suepeusto que el código anterior no posi-ciona los textos en dos líneas.

Si usted desea realizar que los textos se po-sicionen en dos líneas debe utilizar el admi-nistrador de diseños GridLayout (Diseño de Retícula)

9.7.3. ADMINISTRADOR DE DISEÑOS GRIDLAYOUT

El administrador de diseños GridLayout divide el contenedor en una retícula que permite co-locar los componentes en filas y columnas.

366 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

Los componentes se se agregan comenzando en la celda superior y de izquierda a derecha, luego continua en la siguiente fila de la misma forma.

Los constructores y métodos de GridLayout se detallan a continuación:

java.lang.Object | +--java.awt.GridLayout

Resumén de Constructores GridLayout() Creates a grid layout with a default of one column per component, in a single row.

GridLayout(int rows, int cols) Creates a grid layout with the specified number of rows and columns.

GridLayout(int rows, int cols, int hgap, int vgap) Creates a grid layout with the specified number of rows and columns.

Resumén de Métodos void addLayoutComponent(String name, Component comp)

Adds the specified component with the specified name to the layout.

int getColumns() Gets the number of columns in this lay-out.

int getHgap() Gets the horizontal gap between compo-nents.

int getRows() Gets the number of rows in this layout.

int getVgap() Gets the vertical gap between components.

void layoutContainer(Container parent) Lays out the specified container using this layout.

Dimension minimumLayoutSize(Container parent) Determines the minimum size of the con-tainer argument using this grid layout.

PROGRAMACION CON JAVA 2 367

Dimension preferredLayoutSize(Container parent) Determines the preferred size of the con-tainer argument using this grid layout.

void removeLayoutComponent(Component comp) Removes the specified component from the layout.

void setColumns(int cols) Sets the number of columns in this layout to the specified value.

void setHgap(int hgap) Sets the horizontal gap between compo-nents to the specified value.

void setRows(int rows) Sets the number of rows in this layout to the specified value.

void setVgap(int vgap) Sets the vertical gap between components to the specified value.

String toString() Returns the string representation of this grid layout's values.

Ejemplo (82): Programa completo para el uso de GridLayout y Label.

// Archivo: UsoGridLayout.java import java.awt.*; import java.awt.event.*; import java.applet.*; public class UsoGridLayout extends Applet { public void init() { setBackground(Color.yellow); //declaración e inicialización de un objeto Font Font f1=new Font("Courier",Font.BOLD,24); //declaración e inicialización de un objeto Label Label textolabel1=new Label("PROGRAMACION EN JAVA 2"); //define el font para el Label //usa el método setFont de la clase Component textolabel1.setFont(f1); //declaración e inicialización de un objeto Font Font f2=new Font("Script",Font.BOLD,34); //declaración e inicialización de un objeto Label

368 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

Label textolabel2=new Label(); //define el font para el Label //usa el método setFont de la clase Component textolabel2.setFont(f2); //define el contenito del rótulo textolabel2.setText("APLICACIONES"); //uso de GridLayout setLayout( new GridLayout(2,1)); add(textolabel1); add(textolabel2); } }

<!--Archivo: applet6.htm --> <HTML> <HEAD> <TITLE> Applet en Java </TITLE> </HEAD> <BODY> <APPLET CODE="UsoGridLayout.class" WIDTH=500 HEIGHT=100> </APPLET> </BODY> </HTML>

PROGRAMACION CON JAVA 2 369

9.7.4. BOTONES PARA PULSAR (BUTTON)

Un botón es un componente en que el usuario puede relizar un clic para disparar una ac-ción específica. Los botones para pulsar se crean con la clase Button (botón) que se hereda de Component.

Los atributos, constructores y métodos de Button se listan a continuación:

java.lang.Object | +--java.awt.Component | +--java.awt.Button

Resumén de atributos

Fields inherited from class java.awt.Component

BOTTOM_ALIGNMENT, CENTER_ALIGNMENT, LEFT_ALIGNMENT, RIGHT_ALIGNMENT, TOP_ALIGNMENT

Fields inherited from interface java.awt.image.ImageObserver

ABORT, ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, WIDTH

Resumén de Constructores Button() Constructs a Button with no label.

Button(String label) Constructs a Button with the specified label.

Resumén de Métodos void addActionListener(ActionListener l)

Adds the specified action listener to receive action events from this button.

void addNotify() Creates the peer of the button.

AccessibleContext getAccessibleContext() Gets the AccessibleContext associated

370 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

with this Button.

String getActionCommand() Returns the command name of the ac-tion event fired by this button.

ActionListener[] getActionListeners() Returns an array of all the action listeners registered on this button.

String getLabel() Gets the label of this button.

EventListener[] getListeners(Class listenerType) Returns an array of all the objects currently registered as FooListeners upon this Button.

protected String paramString() Returns a string representing the state of this Button.

protected void processActionEvent(ActionEvent e) Processes action events occurring on this button by dispatching them to any re-gistered ActionListener objects.

protected void processEvent(AWTEvent e) Processes events on this button.

void removeActionListener(ActionListener l) Removes the specified action lis-tener so that it no longer receives action events from this button.

void setActionCommand(String command) Sets the command name for the ac-tion event fired by this button.

void setLabel(String label) Sets the button's label to be the specified string.

Methods inherited from class java.awt.Component

action, add, addComponentListener, addFocusListener, addHierarchyBoundsListener, addHierarchyListener, addInputMethodListener, addKeyListener, addMouseListener, addMouseMotionListener, addMouseWheelListener, addPropertyChangeListener, addPropertyChangeListener, applyComponentOrientation, areFocusTraversalKeysSet, bounds, checkImage, checkImage, coalesceEvents, contains, contains, createImage, createImage, createVolatileImage, createVolatileImage, deliverEvent, disable, disableEvents, dispatchEvent, doLayout, enable, enable, enableEvents, enableInputMethods, firePropertyChange, firePropertyChange, firePropertyChange, getAlignmentX, getAlignmentY, getBackground, getBounds, getBounds,

PROGRAMACION CON JAVA 2 371

getColorModel, getComponentAt, getComponentAt, getComponentListeners, getComponentOrientation, getCursor, getDropTarget, getFocusCycleRootAncestor, getFocusListeners, getFocusTraversalKeys, getFocusTraversalKeysEnabled, getFont, getFontMetrics, getForeground, getGraphics, getGraphicsConfiguration, getHeight, getHierarchyBoundsListeners, getHierarchyListeners, getIgnoreRepaint, getInputContext, getInputMethodListeners, getInputMethodRequests, getKeyListeners, getLocale, getLocation, getLocation, getLocationOnScreen, getMaximumSize, getMinimumSize, getMouseListeners, getMouseMotionListeners, getMouseWheelListeners, getName, getParent, getPeer, getPreferredSize, getPropertyChangeListeners, getPropertyChangeListeners, getSize, getSize, getToolkit, getTreeLock, getWidth, getX, getY, gotFocus, handleEvent, hasFocus, hide, imageUpdate, inside, invalidate, isBackgroundSet, isCursorSet, isDisplayable, isDoubleBuffered, isEnabled, isFocusable, isFocusCycleRoot, isFocusOwner, isFocusTraversable, isFontSet, isForegroundSet, isLightweight, isOpaque, isShowing, isValid, isVisible, keyDown, keyUp, layout, list, list, list, list, list, locate, location, lostFocus, minimumSize, mouseDown, mouseDrag, mouseEnter, mouseExit, mouseMove, mouseUp, move, nextFocus, paint, paintAll, postEvent, preferredSize, prepareImage, prepareImage, print, printAll, processComponentEvent, processFocusEvent, processHierarchyBoundsEvent, processHierarchyEvent, processInputMethodEvent, processKeyEvent, processMouseEvent, processMouseMotionEvent, processMouseWheelEvent, remove, removeComponentListener, removeFocusListener, removeHierarchyBoundsListener, removeHierarchyListener, removeInputMethodListener, removeKeyListener, removeMouseListener, removeMouseMotionListener, removeMouseWheelListener, removeNotify, removePropertyChangeListener, removePropertyChangeListener, repaint, repaint, repaint, repaint, requestFocus, requestFocus, requestFocusInWindow, requestFocusInWindow, reshape, resize, resize, setBackground, setBounds, setBounds, setComponentOrientation, setCursor, setDropTarget, setEnabled, setFocusable, setFocusTraversalKeys, setFocusTraversalKeysEnabled, setFont, setForeground, setIgnoreRepaint, setLocale, setLocation, setLocation, setName, setSize, setSize, setVisible, show, show, size, toString, transferFocus, transferFocusBackward, transferFocusUpCycle, update, validate

Ejemplo (83): Programa completo para el uso de Button.

// Archivo: UsoButton.java import java.awt.*; import java.awt.event.*; import java.applet.*; public class UsoButton extends Applet { private Button boton1,boton2; private int opcion; public void init() { setBackground(Color.yellow);

372 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

//declaración e inicialización de objetos Button boton1=new Button("Función seno"); boton2=new Button("Función parábola"); //agegar botones add(boton1); add(boton2); } public void paint(Graphics g) { //llamar a la grafica de las funciones switch(opcion) { case 1: fseno(g); break; case 2: fparabola(g);break; } } public boolean action(Event e, Object o) { //verificar si un boton disparó el evento if(e.target instanceof Button) { //comprobar si se pulsó boton1 o boton2 if(e.target==boton1) {opcion=1;repaint();} //opcion=1 y repintar else if(e.target==boton2) {opcion=2;repaint();}//opcion=2 y repintar return true; } return true; } //dibuja la función seno void fseno(Graphics g) { double x,y; //(x, y) : coordenadas cartesianas int x0,y0; //(x0, y0): origen de las coordenadas carte-sianas // en la pantalla double xp,yp; //(xp, yp) : coordenadas de pantalla double angrad; x0 = 400; y0 = 200; //dibuja ejes g.drawLine(0,y0,800,y0); g.drawLine(x0,0,x0,400); //dibuja parabola for(x=-400;x<=400;x++) { angrad=Math.toRadians(x); y=100*Math.sin(angrad); //convertir a coordenadas de pantalla xp=x0+x;

PROGRAMACION CON JAVA 2 373

yp=y0-y; //dibujar punto g.drawOval((int) xp,(int) yp,2,2); } } //dibuja la función parabola void fparabola(Graphics g) { double x,y; //(x, y) : coordenadas cartesianas int x0,y0; //(x0, y0): origen de las coordenadas carte-sianas // en la pantalla int xp,yp; //(xp, yp) : coordenadas de pantalla x0 = 200; y0 = 200; //dibuja ejes g.drawLine(0,y0,400,y0); g.drawLine(x0,0,x0,400); //dibuja parabola for(x=-300;x<=300;x++) { y=x*x; //convertir a coordenadas de pantalla xp=(int)(x0+x); yp=(int)(y0-y); //dibujar punto g.drawOval(xp,yp,2,2); } } } <!--Archivo: applet7.htm --> <HTML> <HEAD> <TITLE> Applet en Java </TITLE> </HEAD> <BODY> <APPLET CODE="UsoButton.class" WIDTH=1000 HEIGHT=400> </APPLET> </BODY> </HTML>

La salida del programa cuando se pulsa fun-ción seno y función parábola se muestra en las siguientes figuras.

374 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

PROGRAMACION CON JAVA 2 375

9.8. LOS GESTORES FLOWLAYOUT, BORDERLAYOUT Y GRIDLAYOUT

En la superficie del applet se disponen los componen-tes, como paneles y controles. Ahora bien, las herra-mientas de diseño no disponen de opciones para situar los componentes en lugares precisos, alinearlos, etc, como ocurre en Windows, ya que en Java existen los de-nominados gestores de diseño que no sitúan los compo-nentes en posiciones absolutas, sino que la disposi-ción se determina mediante un algoritmo. El más simple de los gestores de diseño es FlowLayout y el más com-plicado es GridBagLayout.

Para el programador acostumbrado a diseñar ventanas y diálogos en el entorno Windows le parecerá extraña es-ta forma de proceder y pensará que con este sistema será difícil elaborar un interfaz gráfico de usuario.

Como veremos, se puede crear un diseño complejo me-diante el gestor GridBagLayout y también, mediante la aproximación de paneles anidados.

No obstante, el programador debe percibir la diferen-cia entre applets y aplicaciones. Los applets están insertados en una página web y se ejecutan en la ven-tana del navegador. El applet comparte espacio con texto, imágenes y otros elementos multimedia. El usua-rio tiene la libertad de moverse por la página, y por otras páginas a través de los enlaces. La percepción que tiene el usuario del applet es completamente dis-tinta de la percepción que tiene de una aplicación que llama completamente su atención.

El programador debe tener en cuenta estas diferencias de percepción, y debe esforzarse en crear un diseño de modo que el usuario encuentre evidente el manejo del applet a primera vista.

9.8.1. EL GESTOR FlowLayout

FlowLayout es un gestor que pone los contro-les en una línea, como puede verse en la fi-gura

376 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

Si se cambia el tamaño del applet y los con-troles no caben en una línea, pasan a la lí-nea siguiente, como puede verse en la figura.

El código fuente

Los controles son objetos de la clase Button, y el gestor de diseño es un objeto de la cla-se FlowLayout. Una vez inicializados los miembros dato, en la función miembro init se establecen sus propiedades y se añaden al ap-plet mediante la función add, una vez esta-blecido el gestor de diseño mediante setLa-yout. Los pasos son los siguientes:

• Crear los botones (objetos de la clase Button) y el gestor de diseño (objeto de la clase FlowLayout)

Button btn1 = new Button(); FlowLayout flowLayout1 = new FlowLayout();

• Establecer sus propiedades en init

PROGRAMACION CON JAVA 2 377

btn1.setFont(new Font("Dialog", 1, 16)); btn1.setLabel("1"); flowLayout1.setHgap(20);

• Establecer el gestor de diseño del ap-plet (o de un panel) mediante setLayout

this.setLayout(flowLayout1);

• Añadir los controles al applet (o a un panel) mediante add

this.add(btn1, null);

Lo que se ha dicho para un applet vale para cualquier panel, ya que un applet no es otra cosa que un panel especializado.

public class FlowApplet extends Applet { Button btn1 = new Button(); Button btn2 = new Button(); Button btn3 = new Button(); Button btn4 = new Button(); FlowLayout flowLayout1 = new FlowLayout(); public void init() { setBackground(Color.white); btn1.setFont(new Font("Dialog", 1, 16)); btn1.setLabel("1"); btn2.setFont(new Font("Dialog", 1, 16)); btn2.setLabel("2"); btn3.setFont(new Font("Dialog", 1, 16)); btn3.setLabel("3"); btn4.setFont(new Font("Dialog", 1, 16)); btn4.setLabel("4"); flowLayout1.setHgap(20); this.setLayout(flowLayout1); this.add(btn1, null); this.add(btn2, null); this.add(btn3, null); this.add(btn4, null); } } 9.8.2. EL GESTOR BorderLayout

Los pasos para establecer el gestor BorderLa-yout son distintos a los empleados para el gestor FlowLayout.

378 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

• Crear los botones (objetos de la clase Button) y el gestor de diseño (objeto de la clase BorderLayout)

Button btnOeste = new Button(); BorderLayout borderLayout1 = new BorderLayout();

• Establecer sus propiedades en init

btnOeste.setFont(new Font("Dialog", 1, 16)); btn1.setLabel("Oeste");

• Añadir los controles al applet (o a un panel) mediante add, indicando en el se-gundo argumento la posición que ocupará cada control en el panel mediante miem-bros estáticos de la clase BorderLayout.

this.add(btnOeste, BorderLayout.WEST);

En este ejemplo, se han creado cinco botones cuyos títulos son Oeste, Norte, Sur, Este y Centro. Cuando se aplica el gestor BorderLa-yout al applet los cinco botones se disponen como se muestra en la figura.

Public class BorderApplet extends Applet { Button btnOeste = new Button(); Button btnEste = new Button(); Button btnNorte = new Button(); Button btnSur = new Button(); Button btnCentro = new Button();

PROGRAMACION CON JAVA 2 379

BorderLayout borderLayout1 = new BorderLayout(); public void init() { setBackground(Color.white); this.setSize(new Dimension(336, 253)); this.setLayout(borderLayout1); btnOeste.setFont(new Font("Dialog", 1, 16)); btnOeste.setLabel("Oeste"); btnEste.setFont(new Font("Dialog", 1, 16)); btnEste.setLabel("Este"); btnNorte.setFont(new Font("Dialog", 1, 16)); btnNorte.setLabel("Norte"); btnSur.setFont(new Font("Dialog", 1, 16)); btnSur.setLabel("Sur"); btnCentro.setFont(new Font("Dialog", 1, 16)); btnCentro.setLabel("Centro"); borderLayout1.setVgap(20); borderLayout1.setHgap(20); this.add(btnOeste, BorderLayout.WEST); this.add(btnEste, BorderLayout.EAST); this.add(btnNorte, BorderLayout.NORTH); this.add(btnSur, BorderLayout.SOUTH); this.add(btnCentro, BorderLayout.CENTER); } }

9.8.3. EL GESTOR GridLayout

Los pasos para establecer el gestor GridLayout son idénticos a los que hemos seguido para establecer lel gestor FlowLayout. Este gestor dispone los controles en forma de un matriz tal como puede verse en la figura. Tenemos ocho botones dispuestos en dos filas y en cuatro columnas.

380 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

Para disponer los controles de esta manera, hemos de seleccionar el objeto gridLayout1 en el panel de estructura y cambiar las popieda-des columns y rows. Opcionalmente podemos es-tablecer un espaciado vertical y horizontal entre los controles, introduciendo valores las propiedades hgap y vgap.

public class GridApplet extends Applet { Button btn00 = new Button(); Button btn01 = new Button(); Button btn02 = new Button(); Button btn03 = new Button(); Button btn10 = new Button(); Button btn11 = new Button(); Button btn12 = new Button(); Button btn13 = new Button(); GridLayout gridLayout1 = new GridLayout(); public void init() { setBackground(Color.white); btn00.setFont(new Font("Dialog", 1, 16));

PROGRAMACION CON JAVA 2 381

btn00.setLabel("00"); btn01.setFont(new Font("Dialog", 1, 16)); btn01.setLabel("01"); btn02.setFont(new Font("Dialog", 1, 16)); btn02.setLabel("02"); btn03.setFont(new Font("Dialog", 1, 16)); btn03.setLabel("03"); btn10.setFont(new Font("Dialog", 1, 16)); btn10.setLabel("10"); btn11.setFont(new Font("Dialog", 1, 16)); btn11.setLabel("11"); btn12.setFont(new Font("Dialog", 1, 16)); btn12.setLabel("12"); btn13.setFont(new Font("Dialog", 1, 16)); btn13.setLabel("13"); gridLayout1.setRows(2); gridLayout1.setHgap(10); gridLayout1.setColumns(3); gridLayout1.setVgap(10); this.setLayout(gridLayout1); this.add(btn00, null); this.add(btn01, null); this.add(btn02, null); this.add(btn03, null); this.add(btn10, null); this.add(btn11, null); this.add(btn12, null); this.add(btn13, null); } }

9.9. EL GESTOR DE DISEÑO GRIDBAGLAYOUT El gestor de diseño GridBagLayout es muy complicado, ya que está gobernado por un conjunto de propiedades que están interelacionados entre sí. Los componentes se disponen en una matriz tal como vimos al estudiar el gestor GridLayout. En la figura vemos la disposi-ción de los controles y a la derecha los valores de los propiedades de dicho gestor para el primer control (en color gris oscuro)

9.9.1. EJEMPLO: DISEÑO DE UNA FICHA

Vamos a estudiar los pasos necesarios para crear una ficha como la que muestra la figura empleando el gestor de diseño GridBagLayout

382 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

Añadimos un panel en la parte inferior del applet y varios controles en la parte supe-rior. Sobre el panel situamos dos botones.

9.9.2. EL PANEL

Poner un panel en la parte inferior y cambiar su propiedad name

Panel panelBotones = new Panel();

Seleccionar en el panel panelBotones y cambiar su propiedad layout a XYLayout

Poner dos botones sobre el panel. Cambiar sus propiedades name y label

Button btnPago=new Button();

PROGRAMACION CON JAVA 2 383

Button btnCancelar=new Button(); btnPago.setLabel("Comprar"); btnCancelar.setLabel("Cancelar");

Seleccionar de nuevo en el panel panelBotones y cambiar su propiedad layout a FlowLayout. Los botones se sitúan en el centro del panel. Opcionalmente, establecer un espaciado hori-zontal entre los botones.

9.9.3. EL APPLET

Situar los siguientes controles sobre el ap-plet cambiando su propiedad name.

Label titulo=new Label(); Label nombre=new Label(); Label direccion=new Label(); Label pago=new Label(); Label telefono=new Label(); Label ciudad=new Label(); Label provincia=new Label(); TextField textNombre=new TextField(); TextField textDireccion=new TextField(); TextField textCiudad=new TextField(); TextField textProvincia=new TextField(); Choice chPago=new Choice();

Cambiar las propiedades de los controles a los valores que se indican en el código de la función miembro init.

titulo.setText("Compre algo ahora"); titulo.setFont(new Font("Times-Roman", Font.BOLD + Font.ITALIC, 16)); nombre.setText("Nombre:"); direccion.setText("Dirección:"); pago.setText("Método de pago:"); telefono.setText("Teléfono:"); ciudad.setText("Ciudad:"); provincia.setText("Provincia:"); textNombre.setColumns(25); textDireccion.setColumns(25); textCiudad.setColumns(15); textProvincia.setColumns(2); btnPago.setLabel("Comprar"); btnCancelar.setLabel("Cancelar");

384 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

Añadir elementos al control selección (Choi-ce) denominado chPago.

chPago.add("Visa"); chPago.add("MasterCard"); chPago.add("Caja Ahorros");

9.9.4. EL GESTOR DE DISEÑO GRIDBAGLAYOUT

Crear dos objetos uno de la clase GridBagLayout y otro de la clase GridBagConstraints. El segundo objeto establece los constraints. El objeto gbc tiene los valores por defecto que hemos mencionado en el primer apartado. Si se cambia un valor de una propiedad (gridwidth, anchor, fill, etc) el cambio permanece hasta que se vuelve a establecer otro valor.

GridBagLayout gbl=new GridBagLayout(); GridBagConstraints gbc=new GridBagConstraints();

Establecer el gestor de diseño GridBagLayout mediante setLayout.

setLayout(gbl);

9.9.5. AÑADIR LOS COMPONENTES AL APPLET

Se añade un componente al applet (o a un pa-nel) en el que se ha establecido el gestor de diseño GridBagLayout, y se han definido los constraints del siguiente modo.

add(componente, constraints);

La primera fila está formada por un único (REMAINDER) componente el titulo, centrado en la parte superior (NORTH)

gbc.anchor=GridBagConstraints.NORTH; gbc.gridwidth=GridBagConstraints.REMAINDER; add(titulo, gbc);

PROGRAMACION CON JAVA 2 385

La segunda fila, está formada por dos contro-les, nombre y a continuación textNombre. El primero está anclado (anchor) al este (WEST), antes estaba en NORTH, gridwidth toma el va-lor 1 (por defecto) antes estaba en REMAIN-DER. Como textNombre es el último control de la fila gridwidth vuelve a tomar el valor RE-MAINDER. Los controles ocupan todo el espacio horizontal disponible, la propiedad fill toma el valor HORIZONTAL

gbc.fill=GridBagConstraints.HORIZONTAL; gbc.anchor=GridBagConstraints.WEST; gbc.gridwidth=1; add(nombre, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; add(textNombre, gbc);

La tercera fila, está formada por dos contro-les: direccion y textDireccion. Las propieda-des anchor y fill ya tienen fijados sus valo-res a WEST y HORIZONTAL, por lo que no hay que volver a establecerlo. Como textDireccion es el último control de la fila su propiedad gridwidth toma el valor REMAINDER.

gbc.gridwidth = 1; add(direccion, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; add(textDireccion, gbc);

La cuarta fila, está formada por cuatro con-troles: ciudad, textCiudad, provincia y text-Provincia. Cuando se coloca el último control textProvincia, su propiedad gridwidth toma el valor REMAINDER.

gbc.gridwidth = 1; add(ciudad, gbc); add(textCiudad, gbc); add(provincia, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; add(textProvincia, gbc);

La quinat fila, está formada por dos contro-les: pago y chPago. El código es semejante, salvo la propiedad fill que toma el valor NO-NE antes estaba en HORIZONTAL. Esto hace que el control chPago no ocupe toda el área dis-ponible, extendiéndose horizontalmente hasta

386 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

alinearse con los otros controles por la par-te derecha.

gbc.gridwidth = 1; add(pago, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.fill=GridBagConstraints.NONE; add(chPago, gbc);

Finalmente, añadimos el panel panelBotones centrado. Cambiamos la propiedad anchor de WEST a SOUTH.

gbc.anchor=GridBagConstraints.SOUTH; add(panelBotones, gbc);

Terminamos el diseño de la ficha separando convenientemente las filas de controles con objetos de la clase Insets, tal como se mues-tra en el código.

public class GridBagApplet1 extends Applet { Panel panelBotones = new Panel(); Label titulo=new Label(); Label nombre=new Label(); Label direccion=new Label(); Label pago=new Label(); Label telefono=new Label(); Label ciudad=new Label(); Label provincia=new Label(); TextField textNombre=new TextField(); TextField textDireccion=new TextField(); TextField textCiudad=new TextField(); TextField textProvincia=new TextField(); Choice chPago=new Choice(); Button btnPago=new Button(); Button btnCancelar=new Button(); GridBagLayout gbl=new GridBagLayout(); GridBagConstraints gbc=new GridBagConstraints(); FlowLayout flowLayout1=new FlowLayout(); public void init() { setBackground(Color.lightGray); //propiedades de los controles titulo.setText("Compre algo ahora");

PROGRAMACION CON JAVA 2 387

titulo.setFont(new Font("Times-Roman", Font.BOLD + Font.ITALIC, 16)); nombre.setText("Nombre:"); direccion.setText("Dirección:"); pago.setText("Método de pago:"); telefono.setText("Teléfono:"); ciudad.setText("Ciudad:"); provincia.setText("Provincia:"); textNombre.setColumns(25); textDireccion.setColumns(25); textCiudad.setColumns(15); textProvincia.setColumns(2); btnPago.setLabel("Comprar"); btnCancelar.setLabel("Cancelar"); chPago.add("Visa"); chPago.add("MasterCard"); chPago.add("Caja Ahorros"); //gestor gridBaglayout setLayout(gbl); //primera fila - título gbc.anchor=GridBagConstraints.NORTH; gbc.insets=new Insets(0,0,10,0); gbc.gridwidth=GridBagConstraints.REMAINDER; add(titulo, gbc); //segunda fila - nombre gbc.fill=GridBagConstraints.HORIZONTAL; gbc.anchor=GridBagConstraints.WEST; gbc.gridwidth=1; gbc.insets=new Insets(0,0,0,0); add(nombre, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; add(textNombre, gbc); //tercera fila - dirección gbc.gridwidth = 1; add(direccion, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; add(textDireccion, gbc); //cuarta fila - ciudad - provincia gbc.gridwidth = 1; add(ciudad, gbc); add(textCiudad, gbc); add(provincia, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; add(textProvincia, gbc); //quinta fila - pago gbc.gridwidth = 1; add(pago, gbc); gbc.insets=new Insets(5,0,5,0); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.fill=GridBagConstraints.NONE; add(chPago, gbc); //panel de los botones panelBotones.setLayout(flowLayout1);

388 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

panelBotones.add(btnPago); panelBotones.add(btnCancelar); gbc.anchor=GridBagConstraints.SOUTH; gbc.insets=new Insets(15,0,0,0); add(panelBotones, gbc); } }

PROGRAMACION CON JAVA 2 389

CAPITULO DIEZ

HILO Y SINCRONIZACIÓN

La programación multihilo es un paradigma conceptual de la programación por el cual se dividen los programs en dos o más procesos que se pueden ejecutar en paralelo. En un momento dado pueden haber datos de entrada de usuario a los que res-ponder, animaciones y visualizaciones de interfaz de usuario, también cálculos grandes que podrían tardar varios segundos en terminar, y nuestros programas tendrán que tratar con es-tos temas sin provocar retrasos desagradables al usuario.

Lo interesante de todos estos procesos en paralelo es que la mayor parte de ellos realmente no necesitan los recursos com-pletos de la computadora durante su vida operativa. El pro-blema en los entornos de hilo único tradicionales es que se tiene que esperar a que se terminen cada una de estas tareas antes de proseguir con la siguiente. Aunque la CPU esté libre la mayor parte del tiempo, tiene que colocar las tareas en la cola ordenadamente.

10.1. EL MODELO DE HILO DE JAVA Los sistemas multihilo aprovechan la circunstancia de que la mayoría de los hilos computacionales invierten la mayor parte del tiempo esperando a que un recurso quede disponible, o bien esperando a que se cumpla al-guna condición de temporización. Si fuésemos capaces de describir todas las tareas como hilos de control independientes, conmutando de manera automática entre

390 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

una tarea que esté lista para pasar a un modo de espe-ra, y otra que sí tenga algo que hacer, conseguiríamos realizar una cantidad mayor de trabajo en le mismo in-tervalo de tiempo.

Java se diseño partiendo de cero, en un mundo en el que el entorno multihilo, a nivel de sistema operati-vo, era una realidad. El intérprete de Java hace uso intensivo de hilos para multitud de propósitos, y to-das las bibliotecas de clases se diseñaron teniendo en mente el modelo multihilo. Una vez que un hilo comien-za su tarea, puede suspenderse, lo que equivale a de-tener temporalmente su actividad. El hilo suspendido puede reanudarse, lo que supone que continúa su tarea allí donde la dejó. En cualquier momento, un hilo pue-de deteriores, finalizando su ejecución de manera in-mediata. Una vez detenido, el proceso no puede reini-ciarse.

10.1.1. PRIORIDADES DE HILO

El intérprete de Java utiliza prioridades pa-ra determinar cómo debe comportarse cada hilo con respecto a los demás. Las prioridades de hilo son valores entre 1 y 10 que indican la prioridad relativa de un hilo con respecto a los demás.

10.1.2. SINCRONIZACIÓN

Ya que los hilos permiten y potencian el com-portamiento asíncrono de los programas, debe existir alguna manera de forzar el sincronis-mo allí donde sea necesario. Por ejemplo, si desease que dos hilos se comunicasen para compartir una estructura de datos compleja (como una lista enlazada), necesitará alguna manera de garantizar que cada uno se aparte del camino del otro. Java incorpora una ver-sión rebuscada de un modelo clásico para la sincronización, el monitor. La mayor parte de los sistemas multihilo implementan los moni-tores a modo de objetos, pero Java proporcio-na una solución más elegante: no existe la clase monitor, cada objeto lleva asociado su propio monitor implícito, en el que puede en-trar sin más que hacer una llamada a los mé-todos synchronized del objeto. Una vez que el hilo está dentro del método synchronized,

PROGRAMACION CON JAVA 2 391

ningún otro hilo puede efectuar una llamada a otro método synchronized sobre el mismo obje-to.

10.1.3. INTERCAMBIO DE MENSAJES

Una vez que el programa se ha dividido en sus partes lógicas, a modo de hilo, es preciso definir exactamente como se comunicarán entre si dichos hilos. Java utiliza los métodos wait y notify para el intercambio de informa-ción entre hilos.

10.2. THREAD En Java los hilos se representa mediante una clase. La clase Thread encapsula todo el control necesario sobre los hilos. Hay que tomar la precaución de distinguir claramente un objeto Thread de un hilo en ejecución. Un objeto Thread se define como el panel de control o proxy de un hilo en ejecución. En el objeto Thread hay métodos que controlan si el hilo se está ejecutando, está durmiendo, en suspenso o detenido. La clase Thread es la única manera de controlar el comporta-miento de los hilos. En la siguiente instrucción se muestra como acceder al hilo en ejecución actual:

Thread t = Thread.currentThread();

* el hilo actual se almacena en la variable t *

10.3. RUNNABLE Si queremos tener más de un hilo necesitamos crear otra instancia de Thread. Cuando construimos una nueva instancia de Thread, necesitamos decirle que código ejecutar en el nuevo hilo de control. Se puede comen-zar un hilo sobre cualquier objeto que implemente la interfaz Runnable.

Runnable es una interfaz simple que abstrae la noción de que se desea que algún código se "ejecute" asíncro-namente. Para implementar Runnable, a una clase le basta con implementar un solo método llamado run. Este es un ejemplo que crea un nuevo hilo.

392 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

class ThreadDemo implements Runnable { ThreadDemo() { Thread ct = Thread.currentThread(); Thread t = new Thread(this, "demo Thread"); System.out.println("hilo actual: " + ct); System.out.println("Hilo creado: " + t); t.start(); try { Thread.sleep(3000); } catch (interrupteExecption e) { System.out.println("Interrumpido"); } System.out.println(!saliendo del hilo main"); } public void run() { try { for >(int y = 5; y > 0; y--) { System.out.println(" " + i); Thread.sleep(1000); } } catch (InterruptedException e) { System.out.println("hijo interrumpi-do"); } System.out.println("saliendo del hilo hijo"); } public static void main (String args []) { new ThreadDemo(); } }

El hilo main crea un nuevo objeto Thread, con new Thread (this, "Demo Thread"), pasando this como primer argumento para indicar que queremos que el nuevo hilo llame al método run sobre este (this) objeto. A conti-nuación llamamos a start, lo que inicia el hilo de la ejecución a partir del método run. Después, el hilo main se duerme durante 3000 milisegundos antes de im-primir un mensaje y después termina. Demo Thread toda-vía está contando desde cinco cuando sucede esto. Se continúa ejecutando hasta que termina con el bucle de run. Esta es la salida después de cinco segundos:

C:\> java ThreadDemo Hilo actual: Thread[main, 5, main] Hilo creado: Thread[demo Thread, 5, main] 5 4

PROGRAMACION CON JAVA 2 393

3 saliendo del hilo main 2 1 saliendo del hilo hijo

10.4. PRIORIDADES DE LOS HILOS El planificador de hilos hace uso de las prioridades de los mismos para decidir cuándo debe dejar a cada hilo que se ejecute, de manera que los hilos con mayor prioridad deben ejecutarse más a menudo que lo de me-nor prioridad. Cuando está ejecutándose un hilo de ba-ja prioridad, y otro de mayor prioridad se despierta de su sueño, o de la espera por un operación de E/S, debe dejarse que se ejecute de manera inmediata, des-alojando al hilo de menor prioridad. Cuando los hilos son de igual prioridad deben desalojarse los unos a los otros, cada cierto tiempo, utilizando el algoritmo circular round-robin para gestionar el acceso al la CPU.

En JDK 1.0 la planificación de hilos es un problema que no está completamente resuelto. Por lo que si pre-tendemos tener un comportamiento predecible sobre las aplicaciones deberemos utilizar hilos que, voluntaria-mente, cedan el control de la CPU.

10.5. SINCRONIZACIÓN Cuando dos o más hilos necesitan acceder de manera si-multánea a un recurso de datos compartido necesitan asegurarse de que sólo uno de ellos accede al mismo cada vez. Java proporciona un soporte único, el moni-tor, es un objeto que se utiliza como cerrojo exclusi-vo. Solo uno de los hilos puede ser el propietario de un monitor en un instante dado. Los restantes hilos que estuviesen intentando acceder al monitor bloqueado quedan en suspenso hasta que el hilo propietario salga del monitor.

Todos los objetos de Java disponen de un monitor pro-pio implícitamente asociado a ellos. La manera de ac-ceder a un objeto monitor es llamando a un método mar-cado con la palabra clave synchronized. Durante todo el tiempo en que un hilo permanezca en un método sin-cronizado, los demás hilos que intenten llamar a un método sincronizado sobre la misma instancia tendrán

394 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

que esperar. Para salir del monitor y permitir el con-trol del objeto al siguiente hilo en espera, el pro-pietario del monitor sólo tiene que volver del método

10.5.1. LA SENTENCIA SYNCHRONIZED

Si se utiliza una clase que no fue diseñada para accesos multihilo y, por ello, dispone de métodos no sincronizados que manipulan el estado interno, puede envolver la llamada al método en un bloque sincronizado. El formato general de la sentencia sincronizada es el siguiente:

synchronized(objeto) sentencia;

En el ejemplo, objeto es cualquier referencia al objeto, y sentencia suele ser un bloque que incluye una llamada al método de objeto, que solo tendrá lugar una vez que el hilo haya entrado con éxito en el monitor de obje-to. Ahora veremos las formas de sincroniza-ción con un ejemplo:

class Callme { void call (String msg) { * también podía haber puesto synchronized antes de void * System.out.print("[" + msg); try Thread.sleep(1000); catch (Exception e); System.out.println("]"); } } class caller implements Runnable { String msg; Callme target; public caller(Callme t, String s) { target = t; msg = s; new Thread(this).start(); } public void run() { synchronized(target) { target.call(msg); } } } class Synch { public static void main(String args[]) { Callme target = new Callme(); new caller(target, "Hola"); new caller(target, "Mundo"); new caller(target, "Sincronizado");

PROGRAMACION CON JAVA 2 395

} }

Este programa imprime por pantalla el literal "Hola Mundo Sincronizado", cada palabra en una línea y entre comillas, se crea una instancia de Callme y tres ins-tancias de caller que cada una de ellas referencia al mismo Callme con lo que necesitamos de una sincroniza-ción para el acceso a Callme, pues sino se mezclarían las tres llamada al haber una sentencia sleep que re-trasa la ejecución de Callme dando lugar a que antes de que acabe un proceso deje libre el acceso a dicho objeto.

10.6. COMUNICACIÓN ENTRE HILOS Veamos, por ejemplo, el problema clásico de las colas, donde uno de los hilos produce datos y otro los consu-me. Para que el problema sea más interesante suponga-mos que el productor tiene que esperar a que el consu-midor haya terminado, para empezar a producir más da-tos. En un sistema basado en sondeo el consumidor es-taría desperdiciando ciclos de CPU mientras espera a que el productor produzca. Una vez que el productor ha terminado, se queda sondeando hasta ver que el consu-midor ha finalizado, y así sucesivamente.

Evidentemente, hay una forma mejor de hacerlo. Java proporciona un mecanismo elegante de comunicación en-tre procesos, a través de los métodos wait, notify y notifyAll. Estos métodos se implementan como métodos de final en Object, de manera que todas las clases disponen de ellos. Cualquiera de los tres métodos sólo puede ser llamado desde dentro de un método synchroni-zed.

• wait: le indica al hilo en curso que abandone el monitor y se vaya a dormir hasta que otro hilo en-tre en el mismo monitor y llame a notify.

• notify: despierta al primer hilo que realizó una llamada a wait sobre el mismo objeto.

• notifyAll_: despierta todos los hilos que realiza-ron una llamada a wait sobre el mismo objeto. El hilo con mayor prioridad de los despertados es el primero en ejecutarse.

396 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

El ejemplo del productor y el consumidor es en Java como sigue:

class Q { int n; boolean valueSet = false; synchronized int get() { if (!valueSet) try wait(); catch(InterruptedException e); System.out.println("Obtenido: " + n); valueSet = false; notify(); return n; } synchronized void put(int n) { if (valueSet) try wait(); catch(InterruptedException e); this.n = n; valueSet = true; System.out.println("Colocado: " + n); notify(); } } class Producer implements Runnable { Q q; Producer (Q q) { this.q = q; new Thread(this, "Producer").start(); } public void run() { int y = 0; while(true) { q.put(i++); } } } class Consumer implements Runnable { Q q; Consumer(Q q) { this.q = q; new Thread(this, "Consumer").start(); } public void run() { while(true) { q.get(); } } class PC { public static void main(String args[]) { Q q = new Q(); new Producer(q); new Consumer(q); } }

PROGRAMACION CON JAVA 2 397

10.6.1. BLOQUEOS

Los bloqueos son condiciones anómalas inusua-les, pero muy difíciles de depurar, donde dos hilos presentan una dependencia circular so-bre un par de objetos sincronizados. Por ejemplo, si un hilo entra en el monitor sobre el objeto X y otro hilo entra en le monitor sobre el objeto Y, y si X intenta llamar a cualquier método sincronizado sobre Y, tal y como cabe esperar quedará detenido. Sin em-bargo, si Y, por su parte, intenta llamar a cualquier método sincronizado con X, entonces quedará esperando indefinidamente, ya que pa-ra conseguir el cerrojo de X tendría antes que liberar su propio cerrojo en Y, con el fin de que el primer hilo pudiera completar-se.

10.7. RESUMEN DE LA INTERFAZ DE PROGRAMACIÓN (API) DE HILOS

Se incluye a continuación una referencia rápida a to-dos los métodos de la clase Thread que se han comenta-do en este capítulo.

10.7.1. MÉTODOS DE CLASE

Estos son los métodos estáticos que deben llamarse de manera directa en la clase Thread.

• currentThread: el método estático de-vuelve el objeto Thread que representa al hilo que se ejecuta actualmente.

• yield: este método hace que el intérpre-te cambie de contexto entre el hilo ac-tual y el siguiente hilo ejecutable dis-ponible. Es una manera de asegurar que los hilos de menor prioridad no sufran inanición.

• Sleep(int n): el método sleep provoca que el intérprete ponga al hilo en curso a dormir durante n milisegundos. Una vez transcurridos los n milisegundos, dicho hilo volverá a estar disponible para su

398 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

ejecución. Los relojes asociados a la mayor parte de los intérpretes Java nos serán capaces de obtener precisiones ma-yores de 10 milisegundos.

10.7.2. MÉTODOS DE INSTANCIA

• start: indica al intérprete de Java que cree un contexto de hilo del sistema y comience a ejecutarlo. A continuación, el método run objeto de este hilo será llamado en el nuevo contexto del hilo. Debe tomarse la precaución de no llamar al método start más de una vez sobre un objeto hilo dado.

• run: constituye el cuerpo de un hilo en ejecución. Este es el único método de la interfaz Runnable. Es llamado por el mé-todo start después de que el hilo apro-piado del sistema se haya inicializado. Siempre que el método run devuelva el control, el hilo actual se detendrá.

• stop: provoca que el hilo se detenga de manera inmediata. A menudo constituye una manera brusca de detener un hilo, especialmente si este método se ejecuta sobre el hilo en curso. En tal caso, la línea inmediatamente posterior a la lla-mada al método stop no llega a ejecutar-se jamás, pues el contexto del hilo mue-re antes de que stop devuelva el con-trol.

• suspend: es distinto de stop. suspend toma el hilo y provoca que se detenga su ejecución sin destruir el hilo de siste-ma subyacente, ni el estado del hilo an-teriormente en ejecución. Si la ejecu-ción de un hilo se suspende, puede lla-marse a resume sobre el mismo hilo para lograr que vuelva a ejecutarse de nuevo.

• resume: se utiliza para revivir un hilo suspendido.

PROGRAMACION CON JAVA 2 399

• setPriority(int p): asigna al hilo la prioridad indicada por el valor entero pasado como parámetro.

• getPriority: devuelve la prioridad del hilo en curso, que es un valor entre 1 y 10.

• setName(String nombre): identifica al hilo con un nombre mnemónico. De esta manera se facilita la depuración de pro-gramas multihilo.

• getName: devuelve el valor actual, de tipo cadena, asignado como nombre al hilo mediante setName.

PROGRAMACION CON JAVA 2 401

BIBLIOGRAFIA

1. Allen Weiss, Mark (2000). “Estructuras de Datos en Java, compatible con Java 2”. Editorial Addison Wesley. España.

2. Ceballos Sierra, Javier (2000). “JAVA 2 Curso de Programa-ción”. Editorial Alfaomega-Rama. México.

3. December, John (1996). “Introducción a Java”. Editorial Prentice Hall. México.

4. Decker, Rick y Hirshfield, Stuart (2001). “Introducción a la Programación en Java”. Segunda edición. México.

5. Deitel, H. M. y Deitel, P. J.(1998).”Cómo programar en Ja-va”. Editorial Prentice Hall. México.

6. Froufe Quintas, Agustín (2000). “JAVA 2 Manual de usuario y tutorial”. Editorial Alfaomega-Rama. México.

7. J. Koosis, Donald y S. Koosis, David (1996). “Java Pro-gramming For Dummies”. Editorial IDG Books. USA.

8. S. Wang, Paul (2000). “Java con programación orientada a objetos y aplicaciones en la World Wide Web”. Editorial Thomson. México.