Programación en Java

  • 0 0 0
  • Like this paper and download? You can publish your own PDF file online for free in a few minutes! Sign Up
File loading please wait...
Citation preview

Desarrollo de software Se tratan diferentes aspectos de Java, desde las aplicaciones hasta los applets a través de numerosos ejemplos. Como herramientas de desarrollo se utilizan Microsoft Visual J++ 6 y JBuilder. La versión tratada del lenguaje es la estándar de Sun Microsystems. Se pretende adiestrar sobre: • • • • • • •

Programación Orientada a Objetos. Construcción de aplicaciones Java. Creación de applets Java. Tratamiento de eventos y construcción de interfaces de usuario. Utilización de Visual J++ 6. Programación multihilo. Acceso a ficheros y conexiones a través de Internet.

El único requisito es conocer algún lenguaje de programación

PROGRAMACIÓN EN JAVA ÁNGEL ESTEBAN

ADVERTENCIA LEGAL Todos los derechos de esta obra están reservados a Grupo EIDOS Consultoría y Documentación Informática, S.L. El editor prohíbe cualquier tipo de fijación, reproducción, transformación, distribución, ya sea mediante venta y/o alquiler y/o préstamo y/o cualquier otra forma de cesión de uso, y/o comunicación pública de la misma, total o parcialmente, por cualquier sistema o en cualquier soporte, ya sea por fotocopia, medio mecánico o electrónico, incluido el tratamiento informático de la misma, en cualquier lugar del universo. El almacenamiento o archivo de esta obra en un ordenador diferente al inicial está expresamente prohibido, así como cualquier otra forma de descarga (downloading), transmisión o puesta a disposición (aún en sistema streaming). La vulneración de cualesquiera de estos derechos podrá ser considerada como una actividad penal tipificada en los artículos 270 y siguientes del Código Penal. La protección de esta obra se extiende al universo, de acuerdo con las leyes y convenios internacionales. Esta obra está destinada exclusivamente para el uso particular del usuario, quedando expresamente prohibido su uso profesional en empresas, centros docentes o cualquier otro, incluyendo a sus empleados de cualquier tipo, colaboradores y/o alumnos. Si Vd. desea autorización para el uso profesional, puede obtenerla enviando un e-mail [email protected] o al fax (34)-91-5017824. Si piensa o tiene alguna duda sobre la legalidad de la autorización de la obra, o que la misma ha llegado hasta Vd. vulnerando lo anterior, le agradeceremos que nos lo comunique al e-mail [email protected] o al fax (34)-91-5017824). Esta comunicación será absolutamente confidencial. Colabore contra el fraude. Si usted piensa que esta obra le ha sido de utilidad, pero no se han abonado los derechos correspondientes, no podremos hacer más obras como ésta. © Ángel Esteban, 2000 © Grupo EIDOS Consultaría y Documentación Informática, S.L., 2000 ISBN 84-88457-18-9

Programación en Java Ángel Esteban Responsable editorial Paco Marín ([email protected]) Autoedición Magdalena Marín ([email protected]) Ángel Esteban ([email protected]) Grupo EIDOS C/ Téllez 30 Oficina 2 28007-Madrid (España) Tel: 91 5013234 Fax: 91 (34) 5017824 www.grupoeidos.com/www.eidos.es www.LaLibreriaDigital.com

Coordinación de la edición Antonio Quirós ([email protected])

Índice ÍNDICE................................................................................................................................................... 5 INTRODUCCIÓN A LA POO ........................................................................................................... 11 ¿QUÉ ES LA POO?.............................................................................................................................. 11 OBJETOS ............................................................................................................................................. 12 MENSAJES .......................................................................................................................................... 13 CLASES............................................................................................................................................... 14 HERENCIA .......................................................................................................................................... 14 MÉTODOS ........................................................................................................................................... 15 POLIMORFISMO .................................................................................................................................. 16 SOBRECARGA ..................................................................................................................................... 16 LA LEY DE DEMETER ......................................................................................................................... 16 MODELO DE OBJETOS ......................................................................................................................... 17 RELACIONES ENTRE CLASES .............................................................................................................. 17 VENTAJAS E INCONVENIENTES DE LA POO ....................................................................................... 18 UN EJEMPLO SENCILLO ...................................................................................................................... 19 INTRODUCCIÓN AL LENGUAJE JAVA ...................................................................................... 21 INTRODUCCIÓN .................................................................................................................................. 21 BREVE HISTORIA DEL LENGUAJE ....................................................................................................... 22 DESCRIPCIÓN DEL LENGUAJE ............................................................................................................. 22 PROGRAMAS EN JAVA: APPLETS Y APLICACIONES ............................................................................ 25 SIMILITUDES Y DIFERENCIAS ENTRE JAVA Y C++ ............................................................................. 26 VERSIONES DEL LENGUAJE ................................................................................................................ 26 ENTORNOS DE DESARROLLO .............................................................................................................. 27 CARACTERÍSTICAS DE LA PLATAFORMA JAVA 2 ............................................................................... 29

SINTAXIS DEL LENGUAJE JAVA................................................................................................. 33 INTRODUCCIÓN .................................................................................................................................. 33 IDENTIFICADORES .............................................................................................................................. 33 PALABRAS CLAVE .............................................................................................................................. 35 LITERALES ......................................................................................................................................... 36 Enteros........................................................................................................................................... 36 Coma flotante................................................................................................................................. 37 Booleanos ...................................................................................................................................... 37 Caracteres...................................................................................................................................... 37 Cadenas ......................................................................................................................................... 38 El literal null.................................................................................................................................. 38 OPERADORES ..................................................................................................................................... 38 SEPARADORES.................................................................................................................................... 39 COMENTARIOS ................................................................................................................................... 39 TIPOS DE DATOS EN JAVA .................................................................................................................. 40 Enteros........................................................................................................................................... 40 Coma flotante................................................................................................................................. 41 Booleanos ...................................................................................................................................... 41 Carácter......................................................................................................................................... 41 Cadenas ......................................................................................................................................... 41 Arrays ............................................................................................................................................ 42 EMPAQUETAR TIPOS PRIMITIVOS ....................................................................................................... 43 CONVERSIÓN DE TIPOS DE DATOS ...................................................................................................... 44 BLOQUES Y ÁMBITOS ......................................................................................................................... 45 Bloques .......................................................................................................................................... 45 Ámbitos .......................................................................................................................................... 46 EXPRESIONES ..................................................................................................................................... 46 CLASIFICACIÓN DE OPERADORES ...................................................................................................... 48 Aritméticos..................................................................................................................................... 48 Operadores sobre enteros........................................................................................................... 48 Operadores sobre reales............................................................................................................. 50 Booleanos ...................................................................................................................................... 50 Relacionales................................................................................................................................... 51 Cadena........................................................................................................................................... 51 Asignación ..................................................................................................................................... 52 PRECEDENCIA DE LOS OPERADORES .................................................................................................. 52 CONTROL DE FLUJO............................................................................................................................ 53 If-else ............................................................................................................................................. 53 Switch............................................................................................................................................. 54 For ................................................................................................................................................. 55 While.............................................................................................................................................. 56 Do-while: ....................................................................................................................................... 57 Break, continue y etiquetas............................................................................................................ 57 Return ............................................................................................................................................ 59 Try, catch, finally y throws: ........................................................................................................... 59 POO EN JAVA: OBJETOS................................................................................................................ 61 INTRODUCCIÓN .................................................................................................................................. 61 OBJETOS ............................................................................................................................................. 61 CREACIÓN DE OBJETOS ...................................................................................................................... 62 Declaración ................................................................................................................................... 62 Instanciación.................................................................................................................................. 63 Inicialización ................................................................................................................................. 64 UTILIZACIÓN DE OBJETOS .................................................................................................................. 64

DESTRUCCIÓN DE OBJETOS ................................................................................................................ 66 POO EN JAVA: CLASES................................................................................................................... 69 CLASES............................................................................................................................................... 69 DECLARACIÓN DE LA CLASE .............................................................................................................. 70 Superclase de la clase.................................................................................................................... 70 Interfaces de la clase ..................................................................................................................... 70 Modificadores de la clase.............................................................................................................. 71 CUERPO DE LA CLASE. DECLARACIÓN DE ATRIBUTOS ...................................................................... 72 Modificadores................................................................................................................................ 72 Tipo................................................................................................................................................ 74 Nombre variable ............................................................................................................................ 75 CUERPO DE LA CLASE. IMPLEMENTACIÓN DE MÉTODOS ................................................................... 75 Declaración del método................................................................................................................. 75 Declaración de variables............................................................................................................... 80 Implementación del método........................................................................................................... 80 HERENCIA .......................................................................................................................................... 82 Sustituir la implementación de un método..................................................................................... 84 Ampliar la implementación de un método ..................................................................................... 85 Métodos que una clase heredada no puede redefinir .................................................................... 85 Métodos que una clase heredada tiene que redefinir .................................................................... 86 CLASES ABSTRACTAS......................................................................................................................... 86 POO EN JAVA: OTROS CONCEPTOS .......................................................................................... 89 INTRODUCCIÓN .................................................................................................................................. 89 INTERFACES ....................................................................................................................................... 89 Declaración del interfaz ................................................................................................................ 90 Cuerpo del interfaz ........................................................................................................................ 90 EXCEPCIONES..................................................................................................................................... 91 PAQUETES .......................................................................................................................................... 94 PRINCIPALES PAQUETES DEL LENGUAJE JAVA................................................................................... 98 LA CLASE OBJECT ............................................................................................................................ 100 POO EN JAVA: UN EJEMPLO. RESUMEN DE CONCEPTOS................................................ 103 INTRODUCCIÓN ................................................................................................................................ 103 DESCRIPCIÓN DEL PROBLEMA.......................................................................................................... 103 UTILIZANDO EL JDK 1.3.................................................................................................................. 104 CREANDO LAS CLASES ..................................................................................................................... 105 APLICACIONES JAVA ................................................................................................................... 111 INTRODUCCIÓN ................................................................................................................................ 111 INTRODUCCIÓN A VISUAL J++ 6...................................................................................................... 112 INTRODUCCIÓN A JBUILDER 3.5 ...................................................................................................... 117 EL MÉTODO MAIN().......................................................................................................................... 122 LA CLASE SYSTEM ........................................................................................................................... 125 LA CLASE RUNTIME ......................................................................................................................... 128 ALGUNAS CONSIDERACIONES SOBRE VISUAL J++ 6 ....................................................................... 130 CONSIDERACIONES SOBRE JBUILDER .............................................................................................. 135 INTERFACES DE USUARIO EN JAVA: COMPONENTES AWT ........................................... 145 INTRODUCCIÓN ................................................................................................................................ 145 EL AWT (ABSTRACT WINDOW TOOLKIT) ...................................................................................... 145 UTILIZANDO LOS COMPONENTES DEL AWT.................................................................................... 148 Frame........................................................................................................................................... 148 Cursor.......................................................................................................................................... 149 7

MenuBar ...................................................................................................................................... 150 Menu ............................................................................................................................................ 150 MenuItem ..................................................................................................................................... 150 CheckboxMenuItem ..................................................................................................................... 150 Dialog .......................................................................................................................................... 152 FileDialog.................................................................................................................................... 153 Container ..................................................................................................................................... 153 Button........................................................................................................................................... 154 Label ............................................................................................................................................ 156 List, Choice.................................................................................................................................. 157 TextField, TextArea ..................................................................................................................... 158 Checkbox, CheckboxGroup ......................................................................................................... 160 ScrollPane.................................................................................................................................... 162 INTERFACES DE USUARIO EN JAVA: GESTORES DE DISEÑO Y EVENTOS................. 165 INTRODUCCIÓN ................................................................................................................................ 165 GESTORES DE DISEÑO ...................................................................................................................... 165 FlowLayout .................................................................................................................................. 167 BorderLayout............................................................................................................................... 167 CardLayout .................................................................................................................................. 168 GridLayout................................................................................................................................... 170 GridBagLayout ............................................................................................................................ 171 TRATAMIENTO DE EVENTOS EN JAVA .............................................................................................. 173 INTERFACES DE USUARIO EN JAVA: COMPONENTES SWING / CONTENEDORES... 189 INTRODUCCIÓN ................................................................................................................................ 189 JFC Y SWING ................................................................................................................................... 190 COMPONENTES SWING FRENTE A COMPONENTES AWT.................................................................. 191 CONTENEDORES DE ALTO NIVEL...................................................................................................... 192 JFrame......................................................................................................................................... 197 JDialog, JOptionPane ................................................................................................................. 199 JApplet ......................................................................................................................................... 208 CONTENEDORES INTERMEDIOS ........................................................................................................ 208 JPanel .......................................................................................................................................... 209 JTabbedPane ............................................................................................................................... 212 JToolBar ...................................................................................................................................... 216 JLayeredPane .............................................................................................................................. 217 INTERFACES DE USUARIO EN JAVA: COMPONENTES ATÓMICOS DE SWING ......... 223 INTRODUCCIÓN ................................................................................................................................ 223 COMPONENTES ATÓMICOS ............................................................................................................... 223 COMPONENTES PARA OBTENER INFORMACIÓN ............................................................................... 225 JButton......................................................................................................................................... 225 JCheckbox.................................................................................................................................... 227 JRadioButton ............................................................................................................................... 229 JComboBox.................................................................................................................................. 231 JMenu .......................................................................................................................................... 233 JSlider.......................................................................................................................................... 238 COMPONENTES PARA MOSTRAR INFORMACIÓN ............................................................................... 242 JLabel .......................................................................................................................................... 242 JToolTip....................................................................................................................................... 245 JProgressBar ............................................................................................................................... 245 COMPONENTES QUE MUESTRAN INFORMACIÓN ESTRUCTURADA.................................................... 247 JColorChooser............................................................................................................................. 247 JFileChooser................................................................................................................................ 252

INTERFACES DE USUARIO EN JAVA: OTRAS CARACTERÍSTICAS DE SWING........... 257 INTRODUCCIÓN ................................................................................................................................ 257 EL GESTOR DE DISEÑO BOXLAYOUT ............................................................................................... 257 ESTABLECIENDO EL LOOK & FEEL .................................................................................................. 262 APPLETS DE JAVA: INTRODUCCIÓN A LOS APPLETS....................................................... 269 CONCEPTOS PREVIOS ....................................................................................................................... 269 Internet......................................................................................................................................... 269 URLs y direcciones IP ................................................................................................................. 270 Clientes y Servidores Web ........................................................................................................... 271 HTML........................................................................................................................................... 272 HTTP ........................................................................................................................................... 272 INTRODUCCIÓN A LOS APPLETS DE JAVA ......................................................................................... 272 EL CICLO DE VIDA DE LOS APPLETS ................................................................................................. 282 SEGURIDAD EN LOS APPLETS ........................................................................................................... 285 TRUSTED/UNTRUSTED APPLETS ...................................................................................................... 289 DIFERENCIAS ENTRE APPLETS Y APLICACIONES .............................................................................. 289 LA ETIQUETA APPLET ....................................................................................................................... 290 Codebase ..................................................................................................................................... 291 Code............................................................................................................................................. 291 Alt................................................................................................................................................. 291 Name............................................................................................................................................ 291 Width, Height............................................................................................................................... 291 Align............................................................................................................................................. 291 Vspace, Hspace............................................................................................................................ 292 ................................................................................................................................... 292 Etiquetas HTML alternativas ...................................................................................................... 292 APPLETS DE JAVA: UTILIZANDO LOS APPLETS ................................................................. 293 INTERACCIÓN DE LOS APPLETS CON EL NAVEGADOR WEB .............................................................. 293 EVENTOS, GRÁFICOS Y FUENTES EN LOS APPLETS ........................................................................... 303 COMPRESIÓN DE APPLETS ................................................................................................................ 322 COMPONENTES SWING Y APPLETS ................................................................................................... 325 LA CLASE JAPPLET .......................................................................................................................... 327 ASPECTOS AVANZADOS DE JAVA: PROCESOS.................................................................... 331 INTRODUCCIÓN ................................................................................................................................ 331 PROCESOS Y MULTIPROCESO ........................................................................................................... 331 HOLA MUNDO CON HILOS ................................................................................................................ 332 PARALELISMO .................................................................................................................................. 333 UTILIZANDO PROCESOS. EL INTERFAZ RUNNABLE .......................................................................... 337 COORDINANDO LOS PROCESOS ........................................................................................................ 344 Sin derecho preferente................................................................................................................. 344 Con derecho preferente ............................................................................................................... 344 ASPECTOS AVANZADOS DE JAVA: CANALES Y SOCKETS............................................... 345 INTRODUCCIÓN A LOS CANALES ...................................................................................................... 345 CANALES ESTÁNDAR DE ENTRADA/SALIDA ..................................................................................... 346 CANALES DE JAVA.IO ....................................................................................................................... 348 CANALES DE TRANSMISIÓN (DATA SINK STREAMS) .......................................................................... 350 CANALES DE PROCESO (PROCESSING STREAMS)............................................................................... 352 Canales de Filtrado ..................................................................................................................... 353 Canales de buffer......................................................................................................................... 353 Canal de Concatenación.............................................................................................................. 354 Canales de conversión de tipos ................................................................................................... 354 9

Serialización de Objetos .............................................................................................................. 356 Canal Contador de Líneas........................................................................................................... 357 Canales de impresión .................................................................................................................. 358 Canales de vuelta atrás ............................................................................................................... 359 APLICACIONES CLIENTE/SERVIDOR EN JAVA ................................................................................... 359

Introducción a la POO ¿Qué es la POO? Las siglas POO se corresponden con Programación Orientada a Objetos, aunque muchas veces las podemos encontrar escritas en inglés OOP (Object Oriented Programming). En este primer capítulo de este curso vamos a tratar de explicar de forma sencilla los principales conceptos y términos que se utilizan dentro de este tipo de programación, es decir, dentro de la Programación Orientada a Objetos. No vamos a entrar en sesudas divagaciones filosóficas respecto a la POO, sino que vamos a definir lo más claramente posible cada uno de los elementos clave que aparecen en la POO para después poder aplicarlos al lenguaje que nos ocupa, es decir, al lenguaje Java. Este tema es muy necesario debido a que el lenguaje Java, como veremos en el siguiente capítulo, es un lenguaje que se basa en la Programación Orientada a Objetos, por lo tanto para conocer el lenguaje Java, es necesario conocer la Programación Orientada a Objetos. La Programación Orientada a Objetos trata de utilizar una visión real del mundo dentro de nuestros programas. La visión que se tiene del mundo dentro de la POO es que se encuentra formado por objetos. Para comprender bien la POO debemos olvidar un poco la Programación Estructurada, que si nos fijamos bien es algo artificial, la POO es una forma de abordar los problemas más natural. Aquí natural significa más en contacto con el mundo real que nos rodea, de esta forma si queremos resolver un problema determinado, debemos identificar cada una de las partes del problema con objetos presentes en el mundo real.

Programación en Java

© Grupo EIDOS

En esta definición de POO ya estamos haciendo referencia al elemento clave de la misma: el objeto. El objeto va a ser la modelización de los objetos que nos encontramos en el mundo real, estos objetos los vamos a utilizar en nuestros programas para dar la solución al problema que nos ocupe en cada caso.

Objetos Como ya hemos adelantado un objeto es la pieza básica de la POO, es una representación o modelización de un objeto real perteneciente a nuestro mundo, por ejemplo, podemos tener un objeto perro que represente a un perro dentro de nuestra realidad, o bien un objeto factura, cliente o pedido. Los objetos en la vida real tienen todos, dos características: estado y comportamiento. El estado de un objeto viene definido por una serie de parámetros que lo definen y que lo diferencian de objetos del mismo tipo. En el caso de tener un objeto perro, su estado estaría definido por su raza, color de pelo, tamaño, etc. Y el comportamiento viene definido por las acciones que pueden realizar los objetos, por ejemplo, en el caso del perro su comportamiento sería: saltar, correr, ladrar, etc. El comportamiento permite distinguir a objetos de distinto tipo, así por ejemplo el objeto perro tendrá un comportamiento distinto a un objeto gato. Si tomamos un ejemplo que tiene que ver más con el mundo de la informática se pueden ver más claros estos dos conceptos. Si tenemos un objeto pantalla que representa la pantalla de nuestro ordenador, el estado de la misma estaría definido por los siguientes parámetros: encendida o apagada, tamaño, resolución, número de colores, etc.; y su comportamiento podría ser: imprimir, encender, apagar, etc. Los parámetros o variables que definen el estado de un objeto se denominan atributos o variables miembro y las acciones que pueden realizar los objetos se denominan métodos o funciones miembro, y para indicar variables miembro y funciones miembro se utiliza el término general miembro. Si lo comparamos con la programación estructurada podríamos hacer la siguiente aproximación: los atributos o variables miembro serían variables y los métodos o funciones miembro procedimientos y funciones. A partir de ahora y a lo largo de todo el presente curso vamos a utilizar únicamente la nomenclatura de atributos y métodos. Los atributos de un objeto deben encontrarse ocultos al resto de los objetos, es decir, no se va a poder acceder directamente a los atributos de un objeto para modificar su estado o consultarlo. Para acceder a los atributos de un objeto se deben utilizar métodos. Es decir, los métodos exponen toda la funcionalidad del objeto, mientras que los detalles del estado interno del objeto permanecen ocultos. Incluso algunos métodos también pueden permanecer ocultos. El hecho de ocultar la implementación interna de un objeto, es decir, como está construido y de que se compone se denomina encapsulación. La encapsulación es uno de los beneficios y particularidades del paradigma de la Programación Orientada a Objetos. Normalmente un objeto ofrece una parte pública que será utilizada por otros objetos para interactuar entre sí, pero también permanece una parte oculta para encapsular los detalles de la implementación del objeto. Ya se ha dicho que un objeto está compuesto de atributos y métodos. Como la caja negra de un avión, el objeto recubre la información que almacena y solamente podemos obtener la información e indicarle que realiza acciones por medio de lo que comúnmente se denomina interfaz del objeto, que estará constituido por los métodos públicos. 12

© Grupo EIDOS

1. Introducción a la POO

Los datos y la implementación queda oculta a los demás objetos que interaccionan en el programa, lo que favorece enormemente la protección de los datos y las estructuras internas contra las modificaciones externas al objeto. De este modo es mucho más sencillo localizar errores en los programas puesto que cada objeto está altamente especializado, y sólo se encarga de su tarea. Como se puede observar, esto consigue una mayor modularidad, que facilita además el diseño en equipo de programas y la reutilización de clases (componentes) creados por otros desarrolladores. Hemos indicado que la encapsulación es un beneficio que nos aporta la POO, es un beneficio porque permite abstraernos de la utilización de los objetos, es decir, a mí me interesa realizar una determinada tarea con un objeto (por ejemplo imprimir una pantalla o rellenar una factura), pero a mí no me interesa como realiza este proceso internamente el objeto que estoy utilizando. En este momento entra en juego otro concepto importante de la POO y que es la abstracción. La abstracción indica la capacidad de ignorar determinados aspectos de la realidad con el fin de facilitar la realización de una tarea. Nos permite ignorar aquellos aspectos de la realidad que no intervienen en el problema que deseamos abordar, y también nos permite ignorar los aspectos de implementación de los objetos en los pasos iniciales, con lo cual sólo necesitamos conocer qué es lo que hace un objeto, y no cómo lo hace, para definir un objeto y establecer las relaciones de éste con otros objetos. Un objeto lo podríamos representar como dos circunferencias, una interna que permanece oculta al mundo exterior y que contendría todos los detalles de la implementación del objeto, y otra circunferencia concéntrica externa, que representa lo que el objeto muestra al mundo exterior y le permite utilizar para interactuar con él. En la Figura 1 se puede ver dicha representación. La encapsulación ofrecida a través de objetos tienen varios beneficios, entre los que destacan la modularidad y la ocultación de la información. Mediante la modularidad podemos escribir código de manera independiente de cómo se encuentren construidos los diferentes objetos que vamos a utilizar. Y ocultando la información se permite realizar cambios en el código interno de los objetos sin que afecte a otros objetos que los utilicen o dependan de ellos. No es necesario entender la implementación interna de un objeto para poder utilizarlo.

Figura 1

Mensajes Los mensajes son la forma que tienen de comunicarse distintos objetos entre sí. Un objeto por sí sólo no es demasiado útil, sino que se suele utilizar dentro de una aplicación o programa que utiliza otros objetos. El comportamiento de un objeto está reflejado en los mensajes a los que dicho objeto puede responder. Representan las acciones que un determinado objeto puede realizar. 13

Programación en Java

© Grupo EIDOS

Un mensaje enviado a un objeto representa la invocación de un determinado método sobre dicho objeto, es decir, la ejecución de una operación sobre el objeto. Es la manera en la que un objeto utiliza a otro, el modo en el que dos objetos se comunican, ya que la ejecución de ese método retornará el estado del objeto invocado o lo modificará. Los mensajes se utilizan para que distintos objetos puedan interactuar entre sí y den lugar a una funcionalidad más compleja que la que ofrecen por separado. Un objeto lanzará o enviará un mensaje a otro objeto si necesita utilizar un método del segundo objeto. De esta forma si el objeto A quiere utilizar un método del objeto B, le enviará un mensaje al objeto A. Para enviar un mensaje se necesitan tres elementos: el objeto al que se le va a enviar el mensaje, el nombre del método que se debe ejecutar y los parámetros necesarios para el método en cuestión.

Clases Una clase es un molde o prototipo que define un tipo de objeto determinado. Una clase define los atributos y métodos que va a poseer un objeto. Mediante las clases podremos crear o instanciar objetos de un mismo tipo, estos objetos se distinguirán unos de otros a través de su estado, es decir, el valor de sus atributos. La clase la vamos a utilizar para definir la estructura de un objeto, es decir, estado (atributos) y comportamiento (métodos). La clase es un concepto abstracto que generalmente no se va a utilizar directamente en nuestros programas o aplicaciones. Lo que vamos a utilizar van a ser objetos concretos que son instancias de una clase determinada. La clase es algo genérico y abstracto, es similar a una idea. Cuando decimos piensa en un coche todos tenemos en mente la idea general de un coche, con puertas, ruedas, un volante, etc., sin embargo cuando decimos "ese coche que está aparcado ahí fuera", ya se trata de un coche determinado, con una matrícula, de un color, con un determinado número de puertas, y que podemos tocar y utilizar si es necesario. Sin embargo como ya hemos dicho la clase es la idea que define al objeto concreto. Un ejemplo que se suele utilizar para diferenciar y relacionar clases y objetos es el ejemplo del molde de galletas. El molde para hacer galletas sería una clase, y las galletas que hacemos a partir de ese molde ya son objetos concretos creados a partir de las características definidas por el molde. Una vez implementada una clase podremos realizar instancias de la misma para crear objetos que pertenezcan a esa clase. Las clases ofrecen el beneficio de la reutilización, utilizaremos la misma clase para crear distintos objetos. Y luego veremos que una vez que tenemos una clase podremos aprovecharla heredando de ella para complicarla o especializarla para una labor concreta. Si comparamos las clases y objetos de la POO con la programación estructurada tradicional, se puede decir que las clases son los tipos de datos y los objetos las variables de esos tipos de datos. De esta forma si tenemos el tipo entero, en la POO diríamos que es la clase entero, y si tenemos una variable de tipo entero, en la POO diríamos que tenemos un objeto de la clase entero.

Herencia La herencia es un mecanismo mediante el cual podemos reutilizar clases ya definidas. Es decir, si tenemos una clase botón que define un tipo de objeto que se corresponde con un botón que tiene un 14

© Grupo EIDOS

1. Introducción a la POO

texto, que se puede pulsar, etc., si queremos definir una nueva clase llamada botón de color, no tenemos que rescribir todo el código y crear una clase completamente nueva, sino lo que haremos será heredar de la clase botón, utilizar lo que nos ofrezca esta clase y añadirle lo que sea necesario para la nueva funcionalidad deseada. La herencia dentro de la POO es un mecanismo fundamental que se puede definir también como una transmisión de las características de padres a hijos. Entendiendo aquí características como métodos y atributos de una clase. La clase hija puede añadir atributos, métodos y redefinir los métodos de la clase padre. Podemos ver la herencia como una sucesiva especialización de las clases. La clase de la que se hereda se suele denominar clase padre o superclase, y la clase que hereda se denomina clase hija o subclase. El mecanismo de herencia es muy potente, puesto que nos permite agregar funcionalidades nuevas a una clase ya existente, reutilizando todo el código que ya se tenga disponible de la clase padre, es decir, se heredarán sus atributos y métodos, como ya habíamos indicado con anterioridad. En las clases hijas podemos redefinir el comportamiento de la clase padre. Para verificar que la herencia entre dos clases es correcta y coherente, debemos hacernos la pregunta de "¿es un?" o "¿es un tipo de?". Por ejemplo, en el caso que comentábamos del botón, tenemos una clase BotonColor que hereda de la clase Boton. Esta herencia contesta perfectamente a la pregunta definida antes: ¿un botón de color es un botón?, evidentemente sí. Mediante el mecanismo de herencia podemos definir superclases denominadas clases abstractas que definen comportamientos genéricos. De esta clase pueden heredar otras clases que ya implementan de forma más concreta estos comportamientos. De esta forma podremos crear jerarquías de clases. Así por ejemplo podemos tener una clase bicicleta, que será más o menos genérica. De esta clase pueden heredar la clase bicicleta de montaña, bicicleta de carreras y tandem, que ya ofrecen una clase más especializada que la clase padre. Los métodos que se heredan de la clase padre no tienen porqué utilizarse sin realizar ningún cambio, se puede llevar a cabo lo que se denomina la sobrescritura de métodos. Podemos heredar un método de la clase padre, pero en la clase hija le podemos dar una implementación diferente para que se adecue a la nueva clase. La herencia puede ser simple si la clase hija hereda de una única clase padre o múltiple si hereda de varias clases padre, más adelante veremos que el tipo de herencia que soporta Java es una herencia simple. Algunas veces la herencia múltiple puede llegar a ser confusa.

Métodos Como ya hemos dicho anteriormente los métodos son las acciones que se pueden realizar con los objetos. También se podría definir un método como la implementación de un mensaje, al fin y al cabo, un mensaje es la llamada o invocación de un método de un objeto. Existen dos métodos especiales dentro de la POO que se denominan constructor y destructor. El método constructor se ejecuta automáticamente cada vez que se crea un objeto de la clase en cuestión, sobre el objeto que acaba de crearse, inmediatamente después de haberse asignado memoria a dicho objeto. Algunos lenguajes proporcionan un constructor por defecto, pero generalmente lo correcto es que lo defina el diseñador de la clase y que en él se lleven a cabo las inicializaciones y todas aquellas operaciones que se necesiten para poder usar el objeto. 15

Programación en Java

© Grupo EIDOS

El método destructor se invoca automáticamente inmediatamente antes de liberar la memoria del objeto en cuestión, o lo que es lo mismo, antes de que se salga del ámbito de la declaración del objeto, por lo que se ha de emplear para que la destrucción del objeto se efectúe correctamente y contendrá operaciones tales como liberación de memoria asignada dinámicamente dependiente del objeto, grabación de todos o parte de los atributos del objeto en un fichero o base de datos y operaciones similares.

Polimorfismo El término polimorfismo expresa la posibilidad de que el mismo mensaje, enviado a objetos distintos, ejecute métodos distintos. Esto significa que podemos definir dentro de dos clases distintas dos operaciones con el mismo nombre y aspecto externo, pero con distintas implementaciones para cada clase. En el momento de emplear estas operaciones, el lenguaje es capaz de ejecutar el código correspondiente dependiendo de la clase del objeto sobre el que se ejecuta la operación. Esto permite definir un interfaz común, un aspecto externo idéntico, para una serie de clases. De esta forma podemos definir un método suma() para la clase Enteros y otro método suma() para la clase Matrices. El mensaje será el mismo, pero la implementación de los métodos será distinta ya que no es lo mismo sumar enteros que matrices.

Sobrecarga La sobrecarga de métodos se produce cuando una clase tiene métodos con el mismo nombre pero que difieren o bien en el número o en el tipo de los parámetros que reciben dichos métodos. Un ejemplo de sobrecarga los podemos tener en el método imprimir(), mediante este método vamos a imprimir en pantalla y realizar un salto de línea. Este método acepta como parámetro una variable de tipo entero o una variable de tipo cadena de caracteres, incluso si no indicamos ningún parámetro realizaría un salto de línea.

La ley de Demeter En lo que respecta a la implementación de métodos de una clase, existe una ley que nos da una serie de pautas para realizar una Programación Orientada a Objetos correcta, esta ley es la Ley de Demeter. La Ley de Demeter, enunciada por Karl Lieberherr, determina el acceso o visibilidad de los objetos en la implantación de un método, y se rige por el siguiente principio: en la implantación de un método se puede tener acceso a los siguientes objetos: •

Atributos de su clase.



Los parámetros que se pasan al método.



Objetos temporales creados dentro del método.

