250 36 5MB
Spanish Pages [367] Year 2000
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