libro java

357
Escuela de Ingeniería en Computación Universidad de La Serena. LECTURAS PARA PROGRAMACIÓN ORIENTADA A OBJETOS UTILIZANDO

Upload: matthew-lee

Post on 30-Oct-2014

122 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Libro Java

Escuela de Ingeniería en ComputaciónUniversidad de La Serena.

LECTURAS PARA PROGRAMACIÓN ORIENTADA A OBJETOS UTILIZANDO

Dr. Eric Jeltsch F.

Agosto 2007.

Page 2: Libro Java

I N D I C E

I N D I C E.................................................................................................................................................................2

C A P I T U L O I......................................................................................................................................................4Características de la Poo.....................................................................................................................................10

C A P I T U L O II..................................................................................................................................................25Elementos Básicos en todo programa Java: Objetos y Métodos.........................................................................28Como construyo programas?...............................................................................................................................29Primer encuentro con POO, el método System.out.println.................................................................................30Cómo edito un programa?...................................................................................................................................30Cómo ejecuto un programa Java.........................................................................................................................31Java, una Plataforma Independiente...................................................................................................................33Una visión de la plataforma JDK........................................................................................................................35Instalación de Java..............................................................................................................................................36

C A P I T U L O III.................................................................................................................................................42Elementos del Lenguaje.......................................................................................................................................42Tipos de Datos y Strings......................................................................................................................................42Algunos Operadores.............................................................................................................................................43Variables..............................................................................................................................................................43Asignaciones........................................................................................................................................................45Punto Flotante......................................................................................................................................................46Funciones Estándares..........................................................................................................................................47Clases de I/O........................................................................................................................................................49ConsoleReader.....................................................................................................................................................52hsa.*.....................................................................................................................................................................53Swing....................................................................................................................................................................54Strings..................................................................................................................................................................57

C A P Í T U L O IV..................................................................................................................................................63Decisiones (if)......................................................................................................................................................63Ciclos....................................................................................................................................................................76

C A P I T U L O V...................................................................................................................................................86Excepciones y Flujo de Datos (Exceptions y Streams).......................................................................................86Como leer archivos de texto.................................................................................................................................95Leer de un Archivo de Texto..............................................................................................................................104Escribiendo un Archivo de Texto.......................................................................................................................106Archivos y Filtros...............................................................................................................................................107Excepciones y Flujo de Datos (Exceptions y Streams).....................................................................................110Diagnostico de los errores en Expresiones y Variables....................................................................................111Excepciones........................................................................................................................................................114Leer desde el teclado..........................................................................................................................................117Como leer archivos de texto...............................................................................................................................120Leer de un Archivo de Texto..............................................................................................................................128Escribiendo un Archivo de Texto.......................................................................................................................131Archivos y Filtros...............................................................................................................................................132

Page 3: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

C A P Í T U L O VI...............................................................................................................................................135Programación Orientada a Objetos en Java.....................................................................................................135Clases y Objetos.................................................................................................................................................136Instancias de una Clase.....................................................................................................................................137Constructores.....................................................................................................................................................138Variables en la clase..........................................................................................................................................139Clase como Tipo.................................................................................................................................................139Expresiones para instanciar..............................................................................................................................140Métodos Instanciados.........................................................................................................................................140La palabra clave this..........................................................................................................................................141Métodos en las Clases........................................................................................................................................142Implementando Estructuras de Datos................................................................................................................142Listas..................................................................................................................................................................142Arboles AVL.......................................................................................................................................................144Jerarquia de Clases............................................................................................................................................157Herencia.............................................................................................................................................................158Jerarquia de clases en Java...............................................................................................................................160Herencia y Constructores..................................................................................................................................161Dynamic Binding................................................................................................................................................162Polimorfismo......................................................................................................................................................162Sobreescritura de métodos.................................................................................................................................163Clases Abstractas y Métodos Abstractos...........................................................................................................163Interfaces............................................................................................................................................................165Paquetes.............................................................................................................................................................168Declaración import...........................................................................................................................................168Java-Paquetes Estandar.....................................................................................................................................169Programación Orientada a Objetos comparada con la Programación de Procesos y programación orientada a eventos................................................................................................................................................................169

C A P I T U L O VII.............................................................................................................................................181Eventos (Events).................................................................................................................................................181Eventos...............................................................................................................................................................182GUI Minimo-Minimorum:.................................................................................................................................186Estuctura de una Aplicación Swing...................................................................................................................189

C A P Í T U L O VIII.............................................................................................................................................203Swing..................................................................................................................................................................203

C A P Í T U L O IX...............................................................................................................................................221Swing: Eventos de Ratón y Movimientos del Ratón...........................................................................................221

C A P I T U L O X................................................................................................................................................232GUI Avanzado (con Swing)................................................................................................................................232

C A P Í T U L O XI................................................................................................................................................245GUI Avanzado (con Swing)................................................................................................................................245

Ingeniería en Computación, Universidad de La Serena 3

Page 4: Libro Java

C A P I T U L O IPROGRAMACIÓN ORIENTADA A OBJETOS

La programación orientada a objetos proporciona una forma de ver los programas en función de los datos y los métodos que operan sobre ellos. En la programación orientada a objetos, la atención se aleja de las funciones y se acerca a las cosas (objetos) que componen el programa. Las diferencias básicas entre la programación orientada a objetos y el enfoque de procesos, eventos u aspectos, pueden agruparse en cuatro principios básicos: abstracción, encapsular, herencia y polimorfismo.

Abstracción es el proceso de ignorar temporalmente los detalles subyacentes al objeto, para centrar la atención en el problema u objeto y así extraer sus características esenciales. Por ejemplo, si se consideran los neumáticos de un auto, el neumático abstracto puede tener una marca, tamaño precio y una cantidad ideal de aire. Estas características se aplican a todos los neumáticos. Al utilizar la abstracción es posible centrar la atención sobre estas características (comunes), en lugar de hacerlo sobre los detalles de un tipo específico de neumático.

Encapsular es el proceso de agrupar la información abstraída del objeto con las operaciones (métodos) que un programa puede realizar sobre los datos. Por ejemplo, una clase es el encapsulado de los datos y métodos de un objeto.

Herencia es un marco en el cual se pueden crear nuevas clases al introducir nuevas características o cambios a clases ya existentes. La herencia libera al programador de la tarea de reescribir funciones cuando se deben hacer pequeños cambios.

Finalmente, el Polimorfismo es la habilidad que tiene un objeto de tomar diferentes formas. El prefijo poli significa “muchas”; morfismo “formas”. Por ejemplo, en un programa, un objeto polimorfo que represente un teléfono puede cambiar de forma para representar un teléfono de tonos, un teléfono de pulsos o incluso un teléfono celular.

Como puede notar algunos conceptos de la POO son análogos a los métodos de programación convencional, por ejemplo. Un método es como un procedimiento porque ambos contienen instrucciones de procesamiento. Las variables de clase y modelo se correlacionan a los datos de la programación tradicional. Los métodos y datos son diferentes porque los procedimientos no están encapsulados normalmente con los datos que manipulan. Una clase es como un tipo abstracto de datos, aunque para la POO, el proceso de escribir no se revela fuera de la clase. La herencia no tiene analogía inmediata en la programación convencional. El paso de mensajes reemplaza a las llamadas de función como método principal de control en los sistemas orientados a objeto. Con las llamadas de funciones, los valores se presentan y el control regresa a la función que efectúa la llamada. Por el contrario, los objetos entran en acción gracias a los mensajes, y el control está distribuido.

Considere como ejemplo, una entidad bancaria. En ella identificamos entidades que son cuentas: cuenta_del_cliente1, cuenta_del_cliente2, etc. Al mismo tiempo, una cuenta puede verse como un objeto que tiene atributos. Por ejemplo, nombre, número_de_cuenta y saldo, y

Page 5: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

un conjunto de métodos como IngresarDinero, RetirarDinero, AbonarIntereses, SaldoActual, Transferencia etc. En el caso de una transferencia, se podría escribir por ejemplo,

cuenta_del_clientel.Transferencia(cuenta_del_cliente2);

cuyo significado sería que, Transferencia es el mensaje que el objeto cuenta_del_cliente2 envía al objeto cuenta_del_cliente1, solicitando le sea hecha una transferencia, siendo la respuesta a tal mensaje la ejecución del método Transferencia. Trabajando a este nivel de abstracción, manipular una entidad bancaria resultará algo muy sencillo.

Mecanismos Básicos de la Poo

ObjetosUn programa OO se compone solamente de objetos, entendiendo por objeto una encapsulación genérica de propiedades o datos y de los métodos para manipularlos. Por ejemplo una ventana de Windows es un objeto, en donde, el color de fondo, la altura, la anchura son propiedades, mientras que las rutinas (transparentes al usuario), que permiten maximizar o minimizar la ventana son métodos.

MensajesCuando se ejecuta un programa OO los objetos están recibiendo, interpretando y respondiendo a mensajes de otros objetos. De manera que en la POO un mensaje está asociado con un método. Si continuamos con el ejemplo de la ventana de Windows, digamos que cuando un usuario desea maximizar una ventana, lo que hace es pulsar el botón de la misma que realiza esa acción, esto es que Windows envíe un mensaje a la ventana para indicarle que tiene que maximizarse, y como respuesta a este mensaje se ejecutará el método programado para ese fin.

MétodosUn método se implementa en una clase de objetos y determina cómo tiene que actuar el objeto para cuando recibe el mensaje vinculado con ese método. De la misma manera un método puede también enviar mensajes a otros objetos solicitando una acción o información.

Cuando se diseña una clase de objetos, la estructura más interna del objeto se oculta a los usuarios que lo vayan a utilizar, manteniendo como única conexión con el exterior, los mensajes. Esto es, los datos que están dentro de un objeto solamente podrán ser manipulados por los métodos asociados al propio objeto. Según lo expuesto, podemos decir que la ejecución de un programa orientado a objetos realiza fundamentalmente tres cosas:

1. Crea los objetos necesarios.2. Los mensajes enviados a unos y a otros objetos dan lugar a que se procese internamente la

información.3. Finalmente, cuando los objetos no son necesarios, son borrados, liberándose la memoria

ocupada por los mismos.

Ingeniería en Computación, Universidad de La Serena 5

Page 6: Libro Java

Empleado

apellido: Stringnombre: Stringrut: intesFemenino: boolean

Empleado

Empleado

- apellido: String- nombre: String- rut: int- esFemenino: boolean

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

ClasesUna clase es un tipo de objetos definido por el usuario. Una clase equivale a la generalización de un tipo específico de objetos. Por ejemplo, Empleado.

No obstante esta clase puede expandirse para incluir atributos, en este caso apellido, nombre, rut y sexo. Para tal efecto, todos los atributos son definidos en la clase a través de variables, es así como la clase adquiere la siguiente forma:

Código Java UML

class Empleado { String apellido; String nombre; int rut; boolean esFemenino;}

Además, si Ud. desea puede definir que los atributos tengan algunas propiedades, tales como privado (-), público(+) o protegido(#). En tal caso queda,

Código Java UML

public class Empleado {private String apellido;private String nombre; private int rut;private boolean esFemenino;}

Por otro lado cabe preguntarse ¿que deseo hacer con la clase Empleado?. Por ejemplo se desea registrar horas de trabajo, horas extraordinarias, sueldo, viáticos, u otros. En tal caso, se deben implementar ciertos métodos que realicen ésta tarea.

Según lo expuesto hasta ahora, un objeto contiene, por una parte, atributos que definen su estado, y por otra, operaciones que definen su comportamiento. También sabemos que un objeto es la representación concreta y específica de una clase. ¿Cómo se escribe una clase de objetos? Como ejemplo, podemos crear una clase PC1.

Ejemplo 1.

public class PC1 {String marca;String procesador;String pantalla;boolean PC1_Encendido;boolean presentacion;}

Ingeniería en Computación, Universidad de La Serena 6

Page 7: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

en esta oportunidad se han definido 5 atributos. Veamos ahora, desde un punto de vista práctico, que acciones serían convenientes considerar, por ejemplo, ponerse en marcha, apagarse, cargar una aplicación, desactivar algún proceso o activar otro, etc. Ahora para implementar este comportamiento hay que crear métodos. Los métodos son rutinas de código definidas dentro de la clase, que se ejecutan en respuesta a alguna acción tomada desde dentro de un objeto de esa clase o desde otro objeto de la misma o de otra clase, recuerde que los objetos se comunican mediante mensajes.

Ejemplo 2.

public class PC1{ String marca; String procesador; String pantalla; boolean PC1_Encendido; boolean presentación;

//método de la clase void EncenderPC1() { if (PC1_Encendido == true) // si está encendido... System.out.println("El PC ya está encendido."); else // si no está encendido, encenderlo. { PC1_Encendido = true; System.out.println("El PC se ha encendido."); } }//método de la clase void Estado() { System.out.println("\nEstado del PC:" + "\nMarca " + marca + "\nProcesador " + procesador + "\nPantalla " + pantalla + "\n"); if (PC1_Encendido == true) // si el ordenador está encendido... System.out.println("El PC está encendido."); else // si no está encendido... System.out.println("El PC está apagado."); }

//método de la clase, llamada clase principal public static void main (String[] args) { PC1 miPC1 = new PC1(); miPC1.marca = "Dell"; miPC1.procesador = "Intel Pentium"; miPC1.pantalla = "AOC"; miPC1.EncenderPC1(); miPC1.Estado(); }}

Ingeniería en Computación, Universidad de La Serena 7

Page 8: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

Como se puede observar un método consta de su nombre precedido por el tipo del valor que devuelve cuando finalice su ejecución (la palabra reservada void indica que el método no devuelve ningún valor y seguido por una lista de parámetros separados por comas y encerrados entre paréntesis (en el ejemplo, no hay parámetros). Los paréntesis indican a Java que el identificador EncenderPC1() se refiere a un método y no a un atributo. A continuación se escribe el cuerpo del método encerrado entre {y}. Usted ya conoce algunos métodos, llamados en otros contextos funciones; seguro que conoce la función logaritmo que devuelve un valor real correspondiente al logaritmo del valor pasado como argumento. Otro método es Estado()que visualiza los atributos específicos de un objeto. Finalmente para poder crear objetos de esta clase y trabajar con ellos, tendrá que añadir a esta clase el método main(), tal como se hizo aquí, o bien escribir un programa principal, tal como se muestra a continuación, en donde MiPC.java esta en un directorio y el archivo PC2.class en el mismo, de otra manera no se entendera el llamado que se hace. A continuación se visualiza un típico mensaje de error de esta naturaleza.

En resumen, las bibliotecas de clases y los marcos estructurales proporcionan una excelente plataforma para el desarrollo de las aplicaciones orientadas a objetos y la reutilización del código.

Ingeniería en Computación, Universidad de La Serena

C:\Documents and Settings\usuario\Escritorio\POO\curso_poo_2006\MiPC.java:5: cannot resolve symbolsymbol : class PC2location: class MiPCPC2 miPC2 = new PC2();^C:\Documents and Settings\usuario\Escritorio\POO\curso_poo_2006\MiPC.java:5: cannot resolve symbolsymbol : class PC2location: class MiPC

PC2 miPC2 = new PC2();

^

2 errors

8

Page 9: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

Ejemplo 3.

public class MiPC { public static void main (String[] args) { PC2 miPC2 = new PC2(); miPC2.marca = "Dell"; miPC2.procesador = "Intel Pentium"; miPC2.pantalla = "AOC"; miPC2.EncenderPC2(); miPC2.Estado(); }}//método de la claseclass PC2{ String marca; String procesador; String pantalla; boolean PC2_Encendido; boolean presentación;

//método de la clase void EncenderPC2() { if (PC2_Encendido == true) // si está encendido... System.out.println("El ordenador ya está encendido."); else // si no está encendido, encenderlo. { PC2_Encendido = true; System.out.println("El ordenador se ha encendido."); } }//método de la clase void Estado() { System.out.println("\nEstado del ordenador:" + "\nMarca " + marca + "\nProcesador " + procesador + "\nPantalla " + pantalla + "\n"); if (PC2_Encendido == true) // si el ordenador está encendido... System.out.println("El ordenador está encendido."); else // si no está encendido... System.out.println("El ordenador está apagado."); }}

Ingeniería en Computación, Universidad de La Serena 9

Page 10: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

Características de la Poo

Las características fundamentales de la POO son: encapsulación, herencia, abstracción, y polimorfismo.

EncapsulamientoLa encapsulación es el término formal que describe el conjunto de métodos y datos dentro de un objeto de forma que el acceso a los datos se permite solamente a través de los métodos del objeto. Esta característica permite entonces ver un objeto como una caja negra en la que se ha introducido de alguna manera toda la información relacionada con dicho objeto, permitiendo manipular los objetos como unidades básicas, permaneciendo oculta su estructura interna. Generalmente los atributos de una clase de objetos se declaran privados, estando así oculto para otras clases, siendo posible el acceso a los mismos únicamente a través de los métodos públicos de dicha clase. El mecanismo de ocultación de miembros se conoce en la POO como encapsulación. El nivel de protección predeterminado para un miembro de una clase es el de package (paquete), habiendo otros tales como, public, private y protected.

Ejemplo 4.

/** * Conversión de grados centígrados a fahrenheit: * F = 9/5 * C + 32 */

import java.lang.System; // importar la clase System

public class CApGrados { // Definición de constantes final static int limInferior = -30; final static int limSuperior = 100; final static int incremento = 6;

public static void main(String[] args) { // Declaración de variables CGrados grados = new CGrados(); int gradosCent = limInferior; float gradosFahr = 0;

while (gradosCent <= limSuperior) // while ... hacer: { // Asignar al objeto grados el valor en grados centígrados grados.CentígradosAsignar(gradosCent); // Obtener del objeto grados los grados fahrenheit gradosFahr = grados.FahrenheitObtener(); // Escribir la siguiente línea de la tabla System.out.println(gradosCent + " C" + "\t" + gradosFahr + " F"); // Siguiente valor gradosCent += incremento; } }}/** * Clase CGrados. Un objeto de esta clase almacena un valor * en grados centígrados. * Atributos: * gradosC

Ingeniería en Computación, Universidad de La Serena 10

Page 11: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

* Métodos: * CentígradosAsignar, FahrenheitObtener y CentígradosObtener */class CGrados{ private float gradosC; // grados centígrados public void CentígradosAsignar(float gC) { // Establecer el atributo grados centígrados gradosC = gC; } public float FahrenheitObtener() { // Retornar los grados fahrenheit equivalentes a gradosC return 9F/5F * gradosC + 32; } public float CentígradosObtener() { return gradosC; // retornar los grados centígrados }}

Tomando la clase CGrados, podemos advertir que contiene atributos private como gradosC, lo que significa que un miembro de una clase declarado private puede ser accedido únicamente por los métodos de su clase, es decir, el atributo gradosC es accedido por el método CentígradosAsignar(). En la eventualidad que un método de otra clase, por ejemplo el método main de la clase class CApGrados, incluyera una declaración, tal como grados.gradosC = 30; el compilador debería mostrar un error, indicando que el miembro gradosC no es accesible desde esta clase, por tratarse de un miembro privado de Cgrados. Si por otra parte, un miembro de una clase declarado public es accesible desde cualquier método definido dentro o fuera de la clase o paquete actual. Por ejemplo, en la clase CApGrados, se puede observar cómo el ojeto grados de la clase CGrados creado en el método main accede a su método CentígradosAsignar(), con el fin de modificar el valor de su miembro privado gradosC.

En este sentido se dice que la clase CGrados encapsula una estructura de datos formada por un float llamado gradosC, y que para acceder a esta estructura proporciona la interfaz pública formada por los métodos CentígradosAsignar, FahrenheitObtener y CentígradosObtener.

Herencia Simple en JavaLa herencia permite el acceso automático a la información contenida en otras clases. De esta forma se garantiza la reutilización de código. A través de la herencia existe una estricta jerarquerización, es decir cada clase tiene su superclase que es la clase superior en la jerarquía y por otra parte ella podrá tener subclases, que son las clases inferiores a ella. Las clases inferiores se suponen que heredan de las clases que están en la parte superior, esto significa también que las subclases disponen de todos los métodos y propiedades de su superclase, proporcionando con ello un mecanismo rápido y cómodo de extender la funcionalidad de una clase. En Java cada clase

Ingeniería en Computación, Universidad de La Serena 11

Page 12: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

sólo puede tener una superclase, llamada herencia simple, mientras que C++ y otros lenguajes orientados a objeto las clases pueden tener más de una superclase, conocida como herencia múltiple. En esta última situación una clase comparte los métodos y propiedades de varias clases. La forma de cómo Java supera esta situación es a través de la implementación de interfaces. Una interface es una colección de nombres de métodos, sin incluir su implementación y que pueden ser añadidas a cualquier clase para proporcionarle comportamientos adicionales no incluidos en los métodos propios o heredados.

Por ejemplo pensemos en la clase Empleado definida como:

Ejemplo 5.

class Empleado {    String nombre;    int numEmpleado, sueldo;

    static private int contador = 0; //definir un constructor    Empleado(String nombre, int sueldo) {

/*Algunas veces un método necesita hacer referencia al objeto que lo invocó, para permitir esto Java define la palabra clave this, que puede ser usado dentro de cualquier método para referirse al objeto actual. Por ejemplo, */        this.nombre = nombre;        this.sueldo = sueldo;        numEmpleado = ++contador;    }

    public void aumentarSueldo(int porcentaje) {        sueldo += (int)(sueldo * aumento / 100);    }

    public String toString() {     return "Num. empleado " + numEmpleado + " Nombre: " + nombre +          " Sueldo: " + sueldo;    }}

En el ejemplo, Empleado se caracteriza por un nombre (String) y por un número de empleado y sueldo (enteros). La clase define un constructor que asigna los valores de nombre y sueldo y calcula el número de empleado a partir de un contador (variable estática que siempre irá aumentando), y dos métodos, uno para calcular el nuevo sueldo cuando se produce un aumento de sueldo (método aumentarSueldo) y un segundo que devuelve una representación de los datos del empleado en un String.(método toString).

Con esta representación podemos pensar en otra clase que reuna todas las características de Empleado y añada alguna propia. Por ejemplo, la clase Ejecutivo. A los objetos de esta clase se les podría aplicar todos los datos y métodos de la clase Empleado y añadir algunos, como por ejemplo el hecho de que un Ejecutivo tiene un presupuesto. Así diriamos que la clase Ejecutivo extiende o hereda la clase Empleado. Esto en Java se hace con la clausula extends que se incorpora en la definición de la clase, de la siguiente forma:

Ingeniería en Computación, Universidad de La Serena 12

Page 13: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

Ejemplo 6.

class Ejecutivo extends Empleado {    int presupuesto;    void asignarPresupuesto(int p) {        presupuesto = p;    }}

Con esta definición un Ejecutivo es un Empleado que además tiene algún rasgo distintivo propio. El cuerpo de la clase Ejecutivo incorpora sólo los miembros que son específicos de esta clase, pero implícitamente tiene todo lo que tiene la clase Empleado. A Empleado se le llama clase base o superclase y a Ejecutivo clase derivada o subclase.

Los objetos de las clases derivadas se crean igual que los de la clase base y pueden acceder tanto sus datos y métodos como a los de la clase base. Por ejemplo:

Ejecutivo jefe = new Ejecutivo( "Armando Mucho", 1000);jefe.asignarPresupuesto(1500);jefe.aumentarSueldo(5);

Nota: La discusión acerca de los constructores la veremos un poco más adelante.

Observar que un Ejecutivo ES un Empleado, pero lo contrario no es cierto. Si escribimos:

Empleado curri = new Empleado ("Esteban", 100);curri.asignarPresupuesto(5000);  // error

se producirá un error de compilación pues en la clase Empleado no existe ningún método llamado asignarPresupuesto.

En la práctica, se muestra otro ejemplo de herencia simple.

Ejemplo 7.

// Crea una superclass.class A { int i, j;

void showij() { System.out.println("i y j: " + i + " " + j); }}

// Crea una subclass .class B extends A { int k;

void showk() { System.out.println("k: " + k); } void sum() { System.out.println("i+j+k: " + (i+j+k)); }

Ingeniería en Computación, Universidad de La Serena 13

Page 14: Libro Java

Fig_Geo

Circulo PoligonoTriangulo

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

}

class SimpleHerencia { public static void main(String args[]) { A superOb = new A(); B subOb = new B();

// la superclass puede ser usada por ella misma. superOb.i = 10; superOb.j = 20; System.out.println("Contenido de superOb: "); superOb.showij(); System.out.println();

/* La subclass tiene acceso a todos los miembros public de su superclass. */ subOb.i = 7; subOb.j = 8; subOb.k = 9; System.out.println("Contenido de subOb: "); subOb.showij(); subOb.showk(); System.out.println();

System.out.println("Sum de i, j y k en subOb:"); subOb.sum(); }}

Como se puede ver, la subclase B incluye todos los miembros de su superclase A, por lo que subOb puede acceder a las variables i y j, y llamar al método showij(). Dentro se sum(), también se pueden referenciar directamente las variables i y j, como si fuesen parte de B.

Abstracción

Por medio de la abstracción conseguimos no detenernos en los detalles, sino generalizar y centrarse en los aspectos que permitan tener una visión global del problema. Por ejemplo el estudio de un PC podría realizarlo a nivel de circuitos electrónicos, o a través de transferencias entre registros, en tal caso el estudio debería centrarse en el flujo de la información entre las unidades (memoria, unidad aritmética, unidad de control, etc.), sin importar el comportamiento de los circuitos electrónicos que componen estas unidades. Es decir, cuando se desarrolla una jerarquía de clases en que algún comportamiento está presente en todas ellas pero se materializa de forma distinta para cada una. Por ejemplo, pensemos en una estructura de clases para manipular figuras geométricas.

clase Abstracta

Ingeniería en Computación, Universidad de La Serena 14

Page 15: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

Podríamos pensar en tener una clase genérica, que podría llamarse Fig_Geo y una serie de clases que extienden a la anterior que podrían ser Circulo, Poligono, etc.

Podría haber un método dibujar dado que sobre todas las figuras puede llevarse a cabo esta acción, pero las operaciones concretas para llevarla a cabo dependen del tipo de figura en concreto (de su clase). Por otra parte la acción dibujar no tiene sentido para la clase genérica Fig_Geo, porque esta clase representa una abstracción del conjunto de figuras posibles.

Para resolver esta problemática Java proporciona las clases y métodos abstractos. Un método abstracto es un método declarado en una clase para el cual esa clase no proporciona la implementación (el código). Una clase abstracta es una clase que tiene al menos un método abstracto. Una clase que extiende a una clase abstracta debe implementar los métodos abstractos (escribir el código) o bien volverlos a declarar como abstractos, con lo que ella misma se convierte también en clase abstracta.

Siguiendo con el ejemplo del apartado anterior, se puede escribir:

Ejemplo 8.

abstract class Fig_Geo {    . . .    abstract void dibujar();    . . .}

class Circulo extends Fig_Geo {    . . .    void dibujar() {        // codigo para dibujar Circulo        . . .    }} 

La clase abstracta se declara simplemente con el modificador abstract en su declaración. Los métodos abstractos se declaran también con el mismo modificador, declarando el método pero sin implementarlo (sin el bloque de código encerrado entre {}). La clase derivada se declara e implementa de forma normal, como cualquier otra. Sin embargo si no declara e implementa los métodos abstractos de la clase base (en el ejemplo el método dibujar) el compilador genera un error indicando que no se han implementado todos los métodos abstractos y que, o bien, se implementan, o bien se declara la clase abstracta. 

En la práctica, se muestra otro ejemplo de Abstracción.

Ejemplo 9.

abstract class A { abstract void callme();

// método en la abstract classes void callmetoo() { System.out.println("Este es un método concreto.");

Ingeniería en Computación, Universidad de La Serena 15

Page 16: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

}}

class B extends A { void callme() { System.out.println("B's es una implementacion de callme."); }}

class AbstractDemo { public static void main(String args[]) { B b = new B();

b.callme(); b.callmetoo(); }}

En resumen, las clases abstractas dividen los problemas complejos en módulos sencillos y ocultan los detalles de la realización. La claridad conceptual está presente en el diseño, en el programa y en la aplicación final.

Polimorfismo

Esta característica permite implementar múltiples formas de un mismo método, dependiendo cada una de ellas de la clase sobre la que se realice la implementación. Esto hace que se pueda acceder a una variedad de métodos distintos (todos con el mismo nombre) utilizando el mismo medio de acceso. La sobreescritura de métodos constituye la base de uno de los conceptos más poderosos de Java llamada la selección de método dinámica o dynamic binding, que es el mecanismo mediante el cual una llamada a una función sobrescrita se resuelve en tiempo de ejecución, en lugar de compilación. Esta es una forma muy usual de implementar el polimorfismo. Por ejemplo

Ejemplo 10.

class A { void callme() { System.out.println("Dentro de A llamando a callme()"); }}

class B extends A { // sobre escritura callme() void callme() { System.out.println("Dentro de B llamando a callme()"); }}

Ingeniería en Computación, Universidad de La Serena 16

Page 17: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

class C extends A { // sobreescritura callme() void callme() { System.out.println("Dentro de C llamando a callme()"); }}

class Despacho { public static void main(String args[]) { A a = new A(); // objeto de tipo A B b = new B(); // objeto de tipo B C c = new C(); // objeto de tipo C A r; // obteniendo una referencia de tipo A

r = a; // r referencia a un objeto A r.callme(); // llamando a la version A de callme()

r = b; // r referencia a un objeto B r.callme(); // llamando a la version B de callme()

r = c; // r referencia a un objeto C r.callme(); // llamando a la version C de callme() }}

Veamos ahora en general, a través de un ejemplo una visión de lo tratado y lo que se aproxima a través del curso.

Ejemplo 11.

/************************************************************************ * Una clase para representar un empleado. Un ejemplo. * ***********************************************************************/public class Empleado { protected String nombre; // nombre del empleado protected String jobT; // trabajo del empleado, el título protected double jornal; // horas asociadas al jornal del empleado // el monto de dinero que la compañia cancela al empleado protected double pagoO;

/********************************************************************** * Constructor: Crea un empleado standar dando nombre, titulo del job, y jornal. * * Parametros: * nombre: el nombre del empleado * titulo: trabajo del empleado, el título * jornal: jornal del empleado**********************************************************************/ public Empleado(String nombre, String titulo, double jornal) { this.nombre = nombre; this.jobT = titulo; if (jornal < 0) {

Ingeniería en Computación, Universidad de La Serena 17

Page 18: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

System.out.println("Error: jornal negativo!"); jornal = 0; } // end if this.jornal = jornal; // parte sin pago acumulado this.pagoO = 0; } // end constructor

/********************************************************************** * Returns el nombre del empleado. *********************************************************************/ public String getNombre() { return nombre; } // end getNombre

/********************************************************************** * Returns el trabajo del empleado. *********************************************************************/ public String getTitulo() { return jobT; } // end getTitulo

/********************************************************************** * Pago al empleado por nº de horas trabajadas. Incrementando * el monto del pago. * * Parameter: nº de horas trabajadas *********************************************************************/ public void pago(double horas) { pagoO += horas * jornal; } // end pago

/********************************************************************** * Returns el monto del pago para el empleado. *********************************************************************/ public double monto_a_Pagar() { return pagoO; } // end monto_a_Pagar

/********************************************************************** * Cero el monto adeudado. Llamada para establecer que se ha cancelado * a empleado de alguna manera. *********************************************************************/ public void cero() { pagoO = 0; } // end cero

/********************************************************************** * Compara este empleado con otro. * Se define para cuando ellos tienen el mismo nombre, jobTitulo y jornal. * Parametros: otro objeto para comparar con este * Return valor: true si este objeto es considerado igual al * otro objeto. *********************************************************************/ public boolean igual(Object otro) { if (otro instanceof Empleado) { Empleado otroEmp = (Empleado) otro; return (nombre.equals(otroEmp.nombre)) && (jobT.equals(otroEmp.jobT)) && (jornal == otroEmp.jornal);

} else { // un objeto no- Empleado

Ingeniería en Computación, Universidad de La Serena 18

Page 19: Libro Java

Empleado

- nombre: String- jobT: String- jornal : double- pagoO: double

+ getNombre():String+ getTitulo():String+ pago(horas: double)+ monto_a_Pagar(): double+ cero(): void+ igual(): boolean+ aString(): String

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

return false; } // end if } // end igual

/********************************************************************** * Crea un String para la representacion de empleado, incluyendo, * nombre,job titulo, jornal y pago. * * Return valor: el string *********************************************************************/ public String aString() { return nombre + ": " + jobT + ", jornal=" + jornal + ", pago = " + pagoO;

} // end aString

} // end class Empleado

Como Ud. puede notar en el código de la clase Empleado existe un mecanismo que le llamamos Constructor. A saber, un constructor es un procedimiento especial de una clase que es llamado automáticamente siempre que se desee crear un objeto de esa clase, siendo su función iniciar el objeto. Por otra parte un destructor es un procedimiento especial de una clase que es llamado automáticamente siempre que se desee destruir un objeto de esa clase, siendo su función acabar cualquier proceso en el que este objeto haya estado involucrado. Observar que cada objeto mantiene su propia copia de los atributos, pero no de los métodos de su clase, esto es cada objeto almacena sus propios datos, pero para acceder y operar con ellos, todos comparten los mismos métodos definidos en su clase. Por lo tanto, para que un método conozca la identidad del objeto particular para el que ha sido invocado, Java proporciona una referencia al objeto denominada this, tal como ud. lo aprecia en el constructor anterior. Como Uds. pueden notar existen otro tipo de Empleados, por ejemplo un Vendedor Viajero (Salesperson) a quien se le paga por horas pero además obtiene una comisión, es decir un porcentaje de las ventas realizadas. A continuación veamos como tratar esta propuesta o cambio en la organización, y desde luego cambios en los sistemas de administración de la misma.Propuesta 1: cambiar la clase Empleado por otra en que a todos los Empleados se les incluya el concepto de Comisión, en donde la Comisión tal vez para muchos es 0. Ante lo cual deriva en una excesiva computación y capacidad de almacenamiento para todos los Empleados, pues no todos estarán en esta situación.

Ingeniería en Computación, Universidad de La Serena 19

Page 20: Libro Java

Empleado

- nombre: String- jobTitulo: String- peso : double- pagoDeuda: double

+ getNombre():String+ getTitulo():String+ pago(horas: double)+ montoPago(): double+Ok()

Salesperson

- tasa: double

+ pagoSale(montoSale : double)

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

Propuesta 2: Crear una nueva clase, llamemosla Salesperson, la cual copia todas las variables y métodos desde la clase Empleado, pero agregando la comisión, o datos faltantes. Los problemas que trae esta propuesta es la duplicidad de código, es decir más tipeo, lo que trae como consecuencia una alta probabilidad de errores, y 2 clases a mantener. Ante las propuestas anteriores surge una mucho más plausible, y se refiere a extender la clase Empleado, y esto se visualiza de la siguiente manera:

public class Salesperson extends Empleado{ //extra variables //extra métodos}//end class Salesperson

en donde se dice que la clase Salesperson hereda todos los métodos y variables desde la clase Empleado, además de otros extras que pueda incluir. La vista de heredar en UML es como sigue,

Veamos la implementación de la clase Salesperson

Ejemplo 12.

/************************************************************************ * Una clase para representar un salesperson. Pago de jornal mas comisiones. * ***********************************************************************/public class Salesperson extends Empleado {

// la comision de salesperson esta representado como una fraccion, no // un porcentaje, esta debería estar entre 0 y 1. protected double razon;

/********************************************************************** * Constructor: Crea un salesperson dando nombre, job titulo, jornal, * y una razon de comision. * * Parametros: * nombre: nombre del empleado * titulo: el job titulo para el empleado * jornal: jornal del empleado

Ingeniería en Computación, Universidad de La Serena 20

Page 21: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

* razon: razon de la comision entre 0 y 1. *********************************************************************/ public Salesperson(String nombre, String titulo, double jornal, double razon) { super(nombre, titulo, jornal); if (razon < 0 || razon > 1) { System.out.println("error: comision debe estar entre 0 y 1"); this.razon = 0; } else { this.razon = razon; } // end if } // end constructor

/********************************************************************** * Constructor: Crea un salesperson quien recibe comision solamente * (no pago por horas), dar el nombre, job titulo y razon de la comision. * * Parametros: * nombre: nombre del empleado * titulo: el job titulo para el empleado * razon: razon de comision del empleado, entre 0 y 1. *********************************************************************/ public Salesperson(String nombre, String titulo, double razon) { this(nombre, titulo, 0, razon); } // end constructor

/********************************************************************** * Pago al salesperson por viaje, de acuerdo a la razon de comision. * * Parametro: monto para el viaje. *********************************************************************/ public void pagoViaje(double montoViaje) { pagoO += razon * montoViaje; } // end pagoViaje

/********************************************************************** * Crea una representacion String para Salesperson, incluyendo nombre, * job titulo, jornal, pagoO, y razon de comision. * * Return valor: representacion string *********************************************************************/ public String aString() { return "(Salesperson) " + super.aString() + ", razon de comision: " + razon;

} // end aString

} // end class Salesperson

Algo que se debe tener cuenta respecto al vocabulario es que la clase Empleado es la superclase(o clase padre), Salesperson es una subclase (o clase derivada). Se dice también que la clase Salesperson extiende a la clase Empleado. Salesperson hereda variables y métodos de la clase Empleado. Salesperson es una clase derivada, que deriva de la clase Empleado.

Una clase hija o derivada hereda todas las variables y métodos del padre, pero NO constructores, esto significa que cada clase necesita de un constructor o constructores propios. Por otra parte, un mejor camino para evitar duplicidad en la codificación de la inicialización es considerar el método super(), considerada como superclase. La declaración

Ingeniería en Computación, Universidad de La Serena 21

Page 22: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

super(nombre, titulo, jornal);

dice que llama al constructor de la superclase, es decir Empleado. Invocar a super(), se debe hacerse en el constructor en la primera llamada, para que pueda asumirlo.

Otra clase derivada podría ser, si es que sigue el juego de la organización, los empleados ejecutivos, los que pueden recibir bonos de productividad, los que no están basados en horas necesariamente. Por ejemplo

Ejemplo 13.

/************************************************************************ * clase para empleado ejecutivo. Obtiene jornal plus bonos. ***********************************************************************/public class Ejecutivo extends Empleado { /********************************************************************** * Constructor: Crea un ejecutivo dando nombre, job titulo, y jornal. * Parametros: * nombre: nombre del empleado * titulo: el job titulo del empleado * jornal: jornal del empleado *********************************************************************/ public Ejecutivo(String nombre, String titulo, double jornal) {/* Note que TODOS estos constructores hacen esto para llamar a la clase padreconstructor con los mismos parametros. Este constructor es necesario ,pues clases hijas no heredan constructores, por eso la declaracion.*/

super(nombre, titulo, jornal); } // end constructor

/********************************************************************** * Pago de bonos al ejecutivo. * * Parametro: monto del bono *********************************************************************/ public void pagoBono(double bono) { pagoO += bono; } // end pagoBono

/********************************************************************** * Crea una representación String de Ejecutivo, incluyendo nombre, * job titulo, jornal y pago. * * Return valor: representacion string *********************************************************************/ public String aString() { return "(Ejecutivo) " + super.aString(); } // end aString

} // end class Ejecutivo

Veamos a continuación una clase principal que servirá para testear la clase Empleado sus métodos y las subclases.Ejemplo 14.

/************************************************************************ * Un programa para testear la clase Empleado y sus subclases.

Ingeniería en Computación, Universidad de La Serena 22

Page 23: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

* ***********************************************************************/

public class EmpleadoTest {

// Metodo principal main: Crea varios empleados de diferentes tipos y testeamos // los diferentes métodos.

public static void main(String noUsado[]) { // un empleado "normal" , pago $2. 250/hora, sin sobretiempo Empleado ambler = new Empleado("Ambler", "agente", 2.250); ambler.pago(8); ambler.pago(10); // total horas son 18, pago es de 2.250 * 18 = $40.500. System.out.println("monto a pagar a ambler: $" + ambler.monto_a_Pagar());

// chequear el metodo cero ambler.cero(); ambler.pago(8); // pago es de 8 * 2.250 = 18.000. System.out.println("monto a pagar a ambler: $" + ambler.monto_a_Pagar());

// un ejecutivo recibe $3.000/hora, sin sobretiempo pero puede recibir bonos Ejecutivo perez = new Ejecutivo("perez", "director", 3.000); perez.pago(10); perez.pago(10); perez.pagoBono(10); // pago debería ser 2.000 * 3.000 + 10.000 = $70.000 System.out.println("montoa a pagar a perez: $" + perez.monto_a_Pagar());

// un vendedor viajero, recibe $1.000/hora plus 20% comision. Sin bonos o sobretiempo Salesperson castillo = new Salesperson("castillo", "salesperson", 1.000, .2); castillo.pago(10); castillo.pagoViaje(40); // pago debería ser 1.000 * 1.000 + .2 * 40.000 = $18.000. System.out.println("montoa pagar a castillo: $" + castillo.monto_a_Pagar());

// Demo para el metodo igual System.out.println(); Empleado emp1 = new Empleado("Mario", "ingeniero", 3.000); Empleado emp2 = new Empleado("Maria", "programador", 3.000); System.out.println(emp1.igual(emp2)); // false Salesperson emp3 = new Salesperson("Mario", "ingeniero", 3.000, .1); System.out.println(emp1.igual(emp3)); // true } // end main} // end class EmpleadoTest

De la misma forma como se ha realizado aquí podría construirse una nueva clase que resulte ser

Ingeniería en Computación, Universidad de La Serena 23

Page 24: Libro Java

Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos

una extensión de Empleado. Por ejemplo, considerar la situación de que algunos Empleados reciben pago extra por sobretiempo, en tal caso considere el cálculo del sueldo con sobretiempo. Por ejemplo “incremento de horas > 8 se paga 50% sino se paga como antes,” etc.

Ingeniería en Computación, Universidad de La Serena 24

Page 25: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

C A P I T U L O IIFUNDAMENTOS

El libro Java How To Program (Deitel & Deitel 3Ed.) comienza con un capítulo que describe las ideas básicas de computación, programas, y lenguajes de programación, este es un buen libro guía. Por otra parte, el libro de Cay S. Horstmann, Core Java 2, Volumen I, es un libro para personas que ya se manejan en Java. En la práctica siempre nos encontraremos con libros que de una u otra manera tienen enfoques distintos. Este material tampoco es la excepción y en nuestro caso está orientado a los alumnos que en cierto modo han programado en algún lenguaje de programación y poseen un conocimiento de las herramientas básicas de la programación, no obstante lo anterior, me he esmerado en mostrar en cada capítulo las herramientas que deberían conocer. No pretendo ser exhaustivo en el tema, sino tan sólo fijar ciertos estándares de conocimientos no importando el orden usual, es decir en este sentido no comienzo definiendo los tipos de datos, luego operadores, como usualmente se hace, sino que con el tipo de datos enteros voy utilizando las asignaciones, operadores, definición de funciones en diversas aplicaciones, ya que Ud. se supone que aprendió C, y además curso Estructuras de Datos.

El lenguaje Java que estaremos usando es uno de los más recientes lenguajes de programación de alto nivel, la primera versión apareció en 1995, y Java2 versión 1.4 que estaremos usando sólo se libero el año 2001. Java nació bajo el alero de una gran empresa de hardware y de desarrollo de tecnologías, como es la empresa SUN Microsystems, siendo uno de los referentes más importantes en el tema. Hoy en día ya se cuenta con la versión 1.5, apropiada para la programación genérica. El programa en Java es traducido por el compilador que es un programa en un lenguaje llamado bytecode que es similar al código de máquina pero es independiente de cualquier sistema en particular. El bytecode producido por compilador e interpretado por la máquina virtual de Java (JVM) se llama código del objeto. Fig. 1 muestra la forma en que se realizan los procesos.

Figura 1. Los 3 procesos: escribir un programa, compilarlo, y ejecutarlo.

Ingeniería en Computación, Universidad de La Seren 25

Page 26: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

Existe un número de herramientas disponibles para compilar y ejecutar programas Java. Para este curso utilizaremos la versión liberada y disponible en el sitio Web, llamada Software Development Kit (SDK), que puede ser bajada en forma gratuita de la dirección, http://java.sun.com/j2se/

Un primer programa en Java

Aquí mostramos algunos programas, su compilación y ejecución.

public class Hola{

declaraciones.

}

Todo programa en Java contiene declaraciones. Cada declaración describe algunas operaciones que el computador lleva a cabo. Por ejemplo, con la línea

System.out.println(Hola La Serena!);

se pretende desplegar el mensaje: Hola La Serena! en la pantalla de la consola. Java tiene varios caminos para escribir mensajes en la pantalla o desplegarlos en páginas Web. En este caso, usamos una parte de un programa(o método) llamado System.out.println. El resultado será que el mensaje sea desplegado en la pantalla DOS Window. Aquí se muestra el programa con dos declaraciones. Las dos declaraciones son escritas en bold face. (Es solo para resaltar, no use bold face en el programa actual, Java no acepta formatos ni fuentes extrañas.)

public class Hola1{ /* Escribe un mensaje sobre la pantalla. */ public static void main(String[] args) { System.out.println(Hola La Serena!); System.out.println(Nos vemos.); }}

La salida será: Hola La Serena! en una línea, y en la próxima se verá Nos vemos.

Notar la forma clásica del programa modelo, en donde las declaraciones están entre{ }.

Ingeniería en Computación, Universidad de La Seren 26

/* Escribe un mensaje sobre la pantalla. */ public static void main(String[] args) { System.out.println(Hola La Serena!); }

Page 27: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

public class Hola{ /* Escribir un mensaje simple. */ public static void main(String[] args) {

Declaraciones

}}

La Fig. 2, muestra el efecto que se genera sobre el archivo fuente Hola_Alumnos tras de realizar la compilación (con el comando javac). Ud. podrá notar la generación de dos nuevos archivos con extensión .class (conteniendo bytecode).

Fig. 2: Generación de archivos .class en bytecode

Ingeniería en Computación, Universidad de La Seren 27

Page 28: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

Elementos Básicos en todo programa Java: Objetos y Métodos.

Por ejemplo, si escribe un programa para alguna organización que posee un gran registro de personal deberá considerar un registro de personas y categorías, siendo probable entonces que defina “Empleados”, “Secretarias” u otros, estos elementos en la Programación Orientada a Objetos se llaman objetos. Al mismo tiempo se necesitan, para que el programa pueda decidir, que operaciones se pueden llevar a cabo sobre los objetos antes definidos. Por ejemplo, actualizar la lista de Empleados, o desplegar algún reporter de alguna información registrada sobre el Personal. Las operaciones que Ud. puede ejecutar sobre los objetos se llaman métodos. Cuando Ud. defina un nuevo tipo de objetos deberá definir también sus métodos. Incluso en las declaraciones de Java ya está implícito este concepto. Por ejemplo, la declaración System.out.println denota el método llamado println que pertenece al objeto llamado System.out. System.out es un objeto cuya labor es recibir la información para luego desplegarla sobre la pantalla. El método println es la operación usada para emisión de mensajes. Así la declaración

System.out.println(Hola amigos!);

usa el método println para enviar el mensaje Hola amigos! al objeto System.out (el que lo despliega en pantalla). Todo objeto pertenece a una clase la cual especifica los métodos y objetos que allí habitan. La potencialidad, en la práctica del lenguaje Java viene dada por su biblioteca de clases. Entre las cuales destacan 2 paquetes (packages) de propósito general como son java.io y java.lang.

Por ejemplo, la biblioteca de Java proporciona 3 flujos estándar, manejados por la clase System del paquete java.lang, que son automáticamente abiertos cuando se inicia un programa y cerrado para cuando finaliza.

System.in, referencia a la entrada estándar del sistema que normalmente coincide con el teclado. Se utiliza para leer datos introducidos por el usuario.

System.out, referencia a la salida estándar del sistema que normalmente es el monitor. Se utiliza para mostrar datos al usuario.

System.err, referencia a la salida estándar de error del sistema, que normalmente es el monitor. Se utiliza para mostrar mensajes de error al usuario.

Java en general nos ofrece la libertad de crear nuestras propias clases, métodos, objetos y paquetes, pero por lo mismo debemos conocer al menos la biblioteca de clases de Java, pues no en vano la librería de Java esta compuesta enteramente de clases.

Existen algunas clases que consisten de un número de métodos stand-alone, es decir que no pertenecen a algún objeto en particular, a estos le llamaremos métodos static. No todos los datos utilizados en los programas Java son objetos, es así por ejemplo los tipos de datos simples, tales como integers y números floating-point son considerados en forma diferente. Ellos son llamados tipos datos primitivos, porque están integrados en el sistema. Sin

Ingeniería en Computación, Universidad de La Seren 28

Page 29: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

embargo, no confundirse porque la biblioteca de Java proporciona las clases: Byte, Character, Short, Integer, Long, Float, Double y Boolean, para encapsular cada uno de los tipos expuestos.

Vea http://java.sun.com/docs/books/tutorial/java/data/numbers.html

Como construyo programas?

En la última sección explicamos que un programa Java consiste de un número de clases. El ejemplo anterior es una muestra de ello pero muy simple. En todo caso, todo programa consiste de una clase que contiene justamente un método estático. Todo lenguaje de programación hace uso de métodos pero usualmente bajo nombres diferentes, por ejemplo, ‘procedure’ o ‘function’ son frecuentes en Pascal o C. En Java se conocen como métodos. Aquí está el programa anterior usando métodos con una indentación apropiada para entender cuando y donde termina una declaración

1. /* Escribir un mensaje en pantalla. */2. public static void main(String[] args)3. { System.out.println(Hola, amigo! );4. System.out.println(Luego nos vemos. );5. }

Comentarios:

1. /* Escribir un mensaje en pantalla. */

Esto es un comentario que describe lo que el programa hace. Puede usar también //, en elcaso que sea solamente una línea.

2. public static void main(String[] args)

Este es el encabezado del método principal. Todo método tiene un nombre, en este caso es la palabra main (principal) que viene justamente antes del paréntesis. Las palabras public, static y void son llamadas por el compilador Java para cuando el método deba ser usado. Esto lo explicaremos después. La parte String[] args, describe la información que esta puesta a disposición, llamada a los parámetros.

3-5. { System.out.println(Hola, amigos! ); System.out.println(Luego nos vemos. );}

es el cuerpo del método.

Todo programa consiste de un número de clases. En los ejemplos anteriores, los programas tienen solamente una clase llamada Hola. Posible de darse cuenta de esto por el encabezado public class Hola

Ingeniería en Computación, Universidad de La Seren 29

Page 30: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

Primer encuentro con POO, el método System.out.println

System.out.println es nuestro primer ejemplo de un método que pertenece a la librería de Java, la que contiene métodos que controlan más aspectos, tales como desplegar un string de caracteres en DOS window. Este es un tipo muy simple de tratamiento de ventanas. El nombre println es la abreviación de ‘print line’, ‘imprime línea.’. Para ver otra sutil diferencia reemplace println por print. Así una declaración del tipo

System.out.print(Hola, amigo!\nLuego nos vemos.\n)

imprime Hola, amigo!, moviendo el cursor al comienzo de la siguiente línea, en donde imprimirá Luego nos vemos., y mueve el cursor a la partida de la siguiente línea. La declaración anterior tiene el mismo efecto que las dos declaraciones siguientes.

System.out.println(Hola, amigo! ); System.out.println(Luego nos vemos. )

Cómo edito un programa?

Cuando escriba un programa, tenga especial cuidado al usar System.out.println. Para escribir un mensaje sobre la pantalla termine con un semicolon, si lo olvida el compilador detectara un error y abortara la compilación de su programa, enviando un mensaje de error compiler error (o syntax error, o parse error). Java es un lenguaje sensitivo, es decir distingue entre mayúsculas y minúsculas, por ejemplo CLASS o Class al comienzo del programa. Ud. debe siempre tipear class, que es la palabra reservada.

Ingeniería en Computación, Universidad de La Seren 30

Page 31: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

Cuántos errores de sintaxis visualiza en este programa?

public Clase Holas{ /* Escribir un mensaje en la pantalla. public static viod Main(string[] args) { System.out,println('Hola, amigo!); System.out.printline(Luego nos vemos.); )}

Otro problema común son los espacios en blanco, por ejemplo,

public c lass H ola{public static void main(String[]args){System.out.println(Hola, amigo!);System.out.println(Luego nos vemos.);}}}

Cómo ejecuto un programa Java

Supongamos que ejecutamos el ejemplo.

public class Hola{ /* Escribir un mensaje en pantalla. */ public static void main(String[] args) { System.out.println(Hola, amigo!); }}

Se supone que Ud. cuenta con un editor de texto como NotePad, TextPad o JPadPro

1. Editar el programa y guardarlo en un archivo llamado Hola.java.2. Si su programa consta de una sola clase guárdelo con el mismo nombre de la clase

seguido de la extensión .java. En nuestro caso guárdelo en Hola.java3. Para compilar escriba el comando en la consola DOS > javac Hola.java 4. Si no tiene problemas de compilación u errores sintácticos el compilador genera una5. versión en bytecode en el archivo con el nombre Hola.class.6. Obtenga ahora una Java Virtual Machine (JVM) que viene incorporada con la

distribución para ejecutar el bytecode compilado del programa que esta en Hola.class , esto lo logra escribiendo >java Hola

Ingeniería en Computación, Universidad de La Seren 31

Page 32: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

Fig. 3. Los tres procesos: escribir el archivo del programa, compilar para producir el archivo .class, y ejecutar el archivo class.

Existen dos formas de correr un archivo ejecutable, ellas son llamadas Aplicaciones Java y Applet Java.

Una Aplicación Java, son programas que pueden ser ejecutados invocando al interprete Java, desde la línea de comando.

Un Applet es un programa Java que es incrustado en páginas Web y ejecutados por un browser que soporta a Java. Hoy en día los Browser, tales como Explorer, Netscape, lo poseen. Así se visualizan ambos, note la diferencia.

public class TrivialAplicacion { public static void main(String[] args) { System.out.println("Hola,amigos.!"); }}

import java.awt.*;import java.applet.Applet; public class TrivialApplet extends Applet { public void paint(Graphics g) { g.drawString("Hola,amigos.!", 20, 20); } }código HTML <applet code="TrivialApplet.class" width=90 height=90></applet>

Ingeniería en Computación, Universidad de La Seren 32

Page 33: Libro Java

Compilar

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

Java, una Plataforma Independiente

Fig 4. La máquina virtual JVM, en acción

Para traducir un programa escrito en un lenguaje de alto nivel (programa fuente) a lenguaje máquina se utiliza un programa llamado compilador. Este programa tomará como datos nuestro programa escrito en lenguaje de alto nivel y dará como resultado el mismo programa pero escrito en lenguaje máquina (en java bytecode), programa que ya puede ejecutar directa o indirectamente el computador. Por ejemplo, un programa escrito en el lenguaje C necesita del compilador C para poder ser traducido. Posteriormente el programa traducido podrá ser ejecutado directamente por el computador. En cambio, para traducir un programa escrito en el lenguaje Java necesita del compilador Java; en este caso, el lenguaje máquina no corresponde al del computador sino al de una máquina ficticia, denominada máquina virtual Java(JVM, Java Virtual Machine), que será puesta en marcha por el computador para ejecutar el programa.

JVM (Máquina Virtual)¿Qué es una máquina virtual?. Una máquina que no existe físicamente sino que es simulada en un computador por un programa. ¿Por qué utilizar una máquina virtual? Porque, por tratarse de un programa, es muy fácil instalarla en cualquier computador, basta con copiar ese programa en su disco duro, por ejemplo. Y, ¿qué ventajas reporta? Pues, en el caso de Java, que un programa escrito en este lenguaje y compilado, puede ser ejecutado en cualquier computador que tenga instalada esa máquina

Ingeniería en Computación, Universidad de La Seren 33

Page 34: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

virtual, de hecho ya todos los sistemas operativos cuentan con este soporte, vea Fig. 4. Esta solución hace posible que cualquier computador pueda ejecutar un programa escrito en Java independiente de la platafor-ma que utilice.Por otra parte, a diferencia de un compilador, un intérprete no genera un programa escrito en lenguaje máquina a partir del programa fuente, sino que efectúa la traducción y ejecución simultáneamente para cada una de las sentencias del programa. Por ejemplo, un programa escrito en el lenguaje javaScript necesita el intérprete que por lo general está en los browser (Netscape, Explorer, etc.) para ser ejecutado. Durante la ejecución de cada una de las sentencias del programa, ocurre simultáneamente la traducción. Notar que, a diferencia de un compilador, un intérprete verifica cada línea del programa cuando se escribe, lo que facilita la puesta a punto del programa. En cambio la ejecución resulta más lenta ya que acarrea una traducción simultánea.

Observación importante:Un programa en Java puede ser una aplicación o un applet. En este curso aprenderá prin-cipalmente a escribir aplicaciones Java. Después aplicará lo aprendido para escribir algunos applets. Dentro de las aplicaciones están las aplicaciones con y sin Swing, en este curso principalmente aprenderá aplicaciones mixtas, es decir con y sin Swing. La librería Swing es una librería con interfaces gráficas muy novedosas. Convengamos sin embargo que una aplicación puede tener una forma más sofisticada (al menos sintácticamente), tal como se muestra a continuación, pudiendo tener otros componentes, tales como extend, implement, abstract y otras que luego veremos

package package_nombre;import class_nombre;import package_nombre.*;. . .public class ClassNombre{

campo-declaracion 1;campo-declaracion 2;. . .metodos-definicion 1;metodos-definicion 2;. . .

public static void main(String [] args) {

declaracion 1;declaracion 2;. . .ejecucion-declaracion 1;ejecucion-declaracion 2;. . .

}}

En general, si quisiéramos ya incorporar elementos de la Programación Orientada a Objetos podríamos haber escrito en forma más general,

import java.lang.*;/* Primer programa como una aplicación en POO*/

Ingeniería en Computación, Universidad de La Seren 34

Page 35: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

public class PrimerProgramm extends Object{ // Comienzo clásico de los Programas en Java public static void main(String args[]) { // salida estandar System.out.println( "Nuestro primer programa Java, pero sofisticado."); }}

Notar que la expresión import java.lang.*; siempre existe por defecto, de manera que se puede omitir, además de extends Object dado que toda clase no se crea por si solo, sino que proviene de una clase madre o padre (super clase) en este caso es Object.

Una visión de la plataforma JDK

La plataforma JDK pone a disposición una serie de comandos y herramientas de utilidad entre las cuales se encuentra:

Java-Compilador: javac, generando Byte-CodeComando: javac ejemplo.javaEjemplo: javac Hola_Alumno.java genera el archivo Hola_Alumno.class y digaHola.class.

Java-Interprete: java, llamando los BytecodeComando: java ejemploImportante: La extensión .class no debe incorporarse!Ejemplo: java Hola_Alumno lleva a cabo la aplicación.

Applet-Viewer: appletviewer, sirve para testear los Java-Applets sin Web-BrowserComando: appletviewer ejemplo.htmlNota: El Applet debe ser referenciado en una página-HTML.Ejemplo (absolutamente AppletMinimal (Hola_AlumnoApplet.java): appletviewer Hola_AlumnoApplet.html.

Generador de Documentos estándar: javadoc, genera documentación en la forma deHTML-Documentos del código fuente Java y contiene comentarios formales.Comando: javadoc ejemplo.javaEjemplo: javadoc -private -version -author -windowtitle "Ejemplo de un JavaDoc"Hola_Alumno.java

Textmode-Debugger: jdb, Debugger orientado al texto.Comando: jdb ejemplo

Desamblador: javap, recuperar códigos fuentes Java desde BytecodeComando: javap ejemplo.

La devolución del compilado Hola_Alumno.class con javap -c Hola_Alumno se vé, así:

Compiled from Hola_Alumnos.javaIngeniería en Computación, Universidad de La Seren 35

Page 36: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

public class Hola_Alumnos extends java.lang.Object { public Hola_Alumnos(); public static void main(java.lang.String[]);}Method Hola_Alumnos() 0 aload_0 1 invokespecial #1 <Method java.lang.Object()> 4 return

Method void main(java.lang.String[]) 0 getstatic #2 <Field java.io.PrintStream out> 3 ldc #3 <String "Hola alumnos"> 5 invokevirtual #4 <Method void println(java.lang.String)> 8 return

Nota: Si Ud. observa NO se recupera el código fuente original, esto es por razones de protección comercial. Sin embargo, existe un Java-Interpete disponible, llamado JavaRuntime Environment (abrev. JRE).

Instalación de Java

Como Ud. podrá haber notado, para escribir programas se necesita un entorno de desarrollo Java. Sun MicroSystems, propietario de Java, proporciona una forma gratuita, llamada Java Development Kit(JDK) que se puede obtener en la dirección Web, http://www.sun.com

Ingeniería en Computación, Universidad de La Seren 36

Page 37: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

Ingeniería en Computación, Universidad de La Seren 37

Page 38: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

Para instalar la versión del CD Rom en una plataforma Windows, hay que ejecutar el archivo j2sdk1_4_0-win.exe. De manera predeterminada el paquete será instalado en jdk1.4, pudiéndose instalar en cualquier otra carpeta. A continuación podrá instalar la documentación en jdk1.4\docs que se proporciona en el archivo j2sdk1_3_0-doc.zip.

La carpeta jre es el entorno de ejecución de Java utilizado por el SDK. Es similar al intérprete de Java (java), pero destinado a usuarios finales que no requieran todas las opciones de desarrollo proporcionadas con la utilidad java. Incluye la máquina virtual, la biblioteca de clases, y otros archivos que soportan la ejecución de programas escritos en Java.

La carpeta lib contiene bibliotecas de clases adicionales y archivos de soporte requeridos por las herramientas de desarrollo.

La carpeta demo contiene ejemplos. Por ejemplo Java2Demo a través de un browser, en este caso a través de Netscape.

La carpeta include contiene los archivos de cabecera que dan soporte para añadir a un programa Java código nativo (código escrito en un lenguaje distinto de Java, por ejemplo Ada o C++).

La carpeta include-old contiene los archivos de cabecera que dan soporte para añadir a un programa Java código nativo utilizando interfaces antiguas.

Ingeniería en Computación, Universidad de La Seren 38

Page 39: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

Ahora, que ya tiene todos los archivos y carpetas de la distribución instalados, sólo le falta un editor de código fuente Java. Es suficiente con un editor de texto sin formato; por ejemplo el bloc de notas de Windows. No obstante, todo el trabajo de edición, compilación, ejecución y depuración, se hará mucho más fácil si se utiliza un entorno de desarrollo con interfaz gráfica de usuario que integre las herramientas mencionadas, en lugar de tener que utilizar las interfaz de línea de órdenes del JDK, como veremos a continuación. Algunos entornos de desarrollo integrados para Java son: Forte de Sun, Visual Café de Symantec, JBuilder de Borland, Kawa de Tek- Tools, Visual Age Windows de IBM, pcGRASP de Auburm University, Visual J++ de Microsoft, JPadPro, BlueJ, Eclipse, y otros. La mayoría de ellos se ajustan a las necesidades del curso. Tomar la precaución de que algunos IDE’s para que funcionen requieren ciertas versiones de Java, infórmese.

JDK 5.0 ( java.sun.com/j2se/1.5.0/download.jsp).

JBuilder 2005 Foundation (www.borland.com/products/downloads/download_jbuilder.html).

NetBeans 5.5 ( www.netbeans.org).

Eclipse 3.1 ( www.eclipse.org).

TextPad ( www.textpad.com).

JCreator LE ( www.jcreator.com).

JEdit ( www.jedit.org).

JGrasp ( www.bluej.org).

DrJava ( drjava.sourceforge.net).

WinZip ( www.winzip.com).

MySQL ( www.mysql.com).

MySQL JDBC Driver ( www.cs.armstrong.edu/liang/intro6e/book/mysqljdbc.jar).

Tomcat ( www.apache.org).

Verificar que el sistema operativo haya asumido los cambios, producto de la instalación de jdk1.4. Para tal efecto, utilizando líneas de comando MSDOS habrá que añadir a la variable de entorno path la ruta de la carpeta donde se encuentra esta utilidad, como por ejemplo:

Ingeniería en Computación, Universidad de La Seren 39

Page 40: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

A continuación se muestran algunas demos que trae la distribución, las que Ud. puede ejecutar sin dificultad. Por ejemplo,

C:\jdk1.3.1\demo\sound\JavaSound.jar C:\jdk1.3.1\demo\jfc\Java2D\Java2Demo.jar

Ingeniería en Computación, Universidad de La Seren 40

Page 41: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

Ingeniería en Computación, Universidad de La Seren 41

Page 42: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

Ingeniería en Computación, Universidad de La Seren 42

Page 43: Libro Java

Dr. Eric Jeltsch F. Capítulo 2: Fundamentos

Ingeniería en Computación, Universidad de La Seren 43

Page 44: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

C A P I T U L O III

Elementos del Lenguaje

En esta lección veremos los elementos que aporta Java (caracteres, tipos de datos, operadores, y otros) para escribir un programa. Considere esta lección como soporte para el resto de las lecciones.

Tipos de Datos y Strings

IntegersHemos visto que no todos los valores tratados por programas Java son objetos. Los tipos de valores simples, tales como integers y floating-point son tratados en forma diferente y son llamados tipos de datos primitivos. Empezaremos con el uso de los enteros (integers.)

Suponga que Ud. visitó Miami, y al regresar le quedan 8 pennies, ningún nickels, 5 dimes y 6 quarters. Cuanto tiene en total?

Para trabajar la respuesta sepa que un penny es una moneda de 1 cent., un nickel son 5 cents, un dime son 10 cents, y un quarter es un cuarto de dólar o 25 cents. A través del siguiente programa no le será difícil saber que Ud. tiene 208 cents. El siguiente programa ilustra varios puntos de interés respecto al trabajo con enteros.

Ejemplo 1

public class Cambio1

{ /* Calcular cuantas monedas Ud. tiene (en cents)Sabiendo que tiene 6 quarters, 5 dimes, ningún nickels,y 8 pennies(o centavos en USA). */

public static void main(String[] args) { System.out.print("Ud. tiene "); //declaración1 System.out.print(6*25 + 5*10 + 0*5 + 8); //declaración2 System.out.println(" cents."); //declaración3 }}

En ejemplo1, el método main contiene tres declaraciones. Cuando lo ejecuta, las tres declaraciones generan tres partes de línea simple sobre la pantalla. Note que las primeras 2 usan print en vez de println. Permitiendo que el valor 208 aparezca inmediatamente después de la palabra Ud. tiene, sobre la misma línea, y cents aparece después.

Ud.tiene 208 cents

Generado por declaración1

declaración2 declaración3

Ingeniería en Computación, Universidad de La Seren 44

Page 45: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

Cuando Java obedece la declaración2, calculara el valor de la expresión aritmética (El símbolo denota multiplicación.) 6*25 + 5*10 + 0*5 + 8 desplegando el resultado, 208.

Algunos Operadores

En Java los siguientes operadores pueden ser usados con expresiones aritméticas.

+ adición substracción multiplicación/ división% módulo

En Java (y muchos otros lenguajes de programación) números son ya sea integers o floating-point. Estos 2 tipos son almacenados en memoria en diferentes sentidos. Si el valor es, por ejemplo 4, se trata de un integer. Por otro lado si es 4.0, será tratado como floating-point. Todos los valores del Ejemplo1 son integers. En la medida que pueda siempre use integers, pues serán tratados más rápido al requerir menos memoria, y no existe peligro de redondeo.

El operador, /, tiene 2 formas. Si es usado con 2 integers entonces es integer division (división entera). Por ejemplo, 11 / 4 = 2, (11) / 4 = 2. Si es usado con dos valores floating-point , o un integer y un valor floating-point, denota división normal. Por ejemplo, 10.5 / 2 = 5.25. El módulo o resto es solamente usado con dos integers. Por ejemplo, 11%4 = 3 y (11)%4 = 3. Si evalúa m/n o m%n donde n es cero, le envía un error.

En los procesos de evaluación, Java asume que los operadores , / y % tienen más alta prioridad que la + y la . Por ejemplo, 3+45 es lo mismo que 3+(45), pero no (3+4)5.

Cuando evalúa expresiones con varios operadores + y en una fila, o varios operadores , / y % en una fila, el criterio es de izq. a der. Por ejemplo, 345 es lo mismo que (34)5, no 3(45). Similarmente 3/4/5 es lo mismo que (3/4)/5, no 3/(4/5) (el que produce un error).

Variables

Ejemplo2

public class Cambio2{ /* Idem Ejemplo1. */ public static void main(String[] args) { int total = 6*25 + 5*10 + 0*5 + 8; System.out.print("Ud. tiene "); System.out.print(total/100); System.out.print(" dólares con "); System.out.print(total%100); System.out.println(" cents."); }

Ingeniería en Computación, Universidad de La Seren 45

Page 46: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

}

El Ejemplo2 es otra versión del programa Ejemplo1, esta vez haciendo uso de variables.

La declaración int total = 6*25 + 5*10 + 0*5 + 8;

nos dice: crea una variable total que denota la expresión 625 + 510 + 05 + 8 ( = 208). La palabra int muestra que el valor de total es un valor integers. Llamado declaración de variable. La declaración

System.out.print(total/100);

dice: la salida es el cuociente entre total que es dividido por 100 (división entera). Es decir 208/100 (= 2) es la salida. La declaración

System.out.print(total%100);

dice: la salida es el resto de la división de total dividido por 100. Es decir 208%100 (= 8). Esto es lo que se despliega en pantalla.

Ud. tiene 2 dólares con 8 cents

Ejemplo 3

public class Cambio3

{ public static void main(String[] args) { int quarters = 6; int dimes = 5; int nickels = 0; int cents = 8;

int total = quarters*25 + dimes*10 + nickels*5 + cents;

System.out.print("Ud. tiene "); System.out.print(total/100); System.out.print(" dólares con "); System.out.print(total%100); System.out.println(" cents."); }}

Si al ejemplo 2 se le incorpora la declaración de variables, se genera el Ejemplo 3. Es importante mencionar que en Java, cuando una variable es creada tiene un área de memoria para almacenar sus valores. La memoria depende del tipo de dato que se le asigno a la variable en la declaración. Por ejemplo, si la declaración dice que es de tipo int, como es el caso de la variable total, dejara 32 bits de memoria. El valor de una variable int esta en el rango 2147483648 a 2147483647. Si maneja enteros más grande reemplace int por long, a lo que la variable le dejará 64 bits de memoria.Ingeniería en Computación, Universidad de La Seren 46

Page 47: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

Asignaciones

Toda variable tiene un nombre y una porción de memoria, según el tipo de dato declarado. Decimos que el valor en la porción de memoria es el valor asignado a la variable. En el siguiente ejemplo el valor de la variable peso es cambiada una vez.

Ejemplo 4

public class Peso1

{ /* Calcula las libras a kilos dado el peso almacenado en libras. */

public static void main(String[] args)

{ int stones = 10; int libras = 8;

libras = 14*stones + libras; double kilos = libras * 0.4536; System.out.print("Ud. pesa "); System.out.print(kilos); System.out.println(" kilos."); }}

Este programa parte creando 2 variables llamadas stones y libras . (1 stone = 14 libras.) y declara

libras = 14*stones + libras;

esto dice: calcula el valor de la expresión 14*stones + libras, y almacena el resultado en la variable libras. En otras palabras, reemplaza el valor original almacenado en libras (= 8)

por la persona con peso total en libras (= 148).

La declaración double kilos = libras * 0.4536;

es nuestro primer ejemplo de cómo usar el valor floating-point. Y dice: crea una variable llamada kilos de tipo double, y le asigna el valor libras * 0.4536 . Una variable de tipo double posee 64 bits de memoria. El producto de un entero y un floating-point es calculado en floating-point. En este caso la respuesta será 67.1328. Una vez que el peso de la persona ha sido calculado, las últimas tres declaraciones entregan la respuesta.

Ud. pesa 67.1328 kilos.

La declaración libras = 14*stones + libras;

es una declaración de variable de tipo int. Esto significa que cuando Java obedece la declaración de asignación la realiza en 2 etapas: primero evalúa la expresión a la derecha de ‘=’, y almacena el resultado en la variable a la izquierda de ‘=’. De esta manera cuando agregamos 15stones y el valor original en libras, obtendremos la respuesta en la variable Ingeniería en Computación, Universidad de La Seren 47

Page 48: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

libras, sobreescribiendo en el antiguo valor. En efecto, agregamos 14stones al valor de libras. Si a menudo necesita hacer este tipo de declaraciones, hágalo como en C. En tal caso podrá escribir.

libras += 14stones;

que dice: adicione 14stones a libras. Similarmente puede usar = para cuando quiera restar o substraer un valor desde una variable, y podemos usar = cuando queramos multiplicar una variable por el valor, y así sucesivamente. Uno de los ejemplos más comúnes en este tipo de declaraciones es para cuando queremos adicionar 1 al valor de la variable. En tal caso podemos escribir, por ejemplo,

x += 1;

para sumar 1 al valor de x. Sin embargo, es más común una declaración del tipo

x++;

Similarmente para restar 1 desde x, podemos escribir x--.

Ud. podrá cambiar el valor almacenado en la variable, pero nunca podrá cambiar el tipo de valor. Por ejemplo, dada la declaración de la variable int libras en el último ejemplo, cualquier nuevo valor asignado a él deberá ser un entero, y siempre será almacenado en 32 bits de memoria. El siguiente diagrama describe las diferentes formas de declaración.

declaración (con un valor inicial)

Tipo Nombre = Expresion ;

Por ejemplo, Tipo puede ser int, Nombre puede ser quarters, y Expresion ser 6. Esta sería la declaración int quarters = 6;

Punto Flotante.

El nombre punto flotante “floating-point” proviene en el sentido que estos números son representados en la memoria del computador. La notación es similar a la notación científica (es decir, 1.0751024), pero usando base 2 en vez de base 10.

En Java, el tipo de dato double es el usado más comúnmente para valores punto flotante. 64 bits son usados para valores double. Siendo el rango de los valores: aproximadamente 1.810308, equivalente a 15 dígitos significativos. El nombre double es para ‘double precision floating-point’. Java tiene un segundo tipo de dato para tratar números floating-point, llamados float. Este tipo de dato usa solamente 32 bits para los valores, siendo más económico en el uso de memoria, pero tiene la mitad de la precisión de double.

Ingeniería en Computación, Universidad de La Seren 48

Page 49: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

Los números floating-point pueden ser escrito con punto decimal, es decir, 14.56 o 14.0. Puede también ser escrito con exponente, es decir, 14.56E-12, que es equivalente a 14.561012.

Como cualquier tipo de dato, podemos declarar variables de tipo double. Por ejemplo,

double radio = 1.67;

que creará una variable llamada radio, considerando 64-bit en memoria que contiene el valor inicial 1.67.

Funciones Estándares

Java proporciona métodos que calculan el rango de las funciones matemáticas usando valores double. Aquí hay algunos ejemplos, ellos son métodos static (es decir, métodos que NO pertenecen a un objeto) en la librería Math de Java.

Math.sin(x) seno de xMath.cos(x) coseno de xMath.tan(x) tangente de xMath.exp(x) ex

Math.log(x) log natural de xMath.abs(x) valor absoluto de xMath.floor(x) entero más grande que sea xMath.ceil(x) entero más pequeño que sea x

En cada caso el parámetro x es de tipo double y el resultado es de tipo double. Notar la perdida de precisión que se obtiene con

float r;r= (float)Math.sqrt(10);

pues el resultado se redondea perdiendo precisión ya que sqrt() devuelve un valor de tipo doble. Algunas otras observaciones, son las siguientes,

int m = 3;int n = 4;double x = mn;

cuando Java ejecuta la tercera declaración evalua mn usando aritmética entera para dar 32-bit al valor entero 12. Entonces convertirá el valor 12 a 64-bit floating-point, que será almacenado en x. Si reemplazamos, la tercera declaración por,

double x = m/n;

la respuesta es que x será seteado a 0. La razón es que en aritmética entera usará la expresión m/n, y el operador será división entera. Así el valor es cero.

Ingeniería en Computación, Universidad de La Seren 49

Page 50: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

Suponga que queremos usar una división normal en floating-point para trabajar sobre x Debemos entonces tratar el valor de m y n como valor floating-point. Pudiendo escribir,

double x = ((double) m) / n;

El término (double) es llamado cast. Podemos usar casts para transformar un valor de un tipo cualquiera que sea en un valor equivalente de otro tipo.

La parte entera de un número floating-point. Por ejemplo, el número floating-point 4.7 se convierte en el entero 4. El camino para hacer esto en Java es usar el cast int. Supongamos lo siguiente,

double x = 4.7;int i = (int) x;

la segunda declaración convertirá el valor de x al entero 4, y lo almacenará en i. Si x ha sido seteado a 4.7, i tomará el valor 4.

Redondear el número. Por ejemplo, el techo de 4.7 es 5. Supongamos lo siguiente, procurando que el valor no sea negativo.

int i = (int) (x + 0.5);

Por ejemplo, si x es igual a 4.7, el valor de x + 0.5 será 5.2, y el valor de(int)(x + 0.5) será 5, el cual es el techo de 4.7. Sin embargo, si x es 4.7, se obtiene que el valor de x + 0.5 será 4.2, y el valor de (int)(x + 0.5) será 4, el que no es el techo de 4.7.

Ejemplo 5.

// Demo para practicar con los tipos de datos y operadoresclass BasicaMate { public static void main(String args[]) { // aritmetica usando integers System.out.println("Aritmética"); /*

double x =4.7;int i = (int) (x + 0.5);System.out.println("x es " + x);

System.out.println("i es " + i);*/ /*

double r; r= Math.sqrt(10);

*/float r;r=(float)Math.sqrt(10);

int m = 3;int n = 4;double x = m/n;double z = ((double) m) / n;

System.out.println("r es " + r); System.out.println("m es " + m); System.out.println("n es " + n);

System.out.println("x es " + x);System.out.println("z es " + z);

Ingeniería en Computación, Universidad de La Seren 50

Page 51: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

}}

Clases de I/OPor lo general, cada texto introductorio en el lenguaje Java trae hoy en día sus propias clases, generando que inevitablemente debamos conocer como trabajan las clases, los métodos y la forma de ingresar y retornar datos. Tal como se mencionaba, en la Lección1 Fundamentos),el libro Java How To Program (Deitel & Deitel 3Ed.) posee el paquete com.deitel.jhtp3.*, de la misma manera el libro de Cay S. Horstmann, Core Java 2, Volumen I, (Fundamentals) trae el paquete corejava, y David Flanagan trae el paquete com.davidflanagan.*. Con esto quiero decir que en la práctica siempre nos encontraremos con libros que de una u otra manera tienen enfoques distintos y distintas clases para tratar el ingreso y retorno de datos. Frecuentemente un programa necesita obtener información desde un origen o enviar información a un destino, hasta el momento los datos son estáticos, es decir han sido incorporados al programa a través de asignaciones simples con expresiones aritméticas. Sin embargo en general la comunicación entre el origen de cierta información y el destino, se realiza mediante un flujo de información (llamado, stream en inglés), que es un objeto que hace de intermediario entre el programa, y el origen o el destino de la información. Luego, para que un programa pueda obtener información desde un origen tiene que abrir un flujo y leer la información, análogamente para escribir la información. De allí que necesitemos incorporar datos en forma dinámica a través del teclado. Todas las clases relacionadas con flujos en la distribución estándar de Java están en el paquete java.io, de manera que en rigor debería importar este paquete en el encabezado mediante la declaración import java.io.*; en el encabezado del programa. Sin embargo, Java lo importa por defecto, de manera que no se preocupe de hacerlo. Como ya habíamos mencionado, existen normalmente tres flujos de datos de I/O conectados a su programa:

System.in--- el flujo de entrada.System.out--- el flujo para los resultados normales.System.err--- el flujo para los mensajes de error.

Normalmente System.in se conecta al teclado y los datos son carácteres. System.out y

System.err se conectan ambos al monitor, y los datos son carácter. Los datos que un teclado envía a un programa son datos character, incluso cuando los carácteres incluyen los digitos ' 0 ' a ' 9 '.

Si su programa hace aritmética, los caracteres de la entrada se convertirán en uno de los tipos numéricos primitivos. Se calcula (usando aritmética), y luego el resultado se convierte a dato character. La información que un programa envía al monitor son datos character:

Ingeniería en Computación, Universidad de La Seren 51

Page 52: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

(Realmente, los caracteres no se envían directamente al monitor, sino que ellos se convierten primero en una señal de video por la tarjeta gráfica. Esta forma de convertir datos de una forma a otra es muy común). El siguiente programa lee characters desde el teclado en el String llamado enDato. Luego los caracteres almacenados en String son enviados al monitor.

Ejemplo 6.

import java.io.*; class Eco{ public static void main (String[] args) throws IOException { InputStreamReader inStream = new InputStreamReader( System.in ) ; BufferedReader stdin = new BufferedReader( inStream ); String enDato;

System.out.println("Ingrese el dato:"); enDato = stdin.readLine(); System.out.println("Ud. ingreso:" + enDato ); }}

La línea import java.io.*; dice que el paquete java.io será usado y * significa que cualquier clase al interior del paquete sera usada.

IOException es necesario para programas que tienen entrada por teclado (por lo menos por ahora.) para informarle al compilador que main() tiene un funcionamiento de entrada que eventualmente podría fallar. A lo que si el programa que se está ejecutando y un funcionamiento de la entrada falla, el sistema le informará del fracaso y el programa se detendrá. En otras lecciones donde tratemos (Exceptions) veremos con más detalle esta y otras situaciones. Examinemos las siguientes declaraciones, que son básicas para el I/O de datos en Java.

(1) InputStreamReader inStream = new InputStreamReader (System.in);(2) BufferedReader stdin= new BufferedReader (inStream);

La (1) construye un objeto de InputStreamReader y le da el nombre inStream. La (2) construye un objeto de BufferedReader llamado stdin que lo conecta al inStream. Pudiendo escribirse en forma resumida como

Ingeniería en Computación, Universidad de La Seren 52

Page 53: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

BufferedReader stdin = new BufferedReader( new InputStreamReader( System.in ) );

La variable inStream. es usada para conectar el InputStreamReader a la BufferedReader.

Observar que si Ud. quisiera que el usuario ingresara datos numericos, su programa debería convertir los caracteres a tipo de dato numérico. Para ello no olvidar que los caracteres son primero leídos en un objeto String para luego convertirlo a dato numérico. Para tal efecto se usa la declaración

enDato = stdin.readLine(); num = Integer.parseInt( enDato );// convertir a int

Aquí se muestra una nueva versión del programa Peso1.java , usando BufferReader.

Ejemplo 7.

import java.io.*;public class PesoBuffer { /* Calcula las libras a kilos dado el peso almacenado en libras. */

public static void main(String[] args) throws IOException { BufferedReader stdin = new BufferedReader ( new InputStreamReader( System.in ) ); String stones, libras;

int num, num1; double kilos;

System.out.println("Digame su peso."); System.out.print("Cuantos stones: ");

stones = stdin.readLine(); num = Integer.parseInt( stones );

System.out.print("Cuantas libras: ");

libras = stdin.readLine(); num1 = Integer.parseInt(libras);

num1 = 14*num + num1;

kilos = num1 * 0.4536; System.out.print("Ud. pesa "); System.out.print(kilos); System.out.println(" kilos."); }//end main}//end PesoBuffer

Ingeniería en Computación, Universidad de La Seren 53

Page 54: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

Aquí se muestra un ejemplo de lo que aparece en pantalla. (Usando input en boldface.)

Digame su peso.Cuantos stones: 8Cuantas libras: 5Ud. pesa 53.0712 kilos.

ConsoleReader ConsoleReader es otra clase usada para leer datos de entrada. Horstmann en su libro Core Java, proporciona un paquete corejava para, entre otras cosas, leer la entrada de datos por teclado. La clase es llamada ConsoleReader, que está habilitada en un archivo de nombre ConsoleReader.java. Para usarla basta insertar la siguiente declaración

ConsoleReader in = new ConsoleReader(System.in);

en su programa, y no olvidar de guardar su programa junto con ConsoleReader en el mismo directorio, o bien guardar la extensión ConsoleReader.class en la misma carpeta de trabajo, así podrá acceder el objeto System.in, el que está conectado al teclado.

in.readInt() // devuelve un valor int. in.readDouble() // devuelve un valor double. in.readLine() // devuelve un string, que consiste de todos los caracteres

ingresados por consola por el usuario hasta el fin de línea.

Aquí se muestra una nueva versión del programa Peso1.java , usando ConsoleReader.

Ejemplo 8

public class PesoConsole

{ /* Calcula las libras a kilos dado el peso almacenado en libras. */

public static void main(String[] args)

{ ConsoleReader in = new ConsoleReader(System.in);

System.out.println("Digame su peso."); System.out.print("Cuantos stones: "); int stones = in.readInt(); System.out.print("Cuantas libras: "); int libras = in.readInt(); libras = 14*stones + libras; double kilos = libras * 0.4536; System.out.print("Ud. pesa "); System.out.print(kilos); System.out.println(" kilos."); }//end main} //end PesoConsole

Ingeniería en Computación, Universidad de La Seren 54

Page 55: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

Aquí se muestra un ejemplo de lo que aparece en pantalla. (Usando input en boldface.)

Digame su peso.Cuantos stones: 8Cuantas libras: 5Ud. pesa 53.0712 kilos.

Obs: Ud. verá el siguiente mensaje si no tiene la librería o archivo ConsoleReader

C:\Documents and Settings\usuario\Escritorio\POO\lect_Jpoo_06\source2\PesoConsole.java:8: cannot resolve symbolsymbol : class ConsoleReader location: class PesoConsole

{ ConsoleReader in = new ConsoleReader(System.in); ^C:\Documents and Settings\usuario\Escritorio\POO\lect_Jpoo_06\source2\PesoConsole.java:8: cannot resolve symbolsymbol : class ConsoleReader location: class PesoConsole

{ ConsoleReader in = new ConsoleReader(System.in); ^2 errors

Herramienta completada con código de salida 1.

Para evitar esto, deberá incluir el archivo ConsoleReader.class en el directorio en donde Ud. está trabajando.

hsa.* A continuación, se muestra otro ejemplo de Peso1.java, usando el paquete hsa que lo puede obtener de la dirección Web: http://www.holtsoft.com/java/hsa_pkg_overview.html

Ejemplo 9.

import hsa.*; public class PesoHsa { /* Calcula las libras a kilos dado el peso almacenado en libras. */

public static void main (String [] args) { int libras, stones; System.out.println("Digame su peso."); System.out.print("Cuantos stones: "); stones = Stdin.readInt(); System.out.print("Cuantas libras: ");libras = Stdin.readInt();libras = 14*stones + libras;double kilos = libras * 0.4536;

System.out.print("Ud. pesa ");System.out.print(kilos);System.out.println(" kilos.");//System.out.println("The number: " + aNum);

} //end main

} //end PesoHsa

Ingeniería en Computación, Universidad de La Seren 55

Page 56: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

Swing

Y finalmente mediante el uso de la librería Swing. Observar que el encabezado invoca a la dirección javax.swing.JOptionPane;

Ejemplo 10.

import javax.swing.JOptionPane;

public class PesoSwing { /* Calcula las libras a kilos dado el peso almacenado en libras. */

public static void main( String args[] ) { int stones, libras; String entrada; // prompt para input y leer la entradaentrada = JOptionPane.showInputDialog("Digame su peso. Cuantos stones: " );

// convertir la entrada de String a integerstones = Integer.parseInt( entrada );

entrada = JOptionPane.showInputDialog("Cuantas libras: " );

// convertir la entrada de String a integer libras = Integer.parseInt( entrada );

libras = 14*stones + libras; double kilos = libras * 0.4536;

// display el promedio de los datos JOptionPane.showMessageDialog( null, "Ud. pesa " + kilos + " kilos ", "Resultado", JOptionPane.INFORMATION_MESSAGE );

Ingeniería en Computación, Universidad de La Seren 56

Page 57: Libro Java

CelsiusToFarehheit2 main

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

System.exit( 0 ); // termina el programa }}

Es así como podríamos continuar haciendo funcionar nuestros programas soportados por diversas librerías de clases. Sin embargo, lo que deseo transmitir es que aprenda a tener la capacidad de incursionar en otros tipos de paquetes y clases para ver el que le convenga o sino buscar nuevas alternativas o bien generar sus propias clases.

Modelemos desde un punto de vista más abstracto una arquitectura para la aplicación que transforma grados Celsius a Fahrenheit. Por ejemplo,

Ejemplo 11.

import java.text.*;import javax.swing.*;/** CelsiusToFahrenheit2 convierte Celsius a Fahrenheit. * input: los grados Celsius, se lee un integer de dialog * output: los grados Fahrenheit, un double */

public class CelsiusToFahrenheit2{ public static void main(String[] args) {

String input = JOptionPane.showInputDialog("Ingresar entero, Cº T.:"); int c = new Integer(input).intValue(); // convierte input en un int double f = ((9.0 / 5.0) * c) + 32; DecimalFormat formato = new DecimalFormat("0.0"); System.out.println("para Cº Celsius " + c + ","); System.out.println("grados Fº Fahrenheit = " + formato.format(f));

Ingeniería en Computación, Universidad de La Seren

JOptionPaneshowInputDialog

IntegerintValue

System.out main

DecimalFormat format

57

Page 58: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

}}

cuyo resultado es 73.4 Fº, pero en MS-DOS. Sin embargo a veces es necesario ingresar los datos por teclado y con varios parámetros a la vez. Esto último lo veremos en el próximo capítulo.

Ahora, nos falta aprender el ingreso de datos a través de archivos, que sean leídos por el programa, tratados o manipulados por él, para luego ir a depositarlos en otro archivo de salida, por ejemplo. Esto lo veremos más adelante, en las siguientes secciones. El propósito del siguiente ejemplo es mostrar entrada y salida de datos usando la consola y los archivos de la clase hsa. El paquete hsa posee muchas otras clases que le pueden ser de utilidad. Ud. podrá comprobar tras la ejecución del programa ArchivoHsaDemo.java que en el archivo salida.txt en su carpeta de trabajo están los datos 34, 56, 78, 90, 12. Además intente ingresar un número NO entero y verá otra de las gracias del paquete hsa, y digo “gracia” porque el código no posee declaraciones try-catch (atrapa excepciones).

Ejemplo 12.

import hsa.*;

public class ArchivoHsaDemo {

public static void main (String [] args) {

int [] numsArray = {34, 56, 78, 90, 12}; int i, aNum; String entraString, saleString;

//Screen Input en la Consola System.out.print("Ingrese un número entero: "); aNum = Stdin.readInt();

// Screen Output para un número System.out.println("El número es: " + aNum);

//Archivo Texto de Output TextOutputFile saleFile = new TextOutputFile ("salida.txt"); for (i = 0 ; i < numsArray.length ; i++) saleFile.println (numsArray [i]); saleFile.close ();

//Archivo Texto de Entrada int numNums = 0;

Ingeniería en Computación, Universidad de La Seren 58

Page 59: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

int[] leerNums;

TextInputFile enFile = new TextInputFile ("salida.txt"); while (!enFile.eof()) { aNum = enFile.readInt(); numNums++; } // end while enFile.close(); leerNums = new int [numNums]; enFile = new TextInputFile ("salida.txt"); for (i = 0; i < numNums; i++) leerNums[i] = enFile.readInt(); enFile.close();

// Chequear los números que han sido leídos. saleString = "Los números son: "; for (i = 0 ; i < numNums ; i++) saleString = saleString + leerNums [i] + ", "; System.out.println(saleString);

} //end main method

} //end ArchivoHsaDemo

Strings.

Esta sección contiene información sobre uno de los tipos de datos más comunes, strings. Un literal string es escrito entre comillas. Por ejemplo, el perro. Si el literal es vacío se escribe . Un string puede contener control de caracteres, esta es una lista de combinaciones que se pueden hacer.

\n newline\t tab\b backspace\r return\f line feed\\ \ character\ caracter\ caracter

Por ejemplo, System.out.print(El\nfin);

Escribirá ‘El’ en una línea y en la otra línea verá ‘fin’.

Si desea almacenar un string basta usar una variable de tipo String. Por ejemplo,

String animal = perro;

La concatenación es denotada por ‘+’. Por ejemplo, si la variable animal ha sido asignada a perro, entonces la expresión El + animal + corre. denota el stringEl perro corre. Expresiones usuales en programas son por ejemplo, la declaración

System.out.println(El + animal + corre.);

Ingeniería en Computación, Universidad de La Seren 59

Page 60: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

que desplegara el mensaje El perro corre. sobre la pantalla. Por otra parte El + animal + corre + cuanTas + veces, denota el string El perro corre 10 veces.

Si recuerda estas declaraciones

System.out.print("Ud. tiene ");System.out.print(total/100);System.out.print(" dólares con ");System.out.print(total%100);System.out.println(" cents.");

Las cinco declaraciones han sido combinadas en una sola,System.out.println

( Ud. tiene + (total/100) + dolares con +(total%100) + cents. );

El siguiente programa usa los métodos usuario.readLine() para leer el nombre del usuario y usuario.readInt() para leer la edad.

Ejemplo 13

public class Chatear

{ /* Chateando. */ public static void main(String[] args)

{ ConsoleReader usuario =new ConsoleReader(System.in);

System.out.println ("Hola. Cómo te llamas?"); String nombre = usuario.readLine(); System.out.println

("Que edad tienes " + nombre + "?"); int edad = usuario.readInt(); System.out.print(edad + "no esta mal la edad, "); System.out.println ("pues yo tengo " + (edad+1) + " que es mejor."); System.out.println ("Hasta la vista " + nombre + "."); }}

En pantalla podrá ver,Hola. Como te llamas?Alicia LobosQue edad tienes Alicia Lobos?2020 no esta mal, pues yo tengo 71 que es mejor.Hasta la vista Alicia Lobos.

Algunas expresiones útiles st.substring(m,n), tal como animal.substring(5,8)Ingeniería en Computación, Universidad de La Seren 60

Page 61: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

genera el string nte, tal como se describe.

e l e f a n t e

0 1 2 3 4 5 6 7 8

Java tiene un tipo de dato llamado String que difiere de los 8 tipos primitivos, en lo fundamental porque un valor del tipo string es un objeto. Un string no es justamente un valor de dato, también tiene "métodos". (Un método es un subprograma que es parte de un objeto.) por ejemplo, si str es una variable de tipo String, Ud. puede llamar al método str.length(), que es una función que devuelve el número de carácteres en el string. Hay mucho más que usted puede hacer con string. Una cosa que usted no puede hacer con string es usar los operadores <,>, <=, y <= para compararlos. Usted puede usar legalmente = = y != para comparar String, pero debido a las peculiaridades en los objetos de la manera de comportarse, ellos no darán los resultados que usted quiere. (El operador = = verifica si se guardan dos objetos en la misma dirección de memoria, en lugar de si ellos contienen el mismo valor. Si Ud. examina la distribución de Java2 verá que en java.lang.String se encuentran estos y otros métodos que le pueden servir de ayuda. No obstante, la versión 1.4 trae en C:\j2sdk1.4.2_05\src\java\util el directorio regex, que es de mucha utilidad.

La clase String define una serie de métodos, al cual le dedicaremos algunos ejemplos. Se supone que s1 y s2 son de tipo Strings:

s1.equals(s2) es una función valor que retorna true si s1 consiste de exactamente los mismos caracteres que s2.

s1.equalsIgnoreCase(s2)chequea si s1 es el mismo string que s2, sin distinguir mayúsculas de minúsculas. Entonces, si s1 es "cat", s1.equals("Cat") es false, mientras que s1.equalsIgnoreCase("Cat") es true.

s1.length(), entrega el número de caracteres en s1.

s1.charAt(N), N integer, es un valor char que retorna el N-ésimo caracter en el string. Posición son numeradas partiendo de 0, asi s1.charAt(0) es actualmente el primer caracter, s1.charAt(1) el segundo y asi sucesivamente. La posición final es s1.length() - 1. s1.substring(N,M), N y M integers, retorna un String que contiene un substring de los caracteres en s1. El substring consiste de los caracteres en s1 en posición N, N+1,..., M-1. Note que el caracter en posición M no está incluído. Vea y analice la salida de Ejemplo7.

Ejemplo 14

public class Test {public static void main (String argv [] ) {

String s = "123456";String t = "012345";String u = s;System.out.println (s.length( ) );

Ingeniería en Computación, Universidad de La Seren 61

Page 62: Libro Java

str1

str2 área de memoria

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

System.out.println (s.indexOf('3') );System.out.println (t.indexOf('6') );System.out.println ("char:" + s.charAt(3) );System.out.println ("sub:" + s.substring (2) );System.out.println ( (s == t)? "Y" : "N" );System.out.println ( (s.equals (t) ? "Y" : "N" ));System.out.println ("compare:" + s.compareTo(u) );

}}

La respuesta es 6, 2, -1, char:4, sub:3456, N, N, compare:0Notar que equals verifica los contenidos de 2 objetos String. Mientras que a diferencia del método equals, el operador = = NO compara los contenidos de los objetos referenciados sino las referencias, es decir, si tenemos

String str1=”abc”;String str2=”abc”;

if (str1.equals(str2)){}

//el resultado es siempre true!!, pues independiente de que se traten o no de objetos diferentes, los contenidos son los mismos.

if (str1==str2){}

//el resultado es siempre true!!, porque ambos identificadores se refieren al mismo objeto. str1 y str2 ocupan la misma área de memoria para objetos String.

Sin embargo, la utilización del operador new hace que se reserve o asigne memoria para un nuevo objeto. Por ejemplo,

String str1= new String(”abc”); String str2=”abc”; if (str1.equals(str2)){}

//el resultado es siempre true!!, pues Java añade el objeto String “abc” al área de memoria destinada a tales objetos, de manera que cuando se compila, la segunda línea no añade un nuevo objeto porque ya existe uno con el mismo literal.

if (str1==str2){}

//el resultado es siempre false!!.

Ingeniería en Computación, Universidad de La Seren

“ abc ”

62

Page 63: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

equals() es un método de la clase java.lang.Object, de manera que Object es la clase madre.

Ejemplo 15

class StringTest { public static void main ( String[] args ) { String str; str = new String("Hola alumnos"); System.out.println(str); str = new String("Chao alumnos"); System.out.println(str); }}

El programa hace exactamente lo esperado, es decir escribe en la salida:

Hola alumnos

Chao alumnos

Veamos algunos detalles del programa.

str = new String("Hola alumnos");

crea un primer Objeto, e inserta una referencia a este objeto en str, y lo imprime

System.out.println(str);

Crea un segundo Objeto, e inserta una referencia al segundo objeto en str

str = new String("Chao alumnos");

En este momento no existe referencia al primer objeto, el cual es ahora "garbage."(basura)

System.out.println(str);

obtiene el dato y lo imprime. Notar que:1. Cada vez que el operador new es usado, un nuevo objeto es creado.2. Cada vez que un objeto es creado, existe una referencia a él..3. Esta referencia es almacenada en una variable.4. más tarde, la referencia en la variable es usada para encontrar el objeto.5. Si otra referencia es almacenada en la variable, ella reemplazará la referencia previa.6. Si ninguna variable referencia a un objeto, no existe forma de encontrarlas.

La forma (6) recibe el nombre de "garbage." La palabra "garbage" es el término correcto para expresar en ciencias de la computación el uso de objetos que no tienen referencias. Esta es una situación común, la que no usualmente representa un “mistake”(equivocación-error). En Java

Ingeniería en Computación, Universidad de La Seren 63

Page 64: Libro Java

Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje

un programa ejecutable con este tipo de situación invoca a su recolector de basura, a lo que el object (el "garbage") puede volver a usar su memoria.

Ejemplo 16 Este ejemplo muestra varios objetos de la misma clase

class StringTest1{ public static void main ( String[] args ) { String strA; // referencia al primer objeto String strB; // referencia al segundo objeto // crea primer objeto y almacena su referencia strA = new String( "Hola alumnos" );

//sigue referenciando al objeto e imprime los datos System.out.println( strA );

// crea un segundo objeto y almacena su referencia. StrB = new String( "Chao alumnos" );

//sigue referenciando al objeto e imprime los datos

System.out.println( strB );

//sigue referenciando al objeto e imprime los datos

System.out.println( strA ); }}

El programa imprime:

Hola alumnos Chao alumnos Hola alumnos

Ingeniería en Computación, Universidad de La Seren 64

Page 65: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

C A P Í T U L O 4

Llegado a esta lección el alumno ya podrá escribir programas simples pero completos. En esta sección se estudiarán las estructuras de control de un programa Java, entre las cuales están las repeticiones o ciclos y otras.

Decisiones (if)Ahora nos dedicaremos al uso de la declaración if. Existe una gran cantidad de alternativas en la programación en donde se debe ya sea decidir o seleccionar desde algunas alternativas. En la mayoría de los programas que hemos visto hasta ahora, las declaraciones no tienen alternativas de hacer otras cosas, es un tanto “lineal” de cómo el compilador se comporta, dada las instrucciones que hemos utilizado. No obstante existen posibilidades de usar alternativas o decisiones. Este tipo de decisiones se llama en Java declaración o estructura if. Un ejemplo de este tipo es,

if (resp == 6048) System.out.println("Bien!");else System.out.println("Error.");

que nos dice, que si el valor de resp es igual a 6048, despliega el mensaje“Bien!”, De otra manera dirá “Error.” Notar que la expresión,

resp == 6048

se refiere a la condición ‘resp es igual a 6048’, usando el símbolo = = para la relación de igualdad, en vez de = para evitar confusión con la asignación. Aquí tenemos un ejemplo que usa la estructura if.

Ejemplo 1

import javax.swing.*;/** ConvertHora traslada tiempo en hrs. en su equivalente en seg. * Input: un entero no-negativo * Output: convierte las horas en seg. */public class ConvertHora{ public static void main(String[] args) { int hora = new Integer( JOptionPane.showInputDialog("Ingrese Hora, un entero:")).intValue(); if ( hora >= 0 ) { // si la entrada de datos es correcta: int segundo = hora * 60 * 60; JOptionPane.showMessageDialog(null, hora + " hora es " + segundo + " segundos"); } else { // si la entrada no corresponde, error: JOptionPane.showMessageDialog(null, "ConvertHora error: entrada negativa " + hora);

Ingeniería en Computación, Universidad de La Seren 65

Page 66: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

} }}

De manera similar, podemos hacer uso de la lógica, en particular del conectivo ``and'' (conjunción) para escribir una expresión que busca una variable entero minuto que se encuentra en un rango de 0..59:

(minuto >= 0) && (minuto <= 59)

El simbolo, &&, denota ``and.'' Una pequeña ejecución de la traza de esta expresión para cuando minuto es 64, y donde el resultado es false, como se aprecia.

(minuto >= 0) && (minuto <= 59)=> (64 >= 0) && (minuto <= 59)=> true && (minuto <= 59)=> true && (64 <= 59)=> true && false => false

TABLA 1: Operadores Lógico

Operador Semantica

E1 && E2

conjunción (``and''): true && true => true true && false => false false && E2 => false

E1 || E2

disjunción (``or''): false || false => false false || true => true true || E2 => true

!E negación(``not''):

!true => false !false => true

La semántica debe respetarse, por ejemplo:

(2 != 1) || (x == 3.14)=> true || (x == 3.14)=> true

esta disjunción, ||, resulta ser true, por lo tanto no existe necesidad de calcular el 2º argumento, resultando la expresión, true.

Ingeniería en Computación, Universidad de La Seren 66

Page 67: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

Ejemplo 2

Otro ejemplo interesante es considerar el método: deposit(int monto): boolean, que trata de especificar lo siguiente..

1. Si monto es no-negativo, entonces adiciona monto a la cuenta balance.

2. de otra manera, use un error de mensaje e ignore el depósito.

3. return el resultado.

Vea la salida y siga practicando, dándose otras situaciones.

import javax.swing.*;/** BankCuenta administra una cuenta simple */public class BankCuenta{

private int balance; // balance >= 0 siempre!

/** Constructor BankCuenta inicializa la cuenta * @param inicial_m – cuenta balance,nonegativo. */ public BankCuenta(int inicial_m) {

if ( inicial_m >= 0 ) { balance = inicial_m; }

else { balance = 0; } }

/** deposita adiciona dinero a la cuenta. * @param monto – el monto a ser agregado, un int nonegativo * @return true, si el deposito sucedio; false, en otro caso */ public boolean deposit(int monto) { boolean result = false; if ( monto >= 0 ) { balance = balance + monto; result = true; } else { JOptionPane.showMessageDialog(null, "BankCuenta error: mal el monto del deposito---ignorado"); } return result; } /* sacarMonto, elimina dinero desde la cuenta, si es posible. * @param monto – el monto de dinero a ser eliminado, un int nonegativo * @return true, si la eliminación ocurrió; false, en otro caso */

public boolean sacarMonto(int monto) { boolean result = false; if ( monto < 0 ) { JOptionPane.showMessageDialog(null, "BankCuenta error: monto malo---ignorado"); } else if ( monto > balance ) { JOptionPane.showMessageDialog(null, "BankCuenta error: monto a sacar excede balance"); } else { balance = balance - monto; result = true; } return result; }

Ingeniería en Computación, Universidad de La Seren 67

Page 68: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

/* getBalance reporta lo ocurrido en balance * @return balance */ public int getBalance() { return balance; }

// Un test de la propuesta:

public static void main(String[] args){BankCuenta tester = new BankCuenta(0); // test objeto

// tratar con el método getBalance: System.out.println("Inicial balance = " + tester.getBalance());

// tratar con deposito: boolean test1 = tester.deposit(5050); // depositamos 5050 pesos System.out.println("Deposito es " + test1 + ": " + tester.getBalance());

// tratar con sacarMonto: boolean test2 = tester.sacarMonto(3033); System.out.println("el monto a sacar es " + test2 + ": " + tester.getBalance());

// tratar una “mistake”: boolean test3 = tester.sacarMonto(6000); System.out.println("el monto a sacar es" + test3 + ": " + tester.getBalance());

}}

Ejemplo 3

public class Multiplica1

{ /* Un usuario busca saber cuanto es 72 veces 84, y chequear su respuesta. */

public static void main(String[] args)

{ ConsoleReader usuario =new ConsoleReader(System.in);

System.out.println("Cuanto es 72 veces 84?"); int resp = usuario.readInt(); if (resp == 6048) System.out.println("Exito!"); else System.out.println("Error!"); }}

Aquí se muestra la salida.Cuanto es 72 veces 84?6048Exito!

Y aquí un ejemplo para el caso de no estar en lo correcto.Cuanto es 72 veces 84?5704Error!

Ingeniería en Computación, Universidad de La Seren 68

Page 69: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

La forma general de la estructura if es,

El esquema siguiente corresponde al programa anterior usando diagramas de flujo

Ingeniería en Computación, Universidad de La Seren 69

Page 70: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

En el siguiente ejemplo, se muestra otra alternativa de uso de la estructura if,

Ejemplo 4

public class Multiplica2 { /* Un usuario busca saber cuanto es 72 veces 84, y chequear que la respuesta es 6048. */

public static void main(String[] args) { ConsoleReader usuario =new ConsoleReader(System.in); System.out.println("Cuanto es 72 veces 84?"); int resp = usuario.readInt(); if (resp == 6048) System.out.println("Exito!"); else { System.out.println ("Error. Trate otra vez."); resp = usuario.readInt(); if (resp == 6048) System.out.println

("Exito."); else System.out.println ("No. La respuesta es 6048"); } }}

Ingeniería en Computación, Universidad de La Seren 70

Page 71: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

Existe una forma corta de usar if. Por ejemplo,

if (a < b) then System.out.println(El número más pequeño es + a);

Que dice: Si a es menor que b despliega un mensaje, de otra manera NO hace nada.

if (a < b) then System.out.println(El número más pequeño es + a);else {}

Esta es una forma más general de una rama en if,

if (con una rama)

if (EXPRESION-Booleana)Declaración

Otra forma un tanto más general,

s = a;if (b < s) s = b;if (c < s) s = c;if (d < s) s = d;

Por ejemplo, si a, b, c y d tienen los valores:

a = 5, b = 10, c = 3, d = 8.

Las respuestas serán:.

1. La primera declaración almacena un 5 en s. (Ahora s contiene el 5.)2. La segunda, no hace nada pues 10 < 5 es false. (Sigue s con 5)3. La tercera almacena 3 en s, pues 3 < 5 es true. (Ahora s contiene 3.)4. La cuarta, no hace nada pues 8 < 3 es false. (Sigue s con 3.)

Note que la declaración if siempre contiene el valor más pequeño de los valores testeados, de manera que al final, s contiene el más pequeño de todos los valores. Una forma simple de if con una rama es usar la declaración return. Aquí les muestro un programa que usa el método Math.sqrt para calcular la raíz cuadrada para el usuario.

Ingeniería en Computación, Universidad de La Seren 71

Page 72: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

Ejemplo 5

public class RaizCua

{ /* Busca el usuario calcular la raíz cuadrada de un número, para ello ingresa un valor y la salida es lo que espera. */

public static void main(String[] args) { ConsoleReader in = new ConsoleReader(System.in); System.out.print("Ingrese un número: "); double x = in.readDouble(); if (x < 0) { System.out.println ("Número debe ser >= 0."); return; } System.out.println ("La raíz cuadrada es " + Math.sqrt(x)); }}

Aquí se muestra un ejemplo de la salida.

Ingrese un número: 9.2La raíz cuadrada es 3.03315017762062

Ingrese un número: -3Número debe ser >=0.

Esta es la forma común de este tipo de estructura,

return (con valor de return)

return EXPRESION;

La primera forma es usada al interior de un método que retorna un valor. Que dice: termina obedeciendo este método y retorna el valor dado por la EXPRESION. El segundo es usado al interior de un método que no retorna valor.

Escogiendo entre alternativasA menudo es necesario escoger entre 3 o más alternativas. Esto puede hacerse combinando varios if. Por ejemplo,

Si el rango de consumo de agua está entre 70 – 100 costo = ASi el rango de consumo de agua está entre 60 – 69 costo = BSi el rango de consumo de agua está entre 50 – 59 costo = CSi el rango de consumo de agua está entre 40 – 49 costo = DSi el rango de consumo de agua está entre 30 – 39 costo = ESi el rango de consumo de agua está entre 20 – 29 costo = FSi el rango de consumo de agua está entre 10 – 19 costo = GSi el rango de consumo de agua está entre 0 – 9 costo = H.

Ingeniería en Computación, Universidad de La Seren

return statement (sin valor de return)

return;

72

Page 73: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

En tal caso, basta considerar las declaraciones if (rango >= 70) costo = A;else rango estará entre 0 a 69.

if (rango >= 70) costo = A;else if (rango >= 60) costo = B;else rango estará entre 0 a 59.

Eventualmente puede tenerif (rango >= 70) costo = "A";else if (rango >= 60) costo = "B";else if (rango >= 50) costo = "C";else if (rango >= 40) costo = "D";else rango = "F";

Aquí mostramos un programa completo que convierte un rango ingresado por usuario en costos.

Ejemplo 6public class Costos{ /* Lee un valor en el rango 0 a 100, y como salida le entrega el costo. */ public static void main(String[] args) { ConsoleReader in = new ConsoleReader(System.in); System.out.print("Ingrese el rango [0-100]: "); int rango = in.readInt(); String costo; if (rango >= 70) costo = "A"; else if (rango >= 60) costo = "B"; else if (rango >= 50) costo = "C"; else if (rango >= 40) costo = "D"; else costo = "F"; System.out.println("Costo = " + costo); }}

La misma técnica puede ser usada para situaciones en las que se quiera testear una serie de situaciones una después de otra

if (B1) S1else if (B2) S2else if (B3) S3 else if (Bn) Snelse T

Ingeniería en Computación, Universidad de La Seren 73

Page 74: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

Podríamos tener un diagrama de flujo que lo representa,

Un tipo de dato bastante frecuente de usar en los códigos donde intervienen las decisiones son los tipos de datos booleanos, llamados boolean. La expresión booleana resp == 6048 puede ser evaluada para obtener uno de los valores de verdad true o false. Estos valores son llamados valores booleanos. Determinando un tipo de dato llamado boolean. Ud. puede crear variables de tipo boolean y asignarlo a una expresión Booleana, por ejemplo,

boolean ok = (x > 0);

El operador == normalmente nunca es usado para testear si 2 string son los mismos, una alternativa es utilizar el método equalsIgnoreCase()

st1.equalsIgnoreCase(st2)

que retorna true si st1 y st2 son dos string que consisten de los mismos caracteres, ya sea mayúscula o minúsculas, de otra manera será false. Como ejemplo mostramos un pequeño sistema de registro para alumnos. En este ejemplo se ha construido una clase llamada Alumno y un archivo para testear si la clase esta correcta para los datos que se le ingresan, al cabo del cual entrega una edición de los datos que Ud. ingreso pudiendo en on-line cambiar los datos que acabo de ingresar.

Ingeniería en Computación, Universidad de La Seren 74

Page 75: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

Ejemplo 7

public class Alumno { private String idNumero;

private String nombre; private String preGrado; private int anhos; private boolean estaRegistrado;

/* alumno se ha registrado. */ public void registro() { estaRegistrado = true; } /* alumno NO se ha registrado. */ public void desregistro() { estaRegistrado = false; } /* Return true si el alumno se ha registrado, sino

return false. */ public boolean tieneRegistro() { return estaRegistrado; }

/* Editar los detalles del alumno. */ public void edit(ConsoleReader input) { System.out.print("ID numero (" + idNumero +") " ); String replica = input.readLine(); if (! replica.equals("")) idNumero = replica;

System.out.print("Nombre (" + nombre + ") "); replica = input.readLine(); if (! replica.equals("")) nombre = replica;

System.out.print("Programa de pregrado (" + preGrado + ") "); replica = input.readLine(); if (! replica.equals("")) if (replica.equals("Ing. Civil") || replica.equals("Ing. Alimentos") || replica.equals("Ing. Computacion") || replica.equals("Ped. Matematicas")) preGrado = replica; else System.out.println("programa de pregrado desconocido."); System.out.print("Años (" + anhos + ") "); replica = input.readLine(); if (! replica.equals("")) anhos = Integer.parseInt(replica);

if (estaRegistrado) System.out.print("Esta registrado (si) "); else System.out.print("Esta registrado (no) "); replica = input.readLine(); if (! replica.equals("")) if (replica.equals("si")) estaRegistrado = true;

Ingeniería en Computación, Universidad de La Seren 75

Page 76: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

else if (replica.equals("no")) estaRegistrado = false; else System.out.println("Replica no entendida."); }

//los datos de pregrado, años y nombre no son cambiados.

/* Crea un nuevo alumno con el ID numero dado, nombre y pregrado. Los años son seteados a 1. Serán registrado como no registrados.

*/

public Alumno(String id, String nm, String preG) { idNumero = id; nombre = nm; preGrado = preG; anhos = 1; estaRegistrado = false; }}//end class Alumno

Observar que Test Alumno es una nueva clase pública la cual invoca a Alumno y ConsoleReader. TestAlumno esta guardado en archivo con nombre TestAlumno.java, independiente de la clase Alumno. Pero si en el mismo directorio donde se reconocen.

public class TestAlumno { /* Lee detalles de los alumnos. Crea el correspondiente objeto Alumno, y edita los detalles del objeto. */

public static void main(String[] args) { /* Crea ConsoleReader para leer el tipo de usuario. */

ConsoleReader in = new ConsoleReader(System.in);

/* Crea el Alumno. */ System.out.println ("Cuál es el número ID del alumno(a)?"); String i = in.readLine(); System.out.println ("Cuál es el nombre del alumno(a)?"); String n = in.readLine(); System.out.println ("Pregrado al que pertenece el alumno(a)?"); String d = in.readLine(); Alumno st = new Alumno(i,n,d); System.out.println(); System.out.println("Editar los detalles del alumno."); st.edit(in); System.out.println(); }}

Aquí se ve la salida posible al programa anterior, llamado Test Alumno.java con la clase Alumno en el archivo Alumno.java, además de la clase ConsoleReader.java

Ingeniería en Computación, Universidad de La Seren 76

Page 77: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

Cuál es el número ID del alumno(a)?9912345Cuál es el nombre del alumno(a)?Alicia LobosPregrado al que pertenece el alumno(a)?Ing. Computacion

Editar los detalle del alumno.ID numero (9912345) 9912346Nombre (Alicia Lobos)Programa de pregrado(Ing. Computacion) Años (1) 2Esta registrado(no) Si

Algunas expresiones booleanas son:

= = igual!= no igual< menor que<= menor o igual a> mayor que>= mayor o igual a

Justamente algunas expresiones aritméticas pueden ser construídas de una forma muy simple usando operadores aritméticos, tales como, +, , , etc. Si B1 y B2 son expresiones Booleanas.

operador hace

B1 && B2 B1 and B2B1 || B2 B1 or B2! B1 not B1

Expresiones cuyo resultado están basado en la lógica Boolena, por ejemplo, B1 && B2 es true si B1 y B2 son ambos true, de otra manera es false. Cuando Java evalúa B1 && B2, evaluara primero B1. Si B1 es false no evaluara B2, pues esta “condenado” a ser false. Un análisis similar se hace con los otros conectivos. La expresión ! B1 será true si B1 es false, y será false si B1 es true.

Una expresión de este tipo,

n >= 0 && n< 10 || n >= 20 && n < 30

Java lo interpreta así,

((n>=0) && (n<20)) || ((n>=20) && (n<30))

Una de las tareas más comunes para cuando compara string, es salir en forma elegante de un menú, por ejemplo tipeando “quit”, para tal efecto se usa que un valor boolean es o no equals.

Ingeniería en Computación, Universidad de La Seren 77

Page 78: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

Ejemplo 8

public class ComoEstas

{ /* Busca el usuario hacer un comentario. */

public static void main(String[] args) { ConsoleReader in = new ConsoleReader(System.in); System.out.println (Hola usuario. Como estas?"); String replica = in.readLine(); if (replica.equals("A la Pinta")) System.out.println ("Yo también."); else if (replica.equals("Para bajo")) System.out.println("Cuanto lo lamento."); }}

Ciclos

Esta sección trata de un problema común en programación y se refiere a la construcción de loops o ciclos. Ud. conoce que declaración usar para la acción de repetir cada vez, lo mismo de la expresión booleana a usar para testear si el loop a finalizado su tarea. Pero desafortunadamente para llevar a cabo este tipo de test, es ya sea al comienzo de la acción, de donde Ud. usa la declaración while, si ocurre al final usa la declaración do-while. Pero que usar cuando desea testear lo que esta ocurriendo a mitad de camino?

Existen varias formas de solucionar esto, un ejemplo típico es que el usuario ingrese un número x, si x 0, despliegue la raíz cuadrada de x. Si el usuario ingresa un número negativo obtendrá una señal de término del programa,

Repeat{ Lea el siguiente valor de la entrada y almacenelo en x; Si x es negativo termina; Salida, la raíz cuadrada de x;}

Aquí les muestro 3-versiones

Versión 1Lea x la primera vez antes de partir el loop. Entonces la declaración while testea, si x0, y si es así, la salida será la raíz cuadrada de x, y entonces leera el siguiente valor de x. Es decir,

Lea el siguiente valor de entradaY almacenelo en x;while (x>=0){ Salida, la raíz cuadrada de x; lea el siguiente valor de la entrada y almacenelo en x;

Ingeniería en Computación, Universidad de La Seren 78

Page 79: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

}

Versión 2Esta versión usa break. Un break dice a Java: termine el loop que Ud. esta realizando en el acto. En esta version, es un break que causa el termino del loop, y no la expresión Booleana al comienzo del while. La expresión Boolean al comienzo del while es la constante true. De seguro que cuando Java evalúa esto, siempre obtendrá el resultado true. Así este ciclo nunca concluye, pero junto con un break podemos generar códigos que terminen la ejecución del programa.

while (true){ Lea el siguiente valor de entrada y almacenelo en x. if (x<0) break. Salida, la raíz cuadrada de x.}

break puede ser usado para terminar cualquier tipo de ciclo incluyendo do-while y for. Si un break esta en el interior de un ciclo que es a su vez parte de un ciclo entonces el interprete terminara la declaración más interna.

Versión 3La tercera versión es usar while junto con una declaración Booleana. La variable esta seteada a false al comienzo, y cuando llega el momento de salir del loop “switched” a true. Al testear el comienzo del while detecta que la variable es ahora true, causando el término del loop.

boolean done = false;while (! done){ lea el siguiente valor de entrada y almacenelo en x. if (x>=0) Salida, la raíz cuadrada de x; else done = true;}

Personalmente prefiero versión 2, otras personas consideran break ser peligroso, aparentemente porque confunde su aplicación. En todo caso, Ud. decide cual utilizar para trabajar con ciclos. Aquí esta el programa completo de la raíz cuadrada usando break.

Ejemplo 9

public class RaizCuaLoop

{ /* Lee número punto flotante ingresado por el usuario y entrega la raíz cuadrada. Terminando si el usuario ingresa un valor <0. */

public static void main(String[] args) { ConsoleReader in = new ConsoleReader(System.in); System.out.println("Programa de Calculo de la Raiz Cuadrada.\n" + "(Ingrese valor<0 para terminar.)");

Ingeniería en Computación, Universidad de La Seren 79

Page 80: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

while (true) { System.out.print("Ingrese el número: "); double x = in.readDouble(); if (x<0) break; System.out.println ("Raiz Cuadrada = " + Math.sqrt(x)); } System.out.println("Chao"); }}

Note que usamos un valor negativo para controlar el programa, valores de este tipo se llaman sentinelas. Otra forma es usar un mensaje de ‘quit’. En tal caso Ud. ingresa esta palabra para terminar el programa, sino convertirá el valor ingresado a double y continua procesando los datos.

while (true){ System.out.print("Ingrese el número: "); String replica = in.readLine(); if (replica.equalsIgnoreCase(quit)) break; double x = Double.parseDouble(replica); System.out.println ("Raiz Cuadrada = " + Math.sqrt(x));}

for A menudo los loop son usados para generar una serie de valores, cada uno de los cuales esta almacenado en una variable. Por ejemplo, supongamos que queremos desplegar una tabla de valores de cos(x) para los valores x: 0, 5, 10, 15, 85, 90. Tal código sería,

double x = 0;while (x <= 90){ Display el valor de x y cos(x). x = x+5;}

Un loop de esta forma puede expresarse como for , que tiene la forma,

for (Primero; Continua; Siguiente) Declaracion

Por ejemplo,

for (double x = 0; x <= 90; x = x + 5) System.out.println(\t + x + \t + Math.cos(x));

(El valor de cos(x) esta desplegado con 16 decimales). Cuando tengamos un loop del tipo while, tal como,

int i = 0;while (i < n){ Declaración i++;

Ingeniería en Computación, Universidad de La Seren 80

Page 81: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

}

Ingeniería en Computación, Universidad de La Seren 81

Page 82: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

Alternativamente podremos convertirlo en for como sigue.for (int i = 0; i < n; i = i+1) Declaración

Para dejar el termino como una constante, podemos usar una constante llamada cuanTos

for (int i = 0; i < cuanTos; i++) Escoger un circulo y un color al azar Y pinte el circulo con el color.

APLICACIONESEn este segmento he escogido estas tres aplicaciones con la intención de usar de mejor manera las estructuras de control en beneficio de obtener un programa amigable.

a) Argumentos en la línea de comando.Muchas veces, cuando invocamos a un programa desde el sistema operativo, necesitamos escribir uno o más argumentos a continuación del nombre del programa, separados por un espacio en blanco. Por ejemplo, ls -l del sistema operativo UNIX o en dir /p del sistema operativo MS-DOS. Tanto ls como dir son programas; -l y /p son opciones o argumentos en la línea de órdenes que pasamos al programa para que tenga un comportamiento diferente al que tiene de forma predeterminada; es decir, para cuando no se pasan argumentos. De la misma forma, podemos construir aplicaciones Java que admitan argumentos a través de la línea de comando. ¿Qué método recibirá esos argumentos? El método main, ya que este método es el punto de entrada a la aplicación y también el punto de salida.

public static void main(String[] args) // Cuerpo del método

Como se puede observar, el método main tiene un argumento args que en lo formal es una matriz unidimensional de tipo String. Para ejecutarlo con parámetros deberá ir a INICIO-programas-accesorios-simbolo del sistema, aunque algunos IDE’s traen incorporado esta alternativa. Si Ud. lo hubiese ejecutado de la misma forma que antes, le debería salir un mensaje, como el siguiente.

Ejemplo 10

import java.text.*;/** CelsiusAFahrenheit convierte input Celsius a Fahrenheit. * input: Cº Celsius, un integer * output: Fº Fahrenheit, un double */public class CelsiusAFahrenheit{ public static void main(String[] args) { int c = new Integer(args[0]).intValue();//args[0] argumento del programa double f = ((9.0/5.0) * c) + 32;

Ingeniería en Computación, Universidad de La Seren 82

Page 83: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

System.out.println("para Cº Celsius " + c + ","); DecimalFormat format = new DecimalFormat("0.0"); System.out.println("Fº Fahrenheit = " + format.format(f)); }}

En general, el nombre args puede ser cualquier otro. Esta matriz almacenará los argumentos pasados en la línea de comando cuando se invoque a la aplicación para su ejecución de la forma que se observa a continuación. Observe que cada argumento está separado por un espacio.

>java MiAplicacion argumento1 argumento2 ...

Cada elemento de la matriz args referencia a un argumento, de manera que args[0] contiene el primer argumento de la línea de comando, args[1] es el segundo, y así sucesivamente. Por ejemplo, supongamos que tenemos una aplicación Java denominada Test.java que acepta los argumentos -n y -l. Entonces, podríamos invocar a esta aplicación escribiendo en la línea de comando del sistema operativo el siguiente comando:

>java Test -n -l

Esto hace que automáticamente la matriz args de objetos String se cree para contener dos objetos String: uno con el primer argumento y otro con el segundo. Para clarificar lo expuesto vamos a mostrar una aplicación a través de un ejemplo que simplemente visualiza los valores de los argumentos que se la han pasado en la línea de comando. Esto nos dará una idea de cómo acceder desde un programa a esos argumentos. Supongamos que la aplicación se denomina Test y que sólo admite argumentos -n, -k y -l. Esto quiere decir que podremos especificar de cero a tres argumentos. Los argumentos repetidos y no válidos se desecharán. Por ejemplo, la siguiente línea invoca a la aplicación Test pasándole los argumentos –n y -l:

>java Test -n -l

Ingeniería en Computación, Universidad de La Seren 83

Page 84: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

El código completo de la aplicación propuesta, se muestra a continuación.

Ejemplo 11

public class Test{ public static void main(String[] args) { // Código común a todos los casos System.out.println("Argumentos: "); if (args.length == 0) { // Escriba aquí el código que sólo se debe ejecutar cuando // no se pasan argumentos System.out.println(" ninguno"); } else { boolean argumento_k = false, argumento_l = false, argumento_n = false; // ¿Qué argumentos se han pasado? for (int i = 0; i < args.length; i++) { if (args[i].compareTo("-k") == 0) argumento_k = true; if (args[i].compareTo("-l") == 0) argumento_l = true; if (args[i].compareTo("-n") == 0) argumento_n = true; } if (argumento_k) // si se pasó el argumento -k: { // Escriba aquí el código que sólo se debe ejecutar cuando // se pasa el argumento -k System.out.println(" -k"); } if (argumento_l) // si se pasó el argumento -l: { // Escriba aquí el código que sólo se debe ejecutar cuando // se pasa el argumento -l System.out.println(" -l"); } if (argumento_n) // si se pasó el argumento -n: { // Escriba aquí el código que sólo se debe ejecutar cuando // se pasa el argumento -n System.out.println(" -n"); } } // Código común a todos los casos }}Al ejecutar el comando >java Test -n -l , se obtendrá el siguiente resultado. Notar el orden de salida de los datosArgumentos:-l-n

b) Relación con el usuario.

En lo fundamental se refiere a los ciclos anidados. Este es un programa que pregunta por las tablas de multiplicar, me da una ayuda y acertando (o errando) me pregunta, si me quiero ir o no, con un mensaje de consola. La idea ahora es usar ciclos anidados para evitar de enviarme afuera hasta mientras no dé con el resultado correcto!!, de ser así me pregunta si quiero seguir practicando las tablas de multiplicar, ahora si ingreso me rindo me entregara el resultado

Ingeniería en Computación, Universidad de La Seren 84

Page 85: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

correcto, y me volverá a preguntar si deseo seguir practicando. Generando con ello un programa amigable para un usuario eventualmente inexperto.

Ejemplo 12

import java.util.*;

public class Multiplicar

{ /* Test para las tablas de multiplicar.*/ public static void main(String[] args) { ConsoleReader in = new ConsoleReader(System.in); Random rand = new Random();

System.out.println("Practicando las Tablas."); String replica; do { /* Escoger 2 numeros entre 1 y 12. */ int a = rand.nextInt(12) + 1; int b = rand.nextInt(12) + 1;

/* Test para el usuario si sabe las tablas. */ System.out.println ("Cuanto es " + a + " multiplicado por " + b + "?"); int respuesta = in.readInt(); if (respuesta == a*b) System.out.println("Bien!"); else System.out.println

("No. La respuesta es a*b");

/* Chequea si el usuario quiere seguir. */ System.out.println ("Quiere seguir practicando (si/no)?"); replica = in.readLine(); } while (replica.equals("si"));

System.out.println("Chao"); }}

Lo siguiente es lo que aparece cuando el programa esta corriendo.

Practicando las Tablas.Cuanto es 11 multiplicado por 8?9No. La respuesta es a*bQuiere seguir practicando (si/no)?siCuanto es 5 multiplicado por 4?20Bien!Quiere seguir practicando (si/no)?noChao

Ingeniería en Computación, Universidad de La Seren 85

Page 86: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

c) Recursividad

Existen procesos que se llaman a sí mismo, tales procesos o métodos son llamados métodos recursivos, muy útiles y fácil de programar en contraste con los métodos iterativos. Por eso que los métodos recursivos son muy aplicados en la programación y Ud. podría seguirse familiarizandose con esto. Consideremos el siguiente programa. “Lea dos enteros de la entrada de usuario y luego despliege el valor del primero elevado al segundo.” El valor es power(n,p). Note que power es un método recursivo.Ejemplo 13

public class PotenProg

{ /* Lee 2 integers, x e y, donde y>=0. Output es el valor de x elevado a y. */

public static void main(String[] args) { ConsoleReader in = new ConsoleReader(System.in);

System.out.print ("Ingrese el primer entero: "); int i1 = in.readInt(); System.out.print ("Ingrese el segundo entero(>0): "); int i2 = in.readInt(); System.out.println (i1 + " elevado a " + i2 + " = " + power(i1,i2)); }

/* Si p>=0, return n elevado a p. */ private static int power(int n, int p) { if (p == 0) return 1; else return power(n,p-1)*n; }}

Lo que realiza este programa es lo siguiente, así se visualiza su interacción con el usuario.

Ingrese el primer entero: 3Ingrese el segundo entero(>0): 5

3 elevado a 5 = 243

Suponga ahora que el programa está siendo ejecutado y la entrada por usuario es 2 y 4. Luego el método main es llamado, el usuario ingresa los dos valores, luego Java llamará a power(2,4) para encontrar la solución y respuesta, notar que la función está definida como método. En la primera llamada al método power el parámetro valor es n = 2 y p = 4. En este caso la segunda declaración return en el cuerpo del método será realizada, esto significa que Java evaluará la expresión power(n,p-1)*n, y entonces power(2,3) será evaluado. Se tiene, power(2,4)→ power(2,3). La siguiente vez que power es llamado pasa lo mismo, esta vez power(2,2) será llamada y el diagrama queda, power(2,4) → power(2,3) → power(2,2).

Ingeniería en Computación, Universidad de La Seren 86

Page 87: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

Similarmente cuando power(2,2) es realizada llamará a power(2,1). Y cuando power(2,1) se realice, llamara a power(2,0). power(2,4) → power(2,3) →

power(2,2) → power(2,1) → power(2,0). Aquí la cadena se detiene pues power(2,0) es realizado y va al primer return y se ejecuta. Así, power(2,0) retorna el valor 1, el que será usado en la ejecución de power(2,1), entregando el valor 12, que es 2, el que será usado en la ejecución de power(2,2), entregando el valor 4, y así sucesivamente. En general, podemos ver que si power(n,p) es realizada, con p0, la cadena completa contendrá p+1 llamadas a power, siendo la última llamada la que entrega 1. Todos los otros entregan n – veces el valor retornado por el siguiente. Las llamadas a power(n,p) entregan np. Vea el diagrama

No digo que este proceso sea rápido, pero si es sencilla su implementación para calcular np.Si p < 0 la cadena seguirá por siempre. Luego un código para calcular np, donde p 0, deberá tener probablemente algo parecido a esto.

int resp = 1;for (int i = 0; i < p; i++) resp = resp * n;

En general, cualquier método recursivo puede ser escrito usando código no-recursivo. Otro ejemplo típico es el factorial de un número entero.

Ejemplo 14

public class FactorialTest{ // Cálculo del factorial de un número public static long factorial(int n) { if (n == 0) return 1; else return n * factorial(n-1); }

public static void main(String[] args) { ConsoleReader in = new ConsoleReader(System.in); int numero; long fac; do

Ingeniería en Computación, Universidad de La Seren 87

Page 88: Libro Java

Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control

{ System.out.print("Ingrese el Número:"); numero = in.readInt(); } while (numero < 0 || numero > 25); fac = factorial(numero); System.out.println("\nEl factorial de " + numero + " es: " + fac); }}

Ingeniería en Computación, Universidad de La Seren 88

Page 89: Libro Java

C A P I T U L O 5

Excepciones y Flujo de Datos (Exceptions y Streams)

Mensajes de error enviados por el compilador.Los humanos podemos tolerar errores ortográficos y gramaticales, pero los computadores no, y por esta razón el compilador Java cumple con su labor de denunciar este tipo de errores, identificando la línea y dando una corta explicación. Por ejemplo, aquí tenemos un programa que tiene varios errores.

public class test{ public static main(String[] args) { System.out.println(Hello!)}

Almacenemos el programa en Test.java y compilemoslo. El compilador replica, con varios errores de mensaje, el primero de ellos es

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\test.java:2: invalid method declaration; return type required{ public static main(String[] args) ^

a) Estableciendo que existe un error en la línea 2 del programa y que se ubica aproximadamente en la posición marcada con ^. No nos dice exactamente cual es el problema, pero si nos invita a reflexionar respecto de la sintaxis de un programa. En este caso particular hemos olvidado la palabra clave void.

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\test.java:3: ')' expected { System.out.println(Hola!) ^

b) Luego el compilador reporta otro error en la línea 3 del programa y que se ubica aproximadamente en la posición marcada con ^. Lo que nos ayuda a ver con mayor preocupación que pasa en ese segmento de programa, y notamos que al escribir la palabra. Hola!, hemos olvidado escribirlo entre comillas.

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\test.java:4: ';' expected}^

c) El compilador reporta otro error en la línea 4 del programa y que se ubica aproximadamente en la posición marcada con ^. Y notamos que nos falto cerrar una declaración con ;

Page 90: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\test.java:5: '}' expected^4 errors

Herramienta completada con código de salida 1

d) El compilador reporta otro error en la línea 5 del programa y que se ubica aproximadamente en la posición marcada con ^. Y notamos que nos falto cerrar un paréntesis, con un semicolon }

Desafortunadamente, el compilador no es perfecto en detectar todos los errors gramaticales en una primera leída, es así como se require compilarlos e ir modificando el código del programa, hasta que quede libre de errores, no obstante el compilador no podrá hacer nada frente a un error semántico. Para completar este segmento digamos que este es un típico error para cuando una clase está carente de una clase principal para ser testeada.

Para mayor consulta dirigirse a The Java Language Specification, de J. Gosling, B. Joy, y G. Steele, Addison Wesley Publishing, 1996, para la definición del lenguaje Java.

Diagnostico de los errores en Expresiones y Variables

Expresiones y variables le dan a un programa más potencia, pero al mismo tiempo ofrecen la oportunidad de generar más errores. Los errores en este sentido pueden ser de dos formas:

Errores relacionados con la gramática, contexto (tipo de datos), que el compilador Java puede detectar, son llamados: errores en tiempo de compilación.

Errores que ocurren para cuando el programa es ejecutado, deteniendose su ejecución en forma temprana, son llamados errores en tiempo de ejecución o excepciones.

Si consideramos el programa public class Test1{public static void main(String[] args) {

System.out.println( (1+2(*3 );//que desea? System.out.println(Hola!); }}

a) vemos que el compilador notifica y anuncia:

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\Test1.java:3: ')' expected

System.out.println( (1+2(*3 ); ^

b) Si consideramos ahora el programa, detecta un problema en la definición del tipo de dato.public class Test1{

public static void main(String[] args) {

Ingeniería en Computación, Universidad de La Seren 90

Page 91: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

string s;//basta con saber que el tipo de dato es String }}

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\Test1.java:4: cannot resolve symbolsymbol : class string location: class Test1 string s; ^

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\Test1.java:3: operator + cannot be applied to int,boolean

System.out.println(3 + true); ^

la explicación del compilador es elocuente, es decir enteros con boolenos no se entienden.

public class test {public static void main(String[] args) {

int i=0; System.out.println(1/i);

System.out.println("Hola!"); }

}

tras el proceso natural de compilación podrá ver que el compilador no anuncia ningún tipo de problemas. Sin embargo, en la ejecución dice lo que se muestra.

este es un típico error en tiempo de ejecución, o también llamado una exception. Esto surgió cuando un programa usa tipos de datos incorrectos como argumentos del programa. No obstante si declara double i=0; en la ejecución saldrá

c) Otro ejemplo, surge para cuando se desea ejecutar un programa Java pero con varios parámetros desde la consola.

public class test {public static void main(String[] args) {

int i = new Integer(args[0]).intValue(); System.out.println(1 / i); System.out.println("Hola!"); }

}

Ingeniería en Computación, Universidad de La Seren 91

Page 92: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

El mensaje de error fue gatillado por la línea 3, y fue generado por la creación de un objeto Integer en la línea, siendo que la entrada de datos es un carácter, en este caso “a”.

Finalmente, mostremos algunos errores que no son detectados ni por el compilador de Java, ni por su intérprete. Por ejemplo, se imprimen las variables x e y que son la misma. La declaración pasa la inspección del compilador Java, ahora realiza su ejecución y si Ud. espera ver ya sea un true o un false verá que surge un resultado, 7.

public class test {public static void main(String[] args) {

int x = 3; int y = 7; System.out.println(x = y);

System.out.println("Hola!"); }

}

Ingeniería en Computación, Universidad de La Seren 92

Page 93: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

La razón es que x = y es una asignación y no un test para igualdad, como (x = = y). La declaración, System.out.println(x = y), asigna y's valor a x's y lo imprime.

Luego de haber visto esta serie de errores podrá formarse una idea, de lo que se trata este capítulo y que se refiere a complementar y reforzar el uso de excepciones, en donde Java posee una forma de tratar los errores en tiempo de ejecución. Además veremos como leer desde el teclado sin usar la clase que se le ha pedido “prestada” a Horstmann’s llamada ConsoleReader, y como leer y escribir archivos de texto, además de como hacer uso de los parámetros que todo método main posee.

ExcepcionesJava tiene un especial mecanismo para tratar errores en tiempo de ejecución. Suponga que escribe algún código que puede tener errores cuando lo ejecuta. Por ejemplo, si una cierta variable se refiriese a un objeto, y un error ocurre si la variable contiene null. Entonces puede Ud. insertar una declaración que arroja una excepción (throws and exception) si la condición de error ocurre. Veamos 2 situaciones.

1. Crear un objeto que describe la condición de error, usualmente llamada un objeto exception. (Ella pertenece a la clase Throwable, y estará ya sea en la subclase Error, si es un serio error del sistema, o en la subclase Exception, si ocurrió el error en el tiempo de ejecución normal.)

2. Esto causa que el interprete se detenga en la secuencia de declaraciones en donde ocurrió el error y comience a buscar una clausuala catch que ha sido escrita para responder al error apropiadamente, es decir, desplegando un window que le informa al usuario que hacer en lo sucesivo. (Como buscar la clausula catch se describirá posteriormente.) Si el interprete no puede encontrar una clausula disponible catch, el programa se detiene y Java desplegara un mensaje de error por defecto en la ventana DOS. Esto origina el nombre de excepciones y una lista de todos los métodos que están siendo ejecutados actualmente.

Las excepciones son a menudo atrapadas o arrojadas por el mismo Java, ya sea por uno de los métodos de librería, o por un interprete, es decir, cuando encuentra algo el mismo trata de accesar a un array de elementos con un valor del indice fuera del rango correcto de valores. En este caso, la excepcion será una IndexOutOfBoundsException.

Una cláusula catch es parte de una declaración try-catch y tiene la forma siguiente.

try{ Declaraciones catch (EXCEPCION1 e1) { Declaraciones}catch (EXCEPCION2 e2){ Declaraciones

finally { Declaraciones}

Ingeniería en Computación, Universidad de La Seren 93

Page 94: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

La última parte finally clausula es por lo general omitida. Cuando el interprete obedece la declaración try-catch, ella ejecuta la DECLARACION try normalmente. Si ninguna excepcion es arrojada, eso es todo cuanto la declaración try-catch hace. Si una excepcion es arrojada, el interprete partira buscando para una try-clausula que sea obedecida para cuando la excepcion fue arrojada.

Por supuesto la declaración try en la declaración try-catch fue obedecida, pero puede haber otra declaración try-catch más cerca de donde ocurrió el error. El intérprete entonces buscará el más interno, llamaremos a la declaración que produjo el error S0. Primero el intérprete mira dentro del cuerpo del método que contiene S0. Si encuentra que S0 está dentro de una try, toma una. Si hay dos o más declaraciones try anidadas que contienen a S0, toma la más interna. Si S0 no está al interior de una try, el intérprete va a la declaración S1 que llamó el método que contiene S0. Entonces empieza buscando la catch más interna que contiene S1. Si no puede encontrar uno en ese cuerpo del método, va a la declaración S2 llamando el método que contiene S1. Y así sucesivamente. Aquí se muestra un programa que contiene una declaración try-catch. El programa lee una serie de valores de punto flotante ingresados por el usuario, y se detiene cuando lee la palabra ‘fin’. Suma los números y al mismo tiempo cuenta cuantos números son, finalmente, divide la suma de los número por el contador generando así el promedio de los números ingresados, el cual es desplegado en pantalla.

El programa chequea si ve en la línea la palabra ‘fin’. La línea es leída usando readLine. Si ella no tiene ‘fin’, el programa procura convertirla en número usando el metodo Double.parseDouble. Si por error de tipeado, el usuario tipea algo que no es un número o la palabra ‘fin’, entonces una NumberFormatException será lanzada. Si no es capturado el programa despliega un mensaje de error por defecto y para.

Una declaración try-catch ha sido insertada en esta versión del programa para capturar las excepciones, y así evitar el mensaje de error. La clausula try incluye la llamada a Double.parseDouble, y la acción que continua para cuando el número esta correcto. La clausula catch justamente despliega un simple error de mensaje, y entonces el programa esta habilitado para realizar su tarea.

Ejemplo 1

public class Promedio1 { /* Lee números flotante ingresados por el

usuario y entrega el promedio. (Version que usa ConsoleReader.)

*/ public static void main(String[] args) {

ConsoleReader usuario = new ConsoleReader(System.in);

/* Lee y agrega los valores, y cuenta cuantos son. */ double sum = 0; int cuanTos = 0; System.out.println("Ingrese los datos."); while (true) { String linea = usuario.readLine();

Ingeniería en Computación, Universidad de La Seren 94

Page 95: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

if (linea.equals("fin")) break; try/* protección de código, que podría lanzar una excepción dentro de try, pues este segmento de código podría causar una excepción, si no existen problemas continue, sino*/

{ double siguiente = Double.parseDouble(linea); sum = sum + siguiente; cuanTos++; } catch (NumberFormatException e)

/* Atrape la excepción, haciendo una prueba para manejar una excepción dentro de catch*/

{ System.out.println ("Ingreso NO reconocido, intentelo de nuevo!."); } } /* el promedio. */ if (cuanTos > 0) System.out.println ("El valor promedio es = " + sum/cuanTos); else System.out.println("Sin resultado."); }}

También como excepciones producidas por Java, puede forzar una excepcion para ser arrojada mediante la declaración throw . Esta clausula indica que algún código en el cuerpo de su método podría lanzar una excepción, para tal efecto simplemente agregar la palabra throw después del nombre del método pero antes de abrir el bloque. Por ejemplo,

public boolean miMetodo(int x, int y) trows AnException {

o más simple seguida por la referencia a un objeto excepcion. Por ejemplo,

throw new NumberFormatException();

Note que un constructor es usado para crear el objeto exception aquí. Existen muchos tipos de excepciones definidas en la librería. Para encontrarlas todas vea la clase Exception y sus subclases. También, puede Ud. definir sus propias clases exccepcion extendiendo la clase Exception.

Leer desde el teclado

Cuando un programa Java lee la entrada, usa un objeto de algún tipo para manejar la entrada. El objeto será conectado a la fuente de la entrada, es decir la entrada fuente, me refiero a el teclado o archivo de texto. En términos de leer valores de entrada desde la fuente usamos métodos pertenecientes a ese objeto. El objeto ConsoleReader el cual hemos usado durante el curso para leer desde el teclado es un típico ejemplo de un objeto que maneja la entrada.

Ingeniería en Computación, Universidad de La Seren 95

Page 96: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

El objeto que maneja la entrada será llamada InputStream o un Reader. La diferencia depende sobre que valores produce para cuando lea los caracteres. Un InputStream returns un 8-bit byte cada vez que lea un carácter, que es como el sistema lo representa. Un Reader returns 16-bit caracteres. Esta es la forma estandar que Java representa caracteres, usando caracteres de código llamados unicode.

Cada vez que se crea un objeto ConsoleReader, hacemos uso de otro objeto llamado System.in. Esto es un InputStream conectado directamente al teclado. InputStreams tiene varios métodos asociados con ellos, pero solamente uno puede ser usado para leer la entrada que es read que lee 8-bit byte. El siguiente diagrama representa el objeto System.in conectado al teclado, con la información que fluye del teclado,

keyboard

System.in

Java posee clases llamadas InputStreamReader que consiste de objetos que producen los caracteres 16-bit unicode usados por Java. Existe un constructor que puede convertir un InputStream en un InputStreamReader. Ud. deberá darle InputStream como parametro, y el creara el InputStreamReader. Por ejemplo, la declaración siguiente construira una InputStreamReader conectado a System.in.

InputStreamReader lector = new InputStreamReader(System.in);

Ud. puede incluir un segundo parámetro para especificar un decodificador noestandar para devolver bytes en caracteres unicode. Sin el segundo parametro, el InputStreamReader usará un decodificador estandar, el cual es satisfactorio para usos o propósitos normales. Lo mismo es posible para la salida. Aquí esta el diagrama de InputStreamReader definido anteriormente. Se obtiene 8-bit bytes desde el teclado, usando System.in, convirtiéndolos en caracteres de 16-bit.

teclado

System.in

InputStreamReader

Un InputStreamReader tiene un método read que entrega un carácter simple. Esto sería posible de usarse para cuando escriba métodos que usan números reales, líneas de texto, etc. Sin embargo, un conveniente punto de partida es un objeto, el cual puede leer una linea de caracteres ala vez. Existen 2 tipos de objetos que pueden hacer uso de ellos. Uno es llamado BufferedReader y el otro es LineNumberReader. Ambos tienen un método readLine que retorna la siguiente línea de entrada. Ud, puede convertir un InputStreamReader en BufferedReader. Usualmente se hace mediante constructores. Por ejemplo,

BufferedReader usuario = new BufferedReader (new InputStreamReader(System.in));

Ingeniería en Computación, Universidad de La Seren 96

Page 97: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

La declaración se vé como sigue,

teclado

System.in

InputStreamReader

BufferedReader

Ejemplo 2Un programa que pregunta por la dimensión del cuadrado y entrega lo solicitado. Si le ingresa el valor 5, vera la figura:

***** * * * * * * *****

import java.io.*; public class Ejerc5{ public static void main(String args[]) throws IOException { int tam; BufferedReader din; din = new BufferedReader( new InputStreamReader(System.in)); System.out.println("Cuadrado"); System.out.println("========"); while (true) { System.out.print("Largo del lado [1-20,0=Fin]: "); tam = Integer.parseInt(din.readLine()); if (tam < 1) { break; } else if (tam <= 20) { for (int i = 1; i <= tam; ++i) { for (int j = 1; j <= tam; ++j) { if (j == 1 || j == tam || i == 1 || i == tam){ System.out.print("*"); } else { System.out.print(" "); } } System.out.println(); } } } } }

Ingeniería en Computación, Universidad de La Seren 97

Page 98: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

Ejemplo 3

El programa CambioMoneda, calcula el cambio para un monto de dolares-y –cents, todo ello ingresado por teclado.

import java.io.*;/** CambioMoneda calcula el cambio para un monto de dolares-y -cents. * input: un monto en dolares y un monto en cents. Ambos enteros. * output: el listado de las monedas necesarias. */public class CambioMoneda{ public static void main(String[] args) throws IOException { BufferedReader teclado = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Tabla de Montos"); System.out.println("==============="); System.out.print("Ingrese monto de dolares: "); String dolares = teclado.readLine(); System.out.print("Ingrese monto de cets: "); String cents = teclado.readLine(); int monedas = (100 * new Integer(dolares).intValue()) + new Integer(cents).intValue(); System.out.println( "quarters = " + (monedas/25) ); monedas = monedas % 25; System.out.println( "dimes = " + (monedas/10) ); monedas = monedas % 10; System.out.println( "nickels = " + (monedas/5) ); monedas = monedas % 5; System.out.println( "pennies = " + monedas ); }

}

Como leer archivos de texto

Existen 2 formatos de archivo:

character file, que es una secuencia de simbolos del teclado, almacenados en un archivo como una secuencia de bytes;

binary file, que es una secuencia de unos y ceros.

Un texto depositado en un archivo podrá tener diferentes formatos, por ejemplo.Hola!Cómo estas tú?49

ó como una secuencia Hola!\nCómo estas tú?\n 49\n

Ingeniería en Computación, Universidad de La Seren 98

Page 99: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

Por otra parte un archive binario es una secuencia de unos y ceros, de manera que 49 es expresado como, 11001, y no como la representación '4' y '9').

Cuando obtenemos información de entrada desde un archivo, se dice que read desde el archivo; para cuando depositamos una información de salida en un archivo, decimos write en él. Cuando comenzamos a usar un archivo, decimos que se open , y cuando terminamos de usarlo, lo close. Los archivos pueden ser read/written en dos sentidos:

sequential file pueden ser read (o written) desde front to back; es decir es un libro que tiene una sola dirección de lectura, pudiendo regresar en una sola dirección, (forwards).

random access file pueden ser reads (o writes) sobre cualquier lugar, es como si en un libro pudiese abrirlo en cualquier página.

Sequential files son simples para manejar y trabajar aplicaciones estandares, mientras que los Random access files son usados principalmente para aplicaciones de database donde se especifican bits de información. En este segmento se verán solamente sequential files. Para programas Java que usan sequential file, se debe establecer si el archio usado es usado para

input: el file es read sequentially y no puede ser written.

output: el file esta written sequentially y no puede ser read.

La clase BufferedReader lee un flujo de entrada de caracteres y los guarda en un array llamado buffer. Para crear una versión en buffer se debe tener un objeto Reader existente de algún tipo. Para crear un BufferedReader se puede utilizar el siguiente constructor.

BufferedReader(Reader). Que crea un flujo de caracteres almacenado en bufer, asociado con el objeto especificado Reader, como FileReader.

BufferedReader(Reader, int). Que crea un flujo de caracteres almacenado en buferasociado con el objeto especificado Reader y con un buffer de tamaño int.

Un flujo de caracteres almacenado en bufer se puede leer utilizando los métodos read() y read(char[], int , int) descritos en FileReader. Puede leer una línea de texto usando el método readLine(). El método readLine() devuelve un objeto String que contiene la próxima línea de texto en el flujo, sin incluir el carácter o caracteres que representan el final de una línea, que puede ser(‘\n’, línea nueva), (‘\r’, retorno de carro) o una combinación de esta última con la primera. Si se llega al final del flujo, el valor devuelto de la cadena es igual a null.

Ejemplo 4:

Escribimos una aplicación que lee el contenido de un archivo secuencial cuyo nombre es dado por el usuario desde el teclado y copia el archivo, f, line by line, en otro file, f.out.

import java.io.*;/** CopiarFile copia el contenido de un file, f, * cuyo nombre es sustituido por un file, f.out */

Ingeniería en Computación, Universidad de La Seren 99

Page 100: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

public class CopiarFile{ public static void main(String[] args) throws IOException { String f = JOptionPane.showInputDialog("Input nombrefile: "); // se construye el objeto view que reads desde el input file: BufferedReader infile = new BufferedReader(new FileReader(f)); // se construye el objeto view que writes al output file: PrintWriter outfile = new PrintWriter(new FileWriter(f + ".out")); while ( infile.ready() ) // existen más lineas que leer en infile? { String s = infile.readLine(); outfile.println(s); } infile.close(); outfile.close(); }}

al ingresar su nombre, asumirá que ese archivo existe y copiara su contenido en un archivo de salida similar. Todo esto lo comprobará si se remite a ver el directorio en donde esta trabajando. A continuación se ve un mensaje clásico para cuando no existe el archivo en cuestión.

El error, java.io.FileNotFoundException, es un ejemplo de una IOException---el programa ”thrown” (lanza) una exception. En todo caso tales exceptions pueden ser manejadas. En este sentido, manejaremos esta excepción para el caso que se ingrese un “0”. Y Ud. vera la diferencia, en donde el programa me invita a ejecutarlo nuevamente.

Ejemplo 5:

import javax.swing.*;/** Dividir lee un int y lo divide en 12 */public class DividirTC { public static void main(String[] args){ int i = readAnInt();

try {JOptionPane.showMessageDialog(null, "La respuesta es" + (12 / i));

Ingeniería en Computación, Universidad de La Seren 100

Page 101: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

} catch(RuntimeException e) {JOptionPane.showMessageDialog(null, "Error en input: " + i + ". Ejecutelo nuevamente."); } System.out.println("Terminado."); }/** readAnInt lee un int y lo retorna */ private static int readAnInt() { String s = JOptionPane.showInputDialog("Ingrese un entero:"); int num = new Integer(s).intValue(); return num; }}

String tokenizers y los file objects pueden ayudar a crear una aplicación cuya entrada se basa en un cierto formato, así como su salida. Un ejemplo estándar es el proceso de enlistar alguna información, en donde en este ejemplo se trata de un archivo secuencial, donde cada línea contiene el nombre de un empleado, las horas trabajadas y el pago por ellas, ya sea en un contexto de sobretiempo o alguna otra que no interesa. La información se ve así.

Fred Mercader|31|20.25Lucy Riggs|42|24.50Ethel Meza|18|18.00!

Notar que la secuencia de líneas es terminada por un simbolo especial, !. Una aplicación de este tipo lee las líneas una por una, extrae el tokens de cada línea, convirtiendo a nombre y número y calculando el sueldo.

Ingeniería en Computación, Universidad de La Seren 101

Page 102: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

class LeerInfo

Metodos

getNextRecord(): boolean

Lee el siguiente registro desde el archivo de entrada. Returns V o F, si esta o no el archivo según el formato deseado.

nombreE(): String Return el nombre del empleado.

horasE(): int Return las horas trabajadas por el empleado.

sueldoE(): double Return el pago para el empleado.

close() Close el archivo base.

/** LeerInfo lee los records desde un sequential file. El records tiene el formato, NOMBRE|HORA|PAGO. El file termina con un ! */

import java.io.*;import java.util.*;

public class LeerInfo{ private BufferedReader infile; // la dirección del input file private String END_OF_FILE = "!"; // nombre, hora y pago del record leído: private String nombre; private int hora; private double pago;

/**constructor de LeerInfo para leer desde un file el file_nombre*/ public LeerInfo(String file_nombre) { try { infile = new BufferedReader(new FileReader(file_nombre)); } catch (Exception e){ System.out.println("LeerInfo error: nombre file malo: " + file_nombre + " Abortando!"); throw new RuntimeException(e.toString()); } }

public String nombreE() { return nombre; } public int horasE() { return hora; } public double sueldoE() { return pago; } public void close() { try { infile.close(); } catch (IOException e){ System.out.println("LeerInfo Atención: falla"); } }

/** getNextRecord pretende leer un nuevo registro. * @return si otro record record fue read y esta ready para procesar*/ public boolean getNextRecord() { boolean result = false; nombre = null; hora = -1; pago = -0.1; try {

Ingeniería en Computación, Universidad de La Seren 102

Page 103: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

if ( infile.ready() ) { String linea = infile.readLine(); StringTokenizer t = new StringTokenizer(linea, "|"); String s = t.nextToken().trim(); if ( ! s.equals(END_OF_FILE) ) { // termina? if ( t.countTokens() == 2 ) { // hora y pago? nombre = s; hora = new Integer( t.nextToken().trim()).intValue(); pago = new Double(t.nextToken().trim()).doubleValue(); result = true; } else { throw new RuntimeException(linea); } } } } catch (IOException e){ System.out.println("LeerInfo error: " + e.getMessage()); } catch (RuntimeException e){ System.out.println("LeerInfo error: mal formato record: " + e.getMessage() + " se salta este record y trata otra vez"); result = getNextRecord(); // try again } return result; }}

Para testear la clase LeerInfo, implementemos una clase principal llamada Pagos.java para testearla.

/** Pagos lee un archivo bajo un cierto formato. */

import javax.swing.*;public class Pagos{

public static void main(String[] args) { String in_nombre = JOptionPane.showInputDialog("Nombre archivo entrada:"); String out_nombre = JOptionPane.showInputDialog("Nombre archivo salida:"); if ( in_nombre != null && out_nombre != null ) {

procesandoArchivo(in_nombre, out_nombre); } System.out.println("Terminado"); }

private static void procesandoArchivo(String in, String out) { LeerInfo leer = new LeerInfo(in);

while ( leer.getNextRecord() ) {//algo se hace con ellos? double pago = leer.horasE() * leer.sueldoE(); } leer.close(); }}

Ingeniería en Computación, Universidad de La Seren 103

Page 104: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

El trabajo duro es realizado al interior de getNextRecord, el que verifica el input file si es no vacío antes de leer el siguiente record. El método también se asegura que el record no este con la bandera, !, y que el record posee un string al nombre, un integer como horas trabajadas y un double para el pago. Si todo esto ocurre, entonces la información desde el record es almacenada y devuelve true. El método no acepta malos formatos de los records y returns false cuando alcanza el fin de la entrada. Algunas de las exception son tratadas, tal como las que surgen cunado intValue y doubleValue fallanl. En tal caso estamos forzados a usar un “ throw new RuntimeException(linea)”, lo que nos informará la cantidad incorrecta de datos sobre la línea de entrada. Como un buen ejercicio complementario, sería interesante que se construyera una clase EscribirInfo para el ejemplo recién dado, en donde los cálculos de los sueldos vayan a dar a otro archivo.

En este otro ejemplo se muestra una aplicación de Java que lee su propio archivo fuente através de un flujo de caracteres almacenado en buffer.

Ejemplo 4

import java.io.*;public class leeFuente { public static void main(String[] arguments) { try {//se crea una fuente de entrada, en este caso el archivo //leeFuente.java FileReader archivo = new FileReader("leeFuente.java");//un filtro de bufer se asocia al archivo, llamado buff, //que es un objeto . BufferedReader buff = new BufferedReader(archivo); boolean eof = false; while (!eof) {//método readLine()dentro de un loop para leer el archivo //de texto línea por línea. El loop termina para cuando //el método devuelve el valor null. String linea = buff.readLine(); if (linea == null) eof = true; else System.out.println(linea); } buff.close(); } catch (IOException e) { System.out.println("Error -- " + e.toString()); } }}

Aquí tenemos otra versión de Promedio1, la diferencia radica en que el programa no usa la clase ConsoleReader. El programa parte creando un BufferedReader para leer la entrada del usuario. Las diferencias son mostrada en “bold”. Como Ud. verá la primera línea será afectada

Ingeniería en Computación, Universidad de La Seren 104

Page 105: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

Ejemplo 5

import java.io.*;

public class Promedio2

{ /* Lee punto flotante ingresado por el usuario y entrega el promedio. (Version que usa BufferedReader.) */ public static void main(String[] args) throws IOException

{ BufferedReader usuario = new BufferedReader (new InputStreamReader(System.in));

/* Lee y suma los valores, y cuenta cuantos son. */ double sum = 0; int cuanTos = 0; System.out.println("Ingrese los valores."); while (true) { String linea = usuario.readLine(); if (linea.equals("fin")) break; try {

double siguiente = Double.parseDouble(linea); sum = sum + siguiente; cuanTos++; } catch (NumberFormatException e) { System.out.println ("Entrada No reconocida, intente nuevamente!."); } }

/* promedio. */ if (cuanTos > 0) System.out.println

("El promedio es = " + sum/cuanTos); else System.out.println("Sin valor.");

}}

Note que en el encabezado del programa así como en ejemplo que hacía referencia a la formación de cuadrados se tiene,

public static void main(String[] args) throws IOException

Este llama al compilador que el método main contiene, llamado readLine, que puede arrojar la IOException, la cual no será atrapada pues main no tiene la declaración try-catch para atraparla. En IOException se cubre un rango de diferentes errores o condiciones que pueden ocurrir en la entrada. Un excepción de chequeo( checked exception) . Esto significa que debemos ya sea escribir una declaración que la atrape, o debemos agregar una clausula throws

Ingeniería en Computación, Universidad de La Seren 105

Page 106: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

throws IOException

al encabezado del método. Una clausula throws lista una o más exepciones, separadas por comas.

CAY HORSTMANN’S ConsoleReader CLASS

import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.IOException;

/** A class to read strings and numbers from an input stream. This class is suitable for beginning Java programmers. It constructs the necessary buffered reader, handles I/O exceptions, and converts strings to numbers.*/

public class ConsoleReader

{ private BufferedReader reader;

/** Constructs a console reader from an input stream such as System.in. */ public ConsoleReader(InputStream inStream) { reader = new BufferedReader (new InputStreamReader(inStream)); }

/** Read a line of input and convert it into an integer. */ public int readInt() { String inputString = readLine(); int n = Integer.parseInt(inputString); return n; }

/** Reads a line of input and convert it into a floating-point number. */ public double readDouble() { String inputString = readLine(); double x = Double.parseDouble(inputString); return x; }

/** Read a line of input. In the (unlikely) event of

an IOException, the program halts. */ public String readLine() { String inputLine = "";

Ingeniería en Computación, Universidad de La Seren 106

Page 107: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

try { inputLine = reader.readLine(); } catch(IOException e) { System.out.println(e); System.exit(1); } return inputLine; }}

Ud. podrá utilizar esta clase en el futuro o tal vez adaptarla para sus propósitos. Recuerde que esta versión como un ejemplo del tema que se esta tratando captura cualquier IOExceptions que ocurra, y detiene el programa. Si Ud. no quiere esto tendrá que eliminar la declaración try-catch.

Leer de un Archivo de Texto

Para leer de un archivo de texto podemos crear un tipo especial de Reader llamados FileReader que están conectados al archivo. Para construir la conexión, usamos el constructor FileReader que tiene el nombre de un archivo como parámetro. Por ejemplo, supongamos que queremos leer de un archivo llamado data.txt. Entonces FileReader puede ser construído como sigue.

FileReader input = new FileReader(data.txt);

Si el archivo no es encontrado, Java lanza una excepción del tipo FileNotFoundException. Esto es una excepción de chequeo, de manera que deberá incluir una clausula throws para que ella en cualquier método no pueda atrapar o capturar.

Un FileReader, tiene un método read que retorna el siguiente carácter unicode en la forma de un valor int, pero carece de un método readLine. Para obtenerlo debemos convertir el FileReader en BufferedReader usando el mismo constructor de la última sección. Este constructor puede ser aplicado a cualquier objeto Reader incluyendo FileReader. La siguiente declaración construye un BufferedReader conectado al archivo data.txt.

BufferedReader data = new BufferedReader

(new FileReader(data.txt));

Aquí está el diagrama que muestra la conexión generada.

Archivo

FileReader

BufferedReader

Ingeniería en Computación, Universidad de La Seren 107

Page 108: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

Una vez que BufferedReader ha sido construído, podemos coleccionar las lineas de entrada desde el archivo usando el método readLine justamente como cuando los datos vinieran del teclado. Una diferencia es que se necesita chequear cuando todas las líneas del archivo han sido leídas. El método readLine returns null cuando el fin de archivo ha sido alcanzado. También, cuando se lee desde un archivo, se le recomienda que siempre cierre la conexión al archivo como si Ud. hubiese terminado con él. FileReaders y BufferedReaders tienen ambos un método llamado close para hacerlo lanzando un IOException.

Tenemos una versión final del programa promedio, el cual lee datos desde un archivo llamado hola.dat. Justamente un BufferedReader es construído, conectando al archivo. No existe ningún Reader conectado al teclado.

Ejemplo 6

import java.io.*;

public class Promedio4{ /* Lee números punto flotante desde un archivo hola.dat, y entrega su promedio. */ public static void main(String[] args) { BufferedReader datos; try { datos = new BufferedReader (new FileReader("hola.dat")); } catch (FileNotFoundException e) { System.out.println ("Archivo hola.dat no fue encontrado."); return; }

/* Lee y suma los valores, contando cuantos son. */ double sum = 0; int cuanTos = 0; try { while (true) { String linea = datos.readLine(); if (linea == null) break; try { double siguiente = Double.parseDouble(linea); sum = sum + siguiente; cuanTos++;

} catch (NumberFormatException e) { System.out.println ("Datos malos: " + linea); } } datos.close(); } catch (IOException e) { System.out.println(e); return; }

Ingeniería en Computación, Universidad de La Seren 108

Page 109: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

/* promedio. */ if (cuanTos > 0) System.out.println ("El promedio es = " + sum/cuanTos); else System.out.println("Ningún resultado."); }}

Notas

Si el archivo no existe el resultado atrapa inmediatamente una excepción del tipo FileNotFoundException a raíz de la primera declaración try-catch y el programa detiene su ejecución.

La declaración fuera de try-catch , la cual contiene el loop while, atrapa la excepción IOExceptions arrojado o lanzado por readLine y close.

La declaración interna de try-catch , interna al loop, atrapa cualquier exepción NumberFormatExceptions arrojada por Double.parseDouble.

La secuencia de datos continua hasta fin de archivo. Si no existe la palabra ‘fin ’ al final, el programa detiene su ejecución leyendo cuando linea este seteado a null.

Si cualquier línea de datos contiene algún error, el programa imprimirá la línea para ayudar al usuario a entender que es lo malo en el archivo.

Escribiendo un Archivo de Texto

Si desea escribir a un archivo de texto en línea basta con usar FileWriter, tal como se muestra en el siguiente ejemplo.

import java.io.*;

public class FileWriterDemo{ public static void main( String args[] ) { FileWriter fw = null; try { fw = new FileWriter( "fileWriter.txt" ); fw.write( "Hola erico, aqui va el archivo" ); } catch ( IOException e ) { System.out.println( "No se pudo generar el archivo" ); } finally { try { if ( fw != null ) fw.close(); } catch ( IOException e ) {} } }}

Ingeniería en Computación, Universidad de La Seren 109

Page 110: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

Si desea escribir a un archivo de texto, es mejor usar un objeto PrintWriter. Este objeto tiene métodos convenientes, tales como println y print, justamenta para System.out. Un PrintWriter no puede ser conectado directamente al archivo, pero puede ser conectado al objeto FileWriter, el cual acepta caracteres unicode y los escribe al archivo de texto. Aquí se da una declaración que crea un PrintWriter para escribir un archivo de texto hola.txt.

PrintWriter salir = new PrintWriter (new FileWriter(hola.txt))

Así es la relación entre ellos,

Archivo

FileWriter

PrintWriter

Una vez realizado esto podemos usar los métodos out.print y out.println para enviar los datos al archivo hola.txt. Después que toda la salida ha sido escrita al archivo llame a out.flush(), para asegurarse que ningún carácter este perdido en la cola para cuando la conección se cierre. Finalmente, llamar a out.close() para cerrar la conexión.

Archivos y Filtros.

En varios de los ejemplos que se han visto se ha utilizado una cadena para referirse al archivo incluido en la operación de un flujo. Esto es suficiente si queremos trabajar con archivos y flujos pero el problema surge para cuando queramos trabajar con copiar archivos, cambiar nombre u otras tareas. Para solucionar este problema se debe trabajar con un objeto File. File es también parte del paquete java.io, y representa una referencia de archivos o carpeta. Los constructores que puede utilizar son:ç

File(String), File(String, String), File(File, String). Junto con ellos existe una cantidad de métodos tales como exists(), length(), renameTo(File), delete() o deleteOnExit(), mkdir(), etc..

Hemos visto que al realizar el comando

>java miProg

el Java interprete obtendrá la clase compilada miProg.class y se dirige a unos de los métodos main , el cual obedecera. En vez de este simple comando podemos tipear el comando

Ingeniería en Computación, Universidad de La Seren 110

Page 111: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

java seguido con algunos argumentos de caracteres llamados command line arguments. Por ejemplo,

java miProg data.txt hola.dat

command line arguments

Un command line argument puede ser cualquier string de caracteres.

Una lista de command line arguments se pasarán del método main en la forma de un array de strings. Si son dos argumentos como en el ejemplo anterior entonces el arreglo es de 2 elementos los que hacen referencia a 2 strings. Este array es parámetro de tipo String[] , que todo método main posee. Si suponemos que, en el encabezado del método main es,

public static void main(String[] args)

y suponemos que el interprete Java es dado la línea de comando con 2 argumentos , como antes se mencionaba, entonces un parametro variable llamado args sera creado que contenga una referencia a los 2 elementos del array que anteriormente hacían referencia al strings data.txt y hola.dat.

data.txt

args hola.dat

Con los argumentos strings presentados en esta forma, el método main puede procesarlo en el sentido que el programador decida. Por ejemplo, puede usar la expresión

args.length

para denotar el número de argumentos. Y los argummentos individuales pueden ser referidos como args[0], args[1], etc.

Un ejemplo de esta idea esta dado por la siguiente aplicación que convierte en mayúscula todo el texto de un archivo. El archivo es leído mediante un flujo de entrada almacenado en buffer, y se lee un carácter a la vez. Una vez convertido en mayúscula, el carácter se envía a un archivo temporal por medio de un flujo de entrada almacenado en buffer. Los objetos File se usan en vez de las cadenas para indicar los archivos involucrados, lo cual hace posible cambiarles el nombre y borrarlos según se necesite.

Ingeniería en Computación, Universidad de La Seren 111

Page 112: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

Ejemplo 7

import java.io.*;public class todoMayusDemo { public static void main(String[] arguments) { todoMayus may = new todoMayus(arguments[0]); may.convert(); }}

class todoMayus { String nombreFuente;

todoMayus(String nombreArg) { nombreFuente = nombreArg; }

void convert() { try { // Crea los objetos archivos(File) File nombre = new File(nombreFuente); File temp = new File( nombreFuente + ".tmp");

// Crea una entrada stream FileReader fr = new FileReader(nombre); BufferedReader in = new BufferedReader(fr);

// Crea la salida stream FileWriter fw = new FileWriter(temp); BufferedWriter out = new BufferedWriter(fw);

boolean eof = false; int inChar = 0; do { inChar = in.read(); if (inChar != -1) { char outChar = Character.toUpperCase( (char)inChar ); out.write(outChar); } else eof = true; } while (!eof); in.close(); out.close();

boolean borrar = nombre.delete(); if (borrar) temp.renameTo(nombre); } catch (IOException e) { System.out.println("Error -- " + e.toString()); } catch (SecurityException se) { System.out.println("Error -- " + se.toString()); } }}

Ingeniería en Computación, Universidad de La Seren 112

Page 113: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

Excepciones y Flujo de Datos (Exceptions y Streams)

Mensajes de error enviados por el compilador.Los humanos podemos tolerar errores ortográficos y gramaticales, pero los computadores no, y por esta razón el compilador Java cumple con su labor de denunciar este tipo de errores, identificando la línea y dando una corta explicación. Por ejemplo, aquí tenemos un programa que tiene varios errores.

public class test{ public static main(String[] args) { System.out.println(Hello!)}

Almacenemos el programa en Test.java y compilemoslo. El compilador replica, con varios errores de mensaje, el primero de ellos es

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\test.java:2: invalid method declaration; return type required{ public static main(String[] args) ^

a) Estableciendo que existe un error en la línea 2 del programa y que se ubica aproximadamente en la posición marcada con ^. No nos dice exactamente cual es el problema, pero si nos invita a reflexionar respecto de la sintaxis de un programa. En este caso particular hemos olvidado la palabra clave void.

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\test.java:3: ')' expected { System.out.println(Hola!) ^

b) Luego el compilador reporta otro error en la línea 3 del programa y que se ubica aproximadamente en la posición marcada con ^. Lo que nos ayuda a ver con mayor preocupación que pasa en ese segmento de programa, y notamos que al escribir la palabra

Hola!, hemos olvidado escribirlo entre comillas.

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\test.java:4: ';' expected}^

c) El compilador reporta otro error en la línea 4 del programa y que se ubica aproximadamente en la posición marcada con ^. Y notamos que nos falto cerrar una declaración con ;

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\test.java:5: '}' expected^4 errorsIngeniería en Computación, Universidad de La Seren 113

Page 114: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

Herramienta completada con código de salida 1

d) El compilador reporta otro error en la línea 5 del programa y que se ubica aproximadamente en la posición marcada con ^. Y notamos que nos falto cerrar un paréntesis, con un semicolon }.

Desafortunadamente, el compilador no es perfecto en detectar todos los errors gramaticales en una primera leída, es así como se require compilarlos e ir modificando el código del programa, hasta que quede libre de errores, no obstante el compilador no podrá hacer nada frente a un error semántico. Para completar este segmento digamos que este es un típico error para cuando una clase está carente de una clase principal para ser testeada.

Para mayor consulta dirigirse a The Java Language Specification, de J. Gosling, B. Joy, y G. Steele, Addison Wesley Publishing, 1996, para la definición del lenguaje Java.

Diagnóstico de los errores en Expresiones y Variables

Expresiones y variables le dan a un programa más potencia, pero al mismo tiempo ofrecen la oportunidad de generar más errores. Los errores en este sentido pueden ser de dos formas:

Errores relacionados con la gramática, contexto (tipo de datos), que el compilador Java puede detectar, son llamados: errores en tiempo de compilación.

Errores que ocurren para cuando el programa es ejecutado, deteniendose su ejecución en forma temprana, son llamados errores en tiempo de ejecución o excepciones.

Si consideramos el programa public class Test1{public static void main(String[] args) {

System.out.println( (1+2(*3 );//que desea? System.out.println(Hola!); }}

Ingeniería en Computación, Universidad de La Seren 114

Page 115: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

a) vemos que el compilador notifica y anuncia:

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\Test1.java:3: ')' expected

System.out.println( (1+2(*3 ); ^

b) Si consideramos ahora el programa, detecta un problema en la definición del tipo de dato.public class Test1{public static void main(String[] args) {

string s;//basta con saber que el tipo de dato es String }}

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\Test1.java:4: cannot resolve symbolsymbol : class string location: class Test1 string s; ^

C:\Documents and Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\Test1.java:3: operator + cannot be applied to int,boolean

System.out.println(3 + true); ^

la explicación del compilador es elocuente, es decir enteros con boolenos no se entienden.

public class test {public static void main(String[] args) {

int i=0; System.out.println(1/i);

System.out.println("Hola!"); }

}

tras el proceso natural de compilación podrá ver que el compilador no anuncia ningún tipo de problemas. Sin embargo, en la ejecución dice lo que se muestra.

este es un típico error en tiempo de ejecución, o también llamado una exception. Esto surgió cuando un programa usa tipos de datos incorrectos como argumentos del programa. No obstante si declara double i=0; en la ejecución saldrá

c) Otro ejemplo, surge para cuando se desea ejecutar un programa Java pero con varios parámetros desde la consola.

Ingeniería en Computación, Universidad de La Seren 115

Page 116: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

public class test {public static void main(String[] args) {

int i = new Integer(args[0]).intValue(); System.out.println(1 / i); System.out.println("Hola!");

}}

El mensaje de error fue gatillado por la línea 3, y fue generado por la creación de un objeto Integer en la línea, siendo que la entrada de datos es un carácter, en este caso “a”.

Finalmente, mostremos algunos errores que no son detectados ni por el compilador de Java, ni por su intérprete. Por ejemplo, se imprimen las variables x e y que son la misma. La declaración pasa la inspección del compilador Java, ahora realiza su ejecución y si Ud. espera ver ya sea un true o un false verá que surge un resultado, 7.

public class test {public static void main(String[] args) {

int x = 3; int y = 7; System.out.println(x = y);

System.out.println("Hola!"); }

}

Ingeniería en Computación, Universidad de La Seren 116

Page 117: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

La razón es que x = y es una asignación y no un test para igualdad, como (x = = y). La declaración, System.out.println(x = y), asigna y's valor a x's y lo imprime.

Luego de haber visto esta serie de errores podrá formarse una idea, de lo que se trata este capítulo y que se refiere a complementar y reforzar el uso de excepciones, en donde Java posee una forma de tratar los errores en tiempo de ejecución. Además veremos como leer desde el teclado sin usar la clase que se le ha pedido “prestada” a Horstmann’s llamada ConsoleReader, y como leer y escribir archivos de texto, además de como hacer uso de los parámetros que todo método main posee.

ExcepcionesJava tiene un especial mecanismo para tratar errores en tiempo de ejecución. Suponga que escribe algún código que puede tener errores cuando lo ejecuta. Por ejemplo, si una cierta variable se refiriese a un objeto, y un error ocurre si la variable contiene null. Entonces puede Ud. insertar una declaración que arroja una excepción (throws and exception) si la condición de error ocurre. Veamos 2 situaciones.

1. Crear un objeto que describe la condición de error, usualmente llamada un objeto exception. (Ella pertenece a la clase Throwable, y estará ya sea en la subclase Error, si es un serio error del sistema, o en la subclase Exception, si ocurrió el error en el tiempo de ejecución normal.)

2. Esto causa que el interprete se detenga en la secuencia de declaraciones en donde ocurrió el error y comience a buscar una clausuala catch que ha sido escrita para responder al error apropiadamente, es decir, desplegando un window que le informa al usuario que hacer en lo sucesivo. (Como buscar la clausula catch se describirá posteriormente.) Si el interprete no puede encontrar una clausula disponible catch, el programa se detiene y Java desplegara un mensaje de error por defecto en la ventana DOS. Esto origina el nombre de excepciones y una lista de todos los métodos que están siendo ejecutados actualmente.

Las excepciones son a menudo atrapadas o arrojadas por el mismo Java, ya sea por uno de los métodos de librería, o por un interprete, es decir, cuando encuentra algo el mismo trata de accesar a un array de elementos con un valor del indice fuera del rango correcto de valores. En este caso, la excepcion será una IndexOutOfBoundsException.

Una cláusula catch es parte de una declaración try-catch y tiene la forma siguiente.

try{ Declaraciones catch (EXCEPCION1 e1) { Declaraciones}catch (EXCEPCION2 e2)

Ingeniería en Computación, Universidad de La Seren 117

Page 118: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

{ Declaracionesfinally { Declaraciones}

La última parte finally clausula es por lo general omitida. Cuando el interprete obedece la declaración try-catch, ella ejecuta la declaración try normalmente. Si ninguna excepción es arrojada, eso es todo cuanto la declaración try-catch hace. Si una excepción es arrojada, el intérprete partira buscando para una try-clausula que sea obedecida para cuando la excepción fue arrojada.

Por supuesto la declaración try en la declaración try-catch fue obedecida, pero puede haber otra declaración try-catch más cerca de donde ocurrió el error. El intérprete entonces buscará el más interno, llamaremos a la declaración que produjo el error S0. Primero el intérprete mira dentro del cuerpo del método que contiene S0. Si encuentra que S0 está dentro de una try, toma una. Si hay dos o más declaraciones try anidadas que contienen a S0, toma la más interna. Si S0 no está al interior de una try, el intérprete va a la declaración S1 que llamó el método que contiene S0. Entonces empieza buscando la catch más interna que contiene S1. Si no puede encontrar uno en ese cuerpo del método, va a la declaración S2 llamando el método que contiene S1. Y así sucesivamente. Aquí se muestra un programa que contiene una declaración try-catch. El programa lee una serie de valores de punto flotante ingresados por el usuario, y se detiene cuando lee la palabra ‘fin’. Suma los números y al mismo tiempo cuenta cuantos números son, finalmente, divide la suma de los números por el contador generando así el promedio de los números ingresados, el cual es desplegado en pantalla.

El programa chequea si ve en la línea la palabra ‘fin’. La línea es leída usando readLine. Si ella no tiene ‘fin’, el programa procura convertirla en número usando el metodo Double.parseDouble. Si por error de tipeado, el usuario tipea algo que no es un número o la palabra ‘fin’, entonces una NumberFormatException será lanzada. Si no es capturado el programa despliega un mensaje de error por defecto y para.

Una declaración try-catch ha sido insertada en esta versión del programa para capturar las excepciones, y así evitar el mensaje de error. La clausula try incluye la llamada a Double.parseDouble, y la acción que continua para cuando el número esta correcto. La clausula catch justamente despliega un simple error de mensaje, y entonces el programa esta habilitado para realizar su tarea.

Ejemplo 1

public class Promedio1 { /* Lee números flotante ingresados por el

usuario y entrega el promedio. (Version que usa ConsoleReader.)

*/ public static void main(String[] args) {

ConsoleReader usuario = new ConsoleReader(System.in);

/* Lee y agrega los valores, y cuenta cuantos son. */

Ingeniería en Computación, Universidad de La Seren 118

Page 119: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

double sum = 0; int cuanTos = 0; System.out.println("Ingrese los datos."); while (true) { String linea = usuario.readLine(); if (linea.equals("fin")) break;

try/* protección de código, que podría lanzar una excepción dentro de try, pues este segmento de código podría causar una excepción, si no existen problemas continue, sino*/

{ double siguiente = Double.parseDouble(linea); sum = sum + siguiente; cuanTos++; } catch (NumberFormatException e)

/* Atrape la excepción, haciendo una prueba para manejar una excepción dentro de catch*/

{ System.out.println ("Ingreso NO reconocido, intentelo de nuevo!."); } } /* el promedio. */ if (cuanTos > 0) System.out.println ("El valor promedio es = " + sum/cuanTos); else System.out.println("Sin resultado."); }}

También como excepciones producidas por Java, puede forzar una excepcion para ser arrojada mediante la declaración throw . Esta clausula indica que algún código en el cuerpo de su método podría lanzar una excepción, para tal efecto simplemente agregar la palabra throw después del nombre del método pero antes de abrir el bloque. Por ejemplo,

public boolean miMetodo(int x, int y) trows AnException {

o más simple seguida por la referencia a un objeto excepcion. Por ejemplo,

throw new NumberFormatException();

Note que un constructor es usado para crear el objeto exception aquí. Existen muchos tipos de excepciones definidas en la librería. Para encontrarlas todas vea la clase Exception y sus subclases. También, puede Ud. definir sus propias clases exccepcion extendiendo la clase Exception.

Leer desde el teclado

Cuando un programa Java lee la entrada, usa un objeto de algún tipo para manejar la entrada. El objeto será conectado a la fuente de la entrada, es decir la entrada fuente, me refiero a el teclado o archivo de texto. En términos de leer valores de entrada desde la fuente usamos métodos pertenecientes a ese objeto. El objeto ConsoleReader el cual hemos usado durante el curso para leer desde el teclado es un típico ejemplo de un objeto que maneja la entrada.

Ingeniería en Computación, Universidad de La Seren 119

Page 120: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

El objeto que maneja la entrada será llamada InputStream o un Reader. La diferencia depende sobre que valores produce para cuando lea los caracteres. Un InputStream returns un 8-bit byte cada vez que lea un carácter, que es como el sistema lo representa. Un Reader returns 16-bit caracteres. Esta es la forma estandar que Java representa caracteres, usando caracteres de código llamados unicode.

Cada vez que se crea un objeto ConsoleReader, hacemos uso de otro objeto llamado System.in. Esto es un InputStream conectado directamente al teclado. InputStreams tiene varios métodos asociados con ellos, pero solamente uno puede ser usado para leer la entrada que es read que lee 8-bit byte. El siguiente diagrama representa el objeto System.in conectado al teclado, con la información que fluye del teclado,

keyboard

System.in

Java posee clases llamadas InputStreamReader que consiste de objetos que producen los caracteres 16-bit unicode usados por Java. Existe un constructor que puede convertir un InputStream en un InputStreamReader. Ud. deberá darle InputStream como parametro, y el creara el InputStreamReader. Por ejemplo, la declaración siguiente construira una InputStreamReader conectado a System.in.

InputStreamReader lector = new InputStreamReader(System.in);

Ud. puede incluir un segundo parámetro para especificar un decodificador noestandar para devolver bytes en caracteres unicode. Sin el segundo parametro, el InputStreamReader usará un decodificador estandar, el cual es satisfactorio para usos o propósitos normales. Lo mismo es posible para la salida. Aquí esta el diagrama de InputStreamReader definido anteriormente. Se obtiene 8-bit bytes desde el teclado, usando System.in, convirtiéndolos en caracteres de 16-bit.

teclado

System.in

InputStreamReader

Un InputStreamReader tiene un método read que entrega un carácter simple. Esto sería posible de usarse para cuando escriba métodos que usan números reales, líneas de texto, etc. Sin embargo, un conveniente punto de partida es un objeto, el cual puede leer una linea de caracteres ala vez. Existen 2 tipos de objetos que pueden hacer uso de ellos. Uno es llamado BufferedReader y el otro es LineNumberReader. Ambos tienen un método readLine que

Ingeniería en Computación, Universidad de La Seren 120

Page 121: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

retorna la siguiente línea de entrada. Ud, puede convertir un InputStreamReader en BufferedReader. Usualmente se hace mediante constructores. Por ejemplo,

BufferedReader usuario = new BufferedReader(new InputStreamReader(System.in));

La declaración se vé como sigue,

teclado

System.in

InputStreamReader

BufferedReader

Ejemplo 2

Un programa que pregunta por la dimensión del cuadrado y entrega lo solicitado. Si le ingresa el valor 5, vera la figura:

***** * * * * * * ***** import java.io.*; public class Ejerc5{ public static void main(String args[]) throws IOException { int tam; BufferedReader din; din = new BufferedReader( new InputStreamReader(System.in)); System.out.println("Cuadrado"); System.out.println("========"); while (true) { System.out.print("Largo del lado [1-20,0=Fin]: "); tam = Integer.parseInt(din.readLine()); if (tam < 1) { break; } else if (tam <= 20) { for (int i = 1; i <= tam; ++i) { for (int j = 1; j <= tam; ++j) { if (j == 1 || j == tam || i == 1 || i == tam){ System.out.print("*"); } else { System.out.print(" "); } } System.out.println(); } } } } }

Ingeniería en Computación, Universidad de La Seren 121

Page 122: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

Ejemplo 3

El programa CambioMoneda, calcula el cambio para un monto de dolares-y –cents, todo ello ingresado por teclado.

import java.io.*;/** CambioMoneda calcula el cambio para un monto de dolares-y -cents. * input: un monto en dolares y un monto en cents. Ambos enteros. * output: el listado de las monedas necesarias. */public class CambioMoneda{ public static void main(String[] args) throws IOException { BufferedReader teclado = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Tabla de Montos"); System.out.println("==============="); System.out.print("Ingrese monto de dolares: "); String dolares = teclado.readLine(); System.out.print("Ingrese monto de cets: "); String cents = teclado.readLine(); int monedas = (100 * new Integer(dolares).intValue()) + new Integer(cents).intValue(); System.out.println( "quarters = " + (monedas/25) ); monedas = monedas % 25; System.out.println( "dimes = " + (monedas/10) ); monedas = monedas % 10; System.out.println( "nickels = " + (monedas/5) ); monedas = monedas % 5; System.out.println( "pennies = " + monedas ); }}

Como leer archivos de texto

Existen 2 formatos de archivo:

character file, que es una secuencia de simbolos del teclado, almacenados en un archivo como una secuencia de bytes;

binary file, que es una secuencia de unos y ceros.

Un texto depositado en un archivo podrá tener diferentes formatos, por ejemplo.Hola!Cómo estas tú?49

ó como una secuencia Hola!\nCómo estas tú?\n 49\n

Ingeniería en Computación, Universidad de La Seren 122

Page 123: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

Por otra parte un archive binario es una secuencia de unos y ceros, de manera que 49 es expresado como, 11001, y no como la representación '4' y '9').

Cuando obtenemos información de entrada desde un archivo, se dice que read desde el archivo; para cuando depositamos una información de salida en un archivo, decimos write en él. Cuando comenzamos a usar un archivo, decimos que se open , y cuando terminamos de usarlo, lo close. Los archivos pueden ser read/written en dos sentidos:

sequential file pueden ser read (o written) desde front to back; es decir es un libro que tiene una sola dirección de lectura, pudiendo regresar en una sola dirección, (forwards).

random access file pueden ser reads (o writes) sobre cualquier lugar, es como si en un libro pudiese abrirlo en cualquier página.

Sequential files son simples para manejar y trabajar aplicaciones estandares, mientras que los Random access files son usados principalmente para aplicaciones de database donde se especifican bits de información. En este segmento se verán solamente sequential files. Para programas Java que usan sequential file, se debe establecer si el archio usado es usado para

input: el file es read sequentially y no puede ser written.

output: el file esta written sequentially y no puede ser read.

La clase BufferedReader lee un flujo de entrada de caracteres y los guarda en un array llamado buffer. Para crear una versión en buffer se debe tener un objeto Reader existente de algún tipo. Para crear un BufferedReader se puede utilizar el siguiente constructor.

BufferedReader(Reader). Que crea un flujo de caracteres almacenado en bufer, asociado con el objeto especificado Reader, como FileReader.

BufferedReader(Reader, int). Que crea un flujo de caracteres almacenado en buferasociado con el objeto especificado Reader y con un buffer de tamaño int.

Un flujo de caracteres almacenado en bufer se puede leer utilizando los métodos read() y read(char[], int , int) descritos en FileReader. Puede leer una línea de texto usando el método readLine(). El método readLine() devuelve un objeto String que contiene la próxima línea de texto en el flujo, sin incluir el carácter o caracteres que representan el final de una línea, que puede ser(‘\n’, línea nueva), (‘\r’, retorno de carro) o una combinación de esta última con la primera. Si se llega al final del flujo, el valor devuelto de la cadena es igual a null.

Ejemplo 4:

Escribimos una aplicación que lee el contenido de un archivo secuencial cuyo nombre es dado por el usuario desde el teclado y copia el archivo, f, line by line, en otro file, f.out.

import java.io.*;

Ingeniería en Computación, Universidad de La Seren 123

Page 124: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

/** CopiarFile copia el contenido de un file, f, * cuyo nombre es sustituido por un file, f.out */public class CopiarFile{ public static void main(String[] args) throws IOException { String f = JOptionPane.showInputDialog("Input nombrefile: "); // se construye el objeto view que reads desde el input file: BufferedReader infile = new BufferedReader(new FileReader(f)); // se construye el objeto view que writes al output file: PrintWriter outfile = new PrintWriter(new FileWriter(f + ".out")); while ( infile.ready() ) // existen más lineas que leer en infile? { String s = infile.readLine(); outfile.println(s); } infile.close(); outfile.close(); }}

al ingresar su nombre, asumirá que ese archivo existe y copiara su contenido en un archivo de salida similar. Todo esto lo comprobará si se remite a ver el directorio en donde esta trabajando. A continuación se ve un mensaje clásico para cuando no existe el archivo en cuestión.

El error, java.io.FileNotFoundException, es un ejemplo de una IOException---el programa ”thrown” (lanza) una exception. En todo caso tales exceptions pueden ser manejadas. En este sentido, manejaremos esta excepción para el caso que se ingrese un “0”. Y Ud. vera la diferencia, en donde el programa me invita a ejecutarlo nuevamente.

Ejemplo 5:

import javax.swing.*;/** Dividir lee un int y lo divide en 12 */public class DividirTC { public static void main(String[] args){ int i = readAnInt();

try {

Ingeniería en Computación, Universidad de La Seren 124

Page 125: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

JOptionPane.showMessageDialog(null, "La respuesta es" + (12 / i)); }

catch(RuntimeException e) {JOptionPane.showMessageDialog(null, "Error en input: " + i + ". Ejecutelo nuevamente."); } System.out.println("Terminado."); }/** readAnInt lee un int y lo retorna */ private static int readAnInt() { String s = JOptionPane.showInputDialog("Ingrese un entero:"); int num = new Integer(s).intValue(); return num; }}

String tokenizers y los file objects pueden ayudar a crear una aplicación cuya entrada se basa en un cierto formato, así como su salida. Un ejemplo estándar es el proceso de enlistar alguna información, en donde en este ejemplo se trata de un archivo secuencial, donde cada línea contiene el nombre de un empleado, las horas trabajadas y el pago por ellas, ya sea en un contexto de sobretiempo o alguna otra que no interesa. La información se ve así.

Fred Mercader|31|20.25Lucy Riggs|42|24.50Ethel Meza|18|18.00!

Notar que la secuencia de líneas es terminada por un simbolo especial, !. Una aplicación de este tipo lee las líneas una por una, extrae el tokens de cada línea, convirtiendo a nombre y número y calculando el sueldo.

Ingeniería en Computación, Universidad de La Seren 125

Page 126: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

class LeerInfo

Metodos

getNextRecord():

boolean Lee el siguiente registro desde el archivo de entrada. Returns V o F, si esta o no el archivo según el formato deseado.

nombreE(): String Return el nombre del empleado.

horasE(): int Return las horas trabajadas por el empleado.

sueldoE(): double Return el pago para el empleado.

close() Close el archivo base.

/** LeerInfo lee los records desde un sequential file. El records tiene el formato, NOMBRE|HORA|PAGO. El file termina con un ! */

import java.io.*;import java.util.*;

public class LeerInfo{ private BufferedReader infile; // la dirección del input file private String END_OF_FILE = "!"; // nombre, hora y pago del record leído: private String nombre; private int hora; private double pago;

/**constructor de LeerInfo para leer desde un file el file_nombre*/ public LeerInfo(String file_nombre) { try { infile = new BufferedReader(new FileReader(file_nombre)); } catch (Exception e){ System.out.println("LeerInfo error: nombre file malo: " + file_nombre + " Abortando!"); throw new RuntimeException(e.toString()); } }

public String nombreE() { return nombre; } public int horasE() { return hora; } public double sueldoE() { return pago; } public void close() { try { infile.close(); } catch (IOException e){ System.out.println("LeerInfo Atención: falla"); } }

/** getNextRecord pretende leer un nuevo registro. * @return si otro record record fue read y esta ready para procesar*/ public boolean getNextRecord() { boolean result = false; nombre = null; hora = -1; pago = -0.1;

Ingeniería en Computación, Universidad de La Seren 126

Page 127: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

try { if ( infile.ready() ) { String linea = infile.readLine(); StringTokenizer t = new StringTokenizer(linea, "|"); String s = t.nextToken().trim(); if ( ! s.equals(END_OF_FILE) ) { // termina? if ( t.countTokens() == 2 ) { // hora y pago? nombre = s; hora = new Integer( t.nextToken().trim()).intValue(); pago = new Double(t.nextToken().trim()).doubleValue(); result = true; } else { throw new RuntimeException(linea); } } } } catch (IOException e){ System.out.println("LeerInfo error: " + e.getMessage()); } catch (RuntimeException e){ System.out.println("LeerInfo error: mal formato record: " + e.getMessage() + " se salta este record y trata otra vez"); result = getNextRecord(); // try again } return result; }}

Para testear la clase LeerInfo, implementemos una clase principal llamada Pagos.java para testearla.

/** Pagos lee un archivo bajo un cierto formato. */

import javax.swing.*;public class Pagos{

public static void main(String[] args) { String in_nombre = JOptionPane.showInputDialog("Nombre archivo entrada:"); String out_nombre = JOptionPane.showInputDialog("Nombre archivo salida:"); if ( in_nombre != null && out_nombre != null ) {

procesandoArchivo(in_nombre, out_nombre); } System.out.println("Terminado"); }

private static void procesandoArchivo(String in, String out) { LeerInfo leer = new LeerInfo(in);

while ( leer.getNextRecord() ) {//algo se hace con ellos? double pago = leer.horasE() * leer.sueldoE(); } leer.close(); }}

El trabajo duro es realizado al interior de getNextRecord, el que verifica el input file si es no vacío antes de leer el siguiente record. El método también se asegura que el record no este con la bandera, !, y que el record posee un string al nombre, un integer como horas trabajadas y un

Ingeniería en Computación, Universidad de La Seren 127

Page 128: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

double para el pago. Si todo esto ocurre, entonces la información desde el record es almacenada y devuelve true. El método no acepta malos formatos de los records y returns false cuando alcanza el fin de la entrada. Algunas de las exception son tratadas, tal como las que surgen cunado intValue y doubleValue fallanl. En tal caso estamos forzados a usar un “ throw new RuntimeException(linea)”, lo que nos informará la cantidad incorrecta de datos sobre la línea de entrada. Como un buen ejercicio complementario, sería interesante que se construyera una clase EscribirInfo para el ejemplo recién dado, en donde los cálculos de los sueldos vayan a dar a otro archivo.

En este otro ejemplo se muestra una aplicación de Java que lee su propio archivo fuente através de un flujo de caracteres almacenado en buffer.

Ejemplo 4

import java.io.*;public class leeFuente { public static void main(String[] arguments) { try {//se crea una fuente de entrada, en este caso el archivo //leeFuente.java FileReader archivo = new FileReader("leeFuente.java");//un filtro de bufer se asocia al archivo, llamado buff, //que es un objeto . BufferedReader buff = new BufferedReader(archivo); boolean eof = false; while (!eof) {//método readLine()dentro de un loop para leer el archivo //de texto línea por línea. El loop termina para cuando //el método devuelve el valor null. String linea = buff.readLine(); if (linea == null) eof = true; else System.out.println(linea); } buff.close(); } catch (IOException e) { System.out.println("Error -- " + e.toString()); } }}

Aquí tenemos otra versión de Promedio1, la diferencia radica en que el programa no usa la clase ConsoleReader. El programa parte creando un BufferedReader para leer la entrada del usuario. Las diferencias son mostrada en “bold”. Como Ud. verá la primera línea será afectada

Ejemplo 5

import java.io.*;

public class Promedio2

Ingeniería en Computación, Universidad de La Seren 128

Page 129: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

{ /* Lee punto flotante ingresado por el usuario y entrega el promedio. (Version que usa BufferedReader.) */ public static void main(String[] args) throws IOException { BufferedReader usuario = new BufferedReader (new InputStreamReader(System.in));

/* Lee y suma los valores, y cuenta cuantos son. */ double sum = 0; int cuanTos = 0; System.out.println("Ingrese los valores."); while (true) { String linea = usuario.readLine(); if (linea.equals("fin")) break; try {

double siguiente = Double.parseDouble(linea); sum = sum + siguiente; cuanTos++; } catch (NumberFormatException e) { System.out.println ("Entrada No reconocida, intente nuevamente!."); } }

/* promedio. */ if (cuanTos > 0) System.out.println

("El promedio es = " + sum/cuanTos); else System.out.println("Sin valor.");

}}

Note que en el encabezado del programa así como en ejemplo que hacía referencia a la formación de cuadrados se tiene,

public static void main(String[] args) throws IOException

Este llama al compilador que el método main contiene, llamado readLine, que puede arrojar la IOException, la cual no será atrapada pues main no tiene la declaración try-catch para atraparla. En IOException se cubre un rango de diferentes errores o condiciones que pueden ocurrir en la entrada. Un excepción de chequeo( checked exception) . Esto significa que debemos ya sea escribir una declaración que la atrape, o debemos agregar una clausula throws

throws IOException

Ingeniería en Computación, Universidad de La Seren 129

Page 130: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

al encabezado del método. Una clausula throws lista una o más exepciones, separadas por comas.

CAY HORSTMANN’S ConsoleReader CLASS

import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.IOException;

/** A class to read strings and numbers from an input stream. This class is suitable for beginning Java programmers. It constructs the necessary buffered reader, handles I/O exceptions, and converts strings to numbers.*/

public class ConsoleReader

{ private BufferedReader reader;

/** Constructs a console reader from an input stream such as System.in. */ public ConsoleReader(InputStream inStream) { reader = new BufferedReader (new InputStreamReader(inStream)); }

/** Read a line of input and convert it into an integer. */ public int readInt() { String inputString = readLine(); int n = Integer.parseInt(inputString); return n; }

/** Reads a line of input and convert it into a floating-point number.

*/ public double readDouble() { String inputString = readLine(); double x = Double.parseDouble(inputString); return x; }

/** Read a line of input. In the (unlikely) event of

an IOException, the program halts. */ public String readLine() { String inputLine = ""; try

Ingeniería en Computación, Universidad de La Seren 130

Page 131: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

{ inputLine = reader.readLine(); } catch(IOException e) { System.out.println(e); System.exit(1); } return inputLine; }}

Ud. podrá utilizar esta clase en el futuro o tal vez adaptarla para sus propósitos. Recuerde que esta versión como un ejemplo del tema que se esta tratando captura cualquier IOExceptions que ocurra, y detiene el programa. Si Ud. no quiere esto tendrá que eliminar la declaración try-catch.

Leer de un Archivo de Texto

Para leer de un archivo de texto podemos crear un tipo especial de Reader llamados FileReader que están conectados al archivo. Para construir la conexión, usamos el constructor FileReader que tiene el nombre de un archivo como parámetro. Por ejemplo, supongamos que queremos leer de un archivo llamado data.txt. Entonces FileReader puede ser construído como sigue.

FileReader input = new FileReader(data.txt);

Si el archivo no es encontrado, Java lanza una excepción del tipo FileNotFoundException. Esto es una excepción de chequeo, de manera que deberá incluir una clausula throws para que ella en cualquier método no pueda atrapar o capturar.

Un FileReader, tiene un método read que retorna el siguiente carácter unicode en la forma de un valor int, pero carece de un método readLine. Para obtenerlo debemos convertir el FileReader en BufferedReader usando el mismo constructor de la última sección. Este constructor puede ser aplicado a cualquier objeto Reader incluyendo FileReader. La siguiente declaración construye un BufferedReader conectado al archivo data.txt.

BufferedReader data = new BufferedReader

(new FileReader(data.txt));

Aquí está el diagrama que muestra la conexión generada.

Archivo

FileReader

BufferedReader

Ingeniería en Computación, Universidad de La Seren 131

Page 132: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

Una vez que BufferedReader ha sido construído, podemos coleccionar las lineas de entrada desde el archivo usando el método readLine justamente como cuando los datos vinieran del teclado. Una diferencia es que se necesita chequear cuando todas las líneas del archivo han sido leídas. El método readLine returns null cuando el fin de archivo ha sido alcanzado. También, cuando se lee desde un archivo, se le recomienda que siempre cierre la conexión al archivo como si Ud. hubiese terminado con él. FileReaders y BufferedReaders tienen ambos un método llamado close para hacerlo lanzando un IOException.

Tenemos una versión final del programa promedio, el cual lee datos desde un archivo llamado hola.dat. Justamente un BufferedReader es construído, conectando al archivo. No existe ningún Reader conectado al teclado.

Ejemplo 6

import java.io.*;

public class Promedio4{ /* Lee números punto flotante desde un archivo hola.dat, y entrega su promedio. */ public static void main(String[] args) { BufferedReader datos; try { datos = new BufferedReader (new FileReader("hola.dat")); } catch (FileNotFoundException e) { System.out.println ("Archivo hola.dat no fue encontrado."); return; }

/* Lee y suma los valores, contando cuantos son. */ double sum = 0; int cuanTos = 0; try { while (true) { String linea = datos.readLine(); if (linea == null) break; try { double siguiente = Double.parseDouble(linea); sum = sum + siguiente; cuanTos++;

} catch (NumberFormatException e) { System.out.println ("Datos malos: " + linea); } } datos.close(); } catch (IOException e) { System.out.println(e); return;

Ingeniería en Computación, Universidad de La Seren 132

Page 133: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

}

/* promedio. */ if (cuanTos > 0) System.out.println ("El promedio es = " + sum/cuanTos); else System.out.println("Ningún resultado."); }}

Notas

Si el archivo no existe el resultado atrapa inmediatamente una excepción del tipo FileNotFoundException a raíz de la primera declaración try-catch y el programa detiene su ejecución.

La declaración fuera de try-catch , la cual contiene el loop while, atrapa la excepción IOExceptions arrojado o lanzado por readLine y close.

La declaración interna de try-catch , interna al loop, atrapa cualquier exepción NumberFormatExceptions arrojada por Double.parseDouble.

La secuencia de datos continua hasta fin de archivo. Si no existe la palabra ‘fin ’ al final, el programa detiene su ejecución leyendo cuando linea este seteado a null.

Si cualquier línea de datos contiene algún error, el programa imprimirá la línea para ayudar al usuario a entender que es lo malo en el archivo.

Escribiendo un Archivo de Texto

Si desea escribir a un archivo de texto en línea basta con usar FileWriter, tal como se muestra en el siguiente ejemplo.

import java.io.*;

public class FileWriterDemo{ public static void main( String args[] ) { FileWriter fw = null; try { fw = new FileWriter( "fileWriter.txt" ); fw.write( "Hola erico, aqui va el archivo" ); } catch ( IOException e ) { System.out.println( "No se pudo generar el archivo" ); } finally { try { if ( fw != null ) fw.close(); } catch ( IOException e ) {} } }}

Ingeniería en Computación, Universidad de La Seren 133

Page 134: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

Si desea escribir a un archivo de texto, es mejor usar un objeto PrintWriter. Este objeto tiene métodos convenientes, tales como println y print, justamenta para System.out. Un PrintWriter no puede ser conectado directamente al archivo, pero puede ser conectado al objeto FileWriter, el cual acepta caracteres unicode y los escribe al archivo de texto. Aquí se da una declaración que crea un PrintWriter para escribir un archivo de texto hola.txt.

PrintWriter salir = new PrintWriter (new FileWriter(hola.txt))

Así es la relación entre ellos,

Archivo

FileWriter

PrintWriter

Una vez realizado esto podemos usar los métodos out.print y out.println para enviar los datos al archivo hola.txt. Después que toda la salida ha sido escrita al archivo llame a out.flush(), para asegurarse que ningún carácter este perdido en la cola para cuando la conección se cierre. Finalmente, llamar a out.close() para cerrar la conexión.

Archivos y Filtros.

En varios de los ejemplos que se han visto se ha utilizado una cadena para referirse al archivo incluido en la operación de un flujo. Esto es suficiente si queremos trabajar con archivos y flujos pero el problema surge para cuando queramos trabajar con copiar archivos, cambiar nombre u otras tareas. Para solucionar este problema se debe trabajar con un objeto File. File es también parte del paquete java.io, y representa una referencia de archivos o carpeta. Los constructores que puede utilizar son:File(String), File(String, String), File(File, String). Junto con ellos existe una cantidad de métodos tales como exists(), length(), renameTo(File), delete() o deleteOnExit(), mkdir(), etc..

Hemos visto que al realizar el comando

>java miProg

el Java interprete obtendrá la clase compilada miProg.class y se dirige a unos de los métodos main , el cual obedecera. En vez de este simple comando podemos tipear el comando java

Ingeniería en Computación, Universidad de La Seren 134

Page 135: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

seguido con algunos argumentos de caracteres llamados command line arguments. Por ejemplo,

java miProg data.txt hola.dat

command line arguments

Un command line argument puede ser cualquier string de caracteres.

Una lista de command line arguments se pasarán del método main en la forma de un array de strings. Si son dos argumentos como en el ejemplo anterior entonces el arreglo es de 2 elementos los que hacen referencia a 2 strings. Este array es parámetro de tipo String[] , que todo método main posee. Si suponemos que, en el encabezado del método main es,

public static void main(String[] args)

y suponemos que el interprete Java es dado la línea de comando con 2 argumentos , como antes se mencionaba, entonces un parametro variable llamado args sera creado que contenga una referencia a los 2 elementos del array que anteriormente hacían referencia al strings data.txt y hola.dat.

data.txt

args hola.dat

Con los argumentos strings presentados en esta forma, el método main puede procesarlo en el sentido que el programador decida. Por ejemplo, puede usar la expresión

args.length

para denotar el número de argumentos. Y los argummentos individuales pueden ser referidos como args[0], args[1], etc.

Un ejemplo de esta idea esta dado por la siguiente aplicación que convierte en mayúscula todo el texto de un archivo. El archivo es leído mediante un flujo de entradab almacenado en buffer, y se lee un carácter a la vez. Una vez convertido en mayúscula, el carácter se envía a un archivo temporal por medio de un flujo de entrada almacenado en buffer. Los objetos File se usan en vez de las cadenas para indicar los archivos involucrados, lo cual hace posible cambiarles el nombre y borrarlos según se necesite.

Ejemplo 7

Ingeniería en Computación, Universidad de La Seren 135

Page 136: Libro Java

Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos

import java.io.*;public class todoMayusDemo { public static void main(String[] arguments) { todoMayus may = new todoMayus(arguments[0]); may.convert(); }}

class todoMayus { String nombreFuente;

todoMayus(String nombreArg) { nombreFuente = nombreArg; }

void convert() { try { // Crea los objetos archivos(File) File nombre = new File(nombreFuente); File temp = new File( nombreFuente + ".tmp");

// Crea una entrada stream FileReader fr = new FileReader(nombre); BufferedReader in = new BufferedReader(fr);

// Crea la salida stream FileWriter fw = new FileWriter(temp); BufferedWriter out = new BufferedWriter(fw);

boolean eof = false; int inChar = 0; do { inChar = in.read(); if (inChar != -1) { char outChar = Character.toUpperCase( (char)inChar ); out.write(outChar); } else eof = true; } while (!eof); in.close(); out.close();

boolean borrar = nombre.delete(); if (borrar) temp.renameTo(nombre); } catch (IOException e) { System.out.println("Error -- " + e.toString()); } catch (SecurityException se) { System.out.println("Error -- " + se.toString()); } }}

Ingeniería en Computación, Universidad de La Seren 136

Page 137: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

C A P Í T U L O 6

Programación Orientada a Objetos en Java

Hasta el momento hemos discutido una serie de conceptos de la programación orientada a objetos en Java, sin preocuparnos mayormente sobre el detalle de ciertas declaraciones, como por ejemplo, ¿Porqué main() en los programas antes escrito deben ser public y static?. La idea para entender la filosofía que está detrás de Java pasa por analizar y entender algunos conceptos de la POO. Por otra parte, en esta oportunidad pretendo que aprendan aplicar en java la POO, así como los fundamentos de la POO, y como ellos se visualizan en Java, como por ejemplo los conceptos de: clase, objeto, método, instancia, herencia, polimorfismo, constructor, interface, sobrecarga, etc. En resumen este segmento trata de introducirlo en los fundamentos que le harán tomar confianza con la POO.

Un pequeño adelanto respecto de los conceptos de la POO es que la POO encapsula datos (atributos) y métodos en un objeto. Los objetos tienen la propiedad de ocultar la información. Ahora si Ud. ha programado en C, verá que es orientado a la acción, Java en cambio es orientada a objetos, esto significa que en C la unidad de programación son las funciones (en Java este tipo de estructuras se llaman métodos). No obstante, las funciones no desaparecen en Java, sino que ellas son encapsuladas como métodos con datos que se procesan al interior de la clase. La Fig.1, nos muestra cómo se ve en general un segmento de programa en Java.

Declaración de clase

public abstract final class Nombre_Clase

extends Nombre_Clase

implements lista_Interface {

Atributo type Nombre Atributo;

Constructor public Nombre_Clase ( )

{//...}Método

public hola (...)

{//...}

Ingeniería en Computación, Universidad de La Seren 137

Page 138: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Fig. 1

Fig. 2

La Fig. 2 muestra los pilares básicos de la orientación a objeto. Los programadores en Java se concentran en crear sus propias Clases, que son tipos definidos de programas o bien utilizar algunas para sus propios fines. Así por ejemplo, ya hemos usado la clase ConsoleReader en los ejemplos de las otras lecciones. Cada clase contiene datos, como también un conjunto de métodos que manipulan los datos.

Observación: El modelamiento de grandes sistemas es exitoso en la medida que se haga asesorar por una herramienta de modelamiento. UML (Unified Modeling Language) es un lenguaje de programación gráfico útil para la descripción de diferentes aspectos en la modelación de un sistema orientado a objetos, en donde se pueden representar clases, objetos y su relación.

Clases y Objetos

Una class (clase) es una estructura de programación en la que se pueden agrupar los datos de un objeto junto con los métodos que operan sobre ellos. En Ejemplo1, se declara una clase de nombre Empleado como Tipo, la que no posee métodos (por ahora). Formalmente una clase puede considerarse como una especificación 4-upla, por tener 4 componentes, en forma de variables con tipo y nombre. El modelo UML asociado a la clase, se muestra a continuación. En donde se han definido 4 atributos, dos de ellos pueden contener una cadena de caracteres (recordar que una cadena de caracteres es un objeto de la clase String), el otro es de tipo entero y finalmente un atributo de tipo boolean , el que puede ser verdadero o falso.

Ejemplo 1class Empleado { String apellido; String nombre; int rut; boolean esFemenino;}

Ingeniería en Computación, Universidad de La Seren

Términos técnicos en POO-Agente-Progr. Visual-dynamic binding

Características-Polimorfismo-Abstracción-Encapsulación-Persistencia

Mecanismos Básicos-Objeto-Mensaje y Métodos-Clase y Modelo-Herencia

138

Page 139: Libro Java

Empleado

Apellido: StringNombre: StringRut: intEsFemenino: boolean

objetoEmpleado: Empleado

Apellido: RojasNombre: LautaroRut: 73881706EsFemenino: false

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Cada componente de este tipo es una clase_instancia de la clase Empleado, usualmente llamada instancia (instance en Inglés), las que usualmente se conocen como objetos. Un objeto es una variable de la clase, intuitivamente un objeto es una entidad del mundo real, por otra parte como ya lo mencionabamos un objeto es una variable (del tipo) de la clase, y los programadores lo conocen como una instancia (es decir, una ejemplificación concreta) de la clase y por ende deberá contener todas las componentes que tenga la clase. En este caso todo objeto de la clase Empleado deberá tener ejemplares de las 4-variables, como lo muestra la figura anterior.

Para mayor información vea, http://java.sun.com/docs/books/tutorial/java/data/objects.html

Instancias de una Clase¿Cómo entender el enunciado “la clase será instanciada”?. La concepción de nuevas instancias en una clase se realizan sintácticamente a través de la palabra new, y la forma de cómo llegar a las variables que tiene la clase se logran a través de la creación de este nuevo objeto seguido de un punto(.).

Ejemplo 2

/*Incorpore Empleado.class a su directorio, o sino compile con el contenido de Empleado.java dentro de su archivo NuevaInstancia.java.*/

class NuevaInstancia {public static void main(String args[]){

Empleado m;// Instancia: creación de un nuevo Objeto

m = new Empleado();// forma de escribir sobre las Instancia-variable:

m.apellido = "Montes";m.nombre = "Hugo";m.rut = 11073;m.esFemenino = false;

// leer las Instancia-variable:System.out.println("Apellido: " + m.apellido);System.out.println("Nombre: " + m.nombre);System.out.println("Numero Personal: " + m.rut);System.out.println("Hablamos de: " + (m.esFemenino ? "Sra." : "Sr."));

// le ponemos un segundo Objeto:Empleado n = new Empleado();

Ingeniería en Computación, Universidad de La Seren 139

Page 140: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

n.apellido = "Rojo";n.nombre = "Maria”;n.rut = 865;n.esFemenino = true;}

}

ConstructoresAl crear la instancia de un objeto, el programa habitualmente asigna valores iniciales a sus elementos de datos. Para simplificar la inicialización de los elementos del objeto, Java soporta una función o método especial llamado constructor, que se ejecuta de forma automática al crear la instancia. La función contructora es un método público que tiene el mismo nombre de la clase.Es necesario tener en cuenta que: Un constructor tiene el mismo nombre que la clase, Un constructor siempre se llama con la palabra clave new,

Los constructores pueden tener ceros o más parámetros, Los constructores no devuelven ningún tipo en forma explícita. Por eso que la llamada a

constructores, como también los métodos con tipo de resultado void entregan el resultado en la forma " return;”.Veamos el siguiente ejemplo.

Ejemplo 3

class Empleado {String apellido;String nombre;int rut;boolean esFemenino;

// Declaración de un Constructor: Empleado(String nn, String vn, int pn, boolean w) { apellido = nn; nombre = vn; rut = pn; esFemenino = w; }}class EjemploConstructor { public static void main(String args[]){Empleado m,n;// Llamada al Constructor:m = new Empleado("Meyer", "Hans", 11073, false);n = new Empleado("Rojo", "Maria", 865, true);

// leer las Instancia-variable:System.out.println("Apellido: " + m.apellido);System.out.println("Nombre: " + m.nombre);System.out.println("Numero Personal: " + m.rut);System.out.println("Hablamos de:" +(m.esFemenino ? "Sra.": "Sr."));

}}

Ingeniería en Computación, Universidad de La Seren 140

Page 141: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Variables en la claseEn contrario a la instancia-variable existe también para una clase y para todo objeto de una clase un ejemplar, llamada variable de la clase, aún cuando la clase no tenga ninguna instancia. Esta variable es estática, y un ejemplo típico es un contador.

Ejemplo 4

class Empleado { String apellido; String nombre; int rut; boolean esFemenino;// una variable de la clase,inicializada por 0. static int contador = 0; Empleado(String nn, String vn, int pn, boolean w) {

apellido = nn;nombre = vn;rut = pn;esFemenino = w;contador++;}

}class EjemploContador { public static void main(String args[]){

System.out.println("Contador: " + Empleado.contador);Empleado m1 = new Empleado("Montes","Hugo",11073,false);System.out.println("Contador: " + Empleado.contador);Empleado m2 = new Empleado("Rojo", "Maria", 865, true);System.out.println("Contador: " + Empleado.contador);

}}

Clase como TipoLa clase Empleado puede variar, de manera que contenga una instancia-variable con nombre ascenso, que puede ser de tipo Empleado.

Ejemplo 5

class Empleado {String apellido;String nombre;int rut;boolean esFemenino;// una clase como tipo en una instancia-variableEmpleado ascenso;// Constructor:Empleado(String nn,String vn,int pn,boolean w,Empleado as) {

apellido = nn;nombre = vn;rut = pn;esFemenino = w;ascenso = as;

}}

Ingeniería en Computación, Universidad de La Seren 141

Page 142: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

class EjemploClasecomoTipo { public static void main(String args[]){

Empleado m, jefe; // una clase como tipo variable localjefe = new Empleado("Rojo", "Martin", 341, false, null);m = new Empleado("Meyer", "Hans", 11073, false, jefe);

}}

Expresiones para instanciarLas variables como Uds. notaron fueron inicializadas por:

Empleado jefe = new Empleado("Soto","Martin",341,false,null);Empleado m = new Empleado("Meyer","Juan",11073,false,jefe);

Otra expresión un tanto más sofisticada pero igualmente válida es:

Empleado m = new Empleado("Meyer", "Juan", 11073, false, new Empleado("Soto", "Martin", 341, false, null));

Es así como a través de los operadores = = y != pueden ser comparadas expresiones, tales como.

Ejemplo 6

class CompararObjetos { public static void main(String args[]){

Empleado m1=new Empleado("Soto","Martin",341,false,null);Empleado m2=new Empleado("Soto","Martin",341,false,null);boolean b = (m1 == m2); // b tendra el valor "false".System.out.println(b);b = (null != null); // b tendrá el valor "false".

}}

Métodos InstanciadosAl interior de una clase cada declaración sin la palabra static describe un método instanciado.

Ejemplo 7class Empleado {

String apellido;String nombre;int rut;boolean esFemenino;

// Constructor: Empleado(String nn, String vn, int pn, boolean w){

apellido = nn;nombre = vn;rut = pn;esFemenino = w;

}// un método Instanciado: void salida(){

Ingeniería en Computación, Universidad de La Seren 142

Page 143: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

System.out.print(esFemenino ? "Sra. " : "Sr. ");System.out.print(apellido + " ");System.out.print(nombre);System.out.println(" (Rut: " + rut + ")");

}}class EjemploMetodoInstanciado { public static void main(String args[]){

Empleado m1 = new Empleado("Soto", "Martin", 341, false);Empleado m2 = new Empleado("Barrios", "Petra", 865, true);// dos llamadas al método instanciado:m1.salida();m2.salida();

}}

La palabra clave thisAl trabajar con objetos, a veces es necesario hacer referencia al objeto de la clase en sí. Por ejemplo, un método de clase puede requerir pasarse a sí mismo otra función, de la misma forma, un método puede necesitar devolver el objeto en sí a la función que lo llama, de manera que el solicitante sepa que objeto está manipulando. En estos casos es posible utilizar la palabra this para hacer referencia al objeto en sí.

a)class Miembro {Miembro anterior;Miembro posterior; void ingreso(Miembro nuevo){

// pone "nuevo" detras de "this" en la cadena:if(nuevo != null){

this.posterior = nuevo; nuevo.anterior = this;

} }}

b)class Empleado {

String apellido;String nombre;int rut;boolean esFemenino;//Constructor:

Empleado(String apellido, String nombre, int pn, boolean w){this.apellido = apellido; // "this" es imprescindiblethis.nombre = nombre; // "this" es imprescindibleint rut;boolean esFemenino;this.rut = pn; // "this" es imprescindiblethis.esFemenino = w; // "this" es imprescindible

}}

Ingeniería en Computación, Universidad de La Seren 143

Page 144: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Métodos en las Clases Son como las variables en la clase, sin embargo es fácil darse cuenta de ella al reconocer la palabra clave static, también conocidos como métodos estáticos. Este tipo de método son globales que funcionan para la clase en general, y no solamente para una determinada instancia.

Ejemplo 8

class Empleado {String apellido;String nombre;int rut;boolean esFemenino;static int contador = 0; // Constructor:

Empleado(String nn, String vn, int pn, boolean w){apellido= nn;nombre = vn;rut = pn;esFemenino = w;contador++;}// 2 métodos en la clase:static int leerContador(){return contador;}static void imprimirContador(){System.out.print("Numero de Empleados: ");// llamada al metodo:System.out.println(leerContador());}

}class Ejemplometodo { public static void main(String args[]){ Empleado jefe = new Empleado("Soto", "Martin", 341, false); // llamada al metodo (con nombre de la clase): int a = Empleado.leerContador(); Empleado.imprimirContador(); }}

Implementando Estructuras de DatosUn importante campo de aplicación de la programación es la forma de estructurar los datos, una de las estructuras más conocidas sin duda son los arrays, colas, stack, listas etc. Sin embargo existen otras más complejas, como arboles y grafos. Con Java también es muy simple de implementarlas.

ListasEn teoría las listas pueden en contrario a los array aceptar muchos elementos y se pueden realizar operaciones que son más elegantes y eficientes que los arrays. Aquí se muestra un ejemplo de lista enlazada.

Ingeniería en Computación, Universidad de La Seren 144

Page 145: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Ejemplo 9

class Empleado {String apellido;String nombre;int rut;boolean esFemenino;

Empleado(String nn, String vn, int pn, boolean w){apellido= nn;nombre = vn;rut = pn;esFemenino = w;

}}

class ListaEmpleados {Empleado elemento;ListaEmpleado continua;// Constructor para Listas con un elemento:

ListaEmpleado(Empleado m){elemento = m;continua = null;

}// Constructor para Lista con más de un elemento:

ListaElemento(Empleado m, ListaEmpleado l){elemento = m;continua = l;

}}

class EjemploLista { public static void main(String args[]){

Empleado m1 = new Empleado("Soto", "Martin", 341, false);Empleado m2 = new Empleado("Barrios", “ Petra", 865, true);Empleado m3 = new Empleado("Meyer", "Hans", 11073, false);// Construcción de una lista con estos 3 Empleados:ListaEmpleado l = new ListaEmpleado(m1,new ListaEmpleado(m2, new ListaEmpleado(m3)));

}}

ArbolesEn teoría los árboles no son nada más que grafos sin ciclos, cuyos elementos relevantes son los vértices(nodos) y los lados(edges). Aquí se muestra un ejemplo de árbol de jerarquerización. Este es un caso particular para la implementación de cualquier tipo de árboles, en particular arboles binarios.

Ejemplo 10

class Persona {String apellido, nombre;Persona padre, madre;Persona(String apellido, String nombre, Persona padre, Persona madre){this.apellido = apellido;this.nombre = nombre;this.padre = padre;this.madre = madre;

Ingeniería en Computación, Universidad de La Seren 145

Page 146: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

} void salida(int e){

for(int s = e ; s > 0 ; s--) System.out.print(' ');System.out.println(vorname + " " + nachname);if( padre != null) padre.salida(e+4);if(madre != null) madre.salida(e+4);

}}class Arbolito { public static void main(String args[]){

Persona p =new Persona("Martin", "Schmidt",new Persona("Hans", "Schmidt", // padrenew Persona("Ulrich", "Schmidt", null, null), // padre del padrenew Person("Susanne","Schmidt", null, null)), // Madre del padre.new Person("Petra","Schmidt", // Madrenew Person("Josef", "Mayer" , null, null ), // Padre de la madre.new Person("Claudia","Mayer" , null, null))); // Madre de la madre.p.salida(0);

}}

Arboles AVL

Métodos de ConsultaAl igual que como se hizo para los árboles de búsqueda binaria podemos realizar consultas en un árbol AVL. A saber, Insertar y Eliminar, y otros métodos que no resultan tan directos como en los árboles de búsqueda binaria, por el problema de balanceo que se genera.

Ejemplos:Dado el siguiente árbol T de búsqueda binaria

8

4 10

2 6

1) En este árbol, son insertados los nodos con claves 9 y 11. Generándose el árbol T1 :

8

4 10

2 6 9 11

Ingeniería en Computación, Universidad de La Seren 146

Page 147: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

2) Basado en T, son insertados los nodos con claves 1, 3, 5 y 7. Generándose el árbol T2:

8

4 -2 10

2 -1 6

1

Ya al insertar la clave „1“ el árbol pierde la propiedad de AVL.. De aquí el aplicar una doble rotación. 4

2 8

1 6 10

Arbol obtenido luego de insertar las claves 3, 5 y 7.

4

2 8

1 3 6 10

5 7

La inserción de las claves „3“, „5“ y „7“ no hacen perder la propiedad AVL.

La propiedad de AVL se pierde si = +2 resp. -2. Esto se remedia mediante rotaciones.

Rotacionesa) Los árboles siguientes contienen los mismos elementos y son ambos árboles de búsqueda binaria. Primero, en ambos casos k1 < k2, segundo, todos los elementos en los subárboles X son menores que k1 en ambos árboles, tercero, todos los elementos en el subárbol Z son

Ingeniería en Computación, Universidad de La Seren 147

Page 148: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

mayores que k2. Finalmente todos los elementos en el subárbol Y están entre k1 y k2. La conversión de uno de ellos al otro se conoce como „Rotación simple“, que significa en lo substancial cambiar la estructura del árbol. Las figuras muestran también las variantes simetricas.

k2 k1

k1 k2 Z

Y X Y Z X

k1 k2

k2 k1

X

Y X Y Z

Z

Rotaciones Simples

Representación en Java

Un árbol AVL se representa de la misma manera que un árbol binario de búsqueda, esto es con nodos que contienen punteros a su padre y a sus hijos izquierdo y derecho, sin embargo, un nodo ahora debe almacenar un campo adicional que indica la altura o balance del nodo.

// Descripción de un nodo para un árbol AVLclass Nodo_Avl{ // Instancias protected Nodo_Avl izq; // hijo Izquierdo protected Nodo_Avl der; // hijo derecho protected int altura; // altura public Comparable datos; // elementos // Constructores public Nodo_Avl(Comparable datElem) { this(datElem, null, null );

Ingeniería en Computación, Universidad de La Seren 148

Page 149: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

} public Nodo_Avl( Comparable datElem, Nodo_Avl ib, Nodo_Avl db ) { datos = datElem; izq = ib; der = db; balance = 0; }}

/*Este método puede ser llamado solamente si k2 tiene un hijo izquierdo, realizando una rotación entre el nodo k2, tal como lo muestra la figura 7. Además, actualiza la altura, asignando la nueva raíz a k2.*/ private static Nodo_Avl RotacionSimpleIzq(Nodo_Avl k2) { Nodo_Avl k1 = k2.izq; k2.izq = k1.der; k1.der = k2; k2.altura = max( altura( k2.izq ), altura( k2.der ) ) + 1; k1.altura = max( altura( k1.izq ), k2.altura ) + 1; return k1; }

b) Existen situaciones en donde el desbalanceo es generado por un nodo que es insertado en el árbol que está contenido en el subárbol de el medio( es decir Y) y que al mismo tiempo como los otros arboles tienen idéntica altura. El caso es fácil de chequear y la solución es llamada “Rotación Doble”, la cual es muy similar a la rotación simple salvo que ahora se ven involucrados 4 subárboles en vez de 3.

k3 k2

k1 k1 k3

D k2 B C A A D B C

Rotación Izq-Der, Rotación Doble.

Ingeniería en Computación, Universidad de La Seren 149

Page 150: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

K3 k2

K1 k3 k1

A k2

D B C A D

B C

Rotación Der-Izq, Rotación Doble.

/* Rotación Doble, basada en Fig. 8: Este método solo puede ser usadosi k3 tiene hijo izquierdo y los hijos de k3 tienen hijo derecho. Esta rotación se conoce como rotación izq-der. Actualiza la altura, y su raíz.*/ private static Nodo_Avl DobleRotacionIzq_Der(Nodo_Avl k3) { /* Rotación entre k1 y k2*/ k3.izq = RotationSimpleIzq( k3.izq); return RotationSimpleDer( k3 ); }

Ingeniería en Computación, Universidad de La Seren 150

Page 151: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Ejemplo:

Ud. podrá verificar que cualquier desbalanceo causado por una inserción en un árbol AVL puede ser realizada por una Rotación Doble o Simple, (Ver (1)). Ahora, respecto a la eficiencia de esta TDA mencionemos que almacenar la información de la altura, que en este caso son suficientes con +1, 0 y –1, es de gran utilidadIngeniería en Computación, Universidad de La Seren 151

Page 152: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

/* Método para calcular la altura de un nodo en un árbol AVL. */ private static int altura( Nodo_Avl b) { return b == null ? -1 : b.altura; }

Entonces recordemos que para Insertar un nodo con la clave „x“ en un árbol AVL, el valor „x“ se inserta recursivamente en el subarbol correspondiente, tal como en los árboles de búsqueda binario. En el caso que la altura del subárbol no cambie, la inserción concluye. En caso contrario es necesario utilizar según sea el caso, Rotación Simple o Rotación Doble.

Implementación de la Inserción en los árboles AVL

Archivo Nodo_Avl.java

// Declaracion de la clase Nodos para los elementos en los arboles AVL.

class Nodo_Avl{ // Instancias protected Nodo_Avl izq; // hijo izquierdo protected Nodo_Avl der; // hijo derecho protected int altura; // altura public Comparable datos; // los datos como elementos del arbol avl // Constructores public Nodo_Avl(Comparable datElem) { this(datElem, null, null ); }

public Nodo_Avl( Comparable datElem, Nodo_Avl ib, Nodo_Avl db ) { datos = datElem; izq = ib; der = db; altura = 0; }}

Archivo Arbol_Avl.java

// Métodos Típicos para los Arboles de Busqueda Binaria// Constructor: Inicializar la raíz con null//// *** algunos métodos usuales para los arboles***// void insertar( x ) --> inserta x // void eliminar( x ) --> elimina x// Comparable hallar( x ) --> hallar un Elemento que corresponde a x// Comparable hallarMin( ) --> Entrega el Elemento más pequeño// Comparable hallarMax( ) --> Entrega el Elemento más grande// boolean esVacio( ) --> Return true si es vacio; else false// void hacerVacio( ) --> Eliminar todos// void printArbol( ) --> Salida de los datos en una sucesión ordenada// void salidaArbolBinario() --> Salida de los datos girados en 90 grados.

/*

Ingeniería en Computación, Universidad de La Seren 152

Page 153: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

* Comparaciones se basan en el método compareTo.(REPASAR) */ public class Arbol_Avl { /* Raiz del Arbol */ private Nodo_Avl raiz; /* * Constructor por defecto */ public Arbol_Avl( ) { raiz = null; } /* * Insertar: Duplicados son ignorados. * x es el dato a ser insertado. */ public void insertar(Comparable x ) { raiz = insertar( x, raiz ); } /* * Eliminar un nodo del Arbol. Caso que x no este, * nada ocurre. * Si x esta, es eliminado. */ //no esta la implementación...... /* * Determinar el elemento más pequeño en el arbol.. * Devuelve: el dato más pequeño o null, * en el caso que el arbol este vacio. * Analogamente se podría determinar el más grande elemento en el arbol */ //no esta implementado..... /* * Eliminar el arbol. */ //no esta implementado.... /* * Test, si el arbol esta vacio o no. * devuelve true, caso de vacio; sino false. */ public boolean esVacio( ) { return raiz == null; } /* * Entregar el contenido del árbol en una sucesion ordenada. */ public void printArbol( ) { if( esVacio( ) ) System.out.println( "Arbol vacio" ); else printArbol( raiz ); } /* * Salida de los elementos del arbol binario rotados en 90 grados */

Ingeniería en Computación, Universidad de La Seren 153

Page 154: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

public void salidaArbolBinario() { if( esVacio() ) System.out.println( "Arbol vacio" ); else salidaArbolBinario(raiz,0); } /* * Metodo interno para tomar un nodo del arbol. * Parametro b referencia al nodo del arbol. * Devuelve los elementos o null, * caso de b sea null. */ private Comparable elementAt(Nodo_Avl b ) { return b == null ? null : b.datos; } /* * Metodo Interno para agregar o insertar un nodo en un subarbol. * x es el elemento a agregar. * b es el correspondiente nodo raiz. * Devuelve la nueva raiz del respectivo subarbol. */ private Nodo_Avl insertar(Comparable x, Nodo_Avl b) { if( b == null ) b = new Nodo_Avl(x, null, null); else if (x.compareTo( b.datos) < 0 ) { b.izq = insertar(x, b.izq ); if (altura( b.izq ) - altura( b.der ) == 2 ) if (x.compareTo( b.izq.datos ) < 0 ) b = RotacionSimpleIzq(b); else b = RotacionDobleIzq_Der(b); } else if (x.compareTo( b.datos ) > 0 ) { b.der = insertar(x, b.der); if( altura(b.der) - altura(b.izq) == 2) if( x.compareTo(b.der.datos) > 0 ) b = RotacionSimpleDer(b); else b = RotacionDobleDer_Izq(b); } else ; // Duplicados; no hace nada b.altura = max( altura( b.izq ), altura( b.der ) ) + 1; return b; } /* * Metodo Interno para determinar el dato más pequeño. * b es la raiz. * Devuelve: Nodo con el elemento mas pequeño. */ private Nodo_Avl hallarMin(Nodo_Avl b) { if (b == null) return b; while(b.izq != null ) b = b.izq;

Ingeniería en Computación, Universidad de La Seren 154

Page 155: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

return b; } /* * Analogamente al anterior pero el más grande. */ private Nodo_Avl hallarMax(Nodo_Avl b ) { if (b == null) return b; while (b.der != null) b = b.der; return b; } /* * Metodo interno para determinar un dato. * x es el dato buscado * b es la raiz * Devuelve: Nodo con el correspondiente dato. */ private Nodo_Avl hallar(Comparable x, Nodo_Avl b) { while( b != null ) if (x.compareTo( b.datos) < 0 ) b = b.izq; else if( x.compareTo( b.datos ) > 0 ) b = b.der; else return b; // paso return null; // no paso nada } /* * Metodo Interno para devolver los datos de un subarbol en una sucesion ordenada. * b es la raiz. */ private void printArbol(Nodo_Avl b) { if( b != null ) { printArbol( b.izq ); System.out.println( b.datos ); printArbol( b.der ); } } /* * salida del arbol binario rotado en 90 Grados */ private void salidaArbolBinario(Nodo_Avl b, int nivel) { if (b != null) { salidaArbolBinario(b.izq, nivel + 1); for (int i = 0; i < nivel; i++) { System.out.print(' '); } System.out.println(b.datos); salidaArbolBinario(b.der, nivel + 1);

Ingeniería en Computación, Universidad de La Seren 155

Page 156: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

} } /* * Salida: altura de los nodos, o -1, en el caso null. */ private static int altura(Nodo_Avl b) { return b == null ? -1 : b.altura; } /* * Salida: Maximum entre lhs y rhs. */ private static int max( int lhs, int rhs ) { return lhs > rhs ? lhs : rhs; } /* * Rotacion Simple Izquierda(simetrica a Rotacion Simple Derecha). * Para los arboles AVL, esta es una de las simples rotaciones. * Actualiza la altura, devuelve la nueva raiz. */ private static Nodo_Avl RotacionSimpleIzq(Nodo_Avl k2) { Nodo_Avl k1 = k2.izq; k2.izq = k1.der; k1.der = k2; k2.altura = max( altura( k2.izq ), altura( k2.der ) ) + 1; k1.altura = max( altura( k1.izq ), k2.altura ) + 1; return k1; } /* * Rotación Simple Derecha. */ private static Nodo_Avl RotacionSimpleDer(Nodo_Avl k1) { Nodo_Avl k2 = k1.der; k1.der = k2.izq; k2.izq = k1; k1.altura = max( altura( k1.izq ), altura( k1.der ) ) + 1; k2.altura = max( altura( k2.der ), k1.altura ) + 1; return k2; } /* * Rotacion doble: primero hijo izquierdo con su hijo derecho * entonces nodo k3 con el nuevo hijo izquierdo. * para los arboles AVL, esta es una doble rotación * actualiza alturas, entrega nueva raiz. */ private static Nodo_Avl RotacionDobleIzq_Der(Nodo_Avl k3) { k3.izq = RotacionSimpleDer( k3.izq ); return RotacionSimpleIzq( k3 ); } /* * rotacion doble: primero hijo derecho * con su hijo izquierdo; luego nodo k1 con nuevo hijo derecho. * Para los AVL, esta es una doble rotación. * actualiza alturas, entrega nueva raiz. */ private static Nodo_Avl RotacionDobleDer_Izq(Nodo_Avl k1) { k1.der = RotacionSimpleIzq(k1.der);

Ingeniería en Computación, Universidad de La Seren 156

Page 157: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

return RotacionSimpleDer(k1); }}

archivo Arbol_AvlTest.java

public class Arbol_AvlTest{ // Programa Test public static void main(String [] args) { Arbol_Avl b1 = new Arbol_Avl(); Arbol_Avl b2 = new Arbol_Avl(); for (int i = 0; i < 7; i++) // { Integer r = new Integer(i); b1.insertar(r); } System.out.println("Arbol girado en 90 grados"); b1.salidaArbolBinario(); for (int i = 0; i < 10; i++) { // Genera un número entre 0 y 100 Integer r = new Integer((int)(Math.random()*100)); b2.insertar(r); } System.out.println("Arbol girado en 90 grados"); b2.salidaArbolBinario(); System.out.println("Travesia en Inorden(Izq-Raiz-Der)"); b2.printArbol(); }}Salida que se genera:

Arbol girado en 90 grados 0 1 23 4 5 6

Arbol girado en 90 grados 4 14 35 3952 64 74 75 77

Travesia en Inorden(Izq-Raiz-Der)4143539

Ingeniería en Computación, Universidad de La Seren 157

Page 158: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

5264747577

Interpretación de la salida

Arbol girado en 90 grados 0 1 23 4 5 6

La implementación de los árboles AVL, así como su salida están basados en los ejemplos y materiales entregados en (3).

3

1 5

0 2 4 6

Propuestas: Una mejora factible de considerar en la implementación del método insertar es considerar que los elementos a ingresar son String o caracteres, además de considerar el factor de balance y la nueva raíz que se obtiene. Como se muestra en el ejemplo siguiente.

caracter que desea insertar al arbol-AVL (Borrar: \n): a

a insertadoAVL con balanceo:a(0)

Caracter que desea insertar al arbol-AVL (Borrar: \n): b

b insertadoAVL con balanceo: b(0)a(1)

c insertadoAVL con balanceo: c(0)b(0) a(0)

Ingeniería en Computación, Universidad de La Seren 158

Page 159: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Jerarquia de Clases

Las clases que poseen la (o las) propiedad de la clase superior son descritas como subclases de la superclase. Ejemplo 11

class Alumno {String apellido;String nombre;boolean esFemenino;String carrera;byte semestre;// Constructor

Alumno (String apellido, String nombre, boolean,esFemenino, String carrera, byte semestre) {

this.apellido = apellido;this.nombre = nombre;this.esFemenino = esFemenino;this.carrera = carrera;this.semestre = semestre;}

}

Una clase puede a menudo ser especializada, de la misma manera que una superclase puede ser generalizada. Un ejemplo, para la especialización sería una clase Colaborador, la que asume una nueva propiedad traducida en una variable tarifa, incorporandosela a la clase Empleado.

Ejemplo 12

class Colaborador {String apellido; // copia de la clase EmpleadoString nombre; // copia de la clase Empleadoint rut; // copia de la clase Empleadoboolean esFemenino; // copia de la clase EmpleadoString tarifa;// trato preferencial??// ConstructorColaborador (String apellido, String nombre, int rut, boolean esFemenino,String tarifa) { this.apellido = apellido; this.nombre = nombre; this.rut = rut; this.esFemenino = esFemenino; this.tarifa = tarifa; }}

Importante: La clase Persona es también una superclase de la clase Colaborador, pero ella no es una superclase directa. En contrario, la clase Colaborador es una subclase ( o indirecta) subclase de la clase Persona. En general, entre una super y una subclase pueden existir muchas (sub- resp.super-)clases.

Ingeniería en Computación, Universidad de La Seren 159

Page 160: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Herencia

En Java la herencia es descrita a través de la palabra reservada extends, en general se tiene

class sub-clase extends super-clase{...}

La Herencia es una de las características más importantes de la POO. En su forma más simple, es el proceso de construir sobre una clase que ya está definida, extendiéndola de alguna forma. Cuando entiende cómo funciona la herencia, puede diseñar y derivar nuevas clases diferentes en forma sustancial a las clases existentes. La herencia proporciona acceso a la información contenida en cualquiera de las clases madre a lo largo de la cadena de herencia. Todas las clases que se escriben, excepto el caso especial de las interfaces, son de forma automática subclases de la clase raíz que incluye Java, llamada Object (objeto). Al crear una clase ya está usando la herencia, es así como este concepto permite a las subclases aprovechar las características de las clases que proporciona Java, las de otros programadores, proveedores y las creadas por el programador.

La mejor forma de visualizar la herencia es pensar en un árbol jerárquico. La siguiente figura muestra una jerarquía de clase básica, donde las clases inferiores se derivan de las superiores.Una subclase hereda todos los métodos y variables de todas sus clases madre. Al escribir una subclase derivada, es como si tecleara de nuevo todos los métodos y variables públicas existentes en las superclases. Desde luego, Java hace esto de forma automática, lo único que debe hacer es crear los métodos y variables nuevos o diferentes que requiere la nueva subclase y que sus clases madres no proporcionan.

A diferencia de otros lenguajes orientados a objetos, como C++, Java sólo permite derivar a partir de una clase madre. No se puede derivar una nueva subclase a partir de dos o más clases madre. La herencia múltiple es el proceso de derivar una clase a partir de dos o más superclases –y es una de las características que los diseñadores de Java dejaron fuera. Afortunadamente, como veremos en el siguiente tip, Java proporciona una alternativa mucho más transparente que la herencia múltiple, utilizando lo que Java llama interface. En la figura se muestra en flecha punteada el modelo de herencia múltiple, en el sentido que Juan no puede heredar de Gerente e Ingeniero.

Empleado

Ingeniero Gerente Secretaria

Juan Susana

Ingeniería en Computación, Universidad de La Seren 160

Page 161: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Ejemplo 13

// Empleado como subclase de Personaclass Empleado extends Persona {// componentes heredadas:directo de Persona: apellido, nombre, esFemenino.// nueva declaración de componente objeto:int rut;// constructorEmpleado (String apellido, String nombre, int rut, boolean esFemenino) {this.apellido = apellido;this.nombre = nombre;this.rut = rut;this.esFemenino = esFemenino;}void salida() {System.out.print(esFemenino ? "Sra. " : "Sr. ");System.out.print(nombre + " " + apellido);System.out.println(" (Rut: " + rut + ")");}}

// Alumno como subclase de Personaclass Alumno extends Persona {// componente heredada:// directamente de Persona: apellido, nombre, esFemenino// nueva declaración de componentes objeto:String carrera;byte semestre;// ConstructorAlumno (String apellido, String nombre, boolean esFemenino, String carrera, byte semestre) {this.apellido = apellido;this.nombre = nombre;this.esFemenino = esFemenino;this.carrera = carrera;this.semestre = semestre;}}

//Colaborador como subclase de Empleadoclass Colaborador extends Empleado {// componentes heredadas:// indirectamente de Persona: apellido, nombre, esFemenino// directamente de Empleado: rut, salida()// nueva componente Objeto:String tarifa;// constructorColaborador (String apellido, String nombre,int rut, boolean esFemenino, String tarifa) {

this.apellido = apellido;this.nombre = nombre;this.rut = rut;this.esFemenino = esFemenino;this.tarifa = tarifa;}

}

Ingeniería en Computación, Universidad de La Seren 161

Page 162: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Estos segmentos de programa se pueden visualizar a través de la siguiente figura dejando en claro el concepto de herencia o jerarquía.

Persona

Apellido : StringNombre: StringesFemen: boolean

Empleado alumnoRut : int carrera: StringSalida (·) Semestre: byte

Colaborador

Tarifa: String

Las variables instanciadas apellido, nombre y esFemenino están implícitamente declaradas en la subclase a través de la herencia. Ud. pueden notar que para colaboradores que realizan labor de investigación pueden de manera elegante a través de 2 superclases ser modeladas, a saber Colaborador y Academico.

De esta forma pueden varias clases tener sus propiedades en una o varias superclases, en tal caso se habla de Herencia Multiple. Java no permite (en contrario a C++) la herencia multiple, en la práctica significa que tras la llave extends puede ser incluida solamente una superclase.

Jerarquia de clases en Java

La clase Object pertenece a una de las clases estandares de Java, se encuentra en java.lang.Object, en términos generales se dice que la clase Object se encuentra en la raiz de la jerarquía de clases.

class Persona {...}//posee el mismo significado queclass Persona extends Object {...}

Ingeniería en Computación, Universidad de La Seren 162

Page 163: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Herencia y Constructores

class Alumno extends Persona {String carrera;byte semestre;// constructor general:Alumno(String apellido, String nombre, boolean esFemenino,String carrera, byte semestre) {// llamada a los constructores de "Persona" con "super":super(apellido, nombre, esFemenino);this.carrera = carrera;this.semestre = semestre;}// Constructor para alumno de Computación en I Sem:

Alumno (String apellido, String nombre, boolean esFemenino) {// llamada del constructor de "Alumno" con "this":this(apellido, nombre, esFemenino, "Computacion", 1);}}

Como ejemplo del uso de estas propiedades sería contar el número de todos los Empleados. Para eso la clase Empleado debería verse así.

Ejemplo 14

class Empleado extends Persona{static int numEmpleados = 0;int rut;// cambio del constructorEmpleado () {numEmpleados++;}// constructorEmpleado (String apellido, String nombre, int rut, boolean esFemenino) {super(apellido, nombre, esFemenino);numEmpleados++;this.rut = rut;}void salida() {System.out.print(esFemenino ? "Sra " : "Sr ");System.out.print(nombre + " " + apellido);System.out.println(" (Rut: " + rut + ")");}}

Es generada una instancia de la subclase Empleado, la que es declarada en la clase Empleado, de manera que el valor de numEmpleados entrega un objeto Empleado. La ausencia de parametros en el constructor Empleado permite que el número de instancias de las subclases sean llamadas.

Ingeniería en Computación, Universidad de La Seren 163

Page 164: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Dynamic Binding

Dynamic Binding es una característica común de los lenguajes orientados a objeto y se refiere al proceso de entrelazar un programa de forma que existan todas las conexiones apropiadas entre sus componentes, en rigor es una consecuencia de la puesta en práctica o realización del polimorfismo.

Polimorfismo

Polimorfismo es un término que se utiliza para describir una situación en donde un nombre puede referirse a diferentes métodos. En Java existen dos tipos de polimorfismo: el que ocurre en la sobrecarga y el que ocurre en el reemplazo.

El polimorfismo en la sobrecarga sucede cuando existen varios métodos dentro de una clase, todos ellos con el mismo nombre, lo cual está permitido siempre y cuando los métodos tengan diferente número o tipos de parámetros. Tener diferentes tipos de retorno no sirve al eliminar la ambigüedad de los métodos y no ayuda si se necesitan dos métodos con el mismo nombre y los mismos parámetros pero diferentes tipos de retorno. Al crear métodos de clase polimórficos y escribir código que acceda a ellos, Java determina cuál de los métodos debe llamar durante la compilación.

Por otra parte, al reemplazar métodos, Java determina cuál debe llamar al momento de ejecutar el programa, no durante la compilación. Para determinar qué métodos debe llamar, Java debe considerar no sólo los que están dentro de una clase, sino además los que están en las clases madres. El reemplazo ocurre cuando un método en una clase tiene el mismo nombre y firma (número, tipo y orden de los parámetros) que un método de una clase madre ( o superclase). En caso de que los métodos tengan el mismo nombre y firma, el método de la clase derivada siempre reemplaza al método de la clase madre.

Ejemplo 15

class EjemploPoli {public static void pago (Empleado empleado) {System.out.println("Empleado" + empleado.apellido + " recibe Pago.");}public static void main (String[] args) {Empleado empleado;// Polimorfismo empleado = new Colaborador("Meyer", "Hans", false, 1, "IIa");// Polimorfismo en la entrega de parametrospago(empleado);}}

Ingeniería en Computación, Universidad de La Seren 164

Page 165: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Sobreescritura de métodos

Ejemplo 16

class Colaborador extends Empleado {String tarifa;// sobreescritura de Metodovoid salida () {

System.out.print(esFemenino ? "Sra. " : "Sr ");System.out.print(nombre + " " + apellido);System.out.println(" Rut: " + rut);System.out.println(" Tarifa: " + tarifa);}

} class EjemploSobreescritura {

public static void main (String[] args) {Empleado m;m = new Empleado("Meyer", "Hans", false, 1);m.salida(); // llamada a salida() de la clase "Empleado"m = new Colaborador("Soto", "Martin", false, 2, "IIa");m.salida(); // llamada a salida() de la clase "Colaborador" }

}

Clases Abstractas y Métodos Abstractos

Al diseñar un programa en Java o cualquier otro lenguaje orientado a objetos, por lo general se inicia con una descripción de alto nivel de lo que se desea que haga el programa. Los lenguajes orientados a objetos facilitan el modelaje (o la representación) del problema que tiene que resolver el programa, ya que se pueden utilizar clases para representar las “cosas” que componen la solución.

Digamos que quiere comenzar con el modelaje de un Alumno y un Empleado y que crea clases para cada uno de estos modelos. Al desarrollarlas, quizá aparecerán características que son comunes a los Alumnos y a los Empleados. Por ejemplo, ambos hacen docencia en la Uni, entonces será necesario escribir un método (tal vez llamado docente) para cada uno. Java proporciona un tipo especial de clase, llamada clase abstracta, que puede ayudar a la organización de las clases basadas en métodos comunes. Una clase abstracta permite colocar los nombres de los métodos comunes en una sola clase (sin tener que escribir el código que los instrumente). Después, al crear nuevas clases como Alumno y Empleado, éstas pueden derivar de una clase abstracta que contiene una serie de métodos requeridos (docente, por decir algo).

Los métodos abstractos contienen sólo el nombre del método seguido de una lista de parámetros (esto también se conoce como firma). No contienen el código que instrumenta el método –esto se deja para las clases derivadas-, después. Otros puntos clave acerca de los métodos abstractos son:

Las clases que contienen métodos abstractos se conocen como clases abstractas. Un programa no puede crear instancias de una clase abstracta de forma directa, es

necesario crear instancias de sus subclases.

Ingeniería en Computación, Universidad de La Seren 165

Page 166: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Las clases abstractas pueden contener una mezcla de métodos abstractos y no abstractos (concretos). Los métodos concretos contienen la instrumentación del método.

Cualquier subclase que extienda a la clase abstracta debe proporcionar la instrumentación de todos los métodos abstractos. En caso contrario, la subclase misma se convierte en una clase abstracta.

Un ejemplo de método abstracto puede ser integrado en la clase Persona, con el nombre de método Ocupación(), la que para esta clase no es todavía realizada y por tal motivo se deja declarada como abstracta.

Ejemplo 17

abstract class Persona {String apellido;String nombre;boolean esFemenino;Persona () {}// constructorPersona (String apellido, String nombre, boolean esFemenino) {this.apellido = apellido;this.nombre = nombre;this.esFemenino = esFemenino;}// método Abstractoabstract void Ocupacion();}

Importante: Los métodos abstractos al igual como otros métodos son heredados.

class Empleado extends Persona {int rut;Empleado (String apellido, String nombre, int rut, boolean esFemenino) {super(apellido, nombre, esFemenino);this.rut = rut;}void salida() {System.out.print(esFemenino ? "Sra " : "Sr ");System.out.print(nombre + " " + apellido);System.out.println(" (Rut: " + rut + ")");}// sobreeescritura del método abstracto heredadovoid Ocupacion() {System.out.println("Trabajan");}}class Alumno extends Persona {String carrera;byte semestre;Student (String apellido, String nombre, boolean esFemenino, String carrera, byte semestre) {super(apellido, nombre, esFemenino);this.carrera = carrera;this.semestre = semestre;

Ingeniería en Computación, Universidad de La Seren 166

Page 167: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

}// sobreescritura del método abstracto heredado void Ocupacion() {System.out.println("Aprender");}}

Interfaces

En Java, una clase puede tener sólo una superclase (clase madre). Como ya vimos, puede crear nuevas clases derivándolas de clases existentes, heredando así las variables y métodos de la clase madre. Ésta es una técnica poderosa que permite agregar funcionalidad de forma creciente y al mismo tiempo mantener las clases tan sencillas como sea posible. Además, obliga a pensar bien el diseño de los programas y organizar su flujo.

Sin embargo, tal vez quiera derivar características de más de una clase madre, lo cual puede venir a raíz del problema que desea resolver, como representar la solución en términos de clases. Java no permite la herencia múltiple, es decir, la capacidad de derivar una nueva clase a partir de más de una clase existente. De cualquier modo, Java tiene una forma para declarar tipos especiales de clase que permite un número ilimitado de derivaciones. Las diferencias principales entre una interface y una clase son las siguientes:

Una interface, al igual que una clase abstracta, proporciona los nombres de los métodos pero no sus instrumentaciones.

Una clase puede instrumentar varias interfaces, ordenando de esta forma la restricción de herencia múltiple de Java.

Un programa no puede crear una instancia u objeto de una interface. Todos los métodos de una interface son implícitamente públicos y abstractos. Todas las variables de una interface son implícitamente públicas, estáticas y finales. No se

permite ningún otro tipo. La clase que instrumenta a la interface debe instrumentar todos los métodos, a menos que

sea declarada como abstracta. Una interface no tiene una clase padre antecesora (Object). En su lugar, las interface

tienen una jerarquía independiente que puede ser aplicada a cualquier parte del árbol de clases.

Ejemplo 18

public class Alumno extends Persona implements nombreEntidad{ private String matriculaNo;

public Alumno(String matriculaNo) { this.matriculaNo = matriculaNo; } //constructor

public String getMatriculaNo() { return matriculaNo; } //getMatriculaNo;

public boolean setMatriculaNo(String matriculaNo) { if (matriculaNo.compareTo("")==0)

Ingeniería en Computación, Universidad de La Seren 167

Page 168: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

{ this.matriculaNo = matriculaNo; return true; } else return false; } //setMatriculaNo()

public String getNombre() { return nombre; } //getNombre()

public boolean setNombre(String newNombre) { if (newNombre.compareTo("")!=0) { nombre = newNombre; return true; } else return false; } //setNombre() public String toString() { return("Nombre:"+this.getNombre()+"\nMatricula Numero: "+this.getMatriculaNo() ); } //toString()

public static void main(String[] args){ Alumno mario = new Alumno("0793022"); System.out.println( mario.getMatriculaNo() ); System.out.println("mario.toString()returns: \n"+mario.toString() ); mario.setNombre("Mario Jorquera"); System.out.println("mario.toString()returns: \n"+mario.toString() ); } //main()} //end class Alumnoclass Persona

{ String nombre;} //class Persona

interface nombreEntidad{ String getNombre(); boolean setNombre(String newNombre);} //interface nombreEntidad

Ingeniería en Computación, Universidad de La Seren 168

Page 169: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Modelamiento UML

Una interface agrega la flexibilidad de declarar un conjunto de métodos y variables que pueden ser instrumentados por cualquier clase en el árbol de jerarquía de clases. Otro uso que tienen las interfaces es proporcionar un conjunto de constantes a las que pueda accederse de forma directa con cualquier otra clase. Por ejemplo, las siguientes instrucciones muestras cómo definir una interfaz que defina un conjunto de constantes.

Importante: En contrario a la herencia normal puede una clase implementar varias Interfaces. Las interfaces al igual que las clases pueden ser utilizadas como tipo de dato. Ejemplo, dado una Interface Academico:

interface Academico {byte SIN_TITULO = 0;byte MAGISTER= 1;byte DOCTOR = 2;byte PROFESOR = 3;void titulo();}

Ahora si Ud. notan la clase Investigacion nos da una información extra sobre el curriculum del Academico dentro de la organización o Colaboradores. Es así como es posible tener:

class Investigador extends Colaborador implements Academico {byte titulo;Investigador (String apellido, String nombre, int rut, boolean esFemenino, int tarifa, byte titulo) {super(apellido, nombre, rut, esFemenino, tarifa);this.titulo = titulo;}void Ocupacion() {System.out.println("Investigar");}// Implementar el método abstracto void titulo() { switch(titulo) {

case MAGISTER:

Ingeniería en Computación, Universidad de La Seren

Persona

nombre: String

AlumnomatricNº: String

getNombre: StringsetNombre(String newNombre): booleangetMatricNº( ) : StringsetMatricNº(String newMN): boolean

nombreEntidad<<interface>>

getNombre( ) : StringsetNombre(String newNombre): boolean

169

Page 170: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

case DOCTOR:case PROFESOR:System.out.println("Titulo o grado");break;case SIN_TITULO:default:System.out.println("Sin Titulo");break;}

}}

PaquetesGeneralmente las clases e Interfaces en Java están subordinadas a paquetes, de manera que para utilizarlos significa darles en el encabezamiento del programa la “ruta” adecuada. Para generar nuestros propios paquetes se deben declarar a través de la declaración

package NombrePaquete;

Con esto, se verifica que toda clase e interface contenida en el programa pertenece a NombrePaquete.

// Declaracion de NombrePaquetepackage AdministracióndelPersonalclass Personal {String apellido;String nombre;boolean esFemenino;Personal () {}Personal (String apellido, String nombre, boolean esFemenino){

this.apellido = apellido;this.nombre = nombre;this.esFemenino = esFemenino;}

}

Declaración import

import NombrePaquete.Tiponombre;import NombrePaquete.*;

La primera declaración declara el paquete completo con todas sus clases e interfaces, de manera que durante la ejecución del programa el compilador deberá examinar la clase o paquete correspondiente y no todo su contenido, como se realiza en la segunda declaración

// Declaracion de NombrePaquetespackage AdministracióndelPersonal;// Importando la clase java.lang.Object// (Sin más ni más, siempre esta este paquete presente)import java.lang.Object;

Ingeniería en Computación, Universidad de La Seren 170

Page 171: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

class Persona extends Object {String apellido;String nombre;boolean esFemenino;Persona () {} Persona(String apellido, String nombre, boolean esFemenino) { this.apellido = apellido; this.nombre = nombre; this.esFemenino = esFemenino; }}

Java-Paquetes EstandarPara Java existe un gran conjunto de paquetes estandares, en donde las clases e interfaces para diferentes aplicaciones están a disposición.

java.lang: clases e interfaces fundamentales. java.io: Entrada y Salida de datos y filtros. java.net: soporte para redes (Sockets, URLs, ...) java.util: clases para diversas estructuras de datos, entre ellas, Listas, Stacks, Hash, fecha y hora. java.util.zip (desde Java 1.1): compresión de datos. java.text (desde Java 1.1): soporte para programas, que consideran diversas lenguajes y países (por

ejemplo: formato de salida para números, fecha u hora local). java.math: soporte para el manejo de números, exactitud, etc. java.beans (desde Java 1.1): soporta los llamados beans (en Java son componentes de software que

pueden ser reutilizados.) java.applet: clase que ayuda en la generación de Applets (programas Java, que se ejecutan bajo un

determinado Browser como parte de una página WWW). java.awt: popularmente llamada Abstract Windowing Toolkit (abrev. AWT), una colección de

clases e interfaces para las interfaces gráficas. java.awt.event (desde Java 1.1): una extensión de AWT. java.awt.image: Elaboración de imágenes. java.awt.peer: interfaces, que son significativas en la realización de AWT .

Programación Orientada a Objetos comparada con la Programación de Procesos y programación orientada a eventos.

Al comparar la programación orientada a objetos (POO) con la metodología tradicional de programación por proceso, puede ver que la primera proporciona un nuevo marco de referencia a través del cual se pueden estudiar los problemas de programación. En una metodología por proceso, se escriben funciones para resolver piezas de un problema. Si otro programador ha escrito funciones que resuelven problemas específicos, es posible, en un nuevo programa, utilizar (llamar) estas funciones. En la programación tradicional, el programador comúnmente ocupa más tiempo en las funciones que en el problema que debe resolver el programa.

Como ya hemos visto, la programación orientada a objetos proporciona una forma de ver los programas en función de los datos y los métodos que operan sobre ellos.. En la programación Ingeniería en Computación, Universidad de La Seren 171

Page 172: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

orientada a objetos, la atención se aleja de las funciones y se acerca a las cosas (objetos) que componen el programa. Las diferencias básicas entre la programación orientada a objetos y el enfoque de procesos pueden agruparse en cuatro principios básicos: abstracción, encapsulado, herencia y polimorfismo.

La abstracción es el proceso de ignorar temporalmente los detalles subyacentes al objeto, para centrar la atención en el problema u objeto y así extraer sus características esenciales. Por ejemplo, si se consideran los neumáticos de un auto, el neumático abstracto puede tener una marca, tamaño precio y una cantidad ideal de aire. Estas características se aplican a todos los neumáticos. Al utilizar la abstracción es posible centrar la atención sobre estas características cave (comunes), en lugar de hacerlo sobre los detalles de un tipo específico de neumático.Encapsular es el proceso de agrupar la información abstraída del objeto con las operaciones (métodos) que un programa puede realizar sobre los datos. Por ejemplo, una clase es el encapsulado de los datos y métodos de un objeto.

La herencia es un marco en el cual se pueden crear clases nuevas al introducir nuevas características o cambios a clases existentes. La herencia libera al programador de la tarea de rescribir funciones cuando se deben hacer pequeños cambios.

Finalmente, el polimorfismo es la habilidad que tiene un objeto de tomar diferentes formas. El prefijo poli significa “muchas”; morfismo “formas”. Por ejemplo, en un programa, un objeto polimorfo que represente un teléfono puede cambiar de forma para representar un teléfono de tonos, un teléfono de pulsos o incluso un teléfono celular.

Como puede notar algunos conceptos de la POO son análogos a los métodos de programación convencional, por ejemplo.

Un método es como un procedimiento porque ambos contienen instrucciones de procesamiento. Las variables de clase y modelo se correlacionan a los datos de la programación tradicional. Los métodos y datos son diferentes porque los procedimientos no están encapsulados normalmente con los datos que manipulan.

Una clase es como un tipo abstracto de datos, aunque para la POO, el proceso de escribir no se revela fuera de la clase.

La herencia no tiene analogía inmediata en la programación convencional.

El paso de mensajes reemplaza a las llamadas de función como método principal de control en los sistemas orientados a objeto. Con las llamadas de funciones, los valores se presentan y el control regresa a la función que efectúa la llamada. Por el contrario, los objetos entran en acción gracias a los mensajes, y el control está distribuido.

En resumen, la orientación a objetos se define por medio de un conjunto de mecanismos: objetos, clases y modelos, métodos y mensajes, y herencia. Estos mecanismos dan origen a conceptos clave inherentes a los sistemas orientados a objetos: encapsulación, abstracción y polimorfismo. Los mecanismos y conceptos de la orientación a objetos llevan esencialmente a

Ingeniería en Computación, Universidad de La Seren 172

Page 173: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

los programadores a escribir código en un nivel superior de abstracción. Asimilar las ideas orientadas a objetos significa aprender las diferencias así como las similitudes entre este método y la programación convencional.

Un ejemplo practico.

Algunas consideraciones para la propuesta de solución.

Pregunta.java: es una clase abstract que acoge los elementos comunes a todos los tipos de preguntas.  Debería contener:

una variable peso para el "peso" de la pregunta, además de métodos public getPeso() y setPeso() para esta variable.

una variable text para el texto de la pregunta, además de un método public getText() para esta variable.  El texto de la pregunta deberá ser "seteado" por constructores y nunca cambiado, de manera que Ud. no necesita un método set para ello.

un método abstract buscar(), que pedirá la pregunta, lee la respuesta del usuario y return un resultado boolean indicando si el usuario la respondió correctamente. También deberá imprimir un mensaje al usuario, llamando la atención de que el resultado a la pregunta fue correcto o no. Estudie la forma de definir las variables, es decir protected, private, u otra.

Ingeniería en Computación, Universidad de La Seren

Metas: a) Recrear los conceptos de la POO, vistos hasta ahora.b) Ganar habilidades en la creación y uso de una jerarquía de clases.

Descripción del Problema

Crear un sistema capaz de administrar un examen tipo cuestionario, basado en 3 tipos de preguntas. Se fijan entre ellas, preguntas del tipo

a) Verdadero/falso,b) Selección múltiple,c) Respuesta cortas.

Cada pregunta debe tener un puntaje o peso, el que representará el resultado del examen. Su propuesta deberá ser capaz de crear un pequeño examen, con tal vez 10 preguntas, y administrarlo en el sentido de dar respuestas a las distintas preguntas que se proponen pero en el contexto de la pregunta, ya sea del tipo a) , b) o c). Para finalmente reportar los resultados en porcentaje.

173

Page 174: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

/** * Una clase que representa una pregunta de un examen. * */public abstract class Pregunta { /** * El nº de puntos para las preguntas. Default es un punto. * es private en vez de protected , así la subclase son forzadas a usar * el metodo getPeso, y así prevenir pesos ilegales. */ private int peso = 1;

/** * texto de la pregunta. Todas las preguntas tienen un texto; la diferencia * esta en el tipo de respuesta y el método de chequear la respuesta. */

protected String text;

/** * Obtener el texto de esta pregunta. * * @return el texto de esta pregunta */ public String getText() { return text; } // end getText

/** * obtener el peso de esta pregunta * * @return el peso */ public int getPeso() { return peso; } // end getPeso

/** * setear el peso de esta pregunta * * @param wt el nuevo peso para esta pregunta. Debe ser mayor que cero, o el metodo imprime un * un mensaje de error y se sale el programa. */ public void setPeso(int wt) { if (wt <= 0) { System.out.println("Error: peso ilegal" + wt); System.exit(1); } else { peso = wt; } // end if } // end setPeso

/** * Busca el usuario la pregunta y chequea para ver si la respuesta dada es correcta * El metodo depende del tipo de pregunta, por eso es un metodo abstract. * * @return true si el usuario responde correctamente */ public abstract boolean buscar();

Ingeniería en Computación, Universidad de La Seren 174

Page 175: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

} // end class Pregunta

TFpregunta.java: Una extensión de la clase Preguntas, para preguntas del tipo true/false. Deberá contener:

un método concreto buscar(). La respuesta "legal" es  "t" o "T" para true, y "f" o "F" para false.  Si el usuario responde cualquier otro string que no sea lo antes dicho, deberá intentarlo otra vez, hasta cuando Ud. le diga Stop, y lo mande a estudiar, o bien comience con un nuevo Examen. Para tal efecto podrá importar otras clases para la lectura de los datos, como lo visto con Console, con hsa o con SavitchIn

una variable para registrar la respuesta correcta (true o false)

un constructor, que crea una pregunta true/false, dado el texto de la pregunta, la respuesta correcta, y el peso "peso". Algo así

/** * Preguntas v/f para un examen. * */public class TFpregunta extends Pregunta { /** * La respuesta correcta para esta pregunta. En este caso la respuesta es * boolean -- ya sea true o false. */ private boolean correctResp;

/** * Constructor: crea una pregunta true/false dado un textopara la pregunta, * la respuesta coorrecta, y el peso (nº de puntos). * * @param pregunta el texto para la pregunta * @param respuesta la respuesta correcta * @param wt el peso */ public TFpregunta(String pregunta, boolean respuesta, int wt) { text = pregunta; correctResp = respuesta; setPeso(wt); } // end constructor

/** * Busca el usuario la pregunta y chequea para ver si la respuesta dada es correcta * el usuario puede ingresar "t" o "T" para true, y * "f" o "F" para false. Si el usuario ingresa una respuesta * que no es ninguna de ellas este método se mantendrá hasta que de con ella * obteniendo un true para la resp. legal o false en otro caso. Cuando el usuario ingresa * una respuestaválida, prints un message estableciendo que la respuesta es correcta. * * @return true si el usuario responde correctamente */

Ingeniería en Computación, Universidad de La Seren 175

Page 176: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

public boolean buscar() { System.out.print(text + " (ingrese T o F): "); // obtener respuesta del usuario y tralada a to lower case String usuText = SavitchIn.readLine().toLowerCase(); if (usuText.equals("t")) { if (correctResp) { System.out.println("correcta!"); return true; } else { System.out.println("no, la respuesta es falsa"); return false; } // end if } else if (usuText.equals("f")) { if (!correctResp) { System.out.println("correcta!"); return true; } else { System.out.println("no, la respuesta es verdadera"); return false; } // end if } else { // respuesta no valida true/false System.out.println("Error: Ud. debe responder 'T' o 'F'. Trate otra vez."); return buscar(); // hacerlo otra vez } // end if } // end buscar

} // end class TFpregunta

Resp_Cortas_Pregunta.java: Una extensión de la clase Preguntas, para las respuestas cortas. El propósito, es que las respuestas cortas tienen solo una posible respuesta. Deberá contener:

un método concreto buscar() .  Comparando la respuesta del usuario a la respuesta correcta, use equalsIgnoreCase.

una variable para registrar la respuesta correcta (un String).

un constructor, que crea una respuesta corta a la pregunta, dado el texto de la pregunta, la respuesta correcta y el peso "peso".

/** * Para responder en forma muy escueta ante una pregunta, para un examen. * Este tipo de preguntas toma una respuesta que puede ser ingresada sobre una linea de entrada * */public class Resp_Cortas_Pregunta extends Pregunta { /** * La respuesta correcta para esta pregunta. En este caso, la respuesta es * un string -- el string exacto debe ser ingresado por el usuario. */

Ingeniería en Computación, Universidad de La Seren 176

Page 177: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

private String correctResp;

/** * Constructor: crea la pregunta y da un texto para la pregunta y la respuesta * correcta, ademas del peso (nº de puntos.). * * @param pregunta el texto para la pregunta * @param respuesta la respuesta correcta * @param wt el peso */ public Resp_Cortas_Pregunta(String pregunta, String respuesta, int wt) { // usa los dos parametros del contructor y setea el peso text = pregunta; correctResp = respuesta; setPeso(wt); } // end constructor

/** * Busca el usuario la pregunta y chequea para ver si la respuesta dada es * correcta. El usuario responde exactamente, excepto por mayusculas. * Prints un message estableciendo si la respuesta fue correcta. * * @return true si el usuario responde correctamente */ public boolean buscar() { System.out.print(text + ": "); String usuText = SavitchIn.readLine();

if (usuText.equalsIgnoreCase(correctResp)) { System.out.println("correcta!"); return true; } else { System.out.println("no, la respuesta correcta es " + correctResp); return false; } // end if } // end buscar

} // end class Resp_Cortas_Pregunta

Selec_Mul_Pregunta.java: Una extensión de la clase Preguntas, para las preguntas de selección múltiple.  Recordar que preguntas de selección múltiple deben tener al menos 2 elecciones.  Esta clase deberá contener:

un método concreto buscar() . Imprimirá la pregunta, seguida por las elecciones, identificándolas por letras 'a', 'b', 'c', etc.

una variable para registrar la elección (un array de Strings) y la respuesta correcta (un int -- es el index de la respuesta correcta en el array de elecciones).

un constructor que crea la pregunta de elección múltiple, dado el texto de la pregunta, el arrray de elecciones, la respuesta correcta y el peso "peso".

Ingeniería en Computación, Universidad de La Seren 177

Page 178: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

/** * preguntas de elección multiple para un examen. La respuesta puede tener cualquier nº de elecciones (al menos 2). * */public class Selec_Mul_Pregunta extends Pregunta { /** * La respuesta correcta para esta pregunta funciona como un * index en el array de elecciones. */ private int correctResp;

/** * el array de elecciones. */ private String elec[];

/** * Constructor: crea una pregunta de selección -multiple, con un peso dado. * * * @param pregunta el texto de la pregunta * @param eleArray un array de seleccion para la respuesta * @param respuesta la respuesta correcta (debe ser un index en el array anterior) * @param wt el peso */ public Selec_Mul_Pregunta(String pregunta, String eleArray[], int respuesta, int wt) { // chequea parametros para validar if (eleArray == null || eleArray.length < 2) { System.out.println("Error: preguntas de selección multiple necesitan al menos 2 elecciones"); System.exit(1); } else if (respuesta < 0 || respuesta >= eleArray.length) { System.out.println("Error: respuesta para selección multiple deben ser un index legal en el array de elección"); System.exit(1); } // end if

text = pregunta; correctResp = respuesta; elec = eleArray; setPeso(wt); } // end constructor

/** * Busca el usuario la pregunta y chequea para ver si la respuesta dada es correcta. * El usuario debe responder 'a', 'b', 'c', o 'd'. Si el usuario ingresa una respuesta, que no esta * este metodo le mandara un mensaje y lo intenta otra vez, hasta obtener la respuesta legal. * Cuando el usuario ingresa una respuesta valida prints un message estableciendo que la respuesta es correcta. * * @return true si el usuario responde correctamente */

public boolean buscar() { int numElec = elec.length; // nº de elecciones para esta pregunta

Ingeniería en Computación, Universidad de La Seren 178

Page 179: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

System.out.println(text + "?"); for (int i = 0; i < numElec; i++) { System.out.println(" " + (char)('a' + i) + ". " + elec[i]); } // end for System.out.print("ingrese la letra de su eleccion: "); // obtener la respuesta del usuario y la traslada a mayuscula String usuText = SavitchIn.readLine().toLowerCase();

if (usuText.length() != 1) { System.out.println("Error: por favor ingrese un caracter simple"); return buscar(); // repetir } // end if

// el usuario responde como un numero, con 'a' = 0, 'b' = 1, etc. int respIndex = usuText.charAt(0) - 'a'; if (respIndex < 0 || respIndex >= numElec) { System.out.println("Error: caracter ilegal"); return buscar(); // repetir } // end if

if (respIndex == correctResp) { System.out.println("correcta!"); return true; } else { System.out.println("no, la respuesta es " + elec[correctResp]); return false; } // end if } // end buscar

} // end class Selec_Mul_Pregunta

Exam.java: Es una clase que entrega una colección de preguntas para un examen dado. El examen parte vacío (no existen preguntas), y proporciona un método para agregar preguntas a un examen. Esta clase deberá contener:

Un array de preguntas.  Estudie la forma de limitar el nº límite de preguntas, por ahora cree un array de tamaño 10.

Un contador para el nº de preguntas en el array.

Un método agregaPregunta() , el que toma una pregunta (de cualquier tipo) como argumento y la agrega al examen.

Un método darExam() el cual administra el examen al usuario, con el fin de garantizar el nº de respuestas, con su porcentaje y el redondeo apropiado, como resultado.

/** * Un examen es una coleccion de preguntas. En este caso, un examen esta * implementado como un array de preguntas y tiene un tamaño maximo. */public class Exam { /** * El nº maximo de preguntas admitidas en un examen. */

Ingeniería en Computación, Universidad de La Seren 179

Page 180: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

public static final int MAX_PREGUNTAS = 10;

/** * El nº actual de preguntas actualmente en el examen. */ private int numPreguntas = 0;

/** * Las preguntas en el examen. */ private Pregunta lasPreguntas[] = new Pregunta[MAX_PREGUNTAS];

/** * Agrega una pregunta al examen. Si el examen ya esta lleno, * prints un mensaje de error y no hace nada. * * @param q la pregunta a agregar */ public void agregaPregunta(Pregunta q) { if (numPreguntas == MAX_PREGUNTAS) { System.out.println("Error: excede nº maximum de preguntas para el examen"); System.exit(1); } // end if lasPreguntas[numPreguntas] = q; numPreguntas++; } // end agrega Preguntas

/** * Administra el examen: busca todas las preguntas y entrega un puntaje * * @return el puntaje (en porcentaje) */ public int darExam() { int total = 0; // total de puntos en el examen int puntaje = 0; // buscar todas las preguntas for (int i = 0; i < numPreguntas; i++) { int peso = lasPreguntas[i].getPeso(); total += peso; if (lasPreguntas[i].buscar()) puntaje += peso; } // end for

// reporta el puntaje, if (total == 0) { return 0; } else { double razon = (double)puntaje / total; return (int)(razon * 100 + .5); } // end if } // end darExam

} // end class Exam

Ingeniería en Computación, Universidad de La Seren 180

Page 181: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

ExamDemo.java Es una clase testeadora capaz de ilustrar el trabajo de cada una de las clases antes definidas, y al mismo tiempo administrar una propuesta de examen, con una solución final.

/** * Un programa principal para testear. */public class ExamDemo { /** * Este programa principal crea un pequeño examen y lo administra, tal como se espera. */ public static void main(String args[]) { // crea un examen con un total de 10 puntos: 8 preguntas de un punto y una de dos puntos Exam miExam = new Exam(); miExam.agregaPregunta(new TFpregunta("La capital de Chile es Santiago", true, 1)); String santiagoElec[] = {"Santiago", "Valparaiso", "Concepcion", "Magallanes", "Arica"}; miExam.agregaPregunta(new Selec_Mul_Pregunta("Cuál es la capital de Region Metropolitana", santiagoElec, 0, 1)); miExam.agregaPregunta(new Resp_Cortas_Pregunta("Cuál es la capital de IV Region", "Coquimbo", 1)); miExam.agregaPregunta(new TFpregunta("La capital de Alberta es Calgary", false, 1)); String BCElec[] = {"Victoria", "Vancouver", "Nanaimo"}; miExam.agregaPregunta(new Selec_Mul_Pregunta("Cuál es la capital de British Columbia", BCElec, 0, 1)); miExam.agregaPregunta(new Resp_Cortas_Pregunta("Cuál es la capital de Argentina", "Buenos Aires", 1)); miExam.agregaPregunta(new Resp_Cortas_Pregunta("Cuál es la capital de Canada", "Ottawa", 2)); miExam.agregaPregunta(new TFpregunta("La capital de La Serena es Illapel", false, 1)); String PElec[] = {"Brasilia", "Rio de Janeiro", "Sao Paulo", "Blumenau"}; miExam.agregaPregunta(new Selec_Mul_Pregunta("Cuál es la capital de Brasil?", PElec, 0, 1));

// give the exam and report the score int puntaje = miExam.darExam(); System.out.println("su resultado es " + puntaje + "%"); } // end main} // end class ExamDemo

Ingeniería en Computación, Universidad de La Seren 181

Page 182: Libro Java

Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos

Salida:

Condiciones de error: deberán ser TODAS cauteladas, ya sea con excepciones o asserciones.

El programa principal o testeador es para fijar un estándar, no obstante si Ud. estima conveniente puede modificarlo.

Pauta de Corrección: (Total 70 ptos.)

correctness de las 4 clases:        15 ptos por clase(60), funcionando por separado.

testing (error de condiciones):     - 5 ptos al total. por cada ERROR.

style y documentation:    5 (deberán contener las pruebas y testing que se le realizó a su propuesta.)

Mapa de clases con UML documentación:    5 (Ir escogiendo alguna herramienta para el modelamiento, por ejemplo, ArgoUML, Poseidon u otra.)

Ingeniería en Computación, Universidad de La Seren 182

Page 183: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

C A P I T U L O 7

Eventos (Events)

La mayoría de los programas o aplicaciones comerciales responden a una amplia gama de acciones, tales como pulsar el mouse sobre un botón o pulsar una tecla de la consola. En todo caso existen otras acciones más sofisticadas, tales como cerrar windows, salvar un archivo etc. a lo que el usuario las utiliza una después de otra sin grandes dificultades. Ahora, el tipo de programas que abordaremos esta relacionada con este tipo de aplicaciones, es decir aquellas que son orientados al usuario. Java2 ofrece facilidades especiales para este propósito, en particular veremos como escribir programas que sean capaces de realizar este tipo de eventos o acciones, tales como presionar o pulsar el mouse sobre una porción de la pantalla o sobre un frame(marco), etc. Hoy en día existen herramientas que le facilitarán la vida, en términos de generar frames, textbox y otros, (por ejemplo, SUN One Studio, entre otros.), pero NO olvide que jamás podrá sustituir lo que Ud. realmente desea de la aplicación, a pesar de todo el código que pudo haber generado la herramienta. En resumen, siempre deberá entrar a manipular el código generado por la herramienta CASE, esto le responde el porque hemos empezado explicando y repasando los conceptos de POO, los que están íntimamente relacionados con los objetivos de manejar eventos.

Java proporciona una biblioteca de herramientas (o clases) denominada JFC (Java Foundation Classes), con el fin de diseñar herramientas Graphic User Interface (GUI), interfaces gráficas (es decir, ventanas con componentes, tales como etiquetas, cajas de texto, botones, barras de desplazamiento, etc.) Actualmente bajo esta denominación se agrupan varias APIs:

Swing. Conjunto de componentes escritos en Java para diseñar interfaces gráficas de usuario que se ejecutan uniformemente en cualquier plataforma nativa que soporta la máquina virtual de Java.

AWT (Abstract Window Toolkit - kit de herramientas de ventanas abstractas). Conjunto de componentes para diseñar interfaces gráficas de usuario común a todas las plataformas nativas. Este grupo ha sido sustituido en gran medida por el conjunto de componentes Swing; muchos de éstos heredan de sus correspondientes componentes AWT.

Java 2D. Permite incorporar en los programas, gráficos 2D de alta calidad, texto e imágenes.

Drag and Drop. Soporte para arrastrar y colocar. Permite la transferencia de datos entre aplicaciones mediante la simple operación de arrastrarlos hasta el lugar de destino.

¿Swing o AWT?. La gran diferencia entre los componentes Swing y los componentes AWT es que los primeros están implementados absolutamente con código no nativo lo que los hace independientes de la plataforma, razón que justifica sobradamente su utilización. Además Ingeniería en Computación, Universidad de La Seren 183

Page 184: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

proporcionan más capacidades que los componentes AWT. Los componentes Swing se pueden identificar porque su nombre empieza por J; por ejemplo, el componente AWT Button tiene su correspondiente componente Swing JButton. Los componentes AWT se localizan en el paquete java.awt y los componentes Swing en el paquete javax.swing.Las herramientas para construir GUIs en Java pueden realizarse con Applets o a través de las aplicaciones, sin embargo los applets tienen serias rectricciones respecto del acceso al disco para nombrar o rescribir un archivo. Notar un dato importante, todos los componentes Swing son subclases de la clase JComponent.

EventosPara diseñar interfaces gráficas (llámese ventanas con componentes, cajas de texto, botones, barras de desplazamiento) java proporciona una biblioteca de clases llamada JFC (Java Foundation Classes), que cobija a Swing, AWT, Java 2D y otras API’s. Swing o AWT?. La gran diferencia entre los componentes es que los primeros están implementados absolutamente con código no nativo lo que los hace independiente de la plataforma, además proporciona más capacidades que AWT. Los componentes de AWT se ubican en java.awt, mientras que los componentes de Swing se ubican en javax.swing. En todo caso todos los componentes Swing son subclases de la clase JComponent. Los programas en Java pueden reaccionar a un amplio rango de acciones orientadas al usuario. Por ejemplo, pulsar el mouse sobre la pantalla, ajustar los bordes del window, tipear un key sobre la consola y muchas otras. Cada una de estas acciones son llamados eventos.

Ejemplo 1

import javax.swing.*;import java.awt.*;import java.awt.event.*;

public class AplicacionSwing extends JFrame{ // Referencias a los componentes private JLabel etiqueta; private JButton botón;

// Otras referencias private static String mensaje = "¡¡¡Hola mundo!!!";

private AplicacionSwing(String título) { // constructor super(título); // título de la ventana principal iniciarComponentes(); // Ajustar el tamaño de la ventana al mínimo pack(); }

private void iniciarComponentes() { // Crear una etiqueta con el texto centrado etiqueta = new JLabel(); etiqueta.setHorizontalAlignment(JLabel.CENTER); // Crear un botón botón = new JButton("Haga clic aquí"); // Establecer como tecla aceleradora la C. Entonces, pulsar Alt+C // será equivalente ha hacer clic, sobre el botón. botón.setMnemonic(KeyEvent.VK_C); // Asignar al botón una descripción abreviada

Ingeniería en Computación, Universidad de La Seren 184

Page 185: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

botón.setToolTipText("botón de pulsación"); // Permitir que el botón responda a los eventos de acción ActionListener al = new ActionListener() { // Este método se ejecutará cuando se haga clic en "botón" public void actionPerformed(ActionEvent evento) { Object obj = evento.getSource(); if (obj == botón) mostrarMensaje(); } }; botón.addActionListener(al);

// Crear un panel para colocar los controles JPanel panel = new JPanel(); // Introducimos un borde sin pintar alrededor de los controles: // createEmptyBorder(top, left, bottom, right) panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); // Establecer un administrador de diseño de cuadrícula panel.setLayout(new GridLayout(0, 1)); // Los controles se añaden en columna (filas = 0) panel.add(etiqueta); panel.add(botón);

// Añadir los componentes al contenedor de la aplicación getContentPane().add(panel, BorderLayout.CENTER);

// Permitir que la ventana de la aplicación responda a los // eventos de ventana (p.e. cerrar la ventana) addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent evento) { cerrarVentana(); } } ); }

private void mostrarMensaje() { // Mostrar el "mensaje" en la "etiqueta" etiqueta.setText(mensaje); }

private void cerrarVentana() { // Salir de la aplicación System.exit(0); }

public static void main(String[] args) { try { // Aspecto y percepción de la interfaz gráfica, look and feel UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName()); } catch (Exception e) { System.out.println("No se pudo establecer el aspecto deseado: " + e);

Ingeniería en Computación, Universidad de La Seren 185

Page 186: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

} AplicacionSwing vPpal = new AplicacionSwing("Aplicación Swing"); vPpal.show(); }}

Ud. puede observar que cuando pulsa el botón la etiqueta muestra el mensaje ¡¡¡Hola Mundo!!!, más aún, en ella se puede observar que el botón puede activarse, además de un clic sobre el mouse, puede utilizarse las teclas aceleradoras Alt+C, y que tiene asociada una breve descripción.

Ejemplo 2

import java.awt.*;import java.awt.event.*;import javax.swing.*;

class ButtonPanel extends JPanel implements ActionListener { public ButtonPanel() {

amaButton = new JButton("Amarillo"); azulButton = new JButton("Azul"); rojoButton = new JButton("Rojo");

add(amaButton); add(azulButton); add(rojoButton);

amaButton.addActionListener(this); azulButton.addActionListener(this); rojoButton.addActionListener(this); }

public void actionPerformed(ActionEvent evt)Ingeniería en Computación, Universidad de La Seren

Marco

Panel

Etiqueta

Botón

186

Page 187: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

{ Object source = evt.getSource(); Color color = getBackground(); if (source == amaButton) color = Color.yellow; else if (source == azulButton) color = Color.blue; else if (source == rojoButton) color = Color.red; setBackground(color); repaint(); }

private JButton amaButton; private JButton azulButton; private JButton rojoButton; }

class ButtonFrame extends JFrame{ public ButtonFrame() { setTitle("Y mas Botones..."); setSize(300, 200); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } );

Container contentPane = getContentPane(); contentPane.add(new ButtonPanel()); }}

public class ButtonDemo{ public static void main(String[] args) { JFrame frame = new ButtonFrame(); frame.show(); }}

Ingeniería en Computación, Universidad de La Seren 187

Page 188: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

Cuando se crean eventos, Java crea un objeto evento para representarlo. El tipo de objeto que es producido depende del orden del evento. Por ejemplo, el objeto evento que se crea para cuando pulsa el mouse pertenece a la clase MouseEvent. Existen varias otras acciones que producen objetos MouseEvent: el botón izquierdo del mouse ha sido presionado etc, o sobre el teclado con keyEvent.

Una vez que ha creado el objeto de evento, Java lo pasará a un método que ha sido escogido para tratarlo como un tipo particular de evento. El método se llama event listener, (método que escucha), este método debe ser capaz de contestar apropiadamente la acción que el usuario demanda o requiere, pero para eso debió haber escogido el o los métodos apropiados. Los métodos listener tienen nombres especiales que indican el tipo de evento a los que ellos responden. Por ejemplo, un método que escucha que se ha pulsado el mouse debe responder a este evento llamado mouseClicked, si es una tecla el evento asociado es keyTyped, y así sucesivamente. (Una lista completa de sus nombres aparece a la parte final de estas notas.) Cada método que escucha tiene un solo parámetro que es el objeto de evento que representa el evento al que él está respondiendo. La vida de un programa interactivo simple, la dividiremos en dos fases.

Ingeniería en Computación, Universidad de La Seren 188

Page 189: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

Fase de la estructuración. Esto puede involucrar el crear una GUI para el programa, y variables de inicialización.

Fase interactiva. Durante esta fase, el programa está esperando por los eventos comenzados por el usuario, de manera que en cuanto uno ocurra, el método correspondiente que escucha obedece. Si no hay ningún evento, el programa se “sienta” y espera hasta que otro evento venga. En general esta fase se reconoce por estar involucrados declaraciones del tipo

public class MiPanel extends JPanel implements ActionListener

Si un método listener no completa su tarea lo bastante rápida, el próximo evento puede ocurrir antes de que este último haya terminado. Para manejar esta posibilidad, todos los objetos eventos se agregan a una cola de prioridades, esto se llama cola de despacho de evento (event dispatching queue). Apenas un método listener ha terminado el proceso de un evento, el próximo evento (si hay uno) en la cola se pasa al método que escucha.

GUI Minimo-Minimorum:Usualmente un programa GUI consiste de una Interface, event listener y códigos de aplicaciones. Nuestro primer programa GUI adolece de listener, pero esto no será lo usual.

import java.awt.*; // import la clase AWTpublic class ejGUI1 {public static void main ( String[] args ) // usual start de una aplicación y no de un Applet!! {

Frame frm = new Frame();//construye objeto Frame, no un Applet! frm.setSize( 150, 100 );// setea a 150 pixeles ancho y 100 altofrm.setVisible( true ); // lo hace visible, sino debe ser false.

}}

Si Ud. lo ejecuto habrá notado que no tiene un event listener, pues no responde por ejemplo para cuando Ud. desea cerrar el frame, veremos como lograrlo a través de una declaración que incluye una expresión del tipo frm.addWindowListener( wquit);. Más simple aún es el siguiente programa, que en realidad no hace absolutamente nada, en realidad teoricamente crea un window, pero nunca es posible de ver el screen.

import javax.swing.*; // import la clase swingpublic class MiniSwing1 { public static void main(String args[]) { JFrame miFrame = new JFrame(); } // end main} // end class MiniSwing1

Más simple aún a los programas anteriores es el siguiente, que en realidad muestra una barra solamente, sin dimensión para el frame.

import javax.swing.*;

Ingeniería en Computación, Universidad de La Seren 189

Page 190: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

public class MiniSwing2 { public static void main(String args[]) { JFrame miFrame = new JFrame(); miFrame.setVisible(true); } // end main} // end class MiniSwing2

Como podrá haber notado, hay que otorgarle un crédito al método setSize, pues ayudo a cambiar el tamaño del frame sobre su pantalla, incluso durante su ejecución, como lo muestra el siguiente ejemplo, pero sigue siendo un problema que el frame aparezca en la esquina superior-izquierda de su pantalla.

import java.awt.*;public class ejGUI2{ public static void main ( String[] args ) { Frame frm = new Frame(); int ancho = 20; int alto = 10; frm.setVisible( true ); for ( int cont=1; cont<300; cont++ ) frm.setSize( ancho++, alto++ ); }}

Otra gracia que presenta la POO como ya lo hemos adelantado es el de poder extender la clase incorporandole nuevas propiedades, como por ejemplo, un mensaje. Notar que se incorpora el método paint(), la tarea de éste método consiste en dar las medidas del área de despliegue. Ahora para lograrlo, hace uso de un objeto Graphics2D, que tiene su semejanza al System.out para cuando se enviaban cadenas de caracteres a la pantalla de la consola. El objeto Graphics tiene a su vez un método llamado drawString(), que se usa para desplegar texto, como muestra el siguiente ejemplo.

import java.awt.*; class miFrame extends Frame { public void paint ( Graphics g ) { g.drawString("Un objeto MiFrame", 10, 50 ); //escribe un string en el Frame con x=10 y=50 }}public class ejGUI3 { public static void main ( String[] args ) { miFrame frm = new miFrame(); frm.setSize( 150, 100 ); frm.setVisible( true ); }}

Ud. habrá notado que no le hemos puesto nombre al frame o a la barra del frame, ahora verá una propuesta.

import javax.swing.*;public class MiniSwing4 { public static void main(String args[]) { JFrame miFrame = new JFrame(); miFrame.setSize(200, 100);

Ingeniería en Computación, Universidad de La Seren 190

Page 191: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

miFrame.setTitle("Titulando los frames"); // lo nuevo. miFrame.setVisible(true); } // end main} // end class MiniSwing4

Vamos a lo prometido, me refiero a tratar de cerrar el frame para cuando pulsemos el cierre de ventana del frame que se ha creado, siendo este otro ejemplo de cuando realizar o gatillar un evento.

import java.awt.*; import java.awt.event.*;class miFrame extends Frame { public void paint ( Graphics g ) { g.drawString("Click el boton de cierre", 10, 50 ); }}class WindowQuit extends WindowAdapter { public void windowClosing( WindowEvent e ) { System.exit( 0 ); // exit del programa }}public class GUItester { public static void main ( String[] args ) { miFrame frm = new miFrame(); WindowQuit wquit = new WindowQuit(); // construye un listener para frame frm.addWindowListener( wquit ); // registra el listener con el frame frm.setSize( 150, 100 ); frm.setVisible( true ); }}

A continuación se presenta la misma estructura, pero en un estilo muy particular, poco didáctico a mi entender, en donde se crea una clase anónima. En todo caso una explicación extensa sobre el particular aparece en Horstmann, CoreJava2, Volumen 1, pág. 327-330.

import javax.swing.*;import java.awt.event.*;

//se usa una clase interna anonima para crear el window listener.public class MiniSwing7 { public static void main(String args[]) { JFrame miFrame = new JFrame(); miFrame.setSize(200, 100); miFrame.setTitle("Baby Swing Program"); miFrame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } // end windowClosing } // end clase anonima ); miFrame.setVisible(true); } // end main} // end class MiniSwing7

Ingeniería en Computación, Universidad de La Seren 191

Page 192: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

El evento de capturar el cierre de windows es uno de los tantos eventos que se analizarán, dentro de un contexto de una estructura que pretende ser estandar.

Estuctura de una Aplicación Swing.

Convengamos en que una aplicación Swing que muestra una interfaz gráfica para cuando se ejecuta no es más que un objeto de una clase derivada de JFrame. Basado en lo anterior, el código mostrado a continuación puede ser una “propuesta válida” para la mayoría de las aplicaciones que inician su ejecución visualizando una ventana principal:

import javax.swing.*; import java.awt.event.*;public class estrucFrame extends JFrame {

public estrucFrame() { super("Titulo de la Aplicacion"); // Aquí, agrega los componentes. } public static void main(String[] args) { JFrame miframe = new estrucFrame();

WindowListener l = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; miframe.addWindowListener(l); miframe.pack(); miframe.setVisible(true); }}

A manera de comentario, digamos que esta aplicación es una subclase de JFrame y todo el trabajo involucrado en la creación de la interfaz de usuario del frame(o marco) se realiza en el método constructor estrucFrame(). Con el método super(cadena); se pretende proporcionar el texto para la barra de título del marco. Luego la interfaz de usuario deberá construirse dentro de este constructor; aquí se pueden agregar los componentes a los contenedores, y estos últimos al marco.

public estrucFrame() { super("Titulo de la Aplicacion"); // Aquí, agrega los componentes. }

Dentro de main() se usa el constructor estrucFrame() para crear una nueva instancia que le llame miframe, de la clase JFrame, la que será la ventana principal de la aplicación. Notar que el nombre del archivo es estructFrame.java.

JFrame miframe = new estrucFrame();

Este código es casi estandar dentro del manejo de eventos, y lo que hace es manejar la tarea de cerrar la aplicación para cuando se cierre el marco o pulse con el mouse sobre la porción cierre de ventana en el marco que se genero. Recordar que dentro del sistema de manejo de eventos

Ingeniería en Computación, Universidad de La Seren 192

Page 193: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

de Java2, si una clase desea responder a un evento de usuario debe implementar las interfaces que maneja los eventos. Estas interfaces se llaman escuchadores de eventos, una de ellas es WindowListener.

WindowListener l = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; miframe.addWindowListener(l);

/* recordar que después de crear un componente y poder asociarle un listener se necesita llamar a los métodos del componente, en este caso addWindowListener(l), es decir llama a todos los componentes JWindow y JFrame;*/

La siguiente declaración llama al método pack() del marco y lo redimensiona al tamaño más pequeño para que contenga todos sus componentes. Usando pack() Ud. se asegura que podrá agregar componentes (nos referimos Button u otros) al marco con la certeza que habrá espacio suficiente para ellos. En general el método pack de la ventana objeto JFrame, redimensiona la ventana al tamaño más pequeño posible que permita contener a todos los componentes que se hallan “incrustado”. Nosotros lo veremos en la próxima lectura, de cómo hacerlo.

Volviendo al código, digamos que ésta última declaración hace visible el marco a través de su método setVisible(bolean). Si el argumento hubiese sido false, el marco se haría invisible (oculto) como ya se pudo dar cuenta.

miframe.setVisible(true);

Al ejecutarlo no vera nada super-extra-especial, sino solamente esto.

Ahora para darle el tamaño que Ud. desee al windows, reemplace la línea miframe.pack() por miframe.setSize(400, 120); por ejemplo

Ingeniería en Computación, Universidad de La Seren 193

Page 194: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

Notar la importancia de la POO y su aplicación a los eventos. Esto es, la aplicación se ejecuta y queda a la espera de las acciones que pueda emprender el usuario de la misma. En el ejemplo tan simple que acabamos de presentar, la única acción que puede tomar el usuario es cerrar la ventana, por ejemplo, haciendo clic en el botón cerrar, lo que origina el evento correspondiente ¿Cómo responde Java a este evento? Ejecutando el método windowClosing asociado con él de forma predeterminada. Por lo tanto, nosotros podemos redefinir este método y programar las acciones a tomar; en este caso, “salir” del sistema con

System.exit(0). Es evidente, que se pueden producir otros eventos; por ejemplo: la ventana se abre, se minimiza, vuelve a su estado normal, etc. Lo que tiene que saber es que Java siempre responderá a cada evento invocando a su método asociado. Lógicamente esa tarea hay que programarla y para poder hacerlo hay que saber cómo manejar ese evento. Según ha podido ver anteriormente, los eventos se manejan a través de un conjunto de métodos predeterminados en todos los componentes, que pueden ser frame, panel, etiquetas, botón y otros. Pero para que un componente pueda responder a los eventos que sobre él pueden ocurrir, tiene que tener asociado el manejador o escuchador de esos eventos. Java 2 proporciona varios manejadores o escuchadores de eventos, como se muestran en la tabla.

Ingeniería en Computación, Universidad de La Seren 194

Page 195: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

Tabla Resumen de trato a los Eventos

Interface Metodos Parametros/Accesos Eventos generados por

ActionListener

actionPerformed ActionEvent Button

getActionCommand ListgetModifiers MenuItem

TexFieldAdjustamentListener adjustmentValueChan

gedAdjustmentEvent Scrollbar

getAdjustablegetAdjustmentTypegetValue

ItemListener itemStateChanged ItemEvent CheckboxgetItem CheckboxMenuItemgetItemSelectable ChoicegetStateChange List

TextListener textValueChanged TextEvent TextComponent

ComponentListener componentMoved ComponentEvent ComponentcomponentHidden getComponentcomponentResizedcomponentShown

ContainerListener conponentAdded ContainerEvent Container

componentRemoved getChildgetContainer

FocusListener focusGained FocusEvent ComponentfocusLost isTemporary

KeyListener keyPressed KeyEvent ComponentkeyReleased getKeyCharkeyTyped getKeyCode

getKeyModifiersTextgetKeyTextisActionKey

MouseListener mousePressed MouseEvent ComponentmouseReleased getClickCountmouseEntered getXmouseExited getYmouseClicked getPoint

translatePointisPopupTrigger

MouseMotionListener mouseDragged MouseEvent ComponentmouseMoved

WindowListener windowClosing WindowEvent WindowwindowOpened getWindowwindowIconifiedwindowDeiconifiedwindowClosedwindowActivatedwindowDeactivated

Ingeniería en Computación, Universidad de La Seren 195

Page 196: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

La jerarquía de clases se visualiza así:

Jerarquía de los EventListener-Interfaces.

Ingeniería en Computación, Universidad de La Seren 196

Page 197: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

Método para el Mouse Significado

mouseClicked Un sensor del Maus fue pulsado y luego dejado.

mouseEntered El puntero del Maus ocupa la Componente.

mouseExited El puntero del Maus abandona la Componente.

mousePressed Un sensor del Maus fue pulsado.

mouseReleased Un sensor del Maus fue soltado.

ActionListener. Permite a un componente responder a las acciones que ocurren sobre él; por ejemplo, un clic sobre un botón. Este manejador se puede asociar con componentes JButton, JTextField, JCheckBox, JRadioButton y JComboBox, invocando al método addActionListener.

AdjustmentListener. Permite a una barra de desplazamiento responder a las acciones que se producen sobre ella. Este manejador se puede asociar con JScrollBar, invocando al método addAdjustmentListener.

ItemListener. Permite a un componente responder a los cambios que se producen al actuar sobre él; por ejemplo, cuando se selecciona una casilla de verificación. Este manejador se puede asociar con componentes JButton, JCheckBox, JRadioButton y JComboBox, invocando al método addItemListener.

KeyListener. Permite a un componente responder a las acciones procedentes del teclado. Este manejador se puede asociar con todos los componentes, invocando al método addKeyListener.

MouseListener. Permite a un componente responder a las acciones del ratón: pulsar y entrar o salir en un área del mismo. Este manejador se puede asociar con todos los componentes, invocando al método addMouseListener.

MouseMotionListener. Permite a un componente responder a los movimientos del ratón. Este manejador se puede asociar con todos los componentes, invocando al método addMouseMotionListener.

WindowListener. Permite a una ventana responder a las acciones que ocurren sobre ella; por ejemplo, minimizarla, abrirla, moverla, etc. Este manejador se puede asociar con componentes JFrame y JWindow, invocando al método addWindowListener.

En el siguiente programa se ejemplifica en detalle cada uno de los métodos, usando window listener que captura y reporta sobre todos los eventos del window.

Ingeniería en Computación, Universidad de La Seren 197

Page 198: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

Interface Metodos Parametros/Accesos Eventos generados por

WindowListener windowClosing WindowEvent WindowwindowOpened getWindowwindowIconifiedwindowDeiconifiedwindowClosedwindowActivatedwindowDeactivated

Como ya se ha mencionado, en Java cualquier clase que implementa una interface, por ejemplo WindowListener debe implementar TODOS los métodos. En este caso, se deben implementar los 7-métodos.

Instrumentalizando la interface WindowListener

import javax.swing.*;import java.awt.event.*;

public class MiniSwing5 {

public static void main(String args[]) { JFrame miFrame = new JFrame(); miFrame.setSize(200, 100); miFrame.setTitle("Programa de Reporte"); miFrame.addWindowListener(new WindowReporter()); // nuevo miFrame.setVisible(true); } // end main

} // end class MiniSwing5

/** * Un window listener que reporta todos los eventos window a la consola. */ class WindowReporter implements WindowListener {

/* Esta clase implement todos los metodos requeridos por la interface WindowListener. Todo metodo trata un tipo de window event. Todo metodo toma un parametro, el cual es un objeto que contiene informacion sobre el evento. Notar que no se usan eventos como Objetos, que también son factibles de implementar.*/

/* Llama al evento window que se muestra por primera vez. * parametro e es un objeto con informacion sobre el evento */ public void windowOpened(WindowEvent e) { System.out.println("window fue abierto por primera vez."); } // end windowOpened

/* * Llamada al evento en respuesta a un requerimiento del usuario con respecto a cerrar el window. * parametro e es un objeto con informacion sobre el evento. */ public void windowClosing(WindowEvent e) {System.out.println("usuario solicita un requerimiento, cerrar window."); System.exit(0);

Ingeniería en Computación, Universidad de La Seren 198

Page 199: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

} // end windowClosing

/* * Llamada al evento después que el requerimiento del usuario con respecto a cerrar el window se ha cumplido. */ public void windowClosed(WindowEvent e) { System.out.println("window ha sido cerrado."); } // end windowClosed

/* * Llamada al evento para cuando window es minimizado. * parametro e es un objeto con informacion sobre el evento. */

public void windowIconified(WindowEvent e) { System.out.println("window ha sido minimizado."); } // end windowIconified

/* * Llamada al evento en respuesta a un requerimiento del usuario con respecto a restaurar el window, luego de haber sido minimizado. * parametro e es un objeto con informacion sobre el evento. */ public void windowDeiconified(WindowEvent e) { System.out.println("window ha sido restaurado."); } // end windowDeiconified

/* * Llamada al evento en respuesta a un requerimiento del usuario con respecto a que window, sea activado. * parametro e es un objeto con informacion sobre el evento. */ public void windowActivated(WindowEvent e) { System.out.println("window ha sido activado."); } // end windowActivated

/* * Llamada al evento en respuesta a un requerimiento del usuario con respecto a desactivar window. * parametro e es un objeto con informacion sobre el evento. */ public void windowDeactivated(WindowEvent e) { System.out.println("window ha sido desactivado."); } // end windowDeactivated

} // end class WindowReporter

Pero no debería este programa llamarlo a confusión, pues si Ud. desea solamente terminar el programa, debería hacer algo como sigue:

class WindowReporter implements WindowListener { public void windowOpened(WindowEvent e) {} public void windowClosing(WindowEvent e) {System.exit(0);} public void windowClosed(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {}} // end class WindowReporter

Otra alternativa es hacer lo que ya se ha realizado antes y es la incorporación de la clase Ingeniería en Computación, Universidad de La Seren 199

Page 200: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

Adapter si posee, y digo si posee pues en la interface ActionListener no es necesaria, al tener solamente un método, de manera que no es necesario incluir una clase Adapter. En tal caso lo anterior quedaría reducido a:

class WindowReporter extends WindowAdapter { public void windowClosing(WindowEvent e){ System.exit(0); }} // end class WindowReporter

Donde sí existe una clase Adapter es en, ComponentListener( cuyo nombre es ComponentAdapter), ContainerListener, FocusListener, KeyListener, MouseListener, MouseMotionListener y WindowListener.(cambie Listener por Adapter. en las otras)

Ahora si hubiera más de un componente asociado con un escuchador de eventos, tendremos que utilizar las capacidades proporcionadas por el objeto ActionEvent que se pasa como argumento. Por ejemplo:

public void actionPerformed (ActionEvent e) {

Object obj = e.getSource(); // objeto que produjo el evento e. if (obj == botón) //por ejemplo. mostrarMensaje();

else if (... ) //

}

Otra técnica que puede ser útil es proceder en función de la clase del componente. Por ejemplo:

public void actionPerformed (ActionEvent e) {

Object obj = e.getSource(); // objeto que produjo el evento e. if (obj instanceof JButton) //por ejemplo. mostrarMensaje(e);

else if (obj instanceof JTextField) //hacer otra cosa.

}

Si ahora, por ejemplo, escribimos un método mouseClicked() que queremos sea obedecido cuando el ratón pulse el botón en una área particular de la pantalla, debemos asegurarnos que:

a. Este asociado con un objeto listener. Podemos escoger cualquier objeto que desee como el objeto que escucha con tal de que éste instrumente la interface de MouseListener. Esto significa que debe tener los cinco métodos: mouseClicked, mouseEntered, mouseExited, mousePressed y mouseReleased.

b. Se identifique la fuente del evento. Esto es, que el objeto que maneja el componente de la interface “el ratón” pulse sobre el botón. En todos nuestros ejemplos, la fuente de cada evento será una componente de la interface de algún tipo.

Ingeniería en Computación, Universidad de La Seren 200

Page 201: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

c. La declaración tiene que ser incluida en la parte de la estructura del programa que registra el objeto que escucha con el objeto fuente. Si c es el componente que es la fuente del evento, y l es el objeto listener entonces la declaración es

c.addMouseListener(l);

Una vez que esta declaración se ha realizado, cualquier evento del ratón causado por pulsar el botón en componente c se pasará al objeto l, y su método mouseClicked obedecerá. Los objetos e serán pasados a cada objetos cada vez. Por ejemplo, si definimos un objeto MouseListener para contener el método mouseClicked que reaccionará al click sobre el mouse, este objeto debe tener los 5-métodos de la interface MouseListener listados anteriormente. Así debemos definir no solamente mouseClicked, sino también mousePressed, mouseReleased, aunque no se ocupen. ¿Cómo hacer esto?. Muy similar a lo planteado antes, ya sea declarar

public void mousePressed(MouseEvent e) { }

y de la misma manera, mouseReleased, mouseEntered y mouseExited. O bien, si Ud. quiere evitar el trabajo de definir cada vez los métodos que correspondan, como en este caso 4-métodos, la librería de Java2 tiene una clase llamada MouseAdapter para este propósito. La definición de las clases listener son de esta forma,

public class MiMouseListener extends MouseAdapter { public void mouseClicked(MouseEvent e)

{ Responde a los click del mouse representado por e. }}

El nombre MiMouseListener puede ser cualquier nombre que Ud. proponga. Los otros nombres deben ser como los que se muestran - MouseAdapter, mouseClicked y MouseEvent, por estar así definidos en la clase.

Como Ud. habrá observado los ejemplos vistos han implementado una sola interface, pero esto es posible de generalizarlo, es decir, poder a través de una declaración manejar eventos de acción y de texto, por ejemplo, tal como se muestra a continuación.

public class Suspenso extends JFrame

implements ActionListener, TextListener

Para concluir este segmento, veamos algunas herramientas que ofrece Java. Como Ud. habrá notado siempre el frame aparece por defecto en la posición esquina superior-izquierda de su pantalla, pero esto puede cambiar. Si Ud. se da cuenta el centrado es dependiente del sistema, Ingeniería en Computación, Universidad de La Seren 201

Page 202: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

pues la resolución de la pantalla es una información que el sistema posee. En Java se tiene una clase Toolkit que posee un método llamado getScreenSize() que retorna el tamaño del “screen” como un objeto Dimension, en el programa llamado d, con variables instanciadas d.height y d.width.

import java.awt.*;import java.awt.event.*;import javax.swing.*;

class CentroFrame extends Jframe { public CentroFrame() { setTitle("Frame Centrado"); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } );

//fragmento usado para obtener el tamaño de la pantalla(screen) Toolkit tk = Toolkit.getDefaultToolkit(); Dimension d = tk.getScreenSize(); int pantallaHeight = d.height; int pantallaWidth = d.width; setSize(pantallaWidth / 2, pantallaHeight / 2); setLocation(pantallaWidth / 4, pantallaHeight / 4);

}}

public class CentrarFrame { public static void main(String[] args) { JFrame frame = new CentroFrame(); frame.show(); }}

Y por último, Ud. habrá observado que en los ejemplos vistos en la barra del frame siempre aparece por defecto la taza de café, propio de Java, que también se puede cambiar. Basta incluir la declaración

/*reemplazamos el icono de defecto por algun.gif,dado que también es dependiente del sistema se usa tk,para incrustar el icono.*/

Image imagen = tk.getImage("algun.gif"); setIconImage(imagen);

Como Ud. habrá observado en la Tabla Resumen de trato a los Eventos aparece en la columna Eventos generados por, el concepto de Component y Container , estos se refieren a que un Component es un elemento de la Interface de usuario, tales como Button, Text field, o scrollbar, mientras que Container es un área de la pantalla o componente que puede contener componentes, tales como windows o un panel. En general digamos que todos los componentes Swing son subclases de la clase JComponent.

Ingeniería en Computación, Universidad de La Seren 202

Page 203: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

Como Ud. podrá recordar, a la clase estrucFrame, luego de ralizada su ejecución se obtuvo una simple ventana con su título, esto es porque no tenía ningún componente, como Button o algún otro que se pudiera haber “incrustado”

TIPOS DE EVENTOSLos eventos se catalogan por su naturaleza, que se indicará en el miembro id de su estructura.

Los grandes grupos de eventos son:

Eventos de VentanaSon los que se generan en respuesta a los cambios de una ventana un frame o un dialogo.WINDOW_DESTROYWINDOW_EXPOSEWINDOW_ICONIFYWINDOW_DEICONIFYWINDOW_MOVED

Eventos de TecladoSon generados en respuesta a cuando el usuario pulsa y suelta una tecla mientras un Componente tiene el foco de entrada.KEY_PRESSKEY_RELEASEKEY_ACTIONKEY_ACTION_RELEASE

/** * keyDemo, para visualizar el uso deKEY_PRESSKEY_RELEASEKEY_ACTIONKEY_ACTION_RELEASE

*/

import java.awt.*;import java.awt.event.*;import javax.swing.*;

class keyDemoPanel extends JPanel implements KeyListener{ public keyDemoPanel() { addKeyListener(this); }

public void keyPressed(KeyEvent evt) { int keyCode = evt.getKeyCode(); int d; if (evt.isShiftDown()) d = 5; else d = 1; if (keyCode == KeyEvent.VK_LEFT) add(-d, 0); else if (keyCode == KeyEvent.VK_RIGHT) add(d, 0);

Ingeniería en Computación, Universidad de La Seren 203

Page 204: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

else if (keyCode == KeyEvent.VK_UP) add(0, -d); else if (keyCode == KeyEvent.VK_DOWN) add(0, d); }

public void keyReleased(KeyEvent evt) {}

public void keyTyped(KeyEvent evt) { char keyChar = evt.getKeyChar(); int d; if (Character.isUpperCase(keyChar)) { d = 5; keyChar = Character.toLowerCase(keyChar); } else d = 1; if (keyChar == 'h') add(-d, 0); else if (keyChar == 'l') add(d, 0); else if (keyChar == 'k') add(0, -d); else if (keyChar == 'j') add(0, d); }

public boolean isFocusTraversable() { return true; }

public void add(int dx, int dy) { end.x += dx; end.y += dy; Graphics g = getGraphics(); g.drawLine(start.x, start.y, end.x, end.y); g.dispose(); start.x = end.x; start.y = end.y; }

private Point start = new Point(0, 0); private Point end = new Point(0, 0);}

class keyDemoFrame extends JFrame{ public keyDemoFrame() { setTitle("keyDemo"); setSize(300, 200); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } );

Container contenPane = getContentPane(); contenPane.add(new keyDemoPanel()); }}

public class keyDemo{ public static void main(String[] args) { JFrame frame = new keyDemoFrame(); frame.show(); }}

Ingeniería en Computación, Universidad de La Seren 204

Page 205: Libro Java

Dr. Eric Jeltsch F. Capitulo 7: Eventos

Eventos de RatónSon los eventos generados por acciones sobre el ratón dentro de los límites de un Componente.MOUSE_DOWNMOUSE_UPMOUSE_MOVEMOUSE_ENTERMOUSE_EXITMOUSE_DRAG

Eventos de BarrasSon los eventos generados como respuesta a la manipulación de barras de desplazamiento (scrollbars).SCROLL_LINE_UPSCROLL_LINE_DOWNSCROLL_PAGE_UPSCROLL_PAGE_DOWNSCROLL_ABSOLUTE

Eventos de ListaSon los eventos generados al seleccionar elementos de una lista.LIST_SELECTLIST_DESELECT

Eventos VariosSon los eventos generados en función de diversas acciones.ACTION_EVENTLOAD_FILESAVE_FILEGOT_FOCUSLOST_FOCUS

Ingeniería en Computación, Universidad de La Seren 205

Page 206: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

C A P Í T U L O 8.

Swing

Digamos que muchos de los componentes Swing están basados en un patrón de diseño denominado MVC, "Modelo-Vista-Controlador", o en inglés (“Model -View-Controller”). El concepto de este patrón de diseño se basa en tres elementos:

Modelo: Almacena el estado interno en un conjunto de clases.

Vista: Muestra la información del modelo

Controlador: Cambia la información del modelo (delegado).

Una fácil manera de entender MVC, es considererar: el modelo como los datos, el view es el window sobre la pantalla, y el controller es la relación entre los dos. No es menester de este tutorial explicar todo el funcionamiento de este nuevo diseño, pero si se quiere profundizar en él consulte [Morgan, 1999].

En el Cap. 7 se dieron los pasos preliminares para entender la filosofía que estaba detrás de los eventos, con la tarea específica de cerrar la ventana para cuando el usuario pulse, el icono respectivo. La idea es ahora estructurar la forma de cómo trabajar con Swing respecto al diseño de una interfaz de usuario. Recordemos que todos los elementos de Swing son parte del paquete javax.swing, y como tal se debe utilizar el encabezado import javax.swing.*;. La forma de utilizar un componente Swing no difiere en nada de cómo se hizo con un objeto de cualquier otra clase. Es decir, se crea el componente invocando al constructor de su clase, luego se establece que deberá realizar, para finalmente añadirlo a un contenedor.

Por ejemplo, se desea crear un botón de pulsación, luego se establece que la tecla aceleradora es la C, además de una descripción abreviada. Esto se visualiza así.

//crear un botónMiBoton = new JButton(“Pulse aquí”);

//Pulsar Alt+C será equivalente a pulsar el botón.MiBoton.setMnemonic(KeyEvent.VK_C);

//asignarle una descripciónMiBoton.setTollTipText(“botón de pulsación.”);

Los componentes más comunes son las llamadas: etiquetas, botones, campo de texto de una línea o de varias, casillas de verificación, botones de opción, listas, barras de desplazamiento, cuadros de diálogo estándar y otros.

Ingeniería en Computación, Universidad de La Seren 206

Page 207: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

Para relacionarlo con el cap. 7, digamos que el siguiente segmento de programa, asocia al componente de la clase JButton, un manejador de eventos de acción. De esta forma el botón podrá responder al evento “click”, mediante el método actionPerformed.

ActionListener al=new ActionListener(){ //este método se ejecuta para cuando se haga click sobre el boton. public void actionPerformed(ActionEvent e){ //proceso a ejecutar. }};boton.addActionListener(al);

Ahora si hubiera más de un componente asociado con un escuchador de eventos, tendremos que utilizar las capacidades proporcionadas por el objeto ActionEvent que se pasa como argumento. Por ejemplo:

public void actionPerformed (ActionEvent e) {

Object obj = e.getSource(); // objeto que produjo el evento e. if (obj == botón) //por ejemplo. mostrarMensaje();

else if (... ) //

}

Otra técnica que puede ser útil es proceder en función de la clase del componente. Por ejemplo:

public void actionPerformed (ActionEvent e) {

Object obj = e.getSource(); // objeto que produjo el evento e. if (obj instanceof JButton) //por ejemplo. mostrarMensaje(e);

else if (obj instanceof JTextField) //hacer otra cosa.

}

Como Ud. habrá observado en Cap.7 aparece en Tabla Resumen de trato a los Eventos la columna Eventos generados por, el concepto de Component y Container , estos se refieren a que un Component es un elemento de la Interface de usuario, tales como Button, Text field, o scrollbar, mientras que Container es un área de la pantalla o componente que puede contener componentes, tales como windows o un panel. En general digamos que todos los componentes Swing son subclases de la clase JComponent. Como Ud. podrá recordar, a la clase estrucFrame, luego de ralizada su ejecución se obtuvo una simple ventana con su título, esto es porque no tenía ningún componente, como Button o algún otro que se pudiera haber “incrustado”.

Los contenedores son componentes Swing utilizados para ubicar otros componentes. En general, se tiene una jerarquía de contenedores, ellos son contenedores de nivel intermedio, de

Ingeniería en Computación, Universidad de La Seren 207

Page 208: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

nivel superior y controles. La siguiente figura nos muestra algo al respecto, en donde se tiene un marco, con un panel

En general, para agregar a un marco los componentes que hemos denominado controles, como son la etiqueta y el botón, hay que utilizar un contenedor intermedio. La figura anterior muestra que realmente existe una jerarquía de contenedores que nos ayudará a colocar

Ingeniería en Computación, Universidad de La Seren

Marco(Frame)

Panel

Marco(Frame)

Panel

Botón

Etiqueta

208

Page 209: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

adecuadamente los controles. La raíz de esa jerarquía es el contenedor de nivel superior definido por el marco de la ventana. Analizando esa figura se observa:

Un marco (objeto de la clase JFrame). Se corresponde con la ventana marco principal. Es el contenedor de nivel superior. Los contenedores correspondientes a JDialog y JApplet son también de nivel superior. Cada contenedor de nivel superior tiene de forma predeterminada un panel raíz (en la figura no se pinta) al que se puede acceder por medio del método getContentPane( ). Se trata de un panel de contenido que permite ubicar otros componentes (paneles y controles). Por ejemplo, la siguiente sentencia añade el objeto panel al panel raíz predeterminado:

getContentPane().add(panel, BorderLayout.CENTER);

Un panel (objeto de la clase JPanel). Se corresponde con la vista o área de trabajo de la ventana marco principal. Es el contenedor de nivel intermedio llamado panel de contenido. Su propósito es simplificar la colocación de controles. Un panel de contenido puede incluir a su vez otros paneles de contenido. La siguiente sentencia es típica en el afán de crear un panel de este tipo:

JPanel panel = new JPanel ();

Una etiqueta (objeto de la clase JLabel) y un botón (objeto de la clase JButton). Esta clase de componentes es lo que genéricamente llamamos controles. Cada uno de ellos realiza una operación específica cara al usuario. Anteriormente, en este mismo capítulo, ya vimos cómo crearlos. Para añadirlos a un panel, utilizaremos el método add. Por ejemplo:

panel.add(botón) ;

Para organizar los controles que se añaden a un contenedor, Java proporciona los llamados administradores de diseño. Un administrador de diseño está pensado para mostrar varios componentes a la vez en un orden preestablecido. De forma predeterminada cada contenedor tiene asignado un administrador de diseño. Swing proporciona seis administradores de diseño, sin embargo se tienen también componentes predefinidas como las que se muestran:

Ingeniería en Computación, Universidad de La Seren 209

Page 210: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

FlowLayout. Diseño en flujo. Coloca los componentes en el contenedor de izquierda a derecha (igual que se coloca el texto en un párrafo). Es el administrador de diseño asignado de forma predeterminada a los contenedores de nivel intermedio.

Ingeniería en Computación, Universidad de La Seren 210

Page 211: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

GridBagLayout. Diseño tipo rejilla. Coloca los componentes en el contenedor en filas y columnas. A diferencia de GridLayout, que explicaremos a continuación, permite que un componente pueda ocupar más de una columna.

BorderLayout. Diseño con límites. Divide un contenedor en cinco secciones denominadas: norte, sur, este, oeste y centro. Es el administrador de diseño que tienen asignado de forma predeterminada los contenedores de nivel superior. Los componentes se colocarán en una sección u otra según decidamos.

CardLayout. Diseño por paneles. Este diseñador permite colocar en el contenedor grupos diferentes de componentes en instantes diferentes de la ejecución (similar a los paneles con pestañas).

GridLayout. Diseño por rejilla. Coloca los componentes en el contenedor en filas y columnas.

Ingeniería en Computación, Universidad de La Seren 211

Page 212: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

BoxLayout. Diseño en caja. Coloca los componentes en el contenedor en una única fila o columna, ajustándose al espacio que haya.

Cuando queramos asignar un determinado administrador de diseño a un contenedor diferente de los predeterminados, primero hay que crearlo y después asignárselo invocando a su método setLayout. Por ejemplo, la siguiente sentencia asigna al contenedor panel un administrador de diseño de tipo GridLayout con 0 filas y 1 columna (los controles se colocarán en columna).

panel.setLayout(new GridLayout(0,1));

Como agregar componentes a un marco de Swing?.

Un JFrame está subdividido en varios paneles diferentes, el panel principal con el que trabaja es el panel de contenido, que representa toda el área de un marco al que se pueden agregar componentes. Para agregar componentes debemos hacer lo siguiente:

Ingeniería en Computación, Universidad de La Seren 212

Page 213: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

Crear un objeto JPanel(que es la versión Swing de un panel). Agregar todos los componentes(que pueden ser contenedores) al JPanel a través del

correspondiente método add(componente). Convertir este JPanel en el panel de contenido con el método

setContentPane(Contenedor). El objeto JPanel debe ser el único argumento.

El siguiente ejemplo usa la estructura antes descrita, agregando a la aplicación un botón rotulado al panel de contenido del marco. El botón se creará desde la clase JButton, que es la versión Swing de un botón seleccionable.

Ejemplo

import java.awt.GridLayout;import java.awt.event.*;import javax.swing.*;

public class Swinger extends JFrame {

public Swinger() { super("Swinger");

String nota = "Interactue conmigo."; JButton miButton = new JButton(nota); JPanel pane = new JPanel(); pane.add(miButton); setContentPane(pane); }//este segmento es casi estandar, para cerrar la aplicación. public static void main(String[] args) { JFrame frame = new Swinger(); WindowListener l = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; frame.addWindowListener(l); frame.pack(); frame.setVisible(true); }}

Tal vez lo único novedoso en este programa es el segmento,

String nota = "Interactue conmigo."; JButton miButton = new JButton(nota);

/* creándose un objeto JButton usando string como rótulo.*/ JPanel pane = new JPanel(); pane.add(miButton);

/* se crea un objeto JPanel, al cual se le agrega este botón.*/ setContentPane(pane);

Ingeniería en Computación, Universidad de La Seren 213

Page 214: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

La ejecución se visualiza así,

Como ya se dió cuenta los botones de Swing forman parte del cuerpo de la clase JButton. Los cuales pueden tener una etiqueta o rótulo de texto, como AWT, una etiqueta de icono o una combinación de ambos. En el caso de icono, basta considerar en el programa base Swinger.java, en donde reemplaza lo “bold” por esto.

ImageIcon miIcon= new ImageIcon(“hola.gif”);JButton miButton = new JButton(miIcon);

JPanel pane = new JPanel();pane.add(miButton);

SetContentPane(pane)

No olvidar que en Java se tiene una clase Toolkit que posee un método llamado getScreenSize() que retorna el tamaño del “screen” como un objeto Dimension, en el programa llamado d, con variables instanciadas d.height y d.width, con el fin de centrar la aplicación.

Notar que el botón “interactua conmigo”, no gatilla ningún evento, es decir, NO se le ha asociado ningún evento que pueda realizar para cuando el usuario pulse el botón. Veamos que esto puede cambiar.

Hasta el momento, podría esperarse, el de continuar dando ejemplos con las distintas herramientas etiquetas, botones, campo de texto de una línea o de varias, casillas de verificación, botones de opción, listas, barras de desplazamiento, cuadros de diálogo estándar y otros., pero lo que deseo es, lograr la comunión entre los eventos, vistos en Cap. 7 y los componentes y controles, que de alguna forma se han mencionado y ejemplificado con JButton, aquí en Cap. 8. No obstante al final de esta sección daremos más ejemplos que resumen muchas de las componentes aquí mencionadas.

Se sabe que dentro del sistema de manejo de eventos de Java2, si una clase desea responder a un evento de usuario debe implementar la interfaces que maneja los eventos, estas interfaces se llaman escuchadores de eventos o listener. Existe una lista de ellos dada en Cap. 7. Por ejemplo, ActionListener() es un evento que se genera cuando un usuario realiza una acción sobre un componente, por ejemplo, pulsar sobre

Ingeniería en Computación, Universidad de La Seren 214

Page 215: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

un botón. Existen varias otras, y la idea es aplicarla en algunas aplicaciones concretas. El paquete java.awt.event contiene todos los escuchadores de eventos básicos, para utilizarlos basta declarar

import java.awt.event.*;

Además, es posible declarar eventos que puedan manejar eventos de acción y de texto, lo que se logra al considerar,

public class Suspenso extends Jframe implements ActionListener, TextListener {//...}

Componentes ListenerAl convertir una clase en un escuchador de eventos, establece un tipo específico de evento para ser escuchado por esa clase, aunque esto último puede que jamás suceda si no agrega al componente un escuchador de evento coincidente. A lo que ese escuchador de evento generará los eventos cada vez que se use el componente. Por eso después de crear un componente, para asociarle un “listener” deberá llamar a alguno de los siguientes métodos del componente. Por ejemplo, addActionListener() para los componentes de JButton, JCheckBox, JComboBox, JTextField y JRadioButton.

La siguiente declaración por ejemplo crea un objeto JButton y le asocia un escuchador de evento de acción:

JButton miButton = new JButton (“miBoton”);MiButton.addActionListener(this);

Note que todos los métodos agregados toman un argumento: A saber, el objeto escuchador de evento de esa clase. Por medio de this Ud. indica que la clase actual es el escuchador de evento.

Métodos Manejadores de Eventos

Cuando Ud. asocia una interfaz a una clase, la clase debe manejar todos los eventos contenidos en la interfaz. En el caso de los escuchadores de eventos, cuando tiene lugar el evento de usuario correspondiente, el sistema de ventanas llama a cada método en forma automática. La interface ActionListener tiene un solo método. Todas las clases que

Ingeniería en Computación, Universidad de La Seren 215

Page 216: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

ActionListener implementa deben tener un método con una estructura como la siguiente:

public void actionPerformed(ActionEvent evt){//...maneje el evento en este sector}

El siguiente ejemplo instrumentaliza al botón de manera que cada vez que se pulse el botón respectivo, se cambiará el titulo del frame por el nombre del botón pulsado.

Ejemplo

import java.awt.event.*;import javax.swing.*;import java.awt.*;

public class tuBoton extends Jframe implements ActionListener { JButton b1 = new JButton("Eric"); JButton b2 = new JButton("Jeltsch");

public tuBoton() { super("Super Botón"); //escuchadores de eventos de acción a los botones b1.addActionListener(this); b2.addActionListener(this); JPanel pane = new JPanel(); pane.add(b1); pane.add(b2); setContentPane(pane); } public static void main(String[] args) { JFrame frame = new tuBoton(); WindowListener l = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; frame.addWindowListener(l); frame.pack(); frame.setVisible(true); } //la instrumentalización del evento asociado al boton. public void actionPerformed(ActionEvent evt) { Object fuente = evt.getSource(); if (fuente == b1) setTitle("Eric"); else if (fuente == b2) setTitle("Jeltsch"); repaint(); }}

En la ejecución Ud. podrá apreciar que cada vez que pulse algunos de los botones, se le asociará el nombre del mismo al nombre del frame.

Ingeniería en Computación, Universidad de La Seren 216

Page 217: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

Tras de pulsar, Eric

Tras de pulsar, Jeltsch

El método getSource() del objeto evt se usa para determinar la fuente del evento, el que procede a llamar a repaint() para dibujar nuevamente el marco. Otro método que sirve es getActionCommand() en el objeto ActionEvent. Si en el ejemplo anterior, reemplaza setTitle("Eric"); por System.exit(0); notara que al pulsar “Eric” la aplicación se cierra. Si en el ejemplo anterior, reemplaza la siguiente declaración

JOptionPane.showMessageDialog(null,"Ud.presiono:"+ evt.getActionCommand());

por setTitle("Eric"); obtendrá el siguiente mensaje

Otra aplicación asociada a pintar el panel de algún color de su preferencia, luego de pulsado el boton correspondiente, se puede apreciar en el ejemplo siguiente.

import java.awt.*;import java.awt.event.*;import javax.swing.*;

class ButtonPanel extends JPanel implements ActionListener { public ButtonPanel() {

amaButton = new JButton("Amarillo"); azulButton = new JButton("Azul"); rojoButton = new JButton("Rojo");

add(amaButton); add(azulButton); add(rojoButton);

amaButton.addActionListener(this); azulButton.addActionListener(this); rojoButton.addActionListener(this); }

Ingeniería en Computación, Universidad de La Seren 217

Page 218: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

public void actionPerformed(ActionEvent evt) { Object source = evt.getSource(); Color color = getBackground(); if (source == amaButton) color = Color.yellow; else if (source == azulButton) color = Color.blue; else if (source == rojoButton) color = Color.red; setBackground(color); repaint();//en general, no es necesario. }

private JButton amaButton; private JButton azulButton; private JButton rojoButton; }

class ButtonFrame extends JFrame{ public ButtonFrame() { setTitle("Y mas Botones..."); setSize(300, 200); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } );

Container contentPane = getContentPane(); contentPane.add(new ButtonPanel()); }}

public class ButtonDemo{ public static void main(String[] args) { JFrame frame = new ButtonFrame(); frame.show(); }}

Como ya hemos adelantado, con los métodos existen una serie de eventos entre ellos: Eventos de Acción, Eventos de Ajuste, Eventos de Enfoque, Eventos de Elemento, Eventos de Tecla, Eventos de Ratón, Eventos de Movimiento de Ratón, Eventos de Ventana, los cuales no son excluyentes, es decir existen Eventos que pueden ser de Acción como de Elemento al mismo tiempo. Veremos a continuación algunos de ellos.

Eventos de Acción: Estos eventos ocurren cuando un usuario termina una acción por medio de uno de los siguientes componentes(JButton, JCheckBox, JComboBox, JTextField, JRadioButton). Para poder manejar estos eventos, se tiene que implementar la interfaz ActionListener, que por lo general la hemos declarado en ya sea de una clase TextFieldTrato o CheckBoxTrato, que están asociados a como tratar los eventos. Además se debe llamar al método addActionListener() de cada componente que genere un evento de acción, a no ser que quiera ignorar los eventos de acción de ese componente.

Ingeniería en Computación, Universidad de La Seren 218

Page 219: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

JTextField y JPasswordField

Ejemplo.

import java.awt.*;import java.awt.event.*;import javax.swing.*;

public class TextFieldDemo extends JFrame { private JTextField text1, text2, text3; private JPasswordField password;

public TextFieldDemo() { super( "Demo de JTextField y JPasswordField" );

Container c = getContentPane(); c.setLayout( new FlowLayout() );

// construcción de textfield de tamaño fijo text1 = new JTextField( 10 ); c.add( text1 );

// construcción de textfield con texto fijo text2 = new JTextField( "Ingrese el texto" ); c.add( text2 );

// construcción de textfield con texto fijo de 20 //elementos visibles y ningún evento a la vista. text3 = new JTextField( "text field no editable", 20 ); text3.setEditable( false ); c.add( text3 );

// construcción de textfield texto fijo password = new JPasswordField( "Texto Oculto" ); c.add( password );

TextFieldTrato tra = new TextFieldTrato(); text1.addActionListener( tra ); text2.addActionListener( tra ); text3.addActionListener( tra ); password.addActionListener( tra );

setSize( 325, 100 ); show(); }

public static void main( String args[] ) { TextFieldDemo app = new TextFieldDemo();

app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ); }

// clase interna para tratar los eventos private class TextFieldTrato implements ActionListener {

Ingeniería en Computación, Universidad de La Seren 219

Page 220: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

public void actionPerformed( ActionEvent e ) { String s = "";

if ( e.getSource() == text1 ) s = "text1: " + e.getActionCommand(); else if ( e.getSource() == text2 ) s = "text2: " + e.getActionCommand(); else if ( e.getSource() == text3 ) s = "text3: " + e.getActionCommand(); else if ( e.getSource() == password ) { JPasswordField pwd = (JPasswordField) e.getSource(); s = "password: " + new String( pwd.getPassword() ); }

JOptionPane.showMessageDialog( null, s ); } } }

JCheckBox

Ejemplo.

import java.awt.*;import java.awt.event.*;import javax.swing.*;

public class CheckBoxDemo extends JFrame { private JTextField t; private JCheckBox bold, italic;

public CheckBoxDemo() { super( "JCheckBox Demo" );

Container c = getContentPane(); c.setLayout(new FlowLayout()); t = new JTextField( "Mire el cambio de estilo", 20 ); t.setFont( new Font( "TimesRoman", Font.PLAIN, 14 ) ); c.add( t ); // crea objeto checkbox bold = new JCheckBox( "Bold" ); c.add( bold ); italic = new JCheckBox( "Italic" ); c.add( italic );

CheckBoxTrato tra = new CheckBoxTrato(); bold.addItemListener( tra ); italic.addItemListener( tra ); setSize( 275, 100 ); show(); }

Ingeniería en Computación, Universidad de La Seren 220

Page 221: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

public static void main( String args[] ) { CheckBoxDemo app = new CheckBoxDemo(); app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ); }

private class CheckBoxTrato implements ItemListener { private int valBold = Font.PLAIN; private int valItalic = Font.PLAIN;

public void itemStateChanged( ItemEvent e ) { if ( e.getSource() == bold ) if ( e.getStateChange() == ItemEvent.SELECTED ) valBold = Font.BOLD; else valBold = Font.PLAIN; if ( e.getSource() == italic ) if ( e.getStateChange() == ItemEvent.SELECTED ) valItalic = Font.ITALIC; else valItalic = Font.PLAIN; t.setFont(new Font( "TimesRoman", valBold + valItalic, 14 ) ); t.repaint(); } }}

Este ejemplo también se considera también como Evento de Elemento, pues este tipo de eventos suceden cuando se selecciona o no un elemento en cualquiera de los siguientes componentes JButton, JCheckBox, JComboBox, JTextField, JRadioButton. La diferencia radica en que para poder manejar estos eventos se tiene que implementar la interfaz ItemListener desde una clase, tal como se hizo en el ejemplo recién visto. La interfaz ItemListener tiene un solo método llamado itemStateChanged() y para determinar el elemento en el que ocurrió el evento se debe llamar al método getItem() en el objeto ItemEvent, también puede usar el método getStateChange().

Eventos de AjusteLos eventos de ajuste se dan cuando se mueve un componente JScrollBar por medio de las flechas de la barra, el cuadro de desplazamiento o haciando click en cualquier parte de la barra. Para manejar estos eventos, una clase debe implementar la interfaz

Ingeniería en Computación, Universidad de La Seren 221

Page 222: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

AdjustmentListener(), que posee adjustmentValueChanged(EventodeAjuste), como método y que toma la forma:

public void adjustmentValueChanged(AdjustmentEvent e){//..}

En este contexto se usa el método getValue() en el objeto AdjustEvent(), que devuelve un entero que representa el valor de la barra de desplazamiento.

Ejemplo

import java.awt.event.*;import javax.swing.*;import java.awt.*;

public class buenAjuste extends JFrame implements AdjustmentListener { BorderLayout borde= new BorderLayout();JTextField valor = new JTextField();JScrollBar bar = new JScrollBar(SwingConstants.HORIZONTAL, 50, 10, 0, 100);

public buenAjuste() { super("Buen Ajuste"); bar.addAdjustmentListener(this); valor.setHorizontalAlignment(SwingConstants.CENTER); valor.setEditable(false); JPanel pane = new JPanel(); pane.setLayout(borde); pane.add(valor, "South"); pane.add(bar, "Center"); setContentPane(pane); } public static void main(String[] args) { JFrame frame = new buenAjuste();

WindowListener l = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; frame.addWindowListener(l);

frame.pack(); frame.setVisible(true); }

public void adjustmentValueChanged(AdjustmentEvent evt){ Object fuente = evt.getSource(); if (fuente == bar) { int nuevoValor = bar.getValue(); valor.setText("" + nuevoValor); } repaint(); } }

Ingeniería en Computación, Universidad de La Seren 222

Page 223: Libro Java

Dr. Eric Jeltsch F. Capítulo 8: Swing

En setText() las comillas vacías se denomina cadena “null”, y están concatenadas al entero nuevoValor para convertir el argumento en una cadena. Como podrá recordar, si concatena una cadena con un tipo diferente, Java siempre manejará el resultado como cadena, la cadena null es un método abreviado para cuando se quiera desplegar algo que todavía no es una cadena.

Ingeniería en Computación, Universidad de La Seren 223

Page 224: Libro Java

Dr. Eric Jeltsch F. Capítulo 9:

C A P Í T U L O 9

Swing: Eventos de Ratón y Movimientos del Ratón

Los “eventos de Ratón” se generan por diferentes interacciones del usuario, es decir, un click del ratón, un ratón entrando al área de los componentes, o saliendo del área. Cualquier componente puede generar estos eventos, los que se implementan desde una clase por medio de la interfaces MouseListener, la cual tiene 5-métodos. A saber mouseCliked(), mouseEntered(), mouseExited(), mousePressed(), mouseReleased(). Cada uno de ellos toma la forma, por ejemplo

public void mouseReleased(MouseEvent e) {//..}

Los métodos que funcionan para MouseEvent son: getClickCount(), getPoint(), getX(), getY().

Por otra parte, los “eventos de movimiento de ratón”, ocurren cada vez que se mueve el ratón en un componente, y como cualquier evento necesita de un soporte, se debe entonces de implementar la interfaces MouseMotionListener desde una clase. En esta interfaces hay 2-métodos mouseDragged() y mouseMoved(). Donde toman la forma, por ejemplo

public void mouseDragged(MouseEvent e) {//..}

A diferencia de las otras interfaces escuchadoras de eventos que ha manejado hasta ahora, la interfaces MouseMotionListener no tiene métodos propios de manera que puede utilizar los mismos métodos anteriores.

Ejemplo:

import java.awt.*;import java.awt.event.*;import javax.swing.*;

public class MouseDemo extends JFrame implements MouseListener, MouseMotionListener { private JLabel statusBar;

public MouseDemo() { super( "Demo para Eventos del Mouse" ); statusBar = new JLabel(); getContentPane().add( statusBar, BorderLayout.SOUTH ); // aplicacion listener para los eventos propios del mouse. addMouseListener( this ); addMouseMotionListener( this ); setSize( 275, 100 ); show();

Ingeniería en Computación, Universidad de La Seren 224

Page 225: Libro Java

Dr. Eric Jeltsch F. Capítulo 9:

}

// tratar los eventos en MouseListener. public void mouseClicked( MouseEvent e ) { statusBar.setText("Click en [" + e.getX() + ", " + e.getY() + "]"); }

public void mousePressed( MouseEvent e ) { statusBar.setText("Presiono en [" + e.getX() +", " + e.getY() + "]" ); }

public void mouseReleased( MouseEvent e ) { statusBar.setText( "Soltado en [" + e.getX() + ", " + e.getY() + "]" ); }

public void mouseEntered( MouseEvent e ) { statusBar.setText( "Mouse en window" ); }

public void mouseExited( MouseEvent e ) { statusBar.setText( "Mouse fuera de window" ); }

// tratar los eventos de MouseMotionListener. public void mouseDragged( MouseEvent e ) { statusBar.setText( "Arrastrar a [" + e.getX() +", " + e.getY() + "]" ); }

public void mouseMoved( MouseEvent e ) { statusBar.setText( "Movido a [" + e.getX() + ", " + e.getY() + "]" ); }

public static void main( String args[] ) { MouseDemo app = new MouseDemo();

app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ); }}

Ingeniería en Computación, Universidad de La Seren 225

Page 226: Libro Java

Dr. Eric Jeltsch F. Capítulo 9:

Notar que:

statusBar = new JLabel(); getContentPane().add( statusBar, BorderLayout.SOUTH );

es para definir statusBar como JLabel e incrustarlo en el panel de contenidos. Después descutiremos en detalle la expresión BorderLayout.SOUTH.

Otra variante interesante es la aplicación siguiente en la cual no se usan los métodos mouseMoved o nuestro conocido MouseMotionListener, pues ahora se considera esta interfaces como una subclase de otra superior que es MouseMotionAdapter, esta clase define ambos mouseMoved y mouseDragged.

Ejemplo:

import javax.swing.*;import java.awt.event.*;import java.awt.*;

public class Pintar extends JFrame { private int xValor = -10, yValor = -10;

public Pintar() { super( "Un lápiz particular" ); getContentPane().add( new Label( "Vaya a Windows y pulse el mouse para pintar" ), BorderLayout.SOUTH ); addMouseMotionListener( new MouseMotionAdapter() { public void mouseDragged( MouseEvent e ) { //xValor e yValor almacenan las coordenadas //del evento mouseDragged xValor = e.getX(); yValor = e.getY(); repaint(); } } );

setSize( 300, 150 ); show(); }

public void paint( Graphics g ) { //sacandole punta al lápiz. g.fillOval( xValor, yValor, 20, 20 ); }

public static void main( String args[] ) { Pintar app = new Pintar(); app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } );

Ingeniería en Computación, Universidad de La Seren 226

Page 227: Libro Java

Dr. Eric Jeltsch F. Capítulo 9:

}}*

Utilizar esta misma idea para detectar cuando se ha pulsado el botón izquierdo , derecho o centro. Los métodos asociados al evento son isMetaDown() y isAltDown().

Eventos de Tecla

Los eventos de tecla ocurren cuando se presiona una tecla sobre el teclado. Cualquier componente puede generar estos eventos, y para dar soporte a los eventos, se tiene que implementar la interfaces KeyListener desde una clase. En la interfaces KeyListener hay tres eventos: keyPressed(), keyReleased() y keyTyped() que toman la forma usual, por ejemplo

public void keyReleased(keyEvent evt) {//...}

El método getKeyChar() de KeyEvent, devuelve el carácter de la tecla asociada con el evento.

Ejemplo:

import javax.swing.*;import java.awt.*;import java.awt.event.*;

public class TeclaDemo extends Jframe implements KeyListener { private String linea1 = "", linea2 = ""; private String linea3 = ""; private JTextArea textArea;

public TeclaDemo() { super( "Demo para los eventos de Tecla" ); textArea = new JTextArea( 10, 15 ); textArea.setText( "Pulse cualquier tecla de la consola..." ); textArea.setEnabled( false );

// admitir frame para procesar los eventos de Tecla o Key addKeyListener( this );

getContentPane().add( textArea ); //otra variante

setSize( 350, 100 ); show(); }

public void keyPressed( KeyEvent e ) { linea1 = "Tecla presionada: " + e.getKeyText( e.getKeyCode() ); seteaLineas2y3( e ); }

Ingeniería en Computación, Universidad de La Seren 227

Page 228: Libro Java

Dr. Eric Jeltsch F. Capítulo 9:

public void keyReleased( KeyEvent e ) { linea1 = "Tecla soltada: " + e.getKeyText( e.getKeyCode() ); seteaLineas2y3( e ); }

public void keyTyped( KeyEvent e ) { linea1 = "Tecla tipeada: " + e.getKeyChar(); seteaLineas2y3( e ); }

private void seteaLineas2y3( KeyEvent e ) { linea2 = "Esta tecla " + ( e.isActionKey() ? "" : "no " ) + "es una acción key";

String temp = e.getKeyModifiersText( e.getModifiers() );

linea3 = "Modifica tecla presionada: " + ( temp.equals( "" ) ? "no" : temp );

textArea.setText( linea1 + "\n" + linea2 + "\n" + linea3 + "\n" ); }

public static void main( String args[] ) { TeclaDemo app = new TeclaDemo();

app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ); }}

Eventos de Ventana

Los eventos de Ventana suceden cuando un usuario abre o cierra un objeto de Ventana tal como un JFrame o JWindow. Cualquier componente puede generar estos eventos y se tiene que implementar la interfaces WindowListener, desde una clase, para dar soporte a los eventos. Existen 7-métodos en esta interfaces. A saber, windowActivated(), windowClosed(), windowClosing(), windowDeactivated(), windowDeiconified(), windowIconified(), windowOpened(), los que toman la forma por ejemplo,

Ingeniería en Computación, Universidad de La Seren 228

Page 229: Libro Java

Dr. Eric Jeltsch F. Capítulo 9:

public void windowOpened(WindowEvent evt){//..}

Los métodos windowClosing(), windowClosed() son semejantes, pero se llama uno al cerrar la Ventana, y al otro una vez cerrada. De hecho para detener el cierre de una Ventana puede utilizar un método windowClosing().

LAYOUT MANAGERS

Por lo general los Layout Managers están considerados para arreglar componentes GUI desde el punto de vista diseño, es decir ofrece herramientas o capacidades que son de uso para determinar la posición exacta y tamaño de todo componente GUI. Algunos de los más básicos son FlowLayout, BorderLayout y GridLayout, pero hay otros como ya se menciono en Cap. 8.

FlowLayout situa los elementos en forma secuencial de izquierda a derecha, en el orden que ellos fueron agregados.

BorderLayout dispone los componentes en cinco áreas: Norte, Sur, Este, Oeste y Centro.

GridLayout dispone los componentes en filas y columnas.

En el siguiente ejemplo mostraremos la disposición de 3- objetos botones tras la aplicación de FlowLayout. Cada boton tiene un evento propio que es definido al interior de la clase que implementa ActionListener. La estructura es muy simple, se definen los botones y seteamos el label asociado a cada uno de ellos,

izq = new JButton( "Izq" );centro = new JButton( "Centro" );der = new JButton( "Der" );

luego agregamos o incrustamos al panel o contenedor c a cada uno de ellos, por ejemplo,

c.add( izq );

finalmente le agregamos la necesidad de responder al evento asociado, por ejemplo,

izq.addActionListener()

Ejemplo:

import java.awt.*;import java.awt.event.*;import javax.swing.*;

public class FlowLayoutDemo extends JFrame { private JButton izq, centro, der;

Ingeniería en Computación, Universidad de La Seren 229

Page 230: Libro Java

Dr. Eric Jeltsch F. Capítulo 9:

private Container c; private FlowLayout layout; public FlowLayoutDemo() { super( "Demo para FlowLayout" );

layout = new FlowLayout();

c = getContentPane(); c.setLayout( layout );

izq = new JButton( "Izq" ); izq.addActionListener( new ActionListener() { //cada boton tiene un evento de acción public void actionPerformed( ActionEvent e ) { layout.setAlignment( FlowLayout.LEFT );

//realinear los componentes atachados, usando //layoutContainer que es un método de la interface //LayoutManager para especificar que el panel de contenido //deberá reordenarse según el ajuste que le de el FL layout.layoutContainer( c ); } } ); c.add( izq );

centro = new JButton( "Centro" ); centro.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { layout.setAlignment( FlowLayout.CENTER );

// realinear los componentes atachados layout.layoutContainer( c ); } } ); c.add( centro );

der = new JButton( "Der" ); der.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { //setAlignment cambia los alineamientos para el FL layout.setAlignment( FlowLayout.RIGHT );

// realinear los componentes atachados layout.layoutContainer( c ); } } ); c.add( der );

setSize( 300, 75 ); show(); }

Ingeniería en Computación, Universidad de La Seren 230

Page 231: Libro Java

Dr. Eric Jeltsch F. Capítulo 9:

public static void main( String args[] ) { FlowLayoutDemo app = new FlowLayoutDemo(); app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ); }}

BorderLayout dispone los componentes en cinco áreas: Norte, Sur, Este, Oeste y Centro.

Ejemplo:

import java.awt.*;import java.awt.event.*;import javax.swing.*;

public class BorderLayoutDemo extends JFrame implements ActionListener { private JButton b[]; private String nombres[] = { "Norte", " Sur", "Este", " Oeste", " Centro" }; private BorderLayout layout;

public BorderLayoutDemo() { super( "Demo para BorderLayout" );//especifica el número de pixeles de distancia entre los //componentes layout = new BorderLayout( 5, 5 );

Container c = getContentPane(); c.setLayout( layout );

// instancia para objeto JButton b = new JButton[ nombres.length ];

for ( int i = 0; i < nombres.length; i++ ) { b[ i ] = new JButton( nombres[ i ] ); b[ i ].addActionListener( this ); }

// orden no interesa, pero notar la forma de accesar al //contenedor c c.add( b[ 0 ], BorderLayout.NORTH ); // North posiciones c.add( b[ 1 ], BorderLayout.SOUTH ); // South "

c.add( b[ 2 ], BorderLayout.EAST ); // East " c.add( b[ 3 ], BorderLayout.WEST ); // West " c.add( b[ 4 ], BorderLayout.CENTER ); // Center "

setSize( 300, 200 ); show(); }

public void actionPerformed( ActionEvent e )

Ingeniería en Computación, Universidad de La Seren 231

Page 232: Libro Java

Dr. Eric Jeltsch F. Capítulo 9:

{ /*cuando usamos el click de un botón particular en el layout el método actionPerformed() es llamado, ocultando el botón que genero el evento*/

for ( int i = 0; i < b.length; i++ ) if ( e.getSource() == b[ i ] ) b[ i ].setVisible( false ); else b[ i ].setVisible( true );

// relayout el contenido del panal layout.layoutContainer( getContentPane() ); }

public static void main( String args[] ) { BorderLayoutDemo app = new BorderLayoutDemo();

app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ); }}

GridLayout dispone los componentes en filas y columnas.

Ejemplo:

import java.awt.*;import java.awt.event.*;import javax.swing.*;

public class GridLayoutDemo extends JFrame implements ActionListener { private JButton b[]; private String nombres[] = { "uno", "dos", "tres", "cuatro", "cinco", "seis" }; private boolean hola = true; private Container c; private GridLayout grid1, grid2;

public GridLayoutDemo() { super( "Demo GridLayout" );//2 filas y 3 columnas con una separación de 5 pixeles //hacia arriba y hacia abajo. grid1 = new GridLayout( 2, 3, 5, 5 );//3-filas y 2-columnas sin separación entre ellos, o //asumido por defecto grid2 = new GridLayout( 3, 2 );

c = getContentPane(); c.setLayout( grid1 );

// crea y agrega buttons b = new JButton[ nombres.length ];

Ingeniería en Computación, Universidad de La Seren 232

Page 233: Libro Java

Dr. Eric Jeltsch F. Capítulo 9:

for (int i = 0; i < nombres.length; i++ ) { b[ i ] = new JButton( nombres[ i ] ); b[ i ].addActionListener( this ); c.add( b[ i ] ); }

setSize( 300, 150 ); show(); }

public void actionPerformed( ActionEvent e ) { if ( hola ) c.setLayout( grid2 ); else c.setLayout( grid1 );

hola = !hola;//recomputa el layout contenedor basado sobre el layout //manager actual c.validate(); }

public static void main( String args[] ) { GridLayoutDemo app = new GridLayoutDemo();

app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ); } }

Panel

Complejos GUI requieren que cada componente sea situado en una posición determinada, esto a manudo se soluciona disponiendo de un layout específico con múltiples paneles. Los paneles son creados con JPanel que es una subclase de JComponent. Por otra parte notar que la clase JComponent hereda la clase java.awt.Container, de manera que JPanel es un Container para todos los efectos, es decir puede tener componentes incluyendo otros paneles, accesados a ellos. En el siguiente ejemplo se define un objeto botonPanel de JPanel que setea un GridLayout de una fila y cinco columnas, notar que los botones están situados al “sur del mundo”. JPanel se adecua a las componentes, redimensione el window para ver como el layout manager afecta afecta al tamaño de JButton, por ejemplo.

import java.awt.*;import java.awt.event.*;import javax.swing.*;

public class PanelDemo extends JFrame { private JPanel botonPanel; private JButton botones[];

Ingeniería en Computación, Universidad de La Seren 233

Page 234: Libro Java

Dr. Eric Jeltsch F. Capítulo 9:

public PanelDemo() { super( "Demo para Panel" );

Container c = getContentPane(); botonPanel = new JPanel(); botones = new JButton[ 5 ];

botonPanel.setLayout( new GridLayout( 1, botones.length ) );

for ( int i = 0; i < botones.length; i++ ) { botones[ i ] = new JButton( "Boton " + (i + 1) ); botonPanel.add( botones[ i ] ); }

c.add( botonPanel, BorderLayout.SOUTH );

setSize( 425, 150 ); show(); }

public static void main( String args[] ) { PanelDemo app = new PanelDemo();

app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ); }}

Ingeniería en Computación, Universidad de La Seren 234

Page 235: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

C A P I T U L O 10

GUI Avanzado (con Swing)

En las lecturas 7-8-9 se entregaron los pasos preliminares para entender la filosofía que estaba detrás de las apariencias gráficas en el diseño de una interfaz de usuario. Convengamos en que el proceso de generar una interfaz de usuario, se puede realizar con herramientas de java.awt.* o de javax.swing.*. Para tal efecto, veamos la relación entre las clases que lo componen, para formarse una idea de su interrelación entre las clases.

Un JFrame está subdividido en varios paneles diferentes, el panel principal con el que trabaja es el panel de contenido, que representa toda el área de un marco al que se pueden agregar componentes. Para agregar componentes debemos hacer lo siguiente:

Crear un objeto JPanel(que es la versión Swing de un panel). Agregar todos los componentes(que pueden ser contenedores) al JPanel a través del

correspondiente método add(componente). Convertir este JPanel en el panel de contenido con el método

setContentPane(Contenedor). El objeto JPanel debe ser el único argumento.

Complejos GUI requieren que cada componente sea situado en una posición determinada, esto a menudo se soluciona disponiendo de un layout específico con múltiples paneles. Los paneles son creados con JPanel que es una subclase de JComponent. Por otra parte notar que la clase

Ingeniería en Computación, Universidad de La Seren 235

Page 236: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

JComponent hereda la clase java.awt.Container, de manera que JPanel es un Container para todos los efectos, es decir puede tener componentes incluyendo otros paneles, accesados a ellos. En el siguiente ejemplo se define un objeto botonPanel de JPanel que declara un GridLayout de una fila y cinco columnas, notar que los botones están situados al “sur del mundo”. JPanel adecua a las componentes, redimensionando el window para ver como el layout manager afecta al tamaño de JButton. Una forma típica de incorporar botones en un JPanel es como sigue.

Container contenidoPanel= getContentPane();JPanel miPanel= new JPanel();miPanel.add(Boton_Amarillo);miPanel.add(Boton_Verde);miPanel.add(Boton_Azul);contenidoPanel.add(miPanel, “South”)

En el ejemplo final, de la lectura anterior, llamada PanelDemo.java, se muestra un panel que incluye cinco botones dispuestos al sur. Una variante, con el fin de optimizar la forma de escribir o de accesarlos al panel se uso un array de botones, pero esto no tiene porque siempre una condición.

La idea ahora es incorporarle otras cualidades sobre el panel, que actua como pizarra para cuando Ud. gatille un evento al presionar algún botón. En el ejemplo siguiente consideramos una estructura de manera que al presionar un botón rotulado genere una figura geométrica tan sofisticada como nosotros queramos, es decir, crearemos una subclase de JPanel.En general la idea es usar JPanel como una pizarra, es decir un área dedicada para dibujar, la que puede recibir eventos del mouse y a menudo extenderla para crear nuevos componentes. La idea es evitar o entregar otra alternativa en la situación de combinar componentes Swing GUI y el pintado sobre una misma ventana o applet, que usualmente genera conflictos en el despliegue de la figura. Entonces con la creación de esta subclase de JPanel podremos incrustar figuras que en el despliegue de la ventana no se van a entorpecer. Una estructura de este tipo de pizarra debería usar el método paintComponent().Se visualiza así:

public void paintComponent(Graphics g){ super.paintComponent(g); // su código de pintado ad-doc}

Ingeniería en Computación, Universidad de La Seren 236

Page 237: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

La clase Pizarra, definida en archivo Pizarra.java, me permite incorporar este método. Desgraciadamente JFrame NO es subclase de JComponent, por tal motivo no contienen el método paintComponent(). De manera que para dibujarlo directamente sobre subclases de este tipo se utiliza repaint().import java.awt.*;import javax.swing.*;

public class Pizarra extends JPanel { public final static int CIRCULO = 1, CUADRADO = 2; private int figura;

public void paintComponent( Graphics g ) {//para asegurarse que el pintado se realice, y el //mecanismo Swing quede intacto. Si la versión de esta //superclase no es llamada la componente típica de GUI no //sera desplegada apropiamente sobre la superficie.Tampoco //le resultara si la llama después de realizar la //declaración de pintado super.paintComponent( g );

if ( figura == CIRCULO ) g.fillOval( 50, 10, 60, 60 ); else if ( figura == CUADRADO ) g.fillRect( 50, 10, 60, 60 ); }

public void draw( int s ) { figura = s; repaint(); }}

En otro archivo de nombre PizarraTest.java testeo el pintado que contiene paintComponent().

import java.awt.*;import java.awt.event.*;import javax.swing.*;

public class PizarraTest extends JFrame { private JPanel buttonPanel; private Pizarra miPanel; private JButton circulo, cuadrado;

public PizarraTest() { super( "Panel como Pizarra" ); miPanel = new Pizarra(); //en versiones Java 1.0 y Java 1.1, esta forma se asocia a la clase canvas miPanel.setBackground( Color.yellow ); cuadrado = new JButton( "Cuadrado" ); cuadrado.addActionListener(

Ingeniería en Computación, Universidad de La Seren 237

Page 238: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

new ActionListener() { public void actionPerformed( ActionEvent e ) { miPanel.draw( Pizarra.CUADRADO ); } } ); circulo = new JButton( "Circulo" ); circulo.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { miPanel.draw( Pizarra.CIRCULO ); } } ); buttonPanel = new JPanel(); buttonPanel.setLayout( new GridLayout( 1, 2 ) ); buttonPanel.add( circulo ); buttonPanel.add( cuadrado ); Container c = getContentPane(); c.add( miPanel, BorderLayout.CENTER ); c.add( buttonPanel, BorderLayout.SOUTH ); setSize( 300, 150 ); show(); } public static void main( String args[] ) { PizarraTest app = new PizarraTest(); app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ); }}

Ingeniería en Computación, Universidad de La Seren 238

Page 239: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

A veces tendrá que usar en la construcción de su pequeño sistema o de la interfaz de usuario que esta construyendo, el ingreso de la información que va más allá que una línea de una cierta magnitud, la cual podemos hacer con JtextField. Sin embargo, tal como se planteaba, si la información consta de varias líneas, lo aconsejable es usar JTextArea(), de manera que cuando Ud. utilice esta área de componentes en su programa y así el usuario pueda entrar cualquier número de líneas de texto, usando solamente ENTER para separarlas. En el constructor de la componente JTextArea() debe especificar el número de filas y columnas para el texto de área. Esta API se encuentra en javax.swing.JTextArea.

JTextArea

Por ejemplo, la siguiente declaración considera 8-líneas de 40-columnas, que es incrustada en el Panel.

miAreadeTexto=new JTexArea(8, 40);//también admite texto.miAreadeTexto=new JTexArea(String texto, int 8, int 40);getContentPane().add(miAreadeTexto);

En Swing el área de texto no tiene una barra de desplazamiento(scrollbar), sin embargo eso no es dificultoso, basta insertar miAreadeTexto dentro del panel asociado a la barra llamado ScrollPane. Esta API se encuentra en javax.swing.JScrollPane.

miAreadeTexto=new JTexArea(8, 40);JScrollPane miscrollPane= new JScrollPane(miAreadeTexto);getContentPane().add(miAreadeTexto);

Ejemplo

import java.awt.*;import java.awt.event.*;import javax.swing.*;

class TextAreaFrame extends JFrame implements ActionListener { public TextAreaFrame() { JPanel p = new JPanel();

Ingeniería en Computación, Universidad de La Seren 239

Page 240: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

botonInsercion = new JButton("Insercion"); p.add(botonInsercion); botonInsercion.addActionListener(this);

botonToken = new JButton("Token"); p.add(botonToken); botonToken.addActionListener(this);

botonNoToken = new JButton("No Token"); p.add(botonNoToken); botonNoToken.addActionListener(this); getContentPane().add(p, "South"); miTextArea = new JTextArea(8, 40); miScrollPane = new JScrollPane(miTextArea); getContentPane().add(miScrollPane, "Center"); setTitle("TextArea Demo"); setSize(300, 300); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } ); }

public void actionPerformed(ActionEvent evt) { Object fuente = evt.getSource(); if (fuente == botonInsercion)//void append(String nuevoText), pega el texto ingresado al //final del texto real en el área de texto. miTextArea.append("Hola amigos, nos vemos!!. "); else if (fuente == botonToken)//void setLineWrap(boolean b), tokenizador si es true. { miTextArea.setLineWrap(true);//validate() recomputa el tamaño y el Layout de sus //componentes en un Container miScrollPane.validate(); } else if (fuente == botonNoToken) { miTextArea.setLineWrap(false); miScrollPane.validate(); } }//declaración obligada, en caso contrario no reconoce las //variables . private JButton botonInsercion; private JButton botonToken; private JButton botonNoToken; private JTextArea miTextArea; private JScrollPane miScrollPane;}public class TextAreaTest {

Ingeniería en Computación, Universidad de La Seren 240

Page 241: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

public static void main(String[] args) { JFrame f = new TextAreaFrame(); f.show(); }}

También es posible de incorporarles Labels y Componentes Label. Basta con construir un componente JLabel con el texto conveniente, ellos NO reaccionan ni gatillan nada frente a un requerimiento del usuario. El constructor para este tipo de situaciones especifica el texto inicial o icono y opcionalmente, el alineamiento de sus componentes. Esta última se realiza a través de la interface SwingConstants, la que especifica LEFT, RIGHT, CENTER, NORTH, EAST, etc...Una declaración típica esJLabel miLabel= new JLabel(“Texto”, SwingConstants.LEFT);

Ejemploimport java.awt.*;import java.awt.event.*;import javax.swing.*; class TextEditFrame extends JFrame{ public TextEditFrame() { setTitle("TextEditTest"); setSize(400, 400); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } ); Container contPanel = getContentPane(); JPanel miPanel = new JPanel(); JButton botonReemplazo = new JButton("Reemplazo"); miPanel.add(botonReemplazo); botonReemplazo.addActionListener(new ActionListener()

Ingeniería en Computación, Universidad de La Seren 241

Page 242: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

{ public void actionPerformed(ActionEvent evt) { String f = desde.getText(); int n = miTextArea.getText().indexOf(f); if (n >= 0 && f.length() > 0) miTextArea.replaceRange(a.getText(), n, n + f.length()); } }); desde = new JTextField(8); miPanel.add(desde); miPanel.add(new JLabel("por")); a = new JTextField(8); miPanel.add(a); miTextArea = new JTextArea(8, 40); miScrollPane = new JScrollPane(miTextArea); contPanel.add(miPanel, "South"); contPanel.add(miScrollPane, "Center"); } private JScrollPane miScrollPane; private JTextArea miTextArea; private JTextField desde, a;}public class TextEditTest { public static void main(String[] args) { JFrame f = new TextEditFrame(); f.show(); }}

Border

Sobre el panel es posible de incorporar una forma de bordes, lo que hace, que la distribución del panel o las secciones del mismo sean delimitadas. Swing ofrece una herramienta llamada border para este propósito. Ud. lo encuentra en java.awt.swing.border que proporciona la interfaces Border . Ahora veremos algunos usos comunes para esta herramienta, llamando al método static BorderFactory(). Existe una variedad de formas y estilos, algunos de ellos son: Lowered bevel, Raised bevel, Etched, Line, Matte y Empty(que es para crear un espacio en blanco alrededor del componente.) Una estructura típica de declaración de cómo agregar un borde etched con un titulo al panel es:

Border etched = BorderFactory.createEtchedBorder();Border titulo=BorderFactory.createTitledBorder(etched,“mi Titulo”);Ingeniería en Computación, Universidad de La Seren 242

Page 243: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

MiPanel = setBorder(titulo);

Ingeniería en Computación, Universidad de La Seren 243

Page 244: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

Ejemplo

import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.border.*; class BorderFrame extends JFrame implements ActionListener{ public BorderFrame() { JPanel botonesPanel = new JPanel(); grupo = new ButtonGroup(); addRadioButton(botonesPanel, grupo, "Lowered bevel", true); addRadioButton(botonesPanel, grupo, "Raised bevel", false); addRadioButton(botonesPanel, grupo, "Etched", false); addRadioButton(botonesPanel, grupo, "Line", false); addRadioButton(botonesPanel, grupo, "Matte", false); addRadioButton(botonesPanel, grupo, "Empty", false);Border etched = BorderFactory.createEtchedBorder();Border titulo = BorderFactory.createTitledBorder(etched,"Tipos de Borde"); botonesPanel.setBorder(titulo); getContentPane().add(botonesPanel, "South"); setDemoPanel(); setTitle("Demo para Bordes"); setSize(600, 200); addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } } ); } public void addRadioButton(JPanel botonesPanel, ButtonGroup g, String botonNombre, boolean v) {JRadioButton button = new JRadioButton(botonNombre, v); button.addActionListener(this); g.add(button); botonesPanel.add(button); button.setActionCommand(botonNombre); } public void actionPerformed(ActionEvent evt) { setDemoPanel(); } public void setDemoPanel() { JPanel miPanel = new JPanel(); Border bordes = null; String comando = grupo.getSelection().getActionCommand(); if (comando.equals("Lowered bevel")) bordes = BorderFactory.createLoweredBevelBorder(); else if (comando.equals("Raised bevel")) bordes = BorderFactory.createRaisedBevelBorder(); else if (comando.equals("Etched")) bordes = BorderFactory.createEtchedBorder(); else if (comando.equals("Line")) bordes = BorderFactory.createLineBorder(Color.blue); else if (comando.equals("Matte")) bordes = BorderFactory.createMatteBorder(10, 10, 10, 10, Color.blue); else if (comando.equals("Empty")) bordes = BorderFactory.createEmptyBorder();

miPanel.setBorder(bordes);

Ingeniería en Computación, Universidad de La Seren 244

Page 245: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

getContentPane().add(miPanel, "Center"); validate(); } private JPanel miPanel; private ButtonGroup grupo;}

public class BorderTest{ public static void main(String[] args) { JFrame frame = new BorderFrame(); frame.show(); }}

Un pequeño resumen de las librerías SWING/AWT

abstract class AbstractButtonvoid addActionListener(ActionListener l)Icon getIcon()String getText()void setIcon(Icon defaultIcon)void setIconTextGap(int iconTextGap)void setText(String texto)class ActionEventObject getSource()String getActionCommand()interface ActionListenervoid actionPerformed(ActionEvent e)class BorderLayoutconstantes: CENTER, EAST, NORTH, SOUTH, WESTconstructores:BorderLayout()BorderLayout(int hgap, int vgap)void setHgap(int hgap)void setVgap(int vgap)class Boxstatic Box createHorizontalBox()

Ingeniería en Computación, Universidad de La Seren 245

Page 246: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

static Box createVerticalBox()class BoxLayout (opcional)constantes: X_AXIS, Y_AXISconstructor: public BoxLayout(Container target,int axis)class Colorconstantes: black, blue, cyan, darkGray, gray, green, lightGray, magenta, orange,pink, red, white, yellowconstructor: Color(int red, int green, int blue)abstract class ComponentColor getBackground()Font getFont()Color getForeground()int getHeight()int getWidth()void repaint()void setBackground(Color c)void setEnabled(boolean b)void setFont(Font f)void setForeground(Color c)void setVisible(boolean b)abstract class ContainerComponent add(Component comp) Component add(Component comp, int index)// segunda forma para BorderLayout, use constantesvoid remove(Component comp)void remove(int index)void setLayout(LayoutManager manager)class FlowLayoutconstantes: CENTER, LEFT, RIGHTconstructores:FlowLayout()FlowLayout(int align)FlowLayout(int align, int hgap,int vgap)void setAlignment(int align)void setHgap(int hgap)void setVgap(int vgap)class Fontconstantes: BOLD, ITALIC, PLAINconstructor:Font(String name, int style,int size)nombre de font standard: “Serif”, “SansSerif”, “Monospaced”class Framevoid setTitle(String titulo)void setMenuBar(MenuBar mb)class GridLayoutconstructores:GridLayout(int rows, int cols)GridLayout(int rows, int cols,int hgap, int vgap)void setHgap(int hgap)void setVgap(int vgap)class ImageIconconstructor:ImageIcon(String filename)class JButtonconstructores:JButton()JButton(String text)JButton(Icon icon)JButton(String text, Icon icon)abstract class JComponentvoid setActionCommand(String accionComand)void setPreferredSize(Dimension prefeSize)

Ingeniería en Computación, Universidad de La Seren 246

Page 247: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

// use new Dimension(width, height)class JDialog (opcional)contiene más metodos usados por JFrame:void setModal(boolean b)class JFrameconstructores:JFrame()JFrame(String titulo)Container getContentPane()void setContentPane(Container c);void setBounds(int x, int y, int width, int height)void setDefaultCloseOperation(int operacion)operacion = EXIT_ON_CLOSE para salir del programa, para cuando frame es closedvoid setJMenuBar(JMenuBar menubar)class JLabelconstantes: LEFT, CENTER, RIGHTconstructores:JLabel()JLabel(String text)JLabel(String text, int horizontalAlignment)JLabel(Icon image)JLabel(String text, Icon icon, int horizontalAlignment)Icon getIcon()String getText()void setHorizontalAlignment(int alinear)void setIcon(Icon icon)void setIconTextGap(int iconTextGap)class JMenuconstructores:JMenu()JMenu(String text)Component add(Component c) void addSeparator()void remove(Component c)class JMenuBarconstructor:JMenuBar()JMenu add(JMenu c) class JMenuItemconstructores:JMenuItem()JMenuItem(String text)JMenuItem(String text, int mnemonic)JMenuItem(Icon icon)JMenuItem(String text, Icon icon)class JPanelconstructores:JPanel()JPanel(LayoutManager layout)class JTextAreaconstructores:JTextArea()JTextArea(int rows, int columns)JTextArea(String text)JTextArea(String text, int rows, int columns)void append(String str)void setLineWrap(boolean wrap)abstract class JTextComponentString getText()void setEditable(boolean b)void setText(String t)class JTextField

Ingeniería en Computación, Universidad de La Seren 247

Page 248: Libro Java

Dr. Eric Jeltsch F. Capítulo 10:

constantes: LEFT, CENTER, RIGHTconstructores:JTextField()JTextField(int columns)JTextField(String text)JTextField(String text, int columns)void setHorizontalAlignment(int alinear)interface LayoutManagermetodos para usar internamente para cuando se implementan layout managersclass Windowvoid addWindowListener(WindowListener l)void pack()

Ingeniería en Computación, Universidad de La Seren 248

Page 249: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

C A P Í T U L O 11

GUI Avanzado (con Swing)

En las lecturas 7-8-9-10, se entregaron los pasos preliminares para entender la filosofía que estaba detrás de las apariencias gráficas en el diseño de una interfaz de usuario. Convengamos en que el proceso de generar una interfaz de usuario, se puede realizar con herramientas de java.awt.* o de javax.swing.*. Para tal efecto, veamos la relación entre las clases que lo componen, para formarse una idea de su interrelación entre las clases. No obstante se trabaja con javax.swing, por una serie de ventajas que esta ofrece.

Menu

Una observación importante es que la clase JFrame amplía la clase Frame de AWT, de manera que JFrame, JWindow y JDialog difieren de sus homólogos del AWT en que utilizan un panel de contenido separado para agregar y diseñar componentes GUI, este panel es un objeto Container al que se accede a través del método getContentPane(), método que lo hemos visto en acción en varios ejemplos hasta ahora. Los menús de Swing, al igual que las ventanas de Swing, son análogos a los AWT la diferencia fundamental es que las clases JMenuBar, JMenu, JMenuItem, JCheckBoxMenuItem y JRadioButtonMenuItem son todas ellas subclases de JComponent y por tanto de la clase Component, esto significa que los menús de Swing constituyen componentes que se pueden usar por cualquiera de las clases Container. Otra característica interesante de los menús Ingeniería en Computación, Universidad de La Seren 249

Page 250: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

de Swing es la propiedad de incorporar imágenes de iconos en los menús. El ejemplo siguiente muestra el uso de los menús en Swing, la metodología es la misma que se ha venido viendo, de manera que aunque el código podrá resultar grande en número de líneas, pero su estructura es muy simple. Otra herramienta de interés es el uso de JSeparator que se utiliza como separador de menús. La lógica en la generación de códigos esta dada por considerar que los elementos de menú se agregan a los menús, mientras que estos últimos se agregan a la barra de menús. Además se agregan radio-botones al correspondiente grupo de botones. La barra de menús se logra por medio del método setJMenuBar() de la clase JFrame. Aquí se aprecia un Menu típico de una GUI.

La barra de menu que podemos apreciar contiene una variedad de menus, la que se encuentra al tope de la pantalla en Windows. Toda barra de menu tiene uno o más menus, organizados por tópicos, en donde los archivos en este caso son: Archivo, Editar, Otro, etc. Por otra parte, al interior de cada uno de los menu se realizan acciones individuales tales como: Abrir, Imprimir, Cortar y Copiar, los que son mostrados para cuando Ud. activa el menu apropiado. En este caso se aprecia un SubMenu, Chequear, Radio1, Radio2 y Planta, la que a su vez tiene incorporado un archivo .gif para hacerlo más didáctico. Estas son algunas de las ventajas que ofrece Swing para trabajar con Menu, situación última que en AWT no es factible, no obstante, se puede trabajar de la misma manera en AWT, salvo restricciones, como las que se han comentado. Ya en la version Java 1.1 fue AWT totalmente elaborada incluyendo los (event handling,). JDK-Version 1.1 fue una segunda Biblioteca para programar interfaces gráficas presentada como: SWING. La que se realiza sobre AWT

Clase Menu en AWT El paquete AWT contiene cuatro clases principales para tratar los menus:

java.awt.Menu java.awt.MenuBar java.awt.MenuItem java.awt.PopupMenu

Para usar menus en su aplicación Ud. necesita agregar las instancias de las tres clases, una para MenuBar con uno o más Menus, todos con varios MenuItems. Ingeniería en Computación, Universidad de La Seren 250

Page 251: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

La clase java.awt.MenuComponent es superclase de todas estas clases. MenuComponent extiende java.lang.Object. Los menus, barra de menu, y menu items no son componentes y no pueden ser agregadas a los contenedores en forma habitual.

java.lang.Object | +---java.awt.MenuComponent | +---java.awt.MenuBar | +---java.awt.MenuItem | +---java.awt.Menu | +---java.awt.PopupMenu

Ambas MenuBar y MenuItem extienden MenuComponent. Menu extiende MenuItem. Además, MenuBar implementa la interface java.awt.MenuContainer.

La Clase MenuComponent es la raíz de la jerarquía de clases Menu. Un MenuBar representa un resumen de los Menu. Objetos de esta clase forman el punto de partida de la estructura de Menu.

Ingeniería en Computación, Universidad de La Seren 251

Page 252: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

Dentro de un MenuBar pueden ser organizados muchos MenuItem. Cada objeto Menu corresponde a la clase Menu de AWT. Por ejemplo, aquí se describe un sistema, del cual se puede apreciar como se correlacionan las actividades con las clases respectivas.

Hola Window Help

Hola Window Help

Diga Hola Mover instance Of

Deshab Diga Hola arriba Habi Diga Hola abajo

Luz(on/off)

Creando Menus Es fácil construir un menu, el orden típico es

1.Crear un nuevo MenuBar. 2.Crear un nuevo Menu. 3.Agregar items al Menu. 4.Si es necesario repita etapas 2 y 3. 5.Agregar el MenuBar al Frame.

Los constructores que Ud. necesita son muy simples. Por ejemplo, para crear un objeto nuevo MenuBar, basta con declarar:

MenuBar miMenubar = new MenuBar();

Para crear un nuevo Menu use el constructor Menu(String titulo). Pasando el titulo al menu que Ud, desee. Por ejemplo, para crear los menus Archivo y Editar, basta con declarar,

Menu miArchivoMenu = new Menu("Archivo");

Ingeniería en Computación, Universidad de La Seren

MenuBar

Menu

MenuItem

Menu

MenuItem

CheckboxMenuItem

252

Page 253: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

Menu miEditarMenu = new Menu("Editar");

MenuItems son creados en forma similar con el constructor MenuItem(String menutext). Pasando el titulo del menu que Ud. quiera, por ejemplo,

MenuItem Cortar = new MenuItem("Cortar");

También puede crear MenuItems al interior de los menus, por ejemplo: Cortar, Copiar, Pegar, Limpiar y seleccionar todos los MenuItems:

Menu editMenu = new Menu("Edit"); editMenu.add(new MenuItem("Cortar")); editMenu.add(new MenuItem("Copiar")); editMenu.add(new MenuItem("Pegar")); editMenu.add(new MenuItem("Limpiar")); editMenu.addSeparator(); editMenu.add(new MenuItem("Seleccionar Todos"));

El método addSeparator() agrega una línea horizontal al menu. Esto es usado para separar logicamente las funciones del menu. Luego podrá incorporar al Menu, las barras del Menu usando MenuBares(Menu m), por ejemplo,:

miMenubar.add(ArchivoMenu); miMenubar.add(EditarMenu);

Finalmente, para cuando la barra de menu estime que esta copada, se procede a incorporarla al Frame usando el método frame setMenuBar(MenuBar mb).Dado un Frame f , este es un ejemplo: f.setMenuBar(miMenuBar);

Ejemplos

import java.awt.Frame;public class AWT_Ej1 {

public static void main(String[] args) {Frame wnd = new Frame("Simple Ventana");wnd.setSize(400,300);wnd.setVisible(true);

} //end main()} //class AWT_Ej1, genera una ventana simple sin la posibilidad de cerrar.

import java.awt.Frame;import java.awt.Window;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;

public class AWT_Ej2 {public static void main(String[] args) {

Frame wnd = new Frame("Simple Ventana, pero se cierra!");wnd.addWindowListener( new WindowCierreAdapter() );wnd.setSize(400,300);

Ingeniería en Computación, Universidad de La Seren 253

Page 254: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

wnd.setVisible(true);} //main()

} //class AWT_Ej2, genera una ventana simple con la posibilidad de cerrar.

class WindowCierreAdapter extends WindowAdapter {public void windowClosing( WindowEvent we) {

Window wnd = we.getWindow();wnd.setVisible(false);wnd.dispose();System.exit(0);

} //windowClosing()} //class WindowCierreAdapter

Clase JMenu en SwingLa clase JMenuBar contiene los métodos necesarios para manejar una barra de menú, que es a su vez un contenedor de menús.

La clase JMenu contiene los métodos para manejar los menús, por ejemplo cuando un menú es cliqueado el menú se expande para mostrar una lista de los items menú. Hacer click sobre un menú genera un evento y por tal motivo deberemos contar con “escuchadores” o listener.

La clase JMenuItem contiene los métodos para manejar items de menú, pudiendo ser un submenú que proporciona a su vez más menús.

La clase JCheckBoxMenuItem contiene los métodos para manejar items de menú según una forma particular de chequeo.

La clase JRadioButtonMenuItem muestra una forma de circulo relleno para optar por alguna opción dentro de un menú.

Creando Menus JMenuBar miMenuBar = new JMenuBar();Si quiere agregarle métodos, bastará con una declaración del tipo:MiFrame.setJMenuBar(miMenuBar);Ahora, si desea para cada menú crear un objeto menú,JMenu editarMenu= new JMenu(“Edit”);Pudiendo agregar menu items, por ejemplo, separadores, JMenuItem archivoNew = new JMenuItem("New"); editarMenu.add(archivoNew);editarMenu.addSeparator(); o submenús a objetos menú, por ejemplo, en este mismo contexto,JMenu opcionMenu=...;editarMenu.add(opcionMenu);para luego accesarlo a la barra del menú,MiMenuBar.addMenu(editarMenu);

El efecto de seleccionar un menú, significa que se gatilla una acción representada por los eventos, por eso que se necesita instalar un escuchador o listener para cada menú items. Algo parecido a, ArchivoNew.addActionListener(this), si Ud. se da cuenta esta forma de construcción para cuando se tienen varios menús y submenús es muy tedioso, de ahí que es recomendable

Ingeniería en Computación, Universidad de La Seren 254

Page 255: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

usar un procedimiento que lo realice. Nosotros mostramos dos modalidades. En este ejemplo se muestra la primera modalidad en donde se realiza:

una inicialización de las variables globales que toman parte en el programa, luego continua con la declaración de la barra de menú (Archivo), creando cada uno de los

componentes de cada segmento, en el ejemplo, me refiero a (Sobre y Exit), incorporandole de inmediato un addActionsListener(), que va a realizar el despliegue de un

mensaje para cuando el escuchador apropiado haya escuchado este evento(Sobre) o se saldrá si escucho (Exit). Esto así construído se incorpora a la barra de manú. De la misma manera se crea (Formato), que tiene otras habilidades, como (Colores) y (Fuentes).

Se crean las clases ItemTrato y EstiloTrato que implementaran la inteface apropiada de ActionListener e ItemListener con los métodos actionPerformed() e ItemStateChanged().

Ejemplo:

import javax.swing.*;import java.awt.event.*;import java.awt.*;

public class MenuTest extends JFrame {private Color colorValor[]={Color.black,Color.blue,Color.red,Color.green}; private JRadioButtonMenuItem colorItems[], fonts[]; private JCheckBoxMenuItem estiloItems[]; private JLabel desplegar; private ButtonGroup miFontGroup, miColorGroup; private int estilo;

public MenuTest() { super( "Usando JMenus" );

JMenuBar miBar = new JMenuBar(); // crea menubar setJMenuBar( miBar );// setea el menubar para JFrame

// crea los archivos del Menu , entre ellos Sobre y //Exit como menu item JMenu miFileMenu = new JMenu( "Archivo" ); JMenuItem sobreItem = new JMenuItem( "Sobre..." ); sobreItem.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { JOptionPane.showMessageDialog( MenuTest.this, "Este es un ejemplo\nde usos de menus", "Sobre", JOptionPane.PLAIN_MESSAGE ); } } ); miFileMenu.add( sobreItem );

JMenuItem exitItem = new JMenuItem( "Exit" );

exitItem.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) {

Ingeniería en Computación, Universidad de La Seren 255

Page 256: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

System.exit( 0 ); } } ); miFileMenu.add( exitItem );

miBar.add( miFileMenu ); // los agrega al File menu

// crea el otro segmento de menu, y sus submenus como menu //items. JMenu formatMenu = new JMenu( "Formato" ); // crea Color como submenu, inicializando colores. String colores[] = { "Black", "Blue", "Red", "Green" }; JMenu colorMenu = new JMenu( "Color" ); colorItems = new JRadioButtonMenuItem[ colores.length ]; miColorGroup = new ButtonGroup();

ItemTrato itemTrato = new ItemTrato();

for ( int i = 0; i < colores.length; i++ ) { colorItems[ i ] = new JRadioButtonMenuItem( colores[ i ] ); colorMenu.add( colorItems[ i ] ); miColorGroup.add( colorItems[ i ] ); colorItems[ i ].addActionListener( itemTrato ); }

colorItems[ 0 ].setSelected( true ); formatMenu.add( colorMenu ); formatMenu.addSeparator();

// crea Font como submenu, inicializando fuentes. String fontNombres[] = { "TimesRoman", "Courier", "Helvetica" }; JMenu fontMenu = new JMenu( "Fuentes" ); fonts = new JRadioButtonMenuItem[ fontNombres.length ]; miFontGroup = new ButtonGroup();

for ( int i = 0; i < fonts.length; i++ ) { fonts[ i ] = new JRadioButtonMenuItem( fontNombres[ i ] ); fontMenu.add( fonts[ i ] ); miFontGroup.add( fonts[ i ] ); fonts[ i ].addActionListener( itemTrato ); }

fonts[ 0 ].setSelected( true ); fontMenu.addSeparator();

String estiloNombres[] = { "Bold", "Italic" }; estiloItems = new JCheckBoxMenuItem[ estiloNombres.length ];

EstiloTrato estiloTrato = new EstiloTrato();

for ( int i = 0; i < estiloNombres.length; i++ ) { estiloItems[ i ] = new JCheckBoxMenuItem( estiloNombres[ i ] ); fontMenu.add( estiloItems[ i ] ); estiloItems[ i ].addItemListener( estiloTrato ); }

formatMenu.add( fontMenu ); miBar.add( formatMenu ); // agrega formato al menu

Ingeniería en Computación, Universidad de La Seren 256

Page 257: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

desplegar = new JLabel("Muestras de Texto", SwingConstants.CENTER ); desplegar.setForeground( colorValor[ 0 ] ); desplegar.setFont( new Font( "TimesRoman", Font.PLAIN, 72 ) );

getContentPane().setBackground( Color.cyan ); getContentPane().add( desplegar, BorderLayout.CENTER );

setSize( 500, 200 ); show(); }

public static void main( String args[] ) { MenuTest app = new MenuTest();

app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ); }

class ItemTrato implements ActionListener { public void actionPerformed( ActionEvent e ) { for ( int i = 0; i < colorItems.length; i++ ) if ( colorItems[ i ].isSelected() ) { desplegar.setForeground( colorValor[ i ] ); break; } for ( int i = 0; i < fonts.length; i++ ) if ( e.getSource() == fonts[ i ] ) { desplegar.setFont( new Font( fonts[ i ].getText(), estilo, 72 ) ); break; }

repaint(); } }

class EstiloTrato implements ItemListener { public void itemStateChanged( ItemEvent e ) { estilo = 0;

if ( estiloItems[ 0 ].isSelected() ) estilo += Font.BOLD;

if ( estiloItems[ 1 ].isSelected() ) estilo += Font.ITALIC;

desplegar.setFont( new Font( desplegar.getFont().getName(), estilo, 72 ) );

Ingeniería en Computación, Universidad de La Seren 257

Page 258: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

repaint(); } }}

Como otra forma de construir menús he considerado, setupEventos(), que es una estructura en donde depósito todos los eventos, tal como se muestran en el siguiente ejemplo. Existe otra forma, más elegante en el texto de Core Java2 de Hortsmann, pág 489, de cómo organizar los menús y submenús.

Ejemplo

import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.event.*;

public class SwingWin extends JFrame {public static int WIDTH = 300;public static int HEIGHT = 300;public static String TITULO = "SwingWin";

Container miframeContainer; // Swing componentes JTextField miTextField = new JTextField(50); JMenuBar miMenuBar = new JMenuBar(); JMenu archivoMenu = new JMenu("File"); JMenuItem archivoNew = new JMenuItem("New"); JMenuItem archivoOpen = new JMenuItem("Open"); JMenuItem archivoSave = new JMenuItem("Save"); JMenuItem archivoExit = new JMenuItem("Exit"); JMenu editarMenu = new JMenu("Edit"); JMenuItem editarCut = new JMenuItem("Cut"); JMenuItem editarCopy = new JMenuItem("Copy"); JMenuItem editarPaste = new JMenuItem("Paste"); JMenu especialMenu = new JMenu("Special"); JCheckBoxMenuItem especialCheck1 = new JCheckBoxMenuItem("Check 1"); JCheckBoxMenuItem especialCheck2 = new JCheckBoxMenuItem("Check 2",true); JSeparator miSeparador = new JSeparator(); JRadioButtonMenuItem especialRadio1 = new JRadioButtonMenuItem("Radio 1"); JRadioButtonMenuItem especialRadio2 = new JRadioButtonMenuItem("Radio 2"); ButtonGroup miButtonGroup = new ButtonGroup();

Ingeniería en Computación, Universidad de La Seren 258

Page 259: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

public SwingWin() { super(TITULO);//el constructor SwingWin invoca a miGui()para construir la //GUI del programa y a setupEventos()para conectar eventos //a su código de manejo de eventos. miGUI(); setupEventos(); setSize(WIDTH,HEIGHT); show(); } void miGUI() {//el método setupMenuBar es invocado por el constructor //miGUI(), para configurar la barra de menús del programa. setupMenuBar(); layoutComponentes(); }

void setupMenuBar() { archivoMenu.add(archivoNew); archivoMenu.add(archivoOpen); archivoMenu.add(archivoSave); archivoMenu.add(archivoExit); editarMenu.add(editarCut); editarMenu.add(editarCopy); editarMenu.add(editarPaste); especialMenu.add(especialCheck1); especialMenu.add(especialCheck2); especialMenu.add(miSeparador); miButtonGroup.add(especialRadio1); miButtonGroup.add(especialRadio2); especialMenu.add(especialRadio1); especialMenu.add(especialRadio2); miMenuBar.add(archivoMenu); miMenuBar.add(editarMenu); miMenuBar.add(especialMenu); setJMenuBar(miMenuBar);//organiza el cuento. }//este método invoca al método getContentPane() de la clase //Jframe con el fin de obtener el container del frame public void layoutComponentes() { miframeContainer = getContentPane(); miframeContainer.setLayout(null); miTextField.setBounds(150,150,100,20); miframeContainer.add(miTextField); }//este método configura los manipuladores de eventos de la //ventana y de cada uno de los elementos de menú. void setupEventos() { addWindowListener(new WindowTrato()); archivoNew.addActionListener(new MenuItemTrato()); archivoOpen.addActionListener(new MenuItemTrato()); archivoSave.addActionListener(new MenuItemTrato()); archivoExit.addActionListener(new MenuItemTrato()); editarCut.addActionListener(new MenuItemTrato()); editarCopy.addActionListener(new MenuItemTrato()); editarPaste.addActionListener(new MenuItemTrato()); especialCheck1.addItemListener(new ItemTrato()); especialCheck2.addItemListener(new ItemTrato()); especialRadio1.addItemListener(new ItemTrato()); especialRadio2.addItemListener(new ItemTrato()); }

public static void main(String[] args) { SwingWin app = new SwingWin();

Ingeniería en Computación, Universidad de La Seren 259

Page 260: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

}

public class WindowTrato extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }

public class MenuItemTrato implements ActionListener { public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); if(cmd.equals("Exit")) System.exit(0); else miTextField.setText(cmd); } }

public class ItemTrato implements ItemListener { public void itemStateChanged(ItemEvent e) { AbstractButton boton = (AbstractButton) e.getItem(); String miLabel = boton.getText(); if(boton.isSelected()) miLabel += " true"; else miLabel += " false"; miTextField.setText(miLabel); } }}

Esta es una parte de su ejecución.

Como ya lo han visto Swing puede considerar label como rotulos en los menús, pero esto no es todo pues también considera iconos o ambos, basta con declarar una expresión del tipo, JMenuItem editarItem = new JMenuItem(“Cut”, new ImageIcon(“cut.gif”)); otras interfaces posibles de generar son

Ingeniería en Computación, Universidad de La Seren 260

Page 261: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

Cuyo código está en miMenuSimple.java.

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

import javax.swing.*;

public class miMenuSimple extends JMenuBar implements ActionListener {

String[] archivoItems = new String[] { "Nuevo", "Abrir", "Salvar", "Exit" }; String[] editarItems = new String[] { "Cortar", "Copiar", "Pegar" }; char[] archivoCortito = { 'N','A','S','E' }; char[] editarCortito = { 'T','C','P' };

public miMenuSimple() {

JMenu archivoMenu = new JMenu("Archivo"); JMenu editarMenu = new JMenu("Editar"); JMenu otroMenu = new JMenu("Otro"); JMenu subMenu = new JMenu("SubMenu"); JMenu subMenu2 = new JMenu("SubMenu2");

// Ensamblar el archivo menu con abreviaciones. for (int i=0; i < archivoItems.length; i++) { JMenuItem item = new JMenuItem(archivoItems[i], archivoCortito[i]); item.addActionListener(this); archivoMenu.add(item);

Ingeniería en Computación, Universidad de La Seren 261

Page 262: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

}

// Ensamblar el archivo menus con los aceleradores de teclado. for (int i=0; i < editarItems.length; i++) { JMenuItem item = new JMenuItem(editarItems[i]); item.setAccelerator(KeyStroke.getKeyStroke(editarCortito[i], java.awt.Event.CTRL_MASK, false)); item.addActionListener(this); editarMenu.add(item); }

// Insertar un separador en el menú Editar editarMenu.insertSeparator(1);

// Ensamblar los submenús de Otro Menu JMenuItem item; subMenu2.add(item = new JMenuItem("Extra 2")); item.addActionListener(this); subMenu.add(item = new JMenuItem("Extra 1")); item.addActionListener(this); subMenu.add(subMenu2);

// Ensamblar Otro Menu en si mismo otroMenu.add(subMenu); otroMenu.add(item = new JCheckBoxMenuItem("Chequear")); item.addActionListener(this); otroMenu.addSeparator(); ButtonGroup buttonGroup = new ButtonGroup(); otroMenu.add(item = new JRadioButtonMenuItem("Radio 1")); item.addActionListener(this); buttonGroup.add(item); otroMenu.add(item = new JRadioButtonMenuItem("Radio 2")); item.addActionListener(this); buttonGroup.add(item); otroMenu.addSeparator(); otroMenu.add(item = new JMenuItem("Planta", new ImageIcon("image.gif"))); item.addActionListener(this);

// Finalmente agrega todos los menús al menubar add(archivoMenu); add(editarMenu); add(otroMenu); }

public void actionPerformed(ActionEvent event) { System.out.println("Menu item [" + event.getActionCommand() + "] fue presionado."); }

public static void main(String s[]) { JFrame frame = new JFrame("Un Simple Menu"); //frame.addWindowListener(new BasicWindowMonitor()); frame.setJMenuBar(new miMenuSimple()); frame.pack(); frame.setVisible(true); }}

Ingeniería en Computación, Universidad de La Seren 262

Page 263: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

Para concluir al menos en esta parte les mostrare el último ejemplo en el mismo contexto de lo tratado hasta ahora, la única novedad es la herramienta llamada Look andFeel, que es capaz de simular interfaces de Motif, Windows que son interfaces gráficas de sistemas propietarios.

Al archivo le he llamado SwingLF.java

import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.event.*;import javax.swing.border.*;import com.sun.java.swing.plaf.motif.*;import javax.swing.plaf.metal.*;import com.sun.java.swing.plaf.windows.*;

public class SwingLF extends JFrame { public static int WIDTH = 450; public static int HEIGHT = 450; public static String TITULO = "SwingLF";//defino mi contenedor Container miframeContainer; // defino los Swing componentes JPanel[] paneles = new JPanel[6]; //botones de chequeo JCheckBox checkbox1 = new JCheckBox("Check 1"); JCheckBox checkbox2 = new JCheckBox("Check 2"); JCheckBox checkbox3 = new JCheckBox("Check 3"); //botones de selección JRadioButton radioButton1 = new JRadioButton("Radio 1"); JRadioButton radioButton2 = new JRadioButton("Radio 2"); JRadioButton radioButton3 = new JRadioButton("Radio 3"); //campos de texto JTextField textField1 = new JTextField("Text field 1",15); JTextField textField2 = new JTextField("Text field 2",15); //barras deslizantes JSlider slider1 = new JSlider(0,0,100,25); JSlider slider2 = new JSlider(0,0,100,75); //botones que cambian el “look” JButton metalButton = new JButton("Metal"); JButton motifButton = new JButton("Motif"); JButton windowsButton = new JButton("Windows"); //construyo la barra de menú JMenuBar miMenuBar = new JMenuBar(); //construyo los componentes de la barra “Archivo” JMenu archivoMenu = new JMenu("Archivo"); JMenuItem archivoNuevo = new JMenuItem("Nuevo"); JMenuItem archivoAbrir = new JMenuItem("Abrir"); JMenuItem archivoSalvar = new JMenuItem("Salvar"); JMenuItem archivoSalir = new JMenuItem("Salir"); //construyo los componentes de la barra “Editar” JMenu editarMenu = new JMenu("Editar"); JMenuItem editarCortar = new JMenuItem("Cortar"); JMenuItem editarCopiar = new JMenuItem("Copiar"); JMenuItem editarPegar = new JMenuItem("Pegar"); //clases LookAndFeel MetalLookAndFeel metalLF = new MetalLookAndFeel(); MotifLookAndFeel motifLF = new MotifLookAndFeel(); WindowsLookAndFeel windowsLF = new WindowsLookAndFeel();

Ingeniería en Computación, Universidad de La Seren 263

Page 264: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

public SwingLF() {//SwingLF carretero super(TITULO); miGUI(); setupEventos(); setSize(WIDTH,HEIGHT); show(); } //miGUI carretera void miGUI() { setupMenuBar(); layoutComponentes(); } void setupMenuBar() { archivoMenu.add(archivoNuevo); archivoMenu.add(archivoAbrir); archivoMenu.add(archivoSalvar); archivoMenu.add(archivoSalir); miMenuBar.add(archivoMenu); editarMenu.add(editarCortar); editarMenu.add(editarCopiar); editarMenu.add(editarPegar); miMenuBar.add(editarMenu); setJMenuBar(miMenuBar); }

public void layoutComponentes() { for(int i=0;i<paneles.length;++i) paneles[i] = new JPanel(); paneles[0].setBorder(new TitledBorder("Checkboxes")); paneles[0].setLayout(new GridLayout(3,1)); paneles[0].add(checkbox1); paneles[0].add(checkbox2); paneles[0].add(checkbox3); paneles[1].setBorder(new TitledBorder("Radio Buttons")); paneles[1].setLayout(new GridLayout(3,1)); paneles[1].add(radioButton1); paneles[1].add(radioButton2); paneles[1].add(radioButton3); paneles[2].setBorder(new TitledBorder("Text Fields")); paneles[2].add(textField1); paneles[2].add(textField2); paneles[3].setBorder(new TitledBorder("Sliders")); paneles[3].add(slider1); paneles[3].add(slider2); paneles[4].setLayout(new GridLayout(3,1)); paneles[4].add(metalButton); paneles[4].add(motifButton); paneles[4].add(windowsButton); miframeContainer = getContentPane(); miframeContainer.setLayout(new GridLayout(3,2)); for(inti=0;i<paneles.length;++i) miframeContainer.add(paneles[i]); }

void setupEventos() { addWindowListener(new WindowTrato()); archivoSalir.addActionListener(new MenuItemTrato()); metalButton.addActionListener(new ButtonTrato()); motifButton.addActionListener(new ButtonTrato()); windowsButton.addActionListener(new ButtonTrato()); }

Ingeniería en Computación, Universidad de La Seren 264

Page 265: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

public static void main(String[] args) { SwingLF app = new SwingLF(); }

public class WindowTrato extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } public class MenuItemTrato implements ActionListener { public void actionPerformed(ActionEvent e) { System.exit(0); } } public class ButtonTrato implements ActionListener { public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); if(cmd.equals("Motif")) { try { UIManager.setLookAndFeel(motifLF); SwingUtilities.updateComponentTreeUI(SwingLF.this); }catch(Exception ex){ System.out.println(ex); } }else if(cmd.equals("Metal")) { try { UIManager.setLookAndFeel(metalLF); SwingUtilities.updateComponentTreeUI(SwingLF.this); }catch(Exception ex){ System.out.println(ex); } }else if(cmd.equals("Windows")) { try { UIManager.setLookAndFeel(windowsLF); SwingUtilities.updateComponentTreeUI(SwingLF.this); }catch(Exception ex){ System.out.println(ex); } } } }}

Ingeniería en Computación, Universidad de La Seren 265

Page 266: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

Ingeniería en Computación, Universidad de La Seren 266

Page 267: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

Actividades on-line:Qué cambios debería darle al código para que la interfaz se viese así?

De la misma manera pero ahora, quisiera que se viera así,

Ingeniería en Computación, Universidad de La Seren 267

Page 268: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

JSlider

Una declaración más o menos típica de JSlider son estructuras del tipo,

JSlider miJSlider = new JSlider( SwingConstants. HORIZONTAL, 0, 200, 10);

indica que cada tick marcado representa 10 como valor en el rango de valores soportado por JSlider,

miJSlider.setMajorTickSpacing(10);

indica si la tabla “milimetrada” se muestra o se oculta,

miJSlider.setPaintTicks(true);

Ejemplo

JSlider slider = new JSlider(JSlider.VERTICAL, 0, 50, 25);//10 slider.setMinorTickSpacing(4);//3 slider.setMajorTickSpacing(20);//10 slider.setPaintTicks(true); slider.setPaintLabels(true); slider.setLabelTable(slider.createStandardLabels(10)); add(slider, BorderLayout.CENTER);

Ingeniería en Computación, Universidad de La Seren 268

Page 269: Libro Java

Dr. Eric Jeltsch F. Capítulo 11:

Ingeniería en Computación, Universidad de La Seren 269