Existen dos formas de la Ley de Demeter, la flexible y la estricta, la flexible permite acceder a los atributos de la clase padre o superclase y la estricta indica que este acceso se debe lograr mediante la utilización de métodos de acceso de la clase padre. 16

© Grupo EIDOS

1. Introducción a la POO

Modelo de objetos El modelo de objetos es un conjunto de principios que se deben dar para que se puedan modelar objetos computacionales (objetos dentro de nuestro código y programas) a partir de objetos de la realidad de manera que éstos reflejen los posibles comportamientos presentes en la realidad y compongan un modelo computacional válido. Es decir, definido e identificado un problema se trata de realizar una representación lógica de los objetos que forman parte del problema en el mundo real, de esta forma podremos utilizar en nuestro programa estos objetos para dar la solución a través de nuestro código. El modelo de objetos que definen un problema de la realidad se basa en los siguientes principios: abstracción, encapsulación, herencia y polimorfismo. Todos estos conceptos básicos de la POO ya han sido discutidos en este tema en mayor o menor medida. Por lo tanto antes de empezar a construir un programa para una tarea específica, es necesario construir y diseñar su modelo de objetos. Existen diversas técnicas de modelización, pero el objetivo de este curso no es el de explicarlas, así que no entraremos en más detalles.

Relaciones entre clases Una clase por sí sola no ofrece una funcionalidad demasiado interesante, como ya veremos a lo largo del curso, el lenguaje Java se encuentra formado por un gran número de clases que forman parte de una compleja y completa jerarquía. Cada una de las clases está especializada en una función o tarea específica, es decir, se da una gran modularidad, cada clase tiene su cometido. Por lo tanto para ofrecer una mayor funcionalidad y realizar tareas más complejas es necesario que exista una relación entre distintas clases. Un ejemplo podría ser las piezas del motor de un coche. Las piezas por si solas no realizan ninguna tarea de importancia, cuando realmente se saca provecho de ellas es cuando se relacionan entre sí y se construye con ellas un motor. A su vez este motor puede ser incorporado dentro de un coche, que estará compuesto a su vez de más objetos o piezas. Como vemos la correspondencia entre los objetos del mundo real y los objetos del mundo computacional es bastante obvia en algunos casos. Básicamente una clase se puede relacionar con otra de tres formas diferentes. Las relaciones que podemos distinguir son: •

Relación de composición: una clase puede estar compuesta de otras clases. Esto se consigue implementando los atributos de la clase como objetos de otra clase. Una clase hace uso de otra a través de sus atributos, una clase se encuentra formada por varias clases. Por ejemplo la clase Coche tiene atributos que son de la clase Puerta, Rueda, Motor, etc.



Relación de uso: una clase se relaciona con otra a través de los mensajes que le envía. Esto se consigue pasándose una instancia de la clase como uno de los parámetros del método invocado por el mensaje. Es decir, si tenemos la clase Pantalla con el método dibujar() y queremos dibujar un objeto de la clase Rectangulo, deberíamos realizar lo siguiente objPantalla.dibujar(Rectangulo), es decir, el parámetro que se le pasa al método dibujar() de la clase Pantalla es un objeto de la clase Rectangulo.



Relación de herencia: este tipo de relación entre clases ya la conocemos y consiste en que una clase hija hereda de una clase padre o superclase pudiendo utilizar así toda la funcionalidad ofrecida por la clase padre y añadir nuevas funcionalidades. En esta forma de relación se 17

Programación en Java

© Grupo EIDOS

consigue la reutilización del código y una progresiva especialización a través de una jerarquía de clases.

Ventajas e inconvenientes de la POO En este apartado vamos a comentar que ventajas nos ofrece el paradigma de la POO, también mostraremos algunas de sus desventajas. Como ventajas o aportaciones podemos destacar las siguientes: •

Facilita la reutilización del software. A través de la herencia se nos permite utilizar en un objeto las operaciones implementadas para otros sin esfuerzo adicional. Por otro lado la encapsulación nos facilita el uso de objetos que no hemos definido ni implementado. Se pude considerar que la encapsulación y el polimorfismo son las herramientas más potentes del paradigma de la POO.



Facilita la construcción de programas portables. Es posible diseñar una capa de objetos que se comunique con la máquina o el sistema operativo, y sobre ésta los objetos que dan funcionalidad a la aplicación. Una migración a otra arquitectura sólo requerirá cambios en dicha capa, y la encapsulación nos garantiza que los cambios se van a limitar a esos objetos. Java refuerza más esta característica de la portabilidad, ya que, como veremos en el próximo capítulo, el lenguaje Java es independiente de la plataforma en la que se ejecuta.



Facilita el mantenimiento. El encapsulamiento nos garantiza que las modificaciones realizadas en un objeto tendrán un efecto limitado. Si un elemento de datos se accede directamente y en un momento dado cambia de tipo o formato, habrá que localizar todos los puntos en los que se accede a dicho elemento y modificarlos en consecuencia. Si este elemento de datos está encapsulado en un objeto y siempre es accedido mediante las operaciones disponibles, un cambio como el indicado se limitará al objeto, del que sólo habrá que cambiar el elemento de datos y las operaciones del objeto que lo utilizan. Lo recomendable es desconocer la implementación interna del objeto, nosotros necesitaremos utilizar un objeto que ofrece una serie de funcionalidades, pero no nos interesa de que forma nos ofrece las mismas.



Provoca que las tareas de análisis, diseño e implementación sean más intuitivas, ya que se manejan objetos, concepto con el que todos estamos familiarizados, y estructuradas, ya que podemos asignar las tareas de diseño e implementación en el ámbito de objetos. Se debe recordar que los objetos en nuestros diseños van a representar objetos presentes en el mundo real.

No todos son beneficios, la POO ofrece también una serie de desventajas, aunque más que desventajas o inconvenientes podemos decir que presenta una serie de dificultades, las cuales se comentan a continuación:

18



Curvas de aprendizaje largas, debido principalmente a que implica un cambio mentalidad, y no sólo el aprender un nuevo lenguaje.



Dificultad en determinar las características de un objeto. Debido a que un objeto no se define aisladamente, sino que depende de las relaciones con otros objetos, el establecimiento de nuevas relaciones puede implicar un cambio en la definición del objeto y viceversa. Por todo ello es conveniente iterar, esto es, repetir el proceso de definición de objetos y de identificación de relaciones, tantas veces como sean necesarias para alcanzar un modelo estable. En muchos casos resulta complicado llegar a un modelo de objetos definitivo con el que se pueda abordar el problema planteado de forma completa.

© Grupo EIDOS



1. Introducción a la POO

Jerarquías de herencia complejas: en muchos casos se tiende a utilizar de forma desmedida el mecanismo de herencia, ofreciendo en algunos casos unas jerarquías de herencia difíciles de seguir y abordar.

Un ejemplo sencillo No hace falta decir que el tema que nos ocupa es un tema eminentemente teórico, pero aun así vamos a incluir un breve y sencillo ejemplo con el que se pretende mostrar de forma sencilla como se puede construir un modelo de objetos, identificando los objetos que intervienen en el problema a resolver, definiendo los atributos de la clase, los métodos, relaciones entre las diferentes clases, etc. En este caso vamos a abandonar los típicos ejemplos de la clase Coche y similares y vamos a mostrar un ejemplo más lúdico. En nuestro ejemplo vamos a tener la clase VideoJuego, es decir, vamos a crear el juego de matamarcianos conocido por todos. No vamos a profundizar demasiado en todos los atributos y métodos de las clases, sino que vamos a mostrar únicamente los más relevantes. En el primer paso vamos a identificar las clases necesarias para abordar nuestro problema, en este caso, la creación de un juego de matamarcianos. Primero tengamos en cuenta las especificaciones: •

En el juego tenemos dos tipos de enemigos: marcianos y venusianos.



El protagonista del juego es un terrícola.



El terrícola dispone de un arma para defenderse de los enemigos, un lanza cohetes.

Como se puede observar no vamos a tener demasiadas complicaciones a la hora definir el modelo de objetos de nuestro programa. Se pueden distinguir seis clases: VideoJuego, Enemigo, Marciano, Venusiano, Terricola y LanzaCohetes. La clase VideoJuego sería la clase principal y contendría al resto de las clases. Por lo tanto entre la clase VideoJuego y el resto de las clases existe una relación de composición. Esta clase tendría como atributos posibles: Enemigos, Heroes y Armas; y como métodos: comenzarPartida(), interrumpirPartida(), reanudarPartida() y finalizarPartida(), la finalidad de cada uno de ellos está bastante clara. La clase Enemigo en realidad va a ser una clase abstracta, ya que no vamos a instanciar objetos de esta clase. La clase Enemigo va a ser la clase padre de la clase Marciano y Venusiano, y lo que se consigue con esta clase es agrupar todo el comportamiento que es común a los enemigos que aparecen en el juego. Esta clase tiene los siguientes atributos: Color, NumeroOjos y NumeroPiernas. Estos atributos serán comunes a las clases Marciano y Venusiano. Existe una relación de herencia entre la clase Enemigo y las clases Marciano y Venusiano. La clase Enemigo podría tener los siguientes métodos: mover(), atacar() y disparar(). Estos métodos también serán heredados por la clase hijas mencionadas. Las clases hijas tienen dos opciones, si la implementación de los métodos anteriores que realiza la clase padre es la adecuada, los heredarán y utilizarán sin más, pero si las clases hijas quieren realizar modificaciones o ampliaciones sobre los métodos heredados deberán implementarlos y por lo tanto sobrescribirlos aportando un comportamiento diferente.

19

Programación en Java

© Grupo EIDOS

Las clases Marciano y Venusiano pueden además de sobrescribir los métodos heredados de la clase Enemigo, aportar nuevos métodos y nuevos atributos. La clase Marciano añade el atributo Visible, es decir, nuestro amigo tiene la capacidad de hacerse invisible, y la clase Venusiano añade el atributo NumeroCabezas. La clase Terricola representa al héroe de nuestro juego y tiene los atributos: NumeroVidas y Municion, ambos requieren poca explicación. Esta clase implementa el método disparar(), que recibe como parámetro un objeto de la clase LanzaCohetes, la relación entre ambas clases es una relación de uso. La clase LanzaCohetes que representa el arma que va a utilizar la clase Terricola y tienen el atributo NumeroCohetes, y posee el método lanzarCohete(). Podríamos entrar en más detalles e ir afinando más en la identificación de objetos, podríamos definir también la clase Cohete, que representaría a los cohetes lanzados por una instancia de la clase LanzaCohetes. Pero no vamos a entrar en más detalles y vamos a dejar de definir más clases, quedándonos con las vistas hasta ahora. En la Figura 2 se trata de mostrar un esquema de todas las clases que implementan el problema propuesto y la relación existente entre cada una de ellas. Cada clase se representa por una circunferencia y las relaciones existentes mediante flechas.

Figura 2

20

Introducción al lenguaje Java Introducción En este capítulo vamos a comentar las características principales del lenguaje Java, también comentaremos algunos conceptos interesantes que aporta el lenguaje. Como su nombre indica este capítulo es introductorio, por lo tanto algunos de los conceptos los explicaremos de forma breve y en los sucesivos capítulos profundizaremos en los temas más interesantes. Por lo tanto en este capítulo todavía no vamos a ver ni una sola línea de código en Java, antes debemos tener claro una serie de puntos acerca del lenguaje. También comentaremos tres herramientas de desarrollo que podemos utilizar para realizar nuestros desarrollos en Java, se trata de las siguientes: •

JDK (Java Development Kit): herramienta ofrecida por Sun MicroSystems, implementa la versión última y oficial de Java.



Microsoft Visual J++ 6.0: incluida dentro de Visual Studio 6, ofrece la versión 1.1 de Java.



Borland JBuilder 3.5: potente entorno de desarrollo que implementa la versión de Java perteneciente a Java 2.

Que el lector no tema por las distintas versiones de Java, en el apartado correspondiente se aclaran las distintas versiones existentes.

Programación en Java

© Grupo EIDOS

Breve historia del lenguaje Los orígenes de Java se remontan al año 1990, cuando un equipo de la compañía Sun Microsystems investigaba, bajo la dirección del ingeniero James Gosling, en el diseño y elaboración de software para pequeños dispositivos electrónicos de consumo. En un primer momento se pensó en la utilización de lenguajes de programación como C o C++, pero para poder compilar un programa en estos lenguajes es preciso adaptarlo a las características de la plataforma en la que debe funcionar, esta situación constituía un gran inconveniente para las compañías dedicadas a la construcción de dispositivos electrónicos, pues cada pocas semanas aparecen en el mercado versiones más potentes y baratas de los chips utilizados, y por lo tanto, el software que se había diseñado para un chip determinado debía modificarse y adaptarse para explotar las características de los chips de reciente aparición. Se hace patente la necesidad de introducir un nuevo lenguaje de programación, que permita desarrollar programas independientes del tipo de plataforma. Los dispositivos que se pretenden fabricar son calculadoras, relojes, equipos de música, cafeteras, etc.…, que no tienen una gran capacidad computacional, por lo que el nuevo lenguaje debe ser capaz de generar programas pequeños y rápidos, además de ser fiables y robustos. La primera versión de este nuevo lenguaje se denominó Oak (roble), pero más tarde Sun descubrió que este nombre estaba ya registrado, y lo tuvieron que cambiar, el nuevo nombre fue Java (una de las versiones sobre el significado del nombre es que Java es un término popularmente empleado en California para designar café de buena calidad). A comienzos de 1993 aparecieron nuevas herramientas gráficas para facilitar la comunicación y navegación por Internet, se concibió la idea de aplicar técnicas de documentos con enlaces de tipo hipertextual para facilitar la navegación por Internet, y se desarrolló el primer browser (navegador Web o visualizador) de lo que se comenzó a denominar World Wide Web. Esta herramienta era denominada Mosaic. El equipo de James Gosling se planteó como objetivo la utilización de Java como lenguaje en el que escribir aplicaciones que pudiesen funcionar a través de Internet. Como resultado de su trabajo se desarrolló un nuevo navegador completamente escrito en Java, llamado HotJava. Este navegador permitía la integración de pequeñas aplicaciones en el interior de las páginas Web. El desarrollo de HotJava hizo patente que las características de Java se adaptan perfectamente a las peculiaridades de Internet. A partir de su primera y sencilla versión Java ha ido creciendo progresiva y espectacularmente para pasar a ofrecer un potente y complejo lenguaje con el que se pueden abarcar una gran cantidad de campos.

Descripción del lenguaje En este apartado vamos a resaltar las características principales del lenguaje Java y comentaremos una serie de términos y conceptos que se hacen indispensables para comprender lo que nos ofrece el lenguaje de programación que nos ocupa. Java es un lenguaje de programación orientado a objetos de propósito general, de ahí la necesidad de estudiar el capítulo anterior dedicado íntegramente a la Programación Orientada a Objetos. Según indican desde Sun Microsystems, Java es un lenguaje creado para realizar una programación en Internet rápida y fácil, rápida y fácil si ya poseemos conocimientos previos de C++ y de programación 22

© Grupo EIDOS

2. Introducción al lenguaje Java

orientada a objetos. Por lo tanto si el lector ya ha programado en C++ la curva de aprendizaje del lenguaje Java se suavizará considerablemente. Aunque no se debe considerar a Java como una herramienta exclusiva y únicamente para la programación en Internet, ya que su uso, lejos de restringirse a este campo, puede y debe extenderse a problemas y situaciones de todo tipo, por lo tanto para evitar confusiones el lenguaje Java se podría definir mejor de la siguiente forma: Java es un lenguaje de programación orientado a objetos, de propósito general que presenta características especiales que lo hacen idóneo para su uso en Internet. Una de estas características son los applets. Un applet es un programa dinámico e interactivo que se puede ejecutar dentro de una página Web que se carga en un navegador Web, y otra característica para la utilización de Java en Internet son los servlets. Un servlets es una aplicación Java que se ejecuta sobre un servidor y que atiende una serie de peticiones realizadas desde un cliente que será un navegador Web. A diferencia de los applets los servlets no presentan interfaz gráfico. Java toma prestadas características y sintaxis de diferentes lenguajes de programación. La sintaxis básica de Java está sacada del lenguaje C/C++ aunque al contrario de estos lenguajes Java es un lenguaje fuertemente tipado. De Smalltalk Java toma conceptos como el recolector de basura (garbage collector, concepto que se explicará más adelante) y un sólido modelo de orientación a objetos, como iremos comprobando a lo largo del presente curso. De Objective-C, Java toma el concepto de interfaz, en el capítulo correspondiente veremos como define e implementa Java los interfaces. El mecanismo de herencia que posee Java, se denomina herencia simple, esto quiere decir que cada clase Java sólo puede tener una superclase o clase padre. En otros lenguajes de programación como C++, las clases pueden heredar de diferentes superclases, esto se denomina herencia múltiple, la cual no emplea Java. Pero Java posee un mecanismo que le permite simular la herencia múltiple, este mecanismo se consigue a través de los interfaces. Como ya adelantábamos, el concepto de interfaz lo toma Java del lenguaje Objective-C. Un interfaz es una colección de nombres de métodos sin definiciones reales que indican que una clase tiene un conjunto de comportamientos, además de los que la clase hereda de sus superclases. Por lo tanto un interfaz es una lista de métodos sin ninguna implementación, la palabra reservada implements es utilizada en la declaración de una clase para indicar que implementa los métodos de un interfaz determinado. Más tarde, en el curso, retomaremos el concepto de interfaz. Al ser un lenguaje de Programación Orientada a Objetos, la unidad básica dentro de la programación en Java va a ser la clase y el objeto. Java está compuesto por un gran número de clases que se agrupan y clasifican en paquetes, en el capítulo dedicado a la POO con Java veremos como se estructura la jerarquía de clases que presenta el lenguaje. Pero a pesar de estar compuesto de clases, en Java nos encontramos también con una serie de tipos de datos predefinidos similares a C o C++, estos tipos, denominados tipos primitivos son: int, byte, short, char, long, boolean, float y double. Por lo tanto en Java podremos definir variables de estos tipos de datos, en este caso se empleará la denominación variable en lugar de objeto, ya que los tipos primitivos no son clases. En el próximo capítulo volveremos a retomar los tipos primitivos. Java presenta una completa y compleja jerarquía de clases, esto le hace un lenguaje muy potente, ya que para cada tarea a realizar existe una clase determinada que se encuentra especializada para realizar una función específica. Se puede considerar que por un lado tenemos el lenguaje Java, que es con el que escribimos nuestras clases y compilamos, y por otro se encuentra la Máquina Virtual de Java, JVM (Java Virtual 23

Programación en Java

© Grupo EIDOS

Machine). Para garantizar que los programas son independientes de la plataforma (capacidad del programa de trasladarse con facilidad de un sistema computacional a otro) hay una sola arquitectura a la que todos los programas Java son compilados, es decir, cuando se compila un programa Java en una plataforma Windows/Intel, se obtiene la misma salida compilada que en un sistema Macintosh o Unix. El compilador compila no a una plataforma determinada, sino a una plataforma abstracta llamada Máquina Virtual de Java. La especificación de la Máquina Virtual de Java define la JVM como: una máquina imaginaria que se implementa emulando por software una máquina real. El código para la Máquina Virtual de Java se almacena en ficheros .class, cada uno de los cuales contiene al menos el código de una clase pública, en el capítulo dedicado a la POO con Java comentaremos en detalle la visibilidad de las clases (públicas o privadas). Por lo tanto, cuando se escribe una aplicación Java o un applet Java (después veremos estos dos tipos de programas que se pueden construir en Java), se está escribiendo un programa diseñado para ejecutarse en la Máquina Virtual de Java. La Máquina Virtual de Java requiere un código binario especial para ejecutar los programas Java, este código no debe tener instrucciones relacionadas específicamente con la plataforma. Los archivos binarios Java, que se obtienen al compilar el código fuente, son independientes de la plataforma y pueden ejecutarse en múltiples plataformas sin necesidad de volver a compilar el fuente. Los archivos binarios Java se encuentran en una forma especial llamada bytecode, que son un conjunto de instrucciones muy parecidas al código máquina, pero que no son específicas para ningún procesador. El compilador Java toma el programa Java y en lugar de generar código máquina específico para los archivos fuente, genera un bytecode. Para ejecutar un programa Java, se debe ejecutar un programa llamado intérprete de bytecode, el cual a su vez ejecuta el programa Java deseado. En el caso de los applets el intérprete se encuentra integrado en el navegador Web con capacidad para Java y es ejecutado automáticamente. El concepto de independencia de la plataforma es ilustrado en la Figura 3.

Figura 3

24

© Grupo EIDOS

2. Introducción al lenguaje Java

La desventaja de utilizar los bytecodes es la velocidad, estos programas tienen una menor velocidad de ejecución, ya que previamente a ejecutarse sobre el sistema, deben ser procesados por el intérprete. Aunque según van apareciendo nuevas versiones del lenguaje Java la velocidad de ejecución se va mejorando, se alcanzará la máxima velocidad y eficacia cuando aparezcan los chips Java. Se trata de una versión hardware del intérprete Java presente en los programas navegadores con capacidad para este lenguaje, es decir, es una implementación hardware de la Máquina Virtual de Java. Estos chips serán los encargados de traducir el código Java sobre la marcha, por lo tanto no será necesaria la etapa intermedia de interpretación de los bytecodes, como se veía en la figura, con lo que se aumentará de forma considerable la velocidad de ejecución. En un principio Sun MicroSystems tiene pensado comercializar estos chips en una especie de tarjeta, que se insertará en un slot del ordenador. Una polémica entorno a Java se produjo cuando Microsoft lanzó su versión del lenguaje, a través de su herramienta de desarrollo Visual J++. Desde esta herramienta corremos el peligro de generar código Java que sí sea dependiente de la plataforma, en este caso de la plataforma Windows, y si estamos utilizando el lenguaje Java es porque nos interesa su característica de independencia de la plataforma, por lo tanto hay que ser cuidadosos en este aspecto. Java incluye características de seguridad para reforzar su empleo en Internet. Un problema de seguridad potencial tiene que ver con los applets de Java, que son código ejecutable que opera en la máquina local del usuario que se conecta a la página Web en la que se encuentran los applets. Java emplea verificación de código y acceso limitado al sistema de archivos para garantizar que el código no dañe nada en la máquina local. En el tema y apartados correspondientes comentaremos las restricciones de seguridad que presentan los applets. Debido a que en Java no existen punteros, la asignación y liberación de recursos tiene algunas particularidades. El recolector de basura (garbage collector) es otro de los aciertos del lenguaje Java, se trata de un hilo de ejecución (thread) que se encarga de rastrear en tiempo de ejecución cada objeto que se ha creado, advierte cuándo desaparece la última referencia a él y libera el objeto por el programador. Es decir, en Java la asignación de memoria es dinámica y automática, cuando se crea un nuevo objeto se destina la cantidad de memoria necesaria, y una vez que se ha dejado de utilizar ese objeto el recolector de basura lo localiza y se apropia de la memoria que empleaba el objeto. Por lo tanto no es necesario realizar ninguna liberación explícita de memoria.

Programas en Java: applets y aplicaciones Los programas Java comprenden dos grupos principales: applets y aplicaciones. Un applet (denominado por algunos autores miniaplicación) es un programa dinámico e interactivo que se ejecuta dentro de una página Web, desplegada por un navegador Web con capacidad para Java como puede ser Navigator de Netscape o el Internet Explorer de Microsoft, por lo tanto los applets para ejecutarse dependen de un navegador Web habilitado para Java. Los applets es uno de los principales motivos que han hecho al lenguaje Java tan popular, sin embargo no son tan potentes como las aplicaciones. Las aplicaciones Java son programas más generales que los applets. No requieren un navegador para ejecutarse sólo necesitan de un intérprete de Java para la plataforma en la que se ejecutarán, y pueden emplearse para realizar todo tipo de aplicaciones posibles. Una de las primeras aplicaciones Java que se realizaron fue el navegador Web HotJava. Una aplicación Java consiste en una o más clases, lo único que se necesita para ejecutar una aplicación es tener una clase que funcione como punto de arranque para el resto del programa.

25

Programación en Java

© Grupo EIDOS

Para ejecutar una aplicación Java en un sistema es necesario ejecutar primero la Máquina Virtual, es decir, el intérprete de Java, que permitirá la ejecución de la aplicación, ya que traduce los bytecodes en código nativo. Este paso intermedio a la ejecución de la aplicación Java puede ser molesto, por ello algunos constructores de software han anunciado que pronto incorporarán la Máquina Virtual de Java a sus sistemas operativos, de esta forma las aplicaciones Java se ejecutarán de una manera muy similar a las aplicaciones de otros lenguajes (C, C++, Pascal, etc.…), todas las llamadas a la Máquina Virtual serán transparentes al usuario y serán manejadas por el sistema operativo. Esto es similar a lo que ocurre cuando un navegador carga un applet y lo ejecuta en la Máquina Virtual de forma automática.

Similitudes y diferencias entre Java y C++ Se debe indicar que existen pocas diferencias entre Java y C++, al menos en cuanto al aspecto del código fuente al menos. Las diferencias, gratas en algunos puntos e ingratas en otros, comenzamos a avistarlas cuando profundizamos en el lenguaje. Podremos rentabilizar la inversión de tiempo y esfuerzo invertidos en aprender C++ y controlar la programación orientada a objetos. Todos estos conocimientos serán aprovechables por el programador en Java, sin embargo no es cierto que para conocer Java se debe estudiar previamente C/C++, Java es un lenguaje por sí mismo. Las cadenas de Java no son punteros a cadenas de caracteres como en C/C++, ya que Java no soporta punteros. Este modo de concebir las cadenas libera al programador de la engorrosa manipulación de cadenas de C/C++. Para manejar cadenas en una aplicación Java disponemos del tipo de dato String, que no es más que una clase definida en el sistema. Los archivos .class funcionan en cualquier máquina, ya que el intérprete encargado de ejecutarlos está codificado de forma nativa en el sistema receptor de la aplicación. Para lograr lo anteriormente expuesto Java es interpretado, por lo que la velocidad de los ejecutables (que realmente no lo son) es menor que la que lograríamos con el mismo código en C++ (de 10 a 20 veces mayor). Esto no debe preocuparnos, ya que diferentes tecnologías consiguen disminuir esta diferencia llegado, en algunos casos, a igualar la velocidad de C++. De entre estas tecnologías destaca la compilación Just-in-time, que permite la conversión en tiempo de ejecución a instrucciones nativas de la máquina en la que se estén ejecutando los bytecodes. Dispondremos de una inmensa jerarquía de clases diseñadas para la creación de aplicaciones en la Web. Jerarquía probada y en constante crecimiento. Sun Microsystems facilita gratuitamente una copia del JDK del producto (acorde al sistema operativo bajo el que funcionará), con todos los elementos necesarios para crear aplicaciones con Java. La distribución del intérprete no es necesaria si estamos distribuyendo una miniaplicación (applet) enlazada a una página Web, ya que el navegador correspondiente sería capaz de realizar una compilación Just-in-Time del applet. En caso de no ser así y sí necesitar el intérprete, éste sería de libre distribución. Otra diferencia notable es que Java no soporta la herencia múltiple, es decir, no puede heredar de varias clases, sin embargo C++ si soporta heredar de varias clases padre. Se puede decir que Java ofrece una Programación Orientada a Objetos simplificada en este aspecto.

Versiones del lenguaje La última versión del lenguaje Java es lo que se denomina Plataforma Java 2 (Java 2 Platform) que se corresponde con las dos últimas versiones de la herramienta de desarrollo de Sun Microsystems, es decir, con el JDK (Java Development Kit) 1.2 y el JDK 1.3, este último de muy reciente aparición. Anteriormente había una correspondencia entre la versión del lenguaje Java y la versión de la herramienta JDK, así la versión 1.1 de Java se correspondía con la versión 1.1 del JDK. 26

© Grupo EIDOS

2. Introducción al lenguaje Java

Ahora vamos a comentar las correspondencias entre las versiones de Java y las distintas herramientas de desarrollo de las que vamos a tratar en este curso. Aunque desde este momento se debe aclarar que este curso no está enfocado a la utilización de ninguna herramienta de desarrollo de terceros como Borland JBuilder o Microsoft Visual J++, sino que se trata la versión estándar del lenguaje, es decir, la que ofrece Sun con su JDK, y en este caso se trata del JDK 1.3, aunque todo lo que vamos a ver es aplicable también al JDK 1.2. La herramienta de desarrollo de Java de la compañía Microsoft, Visual J++ 6.0, soporta la versión 1.1 del lenguaje. Esta herramienta puede interesarnos si lo que vamos a utilizar es la versión 1.1 de Java, esto no es ninguna contradicción, ya que la propia Sun sigue ofreciendo una versión del JDK para la versión 1.1 de Java, se trata del JDK 1.1.8. La versión 1.1 de Java sigue estando vigente debido a la rápida evolución que está sufriendo el lenguaje. Algunos de los ejemplos ofrecidos en el curso no funcionarán dentro de Visual J++ ya que se corresponderán con nuevas características de Java, de todas formas esta situación se le indicará al lector cuando se produzca. La herramienta de desarrollo Borland JBuilder 3.5, de la compañía Inprise, implementa la Plataforma Java 2, equiparándose a la herramienta de Sun JDK 1.2. Si el lector quiere utilizar la última versión de Java es recomendable que utilice JBuilder 3.5. Además en diversos estudios comparativos entra distintas herramientas de desarrollo del lenguaje Java, Borland JBulider ha sido casi siempre la mejor considerada. El lenguaje Java todavía no ha tenido una versión definitiva ni estable, cosa que supone un grave inconveniente para los sufridos desarrolladores, que tenemos que estar actualizándonos continuamente. Según se ha comunicado desde Sun Microsystems, la versión Java 2 Platform es la versión definitiva del lenguaje, esperemos que esto sea cierto, ya que desde mediados/finales del año 1996 se han sucedido un gran número de versiones, y el seguimiento y aprendizaje del lenguaje resulta verdaderamente agotador y desconcertante.

Entornos de desarrollo Como ya hemos dicho a lo largo de este capítulo vamos a comentar en el curso tres herramientas de desarrollo distintas para utilizar en la realización de nuestros programas en Java, aunque siempre utilizando el estándar del lenguaje Java. La herramienta de desarrollo oficial de Java es el JDK (Java Development Kit). La herramienta JDK la podemos obtener de forma gratuita desde el sitio Web que posee Sun Microsystems dedicado por completo al lenguaje Java, http://java.sun.com. Las versiones actuales de este producto son la 1.1.8, la 1.2 y la 1.3, correspondiéndose la primera con la versión 1.1 de Java y las dos últimas con la última versión denominada Java 2 Platform. Debido a que muchos fabricantes todavía no soportan la versión nueva de Java y también debido a que la nueva versión es bastante reciente, coexisten las dos versiones del lenguaje. Sun Microsystems no nos lo pone fácil con las nomenclaturas de versiones y de productos, y si acudimos a su sitio Web para descargar el JDK, vemos que no aparece la versión 1.2 ni la 1.3. Esto es debido a que el JDK se encuentra incluido en lo que se denomina Java 2 SDK (Software Development Kit). De esta forma si deseamos la versión 1.2 del JDK veremos descargar el producto Java 2 SDK Standard Edition v 1.2, y si lo que deseamos es tener el JDK 1.3 debemos conseguir el Java 2 SDK Standard Edition v 1.3. A los efectos del presente curso las dos versiones del Java 2 SDK son válidas.

27

Programación en Java

© Grupo EIDOS

