0% encontró este documento útil (0 votos)
269 vistas421 páginas

Libro Java2 GMV

nb

Cargado por

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

Libro Java2 GMV

nb

Cargado por

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

UNIVERSIDAD

NACIONAL DE
INGENIERIA

PROGRAMACION CON JAVA 2

Ing. Gilmer Matos Vila


CIP 77324
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
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
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
iii
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
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
iv Ing. Gilmer Matos Vila
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
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.............................................................................................................................396
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

v
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écnicas 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
Microsystems(TM), Inc.

El primer Capitulo I trata sobre las características del


lenguaje 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 sentencias de control, y. En el Capitulo II detalla sobre
los arreglos y la gestión de de cadenas. El Capitulo III se
detalla las características de la Programación Orientada a
PROGRAMACION CON JAVA 2 1
Objetos. El Capítulo IV contempla el tratamiento de errores
en tiempo de compilación conocido también como gestión de
excepciones. El Capítulo V tratao sobre el uso de paquetes en
Java. 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 permitirán usar concurrentemente los recursos de un
ordenador.

2 Ing. Gilmer Matos Vila


CAPITULO 1

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
convencionales 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
compilador Java puede transportarse a cualquier
plataforma (Intel, Sparc. Motorola, etc.) que tenga
instalada una máquina virtual Java y ejecutarse.
Pensando en internet 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 diferente 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


compilador 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.

PROGRAMACION CON JAVA 2 3


Programa Código de Máquina
escrito Compilador bytes virtual
en Java de Java

Los códigos de bytes de Java son un conjunto de


instrucciones 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 sistemas 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 aplicaciones de Internet
(denominadas applets) la máquina virtual está incluida
en el navegador y para las aplicaciones Java
convencionales, puede venir con el sistema operativo,
con el paquete Java, o bien puede obtenerla 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
proyecto de investigación para desarrollar software
para comunicación entre aparatos electrónicos de
consumo como vídeos, televisores, equipos de música.
etc. Durante 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 escribir 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
proyecto 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
4 Ing. Gilmer Matos Vila
que conecta múltiples ordenadores con diferentes
sistemas operativos y diferentes arquitecturas de
microprocesadores, pero todos tienen en común un
navegador que utilizan para comunicarse entre sí. Esta
idea hizo que el grupo investigador 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
cualquier ordenador, independientemente de su sistema
operativo 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
programación no tiene competidores. No obstante, con
Java se puede programar cualquier cosa, razón por la
que tambié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
tenga que desarrollar aplicaciones que tengan que
ejecutarse 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.


Java es un lenguaje fácil de aprender. Tiene un tamaño
pequeño que favorece el desarrollo y reduce las
posibilidades de cometer errores: a la vez es potente
y flexible.

PROGRAMACION CON JAVA 2 5


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
advierte a los potenciales usuarios de Java que en
este lenguaje no existen punteros ni aritmética de
punteros, las cadenas de caracteres son objetos y la
administració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,


STANDARD EDITION VERSION 1.4.0.
Ejecutar el archivo JAVA\j2sdk-1_4_0_03-
windows-i586.exe desde el CD-ROM para
instalar 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
aplicaciones de la plataforma Java (se asume
que el Java esta instalado en c:\j2sdk1.4.0).

c:\j2sdk1.4.0

6 Ing. Gilmer Matos Vila


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

c:\j2sdk1.4.0\bin

Los archivos ejecutables para el desarrollo


de programas contenidos en el Kit de
desarrollo 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
Java. Los archivos ejecutables son idénticos
a los archivos en /j2sdk1.4.0/bin. La
herramienta 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

PROGRAMACION CON JAVA 2 7


Contiene los archivos DLL utilizados por la
Máquina Virtual Clásica Java 2 (Java 2
Classic Virtual Machine). Estos archivos
están presentes sólo en el Java 2 SDK. Ellos
no están incluidos con el Java 2 Runtime
Environment.

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

Contiene los archivos DLL utlizados por el


Java HotSpot Client Virtual Machine, que es
TM

implementado con la tecnología Java HotSpot.

c:\j2sdk1.4.0\jre\lib

Librerías, configuración de propiedades y


archivos 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
internacionalización.

Aparte del subdirectorio ext (descrito antes)


hay varios subdirectorios de recursos
adicionales 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
archivo JavaHelp jar va cuando este es
instalado.

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

Contiene archivos utilizados para la


administración de la seguridad. Estos
incluyen las políticas de seguridad
(java.policy) y los archivos de las
propiedades de seguridad (java.security).

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

8 Ing. Gilmer Matos Vila


Los archivos Jar conteniendo clases de apoyo
para applets pueden ser colocados en el
directorio lib/applet/. Este reduce el tiempo
de inicio para applets grandes, permitiendo a
las clases applet ser pre cargados desde el
sistema de archivos local teh, con el
cargador de clases applet, proporcionando las
mismas 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 2D TM


y
fiuncionalidad JFC\Swing.

c:\j2sdk1.4.0\demo\jpda

PROGRAMACION CON JAVA 2 9


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

c:\j2sdk1.4.0\demo\sound

Contiene código fuente con demos de sonido


Java.

c:\j2sdk1.4.0\include

Archivos de cabecera del lenguaje C que


apoyan la programación de código nativo
utilizando el Java Native Interface y el Java
Virtual Machine Debugger Interface.

c:\j2sdk1.4.0\include-old

Archivos de cabecera que apoyan la


programación de código nativo utilizando
interfaces antiguas. Estos archivos de
cabecera son proporcionados sólo por
compatibilidad hacia atrás. Estas interfaces
son desaprobadas, inseguras y no disponibles
en todas las máquinas 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


Integrado (Integrated Development Environment: IDE),
para Java, que proporciona al usuario un amplio rango
de funcionalidades 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.

10 Ing. Gilmer Matos Vila


 Internet Explorer 4 o superior
(opcional)

1.5.2. INSTALACION DE JCREATOR


Descomprimir el fichero de instalación
JCREATORPRO2\JCREATORSETUP.EXE en un
directorio 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
resolver un tipo determinado de problema o para
cumplir metas 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 utilizan 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


ejecutar la aplicación
PROGRAMACION CON JAVA 2 11
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
activa (o invoca) un método de ese objeto, le pasa
argumentos y obtiene el valor que devuelve. Los
objetos interactúan al enviar y recibir mensajes.

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
posibilidades de volver a usarlo. Un programa de Java
puede definir sus propias clases, utilizarlas ya
integradas 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
aplicaciones.

Escriba el siguiente código en el IDE


JCreator:

Ejemplo ( 0): Programa que imprime un


mensaje.

