Sie sind auf Seite 1von 391

Tema0.

Introduccin a Java
Paradigmas de programacin
Programacin orientada a objetos
El lenguaje Java
Caractersticas de Java
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 2/14
Paradigmas de programacin
Dos paradigmas de programacin:
Modelo orientado a procesos: los programas son una
serie de pasos lineales (ej. C)
Qu est pasando?
Cdigo actuando sobre datos
Programacin orientada a objetos: organiza un
programa alrededor de sus datos (objetos) y
un conjunto de interfaces bien definidas
Quin est siendo afectado?
Datos controlando el acceso al cdigo
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 3/14
Programacin
orientada a objetos
Aparece a finales de los 60, pero es a principios
de los 80 cuando con el lenguaje Smalltalk
comienza un inters claro hacia este paradigma.
La programacin orientada a objetos es el
paradigma de programacin y anlisis y diseo de
aplicaciones claramente dominante en la
actualidad.
Hoy prcticamente no se concibe un lenguaje de
programacin sin caractersticas de orientacin a
objetos: Eiffel, C++, Java, C#, etc.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 4/14
Programacin
orientada a objetos
Las ventajas del paradigma OO son mltiples:
Es intuitiva, describe un problema en trminos similares a los que
utiliza la mente humana.
Permite construir soluciones ms seguras y con un mantenimiento
ms sencillo.
Fomenta la reutilizacin y el trabajo en equipo. Escalabilidad de
las aplicaciones.
Las caractersticas principales del paradigma OO:
Incorpora los conceptos de abstraccin y encapsulacin
heredados de los tipos de datos abstractos.
Incorpora mecanismos especficos y extremadamente poderosos
como son la herencia y el polimorfismo.
Admite de manera muy natural en algunos lenguajes el soporte de
genericidad (patrones) y la definicin de operadores.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 5/14
Conceptos bsicos de la POO
Clase
Define las caractersticas abstractas de una cosa
Lo que le caracteriza (atributos)
Las cosas que puede hacer (mtodos)
Objeto
Una instancia particular de una clase
Los valores de sus atributos conforman su estado
Mtodos
Las habilidades asociadas a un objeto
Paso de mensajes
Para enviar datos a otro objeto o invocar un mtodo
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 6/14
Programacin
orientada a objetos
El desarrollo siguiendo el enfoque orientado a objetos es un
proceso integral que incluye mtodos especficos de anlisis y
diseo, notacin grfica (UML) y lenguajes de programacin
orientados a objetos
Las soluciones obtenidas durante la fase de anlisis y diseo no
son especficas para ningn lenguaje de POO.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 7/14
El lenguaje Java
Desarrollado en los laboratorios de Sun, es uno de los
lenguajes de programacin orientado a objetos que mayor
repercusin ha tenido en los ltimos aos
Basado en C++ pero simplificado, mucho ms fcil de
usar, de ms alto nivel y menos propenso a errores
Amplsima biblioteca estndar de clases predefinidas
Las aplicaciones Java pueden ser ejecutadas en
cualquier plataforma sin necesidad de recompilacin
Gestin avanzada de memoria mediante un recolector de basura
Gestin avanzada de errores, tanto en tiempo de compilacin
como de ejecucin
Lenguaje abierto. Existen kits de desarrollo y numerosa
documentacin gratuitos en la red
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 8/14
Introduccin histrica
GREEN
Patrick Naughton y James Gosling, Sun Microsystems, 1991
Pequeo lenguaje para receptores de TV por cable.
Cdigo ligero.
Multiplataforma.
OAK
Propuesta anterior de N. Wirth: USCD Pascal.
La portabilidad del cdigo se consigue con
bytecodes y una mquina virtual.
Experiencia previa de los diseadores en C++.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 9/14
Introduccin histrica
*7
Fracaso de un controlador remoto en 1992.
First Person Inc
1993 y primera mitad de 1994. Fracaso
empresarial.
Explosin de Internet: el navegador.
Mosaic & Netscape (J. Clark y
M. Andreessen).
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 10/14
Introduccin histrica
Java
Navegador construido en Java:
HotJava (Naughton y Payne, 1995)
Finales de 1995 Netscape 2.0 incluye soporte para Java.
Sun desarrolla lanza Java a principios de 1996.
IBM, Symantec, etc. tambin
incluyen el soporte a Java.
Microsoft tambin soporta Java.
En 1998 Sun lanza Java 2.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 11/14
Caractersticas de Java
Orientado a objeto
Simple
Distribuido
Robusto
Seguro
Multiplataforma
Portable
Interpretado
Multihilo
Dinmico
Compilacin, bytecode y JVM
Java sigue un esquema no tradicional de compilacin/ejecucin
La compilacin genera un ejecutable en bytecode o cdigo intermedio
independiente
Para su ejecucin se requiere un JRE especfico de la plataforma formado
por una mquina virtual java (JVM) y las libreras de clases.
La JVM interpreta el bytecode o realiza su compilacin just-in-time para
que su ejecucin sea ms eficiente
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 13/14
Compilacin, bytecode y JVM
Ventajas de este sistema:
Se compila la aplicacin una nica vez y los ejecutables en bytecode obtenidos
son vlidos para cualquier plataforma. El cdigo fuente queda a salvo.
Es muy robusto. La mquina virtual Java es capaz de detectar y notificar gran
cantidad de errores durante la ejecucin de la aplicacin (como accesos a
elementos fuera de un vector).
El recolector de basura no ocupa espacio en el ejecutable, ya que viene
integrado en la JVM.
Los ejecutables son pequeos porque las libreras de clases vienen
proporcionadas junto a la JVM en el JRE de la plataforma concreta.
Inconvenientes:
Velocidad. Evidentemente la interpretacin o incluso compilacin just-in-time del
bytecode produce aplicaciones ms lentas que la ejecucin directa de un binario.
El recolector de basura puede suponer una sobrecarga adicional a la CPU.
La generalidad tiene como inconveniente que no se aprovecha totalmente la
potencia de la mquina y del sistema operativo.
Java vs otros lenguajes OO
Java C# C++ Eiffel Smalltalk
Ao aparicin 1995 2000 1985 1985 1970
Sintaxis Ins. C++ Ins. Java Ins. C Ins. Pascal Original
Difusin Amplia Amplia Amplia Limitada Limitada
Librera de clases Muy amplia Muy amplia Escasa Amplia Amplia
Recolector basura S S No S S
Manejo objetos Dinmico Dinmico Est./Din. Est./Din. Dinmico
Tipo ejecutable Bytecode IL Code Binario Binario Bytecodes
Ejecucin Mediante JVM Mediante CLR Directa Directa Mediante SVM
Velocidad ejecutable Media Media Muy alta Alta Baja
Soporte excepciones S S S S S
Herencia mltiple No No S S No
Soporte operadores Muy limitado Limitado S S No
Soporte plantillas No No S S No
Tema1. El entorno de
programacin Java
Distribuciones y desarrollo Java
Funcionamiento de Java
El entorno de programacin
Estructuras fundamentales en Java
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 2
Distribuciones de Java
Existen distintas ediciones de Java para el desarrollo de
aplicaciones en distintos mbitos:
Aplicaciones de propsito general (J2SE)
Aplicaciones de gestin en entornos empresariales (J2EE)
Aplicaciones para telfonos mviles, PDAs y otros dispositivos
electrnicos que permitan aplicaciones empotradas (J2ME)
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 3
Distribuciones de Java
La ms utilizada es sin duda la edicin estndar (J2SE). Los
ejemplos de cdigo Java que veremos a lo largo de los siguientes
temas pertenecen a esta edicin.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 4
Distribuciones de Java
Existen dos kits diferentes descargables de la pgina de Sun:
Java Development Kit (JDK) permite desarrollar y ejecutar aplicaciones
Java Runtime Environment (JRE) permite nicamente la ejecucin
J2SE incluye bibliotecas muy extensas y completas, que permiten
la implementacin de casi cualquier tipo de aplicacin:
Seguridad
EEDDs
Componentes (JavaBeans)
Internacionalizacin
Entrada/Salida
XML
Redes y acceso a Internet
Programacin distribuida (RMI)
Matemtica de precisin arbitraria
Sonido
Interfaz de usuario (AWT, Swing)
Grficos 2D
Manipulacin, carga y descarga
de imgenes
Impresin
Acceso a bases de datos (JDBC)
Gestin de preferencias y
configuraciones
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 5
Entornos de desarrollo Java
JDK
El kit de desarrollo bsico proporcionado por Sun.
Es lo mnimo que se necesita para desarrollar. til si
se necesita compilar aplicaciones Java de manera
espordica o en general para programadores con
espiritu espartano. Puede bajarse gratuitamente
para cualquier plataforma de java.sun.com.
NetBeans
Entorno integrado de desarrollo Java de Sun,
realizado ntegramente en Java (y por tanto
multiplataforma). Consume bastantes recursos.
Permite disear ventanas, escribir cdigo,
compilar, ejecutar etc. Puede obtenerse gratis en
www.netbeans.org.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 6
Entornos de desarrollo Java
Borland Jbuilder
Excelente entorno integrado de desarrollo Java de
Borland. Al igual que Netbeans, tambin est
realizado ntegramente en Java. Existen versiones
limitadas que pueden bajarse de www.borland.com
Microsoft Visual J++
Uno de los ms populares, aunque las
aplicaciones obtenidas pueden presentar
problemas de compatibilidad con el SDK oficial
de Java, por el uso de libreras especificas de
Microsoft.
Otros: Eclipse, IBM WebSphere, Oracle JDeveloper, etc.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 7
Funcionamiento de Java
Programacin Compilador
Intrprete Ejecucin
myProgram.java
cdigo fuente
bytecode
myProgram.class
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 8
Funcionamiento de Java
Cdigo fuente
Secuencia de instrucciones que forma el programa y que puede
ser escrita con cualquier editor.
Bytecode
Dialecto de ms bajo nivel que el cdigo fuente, es decir, ms
cercano a las instrucciones mquina. Se obtiene al compilar el
cdigo fuente y no es directamente ejecutable. Para ser
ejecutado precisa la Java VM.
Mquina Virtual (MV)
Hace posible que el bytecode, que no es cdigo maquina
especfico para ninguna mquina, se ejecute en cualquier
plataforma para la que exista una MV.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 9
Comandos bsicos
Comando Funcin
javac Es el compilador de Java, convierte programas escritos en Java a bytecodes.
java Es el intrprete de Java, permite ejecutar los bytecodes.
javadoc Genera la documentacin API en formato HTML a partir del cdigo fuente Java.
jdb Debugger de Java.
javap Desensambla archivos Java (bytecodes).
javah
Crea las cabeceras y estructuras en C correspondientes a una clase Java.
Esto permite la invocacin de mtodos nativos (en C o C++) desde programas
escritos en Java.
appletviewer Permite ejecutar applets sin necesidad de emplear un navegador web.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 10
Lenguaje Java
/* myProgram.java */
class myProgram {
public static void main(String args[]) {
int num; // Declaracin de variable de tipo entero
num = 100; // asignacin a num del valor 100
System.out.println(Esto es num: + num);
num = num * 2;
System.out.println(El doble de num es: + num);
}
}
Programacin
myProgram.java
cdigo fuente
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 11
Lenguaje Java
Compilador
javac <opciones> <ficheros en java>
javac myProgram.java
Opcin Significado
-classpath <dirs>
busca las clases necesarias en los directorios mencionados
-verbose
da informacin de todo lo que hace el compilador
-d <directorio>
pone el resultado de la compilacin (el fichero .class) en el
directorio indicado
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 12
Lenguaje Java
Java bytecode
myProgram.class
Compilador
Se obtiene
MV
Mac
MV
Windows
MacOS Windows
MV
Linux
Linux
MV
Solaris
Solaris
HW
Java
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 13
Lenguaje Java
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 14
Lenguaje Java
Intrprete
java <opciones> <ficheros en java>
java myProgram
Opcin Significado
-classpath <dirs>
busca las clases necesarias en los directorios mencionados
-verbose
da informacin de todo lo que hace el intrprete
-version
indica el nmero de versin del intrprete
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 15
Lenguaje Java
Alternativa para mayor velocidad de ejecucin
Interpretacin de bytecodes es lenta
Esquema de compilacin dinmica just-in-time
Intrprete
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 16
Lenguaje Java
Ejecucin
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 17
Texto que no aparece en el programa ejecutable
Comentario de lnea
Comentarios largos
Comentarios
System.out.println(We will not use Hello world!);
// is this too cute?
/* This is the first sample program in Core Java
Copyright 1998 Cay Horstmann and Gary Cornell
*/
public class FirstClass {
public static void main (String[] args) {
System.out.println(Hello world!);
}
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 18
Tipos de datos
Java es un lenguaje fuertemente tipado
int 4 bytes -2.147.483.648 a 2.147.483.647
short 2 bytes -32.768 a 32.767
long 8 bytes -9.223.372.036.854.775.808L a
9.223.372.036.854.775.807L
byte 1 byte -128 a 127
double 8 bytes 1.79769313486231570E+308
float 4 bytes 3.40282347E+38F
char 2 bytes 0 a 65.535
boolean 1 bit true o false
Enteros
Coma
flotante
Caracteres
Booleano
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 19
Variables
Son la unidad bsica de almacenamiento
int numEntero; // nmero entero
double numDoble; // nmero de doble precisin
boolean listo = true; // variable booleana
char letra; // variable de tipo carcter
int a, b; // dos variables de tipo entero
int foo; // esto es una declaracin
foo = 37; // esto es una asignacin
foo = foo + 2; // tambin es una asignacin
int i = 10; // esto es una inicializacin
int j = 2 * i; // esto es una inicializacin dinmica
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 20
Conversin de tipos
Promocin de variables
Se pueden asignar sin un cast explcito
Truncado
Posible prdida de informacin
byte short int long float double
char int
byte b;
int i,
double d = 257.351;
i = (int) d; //i = 257
b = (byte) i; //b = 1
double x = 9.997;
int nx = (int) x;
double x = 9.997;
int nx = (int)Math.round(x);
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 21
Constantes
Se utiliza la palabra reservada final
Slo se puede asignar la variable una vez
Su valor se establece para siempre y no se modifica
Se suelen nombrar en maysculas
public class UsesConstants {
public static void main (String[] args) {
final double CM_PER_INCH = 2.54;
double paperWidth = 8.5;
double paperHeight = 11;
System.out.println(Paper size in centimeter:
+ paperWidth * CM_PER_INCH + by
+ paperHeight * CM_PER_INCH);
}
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 22
Bloques y alcances
Un bloque de sentencias es un conjunto de sentencias
simples de Java entre dos corchetes
Los bloques definen el alcance de las variables
No pueden declararse variables con el mismo nombre dentro de
un mismo bloque
{
int n;
. . .
{
int k;
. . .
}
// k variable local del bloque
// y definida nicamente
// hasta el final del bloque
}
{
int n;
. . .
{
int k;
int n;
. . .
}
// error no se puede redefinir
// n en el bloque inferior
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 23
Operadores aritmticos
Operadores aritmticos usuales
int i = n + 2; // suma
int a = 2 * i; // producto
int b = a - 17; // resta
int c = n / 2; // divisin
int d = n % 2; // mdulo
int m = 7;
int n = 7;
a = 2 * ++m; //a igual a 16
a = 2 * m++; //a igual a 14
-- Decremento
++ Incremento
% Mdulo
/ Divisin
* Producto
- Resta
+ Suma
Operadores con asignacin
En general cualquier operador antes del signo =
x += 5; // esto es
x = x + 5; // equivalente
y *= 2; // esto es
y = y * 2; // equivalente
Operadores a nivel de bits
<<<= Desplazamiento a izquierda rellenando con ceros y asignacin
<<= Desplazamiento a izquierda y asignacin
>>>= Desplazamiento a derecha rellenando con ceros y asignacin
>>= Desplazamiento a derecha y asignacin
^= XOR a nivel de bit y asignacin
|= OR a nivel de bit y asignacin
&= AND a nivel de bit y asignacin
<<< Desplazamiento a izquierda rellenando con ceros
<< Desplazamiento a izquierda
>>> Desplazamiento a derecha rellenando con ceros
>> Desplazamiento a derecha
^ XOR a nivel de bit
| OR a nivel de bit
& AND a nivel de bit
~ NOT a nivel de bit
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 25
Operadores lgicos
NOT unario lgico !
AND lgico &
OR lgico |
XOR lgico ^
AND en cortocircuito &&
OR en cortocircuito | |
AND y asignacin &=
OR y asignacin |=
XOR y asignacin ^=
Igual a ==
Distinto de !=
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 26
Jerarqua de los operadores
Operador Asociacin
() [] .
izquierda a derecha
++ -- ~ !
derecha a izquierda
* / %
izquierda a derecha
+ -
izquierda a derecha
<< >> >>>>
izquierda a derecha
< <= > >=
izquierda a derecha
== !=
izquierda a derecha
&
izquierda a derecha
|
izquierda a derecha
&&
izquierda a derecha
||
izquierda a derecha
= (op)=
derecha a izquierda
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 27
Sentencias condicionales
Seleccin IF
if (print == true)
System.out.println(A);
if (yourSales >= target) {
performance = OK;
bonus = 100;
}
if (condicin) sentencia;
if (condicin) { bloque }
yourSalestarget
performance = OK
bonus = 100
NO
S
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 28
Sentencias condicionales
Seleccin IF-ELSE
if (yourSales >= 2 * target) {
performance = Excellent;
bonus = 1000;
}
else if (yourSales >= 1.5 * target) {
performance = Fine;
bonus = 500;
}
else if (yourSales >= target) {
performance = Satisfactory;
bonus = 100;
}
else {
fired = true;
}
if (condicin) sentencia
1
else sentencia
2
;
if (condicin) { bloque
1
} else { bloque
2
};
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 29
Bucles indeterminados
Bucle DO-WHILE
do {
//bloque sentencias
} while (condicin);
Bucle WHILE
while (condicin) {
//bloque sentencias
}
boolean seguir;
int numero, cociente, resto;
cociente=0;
resto=numero;
seguir = (numero > divisor);
while (seguir) {
cociente++;
resto-=divisor;
seguir = (numero > divisor);
}
boolean seguir;
int numero, cociente, resto;
cociente=0;
resto=numero;
seguir = (numero > divisor);
do {
cociente++;
resto-=divisor;
seguir = (numero > divisor);
} while (seguir);
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 30
Bucles determinados
Bucle FOR
for (inicializacin; condicin; iteracin) {
//bloque de instrucciones...
}
int i;
for (i = 1; i <= 10; i++)
System.out.println(Counting up + i);
for (int i = 10; i > 0; i--)
System.out.println(Counting down + i);
System.out.println(Blast off!!);
int factorial, numero;
factorial = 1;
for (i=numero; i>1; i--) factorial=factorial * i;
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 31
Seleccin mltiple
Seleccin SWITCH
switch (expresin) {
case val_1:
sentencias;
break;
.........
case val_i:
sentencias;
break;
.........
default:
sentencias;
}
switch (codigo) {
case 10:
a = 10;
b = true;
break;
case 100:
a = 50;
b = false;
break;
case 200:
a = 75;
break;
default:
a =1;
b = false;
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 32
Seleccin mltiple
class Ejemplo {
public static void main( String args[] )
{
int mes = 8;
String estacion;
switch ( mes ) {
case 12: // Contina
case 1: // Contina
case 2:
estacion = "invierno";
break;
case 3: // Contina
case 4: // Contina
case 5:
estacion = "primavera";
break;
case 6: // Contina
case 7: // Contina
case 8:
estacion = "verano";
break;
case 9: // Contina
case 10: // Contina
case 11:
estacion = "otoo";
break;
default:
estacion = mes falso";
}
System.out.println( Agosto es +
estacion + "." );
}
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 33
Arrays
int[] arrayOfInt;
arrayOfInt = new int[100];
double[] arrayOfDouble = new double[10];
for (int i = 0; i < arrayOfInt.lenght); i++)
arrayOfInt[i] = i;
int[] luckyNumbers = smallPrimes;
luckyNumbers[5] = 12;
// ahora smallPrimes[5] tambin es 12
2 3 4 5 1 0
arrayOfInt[i] smallPrimes
luckyNumbers
2
3
5
7
11
12
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 34
Matrices
No son arrays multidimensionales sino arrays de arrays
matriz[i][j]
3,2
2,2
1,2
0,2 0,3 0,1 0,0
3,3 3,1 3,0
2,3 2,1 2,0
1,3 1,1 1,0
double[][] matriz;
matriz = new double[4][4];
for (int i = 0; i < matriz.length; i++)
for (int j = 0; j < matriz[i].length; j++)
matriz[i][j] = i + j;
int[][] demo = { {1, 2}, {3, 4} };
double[] temp = matriz[i];
matriz[i] = matriz[i + 1];
matriz[i + 1] = temp;
Programacin OO en
Java
ndice
Tema 2: Programacin orientada a
objetos en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
1 Clases de objetos
2 Proteccin de miembros
3 Proteccin de clases
4 Inicializacin y finalizacin
5 Creacin de objetos
6 Trabajando con objetos
7 Relaciones entre clases
8 Clases anidadas e interiores
9 Autoreferencias
10 Aplicaciones orientadas a objetos
11 Herencia en Java
12 Adicin, redefinicin y anulacin
13 Proteccin y herencia
14 Herencia mltiple
15 Polimorfismo
16 Ligadura dinmica
17 Informacin de clases en tiempo
de ejecucin
18 Otros temas de inters en Java
Programacin OO en
Java
Clases de objetos
Clases de objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Las clases de objetos son los elementos bsicos
de la programacin orientada a objetos y
representan conceptos o entidades significativos de
un problema determinado. Una clase viene descrita
por dos tipos de elementos:
Atributos (o variables de clase). Describen el estado interno de cada objeto
Operaciones (o mtodos). Describen lo que se puede hacer con el objeto, los
servicios que proporciona
Atributos
Operaciones
Cuenta
numero: Long
titular: String
saldo: Float
intersAnual: Real
ingreso (cantidad: Integer)
reintegro (cantidad: Integer)
ingresoInteresMes ()
enRojos (): Boolean
leerSaldo (): Integer
Nombre de
la clase
Programacin OO en
Java
Clases de objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Una clase de objetos describe las caractersticas
comunes a un conjunto de objetos. Durante la
ejecucin de la aplicacin se producir la
instanciacin de esta clase, es decir, la creacin de
los objetos que representan cada uno de los
individuos con sus caractersticas propias, es decir,
valores especficos para sus atributos
Cuenta
numero: Long
titular: String
saldo: Float
intersAnual: Real
ingreso (cantidad: Integer)
reintegro (cantidad: Integer)
ingresoInteresMes ()
enRojos (): Boolean
leerSaldo (): Integer
c : Cuenta
numero=123890023
titular=Miguel Prez
saldo=1800.4
intersAnual=0.25
Clase de objetos
Objetos
d : Cuenta
numero=23900839
titular=Antonio Gmez
saldo=200
intersAnual=0.25
e : Cuenta
numero=151590020
titular=Javier Snchez
saldo=1200.2
intersAnual=1.25
Programacin OO en
Java
Clases de objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La implementacin de esta clase en Java se realizara en un fichero con nombre
Cuenta.java, y su contenido sera el siguiente:
class Cuenta {
long numero;
String titular;
float saldo;
float interesAnual;
void ingreso (float cantidad) { }
void reintegro (float cantidad) { }
void ingresoInteresMes () { }
boolean enRojos () { }
float leerSaldo () { }
}
Atributos
Operaciones
Los atributos pueden ser de cualquiera de los tipos
bsicos de Java: boolean, char, byte, short, int, long,
float y double, referencias a otros objetos o arrays de
elementos de alguno de los tipos citados
Programacin OO en
Java
Clases de objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
En Java la implementacin de las operaciones se
realiza en el interior de la definicin de la clase, justo
tras su declaracin:
class Cuenta {
long numero;
String titular;
float saldo;
float interesAnual;
void ingreso (float cantidad) {
saldo += cantidad;
}
void reintegro (float cantidad) {
saldo -= cantidad;
}
void ingresoInteresMes () {
saldo += interesAnual * saldo / 1200;
}
boolean enRojos () { return saldo < 0; }
float leerSaldo () { return saldo; }
}
Programacin OO en
Java
Clases de objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
El acceso a los atributos de la clase desde la
implementacin de las operaciones se realiza de
forma directa
Los atributos u operaciones estticas (static) son
aquellos que pertenecen a la clase en s, y no a los
objetos
De un atributo esttico no se genera una copia por
cada objeto que se crea. Existe una nica copia
compartida por todos los objetos de la clase
Una operacin esttica nicamente puede acceder
a miembros estticos
Programacin OO en
Java
Clases de objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
class Cuenta {
long numero;
String titular;
float saldo;
float interesAnual;
// Contador de operaciones
static int nOp = 0;
static int leerNOperaciones () { return nOp; }
// Operacin esttica auxiliar de conversin
static long eurosAPesetas (float euros) { return euros * 166.386f; }
void ingreso (float cantidad) { saldo += cantidad; ++nOp; }
void reintegro (float cantidad) { saldo -= cantidad; ++nOp; }
El atributo nOp mantiene una cuenta global del nmero de operaciones
realizadas en las cuentas del banco, para la realizacin de estadsticas. La
operacin leerNOperaciones () permite leer este contador
La operacin eurosAPesetas () es una operacin auxiliar de la clase Cuenta para
ser usada cuando sea necesaria una conversin de moneda
Programacin OO en
Java
Proteccin de
miembros
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
El principio de ocultacin de informacin se plasma
en los lenguajes OO en diversos mecanismos de
proteccin de los miembros de la clase
UML permite asociar tres niveles de proteccin
diferentes a cada miembro de la clase:
Miembros pblicos (+). Sin ningn tipo de proteccin especial
Miembros privados (-). Inaccesibles desde el exterior de la clase
Miembros protegidos (#). Similares a los privados aunque se permite su
acceso desde las clases descendientes*
Proteccin de miembros
* Las veremos ms adelante, al estudiar el mecanismo de la herencia
Clase
-atributoPrivado: Tipo
+atributoPublico: Tipo
#atributoProtegido: Tipo
-operacionPrivada ()
+operacionPublica ()
#operacionProtegida ()
Programacin OO en
Java
Proteccin de
miembros
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
En Java un miembro se etiqueta como pblico colo-
cando el identificador public delante de su declaracin
Para los miembros privados utilizaremos el identifica-
dor private
class Cuenta {
private long numero;
private String titular;
private float saldo;
private float interesAnual;
public void ingreso (float cantidad) {
saldo += cantidad;
}
public void reintegro (float cantidad) {
saldo -= cantidad;
}
public void ingresoInteresMes () {
saldo += interesAnual * saldo / 1200;
}
public boolean enRojos () { return saldo < 0; }
public float leerSaldo () { return saldo; }
}
Cuenta
-numero: Long
-titular: String
-saldo: Float
-intersAnual: Real
+ingreso (cantidad: Integer)
+reintegro (cantidad: Integer)
+ingresoInteresMes ()
+enRojos (): Boolean
+leerSaldo (): Integer
Programacin OO en
Java
Proteccin de
miembros
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Los miembros no etiquetados son accesibles por
parte de clases amigas. En C++ y otros lenguajes
OO las clases amigas a una dada pueden indicarse
explcitamente
En Java se consideran amigas todas aquellas que
forman parte del mismo paquete
Un fichero fuente java forma en s un paquete y por tanto todas las clases
incluidas en l son amigas
Las clases incluidas en varios ficheros fuente pueden agruparse en un nico
paquete indicando el nombre de paquete al principio de cada fichero mediante
el indicador package
package prueba;
class A {
...
}
class B {
...
}
package prueba;
class C {
...
}
class D {
...
}
class E {
...
}
Las clases A, B y C son amigas al pertenecer
al mismo paquete prueba
Las clases D y E son amigas al pertenecer al
mismo fichero fuente
Programacin OO en
Java
Proteccin de
miembros
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
En este ejemplo, las clases Cuenta y Banco son amigas al pertenecer al mismo
fichero fuente. El acceso a los atributos de los objetos de la clase Cuenta
almacenados en el vector interno de Banco queda as garantizado. El atributo
saldo puede mantenerse como privado puesto que existe una operacin que
permite obtener su valor
class Cuenta {
long numero;
String titular;
private float saldo;
float interesAnual;
public void ingreso (float cantidad) {
saldo += cantidad;
}
public void reintegro (float cantidad) {
saldo -= cantidad;
}
public void ingresoInteresMes () {
saldo += interesAnual * saldo / 1200;
}
public boolean enRojos () { return saldo < 0; }
public float leerSaldo () { return saldo; }
}
class Banco {
Cuenta[] c; // vector de cuentas
...
}
Programacin OO en
Java
Proteccin de
miembros
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Atencin: todas las clases que no se declaren como
pertenecientes a ningn paquete de forma explcita,
pertenecen a un paquete por defecto y por tanto
son amigas
Un paquete crea un espacio de nombres propios.
Esto significa que la clase pasa a tener como prefijo
el propio nombre del paquete. A la hora de utilizarla
tenemos tres opciones:
Utilizar su nombre completo: prueba.A
Importar esa clase, para poder utilizarla sin el prefijo. Esto se indica al principio
del cdigo fuente mediante import prueba.A
Importar directamente todas las clases del paquete, que se usaran sin prefijo:
import prueba.*
Programacin OO en
Java
Proteccin de
clases
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Por proteccin de clases entendemos un nivel superior
de la ocultacin de informacin, a nivel de clases. Es
decir, se trata de especificar que clases pueden ser
utilizadas y cuales no, y por quin
Dentro de un paquete, las clases son amigas y por
tanto no existen restricciones respecto a la utilizacin
de una clase por las otras
Sin embargo, desde el punto de vista del exterior,
nicamente podrn ser utilizadas las clases pblicas
del paquete, es decir, aquellas con el identificador
public situado delante de su declaracin
Proteccin de clases
Programacin OO en
Java
Proteccin de
clases
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Atencin: Java slo permite una clase pblica por
fichero fuente, y el nombre de la clase y el fichero
deben coincidir
En nuestro ejemplo, si queremos que la clase Cuenta pueda ser utilizada desde
el exterior del fichero Cuenta.java deberemos declararla como pblica
public class Cuenta {
long numero;
String titular;
private float saldo;
float interesAnual;
public void ingreso (float cantidad) {
saldo += cantidad;
}
public void reintegro (float cantidad) {
saldo -= cantidad;
}
public void ingresoInteresMes () {
saldo += interesAnual * saldo / 1200;
}
public boolean enRojos () { return saldo < 0; }
public float leerSaldo () { return saldo; }
}
Programacin OO en
Java
Inicializacin y
finalizacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La iniciacin de los atributos de la clase se realiza
en Java, al igual que en C++, mediante el uso de
constructores cuyo nombre coincide con el de la
clase
Inicializacin y finalizacin
public class Cuenta {
long numero;
String titular;
private float saldo;
float interesAnual;
Cuenta (long aNumero, String aTitular, float aInteresAnual) {
numero = aNumero;
titular = aTitular;
saldo = 0;
interesAnual = aInteresAnual;
}
public void ingreso (float cantidad) {
saldo += cantidad;
}
// Resto de operaciones de la clase Cuenta a partir de aqu
Programacin OO en
Java
Inicializacin y
finalizacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Java permite la sobrecarga de operaciones, por tanto
se pueden definir varios constructores posible para una
clase siempre que se diferencien en la lista de
argumentos
// Importar todas las clases del paquete java.io
import java.io.*;
public class Cuenta {
long numero;
String titular;
private float saldo;
float interesAnual;
// Constructor general
Cuenta (long aNumero, String aTitular, float aInteresAnual) {
numero = aNumero;
titular = aTitular;
saldo = 0;
interesAnual = aInteresAnual;
}
Programacin OO en
Java
Inicializacin y
finalizacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
// Constructor para obtener los datos de la cuenta de un fichero
Cuenta (long aNumero) throws FileNotFoundException, IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream (aNumero + .cnt);
ObjectInputStream ois = new ObjectInputStream (fis);
numero = aNumero;
titular = (String) ois.readObject ();
saldo = ois.readFloat ();
interesAnual = ois.readFloat ();
ois.close ();
}
public void ingreso (float cantidad) {
saldo += cantidad;
}
public void reintegro (float cantidad) {
saldo -= cantidad;
}
public void ingresoInteresMes () {
saldo += interesAnual * saldo / 1200;
}
public boolean enRojos () { return saldo < 0; }
public float leerSaldo () { return saldo; }
}
Nota: vase el apartado I/O: Reading and Writing del tutorial Java de Sun como apoyo para entender
el cdigo del nuevo constructor
Programacin OO en
Java
Inicializacin y
finalizacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Si no se proporciona ningn constructor, Java
proporciona automticamente un constructor por
defecto, que no recibe argumentos y realiza una
inicializacin por defecto de los atributos
Una vez implementado un constructor propio por parte
del programador, Java elimina dicho constructor,
aunque puede ser definido nuevamente de manera
explcita
Cuenta () {
numero = 00000000;
titular = ninguno;
saldo = 0;
interesAnual = 0;
}
Programacin OO en
Java
Inicializacin y
finalizacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Naturalmente los constructores pueden ser marcados
como pblicos, privados, protegidos o con acceso a
nivel de paquete, lo que especificar quien puede crear
objetos de esta clase y de que manera
// Constructor general
public Cuenta (long aNumero, String aTitular, float aInteresAnual) {
numero = aNumero;
titular = aTitular;
saldo = 0;
interesAnual = aInteresAnual;
}
// Constructor para obtener los datos de la cuenta de un fichero
public Cuenta (long aNumero) throws FileNotFoundException,
IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream (aNumero + .cnt);
ObjectInputStream ois = new ObjectInputStream (fis);
numero = aNumero;
titular = (String) ois.readObject ();
saldo = ois.readFloat ();
interesAnual = ois.readFloat ();
ois.close ();
}
Programacin OO en
Java
Inicializacin y
finalizacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Cuando finaliza el uso de un objeto, es frecuente la
realizacin de ciertas tareas antes de su destruccin,
principalmente la liberacin de la memoria solicitada
durante su ejecucin. Esto se realiza en C++ y otros
lenguajes OO en los denominados destructores
Estos destructores son operaciones invocadas
automticamente justo antes de la destruccin del
objeto
Sin embargo, en Java la liberacin de memoria se
realiza de manera automtica por parte del recolector
de basura, por tanto la necesidad de este tipo de
operaciones no existe en la mayor parte de los casos
Programacin OO en
Java
Inicializacin y
finalizacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Sin embargo s puede ser necesario realizar alguna
tarea no relacionada con la liberacin de memoria
antes de la destruccin del objeto, como por ejemplo
salvar el estado de la clase en un fichero o base de
datos
Java permite introducir cdigo para este fin
implementando una operacin pblica especial
denominada finalize. Esta operacin es invocada
automticamente antes de la destruccin del objeto por
parte del recolector de basura
Programacin OO en
Java
Inicializacin y
finalizacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Siguiendo nuestro ejemplo, vamos asegurarnos de que el estado de una cuenta
queda salvado en disco antes de su destruccin, para poder ser recuperada
posteriormente. Para ello introducimos el cdigo de escritura en fichero en la
operacin finalize de la clase Cuenta
public void finalize () : throws FileNotFoundException, IOException {
FileOutputStream fos = new FileOutputStream (numero + .cnt);
ObjectOutputStream oos = new ObjectOutputStream (fos);
oos.writeObject (titular);
oos.writeFloat (saldo);
oos.writeFloat (interesAnual);
oos.close ();
}
Programacin OO en
Java
Inicializacin y
finalizacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Sin embargo no sabemos en que momento ser
llamada dicha operacin, puesto que el recolector de
basura puede decidir su eliminacin en un momento
indeterminado, e incluso no ser eliminado hasta el
final de la ejecucin de la aplicacin
Una posible solucin, aunque no muy recomendable,
es ordenar al recolector de basura que realice una
limpieza de memoria inmediata, para asegurar la
finalizacin de los objetos. Esto se realiza mediante
Runtime.getRuntime ().gc ()
Se recomienda crear en su lugar una operacin
ordinaria con este mismo propsito, que sea invocada
cuando haya finalizado el uso del objeto
Programacin OO en
Java
Inicializacin y
finalizacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
En nuestro ejemplo introduciremos en la clase Cuenta una operacin pblica salvar
en lugar de finalize, con la misma implementacin. Tras finalizar las operaciones
sobre la cuenta, invocaremos a salvar para guardar los cambios realizados
public void salvar () : throws FileNotFoundException, IOException {
FileOutputStream fos = new FileOutputStream (numero + .cnt);
ObjectOutputStream oos = new ObjectOutputStream (fos);
oos.writeObject (titular);
oos.writeFloat (saldo);
oos.writeFloat (interesAnual);
oos.close ();
}
Programacin OO en
Java
Creacin de objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
En Java los objetos se crean nicamente de forma
dinmica, es decir, en el heap. Para ello se utiliza el
operador new, de manera similar a C++
Los objetos en Java se utilizan siempre a travs de
referencias. Las referencias son similares a los
punteros de C/C++, aunque su uso es mucho ms
sencillo
Por tanto los pasos a seguir en la creacin de un
objeto son:
Declarar una referencia a la clase
Crear un objeto mediante el operador new invocando al constructor adecuado
Conectar el objeto con la referencia
Creacin de objetos
Programacin OO en
Java
Creacin de objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La creacin de un objeto de la clase Cuenta se realizara de la siguiente forma:
Cuenta c; // Una referencia a un objeto de la clase Cuenta
c = new Cuenta (18400200, Pedro Jimnez, 0.1f);
En cambio, los tipos bsicos (int, long, float, etc.) s
pueden ser creados directamente en la pila. Esto es
posible porque Java no los implementa realmente
como clases de objetos, por motivos de eficiencia y
comodidad, ya que su uso es muy frecuente
Cuenta c;
float in;
long num;
in = 0.1f;
num = 18400200;
c = new Cuenta (num, Pedro Jimnez, in);
Programacin OO en
Java
Creacin de objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Las cadenas de caracteres se implementan con una
clase (String). Sin embargo no suele ser necesaria su
creacin de manera explcita, ya que Java lo hace de
manera automtica al asignar una cadena constante*
String s; // Una referencia a un objeto de la clase String
// Conexin de la referencia s con un objeto String
// creado dinmicamente e inicializado con la constante Pedro
s = Pedro;
// Sera equivalente a:
// char[] cc = {'P', 'e', 'd', 'r', 'o'}
// s = new String (cc);
Los arrays tambin deben ser creados dinmicamente
con new como si fueran objetos
* Vase el apartado Characters and Strings del tutorial de Java de Sun para ms informacin
int[] v; // Una referencia a un vector de enteros
v = new int[10] // Creacin de un vector de 10 enteros
Programacin OO en
Java
Creacin de objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Si el array es de referencias a objetos, habr que
crear adems cada uno de los objetos referenciados
por separado
Cuenta[] v; // Un vector de referencias a objetos de la clase Cuenta
int c;
v = new Cuenta [10] // Crear espacio para 10 referencias a cuentas
for (c = 0; c < 10; c++)
v[c] = new Cuenta (18400200 + c, Cliente n. + c, 0.1f);
La destruccin de los objetos se realiza de manera
automtica cuando el recolector de basura detecta que
el objeto no est siendo usado, es decir, no est
conectado a ninguna referencia
Cuenta c1 = new Cuenta (18400200, Cliente 1, 0.1f);
Cuenta c2 = new Cuenta (18400201, Cliente 2, 0.1f);
c1 = c2
// El objeto asociado a la cuenta 18400200 ha quedado desconectado
// y ser eliminado por el recolector de basura
Programacin OO en
Java
Trabajando con
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Trabajar con un objeto Java es similar a C++,
aunque las referencias permiten un uso mucho ms
sencillo
Trabajando con objetos
Cuenta c1 = new Cuenta (18400200, Pedro Jimnez, 0.1f);
Cuenta c2 = new Cuenta (18400201);
c2.reintegro (1000);
c1.ingreso (1000);
if (c2.enRojos ())
System.out.println (Atencin: cuenta 18400201 en nmeros rojos);
Programacin OO en
Java
Trabajando con
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
System.out.println (** Introduzca num. cuenta e importe a retirar);
InputStreamReader isr = new InputStreamReader (System.in);
StreamTokenizer stk = new StreamTokenizer (isr);
try {
stk.nextToken ();
long nc = (long) stk.nval;
stk.nextToken ();
float mi = (float) stk.nval;
}
catch (IOException e) {
System.out.println (Error leyendo datos de operacin);
}
Cuenta c;
try {
c = new Cuenta (nc);
}
catch (Exception e) {
System.out.println (Imposible recuperar cuenta);
return;
}
if (c.leerSaldo () < mi)
System.out.println (Saldo insuficiente);
else
c.reintegro (mi);
c.salvar ();
En este ejemplo se pide un nmero de cuenta al usuario y una cantidad a retirar.
A continuacin se carga la cuenta solicitada y se realiza el reintegro
Programacin OO en
Java
Trabajando con
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Naturalmente el compilador producir un error ante
cualquier acceso ilegal a un miembro de la clase
El acceso a un miembro esttico se realiza utilizando
el nombre de la clase en lugar de un objeto
Cuenta c = new Cuenta (18400200, Cliente 1, 0.1f);
c.ingreso (1000);
int pts = Cuenta.eurosAPesetas (c.leerSaldo ());
System.out.println (Saldo: + c.leerSaldo () + ( + pts + pesetas);
Cuenta c = new Cuenta (18400200, Pedro Jimnez, 0.1f);
c.saldo = 1000;
Cuenta.java:XX: saldo has private access
c.saldo = 1000;
^
1 error
Programacin OO en
Java
Relaciones entre
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Un conjunto de objetos aislados tiene escasa
capacidad para resolver un problema. En una
aplicacin til los objetos colaboran e intercambian
informacin, mantienen distintos tipos de relaciones
entre ellos
A nivel de diseo, podemos distinguir entre 5 tipos
de relaciones bsicas entre clases de objetos:
dependencia, asociacin, agregacin, composicin y
herencia*
Relaciones entre clases
* La veremos ms adelante, en un apartado especfico
Programacin OO en
Java
Relaciones entre
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La dependencia es la relacin menos importante.
Simplemente refleja que entre dos clases de objetos
existe una posible colaboracin temporal con algn
propsito
Una dependencia puede indicar la utilizacin de un
objeto de una clase como argumento de una
operacin de otra o en su implementacin
Como vimos anteriormente, la clase Cuenta requiere las clases FileOutputStream
y ObjectOutputStream de la librera de clases de Java para la implementacin de la
operacin salvar
FileOutputStream
ObjectOutputStream
Cuenta
numero: Long
titular: String
-saldo: Float
intersAnual: Real
+ingreso (cantidad: Integer)
+reintegro (cantidad: Integer)
+ingresoInteresMes ()
+enRojos (): Boolean
+leerSaldo (): Integer
+salvar ()
Programacin OO en
Java
Relaciones entre
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
En cambio, la asociacin es la relacin ms
importante y ms comn. Refleja una relacin entre
dos clases independientes que se mantiene durante
la vida de los objetos de dichas clases o al menos
durante un tiempo prolongado
En UML suele indicarse el nombre de la relacin, el
sentido de dicha relacin y las cardinalidades en los
dos extremos
Vamos a sustituir el atributo titular por una asociacin con una nueva clase
Cliente completa
ttuar
1
Cuenta
numero: Long
-saldo: Float
intersAnual: Real
+ingreso (cantidad: Integer)
+reintegro (cantidad: Integer)
+ingresoInteresMes ()
+enRojos (): Boolean
+leerSaldo (): Integer
+leerTitular (): Cliente
+salvar ()
Cliente
nombre: String
apellidos: String
direccin: String
localidad: String
fNacimiento: Date
+nombreCompleto (): String
+direccionCompleta (): String
*
Programacin OO en
Java
Relaciones entre
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Una asociacin se implementa en Java introducien-
do referencias a objetos de la clase destino de la
relacin como atributos de la clase origen
Si la relacin tiene una cardinalidad superior a uno
entonces ser necesario utilizar un array o una
estructura de datos dinmica del paquete java.util
como Vector o LinkedList
Normalmente la conexin entre los objetos se
realiza recibiendo la referencia de uno de ellos en el
constructor u otra operacin similar del otro
Programacin OO en
Java
Relaciones entre
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
public class Cuenta {
long numero;
Cliente titular;
private float saldo;
float interesAnual;
// Constructor general
public Cuenta (long aNumero, Cliente aTitular, float aInteresAnual) {
numero = aNumero;
titular = aTitular;
saldo = 0;
interesAnual = aInteresAnual;
}
Cliente leerTitular () { return titular; }
// Resto de operaciones de la clase Cuenta a partir de aqu
public class Cliente {
String nombre, apellidos;
String direccion, localidad;
Date fNacimiento;
Cliente (String aNombre, String aApellidos, String aDireccion,
String aLocalidad, Date aFNacimiento) {
nombre = aNombre;
apellidos = aApellidos;
direccion = aDireccion;
localidad = aLocalidad;
fNacimiento = aFNacimiento;
}
String nombreCompleto () { return nombre + + apellidos; }
String direccionCompleta () { return direccion + , + localidad; }
}
Programacin OO en
Java
Relaciones entre
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La agregacin es un tipo especial de asociacin
donde se aade el matiz semntico de que la clase
de donde parte la relacin representa el todo y las
clases relacionadas las partes.
Realmente Java y la mayora de lenguajes orien-
tados a objetos no disponen de una implementacin
especial para este tipo de relaciones. Bsicamente
se tratan como las asociaciones ordinarias
Polgono
formado por
2 *
Segmento
Departamento
dispone de
1 *
Despacho
Programacin OO en
Java
Relaciones entre
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La composicin es un tipo de agregacin que aade
el matiz de que la clase todo controla la existencia
de las clases parte. Es decir, normalmente la clase
todo crear al principio las clases parte y al final
se encargar de su destruccin
Supongamos que aadimos un registro de movimientos a la clase Cuenta, de
forma que quede constancia tras cada ingreso o reintegro
ttuar
*
1
regstra
*
Cuenta
numero: Long
titular: String
-saldo: Float
intersAnual: Real
+ingreso (cantidad: Integer)
+reintegro (cantidad: Integer)
+ingresoInteresMes ()
+enRojos (): Boolean
+leerSaldo (): Integer
+leerTitular (): Cliente
+salvar ()
Cliente
nombre: String
apellidos: String
direccin: String
localidad: String
fNacimiento: Date
+nombreCompleto (): String
+direccionCompleta (): String
Movimiento
fecha: Date
tipo: Char
importe: Real
saldo: Real
Programacin OO en
Java
Relaciones entre
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Las composiciones tienen una implementacin
similar a las asociaciones, con la diferencia de que el
objeto principal realizar en algn momento la
construccin de los objetos compuestos
import java.util.Date
class Movimiento {
Date fecha;
char tipo;
float importe;
float saldo;
public Movimiento (Date aFecha, char aTipo, float aImporte, float aSaldo) {
fecha = aFecha;
tipo = aTipo;
importe = aImporte;
saldo = aSaldo;
}
}
Programacin OO en
Java
Relaciones entre
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
public class Cuenta {
long numero;
Cliente titular;
private float saldo;
float interesAnual;
LinkedList movimientos; // Lista de movimientos
// Constructor general
public Cuenta (long aNumero, Cliente aTitular, float aInteresAnual) {
numero = aNumero; titular = aTitular; saldo = 0; interesAnual = aInteresAnual;
movimientos = new LinkedList ();
}
// Nueva implementacin de ingreso y reintegro
public void ingreso (float cantidad) {
movimientos.add (new Movimiento (new Date (), 'I', cantidad, saldo += cantidad));
}
public void reintegro (float cantidad) {
movimientos.add (new Movimiento (new Date (), 'R', cantidad, saldo -= cantidad));
}
public void ingresoInteresMes () { ingreso (interesAnual * saldo / 1200); }
// Resto de operaciones de la clase Cuenta a partir de aqu
Nota: tambin sera necesario modificar el otro constructor y la operacin salvar para tener en cuenta la lista de movimientos
a la hora de leer/escribir la informacin de la Cuenta en disco
Programacin OO en
Java
Clases anidadas e
interiores
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Java y algunos otros lenguajes OOP permiten la
definicin de una clase de objetos dentro de otra
El sentido de esta posibilidad es empaquetar dentro
de una clase aquellas otras clases que no tienen
utilidad o entidad fuera del contexto de ella
Al igual que cualquier otro miembro de una clase,
una clase anidada puede ser esttica y utilizar los
niveles de proteccin public, private y protected
Cuando la clase anidada no es esttica, se
denomina clase interior
Clases anidadas e interiores
Programacin OO en
Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
import java.util.Date
public class Cuenta {
long numero;
Cliente titular;
private float saldo;
float interesAnual;
LinkedList movimientos; // Lista de movimientos
static private class Movimiento {
Date fecha;
char tipo;
float importe;
float saldo;
public Movimiento (Date aFecha, char aTipo, float aImporte, float aSaldo) {
fecha = aFecha; tipo = aTipo; importe = aImporte; saldo = aSaldo;
}
}
// Constructor general
public Cuenta (long aNumero, Cliente aTitular, float aInteresAnual) {
numero = aNumero; titular = aTitular; saldo = 0; interesAnual = aInteresAnual;
movimientos = new LinkedList ();
}
// Resto de operaciones de la clase Cuenta a partir de aqu
Desde el punto de vista de la organizacin del cdigo, tendra mucho ms
sentido introducir la clase Movimiento en el interior de Cuenta. Al ser declarada
como privada, se impedira su utilizacin desde el exterior
Clases anidadas e
interiores
Programacin OO en
Java
Clases anidadas e
interiores
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Las clases anidadas estticas no tienen una utilidad
mayor que la de un mero organizador de cdigo
En cambio las clases interiores tienen caracters-
ticas especiales
Pueden ser creadas nicamente dentro de la clase que las engloba
Tiene acceso completo y directo a todos los atributos y operaciones del objeto
que realiza su creacin
Los objetos de la clase interior quedan ligados
permanentemente al objeto concreto de la clase
englobante que realiz su creacin
No debe confundirse este elemento con la relacin
de composicin, aunque en muchos casos podremos
utilizar clases interiores para la implementacin de
este tipo de relaciones
Programacin OO en
Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
import java.util.Date
public class Cuenta {
long numero;
Cliente titular;
private float saldo;
float interesAnual;
LinkedList movimientos; // Lista de movimientos
private class Movimiento {
Date fecha;
char tipo;
float importe;
float saldoAct;
public Movimiento (Date aFecha, char aTipo, float aImporte) {
fecha = aFecha;
tipo = aTipo;
importe = aImporte;
saldoAct = saldo; // Copamos el saldo actual
}
}
// Constructor general
public Cuenta (long aNumero, Cliente aTitular, float aInteresAnual) {
numero = aNumero; titular = aTitular; saldo = 0;
interesAnual = aInteresAnual;
movimientos = new LinkedList ();
}
Implementando la clase Movimiento como una clase interior es posible copiar el
valor del saldo actual de la cuenta que realiza el movimiento de manera directa
Clases anidadas e
interiores
Programacin OO en
Java
Clases anidadas e
interiores
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
// Nueva implementacin de ingreso y reintegro
public void ingreso (float cantidad) {
movimientos.add (new Movimiento (new Date (), 'I', cantidad, saldo));
saldo += cantidad;
}
public void reintegro (float cantidad) {
movimientos.add (new Movimiento (new Date (), 'R', cantidad, saldo));
saldo -= cantidad;
}
public void ingresoInteresMes () { ingreso (interesAnual * saldo / 1200); }
// Resto de operaciones de la clase Cuenta a partir de aqu
public boolean enRojos () { return saldo < 0; }
public float leerSaldo () { return saldo; }
}
Implementando la clase Movimiento como una clase interior es posible copiar el
valor del saldo actual de la cuenta que realiza el movimiento de manera directa
Programacin OO en
Java
Relaciones entre
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
En ocasiones es necesario obtener una referencia
en la implementacin de una operacin al propio
objeto sobre el que ha sido invocada la operacin
Esta referencia se obtiene en C++ y Java mediante
el operador this
Cuando encontremos this en una expresin,
podremos sustituirlo mentalmente por este objeto
Aunque no es necesario, podemos utilizar this para
llamar desde la implementacin de una operacin a
otra operacin del mismo objeto
Autoreferencias
Programacin OO en
Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La llamada a la operacin ingreso desde ingresoInteresMes puede realizarse
utilizando this como referencia del objeto sobre el que se invoca la operacin
public class Cuenta {
long numero;
Cliente titular;
private float saldo;
float interesAnual;
public void ingresoInteresMes () { this.ingreso (interesAnual * saldo / 1200); }
// Resto de las operaciones de la clase Cuenta
En este ejemplo, el uso de this es realmente til. Nos permite implementar la
operacin transferirDesde llamando a una operacin transferirA, previamente
implementada
public class Cuenta {
long numero;
Cliente titular;
private float saldo;
float interesAnual;
public void transferirA (Cuenta c, float cant) {
reintegro (cant); c.ingreso (cant);
}
public void transferirDesde (Cuenta c, float cant) {
c.transferir_a (this, cant);
}
// Resto de las operaciones de la clase Cuenta
Relaciones entre
objetos
Programacin OO en
Java
Relaciones entre
objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
public class Cuenta {
long numero;
Cliente titular;
private float saldo;
float interesAnual;
// Constructor general
public Cuenta (long aNumero, Cliente aTitular, float aInteresAnual) {
numero = aNumero; titular = aTitular; saldo = 0; interesAnual = aInteresAnual;
movimientos = new LinkedList ();
}
// Constructor especfico para cuentas de ahorro (interesAnual = 0.1%)
public Cuenta (long aNumero, Cliente aTitular) {
this (aNumero, aTitular, 0.1);
}
// Resto de la clase Cuenta
Otra utilidad de this en Java es realizar una llamada
a un constructor desde otro constructor
Pero atencin: un constructor no es una operacin
ordinaria. nicamente puede llamarse a un
constructor desde otro constructor y debe ser la
primera instruccin de su implementacin
Programacin OO en
Java
Aplicaciones
orientadas a objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
En una aplicacin orientada a objetos debe existir
una clase que represente la propia aplicacin. Este
sera el punto donde comenzara la ejecucin de la
misma
En lenguajes no totalmente orientados como C++
en la funcin main se crea una instancia de esta
clase y se llama a alguna operacin como ejecutar
para arrancar la aplicacin. Sin embargo esto no es
obligatorio, y un mal programador puede realizar una
aplicacin hbrida, con cdigo no orientado a objetos
Aplicaciones orientadas a objetos
public class BancoApp {
public static void main (String[] args) {
Cuenta c1 = new Cuenta (18400200, Pedro Jimnez, 0.1f);
c1.ingreso (1000);
System.out.println (Ingreso realizado);
}
}
Programacin OO en
Java
Aplicaciones
orientadas a objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
En un lenguaje orientado a objetos puro como
Java esta clase de aplicacin es obligatoria. La
mquina virtual Java se encarga de instanciar esta
clase y llamar a una operacin especial con nombre
main. La existencia de una operacin esttica
pblica con este nombre es lo que caracteriza la
clase de aplicacin
La clase aplicacin debe ser pblica y no tener ningn constructor o un
constructor por defecto
Al menos debe implementar la operacin main, con la siguiente declaracin:
public static main (String[] args)
Programacin OO en
Java
Aplicaciones
orientadas a objetos
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
A la hora de ejecutar la aplicacin, deber indicarse
esta clase a la mquina virtual Java
Tras compilar los ficheros de la ltima versin de nuestro ejemplo: Cliente.java,
Cuenta.java y BancoApp.java obtendremos los ficheros en byte code:
Cliente.class, Cuenta.class, Movimiento.class y BancoApp.class.
Finalmente, pasando la clase BancoApp.class a la mquina virtual java
pondremos en funcionamiento la aplicacin
$ls
BancoApp.java Cliente.java Cuenta.java
$javac *.java
$ls
BancoApp.class Cliente.class Cuenta.class Movimiento.class
BancoApp.java Cliente.java Cuenta.java
$java Cuenta
Exception in thread main java.lang.NoSuchMethodError: main
$java BancoApp
Transferencia realizada
$
La mquina virtual java
producir un error si se
le pasa una clase sin
la operacin main
Nota: Las clases que constituyen una aplicacin Java tambin pueden distribuirse de manera mucho ms compacta
en un nico fichero JAR. Consltese la bibliografa para ver como crean y utilizan estos ficheros
Programacin OO en
Java
Herencia
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La herencia es un mecanismo de la OOP que
permite construir una clase incorporando de manera
implcita todas las caractersticas de una clase
previamente existente. Son varias las razones que
justifican su existencia:
Modelado de la realidad. Son frecuentes las relaciones de
especializacin/generalizacin entre las entidades del mundo real, por tanto es
lgico que dispongamos de un mecanismo similar entre las clases de objetos
Evitar redundancias. Toda la funcionalidad que aporta una clase de objetos es
adoptada de manera inmediata por la clase que hereda, por tanto evitamos la
repeticin de cdigo entre clases semejantes
Facilita la reutilizacin. Una clase no tiene por qu limitarse a recibir una serie
de caractersticas de otra clase por herencia de forma pasiva. Tambin
disponen de cierto margen de adaptacin de estas caractersticas
Sirve de soporte para el polimorfismo
Herencia
Programacin OO en
Java
Herencia
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Sea una clase A. Si una segunda clase B hereda de
A entonces decimos:
A es un ascendiente o superclase de B. Si la herencia entre A y B es directa
decimos adems que A es la clase padre de B
B es un descendiente o subclase de A. Si la herencia entre A y B es directa
decimos adems que B es una clase hija de A
A
B
C D
En Java, Eiffel, Smalltalk y otros lenguajes
orientados a objetos puros, todas las clases heredan
automticamente de una superclase universal. En
Java esta superclase se denomina Object
Programacin OO en
Java
Herencia
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Existen diferentes situaciones en las que puede
aplicarse herencia:
Especializacin. Dado un concepto B y otro concepto A que representa una
especializacin de A, entonces puede establecerse una relacin de herencia
entre las clases de objetos que representan a A y B. En estas situaciones, el
enunciado A es un B suele ser aplicable
Vehculo
Coche
Empleado
Contable
Figura
Cuadrado
Extensin. Una clase puede servir para extender la funcionalidad de una
superclase sin que represente necesariamente un concepto ms especfico.
Lista
ListaSalvable
recuperar ()
salvar ()
Cuenta
CuentaconHistorico
registra
*
Movimiento
fecha: Date
tipo: Char
importe: Real
saldo: Real
Programacin OO en
Java
Herencia
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Especificacin. Una superclase puede servir para especificar la funcionalidad
mnima comn de un conjunto de descendientes. Existen mecanismos para
obligar a la implementacin de una serie de operaciones en estos
descendientes
Construccin. Una clase puede construirse a partir de otra, simplemente
porque la hija puede aprovechar internamente parte o toda la funcionalidad del
padre, aunque representen entidades sin conexin alguna
Lista
Pila
Lnea Texto
Cuadrado
ObjetoGrfico
seleccionar ()
mover ()
escalar ()
cambiar color ()
pintar ()
Programacin OO en
Java
Herencia
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Ejemplos de herencia:
Distintos tipos de cuentas bancarias
Cuenta
numero: Long
titular: String
saldo: Real
interes: Real
ingreso ()
ingresoInteresMes ()
leerSaldo ()
transferirA ()
CuentaCorriente
reintegro ()
PlanPensiones
vencimiento:Date
cotizacion: Float
numCuentaOrigen: String
CuentaAhorroPFijo
vencimiento: Date
ingresoMes ()
Programacin OO en
Java
Herencia
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Elementos de una interfaz de usuario
Figura
x, y: Integer
mover (nx: Integer, ny: Integer)
Rectngulo
ancho, alto: Integer
escalar (nx: Integer, ny: Integer
Ventana
titulo: String
pintar ()
Editor
pintar ()
Boton
accion ()
Programacin OO en
Java
Herencia
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Estructuras de datos
Contenedor
nelem: Integer
vaciar ()
copiar (c: Contenedor)
tamaa (): Integer
vacio (): Boolean
Secuencia
escribir (e: Elemento, pos: Integer)
leer (pos: Integer): Elemento
borrar (pos: Integer)
ContenedorAsociativo
escribir (e: Elemento, c: Clave)
leer (c: Clave): Elemento
borrar (c: Clave)
Vector
buffer[nelem]: Elemento
redimensionar (t: Integer)
Lista
cabecera: Nodo
insertar (e: Elemento, pos: Integer)
insertaPrin (e: Elemento)
insertarFinal (e: Elemento)
TablaHash
tabla[nelem]: Elemento
funcionHash (c: Clave): Integer
Programacin OO en
Java
Herencia en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Vamos a estudiar la herencia en Java siguiendo un
ejemplo de un programador de tareas
La clase TareaPeriodica representa cualquier tarea que se ejecuta sucesivamente
cada vez que se cumple el periodo de activacin (en seg.)
La clase TPReloj representa un reloj que muestra en pantalla la hora cada 30 min.
La clase TPAviso muestra un aviso cuando se cumple un intervalo de tiempo
La clase TPEjecucion ejecuta un comando determinado peridicamente
Herencia en Java
TareaPeriodica
periodoSegs: Integer
ultimaej: Date
activa: Boolean
+necesitaEjecucion (): Boolean
+actualizarReloj ()
+ejecutarTarea ()
+activar ()
+desactivar ()
TPReloj
+leerHora (): String
TPAviso
msg: String
+leerMsg (): String
TPEjecucion
cmd: String
+leerCmd (): String
Programacin OO en
Java
Herencia en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La implementacin de la clase TareaPeriodica no tiene ninguna caracterstica
especial
import java.util.*;
public class TareaPeriodica {
int periodoSegs;
Date ultimaEj;
boolean activa;
public TareaPeriodica(int aPeriodoSegs) {
periodoSegs = aPeriodoSegs;
actualizarReloj ();
activa = true;
}
// Constructor para ejecuciones cada segundo
public TareaPeriodica () {
this (1);
}
public void actualizarReloj () {
ultimaEj = new Date (); // Hora actual
}
Programacin OO en
Java
Herencia en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
public boolean necesitaEjecucion () {
if (!activa)
return false;
// Calcular la hora de la prxima ejecucin
Calendar calProximaEj = new GregorianCalendar ();
calProximaEj.setTime (ultimaEj);
calProximaEj.add (Calendar.SECOND, periodoSegs);
Calendar calAhora = new GregorianCalendar ();
// Comprobar si ha pasado a la hora actual
return (calProximaEj.before (calAhora));
}
public void ejecutarTarea () {
System.out.println ("Ejecucion de tarea");
}
public void activar () { activa = true; }
public void desactivar () { activa = false; }
}
La operacin ejecutarTarea realmente no tiene una implementacin concreta, al
tratarse de una clase muy general
Programacin OO en
Java
Herencia en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Para que una clase herede de otra, utilizaremos el
indicador extends en la declaracin de la clase
import java.util.Calendar;
import java.util.GregorianCalendar;
public class TPReloj extends TareaPeriodica {
public TPReloj () {
periodoSegs = 60; // Comprobar cada minuto
actualizarReloj ();
activa = true;
}
public String leerHora () {
Calendar cal = new GregorianCalendar ();
return cal.get (Calendar.HOUR_OF_DAY) + ":" + cal.get (Calendar.MINUTE);
}
}
Atencin!: Aunque el cdigo de estas clases compila perfectamente, la implementacin de los
constructores es formalmente incorrecta. Ms adelante veremos por qu.
Programacin OO en
Java
Herencia en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
public class TPAviso extends TareaPeriodica {
String msg;
public TPAviso(String aMsg, int aPeriodoSegs) {
periodoSegs = aPeriodoSegs;
actualizarReloj ();
activa = true;
msg = aMsg;
}
public String leerMsg () { return msg; }
}
import java.lang.Runtime;
import java.io.IOException;
public class TPEjecucion extends TareaPeriodica {
String cmd;
public TPEjecucion(String aCmd, int aPeriodoSegs) {
periodoSegs = aPeriodoSegs;
actualizarReloj ();
activa = true;
cmd = aCmd;
}
String leerCmd () { return cmd; }
}
Atencin!: Aunque el cdigo de estas clases compila perfectamente, la implementacin de los
constructores es formalmente incorrecta. Ms adelante veremos por qu.
Programacin OO en
Java
Herencia en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Todos las clases en Java heredan en ltima
instancia de Object. Incluso si creamos una clase
independiente, Java la hace heredar implcitamente
de Object
Object
#clone (): Object
+equals (Object obj): Boolean
#finalize ()
+getClass (): Class
+hasCode (): int
+notify ()
+notifyAll ()
+toString (): String
+wait ()
+wait (timeout: Long)
+wait (timeout: Long, nanos: Integer)
Esto hace que las clases formen una jerarqua con
Object como raz
Object
... ... ... ... ...
Programacin OO en
Java
Herencia en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
public class AppGestorTareas {
public static void main (String[] args) {
TareaPeriodica tp = new TareaPeriodica (5);
TPAviso tpa = new TPAviso (Estudiar Programacin Avanzada !, 60);
while (!tp.necesitaEjecucion ())
System.println (Esperando ejecucin de tarea peridica...);
tp.ejecutarTarea ();
while (!tpa.necesitaEjecucion ())
System.println (Esperando ejecucin de aviso...);
System.println (Aviso: + tpa.leerMsg ());
}
}
En la implementacin de una operacin de la
subclase no existe diferencia aparente entre un
atributo u operacin propia de la clase y un atributo u
operacin heredados
Ahora podemos crear y usar objetos de cualquiera de las clases anteriores.
Desde el exterior tampoco existen diferencias aparentes entre la llamada a una
operacin heredada o propia de la clase:
Programacin OO en
Java
Herencia en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La inicializacin de los atributos de una superclase
en el constructor de una subclase presenta varios
inconvenientes serios:
Resulta redundante. La superclase tiene ya un constructor que hace ese
trabajo. Por qu repetir cdigo entonces?
Si la clase tiene una larga lista de ascendientes, entonces el constructor sera
muy largo
La superclase puede tener una inicializacin compleja, y la inclusin del
cdigo de inicializacin en la subclase puede requerir un conocimiento
excesivo de la superclase por parte del implementador
public class TPAviso extends TareaPeriodica {
String msg;
public TPAviso(String aMsg, int aPeriodoSegs) {
periodoSegs = aPeriodoSegs;
actualizarReloj ();
activa = true;
msg = aMsg;
}
public String leerMsg () { return msg; }
}
Programacin OO en
Java
Herencia en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
El procedimiento correcto consiste en realizar una
llamada al constructor de la superclase para que
realice la inicializacin de los atributos heredados
En Java esta llamada al constructor de la
superclase se realiza con la instruccin super
seguida de los parmetros de inicializacin de
alguno de los constructores del padre de la clase
La implementacin correcta del constructor de la clase TPAviso sera por tanto la
siguiente:
public class TPAviso extends TareaPeriodica {
String msg;
public TPAviso(String aMsg, int aPeriodoSegs) {
super (aPeriodoSegs);
msg = aMsg;
}
public String leerMsg () { return msg; }
}
Programacin OO en
Java
Herencia en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Y de las otras dos subclases:
import java.lang.Runtime;
import java.io.IOException;
public class TPEjecucion extends TareaPeriodica {
String cmd;
public TPEjecucion(String aCmd, int aPeriodoSegs) {
super (aPeriodoSegs);
cmd = aCmd;
}
String leerCmd () { return cmd; }
}
import java.util.Calendar;
import java.util.GregorianCalendar;
public class TPReloj extends TareaPeriodica {
public TPReloj () {
super (60);
}
public String leerHora () {
Calendar cal = new GregorianCalendar ();
return cal.get (Calendar.HOUR_OF_DAY) + ":"
+ cal.get (Calendar.MINUTE);
}
}
Programacin OO en
Java
Herencia en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
nicamente debe llamarse a un constructor del
ascendiente inmediato. El constructor de este ltimo
realizar a su vez una llamada a un constructor de su
ascendiente inmediato y as sucesivamente hasta
inicializar todos los atributos heredados
A
super (...)
super (...)
super (...)
super (...)
B
D C
Programacin OO en
Java
Herencia en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Para terminar, es posible impedir la herencia a partir
de una clase declarndola como final
Sin embargo, esta es una caracterstica que debe ser
utilizada con prudencia, ya que puede restringir en
exceso la extensin y reutilizacin de las clases del
sistema en el futuro
import java.lang.Runtime;
import java.io.IOException;
final public class TPEjecucion extends TareaPeriodica {
String cmd;
public TPEjecucion(String aCmd, int aPeriodoSegs) {
super (aPeriodoSegs);
cmd = aCmd;
}
String leerCmd () { return cmd; }
}
Programacin OO en
Java
Adicin,
redefinicin y
anulacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La herencia en s no sera tan interesante si no fuera
por la posibilidad de adaptar en el descendiente los
miembros heredados
Adicin. Trivialmente el descendiente puede aadir nuevos atributos y
operaciones que se suman a los recibidos a travs de la herencia
Redefinicin. Es posible redefinir la implementacin de una operacin heredada
para adaptarla a las caractersticas de la clase descendiente. Tambin es
posible cambiar el tipo de un atributo heredado
Anulacin. Cuando un atributo u operacin heredados no tienen utilidad en el
descendientes, pueden ser anulados para impedir su utilizacin
No todos los lenguajes orientados a objetos soportan
estas caractersticas, en especial la anulacin
Adicin, redefinicin y anulacin
Programacin OO en
Java
Adicin,
redefinicin y
anulacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La redefinicin se realiza en Java y la mayora de los
lenguajes OO definiendo nuevamente la operacin en
el descendiente, utilizando exactamente el mismo
nombre y lista de argumentos
Las clases descendientes TPReloj, TPEjecucion y TPAviso no son capaces de
realizar su misin porque la implementacin de ejecutarTarea que contienen es la
heredada de TareaPeriodica, que no hace nada en particular. Es preciso redefinir
esta operacin en cada una de las subclases para que cumpla la funcin que se
espera de ella
TareaPeriodica
periodoSegs: Integer
ultimaej: Date
activa: Boolean
+necesitaEjecucion (): Boolean
+actualizarReloj ()
+ejecutarTarea ()
+activar ()
+desactivar ()
TPReloj
+leerHora (): String
TPAviso
msg: String
+leerMsg (): String
TPEjecucion
cmd: String
+leerCmd (): String
Programacin OO en
Java
Adicin,
redefinicin y
anulacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
import java.util.Calendar;
import java.util.GregorianCalendar;
public class TPReloj extends TareaPeriodica {
public TPReloj () {
super (60);
}
public String leerHora () {
Calendar cal = new GregorianCalendar ();
return cal.get (Calendar.HOUR_OF_DAY) + ":" + cal.get (Calendar.MINUTE);
}
public void ejecutarTarea () {
Calendar cal = new GregorianCalendar ();
int min = cal.get (Calendar.MINUTE);
if (min == 0 || min == 30)
System.out.println ("Hora: " + cal.get (Calendar.HOUR_OF_DAY) + " " + min);
}
}
Programacin OO en
Java
Adicin,
redefinicin y
anulacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
public class TPAviso extends TareaPeriodica {
String msg;
public TPAviso(String aMsg, int aPeriodoSegs) {
super (aPeriodoSegs);
msg = aMsg;
}
public String leerMsg () { return msg; }
public void ejecutarTarea () {
System.out.println ("ATENCIN AVISO: " + msg);
desactivar ();
}
}
import java.lang.Runtime;
import java.io.IOException;
public class TPEjecucion extends TareaPeriodica {
String cmd;
public TPEjecucion(String aCmd, int aPeriodoSegs) {
super (aPeriodoSegs);
cmd = aCmd;
}
String leerCmd () { return cmd; }
public void ejecutarTarea () {
try {
Runtime.getRuntime ().exec (cmd);
}
catch (IOException e) {
System.out.println ("Imposible ejecutar comando: " + cmd);
}
}
}
Programacin OO en
Java
Adicin,
redefinicin y
anulacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Cada tarea ejecuta ahora su funcin, aunque la llamada es aparentemente la
misma
public class AppGestorTareas {
public static void main (String[] args) {
TareaPeriodica tp = new TareaPeriodica (5);
TPAviso tpa = new TPAviso (Estudiar Programacin Avanzada !, 60);
TPEjecucion tpe = new TPEjecucion (rm ~/tmp/*, 3600);
while (!tp.necesitaEjecucion ())
System.println (Esperando ejecucin de tarea peridica...);
tp.ejecutarTarea ();
while (!tpa.necesitaEjecucion ())
System.println (Esperando ejecucin de aviso...);
tpa.ejecutarTarea ();
while (!tpr.necesitaEjecucion ())
System.println (Esperando ejecucin de comando...);
tpe.ejecutarTarea ();
}
}
Despus de la redefinicin, en el descendiente es
posible llamar a la versin original de la operacin en
el ascendiente mediante:
super.nombreOperacionRedefinida ()
import java.util.*;
public class TareaPeriodica {
int periodoSegs;
Date ultimaEj;
boolean activa;
public TareaPeriodica(int aPeriodoSegs) {
periodoSegs = aPeriodoSegs;
actualizarReloj ();
activa = true;
}
public TareaPeriodica () { this (1); }
final public void actualizarReloj () {
ultimaEj = new Date (); // Hora actual
}
final public boolean necesitaEjecucion () {
// Implementacin de la operacin
}
public void ejecutarTarea () {
System.out.println ("Ejecucion de tarea");
}
final public void activar () { activa = true; }
final public void desactivar () { activa = false; }
}
Programacin OO en
Java
Adicin,
redefinicin y
anulacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Otro uso posible de la palabra clave final es impedir
la redefinicin de una operacin en las subclases
public class TPAviso extends TareaPeriodica {
String msg;
// Impedir el acceso desde el exterior y las subclases
// al atributo activa
private boolean activa;
public TPAviso(String aMsg, int aPeriodoSegs) {
super (aPeriodoSegs);
msg = aMsg;
}
// Resto de la implementacin de la clase a partir de aqu
Programacin OO en
Java
Adicin,
redefinicin y
anulacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La anulacin es un mecanismo menos til, y con
menor soporte por parte de los lenguajes de
programacin
En Java es posible impedir el acceso a un atributo
redeclarndolo en una subclase como privado o
protegido, segn sea el nivel de proteccin que se
desee
public class TPAviso extends TareaPeriodica {
String msg;
public TPAviso(String aMsg, int aPeriodoSegs) {
super (aPeriodoSegs);
msg = aMsg;
}
public void activar () {}
public void desactivar () {
System.out.printl (Error: llamada a operacin privada);
System.getRuntime ().exit (1);
}
public String leerMsg () { return msg; }
public void ejecutarTarea () {
System.out.println ("ATENCIN AVISO: " + msg);
desactivar ();
}
}
Programacin OO en
Java
Adicin,
redefinicin y
anulacin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Sin embargo, Java no permite redefinir una
operacin haciendo su nivel de acceso ms restrictivo
Una solucin parcial consistira en redefinirla como
vaca o incluyendo un cdigo que impida su utilizacin
Programacin OO en
Java
Proteccin y
herencia
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Hemos visto anteriormente como los distintos niveles
de proteccin limitan el acceso a los miembros de la
clase desde el exterior. Pero como afectan estos
niveles de proteccin a los miembros heredados?
Miembros pblicos. Son accesibles desde los descendientes, y se heredan como
pblicos
Miembros privados. No son accesibles desde los descendientes
Miembros con acceso a nivel de paquete. Son accesibles desde los descendientes
siempre y cuando pertenezcan al mismo paquete que el ascendiente. Se heredan
con el mismo nivel de proteccin
Un nuevo nivel de proteccin es el de miembros
protegidos (protected). Un miembro protegido es
accesible nicamente desde los descendientes
Proteccin y herencia
Programacin OO en
Java
Proteccin y
herencia
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Adems, un miembro protegido mantiene en la
subclase el nivel de acceso protegido
En nuestro ejemplo, los atributos de la clase TareaPeriodica son accesibles
desde TPReloj, TPEjecucion y TPAviso porque al pertenecer al mismo paquete
son amigas
Para permitir el acceso a los atributos de la clase TareaPeriodica nicamente
desde los descendientes es conveniente marcarlos como protegidos
import java.util.*;
public class TareaPeriodica {
protected int periodoSegs;
protected Date ultimaEj;
boolean activa;
public TareaPeriodica(int aPeriodoSegs) {
periodoSegs = aPeriodoSegs;
actualizarReloj ();
activa = true;
}
// Resto de operaciones de la clase a partir de aqu
Programacin OO en
Java
Polimorfismo
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Son dos mecanismos relacionados que otorgan a la
OOP una gran potencia frente a otros paradigmas de
programacin
nicamente tienen sentido por la existencia de la
herencia
El polimorfismo (o upcasting) consiste en la posibilidad
de que una referencia a objetos de una clase pueda
conectarse tambin con objetos de descendientes de
sta
Polimorfismo
B rb = new B (); // Asignacin ordinaria
A ra = rb; // Asignacin polimorfa
ra: A
B
A
rb: B
objeto: B
Programacin OO en
Java
Polimorfismo
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
public class AppGestorTareas {
public static void main (String[] args) {
TPReloj tpr = new TPReloj ();
TPAviso tpa = new TPAviso (Ha pasado un minuto, 60);
TPEjecucion tpe = new TPEjecucion (/bin/sync, 120);
TareaPeriodica tp;
tp = tpr;
tp.desactivar ();
tp = tpa;
tp.desactivar ();
tp = tpe;
tp.desactivar ();
}
}
El sentido del polimorfismo es realizar una generaliza-
cin, olvidar los detalles concretos de uno o varios
objetos de distintas clases y buscar un punto comn a
todos ellos en un ancestro
Se trata de algo que realiza comnmente la mente
humana durante el proceso de razonamiento
Programacin OO en
Java
Polimorfismo
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La mayora de las veces, las conexiones polimorfas se
realizan de manera implcita en el paso de argumentos
a una operacin. De esta manera es posible escribir
operaciones polimorfas que reciban objetos de
mltiples clases
public class AppGestorTareas {
private static void esperarEjecutar (TareaPeriodica tp)
{
while (!tp.necesitaEjecucion ());
tp.ejecutarTarea ();
}
public static void main (String[] args) {
TPReloj tpr = new TPReloj ();
TPAviso tpa = new TPAviso (Ha pasado un minuto, 60);
TPEjecucion tpe = new TPEjecucion (/bin/sync, 120);
esperarEjecutar (tpr);
esperarEjecutar (tpa);
esperarEjecutar (tpe);
}
}
Programacin OO en
Java
Polimorfismo
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Otra aplicacin muy til es la construccin de
estructuras de datos que puedan mantener objetos de
distintas clases
Vamos a implementar una nueva clase GestorTareas que va a contener una lista de
tareas a realizar. La llamada a chequearEjecutar realizar la comprobacin y ejecucin
de las tareas que lo requieran
import java.lang.Exception;
class DemasiadasTareas extends Exception {}
public class GestorTareas {
TareaPeriodica[] tareas;
int nTareas, maxTareas;
public GestorTareas (int aMaxTareas) {
nTareas = 0;
maxTareas = aMaxTareas;
tareas = new TareaPeriodica[maxTareas];
}
// Sigue...
import java.lang.System;
public class AppGestorTareas {
public static void main (String[] args) {
GestorTareas gt = new GestorTareas (10);
try {
gt.nuevaTarea (new TPReloj ());
gt.nuevaTarea (new TPAviso (Ha pasado un minuto, 60));
gt.nuevaTarea (new TPEjecucion (/bin/sync, 120));
} catch (DemasiadasTareas e) {
System.out.println (Mmmm.... esto no deberia haber pasado);
}
gt.chequearEjecutar ();
}
}
Programacin OO en
Java
Polimorfismo
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
// Continuacin de la clase GestorTareas
public void nuevaTarea (TareaPeriodica tp)
throws DemasiadasTareas {
if (nTareas == maxTareas)
throw new DemasiadasTareas ();
tareas[nTareas++] = tp;
}
public void chequearEjecutar ()
{
for (int t = 0; t < nTareas; t++)
if (tareas[t].necesitaEjecucion ())
tareas[t].ejecutarTarea ();
}
}
Programacin OO en
Java
Polimorfismo
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Pero siempre debe quedar claro que tras la conexin
polimorfa nicamente podemos acceder a las opera-
ciones pertenecientes a la clase asociada a la refe-
rencia. El resto de operaciones del objeto no son
accesibles a travs de esta referencia
public class AppGestorTareas {
public static void main (String[] args) {
TPReloj tpr = new TPReloj ();
TareaPeriodica tp;
tp = tpr;
tp.desactivar (); // Ok
tp.leerHora () // Error !!
tpr.leerHora (); // Ok
}
}
AppGestorTareas.java:XX: cannot resolve symbol
symbol : method leerHora ()
location: class TareaPeriodica
tp.leerHora ();
^
1 error
Programacin OO en
Java
Polimorfismo
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
En Java, una referencia a Object puede ser conec-
tada a cualquier objeto, puesto que como sabemos es
un ancestro de todas las clases
public class AppGestorTareas {
public static void main (String[] args) {
TPReloj tpr = new TPReloj ();
Object o;
o = tpr;
System.out.println (o.getClass ().getName ());
}
}
Adems, las interfaces implementadas por una clase
tambin pueden ser utilizadas para realizar conexiones
polimorfas. Es decir, las interfaces que implementa una
clase se comportan igual que las superclases en lo que
respecta al uso del polimorfismo
Programacin OO en
Java
Ligadura dinmica
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Entendemos por resolucin de una llamada el proceso
por el cual se sustituye una llamada a una funcin por
un salto a la direccin que contiene el cdigo de esta
funcin
Normalmente, la resolucin de llamadas se realiza en
en tiempo de compilacin, porque resulta ms sencillo
y sobre todo ms eficiente. Cuando la aplicacin se
est ejecutando, las llamadas ya estn preparadas.
Este enfoque se denomina ligadura esttica
Ligadura dinmica
f ()
CALL _f
Programacin OO en
Java
Polimorfismo y
ligadura dinmica
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
El problema aparece en OOP cuando realizamos una
conexin polimorfa y llamamos a una operacin
redefinida
A r = ??
r.f ()
CALL _A_f ?
CALL _B_f ?
CALL _C_f ?
A
f ()
El compilador no tiene informacin para resolver la
llamada. Por defecto utilizara el tipo de la referencia, y
por tanto generara una llamada a la implementacin
de f () en la clase A
Pero la referencia r puede apuntar a objetos de las
clases A, B o C, con distintas versiones de f ()
B
f ()
C
f ()
Programacin OO en
Java
Polimorfismo y
ligadura dinmica
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La solucin consiste en esperar a resolver la llamada
al tiempo de ejecucin, cuando se conoce realmente
los objetos conectados a r, y cul es la versin de f ()
apropiada. Este enfoque de resolucin de llamadas se
denomina ligadura dinmica y es mucho ms lenta y
compleja que la esttica
Hay tres enfoques posibles a la hora de abordar el
problema de la resolucin de llamadas
Establecer la ligadura esttica por defecto. El programador puede activar la
ligadura dinmica para una funcin concreta cuando lo ve necesario,
declarndolas como virtuales (C++)
Utilizar un compilador inteligente que decide la ligadura esttica o dinmica en
funcin del empleo que se hace de cada funcin (Eiffel)
Establecer la ligadura dinmica para todas las funciones y evitar problemas a
costa de eficiencia en la ejecucin (Smalltalk, Java)
Programacin OO en
Java
Polimorfismo y
ligadura dinmica
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
public class AppGestorTareas {
public static void main (String[] args) {
TPReloj tpr = new TPReloj ();
TPAviso tpa = new TPAviso (Ha pasado un minuto, 60);
TPEjecucion tpe = new TPEjecucion (/bin/sync, 120);
TareaPeriodica tp;
tp = tpr;
tp.ejecutarTarea (); // Versin de TPReloj
tp = tpa;
tp.ejecutarTarea (); // Versin de TPAviso
tp = tpe;
tp.ejecutarTarea (); // Versin de TPEjecucion
}
}
Por tanto, la ligadura dinmica, por defecto en Java,
garantiza siempre la llamada a la versin correcta de
cada funcin, con independencia del uso de
conexiones polimorfas o no
Las llamadas a la funcin ejecutarTarea se resuelven correctamente, a pesar de
realizarse a travs de una referencia a TareaPeriodica
Programacin OO en
Java
Informacin de
clases en tiempo de
ejecucin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Tras realizar una conexin polimorfa es frecuente la
necesidad de volver a recuperar el objeto original, para
acceder a sus operaciones propias
Se trata de la operacin inversa al polimorfismo
(upcasting), denominada downcasting
Si el polimorfismo implica una generalizacin, el
downcasting implica una especializacin
Al contrario que el upcasting, el downcasting no puede
realizarse directamente mediante una conexin con
una referencia de la clase del objeto
Informacin de clases en tiempo de
ejecucin
Programacin OO en
Java
Informacin de
clases en tiempo de
ejecucin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Tras crear un objeto de tipo TPReloj y conectarlo mediante una referencia a
TareaPeriodica, intentamos recuperar nuevamente una referencia de tipo TPReloj al
objeto. No es posible de manera directa
public class AppGestorTareas {
public static void main (String[] args) {
TareaPeriodica tp = new TPReloj (); // upcasting
TPReloj tr = tp; // downcasting ?
}
}
AppGestorTareas.java:XX: incompatible types
found : TareaPeriodica
required: TPReloj
TPReloj tr = tp;
^
1 error
Un simple casting nos permitir forzar la conexin a la
referencia
public class AppGestorTareas {
public static void main (String[] args) {
TareaPeriodica tp = new TPReloj (); // upcasting
TPReloj tr = (TPReloj) tp; // downcasting
}
}
Programacin OO en
Java
Informacin de
clases en tiempo de
ejecucin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Pero cuidado ! El casting de Java es inteligente. Un
intento de conexin imposible producir una excepcin
ClassCastException durante la ejecucin
Exception in Thread main java.lang.ClassCastException
at AppGestorTareas.main(AppGestorTareas.java:XX)
public class AppGestorTareas {
public static void main (String[] args) {
TareaPeriodica tp = new TPReloj (); // upcasting
TPReloj tr = (TPReloj) tp; // downcasting ok
// Downcasting imposible: lanza excepcin ClassCastException
TPAviso ta = (TPAviso) tp;
}
}
Programacin OO en
Java
Informacin de
clases en tiempo de
ejecucin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Podemos capturar esta excepcin para determinar si
el objeto apuntado por la referencia era del tipo
esperado o no, realizando acciones diferentes en cada
caso
import java.lang.*;
public class AppGestorTareas {
public static void main (String[] args) {
TareaPeriodica tp;
TPReloj tr;
// Posiblemente en algn punto la referencia tp ha sido conectada con un objeto
// de la clase TPReloj
...
try {
tr = (TPReloj) tp;
System.out.println (La hora actual es: + tr.leerHora ());
}
catch (ClassCastException e) {
System.out.println (La referencia tp no apunta a un objeto de la clase TPReloj);
}
}
}
Programacin OO en
Java
Informacin de
clases en tiempo de
ejecucin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
import java.lang.*;
public class AppGestorTareas {
public static void main (String[] args) {
TareaPeriodica tp; TPReloj tr; TPAviso ta; TPEjecucion te;
// tp es conectada a algn objeto
...
try {
tr = (TPReloj) tp;
// Operar con tr
return;
}
catch (ClassCastException e) {
// Si no es de tipo TPReloj, continuamos por aqu
}
try {
ta = (TPAviso) tp;
// Operar con ta
return;
}
catch (ClassCastException e) {
// Si no es de tipo TPAviso, continuamos por aqu
}
try {
te = (TPEjecucion) tp;
// Operar con te
return;
}
catch (ClassCastException e) {
// Si tampoco es de tipo TPEjecucin Entonces de que tipo es?
System.out.println (Error: objeto de clase desconocida);
}
}
}
import java.lang.ClassCastException;
import java.lang.System;
public class AppGestorTareas {
public static void main (String[] args) {
TareaPeriodica tp; TPReloj tr; TPAviso ta; TPEjecucion te;
// tp es conectada a algn objeto
...
if (tp instanceof TPReloj) {
tr = (TPReloj) tp;
// Operar con tr
}
else
if (tp instanceof TPAviso) {
ta = (TPAviso) tp;
// Operar con ta
}
else
if (tp instanceof TPEjecucion) {
te = (TPEjecucion) tp;
// Operar con te
}
else
System.out.println (Error: objeto de clase desconocida);
}
}
Programacin OO en
Java
Informacin de
clases en tiempo de
ejecucin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Mucho ms cmodo es utilizar instanceof para
determina si el objeto es de la clase esperada antes de
realizar el casting
import java.lang.ClassCastException;
import java.lang.System;
public class AppGestorTareas {
public static void main (String[] args) {
TareaPeriodica tp;
// tp es conectada a algn objeto
...
Class c = tp.getClass ();
System.out.println (La referencia tp apunta a un objeto de la clase: + c.getName ());
Class c = TareaPeriodica.class;
if (c.isInterface ())
System.out.println (TareaPeriodica es una Interfaz);
}
Programacin OO en
Java
Informacin de
clases en tiempo de
ejecucin
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La operacin getClass () de Object devuelve un objeto
de la clase Class que permite obtener en tiempo de
ejecucin gran cantidad de informacin de la clase a la
que pertenece el objeto. El atributo esttico class de la
clase tambin devuelve una referencia a este objeto
Programacin OO en
Java
Clases abstractas
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Existen clases que representan conceptos tan
genricos que no tiene sentido su instanciacin en
objetos
Adems en este tipo de clases puede ser imposible o
intil la implementacin de ciertas operaciones
La utilidad de este tipo de clases est en la aplicacin
de herencia para obtener clases que representan
conceptos concretos para los que s que tiene sentido
su instanciacin
La clase TareaPeriodica es un claro ejemplo: por s sola no tiene utilidad, pero
simplifica mucho la construccin de las otras tres clases. De hecho, la operacin
ejecutarTarea en TareaPeriodica no tiene una implementacin til
Clases abstractas
Programacin OO en
Java
Clases abstractas
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Estas clases se denominan clases abstractas y este
tipo de operaciones sin implementacin posible,
operaciones abstractas
Las operaciones abstractas deben ser implemen-
tadas obligatoriamente en alguna de las subclases
para que la clase correspondiente sea instanciable
Una clase abstracta puede no tener ninguna
operacin abstracta, pero una clase que contenga al
menos una operacin abstracta debe ser declarada
como abstracta
En Java, tilizando la declaracin abstract podremos
establecer una clase o una operacin como abstracta
import java.util.*;
abstract class TareaPeriodica {
int periodoSegs;
Date ultimaEj;
boolean activa;
public TareaPeriodica(int aPeriodoSegs) {
periodoSegs = aPeriodoSegs;
actualizarReloj ();
activa = true;
}
public TareaPeriodica () { this (1); }
public void actualizarReloj () {
ultimaEj = new Date (); // Hora actual
}
public boolean necesitaEjecucion () {
if (!activa)
return false;
// Resto de la implementacin de esta
// operacin aqu
}
abstract public void ejecutarTarea ();
public void activar () { activa = true; }
public void desactivar () { activa = false; }
}
Programacin OO en
Java
Clases abstractas
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Vamos a declarar la clase TareaPeriodica y su operacin ejecutarTarea como
abstractas
Programacin OO en
Java
Clases abstractas
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Java devuelve ahora un error en tiempo de compilacin si se intenta crear un
objeto de la clase TareaPeriodica
public class AppGestorTareas {
public static void main (String[] args) {
TareaPeriodica tp = new TareaPeriodica (5);
while (!tp.necesitaEjecucion ())
System.println (Esperando ejecucin de tarea peridica...);
tp.ejecutarTarea ();
}
}
AppGestorTareas.java:XX: class TareaPeriodica is an abstract class; cannot be instantiated
TareaPeriodica tp = new TareaPeriodica ();
^
1 error
La abstraccin de una clase se propaga por la
jerarqua de herencia hasta que todas las operaciones
quedan implementadas. Es decir, la primera clase
instanciable es aquella con todas las operaciones
implementadas
Programacin OO en
Java
Clases abstractas
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La idea de clase abstracta, llevada al extremo, nos
lleva en Java a las interfaces. Una interfaz es similar
a una clase totalmente abstracta:
Todas las operaciones de la interfaz son implcitamente abstractas, es decir,
carecen de implementacin
Una interfaz no puede contener atributos
Las interfaces sirven para especificar las operaciones
que obligatoriamente deben implementar una serie de
clases
La implementacin de una interfaz no se realiza
mediante herencia (extends) sino mediante
implements. No obstante, el comportamiento es
similar al de la herencia, aunque ms sencillo
Programacin OO en
Java
Clases abstractas
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Si una clase declara la implementacin de una
determinada interfaz, esta implementacin debe ser
completa, es decir, de todas las operaciones de la
interfaz
Podemos transformar TareaPeriodica en una interfaz, de forma que especifique lo
que tiene que implementar cualquier clase que represente una tarea peridica. Este
enfoque proporciona mayor libertad a la hora de disear las otras clases
<<interfaz>>
TareaPeriodica
+necesitaEjecucion (): Boolean
+actualizarReloj ()
+ejecutarTarea ()
+activar ()
+desactivar ()
TPReloj
+leerHora (): String
+necesitaEjecucion (): Boolean
+actualizarReloj ()
+ejecutarTarea ()
+activar ()
+desactivar ()
TPAviso
msg: String
+leerMsg (): String
+necesitaEjecucion (): Boolean
+actualizarReloj ()
+ejecutarTarea ()
+activar ()
+desactivar ()
TPEjecucion
cmd: String
+leerCmd (): String
+necesitaEjecucion (): Boolean
+actualizarReloj ()
+ejecutarTarea ()
+activar ()
+desactivar ()
Programacin OO en
Java
Clases abstractas
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La interfaz TareaPeriodica y la clase TPReloj tendran ahora el siguiente aspecto.
Las otras clases tendran implementaciones similares
import java.util.Calendar;
import java.util.GregorianCalendar;
public class TPReloj implements TareaPeriodica {
Date ultEjecucion;
boolean activa;
public TPReloj () { activa = true; ultEjecucion = new Date () }
public void ejecutarTarea () {
Calendar cal = new GregorianCalendar ();
int min = cal.get (Calendar.MINUTE);
System.out.println ("Hora: " + cal.get (Calendar.HOUR_OF_DAY)
+ " " + min);
ultEjecucion = cal.getTime ();
}
public interface TareaPeriodica {
boolean necesitaEjecucion ();
void ejecutarTarea ();
void activar ();
void desactivar ();
}
Programacin OO en
Java
Clases abstractas
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
public boolean necesitaEjecucion () {
if (!activa)
return false;
Calendar calProximaEj = new GregorianCalendar ();
Calendar calUltEjecucion = new GregorianCalendar ();
calUltEjecucion.setTime (ultEjecucion);
Calendar calAhora = new GregorianCalendar ();
if (calAhora.equal (calUltEjecucion))
return false;
int min = calAhora.get (Calendar.MINUTE);
if (min == 00 || min == 30)
return true;
return false;
}
public void activar () { activa = true; }
public void desactivar () { activar = false; }
public String leerHora () {
Calendar cal = new GregorianCalendar ();
return cal.get (Calendar.HOUR_OF_DAY) + ":" +
cal.get (Calendar.MINUTE);
}
}
Programacin OO en
Java
Clases abstractas
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Una clase puede implementar ms de una interfaz
Una interfaz puede heredar de otra interfaz
Cuando utilizar una interfaz en lugar de una clase
abstracta?
Por su sencillez se recomienda utilizar interfaces siempre que sea posible
Si la clase debe incorporar atributos, o resulta interesante la implementacin de
alguna de sus operaciones, entonces declararla como abstracta
En la biblioteca de clases de Java se hace un uso
intensivo de las interfaces para caracterizar las
clases. Algunos ejemplos:
Para que un objeto pueda ser guardado en un fichero la clase debe implementar
la interfaz Serializable
Para que un objeto sea duplicable, su clase debe implementar Cloneable
Para que un objeto sea ordenable, su clase debe implementar Comparable
Programacin OO en
Java
Herencia mltiple
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Consiste en la posibilidad de que una clase tenga
varios ascendientes directos
Puede surgir de manera relativamente frecuente y
natural durante el diseo
Herencia mltiple
FiguraGeometrica
almacena
*
Lista
Poligono
Punto
FicheroLectura FicheroEscritura
FicheroLecturaEscritura
Imagen EnlaceURL
ImagenSensible
Programacin OO en
Java
Herencia mltiple
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Tiene claramente aspectos positivos
Surge de manera natural al describir la estructura de un sistema
Proporciona mucha flexibilidad a la hora de construir clases nuevas
Pero tambin aspectos negativos
Complica el diseo. La jerarqua de clases deja de ser tal jerarqua para pasar a
ser una red
Provoca problemas de eficiencia. La llamada a una operacin heredada implica la
bsqueda por mltiples caminos
Ambigedad: dos atributos u operaciones con el mismo nombre pueden llegar a
una clase por dos caminos distintos
Herencia repetida: en una estructura con forma de rombo, un atributo u operacin
puede llegar a una clase por dos caminos distintos
A
atributoX
B
atributoX
C
A B
C
D
atributoX
Programacin OO en
Java
Herencia mltiple
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
La apuesta de los creadores de Java es clara: no
permitir la herencia mltiple, por las razones expuestas
anteriormente
A veces es posible sustituir la herencia mltiple por
una combinacin herencia/composicin, aunque el
resultado no puede considerarse equivalente
FiguraGeometrica
Poligono
listaPuntos (): Lista
almacena
*
contiene
1
Lista
aadir (s: Segmento)
borrarPrim ()
borrarUlt ()
almacena
*
contiene
1
FiguraGeometrica
Poligono
aadir (s: Segmento)
Segmento
Segmento
Lista
Programacin OO en
Java
Herencia mltiple
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Adems, Java s que permite la implementacin de
una o varias interfaces adems de la herencia, lo que
puede considerarse una forma restringida de herencia
mltiple
Una clase puede heredar de otra e implementar una o
varias interfaces sin que aparezcan los problemas
asociados con la herencia mltiple
<<interfaz>>
FiguraGeometrica
Poligono
listaPuntos (): Lista
almacena
*
Segmento
Lista
Programacin OO en
Java
Otros temas de
inters en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Entrada/Salida. La librera de clases de Java dispone
de gran cantidad de clases para la gestin transparente
de E/S. Estas clases pueden combinarse para crear
flujos de datos especializados
Las clases FileInputStream y FileOutputStream permite abrir streams de E/S
secuencial a ficheros en disco. La clase RandomAccessFile permite leer y escribir
informacin a un fichero de forma aleatoria
Las clases DataInputStream y DataOutputStream permite leer y escribir
informacin de un stream
Las clase BufferedInputStream y BufferedOutputStream permite leer y escribir
informacin utilizando un buffer intermedio para acelerar las operaciones
Las clase PrintWriter permite escribir en formato texto ASCII en un fichero
Ver el apartado I/O: Reading and Writing del tutorial
Java para ms informacin
Otros temas de inters en Java
Programacin OO en
Java
Otros temas de
inters en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Serializacin. Una de las caractersticas ms potentes
de Java es la posibilidad de serializar un objeto, es
decir, convertirlo en una secuencia de bytes y enviarlo
a un fichero en disco, por un socket a otro ordenador a
travs de la red, etc. El proceso sera el siguiente:
Declarar la implementacin de la interfaz Serializable en la clase que deseemos
serializar. Se trata de una interfaz vaca, por lo que no hay operaciones que
implementar
Para serializar el objeto crearamos un stream ObjectOutputStream y
escribiramos el objeto mediante la operacin writeObject ()
Para deserializar el objeto crearamos un stream ObjectInputStream, leeramos el
objeto mediante readObject () y realizaramos un casting a la clase del objeto
Ver el apartado Object Serialization del tutorial Java
para ms informacin
import java.io.*;
import java.util.*;
// Es necesario que la clase Movimiento implemente la interfaz Serializable para
// que los objetos puedan ser escritos en disco
public class Cuenta {
long numero;
Cliente titular;
private float saldo;
float interesAnual;
LinkedList movimientos;
static private class Movimiento implements Serializable {
Date fecha;
char tipo;
float importe;
float saldo;
public Movimiento (Date aFecha, char aTipo, float aImporte, float aSaldo) {
fecha = aFecha;
tipo = aTipo;
importe = aImporte;
saldo = aSaldo;
}
}
}
Programacin OO en
Java
Otros temas de
inters en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Vamos a modificar ahora el constructor de la clase Cuenta y la operacin salvar para
que sean capaces de cargar y salvar el historico de movimientos. La capacidad de
seralizacin de Java permite salvar la lista enlazada de un golpe
public Cuenta (long aNumero, Cliente aTitular, float aInteresAnual) {
numero = aNumero;
titular = aTitular;
saldo = 0;
interesAnual = aInteresAnual;
movimientos = new LinkedList ();
}
Cuenta (long aNumero) throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream (new FileInputStream (aNumero + ".cnt"));
numero = ois.readLong ();
titular = (Cliente) ois.readObject ();
saldo = ois.readFloat ();
interesAnual = ois.readFloat ();
movimientos = (LinkedList) ois.readObject ();
ois.close ();
}
void salvar () throws FileNotFoundException, IOException {
ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream (numero + ".cnt"));
oos.writeLong (numero);
oos.writeObject (titular);
oos.writeFloat (saldo);
oos.writeFloat (interesAnual);
oos.writeObject (movimientos);
oos.close ();
}
// Resto de operaciones de la clase Cuenta a partir de aqu
Programacin OO en
Java
Otros temas de
inters en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Programacin OO en
Java
Otros temas de
inters en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
Multitarea. Es posible implementar una o varias tareas
que se ejecuten en varias hebras de ejecucin en
paralelo, de la siguiente manera
Construir una clase que represente la tarea y herede de la clase Java Thread
Redefiniendo la operacin run () de Thread podremos introducir el cdigo que
deseamos ejecutar en la hebra
Para arrancar la nueva hebra basta con crear un objeto de la clase y ejecutar la
operacin start ()
Si se desea parar la hebra durante un tiempo determinado, puede utilizarse la
operacin sleep (int segs)
La tarea finaliza cuando se el hilo de ejecucin llega de forma natural al final de la
operacin run ()
Ver el apartado Threads: doing two or more tasks at
once del Tutorial Java para ms informacin
Programacin OO en
Java
Otros temas de
inters en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
import java.lang.Exception;
class DemasiadasTareas extends Exception {}
public class GestorTareas extends Thread {
TareaPeriodica[] tareas;
int nTareas, maxTareas;
boolean terminar;
public GestorTareas (int aMaxTareas) {
super ("GestorTareas");
terminar = false;
nTareas = 0;
maxTareas = aMaxTareas;
tareas = new TareaPeriodica[maxTareas];
}
public void nuevaTarea (TareaPeriodica tp) throws DemasiadasTareas {
if (nTareas == maxTareas)
throw new DemasiadasTareas ();
tareas[nTareas++] = tp;
}
// Sigue...
Ejemplo: un gestor de tareas que funciona en paralelo con el resto de la aplicacin,
realizando la comprobacin peridica de las tareas que requieren ejecucin
Programacin OO en
Java
Otros temas de
inters en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
// Continua la clase GestorTareas
public void run ()
{
System.out.println ("Gestor de tareas en funcionamiento");
while (!terminar) {
for (int t = 0; t < nTareas; t++)
if (tareas[t].necesitaEjecucion ())
tareas[t].ejecutarTarea ();
// Esperar un segundo antes de volver a comprobar
try {
sleep (1);
}
catch (InterruptedException e) { };
}
System.out.println ("Finalizando gestor de tareas");
}
void terminar () { terminar = true; }
}
La operacin terminar () va a permitir forzar la finalizacin del gestor de tareas
Programacin OO en
Java
Otros temas de
inters en Java
P
r
o
g
r
a
m
a
c
i

n
A
v
a
n
z
a
d
a
import java.lang.System;
import java.io.IOException;
public class AppGestorTareas {
public AppGestorTareas() {}
public static void main(String[] args) {
GestorTareas gt = new GestorTareas (10);
try {
gt.nuevaTarea (new TPReloj ());
gt.nuevaTarea (new TPAviso ("Ha pasado 1 minuto", 60));
} catch (DemasiadasTareas dt) {}
gt.start (); // Arrancar hilo
System.out.println ("Hilo de ejecucion principal");
System.out.println ("Pulsa una tecla para terminar");
try {
System.in.read ();
}
catch (IOException e) {}
gt.terminar ();
System.out.println ("Final de hilo de aplicacion");
}
}
Esta aplicacin contara con dos hilos de ejecucin en paralelo, uno principal y otro
asociado al gestor de tareas
Tema5.
Excepciones
Tipos de excepciones
Gestin de las excepciones
Propagacin de excepciones
Excepciones definidas por el usuario
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 2/40
Excepciones
Situaciones anmalas que aparecen durante la ejecucin
de un programa
Son objetos que describen una condicin excepcional
Cuando un mtodo encuentra una condicin anormal que
no puede manejar, lanza una excepcin
Se crea el objeto correspondiente (Exception) y se enva al
mtodo original que invoc el mtodo anterior que ha
provocado la excepcin
El mtodo a su vez, puede procesar (capturar) la
excepcin o pasarla al mtodo que la invoc. As,
sucesivamente, a travs de toda la pila de invocaciones
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 3/40
Excepciones
Su gestin permite la deteccin y correccin de
errores en ejecucin
Simplifican los programas ya que se diferencia el cdigo
normal del cdigo de tratamiento de errores
Se crean programas mas robustos ya que en muchos
casos si no se trata la excepcin el programa no compila
Slo se deben usar cuando no se puede
resolver la situacin anmala directamente
en ese contexto
Se tiene que seguir haciendo el control
de errores habitual
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 4/40
Tipos de situaciones
excepcionales
Excepciones
Situaciones ms o menos habituales que impiden
completar la ejecucin correcta del cdigo
Generalmente el programador debe proporcionar el cdigo
que las trate o gestione
Ejemplos
Error en el cdigo o en los datos
Uso inadecuado de un mtodo
Ejemplo, la excepcin ArrayIndexOutOfBoundsException no
debera lanzarse nunca si los ndices de acceso a un
vector no se salen de los lmites.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 5/40
Tipos de situaciones
excepcionales
Errores
Representan situaciones de error normalmente no
recuperables
El programador normalmente no tiene que proporcionar un
tratamiento para ellas
Ejemplos
No se puede localizar y cargar una clase
Se agota la memoria
Ejemplo, la excepcin OutOfMemoryError salta cuando se
agota la memoria del sistema o se sobrepasa el lmite
permitido por la mquina virtual
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 6/40
Tipos de excepciones
Predefinidas en el sistema
Se lanzan automticamente cuando se realiza alguna
operacin no valida
Acceso a un objeto que no existe,
Acceso a una posicin de un array que no existe,
Divisin por cero
Generadas por el programador
El programa explcitamente genera una excepcin al
detectar una situacin de error que no se puede resolver
en ese contexto
til en situaciones de prueba y depuracin
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 7/40
Tipos de excepciones
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 8/40
Excepciones y
errores predefinidos
Java genera los errores de ejecucin en
forma de excepciones
Runtime Exceptions
Punteros null, arrays, aritmtica, etc.
No se suelen comprobar aunque tambin se puede
Error
Errores ms serios
Errores de linkado, desbordamiento de memoria, etc.
En general tampoco se procesan
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 9/40
Excepciones y
errores predefinidos
Excepciones Errores
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 10/40
Ejemplo
public class HolaMundo {
public static void main (String args[]){
int i = 0;
String vectorS [] = {
"Hola mundo1",
"Hola mundo 2",
for (i = 0; i < 3; i++) {
System.out.println(vectorS[i]);
}
}
}
$ java HolaMundo
HolaMundo 1
HolaMundo 2
java.lang.ArrayIndexOutBoundsException : 2
at HolaMundo.main(HolaMundo.java:8)
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 11/40
Gestin de excepciones
try {
// bloque de cdigo donde puede producirse una excepcin
}catch( TipoExcepcin1 e ) {
// gestor de excepciones para TipoExcepcin1
// se ejecuta si se produce una excepcin TipoExcepcin1
}catch( TipoExcepcin2 e ) {
// gestor de excepciones para TipoExcepcin2
// opcionalmente se puede volver a lanzar una excepcin
throw new TipoExcepcin2();
} finally {
// bloque que se ejecuta siempre, haya o no excepcin
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 12/40
Gestin de excepciones
Para gestionar excepciones hay que insertar el cdigo donde
se puede dar dentro de un bloque try.
Se crea una lista de bloques catch adyacentes, uno por cada
posible excepcin.
El bloque de cdigo finally se ejecuta siempre, haya o no
excepcin
La nica situacin en la que la sentencia finally no se ejecuta es
si se llama al mtodo System.exit (), que termina la ejecucin del
programa
Para lanzar de forma explcita una excepcin se utiliza throw
Se puede utilizar para propagar una excepcin tratada
parcialmente
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 13/40
Excepciones anidadas
try{
// Cdigo
try{
// Cdigo
}catch(TipoExcepcin2 excepcin2) {
// gestor de excepciones para TipoExcepcin2
}
} catch(TipoExcepcin1 excepcin1) {
// gestor de excepciones para TipoExcepcin1
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 14/40
Sin captura de excepciones
Exception in thread "main" java.lang.ArithmeticException:
divide by zero
at java.math.MutableBigInteger.divide(Unknown Source)
at java.math.BigInteger.divide(Unknown Source)
at PruebaExcepciones.main(Main.java:14)
public class PruebaExcepciones {
public static void main(String args[]) {
int valor=5, cero=0;
int[] array = {1, 2, 3};
valor = valor/cero; //divisin por cero
array[4]= 5; //acceso posicin no disponible
}
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 15/40
Captura de excepciones
public class PruebaExcepciones {
public static void main(String args[]) {
int valor=5, cero=0;
int[] array = {1, 2, 3};
try {
valor = valor/cero; //divisin por cero
array[4]= 5; //acceso posicin no disponible
}
catch( ArithmeticException e ) {
System.out.println( "Division por cero" );
}
catch( Exception e ) {
System.out.println( "Error en la ejecucin");
}
} }
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 16/40
Gestin incompleta de
excepciones: throws
Si un mtodo no gestiona o captura todas las excepciones
que puede generar (excepto las del tipo RuntimeException
o Error) debe especificarlo mediante throws
Indica que el cdigo producir una excepcin, que no se
tratar dentro de l y se pasar al mtodo superior,
utilizando la clusula throws
public void ejemploExcep () throws IOException
A continuacin de la palabra reservada throws aparece una
lista de todas las excepciones que se pueden dar dentro
del mtodo y no sern gestionadas.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 17/40
Gestin incompleta de
excepciones: throws
import java.io.*;
public class PruebaExcepciones {
public static char leer() throws IOException {
return (char) System.in.read();
}
public static void main(String args[]) {
try {
char car = leer();
System.out.println("Caracter: " + car);
} catch (IOException e) {
System.out.println("Error de entrada de datos");
}
}
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 18/40
Gestin incompleta de
excepciones: throws
Un mtodo sobreescrito no puede declarar ms
excepciones que (subclases de) las que declara su
clase padre
Si un mtodo sobreescrito emite una excepcin no
declarada en el padre, es obligatorio procesarla
dentro del mtodo aunque no se haga nada
class X extends Applet {
public void start () { // start heredado de Applet
try { } catch (IOException e) { /* vacio */ }
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 19/40
Lanzamiento de
nuevas excepciones
public class Alumno{
public Alumno(String nombre, String apellidos) throws Exception{
if(nombre == null || apellidos == null)
throw new Exception("Argumentos no vlidos");
//si el constructor lanza la excepcin el objeto
//no se crea
}
public static void main(String args[]) {
try{
Alumno alum = new Alumno(null, "hola");
}
catch (Exception e){
//el objeto excepcin contiene informacin til
//que podemos utilizar
System.out.println("Excepcion: "+ e.getMessage());
}
}
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 20/40
Propagacin de excepciones
Todas las excepciones que se puedan generar se han de manejar o delegar
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 21/40
Propagacin de excepciones
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 22/40
Excepciones
definidas por el usuario
El programador tambin puede definir sus propias
clases de excepciones
Se define una clase que herede de Throwable o ms
normalmente de Exception
public class EdadFueraDeRangoException extends Exception {
public EdadFueraDeRangoException (String texto) {
super(texto);
}
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 23/40
Mtodos de Throwable
Cuando una excepcin no se procesa hasta el final, el
programa se interrumpe y se ejecuta printStackTrace()
Throwable(String)
Constructor que asigna un mensaje al
objeto
getMessage()
Devuelve el mensaje del objeto
toString()
Devuelve un string incluyendo la clase del
objeto ms el mensaje
printStackTrace()
Escribe la traza de ejecucin en la slida de
error estndar
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 24/40
Ejemplo excepciones
definidas por el usuario
public class MiExcepcion extends Exception {
int datoInformacion;
public MiExcepcion( int datos ) {
// Guarda la informacin de diagnstico en el objeto
datoInformacion= datos;
}
// Sobreescribeel mtodo de Throwable
public String getMessage() {
return ("La maxima es: Compra Barato, Vende Caro\n" +
"El valor de datoInformacion es: " + datoInformacion);
}
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 25/40
Ejemplo excepciones
definidas por el usuario
public class EjemploExcepcion {
public static void main ( String args[] ) {
try{
for( int cnt = 0; cnt < 5; cnt++ ) {
if( cnt == 3 ) throw new MiExcepcion(3);
// Lanza la excepcin propia si "cnt" es 3
System.out.println("Procesando datos: " + cnt);
}
System.out.println("Esta lnea no se ejecuta nunca.");
}catch( MiExcepcion e ) {
System.out.println("Controlador de Excepciones, recoge el
mensaje: "+ e.getMessage() );
System.out.println(Intentando finalizar la ejecucin.");
return;
}finally {
System.out.println( "Bloque finally, para probar que se entra
en el independientemente de la sentencia return
del Controlador de Excepciones." );
}
System.out.println("Esta sentencia nunca se ejecutara debido al
return del controlador de excepciones" );
} }
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 26/40
Jerarqua de excepciones
// En el fichero TemperatureException.java
public class TemperatureException extends Exception{}
// En el fichero TooColdException.java
public class TooColdException extends
TemperatureException{}
// En el fichero TooHotException.java
public class TooHotException extends
TemperatureException{}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 27/40
Jerarqua de excepciones
TemperatureException
TooHotException TooColdException
Tratamiento genrico
catch (TempException te) {
...
}
Tratamiento especfico
catch (TooHotException the) {
...
}
catch (TooColdException tce)
{
...
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 28/40
Ejemplo
public class VirtualPerson {
private static final int tooCold = 5;
private static final int tooHot = 85;
public void drinkCoffee (CoffeeCup cup) throws
TooColdException, TooHotException {
int temperature= cup.getTemperature();
if (temperature<= tooCold) {
throw new TooColdException();
}
else if (temperature>= tooHot){
throw new TooHotException();
}
//...
}
//...
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 29/40
Ejemplo
public class CoffeeCup {
// 75 es la mejor temperatura para un caf
private int temperature = 75;
public void setTemperature(intval) {
temperature = val;
}
public int getTemperature() {
return temperature;
}
//...
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 30/40
Ejemplo
public class Example {
public static void main(String[] args) {
int temperature= 0;
if (args.length> 0) {
try {
temperature= Integer.parseInt(args[0]);
}catch(NumberFormatException e) {
System.out.println("Must enter an integer.");
System.exit(1);
}
} else {
System.out.println("Must enter temperature.");
System.exit(1);
}
// Crear un caf y establecer su temperatura.
CoffeeCup cup = new CoffeeCup();
cup.setTemperature(temperature);
// Crear y servir cliente
VirtualPerson cust = new VirtualPerson();
VirtualCafe.serveCustomer(cust, cup);
}}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 31/40
Ejemplo
public class VirtualCafe {
public static void serveCustomer(VirtualPerson cust,
CoffeeCup cup) {
try {
cust.drinkCoffee(cup);
System.out.println(El caf est en su punto.");
} catch (TooColdException e) {
System.out.println(Caf muy fro.");
// Aparselas con un cliente enfadado...
} catch (TooHotException e) {
System.out.println(Caf muy caliente.");
// Aparselas con un cliente enfadado...
}
}
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 32/40
Ejemplo
public class VirtualCafe {
public static void serveCustomer(VirtualPerson cust,
CoffeeCup cup) {
try {
cust.drinkCoffee(cup);
System.out.println(El cafesten su punto.");
} catch (TemperatureException e) {
System.out.println(Caf muy fro o caliente.");
// Aparselas con un cliente enfadado...
}
}
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 33/40
Ejemplo
public class VirtualCafe {
public static void serveCustomer(VirtualPerson cust,
CoffeeCup cup) {
try {
cust.drinkCoffee(cup);
System.out.println(El cafesten su punto.");
} catch (TemperatureException e) {
System.out.println(Caf muy fro o caliente.");
// Aparselas con un cliente enfadado...
}
// NO COMPILAR PORQUE ESTE catch NO SE ALCANZA NUNCA
catch(TooColdExceptione) {
System.out.println(Cafmuy fro);
}
} }
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 34/40
Ventajas de las excepciones
Separacin del tratamiento de errores del resto del cdigo
del programa.
Evitar manejos de cdigos de error.
Evitar alteracin del flujo de un programa.
Propagacin de errores a lo largo de la pila de llamadas a
mtodos.
Evitar retornos continuos en caso de error.
Evitar la necesidad de argumentos adicionales.
Agrupamiento y definicin de tipos de errores como clases.
Jerarquas de excepciones.
Tratar errores a diferentes niveles de especifidad.
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 35/40
Ventajas de las excepciones
readFile {
open the file;
determine its size;
allocate that much memory;
read the file into memory;
close the file;
}
Sin tratamiento de
errores
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 36/40
Ventajas de las excepciones
errorCodeType readFile {
initialize errorCode = 0;
open the file;
if (theFileIsOpen) {
determine its size;
if (gotTheFileLenght) {
allocate that much memory;
if (gotEnoughMemory) {
read the file into memory;
if (readFailed) errorCode = -1;
} else errorCode = -2;
} else errorCode = -3;
close the file;
if (theFileDidntClose && errorCode == 0)
errorCode = -4;
else errorCode = errorCode & -4;
} else errorCode = -5;
return errorCode
}
Tratamiento de errores
sin excepciones
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 37/40
Ventajas de las excepciones
readFile {
try {
open the file;
determine its size;
allocate that much memory;
read the file into memory;
close the file;
}
catch (fileOpenFailed) { doSomething; }
catch (sizeDeterminationFailed) { doSomething; }
catch (memoryAllocationFailed) { doSomething; }
catch (readFailed) { doSomething; }
}
Tratamiento de errores
con excepciones
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 38/40
Ventajas de las excepciones
method1 {
call method2;
}
method2 {
call method3;
}
method3 {
call readFile;
}
Sin tratamiento
de errores
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 39/40
Ventajas de las excepciones
method1 {
errorCodeType error;
error = call method2;
if (error) doErrorProcessing;
else proceed;
}
errorCodeType method2 {
errorCodeType error;
error = call method3;
if (error) return error;
else proceed;
}
Tratamiento de errores
sin excepciones
errorCodeType method3 {
errorCodeType error;
error = call
readFile;
if (error) return
error;
else proceed;
}
Prog. Avanzada - ITIG Jos Ramn Jurez Rodrguez 40/40
Ventajas de las excepciones
method1 {
try {
call method2;
}
catch (exception) {
doErrorProcessing;
}
}
method2 throws exception {
call method3;
}
Tratamiento de errores
con excepciones
method3 throws exception {
call readFile;
}
Tema 3: Programacin en
entornos grficos de usuario
Programacin en
GUIs
1.Introduccin
2.Evolucin histrica
3.Caractersticas de la programacin
en GUIs
4.Gestin de eventos
5.El patrn MVC
6.Programacin de GUIs en Java
7.Componentes Swing
8.Primeros pasos en Swing
9.Gestores de de distribucin
10.Diseando nuestro JFrame
11.Captura de eventos
12.Cuadros de dilogo
13.Teclas rpidas
14.Los looks de Swing
Introduccin
Introduccin
Entendemos por Interfaz Grfica de Usuario (GUI) al
software que permite la interaccin entre el usuario y
los servicios que proporciona el sistema operativo,
utilizando para ello una representacin grfica intuitiva
de alto nivel
La informtica moderna no puede entenderse sin el
impacto que supuso la generalizacin de los entornos
grficos de usuario a partir de los 80
Hoy en da, la mayor parte de las aplicaciones
destinadas a usuarios finales se realizan para este tipo
de entornos
Programacin en
GUIs
Introduccin
La mayora de los GUIs de propsito general siguen
la llamada metfora de escritorio, y utilizan un sistema
de ventanas. Para la interaccin con el usuario
disponen de un nmero ms o menos grande de
elementos o widgets: botones, editores, etc.
No vamos a estudiar aqu las caractersticas de las
interfaces de usuario, su diseo o implementacin
(asignatura Interfaz Persona-Ordenador)
Nos centraremos en las caractersticas de la
programacin en este tipo de entornos, el cambio que
supone respecto a la programacin clsica y las
nuevas posibilidades que aporta
Programacin en
GUIs
Evolucin histrica
Evolucin histrica
La aparicin de los GUIs fue posible por la mejora de
las prestaciones de los ordenadores. La escasa
potencia de los ordenadores hasta principios de los 70
haca impensable desperdiciar CPU en la interfaz con
el usuario
Hasta entonces el usuario dispona de una mnima
interfaz en modo texto, bsicamente una lnea donde
se tecleaban los comandos del S.O., en un nivel muy
cercano a la mquina
Programacin en
GUIs
Programacin en
GUIs
Evolucin histrica
Alto (1973). Desarrollado en el Xerox PARC, Alto fue
el primer ordenador que incorporaba ratn y un
sistema operativo con una interfaz grfica de usuario.
Sin embargo su precio era prohibitivo, lo que impidi
su difusin fuera del mbito de universidades y
centros de investigacin
Los orgenes
Star (1981). Xerox desarroll Star con la
intencin de presentar un ordenador personal
para el mbito de la ofimtica. Implementa por
primera vez la metfora de escritorio y generaliza
el uso de iconos y ventanas solapadas. Su
influencia en Apple y el resto de GUIs que
siguieron fue enorme
Programacin en
GUIs
Evolucin histrica
System 1 (1984). Steve Jobs tomo las
ideas desarrolladas en el Xerox PARC para
disear el sistema operativo del nuevo
ordenador que iba a lanzar al mercado su
compaa Apple, el Macintosh. Este
ordenador acerc la informtica al usuario
domstico como nunca antes haba ocurrido
Los entornos operativos de Apple y Next
GS/OS (1988). El System 1
evolucion rpidamente hasta el
GS/OS, que incorporaba explotaba el
soporte de color (200x320x16 colores)
y sonido del Apple IIGS, as como su
mayor potencia. Los ordenadores
Apple se hicieron populares por lo
sencillo e intuitivo que era su uso
Programacin en
GUIs
Evolucin histrica
System 7 (1991). Represent un enorme
salto frente a los sistemas anteriores, al
incluir soporte de red de forma
transparente, direccionamiento de memoria
de 32 bits y memoria virtual, as como
tecnologas como Drag-and-drop, Quicktime
(multimedia) y Truetype (fuentes mejorados)
NextStep (1988). Steve Jobs fue
despedido de Apple y fund una nueva
compaa: Next. Los ordenadores Next y su
sistema operativo NextStep estaban llenos
de innovaciones y buen diseo. Como
curiosidad, el lenguaje de programacin
nativo de NextStep eral el Objetive-C, un
lenguaje OOP
Programacin en
GUIs
Evolucin histrica
X-Window
El sistema X-Window fue desarrollado en el MIT en 1984, apareciendo la
primera versin comercial en 1986. X-Window no era un GUI en s, sino
simplemente un sistema de ventanas con capacidad de funcionar a travs de
la red. Para trabajar con X-Window era necesario un gestor de ventanas, que
era el que proporcionaba el look-and-feel definitivo
TWM. Fue uno de los primeros
gestores de ventanas para X.
Realmente proporcionaba lo mnimo
para trabajar con la mquina
Programacin en
GUIs
Evolucin histrica
Motif. El primer gestor de ventanas
para X-Window que proporcionaba una
buena calidad de presentacin.
Durante aos el toolkit de
programacin Motif ha sido el
predilecto para los programadores en
X-Window
OpenWindows. Ha sido el gestor de
ventanas utilizado por SUN durante
aos. De caractersticas similares a
Motif, con un look muy peculiar. Las
primeras versiones de Linux tambin
utilizaban este gestor de ventanas,
antes de la aparicin de Gnome y KDE
Programacin en
GUIs
Evolucin histrica
KDE. Fue desarrollado para Linux,
con la intencin de competir con
Windows en aspecto, facilidad de uso
y cantidad de aplicaciones. El toolkit
de programacin es Qt de la compaa
Trolltech para C++
Gnome. Es fruto de un proyecto que
surgi con el objetivo de construir un
gestor de ventanas igual o mejor que
KDE pero utilizando un toolkit abierto
desarrollado por la comunidad (GTK).
Sin embargo el resultado no llega al
nivel de KDE. Adems GTK est
basado en C, y no es ni de lejos tan
fcil de usar y potente como Qt
Programacin en
GUIs
Evolucin histrica
Windows 1.0 (1985). Fue un intento
de Microsoft para implantar la filosofa
de los GUIs de Apple en la plataforma
PC. El resultado era realmente
bastante pobre. Su repercusin fue
francamente escasa
Windows 3.1 (1992). El primer GUI de
Microsoft con verdadero xito,
Responsable del gran salto del PC al
modo grfico. Era todava inferior en
prestaciones a los GUIs de Apple,
aunque la distancia se acortaba.
Windows y OS/2
Programacin en
GUIs
Evolucin histrica
OS/2 (1992). El entorno operativo de
IBM, con la intencin de competir con
Windows en el mercado de los PCs.
Era superior a Windows 3.1 y tuvo
cierta popularidad. OS/2 no era un
simple entorno grfico de ventanas, sin
un sistema operativo completo de 32
bits, no basado en MS-DOS
Windows 95 (1995). Represent un
gran salto de calidad frente a
Windows 3.X, y definitivamente lanz
a Microsoft a la supremacia en el
mundo PC.
Caractersticas de la
programacin en GUIs
Caractersticas de la programacin en GUIs
La programacin en un GUI determinado requiere el
uso de un toolkit (o SDK) para ese GUI, en el lenguaje
de programacin que queramos utilizar
Existe siempre un toolkit oficial que proporciona el fabricante del GUI,
normalmente para C o C++. Por ejemplo MFC para programacin en Windows
Tambin existen toolkits alternativos desarrollados por terceros, ya sean
comerciales o gratuitos. Por ejemplo, OWL (C++) de Borland para Windows
Finalmente tambin es posible el uso de un toolkit multiplataforma, como GTK+
(para C), Qt o Fltk (ambos para C++)
La estructura de un GUI es de forma natural orientada
a objetos. El desarrollo con un toolkit orientado a
objetos es mucho ms sencillo y rpido
Programacin en
GUIs
Caractersticas de la
programacin en GUIs
La programacin de aplicaciones para un GUI implica
un cambio radical de filosofa y estructura en los
programas
Un programa tradicional tiene una estructura lineal,
con el cdigo repartido en una serie de funciones u
operaciones. Existe una funcin u operacin principal
donde comienza la ejecucin y a partir de ah se
encadenan las llamadas de unas funciones a otras
hasta que en un punto determinado acaba la ejecucin
Programacin en
GUIs
Programa
Inicio Programa Fin
Caractersticas de la
programacin en GUIs
En cambio la programacin en GUIs es orientada a
eventos. La mayora de los eventos son sucesos
asncronos producidos por la interaccin del usuario
con la aplicacin, y estn ligados a algn elemento de
la interfaz. Algunos ejemplos son:
Pulsar un botn
Cambiar el tamao de una ventana
Mover una barra de desplazamiento
Pulsar una tecla
Tocar alguno de los botones minimizar-maximizar-cerrar de la ventana
Hacer un click de ratn sobre un elemento determinado
Algunos eventos no relacionados directamente con el
usuario son:
Aparicin de una ventana
Tick de un reloj programado con antelacin
Programacin en
GUIs
Caractersticas de la
programacin en GUIs
La mayor parte del cdigo en un programa para un GUI
est en los llamados manejadores de eventos. Cada
manejador se encarga de realizar el conjunto de
acciones asociadas a un evento determinado. Existe un
gestor de eventos (que puede proporcionar el toolkit)
que se encarga de recibir todos los eventos de la
aplicacin y llamar al manejador adecuado
Programacin en
GUIs
Manejador 1
Manejador 2
Manejador 3
Manejador 4
Gestor de
eventos
Inicio Fin
Inicializacin
Caractersticas de la
programacin en GUIs
Los entornos modernos orientados a componentes
como Delphi, C++ Builder, Visual Basic etc. permiten
realizar las dos primeras fases de manera visual en lo
que se conoce como fase de diseo
Programacin en
GUIs
Caractersticas de la
programacin en GUIs
Una vez realizado el diseo, los entornos de desarrollo
eligen una de las siguientes estrategias:
Salvar el diseo y las propiedades en ficheros ocultos especiales que son
compilados junto al cdigo (Delphi, C++ Builder, Visual Basic)
Generar el cdigo correspondiente de la interfaz que el desarrollador completa con
su propio cdigo (NetBeans)
Programacin en
GUIs
Gestin de eventos
Gestin de eventos
Como acabamos de ver, en un programa para un GUI
la tarea fundamental a realizar es gestionar adecuada-
mente los eventos recibidos
La informacin asociada a un evento suele ser como
mnimo un campo indicador del tipo de evento y el
identificador del elemento que genera dicho evento
(botn, ventana, etc.)
Un aspecto fundamental en el diseo de un toolkit es
la forma en que se produce la conexin entre el gestor
de eventos y los manejadores
Programacin en
GUIs
Gestin de eventos
En los toolkits ms bsicos y primitivos, que suelen
ser para el lenguaje C, el programador realiza la
implementacin del gestor de eventos y la llamada
directa a los distintos manejadores
Durante la inicializacin de la aplicacin debe pasarse
al toolkit el nombre de nuestro gestor de eventos
Programacin en
GUIs
int main() {
...
/* Indicar al toolkit la funcin para la gestin de eventos */
gestorEventosGUI(gestorEventos);
...
}
void gestorEventos(Evento e)
{
switch(e.tipo) {
case VENTANA_ABRIR: ventanaAbrir(e); break;
case VENTANA_CERRAR: ventanaCerrar(e); break;
case BOTON_PULSADO: botonPulsado(e); break;
...
}
}
Gestin de eventos
En toolkits ms sofisticados es posible indicar por
cada evento que nos interese una funcin que hace
las veces de manejador (CALLBACK). El gestor de
eventos est integrado en el toolkit
Programacin en
GUIs
En ocasiones tambin es posible indicar un callback
especfico por cada evento y elemento que lo genera
int main() {
...
/* Indicar al toolkit los distintos manejadores */
manejadorEventoGUI(VENTANA_ABRIR, ventanaAbrir);
manejadorEventoGUI(VENTANA_CERRAR, ventanaCerrar);
manejadorEventoGUI(BOTON_PULSADO, botonPulsado);
...
}
int main() {
...
/* Indicar al toolkit los distintos manejadores */
manejadorEventoGUI(VENTANA_ABRIR, ventana1, ventana1Abrir);
manejadorEventoGUI(VENTANA_CERRAR, ventana1, ventana1Cerrar);
manejadorEventoGUI(BOTON_PULSADO, boton1, boton1Pulsado);
...
}
Gestin de eventos
El uso de CALLBACKs suele favorecer el uso de
elementos no muy aconsejables: variables y objetos
globales, punteros a void, etc.
En toolkits con un diseo OO cada elemento es
representado por una clase de objetos, con una o varias
operaciones dedicadas al procesamiento de eventos
Heredando y redefiniendo estas operaciones podemos
realizar la implementacin de los manejadores
Programacin en
GUIs
class MiVentana : public Ventana {
...
void evAbrir()
{
...
}
void evPintar()
{
...
}
...
}
Gestin de eventos
Java utiliza un sistema que combina el esquema de
CALLBACKS con el anterior
Existen una serie de clases especiales (EventListener)
que capturan y procesan cada evento generado por
cada componente
Programacin en
GUIs
// Definicin del event listener
class procesamientoBoton implements ActionListener {
void actionPerformed(ActionEvent e)
{
// Procesar evento de pulsacin de botn
}
}
// Conectar el botn con el listener
boton1.addActionListener(new procesamientoBoton());
Gestin de eventos
Finalmente algunos toolkits com Qt disponen de
mecanismos especficos. Este toolkit incorpora una
extensin a C++ que permite enlazar un evento
producido por un elemento con una operacin de un
objeto determinado
Cada objeto que representa un elemento genera un
conjunto de eventos (SIGNALs) que pueden ser
conectadas con operaciones de otros objetos para
procesar estas seales (SLOTs)
Este mecanismo es extremadamente elegante, simple
y flexible
Programacin en
GUIs
QObject::connect(boton1, SIGNAL(clicked()), ventana1, SLOT(botonPulsado())
Programacin en
GUIs
El patrn MVC
El patrn MVC
A la hora de disear una aplicacin con una interfaz
grfica de usuario es importante el patrn de diseo
MVC (modelo-vista-controlador). En este esquema se
definen tres roles bien diferenciados para cada clase:
Modelo: el modelo est constituido por el conjunto de clases que representan el
problema
Vistas: una vista es una clase (o varias) que proporcionan una posible visualizacin
de la informacin contenida en un modelo
Controlador: el controlador est constituido por una o varias clases encargadas de
coordinar la interaccin entre las vistas y el modelo. Cada vez que un modelo
cambia internamente, actualiza sus vistas
Modelo
(Cuenta)
Vista 1
(GUI)
Vista 2
(Informe)
Controlador
(Aplicacin)
Programacin en
GUIs
El patrn MVC
Este patrn se estudia en detalle en la asignatura
Interfaz Persona-Ordenador
Aunque no se aplique a rajatabla, la idea ms
importante detrs de este patrn es la separacin
siempre entre la representacin de un sistema y la
interfaz de usuario proporcionada para visualizar e
interaccionar con ese sistema
El mezclar en una clase ambos aspectos es una
psima prctica, que dificulta su mantenimiento y
reutilizacin
Programacin en
GUIs
Programacin
de GUIs en Java
Programacin de GUIs en Java
Puesto que Java pretende ser un lenguaje multipla-
taforma, el diseo de su toolkit para programacin de
GUIs se hizo pensando en que las aplicaciones tuvieran
un buen aspecto en cualquier plataforma pero indepen-
diente de cualquier GUI especfico
Este toolkit se denomin AWT 1.0 (Abstract Window
Toolkit)
Programacin en
GUIs
Programacin
de GUIs en Java
Realmente las aplicaciones AWT 1.0 tenan un aspecto
mediocre y un escaso nmero de elementos. Adems su
diseo interno era muy deficiente
La situacin mejor algo con AWT 1.1, pero no fue
hasta Java 1.2 cuando apareci Swing, un toolkit
completamente nuevo, con un diseo interno orientado a
componentes y un look mucho ms satisfactorio
Programacin en
GUIs
Programacin
de GUIs en Java
A pesar de que Swing tiene un estilo visual propio por
defecto, puede tambin utilizar un aspecto Motif,
Windows o Apple. Estos ltimos slo en las
plataformas correspondientes. Adems puede cambiar
de aspecto en tiempo de ejecucin
Aspecto Swing por defecto
Aspecto Motif
Aspecto Windows
Programacin en
GUIs
Componentes de
Swing
Componentes de Swing
Componentes contenedores (sirven para contener y
organizar otros compontes):
JFrame. Representa una ventana bsica, capaz de
contener otros componentes. Casi todas las
aplicaciones construyen al menos un JFrame
JDialog, JOptionPane, etc. Los cuadros de dilogo
son JFrame restringidos, dependientes de un
JFrame principal. Los JOptionPane son cuadros de
dilogo sencillos predefinidos para pedir
confirmacin, realizar advertencias o notificar errores.
Los JDialog son cuadros de dilogo generales,
normalmente utilizados para peticiones de datos
Programacin en
GUIs
Componentes de
Swing
JInternalFrame. Consiste simplemente en una
ventana hija, que no puede salir de los lmites
marcados por la ventana principal. Es muy comn en
aplicaciones que permiten tener varios documentos
abiertos simultneamente
JPanel. Un panel sirve para agrupar y organizar
otros componentes. Puede estar decorado mediante
un borde y una etiqueta
JScrollPane. Es un panel que permite visualizar un
componente de un tamao mayor que el disponible
mediante el uso de barras de desplazamiento
Programacin en
GUIs
Componentes de
Swing
JSplitPane. Permite visualizar dos componentes,
uno a cada lado, con la posibilidad de modificar la
cantidad de espacio otorgado a cada uno
JTabbedPane. Permite definir varias hojas con
pestaas, que pueden contener otros componentes.
El usuario puede seleccionar la hoja que desea ver
mediante las pestaas
JToolBar. Es un contenedor que permite agrupar
otros componentes, normalmente botones con iconos
en una fila o columna. Las barras de herramientas
tienen la particularidad de que el usuario puede
situarlas en distintas configuraciones sobre el frame
principal
Programacin en
GUIs
Componentes de
Swing
Controles bsicos:
JButton, JCheckBox, JRadioButton. Distintos tipos de
botones. Un check box sirve para marcar una opcin. Un
radio button permite seleccionar una opcin entre varias
disponibles
JComboBox. Las combo boxes o listas desplegables que
permiten seleccionar un opcin entre varias posibles
JTextField, JFormattedTextField, JPasswordField.
Distintos tipos de editores. JFormattedTextField permite
indicar el conjunto de caracteres legales que pueden
introducirse. JPasswordField no muestra el contenido
JList. Listas que permiten seleccionar uno o ms
elementos
JSlider. Un slider permiten introducir un valor
numrico entre un mximo y un mnimo de manera
rpida
Programacin en
GUIs
Componentes de
Swing
JSpinner. Permiten seleccionar un valor entre un rango de
opciones posibles, al igual que las listas desplegables,
aunque no muestran tal lista. Los valores cambian al pulsar
los botones de desplazamiento. Tambin se puede introducir
un valor directamente
Mens desplegables. Existen dos tipos de mens:
JMenuBar, que consiste en una barra de mens
desplegables en la parte superior de la aplicacin, y
JPopupMenu, un men que se obtiene al pulsar con el botn
derecho del ratn sobre una zona determinada. Los mens
estn compuestos por distintos items: JSeparator (una lnea
de separacin entre opciones), JMenuItem (una opcin
ordinaria), JMenu (un submenu), JCheckboxMenuItem (un
opcin en forma de check box) o finalmente
JRadioButtonMenuItem (una opcin en forma de radio
button
Programacin en
GUIs
Componentes de
Swing
Controles especializados:
JColorChooser. Consiste en un selector de colores
JFileChooser. Permite abrir un cuadro de dilogo para pedir
un nombre de fichero
JTable. Permite visualizar una tabla de informacin, con
capacidad para permitir la edicin por parte del usuario. La
tabla puede incluir texto, imgenes y algunos controles
bsicos como check buttons y combo boxes
JTree. Su funcin es mostrar informacin de tipo jerrquico
Programacin en
GUIs
Componentes de
Swing
Controles no interactivos (muestran algn tipo de
informacin pero no interaccionan con el usuario):
JLabel. Permite situar un texto, un texto con una imagen o
una imagen nicamente en la ventana. No son iteractivos y
puede utilizarse cdigo HTML para escribir texto en varias
lneas y con varios atributos
JProgressBar. Permite mostrar que porcentaje del total de
una tarea a realizar ha sido completado
JToolTip. Consiste en una etiqueta de ayuda que surge al
cabo de uno segundos sobre la posicin apuntada por el
cursor. Normalmente no es necesario utilizar directamente la
clase JToolTip, se puede establecer para cualquier
componente de la ventana mediante: e.setToolTipText(sta
es la etiqueta)
Programacin en
GUIs
Primeros pasos
en Swing
Primeros pasos en Swing
Casi siempre, el primer paso a la hora de construir una
aplicacin es crear un JFrame inicial
Por defecto un JFrame se crea de forma invisible, as
que que es necesario activar su visualizacin mediante
la operacin setVisible()
import javax.swing.JFrame;
public class AppHolaMundo {
public static void main(String[] args) {
JFrame f = new JFrame("Prueba");

f.setVisible(true);
}
}
Programacin en
GUIs
Primeros pasos
en Swing
Sin embargo, al cerrar este frame la aplicacin no
termina, se queda colgada. Esto ocurre porque es
necesario asociar la accin de cerrar el JFrame con la
finalizacin de la aplicacin
Podemos realizar esta asociacin mediante la
operacin setDefaultCloseOperation()
import javax.swing.*;
public class AppHolaMundo {
public static void main(String[] args) {
JFrame f = new JFrame("Prueba");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
Programacin en
GUIs
Primeros pasos
en Swing
Vamos a crear un JLabel con el texto Hola mundo y lo vamos a aadir al
JFrame. Con esto ya tenemos un Hola mundo en Swing
import javax.swing.JFrame;
public class AppHolaMundo {
public static void main(String[] args) {
JFrame f = new Jframe("Prueba");
// Equivalente a f.getContentPane().add(new JLabel...)
f.add(new Jlabel (Hola mundo));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
Los componentes se aaden al panel de contenidos del
JFrame, accesible mediante getContentPane().add()
El JFrame dispone de una operacin add() que ya hace
esto directamente
Programacin en
GUIs
Gestores de
distribucin
Gestores de distribucin
Una de las tareas ms tediosas a la hora de disear un
frame con varios elementos en el interior es posicionar y
establecer el tamao de cada uno de estos elementos.
Dos alternativas:
Posicionar cada uno los elementos indicando posiciones y tamaos. Es tedioso si
no se realiza de forma interactiva. Adems al cambiar el tamao del frame los
elementos pueden desajustarse
Utilizar un gestor de distribucin que se encarga de distribuir los componentes de
forma automtica. Puede ser complicado obtener la distribucin que realmente
deseamos
Programacin en
GUIs
Gestores de
distribucin
En la programacin con Swing se recomienda el uso de
un gestor de distribucin (LayoutManager) para la
distribucin de los componentes en frames y cuadros de
dilogo
Podemos establecer el gestor de distribucin para los
elementos situados en un panel mediante
panel.setLayout(<gestor de distribucin>)
Podemos anular la distribucin automtica mediante
panel.setLayout(null) e indicar coordenadas absolutas
Para establecer el tamao del frame que contiene los
componentes tenemos igualmente dos opciones:
Utilizar frame.pack() para que ajuste su tamao al de los componentes de su
interior. Esta es la opcin ms recomendable
Establecer su tamao indicando ancho y alto mediante frame.setSize()
Programacin en
GUIs
Gestores de
distribucin
Vamos a disear una interfaz para el ejemplo de la cuentas bancarias del tema 2.
Empezaremos aadiendo etiquetas (JLabel) y editores (JTextField) para poder
visualizar la informacin de la cuenta
public class AppBanco {
public static void main(String[] args) {
JFrame f = new JFrame("Gestin de Cuentas");
f.add(new JLabel ("Cdigo"));
f.add(new JTextField (8));
f.add(new JLabel ("Titular"));
f.add(new JTextField (30));
f.add(new JLabel ("Saldo"));
f.add(new JTextField (8));
f.add(new JLabel ("Inters"));
f.add(new JTextField (4));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);
}
}
El resultado no es correcto por dos razones. En primer lugar Swing utiliza por
defecto el gestor de distribucin BorderLayout que no es vlido para nuestro
ejemplo. Adems la ventana no tiene el tamao adecuado para visualizar los
componentes
Programacin en
GUIs
Gestores de
distribucin
El gestor de distribucin BorderLayout permite un
componente pegado a uno de los bordes del panel o en
el centro del mismo. Por defecto los componentes se
situan junto al borde izquierdo
public class AppBanco {
public static void main(String[] args) {
JFrame f = new JFrame("Gestin de Cuentas");
f.add(new JLabel("Este"), BorderLayout.WEST);
f.add(new JLabel("Centro"), BorderLayout.CENTER);
f.add(new JLabel("Oeste"), BorderLayout.EAST);
f.pack(); // Ajustar Frame a los contenidos
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);
}
}
Programacin en
GUIs
Gestores de
distribucin
El gestor de distribucin BoxLayout organiza los
componentes horizontal o verticalmente, ajustando los
componentes al espacio disponible
public class AppBanco {
public static void main(String[] args) {
JFrame f = new JFrame("Gestin de Cuentas");
f.setLayout(
new BoxLayout(f.getContentPane(), BoxLayout.X_AXIS));
f.add(new JLabel("Cdigo"));
f.add(new JTextField(8));
f.add(new JLabel("Titular"));
f.add(new JTextField(30));
f.add(new JLabel("Saldo"));
f.add(new JTextField(8));
f.add(new JLabel("Inters"));
f.add(new JTextField(4));
f.pack(); // Ajustar JFrame a los contenidos
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);
}
}
Programacin en
GUIs
Gestores de
distribucin
Utilizando el parmetro X_AXIS o Y_AXIS conseguimos
una distribucin horizontal o vrtical
El gestor de distribucin FlowLayout es similar al
BoxLayout horizontal pero los componentes mantienen
sus dimensiones
Programacin en
GUIs
Gestores de
distribucin
El gestor de distribucin GridLayout organiza los
componentes en una rejilla de celdas del mismo tamao
public class AppBanco {
public static void main(String[] args) {
JFrame f = new JFrame("Gestin de Cuentas");
f.setLayout(new GridLayout(4,2));
f.add(new JLabel("Cdigo"));
f.add(new JTextField(8));
f.add(new JLabel("Titular"));
f.add(new JTextField(30));
f.add(new JLabel("Saldo"));
f.add(new JTextField(8));
f.add(new JLabel("Inters"));
f.add(new JTextField(4));
f.pack(); // Ajustar Frame a los contenidos
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);
}
}
Programacin en
GUIs
Gestores de
distribucin
El gestor de distribucin GridBagLayout es un
organizador basado tambin en rejilla aunque ms
flexible, con capacidad para que los componentes
ocupen varias celdas de distinto tamao si es necesario
El gestor SpringLayout se basa en la especificacin de
distancias entre los bordes de los distintos
componentes. Est pensado para el uso de un editor
grfico interactivo
Tambin, aunque est desaconsejado, podemos anular
el gestor de distribucin y e indicar directamente
posiciones y tamaos para los componentes
Programacin en
GUIs
Gestores de
distribucin
public class AppBanco {
public static void main(String[] args) {
JFrame f = new JFrame("Gestin de Cuentas");
JLabel lc, lt;
JTextField tfc, tft;

f.setLayout(null);
f.add(lc = new JLabel("Cdigo"));
f.add(tfc = new JTextField(8));
lc.setBounds(10, 10, 50, 20);
tfc.setBounds(70, 10, 50, 20);

f.add(lt = new JLabel("Titular"));
f.add(tft = new JTextField(30));
lt.setLocation(10, 40); lt.setSize(50, 20);
tft.setLocation(70, 40); tft.setSize(120, 20);

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setSize(320, 200);
f.setVisible(true);
}
}
sta sera la forma de organizar la ventana principal de nuestro ejemplo de
manera manual
Programacin en
GUIs
Gestores de
distribucin
La organizacin manual o mediante un gestor de
distribucin complejo nicamente resulta prctica
mediante un editor grfico
Programacin en
GUIs
Gestores de
distribucin
A efectos prcticos se usan la mayora de las veces
FlowLayout y BoxLayout, utilizando paneles internos
para agrupar ciertos componentes
Vamos a utilizar tres JPanel para agrupar los componentes en tres grupos
organizados mediante FlowLayout. A su vez estos tres paneles van a ser
controlados por un BoxLayout
Cdigo
Titular
Saldo Inters
JPanel pc (FlowLayout)
JPanel pt (FlowLayout)
JPanel psi (FlowLayout)
(BoxLayout Y_AXIS)
Programacin en
GUIs
Gestores de
distribucin
public class AppBanco {
public static void main(String[] args) {
JFrame f = new JFrame("Gestin de Cuentas");
JPanel pc = new JPanel();
pc.setLayout(new FlowLayout(FlowLayout.LEFT));
pc.add(new JLabel("Cdigo"));
pc.add(new JTextField(8));
JPanel pt = new JPanel();
pt.setLayout(new FlowLayout(FlowLayout.LEFT));
pt.add(new JLabel("Titular"));
pt.add(new JTextField(30));

JPanel psi = new JPanel();
psi.setLayout (new FlowLayout(FlowLayout.LEFT));
psi.add (new JLabel("Saldo"));
psi.add (new JTextField(8));
psi.add (new JLabel("Inters"));
psi.add (new JTextField(4));
f.setLayout (
new BoxLayout(f, BoxLayout.Y_AXIS));
f.add(pc);
f.add(pt);
f.add(psi);
f.pack(); // Ajustar Frame a los contenidos
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);
}
}
Programacin en
GUIs
Diseando nuestro
JFrame
Diseando nuestro JFrame
Cuando un JFrame tiene cierta complejidad, lo ms
correcto y elegante es extender esta clase aadiendo
todas las caractersticas que necesitemos
El constructor puede utilizarse para la creacin de
componentes, gestores de distribucin,etc.
Los componentes pueden conectarse a referencias que
sean atributos para tener acceso a ellos en mltiples
operaciones de la clase
El enfoque utilizado hasta ahora en nuestra aplicacin es vlido nicamente para
aplicaciones muy simples. Vamos a definir una nueva clase FAppCuenta a partir
de JFrame
public class AppBanco {
public static void main(String[] args) {
FAppBanco f = new FAppBanco();
}
}
Programacin en
GUIs
Diseando nuestro
JFrame
import java.awt.*;
import javax.swing.*;
public class FAppBanco extends JFrame {
JTextField tfc, tft, tfs, tfi;

public FAppBanco() {
super("Gestin de Cuentas Bancarias");
JPanel pc = new JPanel();
pc.setLayout(new FlowLayout(FlowLayout.LEFT));
pc.add(new JLabel("Cdigo"));
pc.add(tfc = new JTextField(8));
JPanel pt = new JPanel();
pt.setLayout(new FlowLayout(FlowLayout.LEFT));
pt.add(new JLabel("Titular"));
pt.add(tft = new JTextField(30));

JPanel psi = new JPanel();
psi.setLayout (new FlowLayout(FlowLayout.LEFT));
psi.add(new JLabel("Saldo"));
psi.add(tfs = new JTextField (8));
tfs.setEditable(false); // Establecermos a slo lectura el saldo
psi.add(new JLabel("Inters"));
psi.add(tfi = new JTextField(4));
setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
add(pc);
add(pt);
add(psi);
pack();

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}

Programacin en
GUIs
Diseando nuestro
JFrame
Usaremos este esquema con las clases JFrame,
JInternalFrame o JDialog, cuando contengan un nmero
relevante de componentes con una gestin ms o
menos compleja, incluyendo captura y procesamiento de
eventos
En estos casos la nueva clase definida, adems de ser
en s un componente de nuestra interfaz, tiene una
segunda funcin muy importante de coordinacin,
gestin y procesamiento de la informacin que llega a
travs de sus componentes hijos
El enfoque utilizado hasta ahora en nuestra aplicacin es vlido nicamente para
aplicaciones muy simples. Vamos a definir una nueva clase FAppCuenta a partir
de JFrame
Programacin en
GUIs
Diseando nuestro
JFrame
Siguiendo con nuestro ejemplo, vamos a aadir una tabla para guardar los
movimientos realizados en la cuenta
Lo primero que hay que hacer es crear una clase especial que va a suministrar la
informacin a la tabla. Para ello podemos implementar la interfaz TableModel o
extender la clase AbstractTableModel, que tiene ya implementaciones por defecto
muchas de sus operaciones
Implementaremos esta clase como interior de FAppBanco
class InfoMovimientos extends AbstractTableModel {
private final String[] nombreCols = { "Fecha", "Tipo", "Importe", "Saldo" };

// Devolver el ttulo de la columna indicada
public String getColumnName(int column) {
return nombreCols[column];
}
// Devolver el nmero de columnas de la tabla
public int getColumnCount() {
return 4;
}
// Devolver nmero de filas de la tabla
public int getRowCount() {
return 0; // De momento, ninguna
}
// Devolver valor en la posicin (rowIndex, columnIndex) de la tabla
public Object getValueAt(int rowIndex, int columnIndex) {
return ""; // De momento, nada
}
}
Programacin en
GUIs
Diseando nuestro
JFrame
Normalmente la tabla debe ser insertada en un JScrollPane, ya que en caso
contrario, al aadir muchas filas ira alargando la ventana paulatinamente hasta
salir incluso de la pantalla
Tambin vamos a aadir en la parte inferior cuatro botones para crear una
cuenta, buscar una cuenta ya existente, realizar una operacin y salir de la
aplicacin
class FAppBanco extends JFrame {
JTextField tfc, tft, tfs, tfi;
JButton bc, bb, bo, bs; // Nuevos atributos
InfoMovimientos im;
JTable tm;
// Resto de la clase a partir de aqu...
// Estamos en el constructor de FAppBanco...
JPanel pm = new JPanel(); // Crear panel de la tabla
pm.setLayout(new BorderLayout());

JLabel lm = new JLabel("Movimientos");
lm.setHorizontalAlignment(JLabel.CENTER);
pm.add(lm, BorderLayout.NORTH);
// Crear la tabla pasando un objeto de la clase InfoMovimientos
tm = new JTable(im = new InfoMovimientos());
JScrollPane sp = new JScrollPane(tm);
sp.setPreferredSize(400, 100);
pm.add(sp, BorderLayout.CENTER);

Programacin en
GUIs
Diseando nuestro
JFrame
// Crear panel de botones
JPanel pb = new JPanel(new FlowLayout(FlowLayout.CENTER));
pb.add(bc = new JButton("Crear"));
pb.add(bb = new JButton("Buscar"));
pb.add(bo = new JButton(Operar));
bo.setEnabled(false); // En principio el botn de operar est deshabilitado
pb.add(bc = new JButton(Salir));
setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
add(pc);
add(pt);
add(psi);
add(pm); // Aadir el panel de la tabla
add(pb); // Aadir el panel de los botones
pack();

setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setVisible (true);
} // Final del constructor de FAppBanco
Programacin en
GUIs
Captura de eventos
Captura de eventos
Como vimos al principio del tema, para la captura de
eventos Swing usa un esquema a similar a los callbacks
pero utilizando clases en lugar de funciones
Cada clase de captura de eventos (denominados event
listeners) debe implementar una interfaz concreta en
funcin del tipo de eventos que desea capturar
Una vez implementado el listener, bastar con indicar
ste al componente del cual deseamos capturar los
eventos
Programacin en
GUIs
Captura de eventos
Existen ciertos event listeners que son comunes a
todos los componentes:
FocusListener: captura eventos relacionados con la recepcin o prdida del foco
KeyListener: captura pulsaciones de teclado sobre el componente activo
MouseListener: captura la entrada o salida del cursor sobre un componente, as
como pulsaciones de los botones
MouseMotionListener: captura movimientos del ratn sobre el componente
Otros son especficos de algunos componentes:
ActionListener: captura cierto tipo de accin realizada sobre ciertos componente.
Por ejemplo, pulsar un botn, seleccionar un elemento en una lista desplegable o
una opcin en un men
ChangeListener: registra los cambios sobre ciertos componente. Por ejemplo un
cambio en el dato de un spinner, o un nuevo valor seleccionado en un slider
ItemListener: recoge el cambio de estado en un componente tipo on/off: check
boxes, radio buttons y listas desplegables
ListSelectionListener: es un listener especfico para detectar las selecciones
mltiples realizadas en listas y tablas
WindowListener: permite recoger los eventos relacionados con las ventanas (cerrar,
minimizar, maximizar, iconizar, etc.) en los frames, frames internos y cuadros de
dilogo
Programacin en
GUIs
Captura de eventos
Si la interfaz captura un nico tipo de evento, como
ActionListener, normalmente tendr una nica operacin
a implementar
void actionPerformed (ActionEvent e)
En cambio los listeners ms complejos como
FocusListener requieren la implementacin de varias
operaciones, cada una para un tipo de evento concreto
void focusGained (FocusEvent e)
void focusLost (FocusEvent e)
Cuidado: un listener puede tener un significado distinto
dependiendo del componente (e.j. ActionListener)
Informacin detallada de cada listener: apartado
Listeners supported by Swing Components del Tutorial
Java de Sun
Programacin en
GUIs
Captura de eventos
Para las interfaces con ms de una operacin Swing
proporciona por comodidad una clase adaptadora que
implementa la interfaz mediante operaciones vacas
Cuando slo necesitamos implementar una operacin
de la interfaz, extender la clase adaptadora es ms
cmodo
La clase adaptadora correspondiente se obtiene
sustituyendo Listener por Adapter
Ejemplo: WindowListener -> WindowAdapter
Programacin en
GUIs
Captura de eventos
Hay dos formas bsicas de implementar un listener:
Hacer que el JFrame que genera o contiene el componente generador del evento
sea un listener, haciendo que implemente la interfaz correspondiente (lo ms simple
y eficiente)
Implementar una pequea clase interior que haga de listener (lo ms flexible)
Una vez implementado el listener, indicaremos al
componente que lo utilice para notificar sus eventos
mediante componente.add????Listener(objetoListener)
donde ???? ser el identificador del tipo de listener
Vamos a capturar el evento de pulsacin del botn Crear y a realizar su
implementacin. En primer lugar declararemos la implementacin de
ActionListener por parte de la clase FAppBanco. Tambin incluiremos un atributo
para la cuenta actual
import java.awt.event.*; // Incluir las clases de eventos
class FAppBanco extends JFrame implements ActionListener {
Cuenta c;
// Continua la implementacin de la clase FAppBanco...
Programacin en
GUIs
Captura de eventos
A continuacin, implementaremos la nica operacin de esta interfaz y algunas
operaciones auxiliares
public void actionPerformed(ActionEvent e) {
long codigo = comprobarCodigo();
if (codigo == -1) return;

float interes = comprobarInteres();
if (interes == -1) return;

salvarCuentaActual(); // Si existe una cuenta en memoria, salvarla

if (existeCuenta(codigo)) {
System.out.println(La cuenta ya existe !);
return;
}

c = new Cuenta(codigo, tft.getText(), interes); // Crear cuenta
tfs.setText("0.0"); // Por defecto el saldo a 0 inicialmente
bo.setEnabled(true); // Activar botn de operaciones
}
Programacin en
GUIs
Captura de eventos
private long comprobarCodigo() {
long codigo;

try {
codigo = Long.parseLong(tfc.getText ());
if (codigo < 0)
throw new NumberFormatException();
}
catch(NumberFormatException nfe) {
System.out.println("Error en cdigo de cuenta");
return -1;
}
return codigo;
}
private float comprobarInteres() {
float interes;
try {
interes = Float.parseFloat(tfi.getText ());
if (interes < 0 || interes > 100)
throw new NumberFormatException();
}
catch(NumberFormatException nfe) {
System.out.println("Error en el formato del inters");
return -1;
}
return interes;
}
public void salvarCuentaActual() {
if (c == null) return;

try {
c.salvar();
}
catch (IOException e) {
System.out.println("Error al salvar cuenta");
}
}
Programacin en
GUIs
Captura de eventos
Finalmente indicaremos al botn Crear que envie los eventos al listener
// Estamos en el constructor de FAppBanco...
JPanel pb = new JPanel (new FlowLayout (FlowLayout.CENTER));
pb.add (bc = new JButton ("Crear"));
bc.addActionListener (this);
pb.add (bb = new JButton ("Buscar"));
pb.add (bo = new JButton ("Operacin"));
bo.setEnabled (false);
pb.add (bs = new JButton ("Salir"));
// Continua el constructor...
La implementacin mediante una clase interior sera la siguiente:
class FAppBanco extends JFrame {
Cuenta c;
JTextField tfc, tft, tfs, tfi;
JButton bc, bb, bo, bs; // Nuevos atributos
InfoMovimientos im;
JTable tm;
public class BotonCrearActionListener implements ActionListener {
public void actionPerformed (ActionEvent e) {
crearCuenta ();
}
}
// Continua la clase FAppBanco a partir de aqu...
Programacin en
GUIs
Captura de eventos
La operacin crearCuenta () de FAppBanco incluira el cdigo de la creacin de
la cuenta (el mismo que la antigua funcin actionPerformed() de FAppBanco)
Finalmente conectaramos el botn con el listener, creando un objeto de la clase
BotonCrearActionListener
// Estamos en el constructor de FAppBanco...
JPanel pb = new JPanel (new FlowLayout (FlowLayout.CENTER));
pb.add (bc = new JButton ("Crear"));
bc.addActionListener (new BotonCrearActionListener ());
pb.add (bb = new JButton ("Buscar"));
pb.add (bo = new JButton ("Operacin"));
bo.setEnabled (false);
pb.add (bs = new JButton ("Salir"));
// Continua el contructor...
No obstante, en nuestro ejemplo continuaremos siguiendo el primer mtodo
Programacin en
GUIs
Captura de eventos
Un componente puede ser conectado a varios listeners
del mismo o distintos eventos. De la misma forma, un
listener puede ser conectado a varios componentes al
mismo tiempo
En estos casos para determinar dentro del listener cul
es el componente que ha enviado el evento podemos
utilizar la operacin getSource() del evento recibido
Esta situacin es muy frecuente cuando la clase
principal hace de listener de los subcomponentes
Vamos a incluir en la operacion actionPerformed() de FAppBanco el cdigo de
procesamiento de los botones Crear, Buscar y Salir
Programacin en
GUIs
Captura de eventos
public void actionPerformed (ActionEvent e) {
if (e.getSource () == bc) { // Botn Crear
long codigo = comprobarCodigo ();
if (codigo == -1) return;

float interes = comprobarInteres ();
if (interes == -1) return;

salvarCuentaActual ();

if (existeCuenta (codigo)) {
System.out.println ("Ya existe una cuenta con ese cdigo");
return;
}

c = new Cuenta (codigo, tft.getText (), interes);
tfs.setText ("0.0");
bo.setEnabled (true);
}

if (e.getSource () == bb) { // Botn Buscar
long codigo = comprobarCodigo ();
if (codigo == -1) return;

try {
c = new Cuenta (codigo); // Cargar la cuenta
// Establecer los valores de la cuenta en los editores
tfc.setText (new Long (codigo).toString ());
tft.setText (c.leerTitular ());
tfs.setText (new Float (c.leerSaldo ()).toString ());
tfi.setText (new Float (c.leerInteres ()).toString ());
im.fireTableDataChanged (); // Actualizar tabla
bo.setEnabled (true);
}
catch (IOException ioe) {
System.out.println ("La cuenta no existe");
}
catch (ClassNotFoundException cnfe){}
}
Programacin en
GUIs
Captura de eventos

if (e.getSource () == bs)
terminarAplicacion ();
}
private void terminarAplicacion () {
salvarCuentaActual (); // Salvar cuenta actual antes de salir
System.exit (0);
}
Vamos a incluir en la operacion actionPerformed() de FAppBanco el cdigo de
procesamiento de los botones Crear, Buscar y Salir

class InfoMovimientos extends AbstractTableModel {
private final String[] nombreCols = { "Fecha", "Tipo", "Importe", "Saldo" };
SimpleDateFormat sdf;

public InfoMovimientos () {
super ();

// Crear un formateador de fechas
sdf = new SimpleDateFormat ("dd.MM.yyyy HH:mm");
}

public String getColumnName (int column) {
return nombreCols[column];
}

public int getColumnCount() {
return 4;
}
Programacin en
GUIs
Captura de eventos
// Devolver nmero de elementos
public int getRowCount() {
if (c != null)
return c.numMovimientosHistorico ();
else
return 0;
}

// Devolver el campo nmero columnIndex del elemento nmero rowIndex
public Object getValueAt(int rowIndex, int columnIndex) {
Movimiento m = c.leerMovimientoHistorico (rowIndex);
switch (columnIndex) {
case 0: return sdf.format (m.fecha);
case 1: switch (m.tipo) {
case 'I': return "ingreso";
case 'R': return "reintegro";
}
case 2: return new Float (m.importe);
case 3: return new Float (m.saldo);
}
return ""; // Aqu no se debera llegar !
}
}
Esta clase usa dos operaciones de la clase Cuenta no existentes en la versin inicial
que vimos en el tema 2: int numMovimientosHistorico() y Movimiento
leerMovimientoHistorico(int nm)
Programacin en
GUIs
Captura de eventos
Queda un fleco pendiente. Si terminamos la aplicacin mediante el botn Salir la
cuenta actual queda salvada en disco automticamente antes de salir. Sin embargo, si
utilizamos el botn de cerrar la ventana la aplicacin se cierra directamente sin salvar la
cuenta
Para evitar esto vamos a capturar los eventos relacionados con la ventana mediante
un WindowListener. En lugar de implementar toda la inferfaz, extendemos la clase
WindowAdapter y redefinimos nicamente la operacin que captura el evento de cierre
de la ventana. Esto nos va a obligar a utilizar una clase interior (por qu?)
// Estamos en el interior de la clase FAppBanco
class FAppBancoWindowListener extends WindowAdapter {
public void windowClosing(WindowEvent e) {
terminarAplicacion();
}
}
// Estamos en el interior del constructor de la clase FAppBanco
// Anulamos esta instruccin
// setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
// Y la sustituimos por una conexin al listener
addWindowListener(new FAppBancoWindowListener());
Programacin en
GUIs
Captura de eventos
Con esto nuestra aplicacin ya es utilizable. Podemos cargar una cuenta existente en
disco o crear una nueva
Programacin en
GUIs
Cuadros de dilogo
Cuadros de dilogo
Los cuadros de dilogo son ventanas con una funcin
especfica
Notificar al usuario un error, advertencia o consejo
Pedir confirmacin sobre una operacin determinada que se va a realizar
Obtener la informacin necesaria para la realizacin de una operacin determinada
Una capacidad especial de los cuadros de dilogo es la
de bloquear la aplicacin de forma que el usuario no
pueda seguir trabajando hasta que se atiende a su
peticin. Este tipo de cuadros de dilogo se denominan
modales
El uso ms frecuente de los cuadros de dilogo es el de
notificacin y confirmacin. Para este fin Swing cuenta
con cuadros de dilogo predefinidos
Programacin en
GUIs
Cuadros de dilogo
Para realizar una notificacin utilizaremos la siguiente
operacin: JOptionPane.showDialog(<frame o dilogo
padre>, <mensaje>, <ttulo>, <tipo>)
El tipo de mensaje puede ser de los siguientes tipos:
ERROR_MESSAGE
INFORMATION_MESSAGE
WARNING_MESSAGE
QUESTION_MESSAGE
PLAIN_MESSAGE
Esto crea lo que se conoce como message box o
cuadro de mensaje modal, con un icono en funcin del
tipo
Programacin en
GUIs
Cuadros de dilogo
Para pedir una confirmacin utilizaremos la siguiente
operacin: JOptionPane.showConfirmDialog(<frame o
dilogo padre>, <mensaje>, <ttulo>, <opciones>,
<tipo>)
Los parmetros son similares. El campo de opciones
puede tomar los valores
YES_NO_OPTION
YES_NO_CANCEL_OPTION
El valor retornado por esta operacin es un entero que
indica el botn pulsado:
YES_OPTION
NO_OPTION
CANCEL_OPTION
CLOSED_OPTION
Programacin en
GUIs
Cuadros de dilogo
Hasta ahora en nuestra aplicacin los mensajes de error se lanzaban a la consola. Es
hora de cambiar todos estos mensajes por cuadros de dilogo. Tambin vamos a
introducir un cuadro de confirmacin cuando se intenta crear una cuenta ya existente
public void actionPerformed(ActionEvent e) {
if (e.getSource() == bc) {
long codigo = comprobarCodigo();
if (codigo == -1)
return;

float interes = comprobarInteres();
if (interes == -1)
return;

salvarCuentaActual();

if (existeCuenta(codigo))
if (JOptionPane.showConfirmDialog(this,
"Ya existe una cuenta con ese cdigo. Desea sobreescribirla?",
"Atencin", JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE) != JOptionPane.YES_OPTION)
return;

c = new Cuenta(codigo, tft.getText (), interes);
tfs.setText("0.0");
bo.setEnabled(true);
}

// Sigue la implementacin del resto de la operacion...

Programacin en
GUIs
Cuadros de dilogo
private long comprobarCodigo() {
long codigo;

try {
codigo = Long.parseLong(tfc.getText ());
if (codigo < 0)
throw new NumberFormatException();
}
catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(this, "Cdigo de cuenta incorrecto",
"Error", JOptionPane.ERROR_MESSAGE);
return -1;
}
return codigo;
}
private float comprobarInteres() {
float interes;
try {
interes = Float.parseFloat(tfi.getText ());
if (interes < 0 || interes > 100)
throw new NumberFormatException();
}
catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(this,
"Inters incorrecto. Debe ser un valor real entre 0 y 100",
"Error", JOptionPane.ERROR_MESSAGE);
return -1;
}
return interes;
}

Programacin en
GUIs
Cuadros de dilogo
La forma ms comn de realizar una peticin de
informacin por parte del usuario es construir un cuadro
de dilogo a medida, normalmente de tipo modal
La clase que representa un cuadro de dilogo genrico
es JDialog. Al igual que en el caso de los frames,
dependiendo de la complejidad del cuadro que
necesitemos podremos construirlo directamente o
utilizar extensin para construir un cuadro de dilogo
personalizado
El constructor de JDialog es el siguiente:
JDialog(<frame o dialogo padre>, <ttulo>, <modal?>)
Programacin en
GUIs
Cuadros de dilogo
Cuando el usuario pulse el botn Operacin vamos a presentar un cuadro de dilogo
que pida el importe y el tipo de operacin a realizar. Vamos a construir este cuadro de
dilogo como una clase nueva hija de JDialog denominada DOperacion
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DOperacion extends JDialog implements ActionListener {
JTextField tfi;
JRadioButton rbi, rbr;
JButton br, bc;
// Importe de la operacin
float importe;
// Este atributo tendr valor true si los datos introducidos son correctos
// y el usuario pulsa el botn Realizar
boolean operar;

public DOperacion(JFrame f) {
super (f, "Realizar operacin", true);

JPanel p = new JPanel();
p.setLayout (new FlowLayout());
JLabel l = new JLabel("Importe");
p.add(l);

tfi = new JTextField(8);
p.add (tfi);

JPanel pto = new JPanel();
pto.setLayout (new FlowLayout());
Programacin en
GUIs
Cuadros de dilogo
Para que los radio buttons de ingreso y reintegro sean autoexcluyentes deben ser
agrupados utilizando un ButtonGroup

rbi = new JRadioButton("Ingreso", true);
rbr = new JRadioButton("Reintegro");
ButtonGroup bg = new ButtonGroup();
bg.add(rbi); // Aadir los dos botones al grupo
bg.add(rbr);

pto.add(rbi);
pto.add(rbr);

JPanel pb = new JPanel();
pb.add(br = new JButton("Realizar"));
pb.add(bc = new JButton("Cancelar"));

setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
add(p);
add(pto);
add(pb);
pack();

// Capturar la pulsacin de los dos botones
bc.addActionListener(this);
br.addActionListener(this);

operar = false;
importe = 0;
}

Programacin en
GUIs
Cuadros de dilogo
Capturamos la pulsacin de los dos botones. Al pulsar Realizar comprobaremos si el
importe es correcto y en caso afirmativo daremos el visto bueno estableciendo el
atributo operar a true
Para poder obtener toda la informacin desde el frame principal hemos introducido
algunas operaciones adicionales
public void actionPerformed(ActionEvent e) {
if (e.getSource () == br) {
try {
importe = Float.parseFloat (tfi.getText ());
operar = true;
hide ();
}
catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog (getContentPane (), "Importe incorrecto",
"Error", JOptionPane.ERROR_MESSAGE);
}
}

if (e.getSource () == bc)
hide ();
}

public float leerImporte () { return importe; }
public boolean esIngreso () { return rbi.isSelected (); }
public boolean esReintegro () { return rbr.isSelected (); }
public boolean realizarOperacion () { return operar; }
}

Programacin en
GUIs
Cuadros de dilogo
Slo falta lanzar el cuadro de dilogo cuando se pulse el botn de Operacin. Para
ello introduciremos el siguiente cdigo en la operacin actionPerformed() de FAppBanco
// Estamos en actionPerformed de la clase FAppBanco
if (e.getSource() == bo) {
DOperacion d = new DOperacion(this); // Construir dilogo y mostrarlo
d.setVisible(true);
// Se ha pulsado el botn de realizar operacin?
if (d.realizarOperacion()) {
if (d.esIngreso())
c.ingreso(d.leerImporte());
else
c.reintegro(d.leerImporte());
// Cambiar valor en el text field de saldo
tfs.setText(new Float(c.leerSaldo()).toString());
// Indicar a la tabla que hemos aadido una fila, para que se actualice
im.fireTableRowsInserted(c.numMovimientosHistorico() - 1,
c.numMovimientosHistorico() - 1);
}
}
}

Programacin en
GUIs
Teclas rpidas
Teclas rpidas
Los usuarios que utilizan habitualmente una aplicacin
suelen requerir ciertas rpidas para agilizar su uso
Normalmente una tecla rpida suele ser una
combinacin del tipo ALT+tecla
Adems, debe ayudarse al usuario a identificar estas
teclas rpidas marcando la tecla en el componente en
cuestin
Programacin en
GUIs
Teclas rpidas
En los componentes que tienen asociada una etiqueta,
como botones, opciones de mens, etc. la tecla rpida
se establece mediante
componente.setMnemonic(<tecla>)
Las teclas vienen identificadas mediante una serie de
cdigos en la clase KeyEvent. Consultar la referencia de
esta clase para obtener la lista completa de cdigos
Las teclas normales tienen asociadas cdigos sencillos.
Por ejemplo la tecla K se codifica como VK_K
Si la tecla indicada tiene un carcter asociado y ste
aparece en la etiqueta del componente, Swing se
encarga de resaltarlo automticamente
Programacin en
GUIs
Teclas rpidas
Existen componentes que no tienen ninguna etiqueta
(p. e. JTextField). Si asociamos teclas a estos
componentes, el usuario no tiene forma de saber cules
son
Sin embargo, estos componentes suelen tener un
JLabel para su identificacin. Podemos asociar la tecla
al JLabel de la siguiente manera:
label.setLabelFor(textfield)
label.setDisplayedMnemonic(<tecla>)
De esta forma el JLabel muestra la tecla rpida, pero
realmente es el editor el que la recibe
Resulta obvio decir que no deben repetirse las teclas
rpidas dentro de un frame o dialog
Programacin en
GUIs
Teclas rpidas
La tecla TAB funciona tambin automticamente para
desplazar el foco de un componente a otro. El orden de
visita de los componentes viene dado por el orden de
insercin de stos en el panel
En los cuadros de dilogo es frecuente que exista un
botn por defecto, que se activa pulsando la tecla
RETURN. Este botn aparece remarcado sobre el resto
El botn por defecto del cuadro de dilogo puede
indicarse de la siguiente manera:
dialogo.getRootPane().setDefaultButton(boton)
Programacin en
GUIs
Teclas rpidas
Teniendo en cuenta lo anterior, aadir las teclas rpidas a nuestra aplicacin es una
cuestin rutinaria. Mostramos aqu parte del cdigo modificado
public FAppBanco() {
super("Gestin de Cuentas Bancarias");
JLabel l;
// Etiquetas y editores
JPanel pc = new JPanel();
pc.setLayout(new FlowLayout(FlowLayout.LEFT));
pc.add(l = new JLabel("Cdigo"));
pc.add(tfc = new JTextField(8));
l.setLabelFor(tfc);
l.setDisplayedMnemonic(KeyEvent.VK_C);

JPanel pt = new JPanel();
pt.setLayout(new FlowLayout(FlowLayout.LEFT));
pt.add(l = new JLabel("Titular"));
pt.add(tft = new JTextField(30));
l.setLabelFor(tft);
l.setDisplayedMnemonic(KeyEvent.VK_T);

// Sigue el cdigo aqu...

// Botones
JPanel pb = new JPanel(new FlowLayout(FlowLayout.CENTER));
pb.add(bc = new JButton("Crear"));
bc.setMnemonic(KeyEvent.VK_R);
pb.add(bb = new JButton("Buscar"));
bb.setMnemonic(KeyEvent.VK_B);
pb.add(bo = new JButton("Operacin"));
bo.setMnemonic(KeyEvent.VK_O);
// Etc, etc...
Programacin en
GUIs
Los looks de Swing
Los looks de Swing
Para terminar con nuestro ejemplo y el tema dedicado a programacin en GUIs
podemos probar distintos looks para nuestra aplicacin
import javax.swing.UIManager;
import javax.swing.JFrame;
import javax.swing.JDialog;
public class AppBanco {

public AppBanco() {
}

public static void main(String[] args) {
try {
UIManager.setLookAndFeel(com.sun.java.swing.plaf.metal.MetalLookAndFeel");
//UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
//UIManager.setLookAndFeel(com.sun.java.swing.plaf.motif.MotifLookAndFeel");
}
catch (Exception e) {}

JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);

FAppBanco f = new FAppBanco();
}
}

Programacin en
GUIs
Los looks de Swing
Look Metal (por defecto en Java 1.4)
Look GTK
Look Motif
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class BorderWindow extends JFrame {
public BorderWindow() {
Container contentPane = getContentPane();
contentPane.add(new JButton("Button 1 (NORTH)"), BorderLayout.NORTH);
contentPane.add(new JButton("2 (CENTER)"), BorderLayout.CENTER);
contentPane.add(new JButton("Button 3 (WEST)"), BorderLayout.WEST);
contentPane.add(new JButton("Long-Named Button 4 (SOUTH)"),
BorderLayout.SOUTH);
contentPane.add(new JButton("Button 5 (EAST)"), BorderLayout.EAST);
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e) {System.exit(0);}});
}
public static void main(String args[]) {
BorderWindow window = new BorderWindow();
window.setTitle("BorderLayout");
window.pack();
window.setVisible(true);
}
}
BorderLayout class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FlowWindow extends JFrame {
public FlowWindow() {
Container contentPane = getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(new JButton("Button 1"));
contentPane.add(new JButton("2"));
contentPane.add(new JButton("Button 3"));
contentPane.add(new JButton("Long-Named Button 4"));
contentPane.add(new JButton("Button 5"));
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent e) {System.exit(0);}});
}
public static void main(String args[]) {
FlowWindow window = new FlowWindow();
window.setTitle("FlowLayout");
window.pack();
window.setVisible(true);
}
}
FlowLayout class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GridWindow extends JFrame {
public GridWindow() {
Container contentPane = getContentPane();
contentPane.setLayout(new GridLayout(0,2));
contentPane.add(new JButton("Button 1"));
contentPane.add(new JButton("2"));
contentPane.add(new JButton("Button 3"));
contentPane.add(new JButton("Long-Named Button 4"));
contentPane.add(new JButton("Button 5"));
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e) {System.exit(0);}});
}
public static void main(String args[]) {
GridWindow window = new GridWindow();
window.inAnApplet = false;
window.setTitle("GridLayout");
window.pack();
window.setVisible(true);
}
}
GridLayout class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GridBagWindow extends JFrame {
final boolean shouldFill = true;
final boolean shouldWeightX = true;
public GridBagWindow() {
JButton button;
Container contentPane = getContentPane();
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
contentPane.setLayout(gridbag);
if (shouldFill) c.fill = GridBagConstraints.HORIZONTAL;
button = new JButton("Button 1");
if (shouldWeightX) c.weightx = 0.5;
c.gridx = 0;
c.gridy = 0;
gridbag.setConstraints(button, c);
contentPane.add(button);
GridBagLayout class
button = new JButton("2");
c.gridx = 1;
c.gridy = 0;
gridbag.setConstraints(button, c);
contentPane.add(button);
button = new JButton("Button 3");
c.gridx = 2;
c.gridy = 0;
gridbag.setConstraints(button, c);
contentPane.add(button);
button = new JButton("Long-Named Button 4");
c.ipady = 40; //make this component tall
c.weightx = 0.0;
c.gridwidth = 3;
c.gridx = 0;
c.gridy = 1;
gridbag.setConstraints(button, c);
contentPane.add(button);
GridBagLayout class
button = new JButton("Button 5");
c.ipady = 0; //reset to default
c.weighty = 1.0; //request any extra vertical space
c.anchor = GridBagConstraints.SOUTH; //bottom of space
c.insets = new Insets(10,0,0,0); //top padding
c.gridx = 1; //aligned with button 2
c.gridwidth = 2; //2 columns wide
c.gridy = 2; //third row
gridbag.setConstraints(button, c);
contentPane.add(button);
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e)
{System.exit(0);}});
}
public static void main(String args[]) {
GridBagWindow window = new GridBagWindow();
window.inAnApplet = false;
window.setTitle("GridBagLayout");
window.pack();
window.setVisible(true);
}
}
GridBagLayout class
Ejemplo de manejo de JCheckBox
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CheckBoxDemo extends JPanel implements ItemListener {
JCheckBox chinButton, glassesButton, hairButton, teethButton;
StringBuffer choices;
JLabel pictureLabel;
public CheckBoxDemo() {
super(new BorderLayout());
chinButton = new JCheckBox("Chin");
chinButton.setMnemonic(KeyEvent.VK_C);
chinButton.setSelected(true);
glassesButton = new JCheckBox("Glasses");
glassesButton.setMnemonic(KeyEvent.VK_G);
glassesButton.setSelected(true);
hairButton = new JCheckBox("Hair");
hairButton.setMnemonic(KeyEvent.VK_H);
hairButton.setSelected(true);
teethButton = new JCheckBox("Teeth");
teethButton.setMnemonic(KeyEvent.VK_T);
teethButton.setSelected(true);
Ejemplo de manejo de JCheckBox
//Register a listener for the check boxes.
chinButton.addItemListener(this);
glassesButton.addItemListener(this);
hairButton.addItemListener(this);
teethButton.addItemListener(this);
//Indicates what's on the geek.
choices = new StringBuffer("cght");
//Set up the picture label
pictureLabel = new JLabel();
pictureLabel.setFont(pictureLabel.getFont().deriveFont(Font.ITALIC));
updatePicture();
//Put the check boxes in a column in a panel
JPanel checkPanel = new JPanel(new GridLayout(0, 1));
checkPanel.add(chinButton);
checkPanel.add(glassesButton);
checkPanel.add(hairButton);
checkPanel.add(teethButton);
add(checkPanel, BorderLayout.LINE_START);
add(pictureLabel, BorderLayout.CENTER);
setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
}
Ejemplo de manejo de JCheckBox
/** Listens to the check boxes. */
public void itemStateChanged(ItemEvent e) {
int index = 0;
char c = '-';
Object source = e.getItemSelectable();
if (source == chinButton) {
index = 0; c = 'c';
} else if (source == glassesButton) {
index = 1; c = 'g';
} else if (source == hairButton) {
index = 2; c = 'h';
} else if (source == teethButton) {
index = 3; c = 't';
}
//Now that we know which button was pushed, find out
//whether it was selected or deselected.
if (e.getStateChange() == ItemEvent.DESELECTED) {
c = '-';
}
//Apply the change to the string.
choices.setCharAt(index, c);
updatePicture();
}
Ejemplo de manejo de JCheckBox
protected void updatePicture() {
//Get the icon corresponding to the image.
ImageIcon icon = createImageIcon("images/geek/geek-"
+ choices.toString() + ".gif");
pictureLabel.setIcon(icon);
pictureLabel.setToolTipText(choices.toString());
if (icon == null) {
pictureLabel.setText("Missing Image");
} else {
pictureLabel.setText(null);
}
}
/** Returns an ImageIcon, or null if the path was invalid. */
protected static ImageIcon createImageIcon(String path) {
java.net.URL imgURL = CheckBoxDemo.class.getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
public static void main(String s[]) {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
JFrame frame = new JFrame("CheckBoxDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new CheckBoxDemo();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
}
Ejemplo de manejo de JCheckBox
Ejemplo de manejo de JButton
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonDemo extends JPanel implements ActionListener {
protected JButton b1, b2, b3;
public ButtonDemo() {
ImageIcon leftButtonIcon = new ImageIcon("images/right.gif");
ImageIcon middleButtonIcon = new ImageIcon("images/middle.gif");
ImageIcon rightButtonIcon = new ImageIcon("images/left.gif");
b1 = new JButton("Disable middle button", leftButtonIcon);
b1.setVerticalTextPosition(AbstractButton.CENTER);
b1.setHorizontalTextPosition(AbstractButton.LEFT);
b1.setMnemonic(KeyEvent.VK_D);
b1.setActionCommand("disable");
b2 = new JButton("Middle button", middleButtonIcon);
b2.setVerticalTextPosition(AbstractButton.BOTTOM);
b2.setHorizontalTextPosition(AbstractButton.CENTER);
b2.setMnemonic(KeyEvent.VK_M);
b3 = new JButton("Enable middle button", rightButtonIcon);
//Use the default text position of CENTER, RIGHT.
b3.setMnemonic(KeyEvent.VK_E);
b3.setActionCommand("enable");
b3.setEnabled(false);
//Listen for actions on buttons 1 and 3.
b1.addActionListener(this);
b3.addActionListener(this);
b1.setToolTipText(
"Click this button to disable the middle button.");
b2.setToolTipText(
"This middle button does nothing when you click it.");
b3.setToolTipText(
"Click this button to enable the middle button.");
//Add Components to this container, using the default FlowLayout.
add(b1);
add(b2);
add(b3);
}
Ejemplo de manejo de JButton
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("disable")) {
b2.setEnabled(false);
b1.setEnabled(false);
b3.setEnabled(true);
} else {
b2.setEnabled(true);
b1.setEnabled(true);
b3.setEnabled(false);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("ButtonDemo");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);}});
frame.getContentPane().add(new ButtonDemo(), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
Ejemplo de manejo de JButton
Ejemplo de manejo de JFileChooser
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.*;
public class FileChooserDemo extends JPanel implements ActionListener {
static private final String newline = "\n";
JButton openButton, saveButton;
JTextArea log;
JFileChooser fc;
public FileChooserDemo() {
super(new BorderLayout());
//Create the log first, because the action listeners
//need to refer to it.
log = new JTextArea(5,20);
log.setMargin(new Insets(5,5,5,5));
log.setEditable(false);
JScrollPane logScrollPane = new JScrollPane(log);
//Create a file chooser
fc = new JFileChooser();
openButton = new JButton("Open a File...",
createImageIcon("images/Open16.gif"));
openButton.addActionListener(this);
saveButton = new JButton("Save a File...",
createImageIcon("images/Save16.gif"));
saveButton.addActionListener(this);
//For layout purposes, put the buttons in a separate panel
JPanel buttonPanel = new JPanel(); //use FlowLayout
buttonPanel.add(openButton);
buttonPanel.add(saveButton);
//Add the buttons and the log to this panel.
add(buttonPanel, BorderLayout.PAGE_START);
add(logScrollPane, BorderLayout.CENTER);
}
Ejemplo de manejo de JFileChooser
public void actionPerformed(ActionEvent e) {
//Handle open button action.
if (e.getSource() == openButton) {
int returnVal = fc.showOpenDialog(FileChooserDemo.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
//This is where a real application would open the file.
log.append("Opening: " + file.getName() + "." + newline);
} else {
log.append("Open command cancelled by user." + newline);
}
//Handle save button action.
} else if (e.getSource() == saveButton) {
int returnVal = fc.showSaveDialog(FileChooserDemo.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
//This is where a real application would save the file.
log.append("Saving: " + file.getName() + "." + newline);
} else {
log.append("Save command cancelled by user." + newline);
}
}
}
Ejemplo de manejo de JFileChooser
Ejemplo de manejo de JFileChooser
/** Returns an ImageIcon, or null if the path was invalid. */
protected static ImageIcon createImageIcon(String path) {
java.net.URL imgURL = FileChooserDemo.class.getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("FileChooserDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new FileChooserDemo();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
}
FileChooserDemo2
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.*;
public class FileChooserDemo2 extends JPanel
implements ActionListener {
static private String newline = "\n";
private ScrollDemo sd = new ScrollDemo(null);
private JTextArea log;
private JFileChooser fc;
public FileChooserDemo2() {
super(new BorderLayout());
log = new JTextArea(5,20);
log.setMargin(new Insets(5,5,5,5));
log.setEditable(false);
JScrollPane logScrollPane = new JScrollPane(log);
JButton sendButton = new JButton("Attach...");
sendButton.addActionListener(this);
add(sendButton, BorderLayout.PAGE_START);
add(logScrollPane, BorderLayout.CENTER);
}
public void actionPerformed(ActionEvent e) {
if (fc == null) {
fc = new JFileChooser();
fc.addChoosableFileFilter(new ImageFilter());
fc.setAcceptAllFileFilterUsed(false);
fc.setFileView(new ImageFileView());
fc.setAccessory(new ImagePreview(fc));
}
int returnVal = fc.showDialog(FileChooserDemo2Bis.this, "Attach");
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
System.out.println("Attaching file: " + file.getName() + ".");
String fileAbsolutePath = file.getAbsolutePath();
log.append("Attaching file: " + file.getName()+ "." + newline);
} else {
log.append("Attachment cancelled by user." + newline);
}
fc.setSelectedFile(null);
}
FileChooserDemo2
public static void main(String[] args) {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("FileChooserDemo2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new FileChooserDemo2Bis();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
}
FileChooserDemo2
ImageFileView
import java.io.File;
import javax.swing.*;
import javax.swing.filechooser.*;
public class ImageFileView extends FileView {
ImageIcon jpgIcon = Utils.createImageIcon("images/jpgIcon.gif");
ImageIcon gifIcon = Utils.createImageIcon("images/gifIcon.gif");
ImageIcon tiffIcon = Utils.createImageIcon("images/tiffIcon.gif");
ImageIcon pngIcon = Utils.createImageIcon("images/pngIcon.png");
public String getName(File f) {
return null; //let the L&F FileView figure this out
}
public String getDescription(File f) {
return null; //let the L&F FileView figure this out
}
public Boolean isTraversable(File f) {
return null; //let the L&F FileView figure this out
}
public String getTypeDescription(File f) {
String extension = Utils.getExtension(f);
String type = null;
if (extension != null) {
if (extension.equals(Utils.jpeg)||extension.equals(Utils.jpg)) {
type = "JPEG Image";
} else if (extension.equals(Utils.gif)){
type = "GIF Image";
} else if (extension.equals(Utils.tiff)||
extension.equals(Utils.tif)) {
type = "TIFF Image";
} else if (extension.equals(Utils.png)){
type = "PNG Image";
}
}
return type;
}
ImageFileView
public Icon getIcon(File f) {
String extension = Utils.getExtension(f);
Icon icon = null;
if (extension != null) {
if (extension.equals(Utils.jpeg)||extension.equals(Utils.jpg)) {
icon = jpgIcon;
} else if (extension.equals(Utils.gif)) {
icon = gifIcon;
} else if (extension.equals(Utils.tiff) ||
extension.equals(Utils.tif)) {
icon = tiffIcon;
} else if (extension.equals(Utils.png)) {
icon = pngIcon;
}
}
return icon;
}
}
ImageFileView
import java.io.File;
import javax.swing.*;
import javax.swing.filechooser.*;
public class ImageFilter extends FileFilter {
public boolean accept(File f) {
if (f.isDirectory()) {
return true;
}
String extension = Utils.getExtension(f);
if (extension != null) {
if (extension.equals(Utils.tiff)||extension.equals(Utils.tif)||
extension.equals(Utils.gif)||extension.equals(Utils.jpeg)||
extension.equals(Utils.jpg)||extension.equals(Utils.png)) {
return true;
} else {
return false;
}
}
return false;
}
public String getDescription() {
return "Just Images";
}
}
ImageFilter
import javax.swing.*;
import java.beans.*;
import java.awt.*;
import java.io.File;
public class ImagePreview extends JComponent
implements PropertyChangeListener {
ImageIcon thumbnail = null;
File file = null;
public ImagePreview(JFileChooser fc) {
setPreferredSize(new Dimension(100, 50));
fc.addPropertyChangeListener(this);
}
public void loadImage() {
if (file == null) {
thumbnail = null;return;
}
ImageIcon tmpIcon = new ImageIcon(file.getPath());
if (tmpIcon != null) {
if (tmpIcon.getIconWidth() > 90) {
thumbnail = new ImageIcon(tmpIcon.getImage().getScaledInstance(
90, -1, Image.SCALE_DEFAULT));
} else { //no need to miniaturize
thumbnail = tmpIcon;
}
}
}
ImagePreview
public void propertyChange(PropertyChangeEvent e) {
boolean update = false;
String prop = e.getPropertyName();
if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(prop)) {
file = null; update = true;
}
else if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(prop)) {
file = (File) e.getNewValue(); update = true;
}
if (update) {
thumbnail = null;
if (isShowing()) {
loadImage(); repaint();
}
}
}
public void paintComponent(Graphics g) {
if (thumbnail == null) loadImage();
if (thumbnail != null) {
int x = getWidth()/2 - thumbnail.getIconWidth()/2;
int y = getHeight()/2 - thumbnail.getIconHeight()/2;
if (y < 0) y = 0;
if (x < 5) x = 5;
thumbnail.paintIcon(this, g, x, y);
}
}
}
import java.io.File;
import javax.swing.ImageIcon;
public class Utils {
public final static String jpeg = "jpeg";
public final static String jpg = "jpg";
public final static String gif = "gif";
public final static String tiff = "tiff";
public final static String tif = "tif";
public final static String png = "png";
public static String getExtension(File f) {
String ext = null;
String s = f.getName();
int i = s.lastIndexOf('.');
if(i > 0 && i < s.length() - 1) ext=s.substring(i+1).toLowerCase();
return ext;
}
protected static ImageIcon createImageIcon(String path) {
java.net.URL imgURL = Utils.class.getResource(path);
if (imgURL != null) return new ImageIcon(imgURL);
else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
}
Utils
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MenuDemo implements ActionListener, ItemListener {
JTextArea output;
JScrollPane scrollPane;
String newline = "\n";
public JMenuBar createMenuBar() {
JMenuBar menuBar;
JMenu menu, submenu;
JMenuItem menuItem;
JRadioButtonMenuItem rbMenuItem;
JCheckBoxMenuItem cbMenuItem;
//Create the menu bar.
menuBar = new JMenuBar();
//Build the first menu.
menu = new JMenu("A Menu");
menu.setMnemonic(KeyEvent.VK_A);
menu.getAccessibleContext().setAccessibleDescription(
"The only menu in this program that has menu items");
menuBar.add(menu);
MenuDemo.java
//a group of JMenuItems
menuItem = new JMenuItem("A text-only menu item",
KeyEvent.VK_T);
menuItem.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_1, ActionEvent.ALT_MASK));
menuItem.getAccessibleContext().setAccessibleDescription(
"This doesn't really do anything");
menuItem.addActionListener(this);
menu.add(menuItem);
ImageIcon icon = createImageIcon("images/middle.gif");
menuItem = new JMenuItem("Both text and icon", icon);
menuItem.setMnemonic(KeyEvent.VK_B);
menuItem.addActionListener(this);
menu.add(menuItem);
menuItem = new JMenuItem(icon);
menuItem.setMnemonic(KeyEvent.VK_D);
menuItem.addActionListener(this);
menu.add(menuItem);
MenuDemo.java
//a group of radio button menu items
menu.addSeparator();
ButtonGroup group = new ButtonGroup();
rbMenuItem = new JRadioButtonMenuItem("A radio button menu item");
rbMenuItem.setSelected(true);
rbMenuItem.setMnemonic(KeyEvent.VK_R);
group.add(rbMenuItem);
rbMenuItem.addActionListener(this);
menu.add(rbMenuItem);
rbMenuItem = new JRadioButtonMenuItem("Another one");
rbMenuItem.setMnemonic(KeyEvent.VK_O);
group.add(rbMenuItem);
rbMenuItem.addActionListener(this);
menu.add(rbMenuItem);
//a group of check box menu items
menu.addSeparator();
cbMenuItem = new JCheckBoxMenuItem("A check box menu item");
cbMenuItem.setMnemonic(KeyEvent.VK_C);
cbMenuItem.addItemListener(this);
menu.add(cbMenuItem);
MenuDemo.java
cbMenuItem = new JCheckBoxMenuItem("Another one");
cbMenuItem.setMnemonic(KeyEvent.VK_H);
cbMenuItem.addItemListener(this);
menu.add(cbMenuItem);
//a submenu
menu.addSeparator();
submenu = new JMenu("A submenu");
submenu.setMnemonic(KeyEvent.VK_S);
menuItem = new JMenuItem("An item in the submenu");
menuItem.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_2, ActionEvent.ALT_MASK));
menuItem.addActionListener(this);
MenuDemo.java
submenu.add(menuItem);
menuItem = new JMenuItem("Another item");
menuItem.addActionListener(this);
submenu.add(menuItem);
menu.add(submenu);
menu = new JMenu("Another Menu");
menu.setMnemonic(KeyEvent.VK_N);
menu.getAccessibleContext().setAccessibleDescription(
"This menu does nothing");
menuBar.add(menu);
return menuBar;
}
public Container createContentPane() {
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setOpaque(true);
output = new JTextArea(5, 30);
output.setEditable(false);
scrollPane = new JScrollPane(output);
contentPane.add(scrollPane, BorderLayout.CENTER);
return contentPane;
}
MenuDemo.java
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem)(e.getSource());
String s = "Action event detected." + newline
+ " Event source: " + source.getText()
+ " (an instance of " + getClassName(source) + ")";
output.append(s + newline);
}
public void itemStateChanged(ItemEvent e) {
JMenuItem source = (JMenuItem)(e.getSource());
String s = "Item event detected." + newline
+ " Event source: " + source.getText()
+ " (an instance of " + getClassName(source) + ")" + newline
+ " New state: " + ((e.getStateChange() == ItemEvent.SELECTED) ?
"selected":"unselected");
output.append(s + newline);
}
protected String getClassName(Object o) {
String classString = o.getClass().getName();
int dotIndex = classString.lastIndexOf(".");
return classString.substring(dotIndex+1);
}
MenuDemo.java
protected static ImageIcon createImageIcon(String path) {
java.net.URL imgURL = MenuDemo.class.getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("MenuDemo");
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
MenuDemo demo = new MenuDemo();
frame.setJMenuBar(demo.createMenuBar());
frame.setContentPane(demo.createContentPane());
frame.setSize(450, 260);
frame.setVisible(true);
}
}
MenuDemo.java

Das könnte Ihnen auch gefallen