El código que generemos en los ejemplos y las características del lenguaje que vamos a utilizar a lo largo de todo el curso se corresponden todas con el JDK de Sun Microsystems, es decir, vamos a utilizar Java estándar. Por lo tanto el único software completamente necesario para seguir el curso satisfactoriamente es el Java 2 SDK Standard Edition. El entorno de desarrollo ofrecido por Sun es bastante pobre, ya que se basa en modo comando, es decir, no ofrece un entorno gráfico, el código lo escribiremos con un editor de texto y luego lo podremos compilar, ejecutar, depurar, etc., con una serie de programas incluidos en el JDK, pero siempre desde la línea de comandos. Pero para mostrar el panorama actual de herramientas de desarrollo de Java se ha decido incluir dos entornos de desarrollo más. Además estos entornos son más amables de utilizar que el ofrecido por Sun, ofreciendo cada uno de ellos un interfaz gráfico que permite que el desarrollo de aplicaciones Java sea más sencillo y rápido. Una de estas herramientas de desarrollo que vamos a comentar en este curso es, como ya hemos adelantado, Microsoft Visual J++ 6.0. Esta herramienta forma parte de la suite de herramientas de Microsoft Visual Studio 6.0. Microsoft Visual J++ 6.0 ofrece un entorno de desarrollo amigable. Sin embargo, como ya habíamos comentado anteriormente, el JDK ofrece un entorno de desarrollo bastante árido, el editor que se propone es el Edit de MS-DOS o cualquier otro editor de texto que no genere un formato para el texto. El entorno de compilación y depuración es bastante pobre y además se basa completamente en la línea de comandos de MS-DOS. El mayor inconveniente que presenta Visual J++ 6.0 es que en algunos casos puede generar código Java que no pertenece al estándar del lenguaje. Pero en este curso se va a tratar el lenguaje Java estándar no la implementación particular de Microsoft. Se podría decir que vamos a ver el lenguaje Java 100% de Sun. Aunque no utilicemos la implementación que realiza Microsoft del lenguaje, nos podemos beneficiar del entorno de desarrollo que ofrece Microsoft, que como ya hemos dicho es mucho más fácil de utilizar y más amigable que el ofrecido por Sun. A lo largo del curso comentaremos en detalle Visual J++ 6.0 y cómo debemos utilizarlo para generar código Java completamente estándar. Pero el mayor inconveniente que presenta Visual J++ 6.0 es que recoge únicamente hasta l versión 1.1 del lenguaje Java, esto en algunos casos puede ser suficiente, pero veremos que en otros no, sobre todo si queremos utilizar las nuevas características de Java 2, como pueden ser la utilización de componentes avanzados (Swing) para construir interfaces de usuario o el acceso a datos mejorado que ofrece a través de JDBC 2.0. Otro punto en contra de Visual J++ es que ofrece un entorno gráfico, pero no es todo lo gráfico que se podría desear, es decir, no permite construir interfaces de usuario al modo de otras herramientas como pueden ser Visual Basic o Delphi, dónde podemos arrastran controles o elementos del interfaz de usuario y situarlos en el lugar deseado, sino que todo lo debemos hacer a través de programación sin que Visual J++ genera una única línea de código fuente. Podemos decir que el segundo entorno de desarrollo utilizado en este curso Borland JBuilder 3.5 soluciona las dos deficiencias que plantea Visual J++. Por un lado ofrece la versión del lenguaje correspondiente a la Java 2 Platform(Plataforma Java 2) y un entorno de desarrollo que permite la creación visual de interfaces de usuario con generación de código Java incluida.

28

© Grupo EIDOS

2. Introducción al lenguaje Java

De todas formas en los sucesivos capítulos veremos con más detenimiento cada uno de estos entornos de desarrollo.

Características de la plataforma Java 2 Este apartado muestra de forma general las características que incluye el lenguaje Java en su última versión y que han ido evolucionando desde la versión 1.0. El contenido de este apartado es a modo informativo, el lector no tiene porque comprender los términos que se van a utilizar en este apartado. Este apartado puede ser útil a lectores que ya conozcan algunas de las versiones anteriores del lenguaje y también nos sirve para observar las nuevas características que ha ido implementando el lenguaje. •

Internacionalización: permite el desarrollo de applets localizables, es decir, un mecanismo de localización sensible a la hora y fecha locales. Se incluye también la utilización de caracteres Unicode. Unicode tiene la capacidad de representar unos 65.000 caracteres, un número bastante amplio para incluir los caracteres de la mayoría de los lenguajes hablados hoy en día.



Seguridad y firma de applets: el API (aquí entendemos como API un conjunto de clases más o menos complejo que cumplen una funcionalidad común) de seguridad de Java está diseñado para permitir a los desarrolladores incorporar funcionalidades de seguridad a sus aplicaciones. Contiene APIs para firma digital y tratamiento de mensajes. Existen interfaces para la gestión de claves, tratamiento de certificados y control de accesos. También posee APIs específicos para el mantenimiento de certificados X.509 v3 y para otros formatos de certificado. Además se ofrecen herramientas para firmar ficheros JAR (Java Archive).



Ampliaciones del AWT: el AWT (Abstract Window Toolkit) es un API encargado de construir el GUI (Graphical User Interface, interfaz de usuario gráfico). El AWT de la versión 1.0 fue diseñado para construir sencillos interfaces de usuario por lo tanto se hizo necesario el ampliar el AWT en la versión 1.1. Estas ampliaciones tratan de resolver las principales deficiencias del AWT , además, representan un comienzo en la creación de una infraestructura más rica para el desarrollo de complicados interfaces de usuario, esto incluye: APIs para la impresión, componentes scroll, menúes popup, portapapeles (copiar/pegar), cursores para cada componente, un modelo de eventos nuevo basado en la delegación de eventos (Delegation Event Model), ampliaciones en el tratamiento de imágenes y gráficos, y un tratamiento de fuentes más flexible de cara a la característica de internacionalización.



JavaBeans: inicialmente se puede definir un JavaBean como un componente software reutilizable, que puede ser manipulado visualmente en una herramienta de desarrollo. Consta de una colección de una o más clases Java que suelen encontrarse en un único fichero JAR (Java Archive). Un JavaBean sirve como un objeto independiente y reusable. El API de los JavaBeans define un modelo de componentes software para Java. Este modelo, desarrollado de forma coordinada entre las compañías Sun, Borland Inprise y otras, es una especificación de como codificar estos componentes para que puedan ser utilizados en diferentes entornos de programación. Un ejemplo de la utilización de los JavaBeans la ofrece la herramienta de desarrollo de Java JBuilder, de la compañía Borland Inprise (también ofrece una herramienta llamada BeansExpress que permite una fácil construcción de JavaBeans). Esta herramienta posee un gran número de JavaBeans como pueden ser los diferentes componentes para la construcción interfaces de usuario (botones, listas, paneles, ventanas, botones de selección, barras de menú, etc.…). Al igual que estos componentes son utilizados por el entorno JBuilder, se pueden incluir dentro de cualquier herramienta de desarrollo que respete y reconozca las características de los JavaBeans. Si creamos un componente con las

29

Programación en Java

© Grupo EIDOS

especificaciones de los JavaBeans, ocultando los detalles de implementación y solamente mostrando las propiedades, métodos y eventos públicos conseguiremos las siguientes ventajas: 1. Pueden ser utilizados por otros desarrolladores usando un interfaz estándar. 2. Se pueden situar dentro de las tablas de componentes de diferentes herramientas de desarrollo. 3. Se pueden comercializar por separado como si se tratara de un producto. 4. Pueden ser actualizado con un impacto mínimo sobre los sistemas en los que se encuentre. 5. Es un componente escrito en Java puro, por lo tanto es independiente de la plataforma.

30



Ficheros JAR (Java ARchive): este formato de fichero presenta muchos ficheros dentro de uno, y además permite la compresión de los mismos. Varios applets y sus componentes requeridos (ficheros .class, imágenes y sonidos) pueden encontrarse dentro de un fichero JAR y por lo tanto cargados por un navegador en una sola petición HTTP. Este formato de ficheros es parecido a los ficheros Cabinet de Microsoft.



Mejoras en Swing: Swing es el otro API existente para crear interfaces de usuario gráficos, ofrece muchos más componentes que el API AWT. Además los componentes Swing permiten modificar su aspecto y comportamiento.



Ampliaciones de Entrada/Salida: el paquete java.io ha sido ampliado con flujos de caracteres, que son parecidos a los flujos de bytes excepto en que contienen caracteres Unicode de 16 bits en lugar de 8 bits. Los flujos de caracteres simplifican la escritura de programas que no dependen de una codificación de caracteres determinada, y son más fácil de internacionalizar.



El Paquete java.math: este paquete ofrece dos nuevas clases BigInteger y BigDecimal, para el tratamiento de operaciones numéricas. Un paquete, que definiremos en detalle más adelante, podemos decir que es un conjunto de clases relacionadas entre sí. Los paquetes es una manera de organizar y clasificar las clases que posee el lenguaje Java.



JDBC 2.0: JDBC es un API para ejecutar sentencias SQL (Structured Query Language), que ofrece un interfaz estándar para el acceso a bases de datos. Ofrece un acceso uniforme a un amplio número de bases de datos. El código de este API está completamente escrito en Java, de hecho se encuentra en el paquete java.sql, por lo tanto ofrece también independencia de la plataforma. Está basado y es muy similar a ODBC (Open Database Connectivity). Usando JDBC es muy sencillo enviar sentencias SQL a cualquier base de datos relacional, gracias al API de JDBC no es necesario escribir un programa que acceda a una base de datos Sybase, otro programa que acceda a una base de datos Oracle u otro que acceda a una base de datos Informix, el mismo programa servirá para ejecutar las sentencias SQL sobre todas estas bases de datos. Básicamente JDBC permite: establecer una conexión con una base de datos, enviar sentencias SQL y procesar los resultados. En la versión 2.0 de JDBC se ha mejorado el acceso a datos haciéndolo más potente a través de la creación de diferentes tipos de cursores para acceder a los datos.



JFC (Java Foundation Classes): con este nombre se agrupan un gran número de clases especializadas en la construcción de interfaces de usuario. Dentro de JFC se encuentran las APIs ya mencionadas para la construcción de interfaces de usuario, es decir, Swing y AWT. Además incluye características de accesibilidad que permiten utilizar tecnologías tales como lectores de pantalla o dispositivos Braille, utilización de gráficos en 2 dimensiones, soporte

© Grupo EIDOS

2. Introducción al lenguaje Java

para arrastrar y soltar (Drag and Drop), posibilidad de modificar el aspecto y comportamiento de los componentes gráficos (pluggable Look and Feel), etc. •

Servlets: los servlets son aplicaciones Java que se ejecutan en servidores Web y que permiten construir páginas Web de forma dinámica. También permiten obtener información de los formularios enviados por los clientes. Son una tecnología que realiza funciones similares a los scripts CGI (Common Gateway Interface) y a las páginas ASP (Active Server Pages).

31

Sintaxis del lenguaje Java Introducción Este capítulo no podría faltar tampoco en nuestro curso de Java, este es el típico capítulo que tienen todos los cursos o libros que traten un lenguaje de programación. En este capítulo vamos a tratar la sintaxis del lenguaje Java. Los alumnos que ya conozcan C o C++ verán que la sintaxis es muy similar, de todas formas recomiendo a todos la lectura de este capítulo. Este capítulo es necesario para saber como escribir el código Java, en el próximo capítulo veremos como implementar los mecanismos de la POO a través de Java. Veremos que muchos de los elementos del lenguaje Java son comunes al resto de los lenguajes existentes.

Identificadores Los identificadores son literales que representan nombres únicos para ser asignados a objetos, variables, clases y métodos, de este modo el compilador puede identificarlos unívocamente. Estos nombres sirven al programador, si éste les da sentido. Por ejemplo, si vamos a implementar una clase para manejo del fichero de clientes, sería recomendable que la misma se llamara algo así como ClientManager, o ManejadordeCliente, no tendría sentido, aunque es totalmente válido llamarla Aj23.

Programación en Java

© Grupo EIDOS

Existen de todos modos algunas limitaciones a la hora de dar nombres a los identificadores, que son las mismas que en la mayoría de los lenguajes. Los identificadores tienen que comenzar por una letra, un subrayado o un símbolo de dólar, tras este carácter, se pueden utilizar combinaciones de los ya mencionados y números del 0 al 9. No pueden utilizarse, como es lógico, las palabras clave del lenguaje como identificadores (que mostraremos más adelante). Aunque estos identificadores pueden ser cualquier longitud, para el compilador sólo son significativos los primeros 32 caracteres. Se debe tener cuidado al escribir los identificadores, porque Java distingue entre mayúsculas y minúsculas, de este modo, Nombre y nombre son dos variables diferentes. Java permite el uso de cualquier carácter del código Unicode para definir identificadores, de esta forma, el identificador Año es totalmente válido en Java. A la hora de nombrar los identificadores, Java presenta una serie de normas de estilo de uso generalizado, lo que significa que se pueden adoptar o rechazar sin que ello influya en lo más mínimo en el comportamiento del código, pero se debe advertir que la mayor parte del código Java existente utiliza estas normas. En Java se utiliza el word-mixing (EsteEsUnEjemploDeWordMixing), la primera letra se escribe en mayúscula (ManejadorDeClientes, por ejemplo) para las clases, y no se utilizan los signos subrayado ni dólar como primer carácter de un identificador. Esta última norma, tiene su explicación: las librerías de C que se utilizan en Java, suelen utilizar los caracteres de subrayado y dólar como primeros caracteres de sus identificadores, por lo que evitándolos, nos evitamos problemas de conflictos de duplicidad. Otro dato de interés a este respecto es que a las clases no se les pone ninguna identificación delante, ya que en Java todo son clases. Los nombres de variables, objetos y métodos en Java, aunque se utiliza word-mixing, comienzan con una minúscula, por ejemplo: toUpper(). Aun cuando esta es una sugerencia y no una norma, es conveniente seguirla, ya que así está notada toda la jerarquía de clases de Java, y al distinguir el lenguaje entre mayúsculas y minúsculas, ni podemos escribir estos nombres de otro modo ni debemos dar a nuestros identificadores de variables y métodos nombres con la primera letra en mayúsculas (para mantener la consistencia con el estilo de los creadores del Java). Sin embargo, en el caso de las variables (aquí y en adelante el termino variable se refiere al nombre de los objetos o de las variables de los tipos primitivos de Java), a muchos programadores nos gusta notar el tipo al que pertenecen, clarificando así el código. De este modo, si una variables es de tipo cadena (string) al nombre le precedería la letra "s". Por ejemplo, sNombre es el identificador de una variable que contiene una cadena. En la Tabla 1, se ofrece una sugerencia para los prefijos de nombres de variables atendiendo a su tipo. Por supuesto, que esto es sólo una indicación y no una norma que se tenga que seguir. Identificadores de variables

34

Prefijo

Tipo

Ejemplo

a

array

aElementos

b

boolean

bCancelar

© Grupo EIDOS

3. Sintaxis del lenguaje Java

c

char

cInicial

d

double

dDistancia

f

float

fInterés

i

integer

iColumna

l

long

lCantidad

s

string

sNombre

Tabla 1

Para los identificadores de variables que se refieren a objetos, utilizaremos tres letras como prefijo, intentando que estas tres letras indiquen de la forma más clara posible el nombre de la clase a la que el objeto pertenece. Por ejemplo, si instanciamos un objeto de la clase Frame, el prefijo podría ser "frm", seguido del nombre que queramos darle a la variable, por ejemplo, frmClientes.

Palabras clave Las palabras clave son identificadores reservados por el lenguaje. Aunque el alumno sea programador de C o C++, le sugerimos que lea con detenimiento la siguiente tabla, ya que Java tiene un número mayor de palabras reservadas que C y C++. Palabras Clave abstract

continue

for

new

switch

boolean

default

goto

null

synchronized

break

do

if

package

this

byte

double

implements

private

threadsafe

byvalue

else

import

protected

throw

case

extends

instanceof

public

transient

catch

false

int

return

True

char

final

interface

short

Try

class

finally

long

static

Void

const

float

native

super

while

Tabla 2

35

Programación en Java

© Grupo EIDOS

Además de estas, existen algunas palabras reservadas, ahora no se utilizan pero es posible que se conviertan en palabras clave en un futuro. Son las siguientes: cast, future, generic, goto, inner, operator, outer, rest, var

Literales Llamamos literales a aquellos elementos de un programa que no pueden variar. Se les llama también constantes. Los literales pueden ser: números, caracteres y cadenas. Los literales numéricos se dividen en: enteros, coma flotante y booleanos (álgebra de Boole). De hecho, los literales booleanos están incluidos en Java dentro de los numéricos por su herencia del C, ya que en C verdadero es 1 y falso 0. Los literales de caracteres no son ASCII sino Unicode, por ello un carácter en Java necesita 16 bits para ser representado, en lugar de 8 como ocurre en otros lenguajes. Los literales dan en Java lugar a cada uno de los tipos básicos, anteponiéndoles la palabra reservada correspondiente a la hora de declararlos.

Enteros Los enteros, dependiendo de la precisión que el número pueda tener se dividen en los siguientes tipos primarios: •

byte 8 bits complemento a dos



short 16 bits complemento a dos



int 32 bits complemento a dos



long 64 bits complemento a dos

Los enteros se almacenan por defecto internamente como tipo int, que es un valor de 32 bits con signo. Si fuese necesario que un literal entero se almacenase como de tipo long, puede hacerse añadiendo una l o L al final del literal, lo que hace que el número se guarde internamente como un valor de 64 bits. Así, el número 42 se representaría como de tipo int, mientras que 42L, sería un long. Estos, pueden representarse en tres formatos diferentes: decimal, octal y hexadecimal. Dependiendo de la base del sistema numérico en la que se deseen representar. Los enteros en su representación decimal, no necesitan ninguna notación especial. Para hexadecimal (base 16) se antepone el prefijo 0x o 0X, y para base 8 (sistema octal) se antepone un 0 inicial. Así, el número decimal 42 en Java puede representarse como indica la Tabla 3. Decimal Hexadecimal Octal 42

0x2A Tabla 3

36

052

© Grupo EIDOS

3. Sintaxis del lenguaje Java

Coma flotante Al igual que los literales enteros pueden ser de cuatro tipos diferentes, los reales en coma flotante – números con parte entera y parte decimal–, pueden ser de dos tipos: float y double. Los primeros se almacenan en 32 bits, mientras que los segundos se almacenan en 64 bits. La única diferencia, es su capacidad de precisión, debida la mayor cantidad de información que necesitan para representarlos. Por defecto, los literales en coma flotante son del tipo double, a diferencia de los enteros, donde no se toma como predeterminado el de mayor precisión. Pero si se desea expresar uno de estos literales en tipo float, basta con añadir una f o F al final del literal (para forzar tipo a double se añade una d o D, pero puesto que este es ya tipo predeterminado, esto sólo sirve en caso de querer dar mayor claridad al código). Ambos (float y double) pueden representarse en notación estándar (3,14159) o científica (314159e-5). •

float 32 bits IEEE 754



double 64 bits IEEE 754

Booleanos El tipo booleano se ha implementado en Java para representar los valores de verdadero y falso, que en C se representan con un literal entero (0 falso y 1 o cualquier cosa que no sea 0, verdadero). Se utiliza para ello dos palabras reservadas: true y false. •

true verdadero



false falso

Caracteres Los caracteres, que se refieran un único carácter Unicode, se representan al igual que en C, entre comillas simples. También pueden incluirse caracteres de control no imprimibles. En la Tabla 4 se ofrecen estos caracteres. Descripción

Representación

Barra invertida

\\

Continuación

\

Retroceso

\b

Retorno de carro

\r

Alimentación formularios

\f

Tabulador horizontal

\t

37

Programación en Java

© Grupo EIDOS

Línea nueva

\n

Comillas simples

\’

Comillas dobles

\"

Carácter unicode

\udddd

Carácter octal

\ddd Tabla 4

Ejemplos de literales de carácter: a \n \u0042

Cadenas Un literal de cadena es un conjunto de caracteres agrupados. Se representan entre comillas dobles. Java, cada vez que encuentra un literal de tipo cadena, crea una nueva instancia de la clase String, a diferencia del lenguaje C, donde un string es un array de caracteres. En Java podemos también, si así lo deseamos, crear un array de caracteres, pero el lenguaje proporciona el tipo String para estos menesteres. Por ejemplo: "Mi mamá me mima, mi mamá me ama"

El literal null El literal null se corresponde con el tipo null, quien tiene un solo valor: la referencia nula.

Operadores Los operadores en Java, como se verá tienen también gran influencia del C, de hecho, son casi los mismos, y funcionan casi exactamente igual. Los veremos más con detenimiento en el apartado de expresiones y operadores. Operadores (según tipo) Unarios

++ --

-

~

Binarios

+

-

*

/

%

De bits

&

|

^

>

Relacionales




=

= = !=

Booleanos

&

|

^

||

Aritméticos

38

&&

>>>

!

= = !=

?:

© Grupo EIDOS

3. Sintaxis del lenguaje Java

Cadenas

+

Asignación

=

+= -=

*=

/=

%=

&= |=

^=

Tabla 5

Separadores Sólo hay un par de secuencias con otros caracteres que pueden aparecer en el código Java; son los separadores simples, que van a definir la forma y función del código. Los separadores admitidos en Java son los que se detallan en la Tabla 6 Separadores ( ) paréntesis

Para contener listas de parámetros en la definición y llamada a métodos. También para definir precedencia en expresiones, contener expresiones para control de flujo y rodear a las conversiones de tipo.

{ } llaves

Para contener los valores de matrices inicializadas automáticamente. También se utiliza para definir un bloque de código, para clases, métodos y ámbitos locales.

[ ] corchetes

Para declarar tipos matriz así como para referenciar los valores de la matriz.

; punto y coma

Separador de sentencias.

, coma

Separa identificadores consecutivos en una declaración de variables. También se utiliza para encadenar sentencias dentro de una sentencia for.

. punto

Para separar nombres de paquete de subpaquetes y clases. También se utiliza para separar una variable o método de una variable de referencia. Tabla 6

Comentarios Los comentarios pueden ser considerados como un caso especial dentro de los elementos de la sintaxis del lenguaje, ya que aunque estos sean reconocidos por el compilador, éste los ignora. Las razones son tan obvias, que no vamos a entrar en detalles. En Java existen tres tipos de comentarios (los dos del C y uno distinto). Tipos de Comentarios // comentario

Se ignoran todos los caracteres desde // hasta fin de línea

39

Programación en Java

© Grupo EIDOS

/* comentario Se ignoran todos los caracteres entre /* y */ */ /** comentario Comentario de documentación (funciona como el anterior) */ Tabla 7

Merece especial atención el comentario de documentación. Cuando se emplea este tipo de comentarios, podemos utilizar una herramienta especial llamada JavaDoc (desarrollada por Sun e incluida en la herramienta JDK) para convertir automáticamente el texto que se encuentra abarcado por este tipo de comentarios en documentación de nuestro código fuente. De este modo, la documentación de nuestro código está dentro del propio código, y podemos crearla al tiempo que lo escribimos o modificamos. Esta herramienta además reconoce ciertos tokens dentro de esta área para dar formato al texto de documentación que se va a crear, pero no vamos a profundizar más en ello.

Tipos de datos en Java Como ya comentamos al hablar de los literales, cada uno de ellos se refiere a un tipo básico de datos, aunque en Java hay algunos tipos de datos que no tienen representación como literales. Estos son los arrays (o matrices) y las clases. Quizás sea discutible considerar las clases como tipos de datos, pero si retomamos el capítulo dedicado a POO, nos daremos cuenta de que al fin y al cabo, cuando creamos una clase lo que estamos creando no es más que un sistema algebraico: definiendo elementos y operaciones sobre dichos elementos; que es al fin y al cabo, lo que hacemos con los enteros, con los números reales o con las cadenas, es decir con los tipos de datos preestablecidos por el lenguaje. Ya comentábamos que una clase se podía asemejar a un tipo de datos y un objeto de la clase a una variable de ese tipo de datos. Veamos, aunque sea muy someramente, ya que los hemos explicado al hablar de los literales, cada uno de los tipos de datos que Java como lenguaje nos proporciona. Aunque previamente, y para poder poner ejemplos de declaración de tipos, debemos indicar la sintaxis de la sentencia de declaración. Esta es (se debe observar que en Java, al igual que en C, las sentencias finalizan con un punto y coma ";"): [= ] [, [= ]]; o bien, con asignación múltiple: ,... , = ;

Enteros Véase el apartado de Enteros en Literales

40

© Grupo EIDOS

3. Sintaxis del lenguaje Java

Tipos de datos Enteros Tipo

Tamaño Ejemplo

byte

8 bits

Byte edad;

short

16 bits

Short alturaEdificio = 614;

int

32 bits

Int miCantidad = 3456740, tuCantidad = 645780;

long

64 bits

Long distanciaInical, distanciaFinal = 86868688; Tabla 8

Coma flotante Véase el apartado de Coma flotante en Literales Tipos de datos de Coma Flotante Tipo

Tamaño

Ejemplo

float

32 bits

float presión;

double

64 bits

double distanciaEstelar; Tabla 9

Booleanos boolean seguir; boolean cancelarProceso = true, abandonarAplicación = false; Véase el apartado de Booleanos en Literales

Carácter char inicial; char miInicial = ´F´; Véase el apartado de Caracteres en Literales

Cadenas String miNombre = "Pep Rubirá" String comillasDobles = "/""

41

Programación en Java

© Grupo EIDOS

Se deben hacer las siguientes consideraciones: •

En este caso, la inicial del nombre de tipo (String, que como ya comentamos es una clase) está en mayúsculas, esto, como ya dijimos es fundamental, ya que Java distingue entre mayúsculas y minúsculas, por lo que si hubiésemos escrito el tipo de dato como "string", el compilador nos reportaría un error al no encontrar ninguna clase que tuviese este nombre.



En la definición de datos de tipo carácter las comillas son simples y en la de tipo String son dobles.



Para crear una cadena de caracteres donde se incluyan las comillas, utilizamos la secuencia de escape correspondiente.

Véase el apartado de Cadenas en Literales.

Arrays En Java, los arrays son objetos, son creados dinámicamente y pueden ser asignados a variables de tipo Object, por lo que todos los métodos de la clase Object (esta clase la trataremos en un próximo capítulo) pueden ser invocados desde un array. Un array tiene un número entero de elementos que lo componen, y nos referimos a ellos por su índice, que obviamente es un entero. Si un array tiene n elementos, el índice varía entre 0 y n-1 ambos inclusive. Un array puede tener 0 elementos, decimos entonces que el array está vacío. Del mismo modo, un array puede tener una o más dimensiones. En cualquier caso, una vez creado el array éste no puede cambiar de tamaño, es estático (existe en Java la clase Vector, que permite trabajar con "arrays" dinámicos). Todos los elementos de un array tienen que ser del mismo tipo, aunque estos pueden ser arrays, en tal caso, debe llegar un momento en que los elementos de estos elementos sean datos de otro tipo. Un array se "fabrica" en dos tiempos: el de declaración y el de creación. En el primero sólo se indican el tipo y las dimensiones de éste, esta información es procesada por el compilador. En el segundo tiempo se crea el array en memoria, para lo que se utiliza el operador new (este operador lo veremos en siguiente capítulo para la creación de objetos), es entonces cuando indicamos el número de elementos que va a contener. Java no permite por lo tanto declarar arrays al estilo de C, donde al tiempo que se declara un array se indica el número de elementos (int n[10] no es válido en Java). Esto es así porque Java no utiliza punteros, sino objetos para crear variables de tipo array, lo que permite entre otras cosas comprobar los límites del array cada vez que se va acceder a él, y reportar un error si se intenta sobrepasar sus límites, en lugar de dejar colgada la aplicación y el sistema operativo, como ocurre en C. La declaración de arrays en Java es casi igual que en C, salvo que los corchetes pueden utilizarse tras el nombre de la variable (como en C) o tras el tipo de la variable. También pueden definirse los elementos de un array en la declaración del mismo. Veamos algunos ejemplos de declaración de arrays en el Código fuente 1.

int iNumeros[]; // Declara un array de enteros char cAlafabeto[]; // Declara un array de caracteres

42

© Grupo EIDOS

3. Sintaxis del lenguaje Java

float fTemp[]; // Declara un array de floats float[] fTemp; // Equivalente a la anterior long lTabla[][]; // Array de dos dimensiones char cAlfabeto []= new char[27] // Declara y construye in array de 27 elementos float fTemp [][] = new float [10][3] // Declara un array de 2 dimensiones: // una con 10 elementos y la otra con 3 elementos int iPrimos = { 1,3,5,7 } // Declara un array de 4 elementos y le da valores Código fuente 1

Esto mismo podría haber hecho como indica el Código fuente 2.

int iPrimos[]; iPrimos = new int[4]; iPrimos[0] = 1; iPrimos[1] = 3; iPrimos[2] = 5; iPrimos[3] = 7; Código fuente 2

Sin embargo, en las especificaciones de Sun para la versión 1.1 de Java, se ha ampliado levemente la forma en cómo se pueden inicializar los arrays. Ahora se permite inicializar los contenidos de un array al utilizar el operador new. Lo que flexibiliza la creación de arrays. El Código fuente 3es ahora correcto.

String[] martians = new String[] { "Gidney", "Cloyd" }; Código fuente 3

Empaquetar tipos primitivos Aunque Java es un lenguaje casi 100% orientado a objetos, internamente trabaja con dos tipos de entidades: tipos primitivos y objetos. La forma en como maneja los tipos numérico, booleano y carácter es muy similar a como lo hacen otros lenguajes procedurales como puedan ser C o Pascal, a diferencia de otros lenguajes como SmallTalk para quien todo son objetos. La única razón de que exista esta diferencia en Java, es que el manejo de tipos primitivos es más eficiente que el de los objetos; y por lo tanto se puede conseguir un mayor rendimiento del sistema. Sin embargo, muchos de los componentes del lenguaje Java sólo pueden trabajar con objetos, es decir tienen que recibir una instancia que directa o indirectamente provenga de la clase Object, que es la raíz de la jerarquía de clases de Java. Para resolver este conflicto, el lenguaje Java dispone de una serie de clases que empaquetan los tipos primitivos. El paquete java.lang (se debe recordar que un paquete es una forma de organizar y agrupar clases relacionadas, en los capítulos siguientes trataremos más en detalle los paquetes) contiene las clases de que se dispone en Java para empaquetar los tipos primitivos.

43

Programación en Java

© Grupo EIDOS

Clase

Tipo primitivo que empaqueta

Integer

Int

Long

Long

Float

Float

Double

Double

Boolean

Boolean Tabla 10

Si se observa la tabla anterior, nos damos cuenta que no existen clases empaquetadoras para los tipos primitivos byte y short, lo que realmente no supone ningún problema, ya que estos dos tipos pueden tratarse como objetos utilizando la clase Integer. Si echamos un vistazo a la jerarquía de clases del Java, se observará que todas las clases empaquetadoras descienden de la superclase Number.

Conversión de tipos de datos Java al igual que C admite el moldeado de tipo (casting) o conversión de tipos, lo que nos permite convertir un tipo de dato en otro. Lo que se suele utilizar principalmente para cambiar el tipo de dato devuelto por una función para que coincida con el tipo de dato esperado por otra a la que se lo vamos a pasar como parámetro. Para realizar el moldeado de tipo (casting), se coloca el tipo desea entre paréntesis a la izquierda del valor que vamos a convertir. El típico ejemplo que muestra esto es el de conversión del valor devuelto por el método read() del sistema estándar de entrada. Este método devuelve un dato de tipo int, y normalmente deseamos almacenarlo como un tipo char, lo convertiremos como muestra el Código fuente 4.

char c; ...................... ...................... c = (char) System.in.read(); Código fuente 4

A la hora de convertir unos datos a otros, puede perderse información dependiendo de la capacidad de almacenamiento que uno y otro tipo de dato tengan. Por lo que debe tener muy en cuenta la información que hemos dado a este respecto en esta sección. Si deseamos convertir un tipo de dato cuya capacidad de almacenamiento es de 64 bits (por ejemplo un long) en otro de menor capacidad (por ejemplo un int, con 32 bits), es muy posible que en la conversión perdamos información. Esto ocurrirá si los bits altos (aquellos que están a la izquierda en

44

© Grupo EIDOS

3. Sintaxis del lenguaje Java

una representación binaria del número) del dato long tenían información (lo que ocurre con toda seguridad para números muy grandes). Otro caso distinto de pérdida de información es el que ocurre cuando se moldea un double para convertirlo en un long. Aunque la capacidad de almacenamiento de ambos sea de 64 bits, el tipo double tiene parte entera y parte fraccionaria, mientras que el long sólo tiene parte entera. Todo esto se debe tener muy presente cuando se vaya a realizar una conversión de tipo, ya que estos errores a veces son difíciles de detectar y nos pueden dar más de un quebradero de cabeza. En la Tabla 11 presentamos las conversiones en las que no puede haber pérdida de información (conversiones seguras). Moldeado sin Pérdida de Información Tipo fuente Tipo Destino byte

short, char, int, long, float, double

short

int, long, float, double

char

int, long, float, double

int

long, float, double

long

float, double

float

Double Tabla 11

Bloques y ámbitos Bloques Al igual que C, Java utiliza las llaves ({} la primera de inicio y la otra de fin de bloque) para determinar los bloques dentro de un programa. Todo lo que se encuentra entre estas dos llaves se considera un bloque. Los bloques son parte de la sintaxis del lenguaje. Los bloques pueden y suelen anidarse; utilizándose la sangría para clarificar el contenido de un bloque. De este modo, el bloque más externo se sitúa al margen izquierdo del fichero de código fuente, y cada vez que se anida un bloque se indenta (sangra) el texto que lo contienen un número determinado de columnas, normalmente tres o cuatro. El sangrado no tiene ninguna utilidad para el compilador, pero sin ella la lectura del código por parte del programador es casi imposible.

45

Programación en Java

© Grupo EIDOS

