LibroJava 2008
LibroJava 2008
Universidad de La Serena.
Agosto 2007.
Escuela Ingeniería en Computación, Universidad de La Serena.
INDICE
I N D I C E ............................................................................................................................................................... 2
C A P I T U L O I.................................................................................................................................................... 4
Características de la Poo ................................................................................................................................... 10
C A P I T U L O II................................................................................................................................................. 24
Elementos Básicos en todo programa Java: Objetos y Métodos........................................................................ 27
Como construyo programas? ............................................................................................................................. 28
Primer encuentro con POO, el método System.out.println ............................................................................... 29
Cómo edito un programa?.................................................................................................................................. 29
Cómo ejecuto un programa Java........................................................................................................................ 30
Java, una Plataforma Independiente.................................................................................................................. 32
Una visión de la plataforma JDK....................................................................................................................... 34
Instalación de Java............................................................................................................................................. 35
C A P I T U L O III ............................................................................................................................................... 41
Elementos del Lenguaje...................................................................................................................................... 41
Tipos de Datos y Strings..................................................................................................................................... 41
Algunos Operadores........................................................................................................................................... 42
Variables ............................................................................................................................................................ 42
Asignaciones....................................................................................................................................................... 44
Punto Flotante.................................................................................................................................................... 45
Funciones Estándares ........................................................................................................................................ 46
Clases de I/O ...................................................................................................................................................... 48
ConsoleReader ................................................................................................................................................... 51
hsa.* ................................................................................................................................................................... 52
Swing .................................................................................................................................................................. 53
Strings................................................................................................................................................................. 56
C A P Í T U L O IV ................................................................................................................................................ 62
Decisiones (if)..................................................................................................................................................... 62
Ciclos.................................................................................................................................................................. 75
C A P I T U L O V ................................................................................................................................................. 85
Excepciones y Flujo de Datos (Exceptions y Streams)...................................................................................... 85
Como leer archivos de texto ............................................................................................................................... 94
Leer de un Archivo de Texto............................................................................................................................. 103
Escribiendo un Archivo de Texto...................................................................................................................... 105
Archivos y Filtros. ............................................................................................................................................ 106
Excepciones y Flujo de Datos (Exceptions y Streams)...................................... ¡Error! Marcador no definido.
Diagnostico de los errores en Expresiones y Variables ..................................... ¡Error! Marcador no definido.
Excepciones ........................................................................................................ ¡Error! Marcador no definido.
Leer desde el teclado .......................................................................................... ¡Error! Marcador no definido.
Como leer archivos de texto ............................................................................... ¡Error! Marcador no definido.
Leer de un Archivo de Texto............................................................................... ¡Error! Marcador no definido.
Escribiendo un Archivo de Texto........................................................................ ¡Error! Marcador no definido.
Archivos y Filtros. .............................................................................................. ¡Error! Marcador no definido.
C A P Í T U L O VI ............................................................................................................................................. 109
Programación Orientada a Objetos en Java.................................................................................................... 109
Clases y Objetos ............................................................................................................................................... 110
Instancias de una Clase.................................................................................................................................... 111
Constructores ................................................................................................................................................... 112
Variables en la clase ........................................................................................................................................ 112
Clase como Tipo............................................................................................................................................... 113
Expresiones para instanciar............................................................................................................................. 114
Métodos Instanciados....................................................................................................................................... 114
La palabra clave this ........................................................................................................................................ 115
Métodos en las Clases ...................................................................................................................................... 116
Implementando Estructuras de Datos .............................................................................................................. 116
Listas ................................................................................................................................................................ 116
Arboles AVL ..................................................................................................................................................... 118
Jerarquia de Clases.......................................................................................................................................... 130
Herencia ........................................................................................................................................................... 131
Jerarquia de clases en Java ............................................................................................................................. 134
Herencia y Constructores................................................................................................................................. 135
Dynamic Binding.............................................................................................................................................. 136
Polimorfismo .................................................................................................................................................... 136
Sobreescritura de métodos ............................................................................................................................... 137
Clases Abstractas y Métodos Abstractos.......................................................................................................... 137
Interfaces .......................................................................................................................................................... 139
Paquetes ........................................................................................................................................................... 142
Declaración import ......................................................................................................................................... 142
Java-Paquetes Estandar................................................................................................................................... 143
Programación Orientada a Objetos comparada con la Programación de Procesos y programación orientada a
eventos.............................................................................................................................................................. 143
C A P I T U L O VII............................................................................................................................................ 155
Eventos ............................................................................................................................................................. 156
GUI Minimo-Minimorum: ............................................................................................................................... 160
Estuctura de una Aplicación Swing.................................................................................................................. 163
C A P Í T U L O IX ............................................................................................................................................. 194
Swing: Layout y Eventos .................................................................................................................................. 194
C A P I T U L O X .............................................................................................................................................. 206
GUI Avanzads................................................................................................................................................... 206
C A P Í T U L O XI .............................................................................................................................................. 219
Menu con Swing ............................................................................................................................................... 219
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.
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
un conjunto de métodos como IngresarDinero, RetirarDinero, AbonarIntereses, SaldoActual,
Escuela Ingeniería en Computación, Universidad de La Serena.
Dr. Eric Jeltsch F. Capítulo I: Programación Orientada a Objetos
cuenta_del_clientel.Transferencia(cuenta_del_cliente2);
Objetos
Un 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.
Mensajes
Cuando 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étodos
Un 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:
Clases
Una 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.
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
Empleado
class Empleado {
String apellido; apellido: String
String nombre; nombre: String
int rut; rut: int
boolean esFemenino; esFemenino: boolean
}
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
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.
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.
//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 PC está encendido...
System.out.println("El PC está encendido.");
else // si no está encendido...
System.out.println("El PC está apagado.");
}
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.
C:\Documents and
Settings\usuario\Escritorio\POO\curso_poo_2006\MiPC.java:5:
cannot resolve symbol
symbol : class PC2
location: class MiPC
PC2 miPC2 = new PC2();
^
C:\Documents and
Settings\usuario\Escritorio\POO\curso_poo_2006\MiPC.java:5:
cannot resolve symbol
symbol : class PC2
location: class MiPC
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.
Ejemplo 3.
//método de la clase
void EncenderPC2() {
if (PC2_Encendido == true) // si está encendido...
System.out.println("El PC ya está encendido.");
else // si no está encendido, encenderlo.
{
PC2_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 (PC2_Encendido == true) // si el PC está encendido...
System.out.println("El PC está encendido.");
else // si no está encendido...
System.out.println("El PC está apagado.");
}
}
Características de la Poo
• Encapsulamiento
La 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
*/
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 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.
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.
Ejemplo 5.
class Empleado {
String nombre;
int numEmpleado, 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;
}
}
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:
Ejemplo 6.
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:
se producirá un error de compilación pues en la clase Empleado no existe ningún método llamado
asignarPresupuesto.
Ejemplo 7.
void showij() {
System.out.println("i y j: " + i + " " + j);
}
}
void showk() {
System.out.println("k: " + k);
}
void sum() {
System.out.println("i+j+k: " + (i+j+k));
}
}
class SimpleHerencia {
public static void main(String args[]) {
A superOb = new A();
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
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.
Ejemplo 8.
Ejemplo 9.
abstract class A {
abstract void callme();
class B extends A {
void callme() {
System.out.println("B's es una implementacion de callme.");
}
}
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
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()");
}
}
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) {
System.out.println("Error: jornal negativo!");
jornal = 0;
} // end if
this.jornal = jornal;
/**********************************************************************
* 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
return false;
} // end if
} // end igual
/**********************************************************************
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
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.
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:
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,
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)
Ejemplo 12.
/************************************************************************
* Una clase para representar un salesperson. Pago de jornal mas comisiones.
*
***********************************************************************/
public class Salesperson extends Empleado {
/**********************************************************************
* 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
* 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;
/**********************************************************************
* 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
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
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.*/
/**********************************************************************
* 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
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.
*
***********************************************************************/
De la misma forma como se ha realizado aquí podría construirse una nueva clase que resulte ser
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.
C A P I T U L O II
FUNDAMENTOS
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.
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/
System.out.println(″Hola La Serena!″);
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{ }.
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).
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
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
Comentarios:
Esto es un comentario que describe lo que el programa hace. Puede usar también //, en el
caso que sea solamente una línea.
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.
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
Se supone que Ud. cuenta con un editor de texto como NotePad, TextPad o JPadPro
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>
Compilar
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.
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;
. . .
}
}
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.
La plataforma JDK pone a disposición una serie de comandos y herramientas de utilidad entre
las cuales se encuentra:
Method Hola_Alumnos()
0 aload_0
1 invokespecial #1 <Method java.lang.Object()>
4 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
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.
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.
• 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).
• 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:
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
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.
Integers
Hemos 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
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.
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.
En los procesos de evaluación, Java asume que los operadores ∗, / y % tienen más alta
prioridad que la + y la −. Por ejemplo, 3+4∗5 es lo mismo que 3+(4∗5), 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, 3−4−5 es lo mismo que (3−4)−5, no
3−(4−5). 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.");
}
}
El Ejemplo2 es otra versión del programa Ejemplo1, esta vez haciendo uso de variables.
nos dice: crea una variable total que denota la expresión 6∗25 + 5∗10 + 0∗5 + 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.
Ejemplo 3
{
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;
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
Este programa parte creando 2 variables llamadas stones y libras . (1 stone = 14 libras.)
y declara
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.
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 15∗stones y el valor original en libras, obtendremos la respuesta en la variable
Escuela Ingeniería en Computación, Universidad de La Serena. 44
Dr. Eric Jeltsch F. Capítulo 3: Elementos del Lenguaje
libras += 14∗stones;
que dice: adicione 14∗stones 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++;
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.
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.075×1024), 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.8×10308, 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.
Escuela Ingeniería en Computación, Universidad de La Serena. 45
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.56×10−12.
Como cualquier tipo de dato, podemos declarar variables de tipo double. Por ejemplo,
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 x
Math.cos(x) coseno de x
Math.tan(x) tangente de x
Math.exp(x) ex
Math.log(x) log natural de x
Math.abs(x) valor absoluto de x
Math.floor(x) entero más grande que sea ≤ x
Math.ceil(x) entero más pequeño que sea ≥ x
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 = m∗n;
cuando Java ejecuta la tercera declaración evalua m∗n 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.
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.
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.
}
}
Clases de I/O
Por 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:
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:
(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.
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. */
System.out.println("Digame su peso.");
System.out.print("Cuantos stones: ");
stones = stdin.readLine();
num = Integer.parseInt( stones );
libras = stdin.readLine();
num1 = Integer.parseInt(libras);
Digame su peso.
Cuantos stones: 8
Cuantas libras: 5
Ud. 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
Aquí se muestra una nueva versión del programa Peso1.java , usando ConsoleReader.
Ejemplo 8
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
Digame su peso.
Cuantos stones: 8
Cuantas libras: 5
Ud. pesa 53.0712 kilos.
C:\Documents and
Settings\usuario\Escritorio\POO\lect_Jpoo_06\source2\PesoConsole.java:8: cannot
resolve symbol
symbol : 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 symbol
symbol : class ConsoleReader
location: class PesoConsole
{ ConsoleReader in = new ConsoleReader(System.in);
^
2 errors
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
Swing
Ejemplo 10.
import javax.swing.JOptionPane;
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.
CelsiusToFarehheit2
main
JOptionPane System.out
showInputDialog main
Integer DecimalFormat
intValue format
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 */
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.*;
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();
} //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
Si desea almacenar un string basta usar una variable de tipo String. Por ejemplo,
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 string
″El perro corre.″ Expresiones usuales en programas son por ejemplo, la declaración
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.″
El siguiente programa usa los métodos usuario.readLine() para leer el nombre del
usuario y usuario.readInt() para leer la edad.
Ejemplo 13
{ /* Chateando. */
public static void main(String[] args)
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 + ".");
}
}
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.
Ejemplo 14
System.out.println (s.length( ) );
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) );
}
}
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.
str1
“ abc ”
str2
área de memoria
Sin embargo, la utilización del operador new hace que se reserve o asigne memoria para un
nuevo objeto. Por ejemplo,
//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){}
Ejemplo 15
class StringTest {
Hola alumnos
Chao alumnos
crea un primer Objeto, e inserta una referencia a este objeto en str, y lo imprime
System.out.println(str);
System.out.println(str);
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
Escuela Ingeniería en Computación, Universidad de La Serena. 60
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
class StringTest1
{
public static void main ( String[] args )
{
String strA; // referencia al primer objeto
String strB; // referencia al segundo objeto
System.out.println( strB );
System.out.println( strA );
}
}
El programa imprime:
Hola alumnos
Chao alumnos
Hola alumnos
CAPÍTULO4
Estructuras de Control
Llegado a esta lección el alumno ya podrá escribir programas simples pero más 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
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);
}
}
}
Escuela Ingeniería en Computación, Universidad de La Serena. 62
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:
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.
conjunción (``and''):
true && true => true
E1 && E2
true && false => false
false && E2 => false
disjunción (``or''):
false || false => false
E1 || E2
false || true => true
true || E2 => true
negación(``not''):
!E !true => false
!false => true
(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.
Ejemplo 2
Otro ejemplo interesante es considerar el método: deposit(int monto): boolean, que
trata de especificar lo siguiente..
}
}
Ejemplo 3
{
ConsoleReader usuario =new ConsoleReader(System.in);
Ejemplo 4
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 (EXPRESION-Booleana)
Declaración
a = 5, b = 10, c = 3, d = 8.
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.
Ejemplo 5
Ingrese un número: -3
Número debe ser >=0.
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.
Aquí mostramos un programa completo que convierte un rango ingresado por usuario en
costos.
Ejemplo 6
public 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) S1
else if (B2) S2
else if (B3) S3
:
else if (Bn) Sn
else T
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,
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.
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;
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;
else if (replica.equals("no"))
estaRegistrado = false;
else
System.out.println("Replica no entendida.");
}
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.
*/
/* 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
= = 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 B2
B1 || 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 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.
Ejemplo 8
Ciclos
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;
}
Versión 1
Lea x la primera vez antes de partir el loop. Entonces la declaración while testea, si x≥0, 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 entrada
Y almacenelo en x;
while (x>=0)
{ Salida, la raíz cuadrada de x;
lea el siguiente valor de la entrada
y almacenelo en x;
}
Versión 2
Escuela Ingeniería en Computación, Universidad de La Serena. 75
Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control
Esta 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 3
La 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;
}
Ejemplo 9
while (true)
{ System.out.print("Ingrese el número: ");
double x = in.readDouble();
if (x<0) break;
System.out.println
Escuela Ingeniería en Computación, Universidad de La Serena. 76
Dr. Eric Jeltsch F. Capítulo 4: Estructuras de Control
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,
Por ejemplo,
(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++;
}
APLICACIONES
En 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.
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;
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.
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
Ejemplo 11
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
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.*;
System.out.println("Chao");
}
}
Lo siguiente es lo que aparece cuando el programa esta corriendo.
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
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));
}
Lo que realiza este programa es lo siguiente, así se visualiza su interacción con el usuario.
Ingrese el primer entero: 3
Ingrese 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
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
do
{
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);
}
}
C:\Documents and
Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\test.jav
a: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.jav
a: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.jav
a:4: ';' expected
}
^
C:\Documents and
Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\test.jav
a:5: '}' expected
^
4 errors
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.
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!);
}
}
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 );
^
C:\Documents and
Settings\usuario\Escritorio\POO\POO_web_CD\Java_poo\Libro_Base_java\Test1.java:
4: cannot resolve symbol
symbol : 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);
^
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();
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.
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.
Excepciones
Java 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.
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
}
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
Escuela Ingeniería en Computación, Universidad de La Serena. 89
Dr. Eric Jeltsch F. Capítulo 5: Excepciones y Flujo de Datos
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.
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);
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,
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.
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.
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 a la 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,
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();
}
}
}
}
}
Ejemplo 3
Por otra parte un archivo 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 abre (open) , y cuando terminamos
de usarlo, lo cerramos (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.
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 */
public class CopiarFile
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.
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));
}
catch(RuntimeException e) {
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.25
Lucy Riggs|42|24.50
Ethel 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.
class LeerInfo
Metodos
/** 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.*;
Para testear la clase LeerInfo, implementemos una clase principal llamada Pagos.java para
testearla.
import javax.swing.*;
public class Pagos{
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 6
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 7
import java.io.*;
/* 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,
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
al encabezado del método. Una clausula throws lista una o más exepciones, separadas por
comas.
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.
*/
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.
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.
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″));
Archivo
↓
FileReader
↓
BufferedReader
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 8
}
catch (NumberFormatException e)
{ System.out.println
("Datos malos: " + linea);
}
}
datos.close();
}
catch (IOException e)
{ System.out.println(e);
return;
}
/* promedio. */
if (cuanTos > 0)
System.out.println
("El promedio es = " + sum/cuanTos);
else
System.out.println("Ningún resultado.");
}
}
Notas
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.
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.*;
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″))
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..
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,
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
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.
Ejemplo 9
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");
CAPÍTULO 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
extends Nombre_Clase
implements lista_Interface {
Atributo
type Nombre Atributo;
Constructor
public Nombre_Clase ( )
{//...}
Método
public hola (...)
{//...}
Fig. 1
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.
Fig. 2
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 1
class Empleado {
String apellido;
String nombre;
int rut;
boolean esFemenino;
}
Ejemplo 2
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();
n.apellido = "Rojo";
n.nombre = "Maria”;
Escuela Ingeniería en Computación, Universidad de La Serena. 111
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
n.rut = 865;
n.esFemenino = true;
}
}
Constructores
Al 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);
Variables en la clase
En 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.
Escuela Ingeniería en Computación, Universidad de La Serena. 112
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
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);
}
}
Ejemplo 5
class Empleado {
String apellido;
String nombre;
int rut;
boolean esFemenino;
// una clase como tipo en una instancia-variable
Empleado ascenso;
// Constructor:
Empleado(String nn,String vn,int pn,boolean w,Empleado as) {
apellido = nn;
nombre = vn;
rut = pn;
esFemenino = w;
ascenso = as;
}
}
class EjemploClasecomoTipo {
public static void main(String args[]){
Empleado m, jefe; // una clase como tipo variable local
jefe = new Empleado("Rojo", "Martin", 341, false, null);
m = new Empleado("Meyer", "Hans", 11073, false, jefe);
}
}
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 Instanciados
Al interior de una clase cada declaración sin la palabra static describe un método instanciado.
Ejemplo 7
class 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(){
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 imprescindible
this.nombre = nombre; // "this" es imprescindible
int rut;
boolean esFemenino;
this.rut = pn; // "this" es imprescindible
this.esFemenino = w; // "this" es imprescindible
}
}
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();
}
}
Listas
En 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.
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)));
}
}
Arboles
En 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;
}
Escuela Ingeniería en Computación, Universidad de La Serena. 117
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
Arboles AVL
Métodos de Consulta
Al 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
4 10
2 6
1) En este árbol, son insertados los nodos con claves 9 y 11. Generándose el árbol T1 :
4 10
2 6 9 11
2) Basado en T, son insertados los nodos con claves 1, 3, 5 y 7. Generándose el árbol T2:
Escuela Ingeniería en Computación, Universidad de La Serena. 118
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
4 -2 10
2 -1 6
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
2 8
1 3 6 10
5 7
La inserción de las claves „3“, „5“ y „7“ no hacen perder la propiedad AVL.
Rotaciones
a) 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
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
Escuela Ingeniería en Computación, Universidad de La Serena. 119
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
substancial cambiar la estructura del árbol. Las figuras muestran también las variantes
simetricas.
k2 k1
k1 k2
Z
Y X Y Z
k1 k2
k2 k1
Y X Y 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.
// Constructores
public Nodo_Avl(Comparable datElem)
{
this(datElem, null, null );
}
public Nodo_Avl( Comparable datElem, Nodo_Avl ib, Nodo_Avl db )
{
datos = datElem;
Escuela Ingeniería en Computación, Universidad de La Serena. 120
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
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;
}
k3 k2
k1 k1 k3
D
k2
B C
A A D
B C
K3 k2
K1 k3 k1
A k2
D B C
A D
B C
/*
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 ); }
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 utilidad
Escuela Ingeniería en Computación, Universidad de La Serena. 123
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
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.
class Nodo_Avl
{
// Instancias
// Constructores
public Nodo_Avl(Comparable datElem)
{
this(datElem, null, null );
}
Archivo Arbol_Avl.java
/*
/*
* Eliminar el arbol.
*/
//no esta implementado....
/*
* Test, si el arbol esta vacio o no.
* devuelve true, caso de vacio; sino false.
*/
/*
* 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
*/
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.
*/
/*
* Analogamente al anterior pero el más grande.
*/
/*
* 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);
}
}
/*
archivo Arbol_AvlTest.java
}
}
Salida que se genera:
Travesia en Inorden(Izq-Raiz-Der)
4
14
35
39
52
64
74
75
77
Interpretación de la salida
Arbol girado en 90 grados
0
1
2
3
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).
1 5
0 2 4 6
a insertado
AVL con balanceo:
a(0)
b insertado
AVL con balanceo:
b(0)
a(1)
c insertado
AVL con balanceo:
c(0)
b(0)
a(0)
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 Empleado
String nombre; // copia de la clase Empleado
int rut; // copia de la clase Empleado
boolean esFemenino; // copia de la clase Empleado
String tarifa;// trato preferencial??
// Constructor
Colaborador (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.
Herencia
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
Juan Susana
Ejemplo 13
// Empleado como subclase de Persona
class Empleado extends Persona {
// componentes heredadas:directo de Persona:
apellido, nombre, esFemenino.
// nueva declaración de componente objeto:
int rut;
Escuela Ingeniería en Computación, Universidad de La Serena. 132
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
// constructor
Empleado (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 + ")");
}
}
Persona
Apellido : String
Nombre: String
esFemen: boolean
Empleado alumno
Rut : int carrera: String
Salida (·) Semestre: byte
Colaborador
Tarifa: String
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.
class Persona {
...
}
//posee el mismo significado que
class Persona extends Object {
...
}
Herencia y Constructores
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
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 parametros
pago(empleado);
}
}
Sobreescritura de métodos
Ejemplo 16
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.
Escuela Ingeniería en Computación, Universidad de La Serena. 137
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
Importante: Los métodos abstractos al igual como otros métodos son heredados.
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
this.matriculaNo = matriculaNo;
return true;
}
else
return false;
} //setMatriculaNo()
interface nombreEntidad
{ String getNombre();
boolean setNombre(String newNombre);
} //interface nombreEntidad
Modelamiento UML
Persona nombreEntidad
<<interface>>
nombre: String
getNombre( ) : String
setNombre(String newNombre): boolean
Alumno
matricNº: String
getNombre: String
setNombre(String newNombre): boolean
getMatricNº( ) : String
setMatricNº(String newMN): boolean
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:
case DOCTOR:
case PROFESOR:
System.out.println("Titulo o grado");
break;
case SIN_TITULO:
default:
System.out.println("Sin Titulo");
break;
}
}
}
Paquetes
Generalmente 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 NombrePaquete
package AdministracióndelPersonal
class 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 NombrePaquetes
package AdministracióndelPersonal;
// Importando la clase java.lang.Object
// (Sin más ni más, siempre esta este paquete presente)
import java.lang.Object;
class Persona extends Object {
String apellido;
Escuela Ingeniería en Computación, Universidad de La Serena. 142
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
String nombre;
boolean esFemenino;
Persona () {
}
Persona(String apellido, String nombre, boolean esFemenino) {
this.apellido = apellido;
this.nombre = nombre;
this.esFemenino = esFemenino;
}
}
Java-Paquetes Estandar
Para Java existe un gran conjunto de paquetes estandares, en donde las clases e interfaces para
diferentes aplicaciones están a disposición.
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
orientada a objetos, la atención se aleja de las funciones y se acerca a las cosas (objetos) que
Escuela Ingeniería en Computación, Universidad de La Serena. 143
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
Como puede notar algunos conceptos de la POO son análogos a los métodos de programación
convencional, por ejemplo.
Una clase es como un tipo abstracto de datos, aunque para la POO, el proceso de escribir no se
revela fuera de la clase.
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.
orientadas a objetos significa aprender las diferencias así como las similitudes entre este
método y la programación convencional.
Un ejemplo practico.
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.
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.
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.
/**
* Una clase que representa una pregunta de un examen.
Escuela Ingeniería en Computación, Universidad de La Serena. 145
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
*
*/
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.
*/
/**
* 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();
• 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
/**
* 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
*/
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) {
Escuela Ingeniería en Computación, Universidad de La Serena. 147
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
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
• 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.
*/
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
• 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).
/**
* 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 {
Escuela Ingeniería en Computación, Universidad de La Serena. 149
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
/**
* 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
*/
if (usuText.length() != 1) {
System.out.println("Error: por favor ingrese un caracter simple");
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
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 método agregaPregunta() , el que toma una pregunta (de cualquier tipo) como
argumento y la agrega al examen.
/**
* 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.
*/
public static final int MAX_PREGUNTAS = 10;
/**
* El nº actual de preguntas actualmente en el examen.
*/
private int numPreguntas = 0;
/**
Escuela Ingeniería en Computación, Universidad de La Serena. 151
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
/**
* 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
*/
/**
* 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
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 {
/**
Escuela Ingeniería en Computación, Universidad de La Serena. 152
Dr. Eric Jeltsch F. Capítulo 6: Programación Orientada a Objetos
Salida:
CAPITULO 7
Eventos
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.
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
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
Escuela Ingeniería en Computación, Universidad de La Serena. 155
Dr. Eric Jeltsch F. Capitulo 7: Eventos
para nombrar o rescribir un archivo. Notar un dato importante, todos los componentes Swing
son subclases de la clase JComponent.
Eventos
Para 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.*;
// Otras referencias
private static String mensaje = "¡¡¡Hola mundo!!!";
Marco
Panel
Etiqueta
Botón
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.*;
add(amaButton);
add(azulButton);
add(rojoButton);
amaButton.addActionListener(this);
azulButton.addActionListener(this);
rojoButton.addActionListener(this);
}
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
Escuela Ingeniería en Computación, Universidad de La Serena. 159
Dr. Eric Jeltsch F. Capitulo 7: Eventos
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.
• 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.
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.
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.*;
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.
Escuela Ingeniería en Computación, Universidad de La Serena. 161
Dr. Eric Jeltsch F. Capitulo 7: Eventos
import javax.swing.*;
public class MiniSwing4 {
public static void main(String args[]) {
JFrame miFrame = new JFrame();
miFrame.setSize(200, 100);
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 );
}
}
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);
Escuela Ingeniería en Computación, Universidad de La Serena. 162
Dr. Eric Jeltsch F. Capitulo 7: Eventos
} // end main
} // end class MiniSwing7
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.
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();
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.
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
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.
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);
Ahora para darle el tamaño que Ud. desee al windows, reemplace la línea miframe.pack()
por miframe.setSize(400, 120); por ejemplo
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.
componentRemoved getChild
getContainer
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.
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.
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.
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.
import javax.swing.*;
import java.awt.event.*;
/**
* Un window listener que reporta todos los eventos window a la consola.
*/
class WindowReporter implements WindowListener {
/*
* 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.
*/
/*
* 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.
*/
/*
* 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
Pero no debería este programa llamarlo a confusión, pues si Ud. desea solamente terminar el
programa, debería hacer algo como sigue:
Otra técnica que puede ser útil es proceder en función de la clase del componente. Por
ejemplo:
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.
Escuela Ingeniería en Computación, Universidad de La Serena. 171
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) { }
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
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,
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
Escuela Ingeniería en Computación, Universidad de La Serena. 172
Dr. Eric Jeltsch F. Capitulo 7: Eventos
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
}
}
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
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.
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 EVENTOS
Los eventos se catalogan por su naturaleza, que se indicará en el miembro id de su estructura.
Eventos de Ventana
Son los que se generan en respuesta a los cambios de una ventana un frame o un dialogo.
WINDOW_DESTROY
WINDOW_EXPOSE
WINDOW_ICONIFY
WINDOW_DEICONIFY
WINDOW_MOVED
Eventos de Teclado
Son generados en respuesta a cuando el usuario pulsa y suelta una tecla mientras un
Componente tiene el foco de entrada.
KEY_PRESS
KEY_RELEASE
KEY_ACTION
KEY_ACTION_RELEASE
/**
* keyDemo, para visualizar el uso de
KEY_PRESS
KEY_RELEASE
KEY_ACTION
KEY_ACTION_RELEASE
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
Eventos de Ratón
Son los eventos generados por acciones sobre el ratón dentro de los límites de un Componente.
MOUSE_DOWN
MOUSE_UP
MOUSE_MOVE
MOUSE_ENTER
MOUSE_EXIT
MOUSE_DRAG
Eventos de Barras
Son los eventos generados como respuesta a la manipulación de barras de desplazamiento
(scrollbars).
SCROLL_LINE_UP
SCROLL_LINE_DOWN
SCROLL_PAGE_UP
SCROLL_PAGE_DOWN
SCROLL_ABSOLUTE
Eventos de Lista
Son los eventos generados al seleccionar elementos de una lista.
LIST_SELECT
LIST_DESELECT
Eventos Varios
Son los eventos generados en función de diversas acciones.
ACTION_EVENT
LOAD_FILE
SAVE_FILE
GOT_FOCUS
LOST_FOCUS
CAPÍTULO 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ón
MiBoton = new JButton(“Pulse aquí”);
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.
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){
Escuela Ingeniería en Computación, Universidad de La Serena. 177
Dr. Eric Jeltsch F. Capítulo 8: Swing
//proceso a ejecutar.
}
};
boton.addActionListener(al);
Otra técnica que puede ser útil es proceder en función de la clase del componente. Por
ejemplo:
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
nivel superior y controles. La siguiente figura nos muestra algo al respecto, en donde se tiene
un marco, con un panel
Marco(Frame)
Panel
Marco(Frame)
Panel
Botón
Etiqueta
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
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:
getContentPane().add(panel, BorderLayout.CENTER);
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:
• 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).
columnas.
• BoxLayout. Diseño en caja. Coloca los componentes en el contenedor en una única fila o
columna, ajustándose al espacio que haya.
panel.setLayout(new GridLayout(0,1));
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:
Ejemplo
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;
public Swinger() {
super("Swinger");
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.
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.
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 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,
• Componentes Listener
Al 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.
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.
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
ActionListener implementa deben tener un método con una estructura como la siguiente:
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 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();
}
}
Escuela Ingeniería en Computación, Universidad de La Serena. 186
Dr. Eric Jeltsch F. Capítulo 8: Swing
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.
Tras de pulsar, Eric
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.*;
add(amaButton);
amaButton.addActionListener(this);
azulButton.addActionListener(this);
rojoButton.addActionListener(this);
}
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
JTextField y JPasswordField
Ejemplo.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public TextFieldDemo() {
super( "Demo de JTextField y JPasswordField" );
Container c = getContentPane();
c.setLayout( new FlowLayout() );
app.addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent e )
{
System.exit( 0 );
}
}
);
}
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 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 );
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 Ajuste
Los 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
Ejemplo
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
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();
frame.pack();
frame.setVisible(true);
}
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.
CAPÍTULO 9
Swing: Layout y Eventos
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
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
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 MouseDemo() {
super( "Demo para Eventos del Mouse" );
statusBar = new JLabel();
getContentPane().add( statusBar, BorderLayout.SOUTH );
app.addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent e )
{
System.exit( 0 );
}
}
);
}
}
Notar que:
Ejemplo:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
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();
}
}
);
}
}
*
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
Ejemplo:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
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 );
String temp =
e.getKeyModifiersText( e.getModifiers() );
textArea.setText(
linea1 + "\n" + linea2 + "\n" + linea3 + "\n" );
}
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,
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.
luego agregamos o incrustamos al panel o contenedor c a cada uno de ellos, por ejemplo,
c.add( izq );
izq.addActionListener()
Ejemplo:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public FlowLayoutDemo()
{
super( "Demo para FlowLayout" );
c = getContentPane();
c.setLayout( layout );
setSize( 300, 75 );
show();
}
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 BorderLayoutDemo()
{
super( "Demo para BorderLayout" );
//especifica el número de pixeles de distancia entre los //componentes
layout = new BorderLayout( 5, 5 );
Container c = getContentPane();
Escuela Ingeniería en Computación, Universidad de La Serena. 201
Dr. Eric Jeltsch F. Capítulo 9: Swing: Layout y Eventos
c.setLayout( layout );
app.addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent e )
{
System.exit( 0 );
}
}
);
}
}
Ejemplo:
Escuela Ingeniería en Computación, Universidad de La Serena. 202
Dr. Eric Jeltsch F. Capítulo 9: Swing: Layout y Eventos
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
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 );
hola = !hola;
//recomputa el layout contenedor basado sobre el layout //manager actual
c.validate();
}
app.addWindowListener(
Escuela Ingeniería en Computación, Universidad de La Serena. 203
Dr. Eric Jeltsch F. Capítulo 9: Swing: Layout y Eventos
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 PanelDemo()
{
super( "Demo para Panel" );
Container c = getContentPane();
botonPanel = new JPanel();
botones = new JButton[ 5 ];
botonPanel.setLayout(
new GridLayout( 1, botones.length ) );
app.addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent e )
{
System.exit( 0 );
}
}
);
}
}
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:
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
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
Escuela Ingeniería en Computación, Universidad de La Serena. 206
Dr. Eric Jeltsch F. Capítulo 10: GUI Avanzados.
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.
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í:
super.paintComponent( g );
if ( figura == CIRCULO )
g.fillOval( 50, 10, 60, 60 );
else if ( figura == CUADRADO )
g.fillRect( 50, 10, 60, 60 );
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
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(
new ActionListener() {
JTextArea
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.
Ejemplo
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
p.add(botonInsercion);
botonInsercion.addActionListener(this);
getContentPane().add(p, "South");
setTitle("TextArea Demo");
setSize(300, 300);
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent e)
{ System.exit(0);
}
} );
}
Ejemplo
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
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:
Ejemplo
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
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);
getContentPane().add(miPanel, "Center");
validate();
}
class GridLayout
constructores:
GridLayout(int rows, int cols)
GridLayout(int rows, int cols,
int hgap, int vgap)
void setHgap(int hgap)
void setVgap(int vgap)
class ImageIcon
constructor:
ImageIcon(String filename)
class JButton
constructores:
JButton()
JButton(String text)
JButton(Icon icon)
JButton(String text, Icon icon)
abstract class JComponent
void setActionCommand(String accionComand)
void setPreferredSize(Dimension prefeSize)
// use new Dimension(width, height)
class JDialog (opcional)
contiene más metodos usados por JFrame:
void setModal(boolean b)
class JFrame
constructores:
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 closed
void setJMenuBar(JMenuBar menubar)
class JLabel
constantes: LEFT, CENTER, RIGHT
constructores:
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 JMenu
constructores:
JMenu()
JMenu(String text)
Component add(Component c)
void addSeparator()
void remove(Component c)
class JMenuBar
constructor:
JMenuBar()
JMenu add(JMenu c)
class JMenuItem
constructores:
JMenuItem()
JMenuItem(String text)
JMenuItem(String text, int mnemonic)
JMenuItem(Icon icon)
C A P Í T U L O 11
GUI Avanzado (Menu 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
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,
Escuela Ingeniería en Computación, Universidad de La Serena. 219
Dr. Eric Jeltsch F. Capítulo 11:Menu con Swing
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
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.
java.lang.Object
|
+---java.awt.MenuComponent
|
+---java.awt.MenuBar
|
+---java.awt.MenuItem
|
+---java.awt.Menu
|
+---java.awt.PopupMenu
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.
Menu
abajo
Luz(on/off) CheckboxMenuItem
Creando Menus
Es fácil construir un menu, el orden típico es
Los constructores que Ud. necesita son muy simples. Por ejemplo, para crear un objeto nuevo
MenuBar, basta con declarar:
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,
También puede crear MenuItems al interior de los menus, por ejemplo: Cortar, Copiar, Pegar,
Limpiar y seleccionar todos los MenuItems:
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;
La 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();
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 usar un procedimiento que lo realice. Nosotros mostramos dos modalidades. En
este ejemplo se muestra la primera modalidad en donde se realiza:
Ejemplo:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public MenuTest() {
super( "Usando JMenus" );
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 );
}
}
Escuela Ingeniería en Computación, Universidad de La Serena. 225
Dr. Eric Jeltsch F. Capítulo 11:Menu con Swing
);
miFileMenu.add( sobreItem );
exitItem.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e )
{
System.exit( 0 );
}
}
);
miFileMenu.add( exitItem );
fontMenu.addSeparator();
formatMenu.add( fontMenu );
miBar.add( formatMenu ); // agrega formato al menu
getContentPane().setBackground( Color.cyan );
getContentPane().add( desplegar, BorderLayout.CENTER );
app.addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent e )
{
System.exit( 0 );
}
}
);
}
repaint();
}
}
if ( estiloItems[ 0 ].isSelected() )
estilo += Font.BOLD;
if ( estiloItems[ 1 ].isSelected() )
estilo += Font.ITALIC;
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.*;
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();
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();
}
Escuela Ingeniería en Computación, Universidad de La Serena. 229
Dr. Eric Jeltsch F. Capítulo 11:Menu con Swing
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());
}
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
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public miMenuSimple() {
Para concluir, es una manera de decir que el semestre termina, 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 and Feel, que es capaz de simular interfaces de Motif,
Windows que son interfaces gráficas de sistemas propietarios.
//clases LookAndFeel
MetalLookAndFeel metalLF = new MetalLookAndFeel();
MotifLookAndFeel motifLF = new MotifLookAndFeel();
WindowsLookAndFeel windowsLF = new WindowsLookAndFeel();
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);
}
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());
}
System.out.println(ex);
}
}
}
}
}
Actividades on-line:
Qué cambios debería darle al código para que la interfaz se viese así?
JSlider
Una declaración más o menos típica de JSlider son estructuras del tipo,
indica que cada tick marcado representa 10 como valor en el rango de valores soportado por
JSlider,
miJSlider.setMajorTickSpacing(10);
miJSlider.setPaintTicks(true);
Ejemplo