class programa1
{

12 Ing. Gilmer Matos Vila


public static void main
(String[] args)
{
System.out.println("Mi
primer programa!!!");
}
}
Para crear el programa elija File (Menú
principal), New, elija la ficha Files , Java
File, ingrese el nombre del archivo en
Filename, elija la carpeta donde se alojará
el archivo en Location y presione el clic en
Aceptar, tal como se muestra en la figura:

El código en el IDE JCreator queda:

PROGRAMACION CON JAVA 2 13


Para compilar el programa presione clic sobre

el icono , luego presione para


ejecutar el programa.

Usted ahora tiene el siguiente resultado:

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
siguientes 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

*/

/**

14 Ing. Gilmer Matos Vila


comentario de documentación, que pueden ser de una
o más líneas y pueden contener palabras claves que
comienzan 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
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


PROGRAMACION CON JAVA 2 15
1.9. PALABRAS CLAVES
Las siguientes son las palabras claves que están
definidas 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

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


utilizada en la actualidad

** indica una palabra clave que fue agregada desde


Java 2

También son palabras reservadas (aunque no son


palabras claves) las siguientes: true, false y null, y
por lo tanto no pueden ser utilizadas como
identificadores.

16 Ing. Gilmer Matos Vila


1.10. IDENTIFICADORES
Los identificadores se utilizan como nombres de clase,
método y variable. Un identificador puede ser
cualquier 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
identificador. Debemos explícitamente suministrar un
nombre 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 Unicode 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, escribimos 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
alcance 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 elementos del código. Se ampliará cuando se
utilice funciones.

PROGRAMACION CON JAVA 2 17


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
valor booleano. Por ejemplo, el valor de un
entero (int) es de 32 bits de datos en un
formato 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.

En la tabla siguiente listamos todos los


tipos 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.


Caracteres Unicode de 16 bits. Los caracteres alfa-
numéricos son los mismos que los ASCII con el bit alto
char
puesto a 0. El intervalo de valores va desde 0 hasta
65535 (valores de 16-bits sin signo).
Tamaño 8 bits. El intervalo de valores va desde -2 7
byte 7
hasta 2 -1 (-128 a 127)
Tamaño 16 bits. El intervalo de valores va desde -215
short
hasta 215-1 (-32768 a 32767)
Tamaño 32 bits. El intervalo de valores va desde -231
int
hasta 231-1 (-2147483648 a 2147483647)
Tamaño 64 bits. El intervalo de valores va desde -263
long
hasta 263-1 (-9223372036854775808 a 9223372036854775807)
Tamaño 32 bits. Números en coma flotante de simple
float precisió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

18 Ing. Gilmer Matos Vila


precisión. Estándar IEEE 754-1985. (de
4.94065645841246544e–324d a 1.7976931348623157e+308d.)

Los tipos básicos que utilizaremos en la


mayor 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
representados por la variable.

Una referencia es denominada un puntero, o


una dirección de memoria en otros lenguajes.
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:

Nombre del Referencia


objeto Un objeto o
un array

1.13. LITERALES
Un valor constante en Java se crea utilizando una
representación literal de él. Java utiliza cinco tipos
de elementos: enteros, reales en coma flotante,
booleanos, 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


literales y sus tipos de datos:

Literal Tipo de Datos


178 Int

8864L Long
PROGRAMACION CON JAVA 2 19
37.266 Double

37.266D double

87.363F float

26.77e3 double

'c' char
true boolean
false boolean
"Hola" String

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
binario 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


prefija 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


infija, que significa que el operador aparece entre
sus operandos:

op1 operador op2 //notación infija

El operador ternario es también infijo; cada


componente del operador aparece entre operandos:
20 Ing. Gilmer Matos Vila
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éticas 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 resultado.

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 después
de ser decrementado

1.14.2. OPERADORES RELACIONALES

Operador Uso Devuelve true si


> op1 > op2 op1 es mayor que op2
PROGRAMACION CON JAVA 2 21
>= 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

1.14.3. OPERADORES CONDICIONALES

Operador Uso Devuelve true si

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

||
op1 || Cualquiera de op1 u op2 es true, evalúa
op2 condicionalmente op2
! ! op op es false
op1 &
&
op2 op1 y op2 son ambos true, siempre evalúa op1 y op2

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

^
op1 ^ Si op1 y op2 son diferentes. Esto es si uno u otro de
op2 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

22 Ing. Gilmer Matos Vila


Operador Uso Operación

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

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

>>>
op1 >>> Corrimiento de bits de op1 hacia la derecha por la
op2 distancia de op2 (sin signo)
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.

PROGRAMACION CON JAVA 2 23


Accede al elemento de la posición op2
op1[ op2 ]
dentro 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.

Declara o llama al método denominado op1


() op1(parámetros) con los parámetros especificados. La lista
de parámetros puede ser una lista vacía.
La lista esta separada por comas.

Convierte (cast) op1 a tipo. Una excepción


(tipo) (tipo) op1 será lanzada si el tipo de op1 es
incompatible con tipo.

Crea un nuevo objeto o array. op1 puede


new new op1 ser una llamada a un constructor o la
especificación de un array.

Instanceof
op1 instanceof Devuelve verdadero si op1 es una instancia
op2 de op2

1.15. ENTRADA Y SALIDA BASICA


Con frecuencia los programas necesitan ingresar
informació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. Tambié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,
memoria, un socket) y lee la información en serie, de
esta manera:

24 Ing. Gilmer Matos Vila


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

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
Abrir el flujo
Mientras haya más información
Mientras haya más información
leer la información
escribir información
cerrar el flujo
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
jerarquías de clases basados en el tipo de datos (si
son caracteres o bytes) con el que operan.

PROGRAMACION CON JAVA 2 25


Flujo de carácter Flujo de byte

Hay veces que es más conveniente agrupar a las clases


por su propósito en vez de por el tipo de datos que
leen o escriben. Así, podemos cruzar los grupos de
flujos de acuerdo a como leen y escriben hacia
almacenes de datos o procesan la información a medida
que se va leyendo o escribiendo.

Flujo de carácter Flujo de byte

Flujo sumidero de
datos

Flujo de
procesamiento

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
derecha 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.).

26 Ing. Gilmer Matos Vila


Figura FUNDAMENTOS DEL java.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
misión es proporcionar miembros comunes que serán
compartidos 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
representan un flujo en el que un destino lee
bytes de un origen. Cuando una aplicación
define 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
PROGRAMACION CON JAVA 2 27
disponible. Devuelve un entero (int)
correspondiente 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
analizaremos 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 Ing. Gilmer Matos Vila


La biblioteca de Java proporciona el
flujo estándar de entrada, manipulado
por la clase system del paquete
java.lang, que es automáticamente
abierto cuando se inicia un programa y
cerrado 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
clases que representan un flujo para leer
caracteres desde un origen. Sus métodos son
análogos a los de la clase InputStream, con
la diferencia 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
representan un flujo en el que un origen
escribe 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
formas:

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


escribe el byte especificado en un flujo de
salida. 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
partir de su posición off, en un flujo de
salida.

Cada uno de estos métodos ha sido escrito


para que bloquee la ejecución del programa
que los invoque hasta que toda la salida
solicitada haya sido escrita.

De manera análoga a read utilizaremos la


clase 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
abstracta 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 Ing. Gilmer Matos Vila


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
excepció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
ocurren). 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


subclases 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


excepciones, 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 capturar las posibles excepciones que
pueden lanzar. Esto es algo a lo que nos
obliga el compilador 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 argumentos utilizados con un método son
correctos, con la única intención de
minimizar los posibles 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


IOException
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 ( 0):
//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
nombre del paquete.

32 Ing. Gilmer Matos Vila


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
datos primitivos mostrados en la sección 1.12.1.

Antes de mencionar el uso de los datos primitivos


ubiquémonos en la jerarquía de clases que se muestra
en la figura 1.2.

InputStream Reader

OutputStream Writer

Figura FUNDAMENTOS DEL java.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
PROGRAMACION CON JAVA 2 33
primitivos; 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


almacenarlo en un objeto String, lo tenemos que hacer
desde un flujo de la clase BufferedReader y para
escribir en el flujo out tenemos los métodos
proporcionados 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


puente para pasar flujos de bytes a flujos de
caracteres 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 Ing. Gilmer Matos Vila


Programa flujoE isr in Teclado

bytes
caracteres

Figura FUNDAMENTOS DEL java.3

Para realizar la lectura de las cadenas


utilizaremos 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.

PROGRAMACION CON JAVA 2 35


Ejemplo ( 0): 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
InputStreamReader(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 Ing. Gilmer Matos Vila
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
numé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 primitivos.

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
útiles 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
valor en un int: 231-1.
Static int MIN_VALUE
Una constante que contiene el minimo
valor en un int: -231.

Constructores
Integer(int value)
Construye un objeto Integer que representa el
valor especifico del int.
Integer(String s)
Construye un objeto Integer que representa el
valor int indicado por el parámetro String.

Ahora mostramos en el idioma original los


Métodos de la clase Integer1

1
Fuente: JDK HELP
PROGRAMACION CON JAVA 2 37
Métodos
byte byteValue()
Returns the value of this Integer as a
byte.
int compareTo(Integer anotherInteger)
Compares two Integer objects
numerically.
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
system 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)
38 Ing. Gilmer Matos Vila
Parses the string argument as a signed
integer in the radix specified by the second
argument.
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
base 2.
static String toHexString(int i)
Returns a string representation of the
integer argument as an unsigned integer in
base 16.
static String toOctalString(int i)
Returns a string representation of the
integer argument as an unsigned integer in
base 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
second 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
argument.

Class Float

La clase Float cubre un valor del tipo de


dato primitivo float dentro de un objeto.

PROGRAMACION CON JAVA 2 39


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.

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
primitive type float.

Constructores
Float(double value)
Constructs a newly allocated Float object that
represents the argument converted to type float.
Float(float value)
Constructs a newly allocated Float object that
represents the primitive float argument.
Float(String s)
Constructs a newly allocated Float object that
represents the floating-point value of type float represented
by the string.

2
Fuente: HELP JDK 2 Ver 1.4 (Idioma Original)
40 Ing. Gilmer Matos Vila
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
values.
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
specified object.
static int floatToIntBits(float value)
Returns a representation of the
specified floating-point value according to the
IEEE 754 floating-point "single format" bit
layout.
static int floatToRawIntBits(float value)
Returns a representation of the
specified 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
object.
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

PROGRAMACION CON JAVA 2 41


infinitely 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
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 float
value represented by the argument string s.

Ejemplo( 0): 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

42 Ing. Gilmer Matos Vila


InputStreamReader isr = new
InputStreamReader(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:
");
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 ( 0): 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
InputStreamReader(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 Ing. Gilmer Matos Vila


1.17. LA CLASE MATH
java.lang.Object
|
+--java.lang.Math

La clase Math contiene métodos para desarrollar


operaciones numéricas básicas tal como la
potenciación, logaritmo, raíz cuadrada y las funciones
trigonométricas.

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
value.
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
PROGRAMACION CON JAVA 2 45
the range of -pi/2 through pi/2.
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
negative infinity) double value that is not less
than the argument and is equal to a mathematical
integer.
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
positive 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
values.
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
values.
static flota min(float a, float b)

46 Ing. Gilmer Matos Vila


Returns the smaller of two float values.
static int min(int a, int b)
Returns the smaller of two int values.
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
mathematical integer.
static long round(double a)
Returns the closest long to the
argument.
static int round(float a)
Returns the closest int to the argument.
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 ( 0): Escriba un programa que
convierta coordenadas polares a coordenadas
cartesianas.

(X,Y)

x  r * cos 

y  r * sen 

//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: ");
sdato = flujoE.readLine(); // leer una línea de texto
teta=Float.parseFloat(sdato);//convierte cadena a float
48 Ing. Gilmer Matos Vila
//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
expresió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, constantes 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
sintaxis del lenguaje) que se evalúan a un único
valor. Podemos escribir expresiones compuestas
combinando expresiones simples. Cuando escribimos
expresiones compuestas, debemos ser explícitos e
indicar con paréntesis que operadores se deben evaluar
primero. Si elegimos 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
más sentencias juntas en un bloque con llaves ( { y
PROGRAMACION CON JAVA 2 49
} ). Aunque no se requiere, recomendamos utilizar
bloques con las sentencias de control de flujo, aún
cuando haya una sola sentencia en el bloque.

1.19. SENTENCIAS DE CONTROL DE FLUJO


Las sentencias de control de flujo se usan para
condicionar 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
ejecuta el primer bloque de sentencias y por
false el segundo.

Una forma abreviada es cuando tenemos una


sola sentencia, caso en el cual no hace falta
poner las llaves.

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

50 Ing. Gilmer Matos Vila


Se puede obviar la sentencia else.

Ejemplo ( 0): 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( 0): Hacer un programa que obtenga el


valor absoluto de un número (Versión 2).

52 Ing. Gilmer Matos Vila


//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
sentencias 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 ( 0): Escriba un programa que lea 3


números enteros e imprima el mayor.

54 Ing. Gilmer Matos Vila


//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 ( 0): Escriba un programa que calcule
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


56 Ing. Gilmer Matos Vila
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
// calcular la division
if (den==0)
if (num==0)
System.out.println("La divison es:
Indeterminado");
else
System.out.println("La divison es:
Infinito");
else
{ div=num/den;
System.out.println("La division :
"+div);
}
}
}

Ejemplo ( 0): Elaborar un programa donde se


ingrese el sueldo de un trabajador, su
respectiva categoría (A,B,C) y su año de
ingreso. Luego se calcule e imprima su nuevo
sueldo si el incremento es:

PROGRAMACION CON JAVA 2 57


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

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.

58 Ing. Gilmer Matos Vila


//archivo: sueldo.java

import java.io.*;

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
PROGRAMACION CON JAVA 2 59
// 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);


}
}

Nota: flujoE.skip(2), evita errores cuando se


realiza la lectura de datos a través del
flujo de entrada; porque permite saltar
'\r\n'(el retorno de carro y nueva línea) que
60 Ing. Gilmer Matos Vila
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 ( 0): 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


comisión es 50.00 u.m. mas 8% de las
ventas superiores a 500.00.

El programa calcula la comisión cuando se


ingresa las ventas.

PROGRAMACION CON JAVA 2 61


//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
62 Ing. Gilmer Matos Vila
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
decisiones 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
constantes de cada case. La ejecución de las
sentencias del bloque de la sentencia switch,
comienza en el case cuya constante coincida
PROGRAMACION CON JAVA 2 63
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
sentencias 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 final.

La sentencia break finaliza la ejecución de


la sentencia switch.

Ejemplo (0): Escribir un programa que lea un


carácter e identifique si es vocal o
consonante.

64 Ing. Gilmer Matos Vila


//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 (0) : Programa que lee un número de 1


a 12 e imprime el nombre del mes.

PROGRAMACION CON JAVA 2 65


66 Ing. Gilmer Matos Vila
//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
correspondientes. 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 default en último lugar, la
cual se ejecutará si mes no ha coincidido con
ningún valor explicitado, default no es
obligatorio y por lo tanto puede no estar.

PROGRAMACION CON JAVA 2 67


Ejemplo (0): 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 COSTO
TARIFA (U.M./Kw-h)
1 2.30
2 8.25
3 6.42
4 5.80
5 9.65

68 Ing. Gilmer Matos Vila


//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


PROGRAMACION CON JAVA 2 69
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
permanezca en true.

La sintaxis general es:

70 Ing. Gilmer Matos Vila


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


repetitivas

Ejemplo (0): 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
comporte 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:
PROGRAMACION CON JAVA 2 71
d = d + 1

Cada vez que se ejecute el ciclo repetitivo,


esta variable permitirá incrementar a d en
una unidad.

72 Ing. Gilmer Matos Vila


//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++;
}
}
}

PROGRAMACION CON JAVA 2 73


Ejemplo (0): 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
comporte 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.

74 Ing. Gilmer Matos Vila


//archivo: sumacifras.java

import java.io.*;
PROGRAMACION CON JAVA 2 75
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


while (while’s anidados)

Ejemplo (0): Escribir un programa que permita


calcular el promedio de los números positivos
ingresados por el teclado, el ingreso termina
cuando el número ingresado es CERO. (Usar
while)

Ejemplo:

76 Ing. Gilmer Matos Vila


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


ingresados es: 6

PROGRAMACION CON JAVA 2 77


//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

78 Ing. Gilmer Matos Vila


Ejemplo (0): Realice el diagrama de
actividades 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 vocales se ingresaron. La lectura de los
caracteres 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 while)

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)

PROGRAMACION CON JAVA 2 79


80 Ing. Gilmer Matos Vila
//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

PROGRAMACION CON JAVA 2 81


82 Ing. Gilmer Matos Vila
Ejemplo (0): Realice el diagrama de
actividades 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).

PROGRAMACION CON JAVA 2 83


84 Ing. Gilmer Matos Vila
PROGRAMACION CON JAVA 2 85
//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;
86 Ing. Gilmer Matos Vila
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 87


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

La sentencia do ... while ejecuta una


sentencia, simple o compuesta, una o mas
veces dependiendo del valor de una expresión.
Su sintaxis 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


finaliza con un punto y coma.

La ejecución de una sentencia do .. while


sucede 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.

88 Ing. Gilmer Matos Vila


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

Ejemplo (0): Escribir un programa que permita


calcular la suma de la siguiente serie, para
N términos; siendo N ingresado por teclado:
(Usar sólo do… while)

2 3 4 5 6 7 8
S 1        ...
2 ! 3 ! 4 ! 5 ! 6 ! 7 ! 8 !

N términos

PROGRAMACION CON JAVA 2 89


//archivo: serie.java

import java.io.*;

90 Ing. Gilmer Matos Vila


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 (0): 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 91


//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


92 Ing. Gilmer Matos Vila
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 (0): Escribir un programa que imprima


los “n” primeros números perfectos, si “n” es
ingresado por el teclado.

PROGRAMACION CON JAVA 2 93


94 Ing. Gilmer Matos Vila
//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 95


1.19.6. SENTENCIA for
La sentencia for permite ejecutar una
sentencia simple o compuesta, repetidamente
un número de veces conocido. Su sintaxis es
la siguiente:

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];


[progresión condición])

sentencia;

Donde:

 v1, v2, …, representan variables de


control 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


expresiones separadas por comas cuyos
valores 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


Compuesta,

96 Ing. Gilmer Matos Vila


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
siguiente sentencia del programa.

Por ejemplo, la siguiente sentencia for


imprime 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
declarado e iniciado en la propia sentencia
for (esto no se puede hacer en una sentencia
while; las variables que intervienen en la
condición de una sentencia while deben haber
sido declaradas 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
intervienen en la condición de finalización.

PROGRAMACION CON JAVA 2 97


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,


imprime los valores desde 1 hasta 10 con
incrementos 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
infinito tiene que pulsar las teclas Ctrl+C.

for (;;)

x++;

Ejemplo ( 0): Escribir un programa que


permita leer un número en base “m” y lo
convierta a otro número en base “n”. El
programa debe imprimir el número en base “n”.
Los valores de m y n son menores que 10 (Usar
sólo for)

98 Ing. Gilmer Matos Vila


//archivo: basemton.java

import java.io.*;

PROGRAMACION CON JAVA 2 99


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);
100 Ing. Gilmer Matos Vila
}//fin de main
}//fin de la clase

Ejemplo(0): Programa que imprime el factorial


de un número.

PROGRAMACION CON JAVA 2 101


//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 (0): Programa que imprime el


factorial de 1 hasta el factorial de “num”.

102 Ing. Gilmer Matos Vila


//archivo: nfactorial.java

import java.io.*;

class nfactorial
{

PROGRAMACION CON JAVA 2 103


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

104 Ing. Gilmer Matos Vila


solamente 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 (0): Escribir un programa que permita


calcular el MCD (Máximo común divisor) de dos
números utilizando el algoritmo de Euclides.

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 105


//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

106 Ing. Gilmer Matos Vila


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
etiqueta 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
comando 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
bucles.

PROGRAMACION CON JAVA 2 107


La versión etiquetada es similar a la
anterior, 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
busqueda.

108 Ing. Gilmer Matos Vila


CAPITULO 2

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;

tipo_de_dato nombre_del_array[];
PROGRAMACION CON JAVA 2 109
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; }
110 Ing. Gilmer Matos Vila
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",


"Antonio"};

Para imprimir a los elementos de array nombres se


escribe

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
trabajo al programador.

Ejemplo (0): Programa que lee la temperatura de los


“n” últimos días y calcula el promedio.

PROGRAMACION CON JAVA 2 111


//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?: ");


112 Ing. Gilmer Matos Vila
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

PROGRAMACION CON JAVA 2 113


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
tabuladores.

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

114 Ing. Gilmer Matos Vila


PROGRAMACION CON JAVA 2 115
//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
declarar 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'


116 Ing. Gilmer Matos Vila
Ejemplo (0): 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ísticas incorporadas que facilitan la
manipulación de cadenas.

PROGRAMACION CON JAVA 2 117


Java tiene una clase incorporada en el paquete
java.lang que encapsula las estructuras de datos de
una cadena. Esta clase, llamada String es la
representació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
manipuladas 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


rango 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
caracteres 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
realizar las operaciones más habituales con
cadenas.
118 Ing. Gilmer Matos Vila
Creación de cadenas

Dado que los Strings son valores constantes,


Java incluye un atajo para un literal de
cadena 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


utilizan 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
comillas, 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
para 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();
PROGRAMACION CON JAVA 2 119
que es lo que sucede cuando se ejecuta este
código. append añade cosas al final de
StringBuffer, y toString convierte a cadenas
el StringBuffer. Trataremos con detalle
append y toString mas adelante en este
capítulo.

Aspectos de precedencia de operadores

Debe tener cuidado cuando mezcle expresiones


enteras con expresiones de concatenación de
cadenas por que puede obtener resultados
sorprendentes.

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

Se podría esperar que el valor de s sea


"cuatro: 4", pero la procedencia de
operadores provoco que se evaluase primero la
subexpresió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.

120 Ing. Gilmer Matos Vila


class Point
{ int x, y;
Point(int x, int y)
{
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
mediante 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
primer carácter y del último más uno que se
desean 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);

PROGRAMACION CON JAVA 2 121


// buf ahora tendrá el valor 'no'

También existe una función útil llamada


toCharArray, 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ámetro 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úsculas o minúsculas.

La clase String ofrece un par de métodos


útiles 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.

122 Ing. Gilmer Matos Vila


Igualdad

El método equals y el operador = = hacen dos


pruebas completamente diferentes para la
igualdad. Mientras que el método equals
compara 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
ordenació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
resultado 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 ordenació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;
PROGRAMACION CON JAVA 2 123
}
}
System.out.print(arr[j]+" ");
}
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,
primero 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 devolverá el resultado de llamar al
método toString 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
funcionalidad de la utilización habitual de
las cadenas. StringBuffer representa
secuencias de caracteres que se pueden
ampliar y modificar. Java utiliza ambas
clases con frecuencia, pero muchos
programadores sólo tratan con String y
permiten que Java manipule StringBuffer por
su cuenta mediante el operador sobrecargado
'+'.

append
124 Ing. Gilmer Matos Vila
Al método append de StringBuffer se le llama
a menudo a través del operador +. Tiene
versiones 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
caracteres.

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
subcadenas 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()

PROGRAMACION CON JAVA 2 125


Initializes a newly created String object so that
it represents an empty character sequence.
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
argument; 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
argument.

126 Ing. Gilmer Matos Vila


Métodos
char charAt(int index)
Returns the character at the specified
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 andonly 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
specified 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,
storing the result into a new byte array.
void getBytes(int srcBegin, int srcEnd, byte[] dst,
int dstBegin)
Deprecated. This method does not
properly convert characters into bytes. As of
JDK 1.1, the preferred way to do this is via the
PROGRAMACION CON JAVA 2 127
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
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
index.
int lastIndexOf(String str)
Returns the index within this string of
the rightmost occurrence of the specified
substring.
int lastIndexOf(String str, int fromIndex)
Returns the index within this string of
128 Ing. Gilmer Matos Vila
the last occurrence of the specified substring,
searching backward starting at the specified
index.
int length()
Returns the length of this string.
boolean matches(String regex)
Tells whether or not this string
matches 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
replacing 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
PROGRAMACION CON JAVA 2 129
substring of this string.
String substring(int beginIndex, int endIndex)
Returns a new string that is a
substring of this string.
char[] toCharArray()
Converts this string to a new character
array.
String toLowerCase()
Converts all of the characters in this
Stringto lower case using the rules of the
default 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
Stringto upper case using the rules of the
default 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
leading 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)

130 Ing. Gilmer Matos Vila


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)
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 3

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


clases. 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
estos 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


conocerse también como funciones miembro. Usted debe notar
que las funciones se utilizan también en el Lenguaje C++. En
capítulos posteriores utilizaremos lós métodos con la
denominación de funciones miembro.

PROGRAMACION CON JAVA 2 133


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

[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


lista 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 pará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


cuando 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


cuando 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:
134 Ing. Gilmer Matos Vila
return (expresión);

return ;

Por supuesto que la última forma no devuelve


ningú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 (0): Uso del método hipotenusa para calcular


la hipotenusa de un triángulo. Notese que en el
llamado

//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

{
PROGRAMACION CON JAVA 2 135
// 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 (0): Uso del método hipotenusa para calcular


la hipotenusa de un triángulo. Notese que en el
llamado

//llamado al método hipotenusa


hipotenusa(ca,cb);

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.
136 Ing. Gilmer Matos Vila
// 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);


}
}

Ejemplo (0): Uso de un método para simular el operador


AND. Notese el uso de throws IOException en los
métodos main y leer_vector, para evitar de este modo
PROGRAMACION CON JAVA 2 137
utilizar try . . . catch. Observe además como se
utiliza el tipo de dato int[] en el método and, para
devolver 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

138 Ing. Gilmer Matos Vila


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 4

CLASES Y PROGRAMACION ORIENTADO A


OBJETOS

Cuando se escribe un programa en un lenguaje orientado a


objetos, definimos una plantilla o clase que describe las
caracterí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
comportamiento (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
comportamiento 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.
PROGRAMACION CON JAVA 2 141
Figura CLASES Y PROGRAMACION ORIENTADO A OBJETOS.4 Clases y objetos

4.1. ATRIBUTOS
Los atributos son las características individuales que
diferencian un objeto de otro y determinan su
apariencia, estado u otras cualidades. Los atributos
se guardan en variables denominadas de instancia, y
cada objeto particular puede tener valores distintos
para estas variables.

Las variables de instancia también denominados


miembros 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
automóvil es el mismo cuatro, para todos los
automóviles.

4.2. COMPORTAMIENTO
El comportamiento de los objetos de una clase se
implementa mediante funciones miembro o métodos. Un
método es un conjunto de instrucciones que realizan
142 Ing. Gilmer Matos Vila
una 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
realizar 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
definición de la clase se pone entre las llaves de
apertura y cierre. El nombre de la clase empieza con
una letra 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
izquierda del rectángulo en el plano
determinado por dos números enteros x e
y.

 Las dimensiones del rectángulo: ancho y


alto, otros dos números enteros.

PROGRAMACION CON JAVA 2 143


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
definición de una función tiene el siguiente
formato:

[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


coloca 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.
144 Ing. Gilmer Matos Vila
Un modificador es una palabra clave que
modifica 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
sentencias dentro de la función. La función
finaliza 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


devuelto 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
funció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

PROGRAMACION CON JAVA 2 145


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
local i, existe desde el punto de su
declaració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
dato, 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
146 Ing. Gilmer Matos Vila
Rectangulo o rectángulos sabrán calcular su
á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
miembros 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


horizontalmente en dx, y verticalmente en dy,
le pasamos dichos desplazamientos, y a partir
de estos datos actualizará los valores que
guardan 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
PROGRAMACION CON JAVA 2 147
encuentra, es decir, será una función del
tipo boolean. La función necesitará conocer
las coordenadas de dicho punto. Para que un
punto de coordenadas x1 e y1 esté dentro de
un rectángulo cuyo origen es x e y, y cuyas
dimensiones 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


condiciones 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
expresiones ya que el resultado es false.
Ahora bien, si la primera es verdadera true,
se pasa a evaluar la segunda, si ésta el
falsa el resultado es false, y así
sucesivamente.

148 Ing. Gilmer Matos Vila


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
automática cuando se crea un objeto, para
situarlo 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 retorno.

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,
ancho 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;
}
}

PROGRAMACION CON JAVA 2 149


Este constructor crea un rectángulo de
dimensiones 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;
}

150 Ing. Gilmer Matos Vila


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
objeto. 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 punto 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 estará situado en el punto de coordenadas
x=0, y=0; y tendrá 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
PROGRAMACION CON JAVA 2 151
rectángulo estará situado en el punto de coordenadas
x=0, y=0; y tendrá 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
miembros 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
llamamos 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


unidades hacia la derecha y 20 hacia abajo,
escribiremos

rect2.desplazar(10, 20);

Podemos verificar mediante el siguiente


código si el punto (20, 30) está en el
interior del rectángulo rect1.

152 Ing. Gilmer Matos Vila


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


posible 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
rectángulo");
}
else
{
System.out.println("El punto está fuera del
rectángulo");
}
}//fin main
}

PROGRAMACION CON JAVA 2 153


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.
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
programador 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++
eliminariamos dicho objeto liberando la memoria que
ocupa mediante delete. El equivalente en Java es el de
asignar 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();
}
}
}
154 Ing. Gilmer Matos Vila
A partir de la sentencia marcada en letra negrita el
recolector de basura se encargará de liberar la
memoria ocupada por dicha imagen. Así pues, se
asignará el valor null a las referencias a objetos
temporales que ocupen mucha memoria tan pronto como no
sean necesarios.

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
Java (JVM). Por tanto, nunca podemos saber cuando se
va a destruir un objeto.

Puede haber situaciones en las que es necesario


realizar ciertas operaciones que no puede realizar el
recolector de basura (garbage collector) cuando se
destruye un objeto. Por ejemplo, se han abierto varios
archivos durante la vida de un objeto, y se desea que
los archivos estén cerrados cuando dicho objeto
desaparece. Se puede definir en la clase un método
denominado finalize que realice esta tarea. Este
método es llamado por el recolector de basura
inmediatamente antes de que el objeto sea destruido.

Ejemplo (0): Manejo de la clase rectángulo.


//archivo Rectangulo.java
public class Rectangulo
{
int x;
int y;
int ancho;
int alto;

PROGRAMACION CON JAVA 2 155


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;
}

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();
156 Ing. Gilmer Matos Vila
int medidaArea=rect1.calcularArea();
System.out.println("El area del rectangulo 1 es
"+medidaArea);

rect2.desplazar(10, 20);

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
importante 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


entender 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
detalles internos, es decir, cómo lo hace, precise un
estudio detallado.

Vemos primero un ejemplo que muestra un código poco


legible y por tanto, muy difícil de mantener

public class Cuen


{
PROGRAMACION CON JAVA 2 157
private int ba;
public void dep(int i)
{
ba+=i;
}
public void ret(int i)
{
ba-=i;
}
public int get()
{
return ba;
}
}

Las abreviaciones empleadas solamente tienen


significado 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 escribir con claridad el nombre de los
diversos elementos 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;
}
}

158 Ing. Gilmer Matos Vila


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
acceso a los miembros de una clase está controlado.
Para usar una clase, solamente necesitamos saber que
funciones miembro se pueden llamar y a qué datos
podemos acceder, no necesitamos saber como está hecha
la clase, 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
conducta. 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
controlada a través de algunas funciones miembro. Para
acceder a un miembro público (public), sea dato o
función basta 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
acceder 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
acceso delante de los miembros, se dice que
son accesibles dentro del mismo paquete

PROGRAMACION CON JAVA 2 159


(package). Esto es lo que hemos utilizado en
algunos 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
con el nombre del archivo. El uso de paquetes
se estudiará más adelante.

Como se habrá dado cuenta hay una correspondencia


entre archivos y clases, entre paquetes y
subdirectorios. El Entorno Integrado de Desarrollo
(IDE) en el que creamos los programas facilita esta
tarea sin que el usuario se aperciba de ello.

Ejemplo (0): Uso de los modificadores de acceso


package

//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

160 Ing. Gilmer Matos Vila


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)
{}
}

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();
}
}

PROGRAMACION CON JAVA 2 161


Ejemplo (0): Uso del modificador de acceso privado
(private). El siguiente programa es similar al
anterior salvo que los métodos de la clase Linea son
private.

//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
162 Ing. Gilmer Matos Vila
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);
}

// 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
Linea1
r1.escribir();
^
2 errors

PROGRAMACION CON JAVA 2 163


Ejemplo (0): 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
{
// 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);
}

}
164 Ing. Gilmer Matos Vila
// 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()

r1.leer();
r1.escribir();
}
}

Ejemplo (0) 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
PROGRAMACION CON JAVA 2 165
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: ");
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
166 Ing. Gilmer Matos Vila
//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();
}
}

4.8. EJEMPLOS DEL USO DE CLASES


Ejemplo (0): Realice un programa que maneje la clase
tiempo. Esta clase debe tener las siguientes
caracterí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)
PROGRAMACION CON JAVA 2 167
void escribir_tiempo() : Permite visualizar el valor
de hora, min , seg (2 PTOS)

tiempo tiempo_transcurrido(tiempo nuevotiempo) :


retorna 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
{ //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

168 Ing. Gilmer Matos Vila


//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;

}
}

//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();
}
}

PROGRAMACION CON JAVA 2 169


Ejemplo (0): 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;
}

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
170 Ing. Gilmer Matos Vila
//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);

}
}

Ejemplo (0): 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
PROGRAMACION CON JAVA 2 171
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)


{ 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();
172 Ing. Gilmer Matos Vila
System.out.println("La suma es: ");
q=q1.sumar(q2);
q=q.simplificar(q);
q.escribir();

}//fin main
}

Ejemplo (0): 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;
}
}

PROGRAMACION CON JAVA 2 173


// Archivo CuentaAppl.java

import java.io.*;

class CuentaAppl
{
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 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();
}
}

174 Ing. Gilmer Matos Vila


Ejemplo (0): 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.

// 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;
}

PROGRAMACION CON JAVA 2 175


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;
}
}

// 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 (0): 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
176 Ing. Gilmer Matos Vila
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);

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);
PROGRAMACION CON JAVA 2 177
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)
{}
}
}

// 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 (0): Clase Conjunto (Versión 1). Muestra el


uso de la funcion miembro union con un parámetro.

178 Ing. Gilmer Matos Vila


Observe el uso de try. . .catch en lugar de throws
IOException 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);

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 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

PROGRAMACION CON JAVA 2 179


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;
}

//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 (0): Clase Conjunto (Versión 2). Muestra el


uso de la funcion miembro union con dos parámetros.

180 Ing. Gilmer Matos Vila


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);

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


PROGRAMACION CON JAVA 2 181
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;
}

//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
}

182 Ing. Gilmer Matos Vila


PROGRAMACION CON JAVA 2 183
Ejemplo (0): 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
arreglo:

 La clase tiene los siguientes datos miembros:


valor[ ]: arreglo que almacena los dígitos del
número.

 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
}
184 Ing. Gilmer Matos Vila
}

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 185


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();
}
}

186 Ing. Gilmer Matos Vila


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(0): 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 187
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);
}

188 Ing. Gilmer Matos Vila


//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 189


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
proporciona 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


atributos 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:

190 Ing. Gilmer Matos Vila


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
pasando ningún argumento a c.area(). El objeto con el
que estamos operando, c, está implícito en la
sintaxis.

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
estrictamente 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
constructor el nuevo objeto implícitamente (this, como
vimos anteriormente), y pasándole también los
argumentos especificados explícitamente entre
paréntesis, si es que los hubiera.

PROGRAMACION CON JAVA 2 191


4.10.1. UTILIZACION DE this EN UN
CONSTRUCTOR
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
clave this.

Ejemplo : Un constructor para la clase


Circulo
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
figura el código de 3 constructores y algunos
utilizan this.

Ejemplo : Múltiple constructores para la


clase Circulo
192 Ing. Gilmer Matos Vila
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 193


Ejemplo(0): 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;
}
}

194 Ing. Gilmer Matos Vila


// 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
clave 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
rescribir el código anterior usando esta
técnica:

public class Circulo1

PROGRAMACION CON JAVA 2 195


{
// 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.

196 Ing. Gilmer Matos Vila


Ejemplo (0): 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 197


// 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());
}
}

198 Ing. Gilmer Matos Vila


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


sino 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 199
p[i]=new Persona();

p[i].leer();

p[i].escribir();

Ejemplo(0): 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;
}

200 Ing. Gilmer Matos Vila


//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 201


4.12. VARIABLES DE CLASE (VARIABLE ESTÁTICA)
En nuestra definición de la clase Circulo hemos
declarado 3 variables de instancias (x, y, r).
Variable de instancia significa que cada clase (cada
círculo) tiene 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
problema sino una ventaja). Cada variable en Java debe
declararse 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
clase 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
manera es fácilmente distinguible de su opuesta,
variables de instancia.
202 Ing. Gilmer Matos Vila
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
Circulo creados, ¿cómo podemos acceder a esa
información? Porque las variables de clase
está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 203


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
misma clase.

Ejemplo(0): 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;
}
}
204 Ing. Gilmer Matos Vila
// 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 205
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 p. 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
siguiente:

Circulo.PI = 4;

El compilador Java es hábil respecto de las variables


declaradas static y final, ya que sabe que tienen
valores 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(0): Realice un programa que calcule el total
de la compra de 3 libros. Debe tener en cuenta lo
siguiente:

 Utilizar la clase libro que tiene los datos


miembro titulo, autor y precio. Además la clase
libro 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
compra. El método void escribir_total_compra ( )

206 Ing. Gilmer Matos Vila


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
InputStreamReader(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 207
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();

}
}

208 Ing. Gilmer Matos Vila


4.16. MÉTODOS DE CLASE (MÉTODOS ESTÁTICOS)
El uso de Math.sqrt(4), permite encontrar la raiz
cuadrada 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
diferencia 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étodos 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
pasan la referencia implícita this. De esta
manera, los métodos sin this no están
asociados con ninguna instancia de la clase y
no pueden hacer referencia a ninguna variable
de instancia o invocar métodos de instancia.

4.16.2. UN MÉTODO DE CLASE PARA CIRCULO


El siguiente ejemplo, muestra dos
definiciones 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 209


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(0): 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;
}

210 Ing. Gilmer Matos Vila


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 211


System.out.println("Utilizando el metodo de clase se
tiene:");
Circulo3 d = Circulo3.elMayor(a,b);
System.out.println("Circulo mayor:");
c.escribir();
}
}

Ejemplo(0): 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
matriz dada, da la matriz unidad. Veamos como se
obtiene la matriz inversa de una matriz 4 x 4, y luego
generalizaremos para una matriz cuadrada de dimensión
n.

El producto de las dos matrices da lugar a los


siguientes sistemas de cuatro ecuaciones con cuatro
incógnitas. Los términos independientes bij son todos
ceros excepto los de la diagonal principal
b00=b11=b22=b33=1.

Primera columna:

212 Ing. Gilmer Matos Vila


Segunda columna:

Tercera columna

Cuarta columna

Para el cálculo de la matriz inversa, deberemos


transformar la matriz a, los términos independientes
b (cada una de las columnas de la matriz unidad), y
calcular las n2 incógnitas x.

La matriz de los términos independientes b es la


matriz 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 213
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
representa la columna de la matriz b de los términos
independientes, y de la matriz c de las incógnitas.

214 Ing. Gilmer Matos Vila


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
inversa 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 215
//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];

216 Ing. Gilmer Matos Vila


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étodo 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


COLLECTOR)
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érprete Java conoce qué objetos tiene
PROGRAMACION CON JAVA 2 217
almacenado. También puede resolver cuáles
variables 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
indicar que no existe el objeto requerido. Podemos
preguntar si una referencia a un objeto es igual o
distinta a null, por ejemplo:

Circulo c = new Circulo();

if ( c != null )
System.out.println("El Circulo 'c' existe !");
218 Ing. Gilmer Matos Vila
Circulo b=null; // b referencia a null

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
referencia 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 (atributo o método) con esa
variable, el sistema de runtime lanzará una
NullPointerException, ya que nuestra variable
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 219


4.19. HERENCIA
La herencia es una propiedad esencial de la
Programació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 afirmamos 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


distingue 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
conductas de una o varias clases denominadas base. Las
clases que heredan de clases base se denominan
derivadas, estas a su vez pueden ser clases bases para
otras clases derivadas. Se establece así una
clasificación jerárquica, similar a la existente en
Biología con los animales y las plantas.

220 Ing. Gilmer Matos Vila


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
base), 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
significativo, si se dice que Tucker fue un automóvil
inmediatamente sabremos varias de sus características,
como ser que consta de cuatro ruedas, tiene un
volante, 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
calle, son diferentes clases de automóviles. En la
terminología orientada a objetos, las camionetas, los
autos de carrera y los autos de calle son subclases de
la clase automóviles. De la misma manera la clase
automóviles es la superclase de las clases camionetas,
autos de carrera y autos de calle.

Automóviles

Camionetas Autos de Autos de calle


carrera

PROGRAMACION CON JAVA 2 221


Cada subclase hereda el estado (en la forma de
declaració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


superclase. Las camionetas, los autos de carrera y los
autos 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
agregar atributos y métodos a los heredados de la
superclase. Por ejemplo, las Camionetas pueden tener
cúpulas, los AutosDeCarreras pueden tener una marcha
más y los AutosDeCalle pueden ser cupés.

Las subclases también pueden redefinir métodos


heredados y proveer implementaciones especializadas
para esos métodos. Por ejemplo, si AutosDeCarrera
posee una marcha más se puede redefinir el método
cambiarDeMarcha para que el corredor pueda utilizar
ese cambio extra.

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
sido 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
funcionalidad de la clase base y le añada otros
comportamientos. Reutilizando el código existente, el
programador 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


particular Windows, con el lenguaje C++, es un ejemplo
ilustrativo. Los compiladores como los de Borland y
222 Ing. Gilmer Matos Vila
Microsoft proporcionan librerías cuyas clases
describen el aspecto y la conducta de las ventanas,
controles, menús, etc. Una de estas clases denominada
TWindow describe 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. Aprovechamos de este modo la ingente cantidad
y complejidad del código necesario para crear una
ventana en un entorno 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ícitamente 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 nuevas.

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
controles.

Los programadores crean clases base:

 Cuando se dan cuenta que diversos tipos tienen


algo en común, por ejemplo en el juego del
ajedrez peones, alfiles, rey, reina, caballos y
torres, 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
existente.

4.19.1. LA CLASE BASE


Vamos a poner un ejemplo del segundo tipo,
que simule la utilización de liberías de
clases para crear un interfaz gráfico de
usuario como Windows 3.1 o Windows 95.

PROGRAMACION CON JAVA 2 223


Supongamos que tenemos una clase que describe
la conducta de una ventana muy simple,
aquella que no dispone de título en la parte
superior, 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


miembros dato: la posición x e y de la
ventana, de su esquina superior izquierda y
las dimensiones 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


constructor 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

224 Ing. Gilmer Matos Vila


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
dato. 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 225


4.19.3. LA CLASE DERIVADA

Incrementamos la funcionalidad de la clase


Ventana definiendo una clase derivada
denominada VentanaTitulo. Los objetos de
dicha clase 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 rató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
Ventana.

La primera sentencia del constructor de la


clase derivada es una llamada al constructor
de la clase base mediante la palabra
reservada super. La llamada

super(x, y, w, h);

inicializa los cuatro miembros dato de la


clase base Ventana: x, y, ancho, alto. A
continuación, se inicializa los miembros dato
de la clase derivada, y se realizan las
226 Ing. Gilmer Matos Vila
tareas de inicialización que sean necesarias.
Si no se llama explícitamente al constructor
de la clase base Java lo realiza por
nosotros, llamando al constructor por defecto
si existe.

La función miembro denominada desplazar


cambia 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


mostrar 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
Ventana, mediante

super.mostrar();

De este modo aprovechamos el código ya


escrito, y le añadimos el código que describe
la nueva funcionalidad de la ventana por
ejemplo, que muestre el título.

Si nos olvidamos de poner la palabra


reservada super llamando a la función
mostrar, tendrí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);
PROGRAMACION CON JAVA 2 227
mostrar();
}
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
derivada 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
definidas en la clase base.

ventana.cambiarDimensiones(10, -5);

Para mostrar la nueva ventana desplazada y


cambiada de tamaño escribimos
228 Ing. Gilmer Matos Vila
ventana.mostrar();

Ejemplo ( 0): 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)
{
PROGRAMACION CON JAVA 2 229
x+=dx;
y+=dy;
}
}

//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;
//...
}
230 Ing. Gilmer Matos Vila
En la clase derivada la función miembro desplazar
accede 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
miembro 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
ausencia 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
Si Si
modificador)
Private No No
Protected Si Si
Public Si Si

PROGRAMACION CON JAVA 2 231


Clases en distintos paquetes
Modificador de
acceso Heredado Accesible
Por defecto (sin
No No
modificador)
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
rectángulo, y el círculo. Tales figuras comparten
características comunes como es la posición de la
figura, de su centro, y el área de la figura, aunque
el procedimiento 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

232 Ing. Gilmer Matos Vila


Figura como una clase abstracta, declarando la función
miembro area abstract.

Las clases abstractas solamente se pueden usar como


clases base para otras clases. No se pueden crear
objetos pertenecientes a una clase abstracta. Sin
embargo, 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
cada 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 tablero.

4.21.1. LA CLASE FIGURA


La definición de la clase abstracta Figura,
contiene la posición x e y de la figura
particular, 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
particular.

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
dato x e y de la clase base, y definen la
función area, declarada abstract en la clase
base Figura, ya que cada figura particular
tiene una fórmula distinta para calcular su
área. Por ejemplo, la clase derivada
Rectangulo, tiene como datos, aparte de su
posición (x, y) en el plano, sus dimensiones,
es decir, su anchura ancho y altura alto.
PROGRAMACION CON JAVA 2 233
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;
}
}
La primera sentencia en el constructor de la
clase derivada es una llamada al constructor
de la clase base, para ello se emplea la
palabra reservada super. El constructor de la
clase derivada llama al constructor de la
clase base y le pasa las coordenadas del
punto x e y. Después inicializa sus miembros
dato ancho y alto.

En la definición de la función area, se


calcula 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
constructor 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.

234 Ing. Gilmer Matos Vila


En la definición de la función area, se
calcula el área del círculo mediante la
conocida fórmula pr2, o bien p*r*r. La
constante Math.PI es una aproximación decimal
del número irracional p.

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


valor devuelto por new al crear objetos de las clases
derivadas en una variable f del tipo Figura (clase
base).

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
Java permiten decidir a que función llamar en tiempo
de ejecución, esto se conoce como enlace tardío o
dinámico. Las 4 líneas de código anterior muestran el
uso del enlace dinámico.

PROGRAMACION CON JAVA 2 235


Ejemplo(0): Programa completo del uso de la clase
Figura.

//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
236 Ing. Gilmer Matos Vila
class FiguraApp
{
public static void main(String[] args)
{
//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
(dinamico)");
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 237


CAPITULO 5

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
objetos 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 comose 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
PROGRAMACION CON JAVA 2 239
la excepción NullPointerException. Estas excepciones
le indican al programador que tipos de fallos tiene el
programa y que debe arreglarlo antes de proseguir.

Figura GESTION DE EXCEPCIONES.5


El segundo grupo de excepciones, es el más
interesante, 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
función es muy usuada cuando creamos applets.
Introducimos el número en un control de
edició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
Integer.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
principio y al final del string, mediante la
función trim, se lanza una excepción
NumberFormatException.

240 Ing. Gilmer Matos Vila


El mensaje que aparece en la ventana nos
indica el tipo de excepción
NumberFormatException, la función que la ha
lanzado Integer.parseInt, que se llama dentro
de main.

Objeto no inicializado

Habitualmente, cuando llamamos desde un


objeto no inicializado, a una función
miembro.

public static void main(String[] args)

String str;

str.length();

//...

El compilador se queja con el siguiente


mensaje "variable str might not have been
initilized". En otras ocasiones, se lanza una
excepción del tipo NulPointerException.
Fijarse que en la porción de código que
sigue, grafico es una variable de instancia
que es inicializada 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
grafico no ha sido inicializado con el valor
devuelto 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
PROGRAMACION CON JAVA 2 241
En otras situaciones el mensaje de error
aparece en el momento en el que se compila el
programa. Así, cuando intentamos leer un
cará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
produce en el programa durante la
compilación. Tal como indica el mensaje que
genera el compilador, se ha de poner la
sentencia System.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


caracteres 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
242 Ing. Gilmer Matos Vila
NumberFormatException que es capturada y se
imprime el mensaje "No es un número".

En vez de un mensaje propio se puede imprimir


el objeto ex de la clase
NumberFormatException
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
modo

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úmeros, se obtiene el texto de cada uno y se
guardan en dos strings. En esta situación se
pueden producir dos excepciones
NumberFormatException, si se introducen
caracteres no numéricos y ArithmeticException
si se divide entre cero.

PROGRAMACION CON JAVA 2 243


Ejemplo (0): 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
numericos";
}
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
ArithmeticException en la expresión que halla
el cociente, que es inmediatamente capturada
en el bloque catch que maneja dicha
excepción, ejecutá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
produzcan o no excepciones. Se puede hacer
esto añadiendo un bloque finally después del
último catch. Esto es importante cuando
244 Ing. Gilmer Matos Vila
accedemos 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
excepció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
situación en la que el usuario introduce un valor
fuera de un determinado intervalo, el programa lanza
un excepción, que vamos a llamar ExcepcionIntervalo.

5.2.1. LA CLASE QUE DESCRIBE LA EXCEPCIÓN


Para crear y lanzar una excepción propia
tenemos 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
mensaje, en el único parámetro que tiene el

PROGRAMACION CON JAVA 2 245


constructor de la clase derivada y éste se lo
pasa a la clase base mediante super.

5.2.2. EL MÉTODO QUE PUEDE LANZAR UNA


EXCEPCIÓ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
excepció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
intervalo");
}
}

Cuando el numerador es mayor que 100 y el


denominador es menor que 5 se lanza throw una
excepción, un objeto de la clase
ExcepcionIntervalo. 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
intervalo 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
especificado.

Ejemplo (0): Uso de excepciones.


public class ExcepcionApp3
{
public static void main(String[] args)
{
String str1="120";
String str2="3";
246 Ing. Gilmer Matos Vila
String respuesta;
int numerador, denominador, cociente;

PROGRAMACION CON JAVA 2 247


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éricos";
}
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


ExcepcionIntervalo
{
if((num>100)||(den<-5))
{
throw new ExcepcionIntervalo("Numeros fuera del
intervalo");
}
}

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
excepció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 sentencias de dicho bloque. En
concreto, se obtiene mediante getMessage el
248 Ing. Gilmer Matos Vila
texto del mensaje que guarda el objeto ex de
la clase ExcepcionIntervalo.

El ciclo de vida de una excepción se puede


resumir del siguiente modo:

 Se coloca la llamada a la función


susceptible 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


VARIAS EXCEPCIONES
Hay otra alternativa para el ejercicio
anterior, que es la de definir una función
denominada calcular, que devuelva el cociente
entre el numerador y el denominador, cuando
se le pasa los strings obtenidos de los
respectivos controles de edición. La función
calcular, convierte los strings en números
enteros, verifica el rango, calcula y
devuelve el cociente entre el numerador y el
denominador,

PROGRAMACION CON JAVA 2 249


Ejemplo (0): 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éricos";
}
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
intervalo");
}
return (num/den);
}
}

Vemos que la función calcular puede lanzar,


throws, tres tipos de excepciones. En el
250 Ing. Gilmer Matos Vila
cuerpo de la función se crea, new, y se
lanza, 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ándonos la variable temporal cociente,
escribiendo 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 251


CAPITULO 6

PAQUETES

6.1. PAQUETES
Un paquete es un conjunto de clases, lógicamente
relacionadas entre sí, agrupadas bajo un nombre (por
ejemplo, el paquete java.io agrupa las clases que
permiten a un programa realizar la entrada y salida de
información); incluso, un paquete puede contener a
otros paquetes.

Prácticamente son bibliotecas a las que el usuario


puede acceder y que ofrecen varias funciones
(métodos). Los usuarios pueden también crear paquetes
informáticos, por ejemplo, haciendo que contengan
todas las clases que ha definido para poner en marcha
algunas 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
visibilidad. 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. Cada archivo .java tiene las mismas cuatro
partes internas y hasta ahora sólo hemos utilizado una
de ellas en nuestros ejemplos. Esta es la forma
general de un archivo fuente de Java, una única
PROGRAMACION CON JAVA 2 253
sentencia de paquete (opcional) las sentencias de
importación deseadas (opcional) 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
compilador en qué paquete se deberían definir
las clases incluidas. Si se omite la
sentencia package, las clases terminan en el
paquete por defecto, que no tiene nombre. El
compilador 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
archivo 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
debe 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
niveles por puntos. Esta jerarquía se debe
reflejar en el sistema de archivos de
desarrollo de Java. Un paquete declarado como

package java.awt.imagen;

se debe almacenar en java/awt/imagen, en


java\awt\imagen o en java:awt:imagen en los
sistemas de archivo UNIX, Windows o
Macintosh, respectivamente.

6.1.2. COMPILACIÓN DE CLASES EN PAQUETES


Cuando se intenta poner una clase en un
paquete, el primer problema es que la
estructura de directorios debe coincidir con
la jerarquía de paquetes exactamente. No se
puede renombrar un paquete sin renombrar el
254 Ing. Gilmer Matos Vila
directorio en el cual están almacenadas las
clases. El otro problema que presenta la
compilació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
contenga algo parecido a ".;C:\java\classes"
que le dice al intérprete que busque en el
directorio de trabajo actual y en el
directorio de instalación del Equipo de
herramientas de desarrollo 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 arriba y ejecutar
"java prueba.PaquetePrueba"3, o añadir el
extremo de su jerarquía de clases de
desarrollo a la variable de entorno
CLASSPATH. Después podrá utilizar "java
prueba.PaquetePrueba" desde cualquier
directorio y Java encontrará el archivo
.class adecuado. Si trabaja con su código
fuente en un directorio llamado C:\mijava, dé
a CLASSPATH el valor
".;C:\mijava;C:\java\classes".

3
La ejecución de la clase Paquete.Prueba se realiza desde la línea de comandos del DOS.
PROGRAMACION CON JAVA 2 255
Para realizar modificaciones de CLASSPATH en
el JCreator, que nos permita definir la
ubicación de nuestros paquetes, debemos
hacerlo utilizando Configure, Options, JDK
Profiles, Edit, Add; tal como se muestra en
la figura 5.1.

Figura PAQUETES.6.

6.1.3. LA SENTENCIA IMPORT


Lo siguiente que se pone después de una
sentencia 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
algún paquete con nombre. Para no tener que
256 Ing. Gilmer Matos Vila
introducir el largo nombre de trayecto de
paquete para cada clase, Java incluye la
sentencia import para que se puedan ver
ciertas 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
separado 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


asterisco (*) 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 Clase Subclase paquete todos


acceso (clase
derivada)

private Sí No No No

protected Sí Sí Sí No

public Sí Sí Sí Sí

package Sí No Sí No

PROGRAMACION CON JAVA 2 257


Un miembro declarado en una clase como:
sin
Puede ser modificador
Private protected public
accedido (default:
desde package)
Su misma
clase sí sí sí sí
Cualquier
Clase o
subclase del no sí sí sí
mismo
paquete
Cualquier
subclase de no no sí sí
otro paquete.
Cualquier
clase de otro no no no sí
paquete.

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
visibles 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


agrupar las clases en paquetes.

• No usar nada, dejar la visibilidad por


defecto (default, package) para métodos y
variables que deban estar ocultas fuera del
paquete, pero que deban estar disponibles al
acceso desde dentro del mismo paquete.
Utilizar protected en su lugar si se quiere
que esos componentes sean visibles fuera del
paquete.

258 Ing. Gilmer Matos Vila


6.1.5. LOS PAQUETES ESTÁNDAR

Paquete Descripción
Contiene las clases necesarias para crear
java.applet applets que se ejecutan en la ventana del
navegador
Contiene clases para crear una aplicación
java.awt
GUI independiente de la plataforma
Entrada/Salida. Clases que definen
java.io
distintos flujos de datos
Contiene clases esenciales, se importa
java.lang impícitamente sin necesidad de una
sentencia import.
Se usa en combinación con las clases del
java.net paquete java.io para leer y escribir
datos en la red.
Contiene otras clases útiles que ayudan
java.util
al programador

6.2. EJEMPLOS DE USO DE PAQUETES


Ejemplo (0): 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


archivo Leer.java debe estar en la carpeta LeerDatos
(el mismo nombre del paquete), dentro del directorio
actual.

//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);
PROGRAMACION CON JAVA 2 259
// Leer. La entrada finaliza al pulsar la tecla Entrar
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.
}
}
260 Ing. Gilmer Matos Vila
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.

Aquí se encuentra Aquí se encuentra


LecturaDatos.java Leer.java

//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: ");
PROGRAMACION CON JAVA 2 261
dato_double = Leer.datoDouble();

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);
}
}

262 Ing. Gilmer Matos Vila


CAPITULO 7

INTERFACES

7.1. ¿QUÉ ES UN INTERFACE?


Una interface Java es un dispositivo que permite
interactuar a objetos no relacionados entre sí. Las
interfaces Java en realidad definen un conjunto de
mensajes 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
constantes.

Runnable es un ejemplo de interface en el cual se


declara, 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.

PROGRAMACION CON JAVA 2 263


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
describa una animación, y también puede implementar el
interface Runnable una clase que realice un cálculo
intensivo.

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,
miembros dato, constantes y otros no constantes.

Ahora bien, la diferencia es mucho más profunda.


Imaginemos que Runnable fuese una clase abstracta. Un
applet 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.

264 Ing. Gilmer Matos Vila


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


jerárquica, simplemente permite que clases no
relacionadas puedan tener algunas características de
su comportamiento 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
implementar interfaces. Vamos a ver en este
PROGRAMACION CON JAVA 2 265
apartado que la importancia de los interfaces
no estriba en resolver los problemas
inherentes a la herencia múltiple sin forzar
relaciones 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
declarada abstracta en la clase base Animal.

Ejemplo (0): Clase abstracta y Herencia


simple.

//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


referencia a un objeto de la clase Gato a una
función hazleHablar que conoce al objeto por
su clase base Animal
//Archivo: PoliApp.java

package polimorfismo;

public class PoliApp


{
266 Ing. Gilmer Matos Vila
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
Perro se imprimirá ¡Guau!. El compilador
solamente sabe que se le pasará un objeto de
alguna 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
hazleHablar para que se imprima ¡pio, pio,
pio ..!.

7.3.2. INTERFACES
Vamos a crear un interface denominado
Parlanchin que contenga la declaración de una
función denominada habla.

public interface Parlanchin


{
public abstract void habla();
}

PROGRAMACION CON JAVA 2 267


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


completamente distinta, la que deriva de la
clase base Reloj. Una de las clases de dicha
jerarquía Cucu implementa el interface
Parlanchin y por tanto, debe de definir
obligatoriamente la función habla declarada
en dicho interface.
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
Parlanchin, este o no en la misma jerarquía
de clases.

public class PoliApp


{

268 Ing. Gilmer Matos Vila


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


imprime en la consola ¡Miau!, por que a la
funció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,
cualquier clase en cualquier familia puede
implementar 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 jerarquía de clases.

Ejemplo (0): Programa completo de la


interface Parlanchin

//Archivo: Parlanchin.java
public interface Parlanchin
{
public abstract void habla();
}

//Archivo Animal1.java

public abstract class Animal1 implements Parlanchin


{
public abstract void habla();
}
PROGRAMACION CON JAVA 2 269
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();
}
}
270 Ing. Gilmer Matos Vila
PROGRAMACION CON JAVA 2 271
CAPITULO 8

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
estudiar la clase File, que nos proporciona
informació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
PROGRAMACION CON JAVA 2 273
métodos 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
caso, el nombre del archivo código fuente
ArchivoApp1.java.

File fichero=new File("ArchivoApp1.java");

274 Ing. Gilmer Matos Vila


Si este archivo existe, es decir, si la
función exists devuelve true, entonces se
obtiene información acerca del archivo:

 getName devuelve el nombre del archivo

 getPath devuelve el camino relativo

 getAbsolutePath devuelve el camino


absoluto.

 canRead nos indice si el archivo se


puede leer.

 canWrite nos indica si el archivo se


puede escribir

 length nos devuelve el tamaño del


archivo, si dividimos la cantidad
devuelta entre 1024 obtenemos el tamaño
del archivo 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

PROGRAMACION CON JAVA 2 275


Para obtener la lista de los archivos del
directorio 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
funció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
implemente 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 archivo termina con una
determinada extensión devuelve true en caso
contrario devuelve false. La función endsWith
de la clase String realiza 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;
276 Ing. Gilmer Matos Vila
}
public boolean accept(File dir, String name)
{
return name.endsWith(extension);
}
}

Para obtener la lista de archivos con


extensió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 (0): Programa completo para el uso de la clase


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.*;

PROGRAMACION CON JAVA 2 277


public class ArchivoApp1
{
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]);
}

}
}
}

278 Ing. Gilmer Matos Vila


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).

PROGRAMACION CON JAVA 2 279


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
jerarquí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
lectura 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
sentencia

import java.io.*;

280 Ing. Gilmer Matos Vila


char Unicode, 16 bits

byte, 8 bits.

PROGRAMACION CON JAVA 2 281


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
caracteres

int read()

int read(char buf[])

int read(char buf[], int offset, int len)

InputStream proporciona métodos similares


para 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
también, un array de bytes, pero nos permite
especificar, 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.

282 Ing. Gilmer Matos Vila


8.2.3. ESCRITURA
La clase Writer proporciona tres métodos para
escribir un carácter char o un array de
caracteres

int write(int c)

int write(char buf[])

int write(char buf[], int offset, int len)

La clase OutputStream proporciona métodos


similares

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
específicos.

La clase System tiene un miembro dato


denominado in que es una instancia de la
clase InputStream 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) { }

PROGRAMACION CON JAVA 2 283


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
convertir 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
miembro 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
InputStreamReader para leer los caracteres
tecleados por el usuario.

Esta conexión se realiza mediante la


sentencia
284 Ing. Gilmer Matos Vila
Reader entrada=new InputStreamReader(System.in);

Para leer una sucesión de caracteres se


emplea un código similar (Vea el archivo
TecladoApp2.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 (0): 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) { }
}
}
PROGRAMACION CON JAVA 2 285
Podemos usar la segunda versión de la función
read para leer el conjunto de caracteres
tecleados por el usuario. (Vea el archivo
TecladoApp1.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 (0): 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];

286 Ing. Gilmer Matos Vila


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();
PROGRAMACION CON JAVA 2 287
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


pantalla 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
produzcan o no errores en el proceso de
lectura/escritura.
finally
{
if(entrada!=null)
{
try
{
entrada.close();
}catch(IOException ex){}
}
}

El código completo de este ejemplo es el


siguiente:

Ejemplo (0): Programa completo para la


lectura 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();

try
288 Ing. Gilmer Matos Vila
{
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


FileReader y FileWriter, llamando a los
respectivos constructores a los que se
les pasa los nombres de los archivos o
bien, objetos de la clase File,
respectivamente

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.

PROGRAMACION CON JAVA 2 289


while((c=entrada.read())!=-1)
{
salida.write(c);
}
 Finalmente, se cierran ambos flujos
llamando 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
siguiente:

Ejemplo (0): 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();
290 Ing. Gilmer Matos Vila
}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


binarios se sustituye FileReader por
FileInputStream y FileWriter por
FileOutputStream. De hecho, si se realiza
esta sustitución en el código fuente de este
ejemplo, los resultados 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
portable. 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
pedido.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

PROGRAMACION CON JAVA 2 291


método 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


escribir datos del tipo primitivo de una
forma portable. Esta clase tiene un sólo
constructor que toma un objeto de la clase
OutputStream o sus derivadas como parámetro.

Se crea un objeto de la clase


DataOutputStream vinculándolo a un un objeto
FileOutputStream para escribir en un archivo
en disco 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

292 Ing. Gilmer Matos Vila


método 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
archivo 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


nombre 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
writeDouble readDouble
decimal
Un string writeChars readLine
PROGRAMACION CON JAVA 2 293
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


DataOutputStream vinculándolo a un un
objeto FileOutputStream para escribir en
un archivo 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


FileOutputStream("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


separarse 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


archivo pedido.txt en disco

294 Ing. Gilmer Matos Vila


 Se crea un objeto de la clase
DataInputStream 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
tabla).

 Se guardan los datos leídos en memoria


en las variables denominadas
descripcion, 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
imprimen y se calcula el precio total del
pedido.
System.out.println("has pedido "+unidad+" "+descripcion+" a
"+precio+" soles.");
total=total+unidad*precio;

PROGRAMACION CON JAVA 2 295


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
indefinido 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)
296 Ing. Gilmer Matos Vila
{
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 (0): 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
FileOutputStream("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
FileInputStream("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();
System.out.println("has pedido "+unidad+"
"+descripcion+" a "+precio+" Soles.");
PROGRAMACION CON JAVA 2 297
total=total+unidad*precio;
}
System.out.println("Final del archivo");

}
catch (EOFException e)
{
System.out.println("Excepción cuando se alcanza el
final 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
denominada serialización de objetos que permite
convertir cualquier objeto cuya clase implemente el
interface 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, serializarlo 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


lenguaje Java para dar soporte a

 La invocación remota de objetos (RMI)

 La persistencia

298 Ing. Gilmer Matos Vila


La invocación remota de objetos permite a los objetos
que viven en otros ordenadores comportarse como si
vivieran en nuestra propia máquina. La serialización
es necesaria para transportar los argumentos y los
valores de retorno.

La persistencia, es una característica importante de


los JavaBeans. El estado de un componente es
configurado 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 correr 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
ObjectOutputStream 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)

PROGRAMACION CON JAVA 2 299


 Los valores de los miembros que no
tengan los modificadores static o
transient, incluyendo los miembros que
se refieren a otros objetos.

El método defaultReadObject de la clase


ObjectInputStream 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
ObjectOutputStream están especializados en la
lectura y escritura de objetos. El
comportamiento de estos dos flujos es similar
a sus correspondientes que procesan flujos de
datos primitivos DataInputStream y
DataOutputStream.

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,


pasá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
vincular 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"));

300 Ing. Gilmer Matos Vila


 El método writeObject escribe los
objetos 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,


pasá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
vincular a un objeto fileIn de la clase
FileInputStream.

ObjectInputStream entrada=new ObjectInputStream(fileIn);

o en una sóla línea

ObjectInputStream entrada=new ObjectInputStream(new


FileInputStream("media.obj"));

 El método readObject lee los objetos del


flujo de entrada, en el mismo orden en
el que ha sido escritos. Primero un

PROGRAMACION CON JAVA 2 301


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
miembro valorMedio, para hallar el valor
medio 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(0): 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();
}

public double valorMedio()


{
int suma=0;
302 Ing. Gilmer Matos Vila
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)
{
Lista lista1= new Lista(new int[]{12, 15, 11, 4, 32});
try
{

PROGRAMACION CON JAVA 2 303


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
dicha información es privada (el miembro dato
tiene el modificador private) una vez que se
ha enviado al flujo de salida alguien puede
leerla en el archivo en disco o interceptarla
en la red.

304 Ing. Gilmer Matos Vila


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
password.

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
caso 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)" :
passWord;
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
FileOutputStream para guardar la
información en el archivo cliente.obj.
PROGRAMACION CON JAVA 2 305
 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


entrada de la clase ObjectInputStream) y
se asocia con un objeto de la clase
FileInputStream 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(0): Programa completo del uso del


modificador transient.

// Archivo: Cliente.java

public class Cliente implements java.io.Serializable

306 Ing. Gilmer Matos Vila


{
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)" :
passWord;
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
ObjectOutputStream(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)
{
System.out.println(ex);
}
PROGRAMACION CON JAVA 2 307
}
}
La salida del programa es

Lo que nos indica que la información sensible


guardada en el miembro dato password que
tiene por modificador transient no ha sido
guardada en el archivo. En la reconstrucción
del objeto obj1 con la información guardada
en el archivo el miembro dato password toma
el valor null.

8.6.4. OBJETOS COMPUESTOS


Volvemos de nuevo al estudio de la clase
Rectangulo que contiene un subobjeto de la
clase Punto.

A dichas clases se les ha añadido la


redefinició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 implementan 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+")");
}
}
La definición de la clase Rectangulo se
muestra en el siguiente cuadro

308 Ing. Gilmer Matos Vila


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
miembro 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


Rectangulo 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();

En el caso de que nos olvidemos de


implementar el interface Serializable en la
clase Punto que describe el subobjeto de la
PROGRAMACION CON JAVA 2 309
clase Rectangulo, se lanza una excepción,
imprimiéndose en la consola.
java.io.NotSerializableException: archivo5.Punto.

Ejemplo(0): Programa completo de escribir/leer objetos


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;
}

public Rectangulo(Punto p)
{
this(p, 0, 0);
310 Ing. Gilmer Matos Vila
}

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
ObjectOutputStream(new FileOutputStream("figura.obj"));
salida.writeObject("guardar un objeto
compuesto\n");
salida.writeObject(rect);
salida.close();

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);
PROGRAMACION CON JAVA 2 311
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
jerarquí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
aproximació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


solamente la clase base tiene que implementar
el interface Serializable

public abstract class Figura implements java.io.Serializable


{
protected int x;
protected int y;
312 Ing. Gilmer Matos Vila
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


clase 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


objeto fig1 de la clase Rectangulo y otro
objeto fig2 de la clase Circulo, se siguen
los mismos pasos que hemos estudiado en
apartados anteriores
Figura fig1=new Rectangulo(10,15, 30, 60);
Figura fig2=new Circulo(12,19, 60);

PROGRAMACION CON JAVA 2 313


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
respectivamente, 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
(correctamente) 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írculo.

Ejemplo (0): Programa completo de escribir/leer


objetos con herencia.

// Archivo: Figura.java
314 Ing. Gilmer Matos Vila
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;
}
}

PROGRAMACION CON JAVA 2 315


// 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);
}
}
}

316 Ing. Gilmer Matos Vila


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


siguiente
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
orden en el que se ha escrito. Además, puede
realizar otras tareas necesarias para
actualizar 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


serialización la clase ha de implementar el
interface Externalizable. La clase es
PROGRAMACION CON JAVA 2 317
responsable 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;;
}

318 Ing. Gilmer Matos Vila


CAPITULO 9

APPLETS

En este capítulo vamos a tratar de ver todo lo que


necesitamos para saber escribir un applet Java. Dado que los
applets pueden usar una gran cantidad de clases del API de
Java, veremos 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


applet es "una pequeña aplicación accesible en un
servidor de Internet, que se transporta por la red, se
PROGRAMACION CON JAVA 2 319
instala automáticamente y se ejecuta in situ como
parte de un documento web". Claro que así la
definición establece el entorno (Internet, Web, etc.).
En realidad, un applet es una aplicación
pretendidamente corta (nada impide que ocupe más de un
gigabyte, a no ser el pensamiento de que se va a
transportar por la red) basada en un formato gráfico
sin representación independiente: es decir, se trata
de un elemento a incluir en otras aplicaciones; es un
componente en su sentido estricto.

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
navegador.
public class Applet1 extends Applet
{
public void init()
{
//...
}
}

9.3. EL PRIMER APPLET


Para crear un applet tenemos que definir una clase
denominada Applet1 derivada de Applet. La primera
sentencia import nos proporciona información acerca de
las clases del paquete applet. Dicho paquete contiene
las clases necesarias para crear applets que se
ejecutan en la ventana del navegador, entre las cuales
está la clase base Applet.

import java.applet.*;
public class Applet1 extends Applet
{
}

320 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


El siguiente paso es dar funcionalidad a la clase,
definir 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
suministra 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
indican las coordendas de la línea base del primer
cará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
navegador toma el control del applet llamando a
algunos de sus métodos, uno de estos es el método
paint que se llama cada vez que se necesita mostrar el
applet en la ventana del navegador.
PROGRAMACION CON JAVA 2 321
Cuando el applet se carga, el navegador llama a su
método init. En este método el programador realiza
tareas de inicialización, por ejemplo, establecer las
propiedades de los controles, disponerlos en el
applet, cargar imágenes, etc.

El método init se llama una sóla vez. Después, el


navegador 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
contiene 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
figuras en la ventana del navegador. Cuando Sun
Microsystems desarrolló el lenguaje Java, se añadió la
etiqueta que permite insertar applets en las páginas
web. Como otras etiquetas tiene un comienzo <APPLET> y
un final señalado por </APPLET>

En el Entorno Integrado de Desarrollo (IDE) de


JCreator creamos un applet. Con JCreator generamos la
clase que describe el applet con algunos métodos y lo
guardamos en un archivo cuyo nombre es el mismo que el
322 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
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,


utilice <APPLET> ... </APPLET> en su página.

Dentro de la etiqueta applet el parámetro más


importante 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


determinan 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
siguiente salida:

PROGRAMACION CON JAVA 2 323


Ejemplo(0): 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>
</HEAD>
324 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
<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
applet, que muestra un mensaje. En este capítulo se
estudiará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 clearRect(int x, int y, int width, int height)
void Clears the specified rectangle by
filling it with the background color of the
current drawing surface.
abstract clipRect(int x, int y, int width, int height)
void Intersects the current clip with the
specified rectangle.
abstract copyArea(int x, int y, int width, int height, int dx,
void int dy)
Copies an area of the component by a
distance specified by dx and dy.

PROGRAMACION CON JAVA 2 325


abstract create()
Graphics 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 dispose()
void Disposes of this graphics context and
releases any system resources that it is using.
void draw3DRect(int x, int y, int width, int height,
boolean raised)
Draws a 3-D highlighted outline of the
specified rectangle.
abstract drawArc(int x, int y, int width, int height, int startAngle,
void int arcAngle)
Draws the outline of a circular or
elliptical 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
current font and color.
abstract drawImage(Image img, int x, int y, Color bgcolor,
boolean ImageObserver observer)
Draws as much of the specified image as
is currently available.
abstract drawImage(Image img, int x, int y, ImageObserver observer)
boolean Draws as much of the specified image as
is currently available.
abstract drawImage(Image img, int x, int y, int width, int height,
boolean Color bgcolor, ImageObserver observer)
Draws as much of the specified image as
has already been scaled to fit inside the
specified rectangle.
abstract drawImage(Image img, int x, int y, int width, int height,
boolean ImageObserver observer)
Draws as much of the specified image as
has already been scaled to fit inside the
326 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
specified rectangle.

PROGRAMACION CON JAVA 2 327


abstract drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
boolean 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 drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
boolean 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 drawLine(int x1, int y1, int x2, int y2)
void Draws a line, using thecurrent color,
between the points (x1, y1) and (x2, y2) in this
graphics context's coordinate system.
abstract drawOval(int x, int y, int width, int height)
void Draws the outline of an oval.
abstract drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
void 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 drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
void Draws a sequence of connected lines
defined by arrays of x and y coordinates.
void drawRect(int x, int y, int width, int height)
Draws the outline of the specified
rectangle.
abstract drawRoundRect(int x, int y, int width, int height,
void int arcWidth, int arcHeight)
Draws an outlined round-cornered
rectangle using this graphics context's current
color.
abstract drawString(AttributedCharacterIterator iterator, int x,
void int y)
Draws the text given by the specified
iterator, using this graphics context's current
color.
abstract drawString(String str, int x, int y)
void Draws the text given
by the specified
string, using this graphics context's current font
328 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
and color.

PROGRAMACION CON JAVA 2 329


void fill3DRect(int x, int y, int width, int height,
boolean raised)
Paints a 3-D highlighted rectangle
filled with the current color.
abstract fillArc(int x, int y, int width, int height, int startAngle,
void int arcAngle)
Fills a circular or elliptical arc
covering the specified rectangle.
abstract fillOval(int x, int y, int width, int height)
void Fills an oval bounded by the specified
rectangle with the current color.
abstract fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
void Fills a closed polygon defined by arrays
of x and y coordinates.
void fillPolygon(Polygon p)
Fills the polygon defined by the
specified Polygon object with the graphics
context's current color.
abstract fillRect(int x, int y, int width, int height)
void Fills the specified rectangle.
abstract fillRoundRect(int x, int y, int width, int height,
void int arcWidth, int arcHeight)
Fills the specified rounded corner
rectangle with the current color.
void finalize()
Disposes of this graphics context once
it is no longer referenced.
abstract getClip()
Shape Gets the current clipping area.
abstract getClipBounds()
Rectangle 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,
replaced by getClipBounds().
abstract getColor()
Color Gets this graphics context's current
color.
abstract getFont()

330 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


Font Gets the current font.

PROGRAMACION CON JAVA 2 331


FontMetrics getFontMetrics()
Gets the font metrics of the current
font.
abstract getFontMetrics(Font f)
FontMetrics Gets the font metrics for the specified
font.
boolean hitClip(int x, int y, int width, int height)
Returns true if the specified
rectangular area might intersect the current
clipping area.
abstract setClip(int x, int y, int width, int height)
void Sets the current clip to the rectangle
specified by the given coordinates.
abstract setClip(Shape clip)
void Sets the
current clipping area to an
arbitrary clip shape.
abstract setColor(Color c)
void Sets
this graphics context's current
color to the specified color.
abstract setFont(Font font)
void Sets this graphics context's font to the
specified font.
abstract setPaintMode()
void Sets
the paint mode of this graphics
context to overwrite the destination with this
graphics context's current color.
abstract setXORMode(Color c1)
void Sets the
paint mode of this graphics
context to alternate between this graphics
context's current color and the new specified
color.
String toString()
Returns a String object representing this
Graphics object's value.
abstract translate(int x, int y)
void Translates
the origin of the graphics
context to the point (x, y) in the current
coordinate system.

332 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
obtener el contexto gráfico g. Solamente es
necesario liberar los recursos asociados al
contexto g, mediante la llamada a la función
dispose, cuando se obtiene el contexto
gráfico 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
referencia 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
dibujar en dicha hoja se toma una pluma, se
dibuja, se toma otra pluma de distinto color
o grosor, se dibuja otra porción del gráfico,
y así sucesivamente. Cuando no se selecciona
PROGRAMACION CON JAVA 2 333
explícitamente, se dibuja con una pluma que
se establece por defecto.

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
cerrada con un color sólido, con una
determinada trama o figura, y fuentes de
texto, para dibujar texto con distintas
fuentes y estilos. 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 tienen 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áfico y proporciona un conjunto de
funciones para 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
similar a Windows. El área
X de trabajo del applet está
compuesta por una matriz
bidimensional de puntos o
pixels. Decimos que un
punto tiene coordenadas
Y (x, y) cuando está en la
columna x medida desde la
izquierda, y está en la
fila y, medida desde
arriba.
La esquina superior izquierda es el
origen (0, 0).
334 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
La esquina inferior derecha viene
determinada por las dimensiones del
componente. La función getSize nos
devuelve un objeto de la clase
Dimension cuyos miembros width y
height nos suministran la anchura y
altura del componente.
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
utiliza la función setColor, y se le pasa un
color 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
diagonal desde el origen (0, 0) o esquina
superior izquierda, hasta la esquina inferior
derecha, 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
miembro height la altura.
g.drawLine(0, 0, getSize().width-1, getSize().height-1);

PROGRAMACION CON JAVA 2 335


9.5.4. DIBUJAR UN RECTÁNGULO
Un rectángulo viene definido por un origen
(esquina superior izquierda), su anchura y
altura. La siguiente sentencia dibuja un
rectá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
rectángulo pintando su interior del color
seleccionado, 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
cerrada mientas que una polilínea es un
conjunto de segmentos. Para formar un
polígono a partir de una pililínea se une el
punto inicial 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};
336 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
g.setColor(Color.blue);
g.drawPolygon(x, y, x.length);

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


pintado 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
contorno está dibujado en azul y su interior
en amarillo.

9.5.7. DIBUJAR UNA IMAGEN


Para dibujar una imagen se requieren dos
pasos:

 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ágina web que contiene al applet. El lugar
más adecuado para cargar la imagen es en la
función init, ya que como se ha mencionado se
llama una sola vez.

public void init()


PROGRAMACION CON JAVA 2 337
{
disco=getImage(getDocumentBase(), "disco.gif");
}

Para dibujar la imagen en el contexto gráfico


g, se llama a la función drawImage. Hay
varias versiones de esta función, la más
simple es aquella a la que se le proporciona
el objeto 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


objeto 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(0): Programa completo del uso de las funciones


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");
338 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
}
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);

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 339


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
denominado RGB, que significa que cualquier
color 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.

Green
Nombre Red (rojo) Blue (azul)
(verde)
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
340 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
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
indican 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);
No es necesario tener a mano la tabla de las
componentes RGB de cada color. La clase Color
nos proporciona un conjunto de colores
predefinidos en forma de miembros estáticos
de dicha 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(0): Programa que imprime un


rectangulo

// Archivo: PaintRect.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class PaintRect extends Applet


{
public void init()
PROGRAMACION CON JAVA 2 341
{
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>

El color de fondo del componente se establece


con setBackground y se obtiene con
getBackground. 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 setBackground. 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
podemos 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

342 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


respectivamete la anchura y altura del
applet.

Ejemplo(0): Programa completo del uso de


Color
// 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());
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 343


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


Times 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
establecer el estilo negrita y cursiva a la
vez.

344 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


La función setFont de la clase Graphics
establece 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,


establecemos una fuente de texto, dibujamos
el texto, y reestablecemos la fuente de texto
por defecto, 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


texto disponibles se escribe el siguiente
código

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);

PROGRAMACION CON JAVA 2 345


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
(baseline) y la línea horizontal de color
rojo. Descent es la distancia entre la línea
horizontal de color azul (baseline) y la
línea horizontal de color verde. Leading
sería la distancia entre las línea de color
verde (descent) y la línea roja (ascent) de
la siguiente línea de texto.

346 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


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
(baseline) consecutivas,
y es la suma de el
ascent, descent y
leading.
Tres funciones que comienzan por
get devuelven los valores de estos
tres atributos de una fuente de
texto: getAscent, getDescent, y
getLeading.

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
posició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);

PROGRAMACION CON JAVA 2 347


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


verticalmente, en una determinada posición.
Teniendo 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
ordenada 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


acentuados, escritos en mayúsculas o
minúsculas, etc, la fórmula para mostrar un
texto centrado verticamente no es única, se
sugiere probar 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


siguiente:

Ejemplo(0): Ejemplo del uso de Font y


FontMetrics

// Archivo: FontApplet2.java

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class FontApplet2 extends Applet


{

public FontApplet2()
{
}
//Initialize the applet
348 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
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;
PROGRAMACION CON JAVA 2 349
g.setColor(Color.black);
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>

350 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


Ejemplo(0): Programa que grafica una
parabola.

// 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
cartesianas
// 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++)
{
PROGRAMACION CON JAVA 2 351
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>

352 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


Ejemplo(0): 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
cartesianas
// 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>

PROGRAMACION CON JAVA 2 353


</HTML>

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
travé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
siguiente manera:

354 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


import java.awt.*;

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
especializado) pueden contener otros
componentes (paneles y controles). La
jerarquía de clases se muestra en la figura

La librería AWT no es muy rica en


componentes, tal como se ve en la figura. Sin
embargo, hemos de tener cuidado en usar
solamente componentes AWT para los applets
que vayamos a publicar en Internet. Los

PROGRAMACION CON JAVA 2 355


navegadores no ejecutan applets que utilicen
componentes no estándar.

Por debajo de los controles AWT están los


controles nativos, esto presenta algunas
dificultades, por ejemplo, los controles son
siempre rectangulares y opacos. La versión
Java 2.0 sustituye la libería AWT por la
denominada Swing en la que se elimina la
dependencia de los controles nativos, el
número y el tipo de componentes puede
satisfacer con creces las aspiraciones de
cualquier programador exigente. Además,
podemos crear nuestros propios controles,
comprarlos o encargarlos a medida, y
situarlos en la paleta de componentes.

9.7.2. ROTULOS (Label)


Un rótulo es una area donde se exhibe una
sola línea de texto estatico (sólo de
lectura). El texto no puede ser modificado
por el usuario 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
centered.
static int LEFT
Indicates that the label should be left
justified.
static int RIGHT
Indicates that the label should be right
justified.

356 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


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
associated 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,
PROGRAMACION CON JAVA 2 357
contains, contains, createImage, createImage, createVolatileImage,
createVolatileImage, deliverEvent, disable, disableEvents, dispatchEvent,
doLayout, enable, enable, enableEvents, enableInputMethods,
firePropertyChange, firePropertyChange, firePropertyChange,
getAlignmentX, getAlignmentY, getBackground, getBounds, getBounds,
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
358 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
Ease-of-use constant for getAlignmentY.
static float CENTER_ALIGNMENT
Ease-of-use constant for getAlignmentY and
getAlignmentX.
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
component which fires action events.
void add(PopupMenu popup)
Adds the specified popup menu to the
component.
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
receive focus events from this component when this
component gains input focus.
void addHierarchyBoundsListener(HierarchyBoundsListener l)
Adds the specified hierarchy bounds
listener 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

PROGRAMACION CON JAVA 2 359


changes.
void addInputMethodListener(InputMethodListener l)
Adds the specified input method listener
to receive input method events from this component.

360 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
receive 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
connecting it to a native screen resource.
void addPropertyChangeListener(PropertyChangeListener listener)
Adds a PropertyChangeListener to the
listener list.
void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener)
Adds a PropertyChangeListener to the
listener 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,
replaced 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 coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent)
AWTEvent Potentially coalesce an event being posted
with an existing event.

PROGRAMACION CON JAVA 2 361


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
coordinates 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.
VolatileI createVolatileImage(int width, int height)
mage Creates a volatile off-screen drawable
image to be used for double buffering.
VolatileI createVolatileImage(int width, int height,
mage ImageCapabilities caps)
Creates a volatile off-screen drawable
image, with the given capabilities.
void deliverEvent(Event e)
Deprecated. As of JDK version 1.1,
replaced by dispatchEvent(AWTEvent e).
void disable()
Deprecated. As of JDK version 1.1,
replaced by setEnabled(boolean).
protected disableEvents(long eventsToDisable)
void Disables the events defined by the
specified 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,
replaced by setEnabled(boolean).
void enable(boolean b)

362 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


Deprecated. As of JDK version 1.1,
replaced by setEnabled(boolean).
protected enableEvents(long eventsToEnable)
void Enables the events defined by the
specified event mask parameter to be delivered to
this component.
void enableInputMethods(boolean enable)
Enables or disables input method support
for this component.
protected firePropertyChange(String propertyName, boolean oldValue,
void boolean newValue)
Support for reporting bound property
changes for boolean properties.
protected firePropertyChange(String propertyName, int oldValue,
void int newValue)
Support for reporting bound property
changes for integer properties.
protected firePropertyChange(String propertyName, Object oldValue,
void Object newValue)
Support for reporting bound property
changes for Object properties.
Accessibl getAccessibleContext()
eContext 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
component.
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.
ColorMode getColorModel()
l Gets the instance of ColorModel used to
display 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)
PROGRAMACION CON JAVA 2 363
location, and if so, returns the containing
component.
Component getComponentAt(Point p)
Returns the component or subcomponent that
contains the specified point.
Component getComponentListeners()
Listener[] Returns an array of all the component
listeners registered on this component.
Component getComponentOrientation()
Orientatio Retrieves the language-sensitive
n orientation that is to be used to order the elements
or text within this component.
Cursor getCursor()
Gets the cursor set in the component.
DropTarge getDropTarget()
t Gets the DropTarget associated with this
Component.
Container getFocusCycleRootAncestor()
Returns the Container which is the focus
cycle root of this Component's focus traversal
cycle.
FocusList getFocusListeners()
ener[] Returns an array of all the focus
listeners 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.
FontMetri getFontMetrics(Font font)
cs Gets the font metrics for the specified
font.
Color getForeground()
Gets the foreground color of this
component.
Graphics getGraphics()
Creates a graphics context for this
component.
GraphicsC getGraphicsConfiguration()

364 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


onfigurati Gets the GraphicsConfiguration associated with
on this Component.
int getHeight()
Returns the current height of this
component.

PROGRAMACION CON JAVA 2 365


Hierarchy getHierarchyBoundsListeners()
BoundsList Returns an array of all the hierarchy
ener[] bounds listeners registered on this component.

Hierarchy getHierarchyListeners()
Listener[] Returns an array of all the hierarchy
listeners registered on this component.
boolean getIgnoreRepaint()

InputCont getInputContext()
ext Gets the input context used by this
component for handling the communication with input
methods when text is entered in this component.
InputMeth getInputMethodListeners()
odListener Returns an array of all the input method
[] listeners registered on this component.

InputMeth getInputMethodRequests()
odRequests Gets the input method request handler
which supports requests from input methods for this
component.
KeyListen getKeyListeners()
er[] Returns an array of all the key listeners
registered on this component.
EventList getListeners(Class listenerType)
ener[] Returns an array of all the objects
currently 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()
366 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
Gets the mininimum size of this component.
MouseList getMouseListeners()
ener[] Returns an array of all the mouse
listeners registered on this component.
MouseMoti getMouseMotionListeners()
onListener Returns an array of all the mouse motion
[] listeners registered on this component.

MouseWhee getMouseWheelListeners()
lListener[ 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.
java.awt. getPeer()
peer.Compo Deprecated. As of JDK version 1.1,
nentPeer programs should not directly manipulate peers;
replaced by boolean isDisplayable().
Dimension getPreferredSize()
Gets the preferred size of this component.
PropertyC getPropertyChangeListeners()
hangeListe Returns an array of all the property
ner[] change listeners registered on this component.

PropertyC getPropertyChangeListeners(String propertyName)


hangeListe Returns an array of all the listeners
ner[] 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
component.
int getX()
PROGRAMACION CON JAVA 2 367
Returns the current x coordinate of the
components origin.

368 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,
replaced 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,
replaced 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,
replaced 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
explicitly set for this Component.
boolean isDisplayable()
Determines whether this component is
displayable.
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
enabled.
boolean isFocusable()
Returns whether this Component can be
PROGRAMACION CON JAVA 2 369
focused.
boolean isFocusCycleRoot(Container container)
Returns whether the specified Container is
the focus cycle root of this Component's focus
traversal cycle.
boolean isFocusOwner()
Returns true if this Component is the focus
owner.
boolean isFocusTraversable()
Deprecated. As of 1.4, replaced by
isFocusable().
boolean isFontSet()
Returns whether the font has been
explicitly 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
native toolkit peer.
boolean isOpaque()
Returns true if this component is
completely opaque, returns false by default.
boolean isShowing()
Determines whether this component is
showing on screen.
boolean isValid()
Determines whether this component is
valid.
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,
replaced by processKeyEvent(KeyEvent).
boolean keyUp(Event evt, int key)
Deprecated. As of JDK version 1.1,
replaced by processKeyEvent(KeyEvent).
void layout()
Deprecated. As of JDK version 1.1,
replaced by doLayout().
void list()

370 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


Prints a listing of this component to the
standard system output stream System.out.

PROGRAMACION CON JAVA 2 371


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
specified 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
specified indentation, to the specified print
writer.
Component locate(int x, int y)
Deprecated. As of JDK version 1.1,
replaced by getComponentAt(int, int).
Point location()
Deprecated. As of JDK version 1.1,
replaced by getLocation().
boolean lostFocus(Event evt, Object what)
Deprecated. As of JDK version 1.1,
replaced by processFocusEvent(FocusEvent).
Dimension minimumSize()
Deprecated. As of JDK version 1.1,
replaced by getMinimumSize().
boolean mouseDown(Event evt, int x, int y)
Deprecated. As of JDK version 1.1,
replaced by processMouseEvent(MouseEvent).
boolean mouseDrag(Event evt, int x, int y)
Deprecated. As of JDK version 1.1,
replaced by processMouseMotionEvent(MouseEvent).
boolean mouseEnter(Event evt, int x, int y)
Deprecated. As of JDK version 1.1,
replaced by processMouseEvent(MouseEvent).
boolean mouseExit(Event evt, int x, int y)
Deprecated. As of JDK version 1.1,
replaced by processMouseEvent(MouseEvent).
boolean mouseMove(Event evt, int x, int y)
Deprecated. As of JDK version 1.1,
replaced by processMouseMotionEvent(MouseEvent).
boolean mouseUp(Event evt, int x, int y)
372 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
Deprecated. As of JDK version 1.1,
replaced by processMouseEvent(MouseEvent).

PROGRAMACION CON JAVA 2 373


void move(int x, int y)
Deprecated. As of JDK version 1.1,
replaced by setLocation(int, int).
void nextFocus()
Deprecated. As of JDK version 1.1,
replaced by transferFocus().
void paint(Graphics g)
Paints this component.
void paintAll(Graphics g)
Paints this component and all of its
subcomponents.
protected paramString()
String Returns a string representing the state of
this component.
boolean postEvent(Event e)
Deprecated. As of JDK version 1.1,
replaced by dispatchEvent(AWTEvent).
Dimension preferredSize()
Deprecated. As of JDK version 1.1,
replaced 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
subcomponents.
protected processComponentEvent(ComponentEvent e)
void Processes component events occurring on
this component by dispatching them to any registered
ComponentListener objects.
protected processEvent(AWTEvent e)
void Processes events occurring on this
component.
protected processFocusEvent(FocusEvent e)
void Processes focus events occurring on this
component by dispatching them to any registered
374 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
FocusListener objects.
protected processHierarchyBoundsEvent(HierarchyEvent e)
void Processes hierarchy bounds events
occurring on this component by dispatching them to
any registered HierarchyBoundsListener objects.
protected processHierarchyEvent(HierarchyEvent e)
void Processes hierarchy events occurring on
this component by dispatching them to any registered
HierarchyListener objects.
protected processInputMethodEvent(InputMethodEvent e)
void Processes input method events occurring on
this component by dispatching them to any registered
InputMethodListener objects.
protected processKeyEvent(KeyEvent e)
void Processes key events occurring on this
component by dispatching them to any registered
KeyListener objects.
protected processMouseEvent(MouseEvent e)
void Processes mouse events occurring on this
component by dispatching them to any registered
MouseListener objects.
protected processMouseMotionEvent(MouseEvent e)
void Processes mouse motion events occurring on
this component by dispatching them to any registered
MouseMotionListener objects.
protected processMouseWheelEvent(MouseWheelEvent e)
void 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

PROGRAMACION CON JAVA 2 375


bounds events from this component.

376 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


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
listener 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
component.
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
listener 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
destroying 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)

PROGRAMACION CON JAVA 2 377


Repaints the specified rectangle of this
component within tm milliseconds.
void requestFocus()
Requests that this Component get the input
focus, and that this Component's top-level ancestor
become the focused Window.
protected requestFocus(boolean temporary)
boolean 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
already the focused Window.
protected requestFocusInWindow(boolean temporary)
boolean Requests that this Component get the input
focus, if this Component's top-level ancestor is
already the focused Window.
void reshape(int x, int y, int width, int height)
Deprecated. As of JDK version 1.1,
replaced by setBounds(int, int, int, int).
void resize(Dimension d)
Deprecated. As of JDK version 1.1,
replaced by setSize(Dimension).
void resize(int width, int height)
Deprecated. As of JDK version 1.1,
replaced by setSize(int, int).
void setBackground(Color c)
Sets the background color of this
component.
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
conform 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.

378 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


void setDropTarget(DropTarget dt)
Associate a DropTarget with this component.

PROGRAMACION CON JAVA 2 379


void setEnabled(boolean b)
Enables or disables this component,
depending 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


enabled for this Component.
void setFont(Font f)
Sets the font of this component.
void setForeground(Color c)
Sets the foreground color of this
component.
void setIgnoreRepaint(boolean ignoreRepaint)
Sets whether or not paint messages
received 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
specified 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()

380 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


Deprecated. As of JDK version 1.1,
replaced by setVisible(boolean).

PROGRAMACION CON JAVA 2 381


void show(boolean b)
Deprecated. As of JDK version 1.1,
replaced by setVisible(boolean).
Dimension size()
Deprecated. As of JDK version 1.1,
replaced 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
component, 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 (0): 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

382 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


//usa el método setFont de la clase Component
textolabel1.setFont(f1);
add(textolabel1);

//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


posiciona los textos en dos líneas.

Si usted desea realizar que los textos se


posicionen en dos líneas debe utilizar el
administrador de diseños GridLayout (Diseño
de Retícula)

PROGRAMACION CON JAVA 2 383


9.7.3. ADMINISTRADOR DE DISEÑOS GRIDLAYOUT
El administrador de diseños GridLayout divide
el contenedor en una retícula que permite
colocar los componentes en filas y columnas.
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 layout.
int getHgap()
Gets the horizontal gap between
components.
int getRows()
Gets the number of rows in this layout.
int getVgap()
Gets the vertical gap between components.
void layoutContainer(Container parent)

384 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


Lays out the specified container using
this layout.
Dimension minimumLayoutSize(Container parent)
Determines the minimum size of the
container argument using this grid layout.
Dimension preferredLayoutSize(Container parent)
Determines the preferred size of the
container 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 components
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 (0): 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");
PROGRAMACION CON JAVA 2 385
//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
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>

386 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


9.7.4. BOTONES PARA PULSAR (BUTTON)
Un botón es un componente en que el usuario
puede relizar un clic para disparar una
acció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.
PROGRAMACION CON JAVA 2 387
AccessibleContext getAccessibleContext()
Gets the AccessibleContext associated
with this Button.
String getActionCommand()
Returns the command name of the
action 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
registered ActionListener objects.
protected void processEvent(AWTEvent e)
Processes events on this button.
void removeActionListener(ActionListener l)
Removes the specified action
listener so that it no longer receives action
events from this button.
void setActionCommand(String command)
Sets the command name for the
action 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,
388 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
createVolatileImage, deliverEvent, disable, disableEvents, dispatchEvent,
doLayout, enable, enable, enableEvents, enableInputMethods,
firePropertyChange, firePropertyChange, firePropertyChange,
getAlignmentX, getAlignmentY, getBackground, getBounds, getBounds,
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 (0): 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;

PROGRAMACION CON JAVA 2 389


public void init()
{

setBackground(Color.yellow);

//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
cartesianas
// 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++)
390 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
{
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);
}
}

//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
cartesianas
// 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>

PROGRAMACION CON JAVA 2 391


La salida del programa cuando se pulsa
función seno y función parábola se muestra en
las siguientes figuras.

392 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


PROGRAMACION CON JAVA 2 393
9.8. LOS GESTORES FLOWLAYOUT, BORDERLAYOUT Y
GRIDLAYOUT
En la superficie del applet se disponen los
componentes, como paneles y controles. Ahora bien, las
herramientas 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 denominados gestores de diseño que no
sitúan los componentes en posiciones absolutas, sino
que la disposición se determina mediante un algoritmo.
El más simple de los gestores de diseño es FlowLayout
y el más complicado es GridBagLayout.

Para el programador acostumbrado a diseñar ventanas y


diálogos en el entorno Windows le parecerá extraña
esta 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


mediante el gestor GridBagLayout y también, mediante
la aproximación de paneles anidados.

No obstante, el programador debe percibir la


diferencia entre applets y aplicaciones. Los applets
están insertados en una página web y se ejecutan en la
ventana del navegador. El applet comparte espacio con
texto, imágenes y otros elementos multimedia. El
usuario 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 distinta 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
controles en una línea, como puede verse en
la figura

394 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


Si se cambia el tamaño del applet y los
controles 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
clase FlowLayout. Una vez inicializados los
miembros dato, en la función miembro init se
establecen sus propiedades y se añaden al
applet mediante la función add, una vez
establecido el gestor de diseño mediante
setLayout. 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 395
btn1.setFont(new Font("Dialog", 1, 16));
btn1.setLabel("1");
flowLayout1.setHgap(20);

 Establecer el gestor de diseño del


applet (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
BorderLayout son distintos a los empleados
para el gestor FlowLayout.
396 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
segundo argumento la posición que
ocupará cada control en el panel
mediante miembros 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
BorderLayout 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();
PROGRAMACION CON JAVA 2 397
Button btnCentro = new Button();
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.

398 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
popiedades columns y rows. Opcionalmente
podemos establecer 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 399
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
disposició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

400 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
superior. 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

PROGRAMACION CON JAVA 2 401


Button btnPago=new Button();
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
horizontal entre los botones.

9.9.3. EL APPLET
Situar los siguientes controles sobre el
applet 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");
402 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
btnCancelar.setLabel("Cancelar");

Añadir elementos al control selección


(Choice) 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
panel) 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 403


La segunda fila, está formada por dos
controles, nombre y a continuación
textNombre. El primero está anclado (anchor)
al este (WEST), antes estaba en NORTH,
gridwidth toma el valor 1 (por defecto) antes
estaba en REMAINDER. Como textNombre es el
último control de la fila gridwidth vuelve a
tomar el valor REMAINDER. 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


controles: direccion y textDireccion. Las
propiedades anchor y fill ya tienen fijados
sus valores 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


controles: ciudad, textCiudad, provincia y
textProvincia. 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
controles: pago y chPago. El código es
semejante, salvo la propiedad fill que toma
el valor NONE antes estaba en HORIZONTAL.
404 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
Esto hace que el control chPago no ocupe toda
el área disponible, extendiéndose
horizontalmente hasta alinearse con los otros
controles por la parte 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
muestra 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);

PROGRAMACION CON JAVA 2 405


//propiedades de los controles
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");

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);
406 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
//panel de los botones
panelBotones.setLayout(flowLayout1);
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 407


CAPITULO 10

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
responder, 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 estos 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
completos de la computadora durante su vida operativa. El
problema 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
alguna condición de temporización. Si fuésemos capaces
de describir todas las tareas como hilos de control
408 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
independientes, conmutando de manera automática entre
una tarea que esté lista para pasar a un modo de
espera, y otra que sí tenga algo que hacer,
conseguiríamos realizar una cantidad mayor de trabajo
en le mismo intervalo de tiempo.

Java se diseño partiendo de cero, en un mundo en el


que el entorno multihilo, a nivel de sistema
operativo, era una realidad. El intérprete de Java
hace uso intensivo de hilos para multitud de
propósitos, y todas las bibliotecas de clases se
diseñaron teniendo en mente el modelo multihilo. Una
vez que un hilo comienza su tarea, puede suspenderse,
lo que equivale a detener 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 puede deteriores, finalizando su
ejecución de manera inmediata. Una vez detenido, el
proceso no puede reiniciarse.

10.1.1. PRIORIDADES DE HILO


El intérprete de Java utiliza prioridades
para 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
comportamiento asíncrono de los programas,
debe existir alguna manera de forzar el
sincronismo 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 versión rebuscada de un modelo
clásico para la sincronización, el monitor.
La mayor parte de los sistemas multihilo
implementan los monitores a modo de objetos,
pero Java proporciona una solución más
elegante: no existe la clase monitor, cada
objeto lleva asociado su propio monitor
implícito, en el que puede entrar sin más que
PROGRAMACION CON JAVA 2 409
hacer una llamada a los métodos synchronized
del objeto. Una vez que el hilo está dentro
del método synchronized, ningún otro hilo
puede efectuar una llamada a otro método
synchronized sobre el mismo objeto.

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
informació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
comportamiento 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
comenzar 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íncronamente. 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.
410 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 interrumpido");
}
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
continuació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
imprimir un mensaje y después termina. Demo Thread
todaví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
3
saliendo del hilo main
PROGRAMACION CON JAVA 2 411
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
menor prioridad. Cuando está ejecutándose un hilo de
baja 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,
desalojando 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
pretendemos tener un comportamiento predecible sobre
las aplicaciones deberemos utilizar hilos que,
voluntariamente, cedan el control de la CPU.

10.5. SINCRONIZACIÓN
Cuando dos o más hilos necesitan acceder de manera
simultá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
monitor, es un objeto que se utiliza como cerrojo
exclusivo. 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


propio implícitamente asociado a ellos. La manera de
acceder a un objeto monitor es llamando a un método
marcado con la palabra clave synchronized. Durante
todo el tiempo en que un hilo permanezca en un método
sincronizado, los demás hilos que intenten llamar a un
método sincronizado sobre la misma instancia tendrán
que esperar. Para salir del monitor y permitir el
control del objeto al siguiente hilo en espera, el
412 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.
propietario 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
objeto. Ahora veremos las formas de
sincronizació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 413
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
instancias de caller que cada una de ellas referencia
al mismo Callme con lo que necesitamos de una
sincronización para el acceso a Callme, pues sino se
mezclarían las tres llamada al haber una sentencia
sleep que retrasa 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
consume. Para que el problema sea más interesante
supongamos que el productor tiene que esperar a que el
consumidor haya terminado, para empezar a producir más
datos. En un sistema basado en sondeo el consumidor
estarí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
consumidor ha finalizado, y así sucesivamente.

Evidentemente, hay una forma mejor de hacerlo. Java


proporciona un mecanismo elegante de comunicación
entre 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
synchronized.

 wait: le indica al hilo en curso que


abandone el monitor y se vaya a dormir hasta que
otro hilo entre 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 realizaron una llamada a wait sobre el mismo
objeto. El hilo con mayor prioridad de los
despertados es el primero en ejecutarse.

414 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 415


10.6.1. BLOQUEOS
Los bloqueos son condiciones anómalas
inusuales, pero muy difíciles de depurar,
donde dos hilos presentan una dependencia
circular sobre 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 embargo, si Y, por su
parte, intenta llamar a cualquier método
sincronizado con X, entonces quedará
esperando indefinidamente, ya que para
conseguir el cerrojo de X tendría antes que
liberar su propio cerrojo en Y, con el fin de
que el primer hilo pudiera completarse.

10.7. RESUMEN DE LA INTERFAZ DE PROGRAMACIÓN


(API) DE HILOS
Se incluye a continuación una referencia rápida a
todos los métodos de la clase Thread que se han
comentado 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


devuelve el objeto Thread que representa
al hilo que se ejecuta actualmente.

 yield: este método hace que el


intérprete cambie de contexto entre el
hilo actual y el siguiente hilo
ejecutable disponible. 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
416 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
mayores 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
apropiado 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
llamada al método stop no llega a
ejecutarse jamás, pues el contexto del
hilo muere antes de que stop devuelva el
control.

 suspend: es distinto de stop. suspend


toma el hilo y provoca que se detenga su
ejecución sin destruir el hilo de
sistema subyacente, ni el estado del
hilo anteriormente en ejecución. Si la
ejecución de un hilo se suspende, puede
llamarse 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 417
 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
programas multihilo.

 getName: devuelve el valor actual, de


tipo cadena, asignado como nombre al
hilo mediante setName.

418 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.


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 Programació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 Java”. 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 Programming For Dummies”. Editorial
IDG Books. USA.

PROGRAMACION CON JAVA 2 419


8. S. Wang, Paul (2000). “Java con
programación orientada a objetos y aplicaciones en la
World Wide Web”. Editorial Thomson. México.

420 A. GAMARRA M. – D. GAMARRA M. – J. GAMARRA M.

También podría gustarte