Ámbitos Los bloques además, definen los ámbitos de las variables. El ámbito se refiere a la longevidad de las variables. Una variable existe sólo dentro del bloque donde ha sido declarada, eliminándola el compilador una vez que se sale de dicho bloque. Esto es cierto para todos los tipos de datos de Java. Si el dato es un objeto, y su clase tiene un destructor asociado (distinto al destructor por defecto, que es interno y Java lo maneja por sí solo) este es invocado al salir la variable de ámbito. Cuando una variable sale de ámbito, es eliminada y la memoria que ésta ocupaba es liberada por el recolector de basura (garbage collector).

Expresiones Una expresión no es más que una secuencia de elementos que puede ser evaluada por el compilador. Una llamada a una función, una asignación, un cálculo aritmético o lógico son algunos ejemplos de expresiones. Las expresiones suelen dividirse según su tipo, es decir según el tipo del valor que devuelven al ser resueltas, en: aritméticas y lógicas. Dentro de cada una de ellas existen subdivisiones. El compilador las analiza y, si está bien construido, las simplifica todo lo posible, evaluándose en tiempo de ejecución. Algunos ejemplos de expresiones aparecen en el Código fuente 5.

System.out.println( "Hola" + c ); a = 21; b = a + b + c + 15; c = (a + b) * (y-7); d = 2 / 3 + 4 * 5 d = a && b; e = (a && b) || c Código fuente 5

Las expresiones se analizan de izquierda a derecha, salvo que existan paréntesis, en tal caso (como ocurre en matemáticas), los fragmentos de la expresión encerrados entre paréntesis son evaluados antes. Si no hubiese paréntesis, hay algunos fragmentos que son evaluados antes que otros, dependiendo de la precedencia (importancia) de los operadores que se encuentran entre los operandos, pero a igual nivel de precedencia, se mantiene la evaluación de izquierda a derecha (sobre precedencia de operadores, consultar el apartado Precedencia de los operadores). En cualquier caso, se recomienda efusivamente para aclarar el código y eliminar posibles errores, utilizar siempre paréntesis para determinar qué fragmentos de la expresión se van a evaluar primero. En el caso de la expresión de ejemplo cuyo resultado se asigna a la variable d, podemos interpretarla de varias maneras, ya que de no saber en qué sentido se evalúan las expresiones y cual es la precedencia de los operadores, el resultado es imprevisible. De todos modos, adelantamos que esta expresión en Java equivale a lo que muestra el Código fuente 6.

46

© Grupo EIDOS

3. Sintaxis del lenguaje Java

d = (2 / 3) + (4 * 5) Código fuente 6

Este ejemplo ilustra claramente la conveniencia de utilizar los paréntesis al declarar expresiones. En Java, a diferencia de otros lenguajes de programación, al evaluar una expresión lógica, podemos hacer que esta sea evaluada de forma perezosa o no perezosa, dependiendo del operador que utilicemos. Una expresión, se evalúa de forma perezosa cuando tras conseguir el resultado buscado, el evaluador no continúa evaluando el resto de las expresiones por la derecha. Veamos un ejemplo. Supongamos que las siguientes funciones devuelven los valores a continuación indicados: •

Hora() Devuelve la hora actual en formato numérico (0-24 hrs)



DíasMes() Devuelve el día del mes en formato numérico (1-31)



Año() Devuelve el año en curso en formato numérico (0-...)

Siendo los operadores tal como se describen: •

|| OR no exclusivo



&& AND

Entonces, la siguiente expresión lógica (que puede estar dentro de una instrucción de bifurcación condicional if): Hora() >= 12 || (DíaMes() > 15 && Año() == 1997) Se evaluará como indica la Tabla 12. Evaluación Perezosa Hora()

DíaMes() Año()

Al ser true el resultado la función Hora(), la expresión es verdadera, por lo que no es necesario invocar las funciones DíaMes() ni Año().

14

10

10

Forma de evaluarse

10

Al ser false el resultado devuelto por Hora(), es necesario invocar DíaMes(), pero como su resultado es también false, no es necesario invocar Año(), ya que el resultado de la expresión es false.

25

Al ser false el resultado de Hora(), es necesario invocar DíaMes(), y como su resultado es true, el resultado de la expresión depende del valor devuelto por Año(), por lo que es necesario invocar esta función, y en este caso, al ser éste true, el resultado de la expresión es true.

1997

47

Programación en Java

10

25

© Grupo EIDOS

Este caso es idéntico al anterior, pero al ser false el resultado de Año(), el resultado de la expresión es false.

1998

Tabla 12

Sin embargo, en ciertos casos deseamos que la expresión se evalúe completamente, normalmente porque deseamos que todas las funciones que la componen sean invocadas y realicen su cometido. Para estos casos, Java dispone de operadores que fuerzan al evaluador a recorrer toda la expresión. Estos son: &, | y ^. Puesto que es muy común que las expresiones contengan operadores, ahora vamos a entrar en más detalle sobre los operadores que Java nos proporciona.

Clasificación de operadores En este apartado veremos, organizados según el tipo, los distintos operadores que el lenguaje Java incorpora. El programador de C y/o C++, comprobará que son prácticamente los mismos, aunque Java permite mayor flexibilidad en algunos de ellos y añade algún otro.

Aritméticos Operadores sobre enteros Estos operadores pueden aplicarse a todos los tipos de datos enteros: byte, short, int, long. Se dividen en: •

Unarios: utilizan un solo operando para realizar la operación.



Binarios: utilizan dos operandos para realizar la operación.



Relacionales: se comparan dos operandos. Operadores Aritméticos para Números Enteros Op.

Descripción

++

Incremento. Añade una unidad al valor actual de la variable. (1)

--

Decremento. Sustrae una unidad al valor actual de la variable. (1)

-

Negación. Equivale a multiplicar por –1 el valor de la variable.

~

Complemento a nivel de bits. (2)

Unarios

48

© Grupo EIDOS

Binarios

Relacionales

3. Sintaxis del lenguaje Java

+

Adición

-

Sustracción

*

Multiplicación

/

División

%

Módulo

>

Desplazamiento a la derecha. (3)

>>>

Desplazamiento a la derecha con relleno de ceros. (3)

&

AND a nivel de bits.

|

OR a nivel de bits.

^

XOR a nivel de bits.




Mayor que

=

Mayor o igual que

==

Igual que

!=

Distinto que Tabla 13

Tanto los operadores unarios como los binarios, independientemente del tipo de los operandos sobre los que se realice la operación, devuelven un int para todos los casos, excepto que uno de los operandos sea un long, en cuyo caso el valor devuelto es de tipo long. (1) Estos operadores pueden utilizarse en forma de prefijo (++variable) o forma de sufijo (varible++). En el primer caso el incremento (o decremento) de la variable se realiza antes de evaluar la expresión, y en segundo se realiza tras evaluar la expresión. (2) Este operador conmuta el número a nivel de bits, es decir, todos los bits que estaban a 0 pasan a ser 1, y todos los bits que estaban a 1 pasan a 0. (3) Estos operadores desplazan los bits a la derecha o izquierda el número de posiciones especificado como segundo operando.

49

Programación en Java

© Grupo EIDOS

Operadores sobre reales Estos operadores trabajan sobre número de coma flotante, es decir, los tipos: float y double. Lo dicho anteriormente acerca de los operadores sobre enteros es aplicable a los operadores sobre números reales salvo que el resultado de la expresión será de tipo float si ambos operandos son de este tipo y en caso contrario el tipo devuelto será double. Operadores Aritméticos para Números Reales Op.

Descripción

++

Incremento. Añade una unidad al valor actual de la variable.

--

Decremento. Sustrae una unidad al valor actual de la variable.

+

Adición

-

Sustracción

*

Multiplicación

/

División

%

Módulo




Mayor que

=

Mayor o igual que

==

Igual que

!=

Distinto que

Unarios

Binarios

Relacionales

Tabla 14

Booleanos Operadores Booleanos

50

Operador

Descripción

&

AND (no perezoso)

|

OR (no perezoso)

© Grupo EIDOS

3. Sintaxis del lenguaje Java

^

XOR (no perezoso)

&&

AND (perezoso)

||

OR (perezoso)

!

NOT (negación)

==

Igualdad

!=

Distinto a

?:

Condicional (op. ternario) Tabla 15

Son aquellos que efectúan operaciones sobre datos de tipo booleano, y como es lógico, el tipo de dato que devuelven es booleano.

Relacionales


Mayor que

=

Mayor o igual que

==

Igual que

!=

Distinto que

Relacionales

Tabla 16

Cadena En Java existe un solo operador que utilice cadenas como operandos, este es el operador binario +, este operador concatena cadenas. En el Código fuente 7 vemos un ejemplo.

String str1 = str2 = str3 =

str1, str2, str3; "En lugar de la Mancha"; "de cuyo nombre no quiero acordarme"; str1 + " " + str2; Código fuente 7

Tras aplicar el operador de concatenación de cadenas, el valor la variable str3 es: 51

Programación en Java

© Grupo EIDOS

"En lugar de la Mancha de cuyo nombre no quiero acordarme"

Asignación Estos operadores, salvo el operador de asignación simple (=) se utilizan para escribir menos, y por lo tanto, su forma simplificada es exactamente equivalente a su forma extendida. Operadores de Asignación Op.

Descripción

Equivalencia

=

Simple

+=

Adición

var1 = var1 + var2 Æ var1 += var2

–=

Sustracción

var1 = var1 – var2 Æ var1 –= var2

*=

Multiplicación var1 = var1 * var2 Æ var1 *= var2

/=

División

var1 = var1 \ var2 Æ var1 \= var2

%=

Módulo

var1 = var1 % var2 Æ var1 %= var2

&=

AND

var1 = var1 & var2 Æ var1 &= var2

|=

OR

var1 = var1 | var2 Æ var1 |= var2

^=

XOR

var1 = var1 ^ var2 Æ var1 ^= var2 Tabla 17

Precedencia de los operadores A continuación se presenta todos los operadores que hemos visto, según su orden de precedencia de mayor a menor, es decir, según su importancia a la hora de ser evaluados. Esto quiere decir, que salvo que se agrupen expresiones mediante el uso de paréntesis, aquellos operadores que tengan mayor orden de precedencia, serán evaluados primero.

52



[] ()



++ --



! ~ instanceof



/%



+-



> >>>

© Grupo EIDOS



< > = = = !=



&^|



&& ||



?:



= += –= *= /= %= &= |= ^=

3. Sintaxis del lenguaje Java

Control de flujo Las sentencias de control de flujo nos permiten que ciertas partes de un programa no se ejecuten (condicionales) o que se ejecuten más de una vez (bucles). Sin ellas, los programas Java se ejecutarían de arriba abajo, se procesarían todas sus líneas y una sola vez cada una de ellas. Las condiciones permiten bifurcar el flujo de la aplicación y en Java se dispone de las sentencias ifelse y switch, los bucles permiten repetir un fragmento de código un número determinado de veces, y las sentencias disponibles en Java para realiza bucles son: for, while y do-while. Todas estas sentencias funcionan exactamente igual que sus homónimas de C, por lo que si el alumno las conoce, puede saltárselas tranquilamente. Java dispone además de otras dos sentencias que permiten hacer saltos: break y continue.

If-else La sintaxis de esta estructura es la siguiente: if () sentencia1; [else [if () ] sentencia2;] Aunque también pueden utilizarse bloques en lugar de sentencias, del siguiente modo: if () { sentencias; } [else [if () ] { sentencias; }] puede ser cualquier expresión que, al ser evaluada, devuelva un resultado de tipo Booleano. Como esta estructura es la más común a través de todos los lenguajes, asumimos que es conocida de sobra, y no entraremos en los detalles de su funcionamiento.

53

Programación en Java

© Grupo EIDOS

Switch La sintaxis de esta estructura es la siguiente: switch( ) { case : sentencias; [break;] [case : sentencias; [break;] ........................ ] [default: sentencias; [break;]] } En esta sentencia, el resultado de la evaluación de es comparado con cada una de las constantes (, ,.....) hasta que se encuentra una que coincida, en ese momento se ejecutan todas las sentencias que se encuentran dentro de ese case, hasta encontrar un break, por lo que si no hay un break al final del case, los cases siguientes también se ejecutarán. debe pertenecer a alguno de los tipos primitivos de Java, no puede ser una clase. Si no se encontrara coincidencia alguna, y existiera la cláusula default, estas sentencias serán ejecutadas hasta encontrar un break. De todos modos, como esta cláusula, caso de existir, siempre se pone la última, no es necesario incluir el break. Esta rama puede simularse mediante el uso de la rama if-else, pero switch ha sido diseñada específicamente para escoger un resultado de entre un grupo de resultados posibles, y es de suponer que el código que se genera es más eficiente que el que se generaría si usáramos para el mismo propósito una estructura if-else. Veamos un ejemplo simple de switch, en el Código fuente 8.

switch( iDíaSemana ) { case 1: sDia = "lunes"; break; case 2: sDia = "martes"; break; case 3: sDia = "miércoles"; break; case 4: sDia = "jueves"; break; case 5: sDia = "viernes"; break; case 6: sDia = "sábado"; break; case 7: sDia = "domingo"; break;

54

© Grupo EIDOS

3. Sintaxis del lenguaje Java

default: sDia = "No se qué día es"; } Código fuente 8

En el Código fuente 9 vemos otro ejemplo en el que no utilizamos una sentencia break tras cada case.

int iMes; int iDías; long nAño; . . . switch (iMes) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: iDías = 31; break; case 4: case 6: case 9: case 11: iDías = 30; break; case 2: if ( ((lAño % 4 == 0) && !(lAño % 100 == 0)) || (lAño % 400 == 0) ) iDías = 29; else iDías = 28; break; default: iDias = 0; } Código fuente 9

For La sintaxis del bucle for es la siguiente: for ( []; []; []) sentencia; O bien: for ( ; ; ){ sentencias; } Aunque estas tres expresiones pueden utilizarse para el propósito que se desee, normalmente se utilizan para los siguientes fines: •

ExprInicializa: en esta expresión se inicializa la variable(s) que va a controlar el bucle. 55

Programación en Java

© Grupo EIDOS



ExprCondición: esta expresión controla cuando finalizan las iteraciones del bucle.



ExprIteración: esta expresión indica cómo cambia la variable de control del bucle.

Se debe señalar que las expresiones son todas optativas, y aunque se pueda escribir un bucle sin ninguna de ellas, no tiene mucho sentido hacerlo. Si así se hiciera, se tendría que mantener los puntos y comas que separan las tres expresiones. Cada una de estas expresiones que se definen en la cabecera del bucle pueden ser simples o expresiones compuestas separadas por comas. Veamos un ejemplo de cada una de ellas: Vemos, en el Código fuente 10, expresiones simples.

for (x = 1; x barra.getMaximum()){ //hemos sobrepasado el máximo de la barra de progreso barra.setValue(barra.getMinimum()); valor=barra.getMinimum(); } else{ barra.setValue(valor); if(valor==barra.getMaximum()) //se emite un pitido al llegar al máximo Toolkit.getDefaultToolkit().beep(); } } public static void main(String s[]) { BarraProgreso ventana = new BarraProgreso(); ventana.creaBarra(); ventana.creaBoton(); ventana.setSize(200,200); ventana.setVisible(true); } } Código fuente 158

Un ejemplo de ejecución este código se ofrece en la Figura 100.

Figura 100

Como se puede comprobar en el ejemplo, la barra de progreso muestra el tanto por ciento (%) de la operación realizada, este tanto por ciento lo calcula teniendo en cuenta el valor actual y sus valores

246

© Grupo EIDOS

12. Interfaces de usuario en Java: componentes atómicos de Swing

máximo y mínimo. Para que se muestre el etiqueta del tanto por ciento se ha utilizado el método setStringPainted() pasándole como argumento el valor true. Podemos mostrar en la barra de progreso cualquier texto mediante el método setString() de la clase JProgressBar y así variar el comportamiento por defecto de la barra de progreso. Para obtener el tanto por ciento de la tarea realizada (completada) representada por la barra de progreso disponemos del método getPercentComplete(). Este es el último de los componentes Swing pertenecientes al grupo de componentes encargados de mostrar información, los siguientes componentes pertenecen al grupo de los componentes atómicos que muestran también una información pero de una forma más compleja y estructurada, además en algunos casos permiten editar esta información.

Componentes que muestran información estructurada En este último apartado se van a tratar dos componentes JColorChooser y JFileChooser que permiten seleccionar un color determinado y un fichero del sistema de ficheros, respectivamente.

JColorChooser Este componente Swing además de ofrecer una información estructurada, como pueden ser los distintos colores, nos permite seleccionar un elemento determinado de esa información. La clase JColorChooser representa un componente Swing atómico, pero bastante complejo y completo que permite seleccionar colores de distintas formas. Además este componente permite mostrar de forma sencilla un diálogo que permite seleccionar también un color. Veremos dos ejemplos de las dos formas que podemos utilizar el componente JColorChooser: como si se tratara de otro componente más o como un diálogo. En el Look & Feel de Java (en el apartado correspondiente hablaremos de los distintos Look & Feel y como establecerlos) una instancia de la clase JColorChooser muestra el siguiente aspecto: se encuentra dividido en dos partes, un panel con pestañas (JTabbedPane) y un panel con la muestra de la selección (preview). El panel de selección con pestañas encuentra en la parte superior y presenta tres pestañas, cada una de ellas permite una forma distinta de seleccionar los colores. El panel de muestra se encuentra en la parte inferior y va mostrando el color seleccionado en cada momento del panel de selección. Para poder tratar la selección actual el componente JColorChooser hace uso de una clase llamada ColorSelectionModel que se encuentra en el subpaquete de Swing denominado javax.swing.colorchooser. El modelo de selección de color (instancia de la clase ColorSelectionModel), lanza un evento de la clase ChangeEvent (este evento vimos que también era lanzado por el componente JSlider) cada vez que se cambia la selección del color en el selector de color (JColorChooser). Si queremos detectar los cambios de selección de color del componente JColorChooser debemos registrar el oyente correspondiente al evento ChageEvent, pero no se debe hacer directamente sobre el componente JColorChooser, sino sobre su ColorSelectionModel. Para obtener la instancia de la clase ColorSelectionModel correspondiente a un objeto de la clase JColorChooser, debemos lanzar sobre el objeto JColorChooser el método getSelectionModel(). 247

Programación en Java

© Grupo EIDOS

Pasemos ahora a ver un código de ejemplo que utiliza un objeto de la clase JColorChooser para configurar el color del texto de una etiqueta.

import import import import import public

java.awt.*; java.awt.event.*; javax.swing.*; javax.swing.event.*; javax.swing.colorchooser.*; class SelectorColor extends JFrame implements ChangeListener{ private JLabel etiqueta; private JColorChooser selectColor; public SelectorColor() { super("Selector de color"); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public void creaEtiqueta(){ //Configuramos la etiqueta sobre la que se aplica la selección de

color etiqueta= new JLabel("La Plataforma Java 2",JLabel.CENTER); etiqueta.setForeground(Color.green); etiqueta.setBackground(Color.white); etiqueta.setOpaque(true); etiqueta.setFont(new Font("SansSerif", Font.BOLD, 24)); etiqueta.setPreferredSize(new Dimension(80,45)); //panel con borde que va a contener la etiqueta JPanel etiquetaPanel = new JPanel(new BorderLayout()); etiquetaPanel.add(etiqueta, BorderLayout.CENTER); etiquetaPanel.setBorder(BorderFactory.createTitledBorder("etiqueta")); getContentPane().add(etiquetaPanel, BorderLayout.CENTER); } public void creaSelectorColor(){ selectColor= new JColorChooser(etiqueta.getForeground()); //se obtiene el modelo de seleción de color para registrar el oyente //de los eventos ChangeEvent selectColor.getSelectionModel().addChangeListener(this); selectColor.setBorder(BorderFactory.createTitledBorder ("Selecciona el color del texto")); getContentPane().add(selectColor,BorderLayout.SOUTH); } public void stateChanged(ChangeEvent e) { etiqueta.setForeground(selectColor.getColor()); } public static void main(String[] args) { SelectorColor ventana = new SelectorColor(); ventana.creaEtiqueta(); ventana.creaSelectorColor(); ventana.pack(); ventana.setVisible(true); } } Código fuente 159

El aspecto del ejemplo es el de la Figura 101

248

© Grupo EIDOS

12. Interfaces de usuario en Java: componentes atómicos de Swing

Figura 101

Como se puede comprobar en el ejemplo el constructor utilizado de la clase JColorChooser recibe como parámetro un color, este es el color seleccionado inicialmente dentro del selector de color. En nuestro caso le hemos indicado el color de la letra de la etiqueta sobre la que se va a aplicar las distintas selecciones de color. El método stateChanged(), que se lanzará cada vez que se cambie la selección de color del selector de color, recupera el color actual mediante el método getColor() de la clase JColorChooser, y se lo aplica al texto de la etiqueta mediante el método setForeground(). En la ejecución del ejemplo se puede observar las tres formas distintas de seleccionar el color que permite el componente JColorChooser, en la Figura 102 se puede ver otra selección distinta, utilizando el formato de color RGB. En este caso el componente JColorChooser lo hemos tratado como otro componente atómico más, añadiéndolo al panel de contenido de la ventana, pero también podemos mostrarlo como un diálogo, para ello podemos utilizar el método estático showDialog() de la clase JColorChooser. La sintaxis de este método es: JColorChooser.showDialog(Component padre, String título, Color color)

249

Programación en Java

© Grupo EIDOS

Figura 102

El primer argumento de este método es el componente padre del diálogo (el componente del que depende), el segundo el título del diálogo y el tercero el color seleccionado por defecto en el diálogo de selección de color. Ahora vamos a modificar el ejemplo anterior para realizar una función similar pero utilizando el selector de colores como un diálogo modal. Para mostrar el diálogo vamos a utilizar un botón (JButton) y el evento ActionEvent. En este nuevo supuesto no se utiliza la clase ColorSelectionModel, sino que el color seleccionado lo obtenemos directamente cuando el usuario pulse el botón de OK del diálogo. Esto se ve mucho más claro en el código fuente del ejemplo

import import import public

250

java.awt.*; java.awt.event.*; javax.swing.*; class DialogoSelectorColor extends JFrame implements ActionListener{ private JLabel etiqueta; private JButton boton; public DialogoSelectorColor() { super("Selector de color con diálogo"); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); }

© Grupo EIDOS

12. Interfaces de usuario en Java: componentes atómicos de Swing

}); } public void creaEtiqueta(){ //Configuramos la etiqueta sobre la que se aplica la selección de color etiqueta= new JLabel("La Plataforma Java 2",JLabel.CENTER); etiqueta.setForeground(Color.green); etiqueta.setBackground(Color.white); etiqueta.setOpaque(true); etiqueta.setFont(new Font("SansSerif", Font.BOLD, 24)); etiqueta.setPreferredSize(new Dimension(80,45)); //panel con borde que va a contener la etiqueta JPanel etiquetaPanel = new JPanel(new BorderLayout()); etiquetaPanel.add(etiqueta, BorderLayout.CENTER); etiquetaPanel.setBorder(BorderFactory.createTitledBorder("etiqueta")); getContentPane().add(etiquetaPanel, BorderLayout.CENTER); } public void creaBoton(){ JPanel panel=new JPanel(); panel.setLayout(new FlowLayout()); boton=new JButton("Selección de color"); panel.add(boton); boton.addActionListener(this); getContentPane().add(panel,BorderLayout.SOUTH); } public void actionPerformed(ActionEvent evento) { Color color=JColorChooser.showDialog(this,"Selecciona un color", etiqueta.getForeground()); if (color!=null) etiqueta.setForeground(color); } public static void main(String[] args) { DialogoSelectorColor ventana = new DialogoSelectorColor(); ventana.creaEtiqueta(); ventana.creaBoton(); ventana.setSize(400,180); ventana.setVisible(true); } } Código fuente 160

El nuevo aspecto de nuestro ejemplo se muestra en la Figura 103.

Figura 103

Y al pulsar el botón de selección de color aparece la Figura 104.

251

Programación en Java

© Grupo EIDOS

Figura 104

Si el usuario cancela la selección de color, ya sea cerrando el diálogo o pulsando el botón de cancelación, no se devolverá ningún color, sino que se devolverá el valor null (nulo). En la figura 18 se puede observar que además de los botones OK y Cancel aparece el botón Reset, al pulsar este botón el color seleccionado actualmente en el diálogo será el que se había indicado inicialmente, es decir, el color que se indica en el método showDialog().

JFileChooser Este es el último componente atómico de Swing que vamos a ver. El componente JFileChooser es similar al visto anteriormente, podemos crearlo como un componente más y añadirlo a un panel o bien mostrarlo como un diálogo modal. Este componente nos permite navegar por el sistema de ficheros y seleccionar un fichero o directorio. Normalmente se utilizan estos componentes como diálogos modales. Pero la clase JFileChooser únicamente muestra el interfaz que nos permite seleccionar los ficheros, pero el tratamiento de los mismos corre de nuestra cuenta, es decir, el tratamiento de los ficheros debemos implementarlo en nuestra aplicación. La clase JFileChooser ofrece dos métodos para mostrar los dos tipos de selectores de ficheros distintos, el que se utiliza para abrir ficheros y el que se utiliza para grabar ficheros, estos métodos son showOpenDialog() y showSaveDialog(). Ambos métodos reciben como argumento un objeto Component que representa el padre del diálogo de selección de ficheros. Estos métodos no son estáticos como ocurría con el componente ColorChooser, sino que se deben lanzar sobre una instancia de la clase JFileChooser. 252

© Grupo EIDOS

12. Interfaces de usuario en Java: componentes atómicos de Swing

Tanto el método showOpenDialog() como showSaveDialog() devuelven un valor entero que se corresponde con las constantes que indican el resultado de la selección del usuario, indican si el usuario a pulsado el botón de cancelación (CANCEL_OPTION) o no (APPROVE_OPTION), ambas constantes de encuentran definidas en la clase JFileChooser. El aspecto que muestra el diálogo para la apertura de fichero es muy similar al del diálogo para guardar ficheros. A continuación vamos a mostrar un sencillo ejemplo que posee dos botones y un área de texto (JTextArea), según el botón que se pulse se mostrará un diálogo de selección de ficheros distinto, para abrir ficheros y para guardar ficheros. En el área de texto se irán mostrando las selecciones de ficheros o cancelaciones realizadas por el usuario. El código fuente completo es el Código fuente 161.

import import import import public

java.awt.*; java.awt.event.*; javax.swing.*; java.io.*; class DialogoSelectorFichero extends JFrame implements ActionListener{ private JTextArea resultado; private JButton botonAbrir; private JButton botonGuardar; private JFileChooser selectorFichero; public DialogoSelectorFichero() { super("Diálogo para la selección de ficheros"); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); selectorFichero=new JFileChooser(); }

public void creaBotones(){ ImageIcon iconoAbrir = new ImageIcon("abrir.gif"); botonAbrir=new JButton("Abrir un fichero...", iconoAbrir); ImageIcon iconoGuardar = new ImageIcon("guardar.gif"); botonGuardar=new JButton("Guardar un fichero...", iconoGuardar); botonAbrir.addActionListener(this); botonGuardar.addActionListener(this); JPanel panelBotones=new JPanel(); panelBotones.add(botonAbrir); panelBotones.add(botonGuardar); getContentPane().add(panelBotones,BorderLayout.NORTH); } public void creaResultado(){ resultado = new JTextArea(5,20); resultado.setMargin(new Insets(5,5,5,5)); resultado.setEditable(false); JScrollPane panelResultado = new JScrollPane(resultado); getContentPane().add(panelResultado,BorderLayout.CENTER); } public void actionPerformed(ActionEvent evento) { if (evento.getSource()==botonAbrir){ int valorDevuelto= selectorFichero.showOpenDialog(this); if (valorDevuelto== JFileChooser.APPROVE_OPTION) { File fichero = selectorFichero.getSelectedFile(); resultado.append("Abierto: " + fichero.getName()+"\n"); } else resultado.append("Apertura cancelada por el usuario\n"); }else{ int valorDevuelto= selectorFichero.showSaveDialog(this);

253

Programación en Java

© Grupo EIDOS

if (valorDevuelto== JFileChooser.APPROVE_OPTION) { File fichero = selectorFichero.getSelectedFile(); resultado.append("Guardado: " + fichero.getName()+"\n"); } else resultado.append("Operación de grabado cancelada"+ "por el usuario\n"); } } public static void main(String[] args) { DialogoSelectorFichero ventana = new DialogoSelectorFichero(); ventana.creaBotones(); ventana.creaResultado(); ventana.pack(); ventana.setVisible(true); } } Código fuente 161

El aspecto de nuestra ventana es el de la Figura 105.

Figura 105

Y la del diálogo de selección de ficheros para su apertura, es la Figura 106.

Figura 106

254

© Grupo EIDOS

12. Interfaces de usuario en Java: componentes atómicos de Swing

Como se puede comprobar en el ejemplo, para obtener el fichero que se ha seleccionado se utiliza el método getSelectedFile(), que devuelve un objeto de la clase File. A través de este objeto podemos manipular ficheros, en una aplicación real se utilizaría para guardar o abrir ficheros. El constructor de la clase JFileChooser puede recibir como argumento un objeto File o String para indicar el directorio inicial. El directorio inicial también se puede especificar mediante el método setCurrentDirectory() al que se le pasa como argumento un objeto de la clase File. Cada vez que se muestra el diálogo para la selección de ficheros guarda el directorio actual de la selección anterior, es decir, va recordando las rutas de las selecciones anteriores. Además permite la creación de nuevos directorios. Este ha sido el componente Swing atómico que cierra este capítulo, en el siguiente capítulo trataremos el nuevo gestor de diseño de Swing y la característica Pluggable Look & Feel.

255

Interfaces de usuario en Java: otras características de Swing Introducción Este capítulo cierra el ciclo de capítulos dedicado a Swing, este capítulo no va a ser tan extenso como los anteriores ya que trataremos dos aspectos muy determinados, el nuevo gestor de diseño de Swing, representado por la clase BoxLayout y la característica especial que ofrece Swing denominada Pluggable Look & Feel.

El gestor de diseño BoxLayout La clase BoxLayout, que podemos encontrar en el paquete javax.swing, representa a un nuevo gestor de diseño ofrecido por Swing. Este gestor de diseño organiza los componentes en una pila, uno encima del otro y también de izquierda a derecha uno al lado del otro. Se puede decir que es una versión ampliada del gestor de diseño FlowLayout que ofrece AWT. Antes de seguir comentando este gestor de diseño ofrecido por Swing, vamos a ver con un sencillo ejemplo la forma en la que distribuye los componentes en el panel al que se aplica. El código fuente de este ejemplo es el Código fuente 162.

Programación en Java

© Grupo EIDOS

import javax.swing.*; import java.awt.event.*; public class BoxLayoutSencillo{ public static void main(String s[]) { JFrame ventana = new JFrame("Ventana con BoxLayout"); ventana.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); JPanel panelContenido=new JPanel(); panelContenido.setLayout(new BoxLayout(panelContenido,BoxLayout.Y_AXIS)); panelContenido.add(new JButton("Soy un botón")); panelContenido.add(new JButton("Soy un botón más")); panelContenido.add(new JButton("Otro botón")); panelContenido.add(new JButton("Soy el último")); ventana.setContentPane(panelContenido); ventana.pack(); ventana.setVisible(true); } } Código fuente 162

Y el aspecto que ofrece es el de la Figura 107.

Figura 107

En el ejemplo anterior podemos comprobar la forma de crear un gestor de diseño para distribuir los componentes de arriba a abajo. El constructor de la clase BoxLayout posee dos argumentos, el panel (JPanel) sobre el que se va a aplicar el gestor de diseño y la orientación en la que se van a distribuir los componentes dentro de dicho panel. Este último parámetro es un entero que se corresponde con las siguientes constantes definidas en la clase BoxLayout: •

X_AXIS: los componentes se distribuyen de izquierda a derecha.



Y_AXIS: los componentes se distribuyen de arriba a abajo.

Si retomamos el ejemplo anterior y cambiamos la constante BoxLayout.Y_AXIS por BoxLayout.X_ AXIS, se obtiene el resultado que muestra la Figura 108.

Figura 108

258

© Grupo EIDOS

13. Interfaces de usuario en Java: otras características de Swing

Conjuntamente con la clase BoxLayout, se suele utilizar la clase Box, esta clase ofrece una serie de métodos para controlar de una forma más precisa la forma en la que se distribuyen los componentes dentro de un panel al que se le ha aplicado este gestor de diseño BoxLayout. En el Código fuente 163 se pueden ver en acción dos de estos métodos, que son métodos estáticos de la clase Box.

import import import public

javax.swing.*; java.awt.event.*; java.awt.*; class DosBoxLayout{ public static void main(String s[]) { JFrame ventana = new JFrame("Ventana con BoxLayout"); ventana.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); JPanel panelSuperior=new JPanel(); panelSuperior.setBorder(BorderFactory.createLineBorder(Color.red)); panelSuperior.setLayout(new BoxLayout(panelSuperior,BoxLayout.Y_AXIS)); panelSuperior.add(new JLabel("Esto es una etiqueta")); panelSuperior.add(Box.createRigidArea(new Dimension(0,5))); panelSuperior.add(new JTextArea(5,30)); JPanel panelInferior=new JPanel(); panelInferior.setBorder(BorderFactory.createLineBorder(Color.green)); panelInferior.setLayout(new BoxLayout(panelInferior,BoxLayout.X_AXIS)); panelInferior.add(Box.createHorizontalGlue()); panelInferior.add(new JButton("Botón 1")); panelInferior.add(Box.createRigidArea(new Dimension(10,0))); panelInferior.add(new JButton("Botón 2")); ventana.getContentPane().add(panelSuperior,BorderLayout.NORTH); ventana.getContentPane().add(panelInferior,BorderLayout.CENTER); ventana.pack(); ventana.setVisible(true); } } Código fuente 163

El interfaz que genera este código es el de la Figura 109.

Figura 109

259

Programación en Java

© Grupo EIDOS

A la vista del código se puede decir que este interfaz está compuesto por dos paneles los que se han aplicado un gestor de diseño BoxLayout distinto, uno de arriba a abajo y otro de izquierda a derecha. Se ha aplicado un borde a cada uno de estos dos paneles para distinguirlos más claramente. En el primer panel se ha utilizado el método createRigidArea() de la clase Box para crear una separación fija (área rígida) invisible entre la etiqueta (JLabel) y el área de texto (JTextArea). En este caso se ha indicado una separación vertical de cinco pixels. En el segundo panel se utiliza otro método de la clase Box, el método createHorizontalGlue(), este método provoca que los dos botones que se añadan a continuación se desplacen hacia la derecha, es decir, este método rellena el espacio sobrante y desplaza a los componentes hacia la derecha. El método createHorizontalGlue() crea un área invisible que crece horizontalmente para rellenar todo el espacio libre disponible dentro del contenedor. En este panel inferior también se utiliza el método createRigidArea() para separar los dos botones diez pixels, en este caso se ha utilizado un área sólo con componente horizontal. Si la llamada al método createHorizontalGlue() la hubiéramos realizado en el lugar en la que se encuentra la llamada al método createRigidArea(), el resultado hubiera sido la Figura 110.

Figura 110

A la vista de la imagen se puede decir que el área se ha extendido entre los dos botones, enviando al segundo botón a la derecha del todo. La clase Box ofrece también el método createVerticalGlue(), en este caso el área invisible se extiende de forma vertical enviando los componentes dentro del panel hacia la zona inferior. El gestor de diseño BoxLayout respeta el tamaño máximo de los componentes que contiene y también la alineación establecida por los mismos, aunque para que no existan problemas de alineación todos los componentes deben tener la misma. Si modificamos el primer ejemplo visto en este apartado como indica el Código fuente 164, se obtiene la Figura 111.

import java.awt.event.*; import java.awt.*; public class BoxLayoutSencillo{ public static void main(String s[]) { JFrame ventana = new JFrame("Ventana con BoxLayout"); ventana.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); JPanel panelContenido=new JPanel();

260

© Grupo EIDOS

13. Interfaces de usuario en Java: otras características de Swing

JButton boton1=new JButton("Soy un botón"); boton1.setAlignmentX(Component.CENTER_ALIGNMENT); JButton boton2=new JButton("Soy un botón más"); JButton boton3=new JButton("Otro botón"); boton3.setAlignmentX(Component.RIGHT_ALIGNMENT); JButton boton4=new JButton("Soy el último"); boton4.setAlignmentX(Component.CENTER_ALIGNMENT); panelContenido.setLayout(new BoxLayout(panelContenido,BoxLayout.Y_AXIS)); panelContenido.add(boton1); panelContenido.add(boton2); panelContenido.add(boton3); panelContenido.add(boton4); ventana.setContentPane(panelContenido); ventana.pack(); ventana.setVisible(true); } } Código fuente 164

Figura 111

La alineación se respetará en este otro ejemplo.

import import import public

javax.swing.*; java.awt.event.*; java.awt.*; class BoxLayoutSencillo{ public static void main(String s[]) { JFrame ventana = new JFrame("Ventana con BoxLayout"); ventana.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); JPanel panelContenido=new JPanel(); JButton boton1=new JButton("Soy un botón"); boton1.setAlignmentX(Component.CENTER_ALIGNMENT); JButton boton2=new JButton("Soy un botón más"); boton2.setAlignmentX(Component.CENTER_ALIGNMENT); JButton boton3=new JButton("Otro botón"); boton3.setAlignmentX(Component.CENTER_ALIGNMENT); JButton boton4=new JButton("Soy el último"); boton4.setAlignmentX(Component.CENTER_ALIGNMENT); panelContenido.setLayout(new BoxLayout(panelContenido,BoxLayout.Y_AXIS)); panelContenido.add(boton1); panelContenido.add(boton2); panelContenido.add(boton3); panelContenido.add(boton4);

261

Programación en Java

© Grupo EIDOS

ventana.setContentPane(panelContenido); ventana.pack(); ventana.setVisible(true); } } Código fuente 165

Cuyo resultado es la Figura 112.

Figura 112

Estableciendo el Look & Feel En el capítulo anterior comentábamos que una característica que ofrece Swing es el aspecto y comportamiento configurable de sus componentes, lo que se denomina Pluggable Look & Feel, es decir, a nuestra aplicación Java le podemos asignar un aspecto específico. Incluso, como veremos un poco más adelante, podemos establecer y cambiar en tiempo de ejecución de nuestra aplicación su Look & Feel. Cuando no se indica ningún Look & Feel determinado Swing utiliza el Look & Feel por defecto, que es el Look & Feel de Java, también denominado Metal (fue el código que se le dio al proyecto que lo desarrolló). Se pueden distinguir cuatro Look & Feel estándar distintos:

262



Java (Metal): se trata del Look & Feel por defecto y es el que se ha estado utilizando en todos los ejemplos de los componentes Swing, ya que en nuestros ejemplos no hemos especificado ningún Look & Feel. Se corresponde con la implementación de la clase javax.swing.plaf.metal.MetalLookAndFeel. Este Look & Feel lo podemos utilizar en cualquier plataforma.



Windows: es aspecto que presentan los sistemas Windows y lo encontramos implementado en la clase com.sun.java.swing.plaf.windows.WindowsLookAndFeel. A diferencia del anterior Look & Feel, éste únicamente puede ser utilizado en plataformas Windows.



Motif: representa el aspecto CDE/Motif, que es el aspecto que tienen las plataformas de Sun. Este Look & Feel es implementado por la clase com.sun.java.swing.plaf.motif.MotifLookAndFeel, y al igual que el Look & Feel de Java puede ser utilizado en cualquier plataforma.



Mac: este último Look & Feel es el correspondiente a los sistemas Macintosh. Se encuentra en al clase javax.swing.plaf.mac.MacLookAndFeel. Al igual que ocurría con el Look & Feel de Windows, este Look & Feel está restringido a una plataforma específica, esta plataforma es la plataforma Mac OS.

© Grupo EIDOS

13. Interfaces de usuario en Java: otras características de Swing

Todas estas clases que implementan un Look & Feel determinado, tienen la característica común que todas ellas heredan de la clase abstracta javax.swing.LookAndFeel. Para indicar un Look & Feel determinado en una aplicación Java utilizaremos la clase UIManager (gestor de interfaz gráfico) que se encuentra en el paquete javax.swing. La clase UIManager ofrece un método estático llamado setLookAndFeel(), que recibe como parámetro una cadena que especifica la clase que se corresponde con el Look & Feel que deseamos asignar a nuestra aplicación Java. El método setLookAndFeel() de la clase UIManager lanza una excepción de la clase UnsupportedLookAndFeelException, que se encuentra también dentro del paquete javax.swing, cuando el Look & Feel que queremos utilizar no es soportado por la plataforma actual, deberemos atrapar por lo tanto esta excepción cuando invoquemos el método setLookAndFeel(). De esta forma si queremos que nuestra aplicación posea el Look & Feel de Motif deberemos incluir el Código fuente 166 dentro del método main() de la aplicación.

try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); } catch (Exception e) { } new AplicacionSwing(); Código fuente 166

Pero el Look & Feel, como ya hemos adelantado al comienzo de este apartado, se puede establecer una vez que la aplicación ya se ha iniciado y el interfaz de usuario es visible, es decir, podemos establecer el Look & Feel de la aplicación en tiempo de ejecución. En este caso además de utilizar el método setLookAndFeel() de la clase UIManager, deberemos utilizar el método estático updateComponentTreeUI() de la clase SwingUtilities, presente también en el paquete javax.swing. El método updateComponentTreeUI() recibe como argumento un objeto de la clase Component que representa el contenedor de alto nivel sobre el que se quiere actualizar su Look & Feel. El método updateComponentTreeUI() de la clase SwingUtilities debe utilizarse para cada uno de los contenedores de alto nivel del interfaz de usuario de la aplicación, para que de esta forma todos actualicen su Look & Feel en tiempo de ejecución. Además es recomendable lanzar el método pack() sobre cada uno de los contenedores de alto nivel del interfaz de usuario, para que se redimensionen todos los componentes según su nuevo Look & Feel. La utilización de este método, conjuntamente con el método setLookAndFee() se puede ver en el Código fuente 167.

try { UIManager.setLookAndFeel(lf); SwingUtilities.updateComponentTreeUI(contenedor); this.pack(contenedor); } catch (Exception excepcion) { System.out.println("No se pudo asignar el Look & Feel"); } Código fuente 167

En este caso se supone que sólo existe un contenedor de alto nivel. 263

Programación en Java

© Grupo EIDOS

La clase UIManager, además del método setLookAndFeel(), nos ofrece otros dos métodos que pueden resultar de utilidad, estos métodos son getSystemLookAndFeelClassName() y getCrossPlatformLooAndFeelClassName(). Ambos métodos devuelven una cadena, en el primer caso se corresponde con el nombre de la clase del Look & Feel de la plataforma sobre la que se está ejecutando la aplicación, y el segundo caso se corresponde con el nombre de la clase que ofrece el Look & Feel de Java, que es el Look & Feel que se garantiza funcionará correctamente para todas las plataformas. Por lo tanto estos dos métodos se pueden utilizar como argumento para el método setLookAndFeel(), así por ejemplo si deseamos aplicar el Look & Feel de la plataforma sobre la que se ejecuta la aplicación, utilizaríamos el Código fuente 168.

try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { } Código fuente 168

Para mostrar la característica Pluggable Look & Feel de Swing se va a utilizar un sencillo ejemplo que consiste una aplicación con una ventana (JFrame) que permite especificar el Look & Feel en tiempo de ejecución. LA ventana de la aplicación del ejemplo, además de contener diversos componentes Swing, contiene cinco botones de opción (JOptionButton) agrupados, y que al seleccionar cada uno de ellos se aplicará sobre la aplicación el Look & Feel que representa cada opción. Es decir, existen cinco botones de opción, cuatro de ellos para cada uno de los distintos Look & Feel (Java, Windows, Motif y Mac) y otro para seleccionar el Look & Feel de la plataforma sobre la que se ejecuta la aplicación. Antes de seguir comentando más detalles de esta aplicación de ejemplo, vamos a mostrar el aspecto que tendría esta aplicación. Al ejecutar la aplicación el aspecto que muestra es el de la Figura 113, y se corresponde con el Look & Feel de Java.

Figura 113

264

© Grupo EIDOS

13. Interfaces de usuario en Java: otras características de Swing

Al iniciarse su ejecución dentro del constructor de la aplicación, se establece el Look & Feel mediante el nombre de la clase devuelto por el método getCrossPlatformLookAndFeelClassName() de la clase UIManager, debido a esto al arrancar la aplicación comienza a ejecutarse utilizando el Look & Feel de Java. El código fuente perteneciente al constructor de nuestra clase se puede observar en el Código fuente 169.

public LF(){ super("Pluggable Look & Feel"); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); try { UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); } catch (Exception e) { } getContentPane().setLayout(new BoxLayout(getContentPane(),BoxLayout.Y_AXIS)); } Código fuente 169

En el constructor además de establecer el Look & Feel de Java se establece el gestor de diseño que va a utilizar el panel de contenido de la ventana. El gestor de diseño que se utiliza es BoxLayout, descrito en el apartado anterior, en su variante de distribución de componentes de arriba a abajo (BoxLayout.Y_AXIS). De la figura anterior también se puede comprobar que la opción seleccionada por defecto se corresponde lógicamente con el Look & Feel que presenta la aplicación inicialmente. Podemos ir asignando a la aplicación los distintos Look & Feel seleccionando la opción correspondiente. A continuación se muestran otras dos figuras, cada una con otro nuevo Look & Feel. La primera corresponde al Look & Feel de Windows y la segunda al Look & Feel de Motif.

Figura 114

265

Programación en Java

© Grupo EIDOS

Figura 115

En mi caso no he podido utilizar el Look & Feel de Mac, ya que he utilizado una plataforma Windows para ejecutar la aplicación de ejemplo, por lo tanto éste Look & Feel no estará disponible, y además en mi caso particular el Look & Feel del sistema (Look & Feel de la plataforma actual) será por lo tanto el de Windows. No vamos hacer como en otros ejemplos de este curso, en los que se ha ofrecido el código completo del ejemplo, sólo vamos a mostrar y comentar aquellos fragmentos que resultan más interesantes (sobre todo desde el punto de vista de la característica Pluggable Look & Feel), ya que el código fuente de la aplicación de ejemplo es bastante sencillo y se utilizan componentes Swing vistos en los capítulos anteriores. Empezamos ofreciendo la declaración de nuestra clase (Código fuente 170).

public class LF extends JFrame implements ActionListener{ Código fuente 170

Como se puede ver es una sencilla ventana que va a contener una serie de componentes Swing. No vamos a detenernos en la creación de los distintos componentes del interfaz de usuario, pero si que es interesante mostrar como se crean las opciones que permiten seleccionar el Look & Feel de la aplicación. Para crear las opciones que representan los distintos LooK & Feel se ha utilizado el método creaOpciones(), cuyo código ofrecemos en el Código fuente 171.

public void creaOpciones(){ panelOpciones=new JPanel(); panelOpciones.setLayout(new GridLayout(1,5,5,5)); opWindows=new JRadioButton("Windows"); opWindows.setMnemonic(KeyEvent.VK_W);

266

© Grupo EIDOS

13. Interfaces de usuario en Java: otras características de Swing

opWindows.addActionListener(this); panelOpciones.add(opWindows); opJava=new JRadioButton("Java/Metal"); opJava.setMnemonic(KeyEvent.VK_J); opJava.addActionListener(this); panelOpciones.add(opJava); opJava.setSelected(true); opMotif=new JRadioButton("Motif"); opMotif.setMnemonic(KeyEvent.VK_M); opMotif.addActionListener(this); panelOpciones.add(opMotif); opMac=new JRadioButton("Mac"); opMac.setMnemonic(KeyEvent.VK_C); opMac.addActionListener(this); panelOpciones.add(opMac); opSistema=new JRadioButton("Sistema"); opSistema.setMnemonic(KeyEvent.VK_S); opSistema.addActionListener(this); panelOpciones.add(opSistema); panelOpciones.setBorder(BorderFactory.createLoweredBevelBorder()); //se agrupan las opciones ButtonGroup grupo=new ButtonGroup(); grupo.add(opWindows); grupo.add(opJava); grupo.add(opMotif); grupo.add(opMac); grupo.add(opSistema); getContentPane().add(panelOpciones); } Código fuente 171

La pulsación de cada opción será tratada dentro del método actionPerformed() que realmente, conjuntamente con el constructor de la clase, es dónde utilizamos métodos y clases relacionados directamente con el mecanismo Pluggable Look & Feel. A continuación se ofrece el código fuente perteneciente al método actionPerformed(). Será en este método dónde se establezca el Look & Feel seleccionado a través de los distintos botones de opción.

public void actionPerformed(ActionEvent evento){ Object fuente=evento.getSource(); String lf=""; if (fuente==opWindows) lf="com.sun.java.swing.plaf.windows.WindowsLookAndFeel"; else if(fuente==opJava) lf="javax.swing.plaf.metal.MetalLookAndFeel"; else if(fuente==opMotif) lf="com.sun.java.swing.plaf.motif.MotifLookAndFeel"; else if(fuente==opMac) lf="javax.swing.plaf.mac.MacLookAndFeel"; else if(fuente==opSistema) lf=UIManager.getSystemLookAndFeelClassName(); try { UIManager.setLookAndFeel(lf); SwingUtilities.updateComponentTreeUI(this); this.pack(); } catch (UnsupportedLookAndFeelException excepcion) { texto.append("Look & Feel no soportado.\n"+excepcion+"\n"); } catch (ClassNotFoundException excepcion){

267

Programación en Java

© Grupo EIDOS

texto.append("Clase no encontrada.\n"+excepcion+"\n"); } catch (InstantiationException excepcion){ texto.append("Excepción de instanciación.\n"+excepcion+"\n"); } catch(IllegalAccessException e){ texto.append("Excepción de acceso.\n"+e+"\n"); } } Código fuente 172

Como se puede comprobar a la vista del código anterior, se decidimos atrapar la excepción UnsupportedLookAndFeelException, se nos obligará a atrapar tres excepciones más. Por lo demás, si se tiene en cuenta lo explicado hasta el momento, el código de este método es bastante sencillo, lo único que se hace es establecer el Look & Feel que se corresponde con la opción pulsada. Si ocurre una excepción se muestra en el área de texto (JTextArea) de la aplicación. Si en mi caso particular, utilizando una plataforma Windows, selecciono la opción correspondiente al Look & Feel de Mac, obtendré una excepción lanzada por el método setLooAndFeel(), esto se puede observar en la Figura 116.

Figura 116

El fichero fuente de Java perteneciente a este ejemplo se puede obtener aquí. Con este apartado damos por terminado la construcción de interfaces en Java y también los componentes Swing, aunque en uno de los capítulos dedicados a los applets volveremos a tratar un componente Swing, el contenedor de alto nivel representado por la clase JApplet. Como se habrá podido comprobar Swing es bastante extenso y potente, tan extenso que sería posible dedicar un curso completo dedicado a Swing. Con estos tres capítulos hemos pretendido mostrar los aspectos más destacados de Swing, sin tener la intención de abarcar todo, ya que como hemos dicho nos dará para un curso completo más. En el siguiente capítulo comenzaremos a ver el otro tipo de aplicaciones que podemos realizar con Java, los applets.

268

Applets de Java: introducción a los Applets Conceptos previos A lo largo del presente capítulo vamos a hacer referencia a una serie de términos relacionados con los applets de Java que conviene tener claros, por ello hemos incluido este apartado, muchos de estos conceptos pueden que sean conocidos para todos, pero es mejor partir de una serie de definiciones que compartamos todos.

Internet Internet es un conjunto de redes cuyo origen se remonta al año 1969 en Estados Unidos. En un principio Internet se creó con fines militares durante La Guerra Fría. Era un proyecto del Departamento de Defensa de Estados Unidos. En un principio este proyecto se denominó ARPANET (Advanced Research Projects Agency-ARPA). El objetivo para el que se había creado el proyecto era mantener una infraestructura robusta de diferentes ordenadores conectados entre sí. Si se suprimía algún nodo de la red, la red debería seguir funcionando, es decir, no existía ningún nodo central o principal. Estas características son debidas al origen militar de la red, de esta forma, si algunas de las partes de la red se destruían debido a un ataque militar, el resto de la red puede seguir funcionando.

Programación en Java

© Grupo EIDOS

De este inicio militar Internet paso a ser utilizado dentro del campo académico, se utilizaba en universidades para proyectos de investigación. Del ámbito académico Internet pasó a ser de dominio público, para todo tipo de actividades, culturales, comerciales, lúdicas, filosóficas, etc. La fama y popularidad de Internet se consiguió y llegó a través de la World Wide Web. La Web o la Gran Telaraña Mundial se basa en el protocolo de Transferencia de Hipertexto HTTP (Hypertext Transport Protocol). La Web nació en el CERN (European Center for Nuclear Research) de la mano de Tim Berners-Lee como intento de crear un sistema hipermedia, basado en enlaces hipertextuales, para la compartición de información científica entre los integrantes del laboratorio del CERN, de una manera clara y sencilla aprovechando los recursos que ofrecía Internet en aquella época. A finales de 1995 la Web se había convertido en el servicio más solicitado y famoso de Internet.

URLs y direcciones IP Una URL (Uniform Resource Locator) es el mecanismo que se utiliza en Internet para localizar e identificar de forma única un recurso dentro de Internet. La sintaxis general de una URL se compone de tres partes: protocolo:/// El campo protocolo especifica el protocolo de Internet que se va a utilizar para transferir los datos del recurso entre el cliente y el servidor. Existen varios protocolos en Internet como pueden ser: FTP (File Transfer Protocolo) para la transferencia de ficheros; HTTP (HyperText Transfer Protocol) protocolo para la transferencia de hipertexto; Telnet, Gopher, etc. A continuación del protocolo aparece los dos puntos (:), la doble barra (//) y el nombre del dominio. El nombre del dominio es la forma de identificar una máquina de forma única en Internet, este nombre de dominio puede ser la dirección IP, en el formato de tétrada punteada (201.234.123.87) o bien su traducción correspondiente a un nombre más descriptivo, como puede ser www.eidos.es. Una dirección IP es un número de 32 bits para identificar de forma única una máquina conectada a Internet. Se divide en grupos de 8 bits y se identifica con su número en notación decimal separado cada uno de ellos por puntos, a este formato se le denomina tétrada punteada. Debido a que recordar direcciones IP puede ser difícil y poco manejable se suelen identificar con nombres de máquinas, así la dirección IP 206.26.48.100 se corresponde con el nombre de la máquina java.sun.com que resulta más fácil de recordar y significativo. Un mismo nombre puede tener diferentes direcciones IP, en Internet esta correspondencia entre direcciones IP y nombres la gestionan servidores de nombres que se encargan de traducir los nombres fáciles de recordar a sus direcciones de 32 bits. Acompañando el nombre del dominio puede aparecer precedido de dos puntos un número de puerto. Los números de puerto se utilizan para identificar de forma única los distintos procesos dentro de una máquina en la red. A cada servidor se le asigna un número de puerto conocido. El rango del número de puerto es 0-65535, ya que se trata de números de 16 bits, los números de puerto del rango 0-1023 se encuentran restringidos ya que se utilizan para servicios conocidos como pueden ser HTTP

270

© Grupo EIDOS

14. Applets de Java: introducción a los Applets

(HyperText Transfer Protocol) en el puerto 80, FTP (File Transfer Protocol) en el puerto 21, telnet en el puerto 23 y otros servicios del sistema. Cada dirección IP es un conjunto de puertos a los que los clientes se pueden conectar a través de Internet. La última parte de la URL indica dónde se encuentra localizado el recurso dentro del servidor, es decir, es el camino del fichero demandado en la URL. El servidor verificará esta parte de la URL para identificar que página HTML, imagen, directorio o aplicación se está demandando. Cada elemento que forma el camino del recurso se para con una barra (/).

Clientes y Servidores Web La arquitectura Cliente/Servidor podemos verla como una forma de abordar los problemas. Dentro de la red el sistema cliente es la estación de trabajo y el servidor es una versión de mayor tamaño capaz de almacenar gran cantidad de datos y ejecutar grandes aplicaciones. Cuando un ordenador se comunica con otro a través de Internet, en dicha comunicación se usa el modelo cliente/servidor. Los recursos de Internet los proporcionan unas máquinas denominadas servidores, que dan el servicio a las peticiones de los clientes. Los clientes son los ordenadores que acceden a estos recursos a través de aplicaciones cliente. Básicamente, un servidor atiende y trata peticiones de varios clientes. En el entorno de Internet la arquitectura cliente/servidor es bastante común y se encuentra muy extendida. Normalmente un servidor se ejecuta un una máquina diferente de la del cliente, aunque no siempre es así. La interacción entre cliente y servidor normalmente comienza en el lado del cliente. El cliente realiza una petición de un objeto o transacción del servidor, el servidor deberá tratar la petición o denegarla. Si la petición es tratada, el objeto se le enviará al cliente. En el entorno de la World Wide Web los servidores se denominan servidores Web y los clientes se denominan navegadores Web. Un servidor Web es el encargado de publicar o poner a disposición de una serie de clientes unos recursos. Estos recursos pueden variar desde una página HTML a un script CGI para la consulta de una tabla en una base de datos, o bien desde una página HTML con diferentes applets a una página ASP que realiza el mantenimiento de una tabla, o incluso un servicio de correo. A la hora de pensar en un servidor Web no debemos limitar sus funciones a la del servicio Web propiamente dicho, es decir, a la publicación de páginas HTML. Los navegadores Web realizan peticiones de documentos que se encuentran en servidores Web, permitiendo así visualizar los documentos de la World Wide Web. Algunos de los clientes más populares son Netscape Navigator y Microsoft Internet Explorer. El proceso de visualización de un documento en la Web comienza cuando el navegador Web envía una petición al servidor Web. El navegador Web envía información, sobre sí mismo y sobre el fichero que está demandando, al servidor Web en cabeceras de petición del protocolo HTTP. El servidor Web recibe y consulta las cabeceras HTTP para obtener toda información relevante, tal como el nombre del fichero que se indica en la petición, y envía el fichero con las cabeceras de

271

Programación en Java

© Grupo EIDOS

respuesta del protocolo HTTP. Entonces el navegador Web utiliza las cabeceras de respuesta HTTP para determinar como mostrar o tratar el fichero que le envía el servidor Web.

HTML HTML es la abreviatura de HyperText Markup Language , y es el lenguaje que todos los programas navegadores usan para presentar información en la World Wide Web (WWW). Este es un lenguaje muy sencillo que se basa en el uso de etiquetas, consistentes en un texto ASCII encerrado dentro de un par de paréntesis angulares(). El texto incluido dentro de los paréntesis nos dará una explicación de la utilidad de la etiqueta. Así por ejemplo la etiqueta

nos permitirá definir una tabla. Las etiquetas podrán incluir una serie de atributos o parámetros, en su mayoría opcionales, que nos permitirán definir diferentes posibilidades o características de la misma. Estos atributos quedarán definidos por su nombre (que será explicativo de su utilidad) y el valor que toman separados por un signo de igual. En el caso de que el valor que tome el atributo tenga más de una palabra deberá expresarse entre comillas, en caso contrario no será necesario. Así por ejemplo la etiqueta
nos permitirá definir una tabla con borde de tamaño 2. Entre otras cosas, el manejo de estas etiquetas nos permitirá: •

Definir la estructura lógica del documento HTML.



Aplicar distintos estilos al texto (negrita, cursiva, ...).



La inclusión de hiperenlaces, que nos permitirán acceder a otros documentos relacionados con el actual.



La inclusión de imágenes y ficheros multimedia (gráficos, vídeo, audio).

HTTP Como ya se ha comentado anteriormente, el protocolo HTTP (HiperText Transfer Protocol) es el utilizado para la transferencia de hipertexto entre el servidor Web y el navegador.

Introducción a los applets de Java Una vez comentados una serie de conceptos relacionados con los applets de Java, vamos a pasar a tratar los applets propiamente dichos. Como ya sabrá el lector a estas alturas, los programas Java comprenden dos grupos principales: applets y aplicaciones. Un applet es un programa dinámico e interactivo que se ejecuta dentro de una página Web, desplegada por un navegador con capacidad para Java como puede ser los navegadores Navigator de Netscape o el Internet Explorer de Microsoft, por lo tanto los applets para ejecutarse dependen de un navegador Web que soporte para Java. Los applets es uno de los principales motivos que han hecho al lenguaje Java tan popular.

272

© Grupo EIDOS

14. Applets de Java: introducción a los Applets

Un applet es un objeto dentro de la jerarquía de clases de Java, es una subclase de la clase Panel, y se encuentra en el paquete java.applet, este paquete además de contener la clase Applet contiene tres interfaces AudioClip, AppletStub y AppletContext. Para poder incluir un applet dentro de una página Web, se deben seguir los siguientes pasos: después de crear una clase con el applet y compilarla dando como resultado un archivo de clase (.CLASS), se debe crear una página Web que contenga al applet, para ello se debe hacer uso del lenguaje HTML (HyperText Markup Language) que dispone de una serie de etiquetas especiales para incluir applets en las páginas Web. Estas etiquetas las comentaremos en el apartado correspondiente dentro de este mismo capítulo. Después de tener un applet y la página Web que hace referencia al mismo, se debe hacer disponible para la World Wide Web. Los applets Java se pueden colocar en un servidor Web de la misma manera que los archivos HTML, no se necesita software de servidor especial para hacer los applets disponibles en la Web, todo lo que se necesita es ubicar el fichero HTML y los archivos de clase compilados del applet en el servidor Web, también se deberán incluir junto al fichero .class del applet, todos los ficheros de clase que utilice el applet y que no se encuentren dentro las clases estándar de Java contenidas en de la Máquina Virtual. Cuando un navegador Web se dispone a visualizar una página Web que contiene un applet o varios, el navegador carga además de la clase, en la que se encuentra el applet, todas las clases que utilice el mismo, y se ejecuta en la máquina local del cliente; a partir de ahora cada vez que se haga referencia a la "máquina local", se está hablando de la máquina dónde se ejecuta el navegador y carga el applet a través de Internet. Los applets se descargan utilizando el mismo protocolo que se utiliza para transferir las páginas Web, es decir el protocolo de transferencia de hipertexto HTTP (HyperText Transfer Protocol). Cabe destacar que los applets poseen una serie de capacidades que las aplicaciones no poseen, esto es debido a que los applets tienen su propia clase llamada Applet, y disponen de tres interfaces AppletStub, AppletContext y AudioClip, que les ofrecen apoyo para las siguientes tareas: •

Los applets pueden reproducir sonidos.



Los applets pueden realizar la carga de documentos HTML, ya que se pueden comunicar con el navegador Web gracias al interfaz AppletContext.



Pueden invocar métodos públicos de otros applets en la misma página Web, es decir, varios applets de pueden comunicar entre sí de forma muy sencilla.



Se ejecutan dentro de una página Web cargada por un navegador.

Todas estas características de los que se han esbozado en estos puntos, se comentarán y tratarán de forma más detenida en los distintos apartados de este tema. Antes de seguir hablando de los applets como si fuera algo abstracto o difícil de realizar, vamos a comentar una serie de pasos básicos para crear nuestro primer applet utilizando la herramienta de Microsoft Visual J++ 6. Al arrancar Visual J++ en la pestaña de Nuevo seleccionamos la carpeta Páginas Web y dentro de esta opción elegimos Subprograma en HTML, esta es una curiosa forma que se ha elegido para nombrar a los applets. Algunos autores hacen referencia a los applets mediante los términos de miniaplicaciones o subprogramas.

273

Programación en Java

© Grupo EIDOS

Le damos un nombre a nuestro proyecto y pulsamos Abrir, en este momento Visual J++ generará un fichero fuente de Java llamado Applet1.java, que contiene la estructura de un applet de ejemplo, y además genera un fichero HTML llamado Page1.htm, que va a ser la página Web que haga referencia al applet antes mencionado. Para empezar desde cero y evitar confusiones, vamos a eliminar todo el código que aparece en el fichero fuente del applet y vamos a comenzar a escribir nosotros mismos nuestro primer applet. En un primer lugar debemos importar el paquete que contiene a la clase Applet, ya hemos comentado en este mismo apartado que un applet es un tipo de panel especial que se va a mostrar en el entorno de un navegador Web dentro de una página HTML.

import java.applet.*; Código fuente 173

A continuación debemos declarar nuestra clase. Debido a que vamos a crear un applet, nuestra clase heredará de la clase Applet. Antes de seguir cambiaremos el nombre de nuestro fichero fuente para cambiar el nombre de la clase del applet, en mi caso lo he llamado AppletSencillo, y la declaración de la clase se muestra en el Código fuente 174.

public class AppletSencillo extends Applet{ } Código fuente 174

Nuestro applet no va hacer mucho, simplemente vamos a mostrar un mensaje en la superficie del applet, para ello vamos a sobrescribir el método paint() de la clase Applet. Más adelante en este capítulo comentaremos el ciclo de vida de los applets y que implica sobrescribir el método paint(), también trataremos la clase Graphics y veremos como mostrar gráficos en un applet, de momento sólo debemos saber que el parámetro de la clase Graphics que recibe el método paint() representa a la superficie del applet. Para mostrar el mensaje "Hola Mundo", implementamos el método paint() como indica el Código fuente 175.

public void paint(java.awt.Graphics g){ g.drawString("Hola Mundo",10,10); } Código fuente 175

De esta forma el código completo de nuestra clase es el Código fuente 176.

import java.applet.*; public class AppletSencillo extends Applet{ public void paint(java.awt.Graphics g){

274

© Grupo EIDOS

14. Applets de Java: introducción a los Applets

g.drawString("Hola Mundo",10,10); } } Código fuente 176

Como se puede ver en el código, un applet no presenta ningún método main(), como ocurría con las aplicaciones. En la aplicaciones era necesario porque era el método de arranque de la clase y era dónde se instanciaba un objeto la clase de la aplicación. Sin embargo esto no pasa en los applets, como se puede ver nosotros no creamos ninguna instancia de la clase de nuestro applet, ahora bien, alguien debe hacerlo, este alguien es el navegador Web. El navegador Web crea una instancia de la clase de nuestro applet a través de la máquina virtual (MV) que contiene, cuando encuentra la etiqueta HTML que hace referencia al applet crea de forma automática una instancia del mismo. Ahora compilamos nuestro applet. Al compilar el applet se genera el fichero .class correspondiente, al igual que ocurría con las aplicaciones. Una vez compilado y generado nuestro applet tenemos que ver la forma de ejecutarlo, pero antes de ejecutarlo debemos modificar la página Web Page1.htm para que haga referencia a nuestro applet, ya que nosotros hemos cambiado el nombre del mismo, y la página Web sigue haciendo referencia a la clase Applet1. Para modificar la página Web hacemos doble click sobre ella en el Explorador de proyectos y en ese momento se abre la página Web en el área que teníamos reservada para el editor de código. El aspecto que ofrece el entorno de desarrollo se puede ver en la Figura 117.

Figura 117

El editor reservado para la página Web presenta tres vistas diferente de la página HTML: Diseño, Código y Vista rápida. En la parte de diseño podemos insertar elementos HTML o modificar los existentes, de forma similar a como lo podemos hacer con otros editores HTML más avanzados y sofisticados como puede ser Microsoft FrontPage, en esta vista podemos ver el aspecto que tiene el applet dentro de la página HTML, en este caso no estamos viendo nuestro applet sino el que había creado de ejemplo Visual J++. 275

Programación en Java

© Grupo EIDOS

Si seleccionamos el área que representa al applet y pulsamos con el botón derecho del ratón podemos seleccionar la opción de menú Propiedades. Al seleccionar esta opción del menú contextual podemos modificar las propiedades del applet desde una ventana de propiedades que aparece en el entorno y que se suele encontrar debajo del explorador de proyectos. En la ventana de Propiedades vamos a modificar la propiedad code del applet, esta propiedad debe indicar el nombre de la clase del applet que queremos mostrar en la página Web. Por lo tanto el valor de esta propiedad va a ser AppletSencillo, también vamos a modificar las propiedades width y height que indican las dimensiones del applet, yo he indicado el valor 100 para ambas propiedades. También podemos modificar las dimensiones del applet seleccionando y arrastrando el ratón, modificando de esta forma su tamaño. Una vez realizadas estas modificaciones sobre las propiedades, ya podemos ver nuestro applet en el lugar en el que aparecía el applet de ejemplo creado por Visual J++. Como se puede ver en la Figura 118, la vista Diseño muestra el applet en un estado similar al que presentaría en ejecución, y como era deseado y esperado muestra el mensaje Hola Mundo.

Figura 118

En la vista Código vemos el código HTML de la página Web (Figura 119), aunque el applet lo seguimos viendo en modo de ejecución, para ver el código HTML que se corresponde con la inclusión del applet en la página Web seleccionamos el applet, pulsamos con el botón derecho del ratón y seleccionamos la opción de menú Ver siempre como texto, de esta forma podemos ver los valores de la etiqueta . Esta etiqueta la discutiremos en el apartado dedicado a los applets y el código HTML.

Figura 119

276

© Grupo EIDOS

14. Applets de Java: introducción a los Applets

La última vista, Vista rápida, se muestra la página Web de la forma en la que se mostraría en un navegador que soporte Java, esta vista si que muestra la verdadera ejecución del applet, no como ocurría en la vista de diseño, aunque al ser un applet tan sencillo en ambas vistas ofrece el mismo aspecto. Por lo tanto si en la vista rápida vemos nuestro applet de forma correcta, es como si ya lo hubiésemos probado en un navegador, pero de todas formas recomiendo ejecutar el applet directamente sobre un navegador Web. Para ejecutar el applet pulsamos directamente el botón representado por una tecla "play" en el entorno de desarrollo, es decir, al igual que ejecutábamos una aplicación. En ese momento se ejecuta el applet, pero no mediante un navegador Web, sino mediante una herramienta del entorno Visual J++ denominada Visor de subprograma. El aspecto de este visor se puede ver en la Figura 120, y la función del mismo es el de desplegar applets, además ofrece un menú que no permite interactuar con el applet a través de una serie de opciones como: Recargar, Iniciar, etc.

Figura 120

Pero si queremos ejecutar el applet desde el entorno de Visual J++ 6 y que además arranque de forma automática el navegador Web para que se ejecute el applet en su interior, debemos acudir a las propiedades del proyecto y en la pestaña Inicio, en la lista desplegable Cuando se ejecute el proyecto, cargar:, seleccionamos la página HTML que hace referencia a nuestro applet. De esta forma cuando ejecutemos el proyecto, se lanzará el navegador Web (Internet Explorer) y cargará la página Web que hace referencia a nuestro applet, y se ejecutará por lo tanto el applet como se puede comprobar en la Figura 121. Esta es la forma más recomendable para probar un applet desde el entorno de desarrollo, pero existe otra forma. Simplemente localizamos en el Explorador de Windows la página Web que hace referencia a nuestro applet y hacemos doble click sobre ella, de esta forma se lanzará el navegador Web y cargará la página en cuestión. Ahora vamos a pasar a construir este mismo applet pero desde el entorno de desarrollo de la herramienta JBuilder 3.5. Para ello creamos un nuevo proyecto utilizando (si queremos) el asistente de proyectos. Una vez creado el proyecto desde el menú de opciones seleccionamos la opción Archivo/ Nuevo y seleccionaremos de la galería de objetos el applet, en ese momento se lanzará el asistente de creación de un nuevo applet.

277

Programación en Java

© Grupo EIDOS

Figura 121

El primer paso de este asistente, que se puede ver en la Figura 122, permite indicar a que paquete va a pertenecer nuestra clase y el nombre de la misma. En la opción clase base podemos elegir la clase Applet de la que queremos heredar, existen dos clases: Applet del paquete java.applet y JApplet del paquete javax.swing. JApplet es un componente Swing que hereda de la clase java.applet.Applet, es la versión Swing de los applets, la clase javax.swing.JApplet la veremos en próximos capítulos. En el ejemplo nuestro applet se llama AppletEjemplo y hereda de la clase java.applet.Applet. En el primer paso del asistente para applets también podemos indicar si queremos que se generen comentarios, si queremos que se ejecute como una aplicación cuando proceda y si deseamos que se generen todos los métodos del ciclo de vida de los applets, estos métodos los veremos en el apartado dedicado al ciclo de vida de los applets.

Figura 122

En la figura 7, se definen los parámetros el applet, en nuestro ejemplo el applet no va a tener ninguno, ya que consiste únicamente en escribir un mensaje en la superficie del applet. 278

© Grupo EIDOS

14. Applets de Java: introducción a los Applets

Figura 123

En el último paso se nos permite especificar los parámetros de configuración de applet en la página HTML, es decir, el nombre de la clase, las dimensiones y la alineación. También podemos indicar si queremos o no que se genere de forma automática la página HTML que va a contener nuestro applet, de la página podemos especificar su nombre y título.

Figura 124

Al pulsar finalizar se generará el fichero fuente del applet y la página HTML que lo contiene. Ahora accedemos al código fuente y añadimos el método paint() con el mismo código que vimos anteriormente para Visual J++. Una vez compilado el applet podemos pulsar el botón "play" para la ejecución del mismo.

279

Programación en Java

© Grupo EIDOS

En ese momento aparece la pantalla de configuración del proyecto para ejecutar el applet (Figura 125), esta pantalla que aparece únicamente la primera vez, nos permite asignar la clase principal del applet, al igual que ocurría con las aplicaciones Java, también es posible definir las dimensiones del applet y los parámetros, pero estos datos ya los hemos indicado anteriormente en el asistente para la creación de applets.

Figura 125

Una vez indicada la información necesaria para ejecutar el applet JBuilder inicia la ejecución del mismo en una herramienta propia de JBuilder, comparable al appletviewer del JDK o al visor de subprograma del Visual J++. El aspecto del visor de applets de JBuilder se puede comprobar en la Figura 126.

Figura 126

280

© Grupo EIDOS

14. Applets de Java: introducción a los Applets

Ya hemos visto como crear y ejecutar un applet con Visual J++ y JBuilder, ahora sólo nos queda hacer lo mismo con la herramienta de Sun JDK. Para ello crearemos el fichero fuente de Java que va a contener el código del applet que sería el Código fuente 177.

import java.applet.*; public class AppletSencillo extends Applet{ public void paint(java.awt.Graphics g){ g.drawString("Hola Mundo",10,10); } } Código fuente 177

Compilamos el código con la herramienta javac y creamos una página HTML que haga referencia a la clase de nuestro applet. Al hacer doble clic sobre la página, ya podríamos ver el applet en nuestro navegador Web, pero también podemos utilizar la herramienta appletviewer que se ofrece con el JDK. Para ejecutar nuestro applet con el appletviewer únicamente deberemos escribir la instrucción en la línea de comandos, como se muestra en el Código fuente 178.

appletviewer pagina.html Código fuente 178

Y el aspecto del appletviewer es el de la Figura 127.

Figura 127

Desde el menú Applet del appletviewer podemos invocar los distintos métodos del ciclo de vida de los applets, que veremos en detalle más adelante en este mismo capítulo. Al principio de este apartado comentábamos que para hacer disponibles los applets en la Web, necesitamos de un servidor Web, ahora bien, para probarlos, es decir, en tiempo de desarrollo de los mismos, puede no ser necesario. Así con nuestro sencillo applet lo probaríamos en una máquina local y una vez que hemos comprobado que funciona lo copiaríamos al servidor Web que corresponda.

281

Programación en Java

© Grupo EIDOS

Este ha pretendido ser el primer contacto con los applets, hemos realizado un applet muy sencillo y lo hemos realizado desde tres herramientas distintas: Microsoft Visual J++ 6, Borland JBuilder 3.5 y el JDK 1.3 de Sun. También hemos visto las diferentes formas que tenemos de ejecutarlo. En los siguientes apartados profundizaremos más en todo lo relacionado con los applets.

El ciclo de vida de los applets Los applets podemos decir que presentan un ciclo de vida, es decir, durante su ejecución pasan por diferentes estados. El ciclo de vida de vida de los applets es controlado por cuatro métodos de la clase Applet, estos métodos son init(), start(), stop() y destroy(). Cuando se carga una página Web que contiene un applet, éste pasa por varias etapas durante el tiempo que aparece en pantalla, el applet realiza unas tareas muy diferentes durante cada una de estas etapas. Si queremos que en una etapa del ciclo de vida de un applet se realice una tarea determinada deberemos sobrescribir el método adecuado. No siempre es necesario sobrescribir todos los métodos del ciclo de vida de un applet. A continuación se comenta cuando se ejecutan cada uno de los métodos del ciclo de vida de un applet. El método init() es llamado una única vez por la Máquina Virtual de Java (JVM) del navegador cuando el applet se carga por primera vez, antes de ser mostrado al usuario, es en este método donde se deben inicializar los objetos, construir los interfaces de usuario, etc. El método start() es llamado cada vez que la página Web que contiene el applet es mostrada en la pantalla del usuario. Al método stop() se le llama cada vez que el usuario carga otra página Web, es decir, cuando se abandona la página que contiene al applet. El último método, destroy(), es llamado una única vez, justo antes de ser eliminado el applet, cuando se abandona el navegador. Este método es invocado automáticamente para realizar cualquier limpieza que sea necesaria, por lo general no es necesario sobrescribir este método, sólo será necesario cuando se tengan recursos específicos que necesiten ser liberados. Es durante esta etapa final de salida, cuando la Máquina Virtual de Java completa algunas funciones de recolección de basura para asegurar que los recursos que empleó el applet sean borrados de la memoria y de que el applet sea completamente destruido cuando se salga de él. Como se ha podido observar en el ciclo de vida de un applet los métodos init() y destroy() se lanzarán solamente una vez cada uno, y sin embargo los métodos start() y stop() se lanzarán las veces que sean necesarios, según interactúe el usuario con el navegador. La Figura 128 muestra la relación entre los métodos del ciclo de vida del applet y los acontecimientos que los marcan:

282

© Grupo EIDOS

14. Applets de Java: introducción a los Applets

Figura 128

Vamos a realizar un seguimiento a través del ciclo de vida de un applet, para lo cual vamos a apoyarnos en una clase Ventana, que va a ser muy sencilla y cuyo código es el Código fuente 179.

import java.awt.*; import java.awt.event.*; public class Ventana extends Frame{ public Ventana(String titulo){ super(titulo); setSize(150,150); show(); addWindowListener(new AdaptadorVentana(this)); } } class AdaptadorVentana extends WindowAdapter{ private Ventana fuente; public AdaptadorVentana(Ventana fuente){ this.fuente=fuente; } public void windowClosing(WindowEvent evento){ fuente.dispose(); } } Código fuente 179

Si algún alumno tiene problemas para entender el código anterior, le remito al capítulo dedicado al interfaz de usuario en Java. La clase Ventana la vamos a utilizar en nuestro applet para crear una ventana cada vez que se ejecuta un método del ciclo de vida de un applet. Para diferenciar las ventanas, a cada una de ellas le pasamos a su constructor el nombre del método del ciclo de vida que las ha llamado. Es decir, cada ventana tendrá un título distinto. El código del applet es el Código fuente 180.

import java.applet.*; public class CicloVida extends Applet{ public void init(){ Ventana ventana=new Ventana("init()"); }

283

Programación en Java

public void Ventana } public void Ventana } public void Ventana } }

© Grupo EIDOS

start(){ ventana=new Ventana("start()"); stop(){ ventana=new Ventana("stop()"); destroy(){ ventana=new Ventana("destroy()");

Código fuente 180

En este caso cada clase se encuentra en un fichero fuente, es decir, existen los ficheros Ventana.java y CicloVida.java. Si ejecutamos nuestro applet pulsando play (en cualquiera de los entornos: Visual J++ o JBuilder), como ya vimos en el apartado anterior, o bien con el appletviewer o directamente con te navegador Web deben aparecer dos ventanas, una creada por el método init() y otra por el método start(). Una vez que hemos cargado el applet, si cerramos el navegador aparecen momentáneamente otras dos ventanas, creadas esta vez por el método stop() y destroy(), ya que además de descargar el applet se cierra el navegador. Hasta aquí todo es correcto y sucede tal y como habíamos explicado anteriormente. Un ejemplo de ejecución del applet se puede ver en la Figura 129.

Figura 129

Continuamos con la ejecución de nuestro applet. Pero si cargamos una página distinta, además de ejecutarse el método stop() se ejecuta el método destroy(), cosa que en absoluto es correcta, sólo se debería ejecutar el método stop(), ya que el navegador no se ha cerrado. Y si volvemos a la página del applet (pulsando la flecha hacia atrás del navegador) además de ejecutarse el método start() también se ejecuta el método init(), situación que también es incorrecta. Esto no es debido a que nuestro applet esté mal construido, sino que es debido a una implementación distinta dentro de la máquina virtual del navegador Web. En mi caso he detectado este fallo en el navegador Internet Explorer en su versión 5.0.

284

© Grupo EIDOS

14. Applets de Java: introducción a los Applets

Si probamos este mismo applet cargando la página que lo contiene desde el navegador Netscape Navigator en su versión 4.5 el applet funciona correctamente, es decir, al cambiar de página se ejecuta únicamente el método stop() y al volver a la página el método start(). Realizo estos comentarios, sólo para las versiones señaladas de los navegadores, que son además los que se han utilizado para las pruebas de los applets que aparecen en este curso. Estos cuatro métodos que componen el ciclo de vida de un applet se ejecutan, como hemos podido comprobar, de forma automática y siguiendo un orden determinado. Otro método que también se ejecuta de forma automática es el método paint(). Este método, que ya hemos comentado someramente en el apartado anterior, tiene la función de pintar o mostrar la apariencia del applet en la pantalla. Este método es otro método de la clase Applet que podemos sobrescribir si lo necesitamos, igual que ocurría con los métodos del ciclo de vida de los applets. Con respecto al ciclo de vida del applet el método paint() se ejecuta por primera vez inmediatamente después del método start() y luego cada vez que se necesita "repintar" la pantalla, es decir, cada vez que se refresca la superficie que comprende al área contenida por el applet. La máquina virtual lanzará el método paint() cada vez que el applet desaparezca total o parcialmente de la pantalla. El método paint() recibe como parámetro un objeto de la clase Graphics, que pertenece al paquete java.awt. La instancia del objeto de la clase Graphics representa la superficie del applet, y lo vamos a utilizar para escribir y dibujar en la superficie del mismo. En el apartado correspondiente veremos como dibujar de forma básica en la superficie de nuestro applet. El método paint() también se ejecuta cuando se llama al método repaint() de la clase Applet.

Seguridad en los applets Java incluye características de seguridad para reforzar su empleo en Internet. Un problema de seguridad potencial tiene que ver con los applets de Java, que son código ejecutable que opera en la máquina local del usuario que se conecta a la página Web en la que se encuentran los applets. Java emplea verificación de código y acceso limitado al sistema de archivos para garantizar que el código no dañe nada en la máquina local. Se debe tener claro que el applet reside en el servidor Web, pero cuando se carga la página Web que lo contiene, las clases del applet se transfieren hasta la máquina cliente, que es dónde se inicia la ejecución del applet. En este apartado, como su nombre indica, vamos a comentar los mecanismos de seguridad que ofrece Java a la hora de ejecutar los applets en la máquina cliente o máquina local, y que restricciones de seguridad impone. Existen dos módulos software encargados del análisis de la seguridad y de la imposición de restricciones, estos módulos son el ClassLoader y el Security Manager. El ClassLoader (clase abstracta del paquete java.lang) tiene las siguientes funciones: por un lado colocar las clases que integran cada applet en un espacio de nombres único y estanco, de forma que es imposible para un applet acceder o manipular recursos de otros applets. Por otro lado analiza los bytecodes que componen la representación binaria intermedia del código del applet para asegurar que son conformes a las normas de Java y no realizan operaciones peligrosas,

285

Programación en Java

© Grupo EIDOS

como conversiones de tipos ilegales, accesos a índices inexistentes de arrays, paso de parámetros incorrectos, etc. Todas estas funciones las lleva a cabo un verificador de código (bytecode verifier). Las comprobaciones que realiza el verificador de código (para más información sobre el proceso de verificación, consultar la siguiente dirección de Internet: http://www.javasoft.com/sfaq/verifier.html) se ven facilitadas por la filosofía de diseño de Java. Así, por ejemplo, Java carece de punteros, por lo que es imposible hacer referencia a una posición de memoria explícita. Además, el intérprete comprueba siempre que el acceso a un array se realiza a través de un índice dentro de un rango válido. Cuando se carga desde un servidor a nuestra máquina local una página Web que contiene algún applet, el código del applet es verificado por el segundo módulo de seguridad para garantizar que el applet sólo emplea llamadas y métodos válidos del sistema. Si el applet pasa la verificación se le permite ser ejecutado, pero a los applets no se les da acceso al sistema de archivos de la máquina local. El objeto responsable de evitar que los applets realicen una operación potencialmente peligrosa es el SecurityManager (gestor de seguridad, clase abstracta del paquete java.lang). Si el SecurityManager determina que la operación está permitida, deja que el programa siga con su ejecución. Cuando una aplicación Java se ejecuta, no hay SecurityManager. Esto es debido a que se espera que cualquier aplicación que el usuario ejecuta es segura para ese usuario. De todas formas podemos escribir e instalar propio SecurityManager para nuestras aplicaciones, por lo tanto en un principio las aplicaciones Java no tiene ningún tipo de restricción. Cada navegador de páginas Web con capacidad para Java tiene un objeto SecurityManager que comprueba si se producen violaciones de las restricciones de seguridad de los applets. Cada vez que una clase Java hace una petición de acceso a un recurso del sistema, la instancia de la clase SecurityManager comprueba la petición realizada, si no se tiene permiso para efectuar el acceso éste se deniega y en caso contrario se le concede y se sigue normalmente con la ejecución del applet. Cuando el SecurityManager detecta una violación crea y lanza un objeto SecurityException y se detiene la ejecución del applet. Normalmente, el constructor de una SecurityException muestra un mensaje de advertencia que indica que se ha producido una excepción de seguridad. En la Figura 130, se puede ver de forma ordenada todo el proceso que se sigue para comprobar que el applet es seguro, desde que el applet se empieza a cargar desde Internet hasta que empieza a ejecutarse en la máquina cliente:

Figura 130

286

© Grupo EIDOS

14. Applets de Java: introducción a los Applets

La clase SecurityManager posee una serie de métodos para realizar las siguientes acciones que refuerzan su política de seguridad: •

Determinar si una petición de conexión, a través de la red, desde una máquina en un puerto específico puede ser aceptada.



Comprobar si un hilo de ejecución puede manipular otro hilo de ejecución diferente.



Comprobar si se puede establecer una conexión vía socket con una máquina remota en un puerto específico.



Impedir la creación de un nuevo objeto de la clase ClassLoader.



Impedir la creación de un nuevo objeto de la clase SecurityManager, ya que podría sobrescribir la política de seguridad existente.



Comprobar que un fichero puede ser borrado.



Comprobar si un programa puede ejecutar otro programa en el sistema local.



Impedir que un programa termine con la ejecución de la Máquina Virtual de Java.



Comprobar si se puede acceder a una librería dinámica.



Comprobar si se puede escuchar en un determinado puerto para esperar peticiones de conexión.



Determinar si un programa puede cargar paquetes Java específicos.



Determinar si un programa puede crear nuevas clases en un paquete Java específico.



Identificar a que propiedades del sistema se puede acceder.



Comprobar si se puede leer un fichero.



Comprobar si se puede escribir datos en un fichero.



Comprobar si un programa puede crear su propia implementación de los sockets para la red.



Establecer si un programa puede crear una ventana de alto nivel. Cualquier ventana que se cree incluirá algún tipo de advertencia visual.

Después de explicar los mecanismos de los que dispone Java para verificar que un applet es seguro, se va a pasar a detallar las restricciones de seguridad que poseen los applets (para más información sobre la seguridad de Java se puede consultar la siguiente dirección: http://www.javasoft.com/sfaq/: •

Los applets no pueden cargar librerías o definir métodos nativos. Si un applet pudiera definir una llamada a un método nativo le daría acceso a la máquina en la que se ejecuta.



Los applets no pueden detener la ejecución de la Máquina Virtual de Java.



No pueden leer ni escribir en el sistema de archivos de la máquina del navegador. No se pueden abrir ni crear ficheros en la máquina del cliente, ni tampoco crear o leer directorios. Si 287

Programación en Java

© Grupo EIDOS

se intenta crear o abrir un objeto java.io.File o java.io.FileInputStream o java.io.FileOutputStream en la máquina del cliente dará lugar a una excepción de seguridad. •

Un applet no puede hacer conexiones a través de la red, sólo se puede conectar con el servidor desde el que se cargó el applet.



No pueden conectarse a puertos del cliente.



Los applets no pueden actuar como servidores de la red esperando para aceptar conexiones de sistemas remotos.



Los applets que se quieran comunicar entre sí deben estar en la misma página Web, en la misma ventana del navegador, y además deben ser originarios del mismo servidor.



No pueden instanciar un objeto de las clases ClassLoader o SecurityManager.



No pueden acceder o cargar clases de paquetes llamados java que no sean los paquetes estándar del API de Java.



No pueden ejecutar ningún programa en el sistema local del cliente.



No pueden leer todas las propiedades del sistema en el que se cargaron. En particular, no puede leer ninguna de las siguientes propiedades del sistema: user.name (nombre de la cuenta del usuario), user.home (directorio home del usuario), java.home (directorio de instalación de Java), user.dir (directorio de trabajo actual del usuario) y java.class.path (directorio en el que se encuentran las clases de Java).



Los applets tampoco pueden definir ninguna propiedad del sistema.



Las ventanas que abren los applets tienen un aspecto diferente, aparece la advertencia de que se trata de una ventana abierta o creada por un applet.



Los applets no pueden instanciar objetos COM (Component Object Model) o comunicarse con ellos, esto es para preservar la seguridad, ya que los objetos COM son poco seguros y permiten realizar operaciones peligrosas en la máquina local.

Los applets se pueden cargar de dos maneras, la forma en que un applet entra en el sistema afecta a lo que se le va a permitir hacer. Si un applet se carga a través de la red, entonces es cargado por el ClassLoader y está sujeto a las restricciones impuestas por el SecurityManager. Pero si un applet reside en el disco local del cliente, y en un directorio que está en el java.class.path (propiedad de la clase System, que indica en que lugar se encuentran las clases de Java) entonces es cargado por el FileLoader del sistema. Las diferencias principales con los anteriores son las siguientes:

288



Pueden leer y escribir ficheros.



Pueden cargar librerías en la máquina del cliente.



Pueden ejecutar procesos, es decir, pueden ejecutar cualquier programa en la máquina del cliente.



Pueden parar la ejecución de la Máquina Virtual de Java.



No son pasados por el verificador de bytecode.

© Grupo EIDOS

14. Applets de Java: introducción a los Applets

Esta relajación de la seguridad es debido a que se supone que los applets cargados del sistema local son más fiables que los que se cargan a través de la red de forma anónima. También se relajará la seguridad de los applets en el caso de que éstos se encuentren firmados digitalmente a través de un certificado. El único "agujero" en la seguridad de un applet es que éste puede reservar mucha cantidad de memoria creando continuamente una gran cantidad de objetos, por ejemplo, un applet podría crear un gran número de ventanas agotando el sistema GUI (Graphical User Interface) de la máquina, iniciar la ejecución de muchos hilos de ejecución paralelos o cargar desde la red una gran cantidad de datos, este tipo de ataque se denomina ataque de negación de servicio (denial of service attack). Este ataque consume muchos recursos del sistema y puede disminuir la velocidad de la máquina o de la conexión a la red de forma considerable. Aunque este ataque es molesto no puede causar un daño real al sistema, se considera que este ataque está fuera del modelo de seguridad de Java.

Trusted/Untrusted applets Cuando decimos que un applet es trusted (de confianza), este applet podrá saltarse las restricciones de seguridad que vienen impuestas a los applets; pero si es untrusted (no es de confianza) tendrá que ajustarse a las restricciones. Un applet de Java se ejecuta dentro de un entorno ofrecido por la Máquina Virtual que evita que el applet realice acciones sobre nuestro sistema que pueden ser potencialmente peligrosas desde el punto de vista de la seguridad. La Máquina Virtual de Java deberá discernir si debe permitir que el applet se salte las restricciones de seguridad o que por el contrario las cumpla escrupulosamente, es decir, debe distinguir si un applet es trusted o untrusted. Por defecto todos applets que cargamos a través de Internet son untrusted, por lo tanto se deben ceñir a las restricciones de seguridad impuestas por la Máquina Virtual. Para que un applet sea trusted debe ir firmado digitalmente o bien las clases del applet deben estar situadas en el CLASSPATH. De esta forma, si nosotros hemos creado nuestro applet, y nuestra variable de entorno CLASSPATH tiene el valor c:\Java\clases deberemos situar los ficheros de clase del applet en el directorio c:\Java\clases. Esto sólo es recomendable para applets que hayamos desarrollado nosotros o alguna persona de confianza.

Diferencias entre applets y aplicaciones A continuación se comentan las diferencias entre las aplicaciones y los applets de Java. Las aplicaciones son programas individuales que se ejecutan utilizando sólo el intérprete de Java, los applets sin embargo se ejecutan desde un navegador de páginas Web, o desde un visor de applets. Una referencia a un applet se introduce en una página Web empleando una etiqueta HTML especial. Cuando un navegador carga la página, carga el applet desde el servidor Web y lo ejecuta en el sistema local. Ya que los applets se ejecutan dentro de un navegador, tienen la ventaja de la estructura que éste les ofrece: una ventana, un contexto de manejo de eventos y gráficos y el interfaz de usuario que la rodea.

289

Programación en Java

© Grupo EIDOS

Sin embargo, todas estas ventajas que tienen los applets sobre las aplicaciones, se ven ensombrecidas por las restricciones impuestas a los applets. Ya que los applets pueden desplegarse desde cualquier parte y ejecutarse en un sistema cliente, las restricciones son necesarias para prevenir que un applet cause daños al sistema o rupturas de seguridad. Sin estas restricciones los applets podrían escribirse para contener virus, gusanos, etc.… y podrían propagarse por toda la red en cuestión de horas. Sin embargo las aplicaciones de forma explícita no ofrecen estas restricciones de seguridad.

La etiqueta applet En este apartado vamos a comentar las características que ofrece el lenguaje HTML para la integración de los applets dentro de páginas Web. Puesto que los applets están diseñados para usarse en conjunción con la WWW (World Wide Web), es necesario contar con una manera estándar de llamar a los applets dentro de un navegador Web. Esto lo permiten un juego de etiquetas HTML (Hypertext Markup Language) que se creó para especificar toda la información necesaria para ejecutar un applet. Así, el código HTML puede emplearse para hacer lo siguiente: •

Especificar el directorio del applet.



Indicar la ubicación del código que emplea el applet.



Especificar el tamaño en pantalla del applet.



Ofrecer alternativas para los navegadores que no tengan capacidad para Java.



Pasar parámetros al applet.

Después de crear el applet y escribir su código, debe añadirse a una página HTML para poder ejecutarse dentro de un navegador. Para ello se debe utilizar la etiqueta del lenguaje HTML. La etiqueta posee los siguientes atributos que a continuación se muestran en la Figura 131, los que son opcionales se encuentran encerrados entre corchetes.

Figura 131

290

© Grupo EIDOS

14. Applets de Java: introducción a los Applets

En su forma más elemental, utilizando sólo los atributos CODE, WIDTH y HEIGHT, la etiqueta crea un espacio del tamaño deseado en el que se cargará y ejecutará el applet. A continuación se pasa a describir los atributos de la etiqueta .

Codebase Este atributo opcional especifica la dirección URL base del applet, es decir, el directorio o carpeta que contiene el código del applet. Si este atributo no es especificado se utiliza el URL del documento HTML.

Code Este atributo requerido ofrece el nombre del fichero .CLASS que contiene el applet. Si no se utiliza el atributo CODEBASE, el archivo se busca en el mismo directorio del archivo HTML que referencia al applet.

Alt Este atributo opcional especifica el texto que debe ser mostrado en pantalla en el caso de que el navegador utilizado para ver las páginas HTML no tenga capacidad para Java.

Name Esta atributo de carácter opcional especifica un nombre para el applet. Esto hace posible que los applets de una misma página Web se puedan comunicar entre sí, haciendo referencia a su nombre.

Width, Height Estos atributos requeridos definen el ancho y alto (en pixels) del applet, sin tener en cuenta los diálogos o ventanas que pueda mostrar el applet.

Align Este atributo de naturaleza opcional especifica la alineación del applet. Los posibles valores de este atributo son los que se enumeran a continuación: •

TEXTTOP: alinea la parte superior del applet con la parte superior del texto más alto en la línea.



TOP: alinea el applet con el elemento más alto en la línea, el cual puede ser otro applet, una imagen, o la parte superior del texto.



ABSMIDDLE: alinea el centro del applet con el centro del elemento más grande de la línea.



MIDDLE: alinea el centro del applet con el centro de la línea base del texto. 291

Programación en Java

© Grupo EIDOS



BASELINE: alinea la parte inferior del applet con la línea base del texto.



ABSBOTTON: alinea la parte inferior del applet con el elemento más bajo en la línea.

Vspace, Hspace Estos atributos opcionales especifican el número de pixels que debe haber encima y debajo del applet (VSPACE) y a cada lado del applet (HSPACE), es decir, los márgenes del applet. Fuera ya de los atributos de la etiqueta pueden aparecer otras etiquetas que se comentan a continuación:

Esta etiqueta permite especificar parámetros de un applet. Los applets leen los valores de los parámetros con el método getParameter() de la clase Applet. Los parámetros para los applets son como los argumentos de la línea de comandos para las aplicaciones. Permiten que el usuario pueda personalizar algunas de las operaciones o características del applet. Al definir parámetros se aumenta la flexibilidad del applet, el applet podrá ejecutarse en diferentes situaciones sin necesidad de modificar su código y volver a compilarlo. Al definir un parámetro para un applet mediante la etiqueta se debe tener en cuenta que es lo que se va a permitir al usuario configurar del applet, como se debe llamar el parámetro, que tipo de valor va a tener el parámetro y cual es su valor por defecto. Además de ofrecer parámetros al usuario para que pueda configurar el applet, se le debe indicar como se pueden utilizar estos parámetros. Por lo tanto se debe implementar el método getParameterInfo() de la clase Applet para que devuelva toda la información y ayuda referente a los parámetros del applet. Los navegadores pueden utilizar esta información para ayudar a los usuarios e indicar que valores puede dar a los parámetros.

Etiquetas HTML alternativas Si el navegador que carga la página en la que se encuentra el applet no reconoce la etiqueta al no tener capacidad para Java, entonces utiliza estas etiquetas alternativas cuando muestre el documento HTML. Los navegadores con capacidad para Java ignoran todas estas etiquetas alternativas.

292

Applets de Java: utilizando los applets Interacción de los applets con el navegador web Cuando realizamos la introducción a los applets, en el capítulo anterior, comentamos que los applets pueden realizar una serie de operaciones apoyándose en el navegador Web. En este apartado vamos a comentar con ejemplos una serie de características que ofrecen los applets y que en cierta medida son exclusivas, y por lo tanto no las presentan las aplicaciones. Lo primero que vamos a comentar acerca de las capacidades de los applets, es la posibilidad que tienen éstos de comunicarse entre sí en una misma página Web. Para realizar una comunicación entre diferentes applets de deben tener en cuenta dos restricciones de seguridad: •

Los applets deben estar en la misma página Web, en la misma ventana del navegador.



Los applets deben ser originarios del mismo servidor.

Un applet para comunicarse con otro puede hacerlo refiriéndose al nombre del applet con el que se quiere comunicar, para ello se usa el método getApplet() del interfaz AppletContext. Este interfaz se corresponde con el entorno o contexto en el que se encuentra un applet, es decir, el documento que contiene al applet y los otros applets contenidos en el mismo documento. El contexto del applet se obtiene utilizando el método getAppletContext() de la clase Applet, este método devuelve un objeto que representa el contexto en el que se encuentra el applet.

Programación en Java

© Grupo EIDOS

Los métodos del interfaz AppletContext pueden ser usados para obtener información relativa al entorno del applet. El método getApplet(), a partir de un nombre que se le pasa como parámetro, nos devuelve una instancia de la clase Applet que representa al applet que posee el nombre que se le ha pasado como parámetro a getApplet() y que se encuentra dentro del entorno correspondiente al AppletContext. Si el applet no existe nos devolverá un nulo. También se puede utilizar otro método del interfaz AppletContext, llamado getApplets(), que devolverá una enumeración (objeto de tipo java.util.Enumeration) de todos los applets existentes en el documento representado por el correspondiente AppletContext. Para darle un nombre a cada applet se debe utilizar dentro del documento HTML el atributo name de la etiqueta , así por ejemplo si queremos identificar con el nombre pepe a un applet representado por la clase Ejemplo escribiríamos lo que vemos en el Código fuente 181.

Código fuente 181

Vamos a ver todo esto mediante un ejemplo sencillo que va a consistir en un par de applets, representados por las clases Remitente y Destinatario. Estos dos applets se van a enviar un mensaje entre sí. La clase Destinatario va a facilitar un método público llamado enviarMensaje() que permite a la clase Remitente enviar un mensaje. El código de la clase Destinatario, es el que muestra el Código fuente 182.

import java.applet.*; import java.awt.*; public class Destinatario extends Applet{ private TextField mensaje; public void init(){ mensaje=new TextField(20); add(mensaje); } public void enviarMensaje(String men){ mensaje.setText(men); } } Código fuente 182

Como se puede ver el método enviarMensaje() permite asignar texto a la caja de texto del applet que actúa como destinatario. El código es bastante sencillo y no ofrece ninguna complicación. Ahora vamos a ver el segundo applet, el que actúa de remitente. Este applet si que va a hacer uso del interfaz AppletContext. Este applet ofrece una caja de texto y un botón, en la caja de texto escribiremos el mensaje que queremos que aparezca en la caja de texto del applet de destino, y al pulsar el botón invocaremos el método enviarMensaje() de la clase Destinatario. El código de la clase Remitente aparece en el Código fuente 183.

294

© Grupo EIDOS

15. Applets de Java: utilizando los applets

import java.applet.*; import java.awt.*; import java.awt.event.*; public class Remitente extends Applet implements ActionListener{ private Button boton; private TextField mensaje; public void init(){ boton=new Button("Enviar mensaje"); mensaje=new TextField(20); add(mensaje); add(boton); boton.addActionListener(this); } public void actionPerformed(ActionEvent evento){ //se obtiene el contexto del applet AppletContext contexto=getAppletContext(); //se obtiene la referencia al otro applet a través de su nombre Applet destinatario=contexto.getApplet("destino"); //se invoca el método que nos interesa del applet Destinatario ((Destinatario)destinatario).enviarMensaje(mensaje.getText()); } } Código fuente 183

Especial atención merece el método actionPerformed(), que se ejecutará al pulsar el botón de envío de mensaje del applet. En este método se obtiene primero el contexto del applet, es decir un objeto AppletContext. A continuación se obtiene una referencia al applet que nos interesa, en este caso el applet se llama destino. Y por último se invoca el método deseado del applet, para poder invocarlo debemos realizar un casting (conversión de clases), ya que la clase Applet no dispone del método obtenerMensaje(), este método pertenece a nuestra clase Destinatario. En el código HTML de la página Web que contiene a los dos applets debemos asignar a la propiedad name de la etiqueta APPLET, que hace referencia al applet Destinatario, el valor destino, ya que es la cadena que le pasamos por parámetro al método getApplet(). El código HTML se muestra en el Código fuente 184.



Document Title





Código fuente 184

En la Figura 132 se puede ver un ejemplo de la ejecución de estos dos applets cooperantes entre sí.

295

Programación en Java

© Grupo EIDOS

Figura 132

Antes habíamos comentado que el interfaz AppletContext ofrece dos métodos para tener referencias a los applets dentro de una misma página Web, los métodos getApplet() y getApplets(). En el ejemplo anterior hemos visto un ejemplo que utiliza el método getApplet(), ahora vamos a ver un nuevo ejemplo que utiliza el método getApplets(). Vamos a crear un applet que muestre el nombre de las clases de todos los applets que se encuentren en la página Web actual, evidentemente este applet también debe estar incluido en la página. Para mostrar el nombre de las clases, nuestro applet va a utilizar un objeto de la clase TextArea. Al pulsar el botón que ofrece el applet se procederá a obtener las referencias a los applets, para así poder mostrar el nombre de la clase de cada uno de ellos. El código de este applet se indica en el Código fuente 185.

import java.applet.*; import java.awt.*; import java.awt.event.*; import java.util.*; public class ListaApplets extends Applet implements ActionListener{ private TextArea listado; private Button boton; public void init(){ setLayout(new BorderLayout()); listado=new TextArea(5,30); boton=new Button("Listar Applets"); add("North",listado); add("South",boton); boton.addActionListener(this); } public void actionPerformed(ActionEvent evento){ listarApplets(); } public void listarApplets(){ AppletContext contexto=getAppletContext(); String nombreClase=""; listado.setText(""); //obtenemos la referencia a todos los applets de la página Enumeration applets=contexto.getApplets(); //recorremos la lista de applets while (applets.hasMoreElements()){

296

© Grupo EIDOS

15. Applets de Java: utilizando los applets

//obtenemos la referencia al applet Object applet=applets.nextElement(); //recuperamos el nombre de la clase del applet nombreClase=applet.getClass().getName(); //añadimos el nombre de la clase al área de texto listado.append(nombreClase+"\n"); } } } Código fuente 185

Como se puede observar se importa el paquete java.util, este paquete es necesario para poder utilizar la clase Enumeration. Esta clase la utilizamos al ejecutar el método getApplets() del interfaz AppletContext. El método getApplets() nos devuelve un objeto de la clase Enumeration que contiene todos los applets que existen en la página Web actual. La clase Enumeration es una clase de utilidad que posee únicamente dos métodos hasMoreElements() y nextElement(). El primero de ellos devuelve un valor booleano y se utiliza para comprobar si existen más elementos en la enumeración, mientras que el segundo de los métodos devuelve el siguiente elemento de la enumeración. El método nextElement() devuelve siempre un objeto de la clase Object, ya que un objeto de la clase Enumeration puede contener cualquier tipo de objeto. Si situamos este nuevo applet en la misma página Web que contenía los dos anteriores y lo ejecutamos mostrará el aspecto de la Figura 133.

Figura 133

Otra posibilidad que nos ofrecen los applets es la de cargar páginas en el navegador, es decir, podemos indicar al navegador que muestre una página determinada. Para ello también nos vamos a apoyar en el interfaz AppletContext, este interfaz ofrece el método showDocument() para realizar esta tarea. Este método recibe como parámetro un objeto de la clase URL. La clase URL representa una URL (Uniform Resource Locator) y se encuentra dentro del paquete java.net. Este paquete contiene una serie de clases especializadas en la utilización de recursos y comunicaciones en Internet. A continuación vamos a realizar un applet que muestre una ventana en la que podemos indicar la URL que deseamos cargar en el navegador. Vamos a crear, además de la clase del applet, una clase llamada VentanaURL que va a representar la ventana que muestra el applet, antes de seguir con la exposición de este ejemplo vamos a ver el código fuente completo en el Código fuente 186. 297

Programación en Java

© Grupo EIDOS

import java.applet.*; import java.awt.*; import java.awt.event.*; import java.net.*; public class MuestraDocumento extends Applet{ private VentanaURL ventana; public void init(){ ventana=new VentanaURL(getAppletContext()); } } class VentanaURL extends Frame implements ActionListener{ //caja de texto que contiene la URL private TextField textoURL; private Button boton; private AppletContext contexto; //el constructor tiene el parámetro contexto para que le pasemos //el contexto del applet public VentanaURL(AppletContext contexto){ super("Mostrar Documento"); this.contexto=contexto; boton=new Button("Muestra URL"); textoURL=new TextField(20); setLayout(new GridLayout(1,2,5,5)); add(textoURL); add(boton); pack(); show(); boton.addActionListener(this); addWindowListener(new AdaptadorVentana()); } public void actionPerformed(ActionEvent evento){ String cadenaURL=textoURL.getText(); URL url=null; //se crea la URL, y es necesario atrapar una excepcion //que lanza su constructor try{ url=new URL(cadenaURL); }catch(MalformedURLException ex){ textoURL.setText("Error en la URL"); } //se muestra la URL en el navegador if (url!=null) contexto.showDocument(url); } class AdaptadorVentana extends WindowAdapter{ public void windowClosing(WindowEvent evento){ dispose(); } } } Código fuente 186

Como se puede ver la clase MuestraDocumento no hace mucho, el applet simplemente crea en su método init() una instancia de la clase VentanaURL, a la que le pasa por parámetro el contexto del applet, ya que la clase que va a realizar la operación de mostrar la URL va a ser la clase VentanaURL, por lo tanto vamos a pasar a comentar la clase VentanaURL. En el constructor de la clase VentanaURL creamos el interfaz de usuario, registramos los oyentes necesarios para la pulsación del botón y para el cierre de la ventana. Además se inicializa el atributo contexto con el contexto que se ha obtenido en el applet. 298

© Grupo EIDOS

15. Applets de Java: utilizando los applets

Al pulsar el botón se procede a recuperar la URL de la caja de texto y a continuación se muestra en el navegador. Es necesario crear una instancia de la clase URL, ya que el método showDocument() recibe un objeto de esta clase como parámetro. Al crear la URL se debe atrapar la excepción que lanza su constructor, esta excepción es de la clase MalformedURLException, esta clase al igual que la clase URL se encuentra en el paquete java.net. El método showDocument() lo lanzamos sobre el atributo contexto, que como ya hemos comentado es el contexto que nos proporciona el applet. Si probamos este applet con Internet Explorer 5, volvemos a tener el problema de la ejecución del método destroy() al abandonar la página Web, este problema ya lo comentábamos en el capítulo anterior en el apartado dedicado al ciclo de vida de los applets. Como hemos dicho con IE 5 se ejecuta el método destroy() por lo tanto perdemos el contexto del applet y no podemos volver a cargar otra URL, es decir, el applet funciona sólo la primera vez. Sin embargo con Netscape Navigator 4.5 el funcionamiento es correcto y podemos cargar tantas URLs como queramos. Este applet, al consistir únicamente en una ventana, podemos insertarlo en la página Web con dimensiones cero. En la Figura 134 se puede ver un ejemplo de la ejecución de este applet.

Figura 134

Otra característica que ofrecen los applets y que se encuentra íntimamente relaciona con el navegador Web es la posibilidad de mostrar mensajes en la línea de estado del navegador. Para esto se vuelve a utilizar un método del interfaz AppletContext, en este caso showStatus(). El método showStatus() recibe como parámetro la cadena de texto que queremos mostrar en la línea de estado del navegador Web. Antes de continuar se debe aclarar que la línea de estado del navegador Web se encuentra en la zona inferior del mismo y es dónde se indica en que estado se encuentra el documento cargado actualmente. Para ilustrar la utilización de este nuevo método vamos a realizar un applet que consiste en una caja de texto, en la que introduciremos el texto que queremos aparezca en la línea de estado del navegador, y un botón con el que indicaremos que queremos asignar el texto correspondiente. El código de este sencillo applet es el Código fuente 187.

299

Programación en Java

© Grupo EIDOS

import java.applet.*; import java.awt.*; import java.awt.event.*; public class LineaEstado extends Applet implements ActionListener{ private Button boton; private TextField texto; public void init(){ boton=new Button("Muestra Estado"); texto=new TextField(20); setLayout(new GridLayout(1,2,5,5)); add(texto); add(boton); boton.addActionListener(this); } public void actionPerformed(ActionEvent evento){ AppletContext contexto=getAppletContext(); contexto.showStatus(texto.getText()); } } Código fuente 187

Y un ejemplo de la ejecución del mismo se puede observar en la Figura 135.

Figura 135

Hasta ahora se han comentado funciones de los applets que tienen que ver con el navegador Web directamente, como el propio título del apartado indica, pero también vamos a incluir en este mismo apartado un par de funciones de los applets, que aunque ya no tengan que ver directamente con el navegador, pueden resultar interesantes. La primera de estas funciones ya la habíamos comentado con anterioridad y consiste en el paso de parámetros al applet desde la página Web. Este paso de parámetros se realiza mediante la etiqueta . Para recuperar el parámetro desde el applet utilizamos el método getParameter() de la clase Applet, pasándole por parámetro una cadena que se corresponde con el nombre del parámetro. El Código fuente 188 se corresponde con el de un applet que recoge un parámetro llamado nombre, y muestra un saludo en la pantalla.

300

© Grupo EIDOS

15. Applets de Java: utilizando los applets

import java.applet.*; import java.awt.*; public class Parametros extends Applet{ private String parametro=""; public void init(){ parametro=getParameter("nombre"); if (parametro==null) parametro= "persona desconocida"; } public void paint(Graphics g){ g.drawString("Buenos días "+parametro,10,20); } } Código fuente 188

Como se puede observar en el código, el método init() es el encargado de recuperar el parámetro y es en el método paint() dónde se muestra el saludo utilizando el atributo del applet que posee el valor ofrecido por el parámetro. En la Figura 136 se muestra la ejecución de este applet, en las dos situaciones, con parámetro y sin el.

Figura 136

Y el código HTML de la página de la Figura 136 es el Código fuente 189.



Document Title





301

Programación en Java

© Grupo EIDOS



Código fuente 189

La siguiente, y última función de los applets que vamos a comentar en este apartado, es la reproducción se sonidos. Para reproducir sonidos disponemos del interfaz AudioClip que lo podemos encontrar dentro del paquete java.applet, pero para utilizar un objeto de este tipo debemos antes asignarle el fichero de sonido que representa. El interfaz AudioClip ofrece tres métodos que nos permiten manipular un fichero de sonido, éstos son play(), loop() y stop(). El método play() ejecuta el fichero de sonido, es decir, reproduce el sonido, el método loop() también lo reproduce pero en un bucle infinito, y stop() detiene la ejecución del sonido. Vamos a ver esto con el ejemplo de un applet que permite reproducir un sonido, pararlo y ejecutarlo en un bucle, primero se muestra el código (Código fuente 190) y a continuación lo comentamos.

import java.awt.*; import java.applet.*; import java.awt.event.*; import java.net.*; public class Sonidos extends Applet implements ActionListener{ private AudioClip sonido; private Button ejecutar,bucle,parar; public void init(){ setLayout(new GridLayout(3,1,10,10)); ejecutar=new Button("Play"); bucle=new Button("Loop"); parar=new Button("Stop"); add(ejecutar); add(bucle); add(parar); ejecutar.addActionListener(this); bucle.addActionListener(this); parar.addActionListener(this); //obtenemos el camino hasta el lugar dónde se encuentra el applet URL codeBase=getCodeBase(); //cargamos el fichero de sonido sonido=getAudioClip(codeBase,getParameter("sonido")); } public void actionPerformed(ActionEvent evento){ AppletContext contexto=getAppletContext(); if (evento.getSource()==ejecutar){ contexto.showStatus("Reproducir sonido"); sonido.play(); } else if (evento.getSource()==parar){ contexto.showStatus("Detener sonido"); sonido.stop(); } else{ contexto.showStatus("Reproducir sonido en un bucle"); sonido.loop(); } } } Código fuente 190

302

© Grupo EIDOS

15. Applets de Java: utilizando los applets

Como se puede comprobar a la vista del código, en este caso tenemos tres fuentes de eventos y un mismo oyente, por lo que en el método actionPerformed() se debe identificar la fuente del evento, para ello utilizamos el método getSource() de la clase java.util.EventObject, de esta clase heredan todas las clase que representan a los eventos. Este método nos devuelve la referencia al objeto que ha producido el evento, por lo tanto debemos comparar el valor devuelto con cada uno de los objetos que son fuente de eventos, es decir, con cada uno de los objetos Button. En el método init() del applet además de crear el interfaz de usuario (Figura 137) y registrar los oyentes correspondientes, cargamos el fichero de sonido. Pero antes necesitamos obtener la ruta hasta nuestro applet, esto se consigue mediante el método getCodeBase() de la clase Applet que nos devuelve un objeto de la clase URL que contiene la dirección hasta nuestro applet. A continuación utilizamos el método getAudioClip() de la clase Applet, el cual permite cargar en el objeto AudioClip correspondiente el fichero de sonido que le especificamos por parámetro. Como se habrá observado, el nombre del fichero de sonido lo pasamos mediante un parámetro del applet (etiqueta ) y lo recuperamos con el método getParameter() de la clase Applet.

Figura 137

Eventos, gráficos y fuentes en los applets En este apartado vamos a tratar las clases Graphics, FontMetrics y Font, es decir, vamos a tratar la parte gráfica de los applets, algo que habíamos comentado de forma muy breve al utilizar el método paint(). También se va a comentar algunos aspectos del tratamiento de eventos dentro de los applets y se mostrarán algunos tipos de eventos que no habíamos visto hasta ahora. Todo ello se irá mostrando y comentando a través de numerosos ejemplos de applets. Pasemos a la parte gráfica de nuestro apartado. El objeto de la clase Graphics que recibe como parámetro el método paint() de la clase Applet representa a la superficie del applet y todo lo que se dibuje o escriba en el se mostrará en el applet. Aunque el método paint() lo estamos utilizando en la clase Applet, se debe señalar que este método se hereda de la clase Container, y por lo tanto lo presentan todos los objetos que realicen funciones de contenedor. La superficie del applet en el navegador Web Internet Explorer 5 se representa mediante el color gris por defecto, pero en el navegador Netscape Navigator 4.5 se representa mediante el color blanco por defecto. El método de la clase Graphics que hemos estado utilizando en diferentes momentos en este capítulo ha sido drawString(). Este método mostrará la cadena de caracteres que le pasemos por parámetro y en la posición que le indiquemos. El origen de coordenadas en la superficie del applet se encuentra en la parte superior izquierda. 303

Programación en Java

© Grupo EIDOS

Vamos a realizar un applet que vaya mostrando las coordenadas sobre las que se encuentra en ese momento el cursor del ratón dentro del applet, además estas coordenadas se muestran justamente al lado del cursor, es decir, en la propia coordenada en la que se encuentra. Nuestro applet va a tener una clase interna que va a ser una clase adaptadora que hereda de la clase MouseMotionAdapter, es decir, va a ser la clase oyente de los movimientos del ratón en nuestro applet. Este ejemplo es interesante también porque vemos un evento que no habíamos tratado hasta ahora, el evento de los movimientos del ratón. El método que vamos a utilizar y sobrescribir de la clase MouseMotionAdapter es mouseMoved() . Como su propio nombre indica este método se ejecutará cuando se mueva el ratón. En este método recogemos los valores actuales de las coordenadas y se los asignamos a los atributos coordX y coordY de nuestro applet, estos atributos han sido declarados para representar a las coordenadas x e y del ratón dentro de nuestro applet. En la última línea del método mouseMoved() se llama al método repaint() para que se actualice y repinte la superficie de nuestro applet. Los valores de las coordenadas se obtienen utilizando los métodos getX() y getY() de la clase MouseEvent. En el método paint() escribiremos el valor de las coordenadas en la coordenada exacta, pero antes de seguir comentando más acerca de este applet de ejemplo veamos su código, en el Código fuente 191.

import java.awt.*; import java.applet.*; import java.awt.event.*; public class Coordenadas extends Applet{ int coordX, coordY; public void init(){ //se inicializan las coordenadas coordX=-1; coordY=-1; //registramos el oyente de los movimientos del ratón addMouseMotionListener(new AdaptadorMovimientosRaton()); } public void paint(Graphics g){ //se comprueba que las coordenadas son correctas if (coordX!=-1) //se escribe la coordenada en la posición en la //que está el ratón g.drawString("("+coordX+","+coordY+")",coordX,coordY); } //clase adaptadora interna que trata los movimientos del ratón class AdaptadorMovimientosRaton extends MouseMotionAdapter{ public void mouseMoved(MouseEvent evento){ coordX=evento.getX(); coordY=evento.getY(); //se vuelve a pintar el applet repaint(); } } } Código fuente 191

En el método paint() mostramos las coordenadas en las que se encuentra el cursor del ratón mediante el ya conocido método drawString() de la clase Graphics.

304

© Grupo EIDOS

15. Applets de Java: utilizando los applets

Pero si probamos este applet comprobamos que no funciona correctamente, ya que cuando salimos de la superficie del applet las coordenadas se quedan pintadas en la superficie del applet. Para evitar este efecto debemos modificar el código del applet para tener en cuenta también los eventos de la entrada y salida del ratón en nuestro applet. Para ello hemos creado una clase interna que herede a la clase adaptadora MouseAdapter y que implemente los métodos mouseExited() y mouseEntered(). Al applet Coordenadas se le añade un nuevo atributo de tipo booleano llamado fuera, para saber en que situación estamos. El nuevo código del applet se muestra en el Código fuente 192.

import java.awt.*; import java.applet.*; import java.awt.event.*; public class Coordenadas2 extends Applet{ int coordX, coordY; //indica si el ratón está fuera del applet boolean fuera; public void init(){ coordX=-1; coordY=-1; fuera=false; addMouseMotionListener(new AdaptadorMovimientosRaton()); addMouseListener(new AdaptadorRaton()); } public void paint(Graphics g){ //se comprueba si el ratón se encuentra en la //superficie del applet if(!fuera){ if(coordX!=-1) g.drawString("("+coordX+","+coordY+")",coordX,coordY); showStatus(""); } else showStatus("El ratón ha salido"); } class AdaptadorMovimientosRaton extends MouseMotionAdapter{ public void mouseMoved(MouseEvent evento){ coordX=evento.getX(); coordY=evento.getY(); repaint(); } } class AdaptadorRaton extends MouseAdapter{ public void mouseExited(MouseEvent evento){ //el ratón ha salido fuera=true; repaint(); } public void mouseEntered(MouseEvent evento){ //el ratón ha entrado fuera=false; repaint(); } } } Código fuente 192

305

Programación en Java

© Grupo EIDOS

En este código se muestra un mensaje en la línea de estado del navegador, pero no se utiliza el interfaz AppletContext, sino que directamente se utiliza el método showStatus() de la clase Applet, el resultado es el mismo que veíamos en el apartado anterior. Con esta nueva versión del applet ya no se produce el efecto comentado anteriormente, cuando desde el método mouseExited() se invoca al método paint() del applet mediante repaint(), el atributo fuera tiene el valor true, por lo tanto en el método paint() no escribe nada y se eliminan las coordenadas de la superficie del applet. En este punto es necesario realizar una aclaración. Cuando modificamos el código fuente de un applet que ya hemos ejecutado en el navegador, si lo volvemos a probar, en muchos casos, los cambios realizados no se reflejan, esto es debido a que el applet se encuentra en la memoria caché del navegador y se está utilizando la versión anterior de nuestro fichero de clase. En este caso la solución es cerrar el navegador y volver a abrirlo para probar el nuevo applet. En la Figura 138 se puede observar un ejemplo de ejecución de este applet.

Figura 138

Si cambiamos todas las sentencias repaint() por la siguiente paint(getGraphics()), podemos pensar que el efecto es el mismo, es decir, la llamada al método paint(). Si realizamos este cambio y ejecutamos el applet de nuevo vemos un efecto distinto, las coordenadas que escribimos nunca se borran, como se puede observar en la Figura 139. El método getGraphics() de la clase Component nos devuelve el objeto Graphics que se corresponde con la superficie del componente gráfico correspondiente, en este caso la superficie del applet.

Figura 139

306

© Grupo EIDOS

15. Applets de Java: utilizando los applets

Este efecto se produce porque no hemos definido correctamente lo que significa llamar al método repaint(), habíamos dicho que el método repaint() llamaba al método paint() del applet, pero esto no es correcto, ya que la llamada no es directa, sino que el método repaint() llama antes al método update() de la clase Component y después de llamar al método update() llama al método paint(). La función que realiza el método update() antes de llamar al método paint() es la de limpiar o borrar toda la superficie que se encuentre representada por la clase Graphics. Por lo tanto si antes de todas las sentencias paint(getGraphics()) añadimos la sentencia update(getGraphics()) el efecto será el idéntico al que se producía al lanzar el método repaint(). Vamos a seguir comentando la utilización del objeto Graphics en los applets en conjunción con el tratamiento de eventos dentro de los mismos. En este caso se va a mostrar un ejemplo de un applet que consiste en escribir en la superficie del mismo la cadena "¡click!" en las coordenadas en las que se haya producido la pulsación del ratón. Para ello vamos a utilizar una clase adaptadora que herede de la clase MouseAdapter, y el método que nos va a interesar va a ser el método mousePressed(). Este método se ejecutará cuando se pulse el botón del ratón. El código de este applet es el que se muestra en el Código fuente 193.

import java.awt.*; import java.applet.*; import java.awt.event.*; public class AppletClick extends Applet{ private int coordX,coordY; public void init(){ coordX=-1; coordY=-1; addMouseListener(new AdaptadorRaton(this)); } public void paint(Graphics g){ if (coordX!=-1) g.drawString("¡Click!",coordX,coordY); } //métodos de acceso public void modificaX(int x){ coordX=x; } public void modificaY(int y){ coordY=y; } } class AdaptadorRaton extends MouseAdapter{ private AppletClick fuente; public AdaptadorRaton(AppletClick fuente){ this.fuente=fuente; } //detectamos la pulsación en el ratón public void mousePressed(MouseEvent evento){ fuente.modificaX(evento.getX()); fuente.modificaY(evento.getY()); fuente.repaint(); } } Código fuente 193

307

Programación en Java

© Grupo EIDOS

Como se puede comprobar, al no utilizar una clase interna debemos ofrecer un par de métodos de acceso para que la clase AdaptadorRaton pueda modificar los atributos coordX y coordY de la clase AppletClick, van a ser estos dos atributos los que representen la coordenada en la que se debe escribir la cadena. Además debemos llevar la referencia de la clase fuente del evento, para ello la clase AdaptadorRaton tiene como atributo un objeto de la clase AppletClick. En este caso no es necesario controlar que el ratón salga de la superficie de nuestro applet, ya que el evento de la pulsación del ratón siempre se va a producir en el interior del mismo. El aspecto de este applet en ejecución es el de la Figura 140.

Figura 140

Podemos realizar una modificación sobre el código anterior para que la cadena "¡Click!" sólo aparezca en el momento de la pulsación del botón y no permanezca pintada en al superficie del applet. Para ello debemos implementar el método mouseReleased(). El método mouseReleased() se ejecutará cuando se suelte el botón del ratón, es decir, un click de ratón ejecutará primero el método mousePressed() y a continuación el método mouseReleased(). En el método mouseReleased() asignamos el valor –1 a los atributos de la clase AppletClick que representan las coordenadas del ratón y a continuación se llama al método repaint(). El código del método mouseReleased() se muestra en el Código fuente 194.

public void mouseReleased(MouseEvent evento){ fuente.modificaX(-1); fuente.modificaY(-1); fuente.repaint(); } Código fuente 194

Creo que ya hemos visto bastante de momento sobre el método drawString() de la clase Graphics, el método paint() y el tratamiento de eventos sobre la superficie del applet, por lo tanto a continuación nos vamos a centrar más en los distintos métodos de la clase Graphics. De esta clase comentaremos desde los métodos que nos permiten modificar el aspecto del applet a los que nos permiten dibujar distintas figuras e insertar ficheros de imágenes. También trataremos los tipos de fuente dentro de los applets.

308

© Grupo EIDOS

15. Applets de Java: utilizando los applets

En todos los ejemplos anteriores cuando escribimos una cadena en la superficie del applet ésta parece en negro, si queremos que aparezca en un color determinado el texto, utilizaremos el método setColor() de la clase Graphics, de esta forma todo lo que se pinte en el objeto Graphics del applet aparecerá con el color especificado como parámetro en el método setColor(). El método setColor() recibe como parámetro un objeto de la clase Color que va a representar el color que se quiere asignar al objeto Graphics correspondiente. La clase Color se encuentra dentro del paquete java.awt y representa como su nombre indica los colores. Esta clase ofrece una serie de constantes para representar colores estándar: rojo, azul, amarillo, etc. Así para asignar el color azul a un objeto Graphics escribiremos lo que indica el Código fuente 195.

g.setColor(Color.blue); Código fuente 195

Pero si queremos asignar un color personalizado por nosotros mismos, deberemos crear un objeto de la clase Color y pasárselo por parámetro al método setColor(). Para indicar un color personalizado, el constructor de la clase Color acepta como parámetros tres enteros en los rangos 0-255 siguiendo por lo tanto la definición de colores según la norma RGB. Cada uno de los enteros indica la intensidad de color rojo, verde y azul, respectivamente. De esta forma, si queremos asignar un color personalizado tenemos que escribir una sentencia similar a la que muestra el Código fuente 196.

g.setColor(new Color(200,4,100)); Código fuente 196

Para asignar un color al fondo del applet utilizamos el método setBackGround(), pero este método no lo ofrece la clase Graphics, sino que se encuentra en la clase Applet. Al método setBackGround() le pasamos por parámetro un objeto de la clase Color, al igual que hacíamos con el método anterior.

setBackground(new Color(12,134,100)); Código fuente 197

Hemos modificado el color de fondo del applet y el color de los elementos gráficos que van a aparecer en el mismo, ahora vamos a modificar el tipo de letra. Para modificar el tipo de letra utilizaremos el método setFont() de la clase Graphics. Este método recibe como parámetro un objeto de la clase Font que se corresponde con la letra que se desea utilizar. La clase Font se encuentra en el paquete java.awt y tiene un constructor que nos permite especificar el tipo o nombre de la letra, el aspecto que va a tener (normal, cursiva o negrita) y el tamaño de la misma. Así si queremos asignar a nuestro applet una letra de tipo Courier en negrita y de tamaño 20 píxeles escribiremos el Código fuente 198.

309

Programación en Java

© Grupo EIDOS

g.setFont(new Font("Courier",Font.BOLD,20)); Código fuente 198

Para definir los diferentes aspectos de las fuentes la clase Font ofrece una serie de constantes, Font.BOLD para la fuente en negrita, Font.ITALIC para la letra cursiva y Font.PLAIN para que muestre el aspecto normal. Para mostrar un ejemplo sencillo de todo lo visto hasta el momento vamos a realizar el famoso applet "Hola Mundo", pero modificando los colores y el tipo de letra. El código de este applet es el Código fuente 199.

import java.awt.*; import java.applet.*; public class HolaMundo extends Applet{ public void init(){ setBackground(Color.pink); } public void paint(Graphics g){ g.setColor(new Color(200,4,100)); g.setFont(new Font("TimesRoman",Font.ITALIC,20)); g.drawString("Hola Mundo",20,20); } } Código fuente 199

Y el aspecto de esta nueva versión del applet "Hola Mundo" se puede comprobar en la Figura 141.

Figura 141

La clase Font ofrece una serie de métodos que nos permiten consultar las características de la fuente actual. Estos métodos son:

310



getName(): devuelve una cadena que indica el nombre de la fuente.



getSize(): devuelve el tamaño de la fuente actual como un entero.

© Grupo EIDOS

15. Applets de Java: utilizando los applets



getStyle(): devuelve el aspecto de la fuente actual mediante un entero que se corresponde con los valores de las constantes de la clase Font. Font.PLAIN fuente normal tiene el valor 0, Font.BOLD fuente negrita tiene el valor 1, Font.ITALIC tiene el valor 2 y la combinación de negrita y cursiva devolverá el valor 3.



isPlain(): devuelve verdadero si el aspecto de la fuente es normal.



isBold(): devuelve verdadero si el aspecto de la fuente es negrita.



isItalic(): devuelve verdadero si el aspecto de la fuente es cursiva.

Para obtener información acerca de las fuentes en el paquete java.awt encontramos también la clase FontMetrics. Esta clase ofrece una serie de métodos que permiten consultar una serie características de las fuentes que tiene asignadas actualmente la clase Graphics y que tiene que ver con las métricas de la fuente. Para obtener una instancia de un objeto de la clase FontMetrics lanzaremos el método getFontMetrics() de la clase Graphics sobre el objeto Graphics del que se quiere consultar la información de su letra. Algunos de los métodos de la clase FontMetrics son getHeight() y getCharWidth(), que nos indican la altura de la letra y la anchura de un carácter determinado, respectivamente, en pixeles. Como se puede deben ver estos métodos ofrecen una información más detallada y específica de las métricas de la fuente que los métodos de la clase Font. Otros métodos de esta clase son: •

stringWidth(): se le pasa una cadena por parámetro y devuelve la anchura de la cadena en pixeles.



getAscent(): devuelve la distancia entre la línea base de la fuente y la parte superior de los caracteres.



getDescent(): devuelve la distancia entre la línea base de la fuente y la parte inferior de los caracteres, esto se aplica a caracteres como p y q que caen más bajo de la línea base.



getLeading(): devuelve el interlineado de la fuente.

El siguiente ejemplo es un applet que permite configurar el mensaje "Hola Mundo", ofrece un interfaz de usuario para realizar esta tarea, además mediante este interfaz de usuario vamos a comentar el tratamiento de nuevos eventos, como son el de selección de una lista desplegable, la entrada de texto en un caja de texto y el de la selección de una casilla de verificación. Para la construcción del interfaz se ha utilizado el gestor de diseño GridLayout, BorderLayout y el anidamiento de objetos Panel. Se podría considerar que este applet es un ejemplo que además de mostrar lo que hemos explicado sobre el tratamiento de fuentes y color, también ofrece un resumen de muchos de los puntos vistos en anteriores apartados y capítulos, por lo que puede resultar bastante interesante. Este applet va a ser algo complicado, por lo tanto vamos a cambiar un poco la filosofía que veníamos utilizando hasta ahora en la explicación de los ejemplos, en lugar de mostrar todo el código y luego comentarlo, vamos a desglosarlo y comentarlo más minuciosamente, aunque para una mayor claridad al final de la exposición mostraremos el código completo. El primer punto que vamos a tratar va a ser la construcción del interfaz de usuario. Para que sea más claro primero vamos a mostrar el aspecto del applet, a continuación comentamos un poco su estructura y a continuación se procederá a facilitar el código fuente. El interfaz de usuario que presenta el applet 311

Programación en Java

© Grupo EIDOS

va a ser el de la Figura 142, que como se puede ver está formado por un objeto TextField, varios objetos Label, dos objetos Checkbox y dos objetos Choice.

Figura 142

En realidad todos los componentes AWT utilizados se encuentran incluidos dentro de un objeto Panel, y es este objeto Panel, conteniendo todos los componentes, el que se añade al applet. Se han utilizado diversos paneles auxiliares, con diferentes gestores de diseño, para ir colocando los componentes del interfaz de usuario. El panel principal, denominado en el código panelInterfaz, presenta un gestor de diseño de la clase GridLayout de 2 filas y una columna. En la primera fila se añade un panel representado por el objeto panel1, que contendrá los controles que indican el tamaño y aspecto de la fuente, y en la segunda fila un panel representado por el objeto panel3. A su vez estos dos paneles incluyen en su interior otros gestores de diseño y otros paneles. En la Figura 143 se puede ver un esquema en el que se identifican cada uno de los paneles y como se encuentran divididos.

Figura 143

El código que permite construir este interfaz de usuario lo tenemos en el método creaInterfaz(). Todos los componentes AWT utilizados para crear el interfaz han sido declarados como atributos de nuestro applet.

public void creaInterfaz(){ //panel que contiene todo el interfaz panelInterfaz=new Panel(); panelInterfaz.setLayout(new GridLayout(2,1)); //panel que contiene los controles de tamaño y aspecto de la fuente

312

© Grupo EIDOS

15. Applets de Java: utilizando los applets

panel1=new Panel(); panel1.setLayout(new GridLayout(1,3,5,1)); //panel que contiene la caja de texto con el tamaño de la fuente panel2=new Panel(); panel2.setLayout(new BorderLayout()); tamaño=new TextField(10); panel2.add("North",new Label("Tamaño")); panel2.add("South",tamaño); panel1.add(panel2); negrita=new Checkbox("Negrita"); panel1.add(negrita); cursiva=new Checkbox("Cursiva"); panel1.add(cursiva); panelInterfaz.add(panel1); //panel que contiene las dos listas desplegables panel3=new Panel(); panel3.setLayout(new GridLayout(1,2,5,1)); //panel que contiene la lista con los tipos de letra panel4=new Panel(); panel4.setLayout(new GridLayout(2,1)); panel4.add(new Label("Tipo Letra:")); tipoLetra=new Choice(); tipoLetra.addItem("Courier"); tipoLetra.addItem("Arial"); tipoLetra.addItem("TimesRoman"); panel4.add(tipoLetra); panel3.add(panel4); //panel que contiene la lista con los colores panel5=new Panel(); panel5.setLayout(new GridLayout(2,1)); panel5.add(new Label("Color Letra:")); colorLetra=new Choice(); colorLetra.addItem("rojo"); colorLetra.addItem("azul"); colorLetra.addItem("verde"); panel5.add(colorLetra); panel3.add(panel5); panelInterfaz.add(panel3); add(panelInterfaz); } Código fuente 200

A la vista del código fuente del método creaInterfaz() y el esquema de la Figura 143, damos por concluida la primera parte de la explicación. Al añadir el panel panelInterfaz al applet, el resto de la superficie del applet queda reservada para contener la cadena de texto a la que se va a ir modificando su aspecto según lo indiquemos en los controles del interfaz de usuario. Ahora debemos centrarnos en el tratamiento de eventos. En nuestro applet tenemos cinco fuentes de eventos, la caja de texto, las dos casillas de verificación y las dos listas desplegables, pero vamos a tener un único oyente, nuestro applet. La caja de texto va a lanzar un evento del tipo TextEvent cada vez que se modifique, ya que queremos que se cambie el tamaño de las letras mientras que lo indicamos en la caja de texto. Este evento puede ser atrapado y tratado por un oyente que implemente el interfaz TextListener. El interfaz TextListener tiene un único método, llamado textValueChanged() y que se ejecutará cuando se modifique el contenido de la caja de texto. Por lo tanto el applet deberá implementar el interfaz TextListener.

313

Programación en Java

© Grupo EIDOS

Cuando cambiamos el valor de un objeto Checkbox o un objeto Choice se lanza un evento de la clase ItemEvent. Este evento será tratado por un oyente que implemente el interfaz ItemListener. El interfaz ItemListener, al igual que el anterior, tiene un único método llamado itemStateChanged() que se ejecutará cuando se seleccione un elemento de la lista o se modifique el valor de la casilla de verificación. Por lo tanto nuestro applet además de implementar el interfaz TextListener debe implementar el interfaz ItemListener. La declaración de nuestra subclase de clase Applet quedaría como indica el Código fuente 201.

public class Fuentes extends Applet implements ItemListener, TextListener{ } Código fuente 201

En el método itemStateChanged() deberemos distinguir en que situación estamos, ya que este método se puede ejecutar desde cuatro fuentes diferentes, las dos casillas de verificación o las dos listas desplegables, realizando en cada caso un proceso distinto, cada uno de estos procesos los comentaremos más adelante. El tratamiento de cualquiera de las cinco situaciones distintas que se puedan dar en el lanzamiento de un evento, es decir, modificación del contenido de la caja de texto, modificación de cualquiera de las dos casillas de verificación y selección de un elemento de cualquiera de las dos listas, ocasionarán una llamada al método repaint(), y consecuentemente una llamada al método paint(), que es precisamente el método que pasamos a comentar a continuación. En el método paint() lo que vamos a hacer va a ser asignar al objeto Graphics de nuestro applet los valores que se hayan indicado en el interfaz de usuario y que tienen que ver con el color de la letra, tamaño, tipo y aspecto. Por lo tanto es necesario definir en nuestro applet cuatro atributos que representen cada uno de estos valores. Y en los métodos para el tratamiento de eventos, es decir en los métodos textValueChanged() y itemStateChanged(), lo que deberemos hacer antes de llamar al método repaint() es actualizar el valor del atributo correspondiente. El método paint() simplemente emplea los valores de los atributos del applet para dibujar en pantalla el mensaje Hola Mundo. El código de este método es el Código fuente 202.

public void paint(Graphics g){ g.setFont(new Font(tipo,aspecto,tam)); g.setColor(color); g.drawString("Hola Mundo",10,180); } Código fuente 202

Aquí se pueden apreciar los atributos que se han definido para nuestra clase Fuentes. El atributo tipo de la clase String contendrá el valor que se ha seleccionado en la lista desplegable que contiene los tipos de letra disponibles, el atributo aspecto del tipo primitivo int contiene el valor de la combinación de las casillas de verificación que indican si la letra va ser en negrita y/o en cursiva. El atributo tam del tipo primitivo int contiene el valor de la caja de texto que indica el tamaño de la fuente, y por último el atributo color que es un objeto de la clase Color, va a contener el color indicado en la lista desplegable correspondiente. Si bien el resto de los valores de los atributos se asigna de 314

© Grupo EIDOS

15. Applets de Java: utilizando los applets

forma más o menos directa, en el caso del atributo color debemos emplear un método auxiliar llamado devuelveColor() que permite realizar la traducción del color especificado en la lista de colores con los disponibles en la clase Color como constantes de la misma. El código de este método es el Código fuente 203.

public Color devuelveColor(String col){ if (col.equals("rojo")) return Color.red; else if (col.equals("azul")) return Color.blue; else return Color.green; } Código fuente 203

En el método init() del applet se deben inicializar los todos estos atributos, además de esta inicialización se lanza el método creaInterfaz() y se registra el oyente para las cinco fuentes de eventos ya comentadas. El código del método init() es el Código fuente 204.

public void init(){ creaInterfaz(); tam=20; tipo="Arial"; color=Color.green; aspecto=Font.PLAIN; tipoLetra.addItemListener(this); colorLetra.addItemListener(this); tamaño.addTextListener(this); negrita.addItemListener(this); cursiva.addItemListener(this); } Código fuente 204

Ya sólo nos queda entrar en detalle en los métodos que tratan los eventos. El método textValueChanged() recupera el valor de la caja de texto correspondiente, lo transforma al tipo primitivo int y se lo asigna al atributo tam de la clase Fuentes. La conversión de cadena de caracteres a tipo int se realiza mediante el método estático parseInt() de la clase Integer, si se produce algún error en la transformación se lanza la excepción NumberFormatException, si se produce esta excepción no se modifica el valor del atributo tam.

public void textValueChanged(TextEvent evento){ int t; try{ t=Integer.parseInt(tamaño.getText()); tam=t; repaint(); } catch (NumberFormatException ex){} } Código fuente 205

315

Programación en Java

© Grupo EIDOS

El método itemStateChanged() debe utilizar el método getSource() sobre el objeto evento de la clase ItemEvent que recibe como parámetro, para averiguar la fuente del evento, ya que, como ya hemos comentado, hay cuatro fuentes posibles. Si el origen del evento es cualquiera de los dos objetos Choice se recupera el valor de la lista desplegable mediante el método getSelectedItem() de la clase Choice, y se le asigna al atributo correspondiente. Y si el origen del evento es uno de los objetos Checkbox se modifica el atributo aspecto sumándole o restándole, según el estado del objeto Checkbox, el valor que se corresponde con la casilla verificada, es decir, Font.BOLD o Font.ITALIC. El código de este método se puede observar en el Código fuente 206.

public void itemStateChanged(ItemEvent evento){ if(evento.getSource()==tipoLetra){ tipo=tipoLetra.getSelectedItem(); } else if(evento.getSource()==colorLetra){ color=devuelveColor(colorLetra.getSelectedItem()); } else if(evento.getSource()==negrita){ if (negrita.getState()) aspecto=aspecto+Font.BOLD; else aspecto=aspecto-Font.BOLD; } else if (evento.getSource()==cursiva){ if (cursiva.getState()) aspecto=aspecto+Font.ITALIC; else aspecto=aspecto-Font.ITALIC; } repaint(); } Código fuente 206

Una vez comentado cada fragmento del código del applet Fuentes, en el Código fuente 207, se muestra el código completo del mismo para tener una visión más general.

import import import public

java.awt.*; java.applet.*; java.awt.event.*; class Fuentes extends Applet implements ItemListener, TextListener{

private Choice tipoLetra, colorLetra; private Checkbox negrita, cursiva; private TextField tamaño; private Panel panelInterfaz, panel1, panel2,panel3,panel4,panel5; private String tipo; private int tam; private Color color; private int aspecto; public void init(){ creaInterfaz(); tam=20; tipo="Arial"; color=Color.green; aspecto=Font.PLAIN;

316

© Grupo EIDOS

15. Applets de Java: utilizando los applets

tipoLetra.addItemListener(this); colorLetra.addItemListener(this); tamaño.addTextListener(this); negrita.addItemListener(this); cursiva.addItemListener(this); } public void itemStateChanged(ItemEvent evento){ if(evento.getSource()==tipoLetra){ tipo=tipoLetra.getSelectedItem(); } else if(evento.getSource()==colorLetra){ color=devuelveColor(colorLetra.getSelectedItem()); } else if(evento.getSource()==negrita){ if (negrita.getState()) aspecto=aspecto+Font.BOLD; else aspecto=aspecto-Font.BOLD; } else if (evento.getSource()==cursiva){ if (cursiva.getState()) aspecto=aspecto+Font.ITALIC; else aspecto=aspecto-Font.ITALIC; } repaint(); } public void textValueChanged(TextEvent evento){ int t; try{ t=Integer.parseInt(tamaño.getText()); tam=t; repaint(); } catch (NumberFormatException ex){} } public Color devuelveColor(String col){ if (col.equals("rojo")) return Color.red; else if (col.equals("azul")) return Color.blue; else return Color.green; } public void paint(Graphics g){ g.setFont(new Font(tipo,aspecto,tam)); g.setColor(color); g.drawString("Hola Mundo",10,180); } public void creaInterfaz(){ //panel que contiene todo el interfaz panelInterfaz=new Panel(); panelInterfaz.setLayout(new GridLayout(2,1)); //panel que contiene los controles de tamaño y aspecto de la fuente panel1=new Panel(); panel1.setLayout(new GridLayout(1,3,5,1)); //panel que contiene la caja de texto con el tamaño de la fuente panel2=new Panel(); panel2.setLayout(new BorderLayout()); tamaño=new TextField(10); panel2.add("North",new Label("Tamaño")); panel2.add("South",tamaño); panel1.add(panel2); negrita=new Checkbox("Negrita"); panel1.add(negrita); cursiva=new Checkbox("Cursiva"); panel1.add(cursiva); panelInterfaz.add(panel1);

317

Programación en Java

© Grupo EIDOS

//panel que contiene las dos listas desplegables panel3=new Panel(); panel3.setLayout(new GridLayout(1,2,5,1)); //panel que contiene la lista con los tipos de letra panel4=new Panel(); panel4.setLayout(new GridLayout(2,1)); panel4.add(new Label("Tipo Letra:")); tipoLetra=new Choice(); tipoLetra.addItem("Courier"); tipoLetra.addItem("Arial"); tipoLetra.addItem("TimesRoman"); panel4.add(tipoLetra); panel3.add(panel4); //panel que contiene la lista con los colores panel5=new Panel(); panel5.setLayout(new GridLayout(2,1)); panel5.add(new Label("Color Letra:")); colorLetra=new Choice(); colorLetra.addItem("rojo"); colorLetra.addItem("azul"); colorLetra.addItem("verde"); panel5.add(colorLetra); panel3.add(panel5); panelInterfaz.add(panel3); add(panelInterfaz); } } Código fuente 207

En el siguiente enlace se puede encontrar el fichero de código fuente del applet. En la Figura 144 se ofrece un ejemplo de la ejecución del applet. Y con esto se da por concluida la explicación de este applet de ejemplo. Lo que veremos a continuación serán los diferentes métodos que nos ofrece la clase Graphics para realizar figuras.

Figura 144

Hasta ahora sólo hemos visto un método que nos permita dibujar algo en la superficie del applet, el método drawString(), pero la clase Graphics ofrece una serie de métodos que nos permiten dibujar diferentes tipos de figuras como pueden ser circunferencias, rectángulos, todo tipo de polígonos, etc.

318

© Grupo EIDOS

15. Applets de Java: utilizando los applets

La clase Graphics tiene una serie de métodos del tipo drawXXX() donde XXX será el tipo de figura que se desea dibujar. Algunos de estos métodos del tipo drawXXX() tienen su equivalente método fillXXX(), estos métodos dibujan la misma figura pero la rellenan de color. Por ejemplo el método drawRect(), que dibuja un rectángulo, tiene su equivalente fillRect(), que dibuja un rectángulo de color, según el color que se haya especificado al objeto Graphics. Todos estos métodos de dibujo reciben una serie de parámetros del tipo entero int que se corresponde con las coordenadas y dimensiones de las figuras. El Código fuente 208 dibujaría un rectángulo de anchura 125 y altura 180 en la posición (35,15) .

public void paint(Graphics g){ g.drawRect(35,15,125,180); } Código fuente 208

El siguiente applet de ejemplo permite elegir de una lista desplegable la figura que se desea dibujar en la superficie del mismo. Al producirse la selección se dibuja en el applet la figura correspondiente. El tratamiento de eventos en este applet es muy sencillo simplemente debemos implementar el interfaz ItemListener, ya que es el encargado de atrapar los eventos que provienen de la selección de una lista. En el método itemStateChanged() vamos a recoger el nombre de la figura seleccionada y se lo vamos a asignar a un atributo de nuestra clase llamado seleccion y que va a ser un objeto de la clase String. El atributo seleccion contiene el nombre de la figura que se desea dibujar. El método itemStatedChanged() también realizará una llamada al método repaint() para que se ejecute el método paint() del applet. En el método paint() dibujaremos la figura correspondiente atendiendo al valor del atributo seleccion. El código completo de este applet se puede ver en el Código fuente 209.

import java.awt.*; import java.applet.*; import java.awt.event.*; public class Figuras extends Applet implements ItemListener{ private Choice figuras; private String seleccion; public void init(){ setLayout(new BorderLayout()); figuras=new Choice(); figuras.addItem("línea"); figuras.addItem("rectángulo"); figuras.addItem("cuadrado"); figuras.addItem("rectángulo redondeado"); figuras.addItem("rectángulo 3D"); figuras.addItem("arco"); figuras.addItem("elipse"); figuras.addItem("círculo"); figuras.addItem("polígono"); add("South",figuras); seleccion=""; figuras.addItemListener(this); } public void itemStateChanged(ItemEvent evento){ seleccion=figuras.getSelectedItem();

319

Programación en Java

© Grupo EIDOS

repaint(); } public void paint(Graphics g){ if (seleccion.equals("línea")) // coordenadas origen, coordenadas fin g.drawLine(35,15,90,200); else if (seleccion.equals("rectángulo")) //coordenadas,anchura,altura g.drawRect(35,15,125,180); else if (seleccion.equals("cuadrado")) g.drawRect(35,15,125,125); else if (seleccion.equals("rectángulo redondeado")) //coordenadas,anchura,altura,arco de la esquina g.drawRoundRect(35,15,125,180,20,20); else if (seleccion.equals("rectángulo 3D")) //coordenadas,anchura,altura,elevación g.draw3DRect(35,15,125,185,true); else if (seleccion.equals("arco")) //coordenadas,anchura,altura,ángulo inicio, grados g.drawArc(35,15,160,160,90,180); else if (seleccion.equals("elipse")) //coordenadas,anchura, altura g.drawOval(35,15,160,100); else if (seleccion.equals("círculo")) g.drawOval(35,15,100,100); else if (seleccion.equals("polígono")){ //coordenadas x, coordenadas y, número de puntos int coordX[]={39,94,97,142,53,58,26}; int coordY[]={33,74,36,70,108,80,106}; int puntos=coordX.length; g.drawPolygon(coordX,coordY,puntos); } } } Código fuente 209

En este enlace se puede obtener el código del ejemplo. En este ejemplo se han utilizado los diferentes métodos drawXXX() de la clase Graphics, cada uno de ellos se acompaña de un comentario en el que se indica el significado de los parámetros. Un ejemplo de la ejecución del applet anterior se puede observar en la Figura 145.

Figura 145

320

© Grupo EIDOS

15. Applets de Java: utilizando los applets

Es posible copiar un área rectangular de un objeto Graphics a una posición diferente, para ello se utiliza el método copyArea() de la clase Graphics. Este método recibe los siguientes parámetros: coordenadas de origen, anchura y altura del área a copiar, coordenadas de destino. Así por ejemplo, si deseamos copiar un área cuadrada de 100 pixeles a 100 pixeles a su derecha escribiremos lo que muestra el Código fuente 210.

g.copyArea(0,0,100,100,100,0); Código fuente 210

Para borrar un área rectangular de un objeto Graphics se utiliza el método clearRect() de la misma clase. Este método recibe como parámetro las coordenadas y la anchura y altura del área a borrar, es decir, tiene los mismos parámetros que el método drawRect(). Para terminar este apartado comentaremos el método drawImage() de la clase Graphics. Este método permite mostrar en la superficie del applet el contenido de un fichero de imagen. Como parámetros recibe un objeto de la clase Image, las coordenadas en las que va a mostrarse la imagen y una referencia a la clase que va a contener a la imagen y la va a mostrar. La clase Image se encuentra en el paquete java.awt y representa una imagen. Para crear un objeto Image se utilizará el método getImage() de la clase Applet. Este método devuelve el objeto Image que se corresponde con el nombre del fichero de imagen que se le pasa por parámetro. Para obtener el nombre completo del fichero de imagen se debe utilizar el método ya conocido getCodeBase() de la clase Applet. El Código fuente 211 se corresponde con un applet que muestra una imagen que se encuentra enmarcada mediante un rectángulo con las esquinas redondeadas.

import java.applet.*; import java.awt.*; import java.net.URL; public class Imagen extends Applet{ Image imagen; public void init(){ URL codeBase=getCodeBase(); //creamos el objeto imagen imagen=getImage(codeBase,"arma.gif"); } public void paint(Graphics g){ //tamaño de la imagen int anchura=imagen.getWidth(this); int altura=imagen.getHeight(this); //se dibuja el rectángulo g.drawRoundRect(52,52,anchura+10,altura+10,30,30); //se dibuja la imagen g.drawImage(imagen,57,57,anchura,altura,this); } } Código fuente 211

321

Programación en Java

© Grupo EIDOS

Para obtener el tamaño de la imagen utilizamos los método getWidth() y getHeight() de la clase Image. Estos dos métodos tienen un parámetro que será una referencia a la clase que muestra la imagen, en este caso es el mismo applet, por lo que se utiliza this. El aspecto de este applet es el de la Figura 146

Figura 146

Compresión de applets Como ya hemos comentado los applets pueden estar formados por diferentes clases. Cuando cargamos uno de estos applets en una página Web, se establece una conexión para cada una de la clases de los applets con el servidor Web que contiene las mismas. De esta forma si hay una página Web con muchos applets o con un applet muy complejo que para su ejecución necesita de un gran número de clases, se incrementarán los tiempos de espera en la carga de los mismos, ya que cada vez que se carga un fichero .CLASS es necesaria una nueva conexión a través de la red, esto es, si el applet tiene veinte clases entonces serán necesarias veinte peticiones HTTP (HyperText Transfer Protocol) que el navegador debe realizar. Esto supone una gran pérdida de tiempo, ya que además de conectarse veinte veces al mismo servidor Web, los ficheros .CLASS no se encuentran comprimidos con utilidades de compresión como PKZIP o similares. Para reducir los tiempos de descarga de los applets se ha creado un mecanismo para enviar los applets a través de la Web dentro de un sólo fichero que contiene todos los ficheros de las clases necesarias y todos los recursos que utilice el applet como pueden ser imágenes o sonidos. De esta forma el navegador sólo necesita realizar una sola conexión con el servidor Web, ya que todos los ficheros necesarios se encuentran en un único fichero. Además de introducir en un mismo archivo todos los ficheros necesarios, se comprimen éstos de forma individual, así se reduce de forma considerable el tiempo de carga. Esta solución la implementan dos mecanismos diferentes, pero que esencialmente hacen lo mismo: ficheros CAB (cabinet files) y ficheros JAR (Java archive). La gran diferencia entre ficheros CAB y ficheros JAR es el formato de los ficheros y los algoritmos de compresión. Los ficheros CAB usan el formato de los ficheros cabinet de Microsoft, que ha sido utilizado por los productos y paquetes de instalación de Microsoft durante bastante tiempo. 322

© Grupo EIDOS

15. Applets de Java: utilizando los applets

En este apartado vamos a comentar ambos mecanismos y también vamos a comentar que herramientas tenemos a nuestra disposición para comprimir ficheros de clase. Para la creación de ficheros cabinet disponemos de la herramienta Microsoft SDK for Java 3.2, esta herramienta la obtenemos del Web de Microsoft, ya que desgraciadamente Visual J++ no nos ofrece ninguna herramienta para empaquetar ficheros de clase. Los ficheros cabinet se basan en el sistema de compresión Lempei-Ziv, como parte fundamental de este formato está la herramienta de compresión Diamond, que provee una compresión eficiente para los datos de programas de instalación y aplicaciones para Internet. Con la herramienta Diamond se pueden almacenar varios ficheros en un único fichero cabinet, y comprimir cada uno de ellos. Diamond es utilizado por la herramienta llamada CABARC (CABinet ARChiver), y esta será la herramienta que usaremos para la creación del fichero cabinet que, como se ha comentado, contendrá todos los ficheros de las clases utilizadas por los applets. La herramienta CABARC la encontramos dentro de Microsoft SDK for Java 3.2. La herramienta CABARC tiene múltiples opciones, pero las más relevantes son: n para la creación de un nuevo fichero cabinet y l para listar los contenidos del fichero cabinet. De esta forma para crear el fichero cabinet llamando clases.cab con todos los ficheros .CLASS del directorio actual se debe escribir lo siguiente en la línea de comandos: cabarc n clases.cab *.class Para asegurarnos que los ficheros que han sido añadidos al fichero clases.cab son los correctos, se puede escribir lo que indica el Código fuente 212.

cabarc l clases.cab Código fuente 212

Para poder utilizar el fichero clases.cab dentro de la página Web, se debe utilizar un parámetro de la etiqueta llamado CABBASE.



Código fuente 213

El único navegador que soporta ficheros cabinet es Internet Explorer. El formato genérico que presentan los ficheros .CAB es el que se puede apreciar en la Figura 147. Otra utilidad adicional que presentan los ficheros .CAB, es la posibilidad de firmarlos digitalmente. De esta forma, cuando un usuario cargue el applet se le preguntará si acepta la firma digital. Si acepta el applet ya no estará sujeto a las restricciones de seguridad, es decir, se podrá conectar a cualquier máquina de Internet, podrá acceder al sistema local de ficheros, podrá instanciar y usar objetos COM, etc. La firma digital asegura la integridad (el código no ha sido alterado ni manipulado después de su publicación) y la autenticidad (indicando el lugar del que proviene el código).

323

Programación en Java

© Grupo EIDOS

Figura 147

Para realizar una firma digital es necesario tener un certificado, para conseguir un certificado válido (SPC, Software Publisher Certificate) es necesario contactar con una autoridad de certificación (CA, Certification Authorities) algunas de ellas son: GTE, VeriSing Inc., etc. La persona que pide el certificado debe identificarse con sus credenciales y garantizar que el código (en nuestro caso los applets) no contiene virus ni elementos maliciosos que puedan dañar el sistema del usuario. El segundo tipo de empaquetado que podemos realizar es a través del formato JAR, este formato es más estándar que el anterior, ya que lo soportan tanto los navegadores Web Netscape Navigator e Internet Explorer, además es el formato propuesto por Sun. Los ficheros JAR se comprimen atendiendo al formato ZIP. Los ficheros JAR también permiten la firma de código. Para crear ficheros JAR Sun nos ofrece la herramienta Java Archive Tool, esta herramienta se ofrece junto el kit de desarrollo JDK (Java Developers Kit) de Sun. Para crear un fichero JAR con todos los ficheros del directorio actual deberemos escribir lo siguiente en la línea de comandos, dónde fichero.jar contendrá todos los ficheros comprimidos. jar cf fichero.jar * Para que un applet contenido en un fichero JAR se pueda incluir en una página Web es necesario escribir el código HTML que se muestra en el Código fuente 214.

Código fuente 214

En este caso se utiliza una propiedad de la etiqueta APPLET llamada ARCHIVE. En definitiva debemos utilizar ficheros CAB y/o JAR debido a que:

324



Ofrecen una compresión eficiente.



Supone un beneficio inmediato y significante para los usuarios de nuestra página Web ya que permite una reducción en el tiempo de carga e inicialización de los applets.

© Grupo EIDOS

15. Applets de Java: utilizando los applets

Componentes Swing y applets En todos los ejemplos utilizados en este capítulo y en el anterior hemos utilizado componentes AWT dentro de objetos de la clase Applet, para construir interfaces de usuario dentro de nuestros applets, también podríamos haber utilizado componentes Swing conjuntamente con la clase javax.swing.JApplet, pero si lo hubiéramos hecho posiblemente al cargar nuestro applet en el navegador no nos habría funcionado. El problema consiste en que en las MV (maquinas virtuales) que poseen los navegadores Netscape o Explorer no poseen la última versión del lenguaje Java, como ejemplo cabe reseñar que Internet Explorer 5 o Netscape Navigator 4.5 no permiten la ejecución de estos applets, mejor dicho, no ocurre nada cuando se ejecuta una página que invoca a uno de estos applets. La máquina virtuales de estos dos navegadores se corresponden con la versión 1.1 del lenguaje Java, es decir, no soportan Java 2. Lo mismo ocurrirá con el visor de applets de Visual J++, sin embargo el visor de applets del JBuilder y del JDK (appletviewer) si que implementan la última versión del lenguaje Java, la plataforma Java 2. La solución para poder utilizar applets Swing (JApplet) en un navegador Web consiste en instalar un software (a modo de parche) que podemos encontrar en el sitio Web de Sun y que se denomina Java Plug-in. Este añadido permite ejecutar applets implementados en Swing, que heredarán de la clase JApplet, esta clase del paquete javax.swing la comentaremos en el siguiente apartado. El Plug-in lo podemos obtener en la dirección http://java.sun.com/products/plugin/, a la hora de obtener el Plug-in deberemos indicar el tipo de plataforma en el que vamos a utilizarlo. También existen varias versiones del Plug-in en nuestro caso nos interesa la última que se corresponde con el JDK 1.3, por lo tanto seleccionaremos el software Java Plug-in 1.3. La instalación del Plug-in en un sistema operativo Windows no tiene ningún tipo de complicación, simplemente deberemos ejecutar el fichero que hemos obtenido de Sun y seguir las instrucciones correspondientes incluso el hecho de que se tenga que utilizar diferentes navegadores Internet Explorer o Netscape Navigator no va a resultar ningún problema, ya que se instala en el sistema operativo independientemente del navegador que se utilice. Solo a la hora de crear la página Web que vaya a hacer la llamada al applet es la que va a ser diferente dependiendo del tipo de navegador. Otra cosa importante es que a diferencia de los applets que no utilizan Swing, con este tipo de applets no vamos a utilizar la etiqueta en el código HTML en ningún caso, puesto que en realidad lo que estamos haciendo es una llamada a un componente ActiveX (proporcionado por el Java Plug-in) que se encarga de su visualización. Debido a esto la etiqueta utilizada es o dependiendo de si el navegador Web es Internet Explorer o Netscape Navigator respectivamente. Así por ejemplo si tenemos la clase SwingApplet, que es la clase que representa a un applet, si queremos incluirla en una página HTML, escribiríamos el código HTML que aparece en el Código fuente 215.

Código fuente 215

Pero si esta clase es un applet de Swing, es decir, hereda de la clase JApplet, deberemos escribir el Código fuente 216, suponiendo que el navegador Web que va a cargar la página, es Internet Explorer. 325

Programación en Java

© Grupo EIDOS



Código fuente 216

Pero si el navegador Web es Netscape Navigator escribiremos el Código fuente 217.