Professional Documents
Culture Documents
0 Antes de empezar 1 Primer programa 2 Variables (y constantes) 3 Entrada/Salida en modo texto 4 Tipos Primitivos 5 Instrucciones de control
Tabla A: Palabras Reservadas en Java Tabla B: Rango de los tipos primitivos Tabla C: Asociatividad de los operadores Apndice A: Instalacin y uso de un compilador Apndice B: Uso de Javadoc Apndice C: Ficheros JAR
0 Antes de empezar
0.1 Objetivos
Estos apuntes pretenden ser una introduccin al lenguaje de programacin Java. Java es un lenguaje muy extenso, con muchas "caras", y ningn libro o coleccin de apuntes pueden pretender cubrir con suficiente profundidad todos los aspectos del lenguaje. De hecho, hoy en da es normal designar mediante la palabra "Java" no a un lenguaje sino a toda un conjunto de herramientas, metodologas, etc. basadas en el lenguaje. Por eso no est de ms que tratemos de delimitar desde el principio cules son los objetivos, qu se pretende y qu no se pretende.
Lo que se pretende es mostrar en suficiente detalle los conceptos bsicos del lenguaje. Para ello se parte de cero, tratando de hacer el aprendizaje lo ms gradual y "suave" posible. El precio a pagar: no ser posible cubrir todos los aspectos del lenguaje. Muchos de los aspectos ms avanzados, y puede que para muchos ms atractivos, del lenguaje no sern tratados. Tambin se ignoran algunos trucos y tcnicas comunes entre los programadores de Java que, aunque tiles, podran confundir al principiante. Se pretende explicar slo lo principal, pero bien, procurando que el lector entienda el porqu de cada paso. El objetivo es llegar a tener un conocimiento slido, una buena base del lenguaje. Ms adelante, si as lo queremos o lo necesitamos, estos conocimientos nos ayudarn a comprender libros dedicados a aspectos ms especficos del lenguaje. En los apndices al final de cada captulo mencionaremos algn aspecto ms especfico que consideremos curioso o interesante. La lista siguiente incluye la mayor parte de los aspectos del lenguaje cubiertos por estos apuntes. Contiene muchos trminos que posiblemente suenen de los ms extraos (e incluso amenazadores) al que an no sabe nada del lenguaje, pero puede resultar de utilidad para los que s sepan algo y quieran evitar perder el tiempo. Breve introduccin a las sentencias de control (bucles, sentencias condicionales, etc.) y otros aspectos bsicos como el manejo de excepciones. Principios de programacin orientada a objetos en Java: encapsulacin, herencia, clases abstractas e interfaces. Programacin de interfaces grficos: control de eventos, clases AWT y Swing (esta ltima slo superficialmente), y desarrollo de Applets. Utilizacin de los recursos bsicos del lenguaje tales como vectores y arrays, y desarrollo de nuestros propios tipos abstractos de datos. Esta otra lista (compuesta por trminos an ms esotricos) incluye parte de lo que no se puede encontrar en estos apuntes: Programacin de Servlets y JSP (Java Server Pages). Programacin concurrente.
Por supuesto el programador no tiene porqu preocuparse del funcionamiento interno del compilador: le basta con usarlo. Sin embargo, no viene mal echar un breve vistazo brevemente cual es la estructura interna de los compiladores tradicionales. En una primera (y muy burda) divisin, el compilador consta de dos fases consecutivas: 1. Anlisis. En esta fase se lee el programa original (al que se suele denominar cdigo fuente) y se analiza para descubrir sus significado. Por ejemplo, al llegar a la instruccin System.out.println( Math.sqrt(2) ); , el compilador leer el cdigo letra a letra (S-y-s-t-e-m-...) reconociendo en primer lugar la palabras "System". Si nos equivocamos y escribimos en nuestro programa Sostem.out.println( Math.sqrt(2) ); , el compilador detectar en esta fase que "Sostem" no corresponde a nada conocido, y nos dar un mensaje de error. Si en cambio el compilador no detecta ningn error la primera fase habr finalizado con xito. El resultado de esta primera fase es una representacin interna del programa fuente (a la que el programador no tiene, en principio, acceso) y que la segunda fase tomar a su vez como entrada. El anlisis de un programa por parte de un compilador no es una tarea complicada (hay tcnicas muy conocidas para automatizar esta parte), pero es farragosa, y a menudo lenta: el compilador debe leer todo el cdigo fuente e ir examinando cada posibilidad para ver cual es el significado de lo escrito por el programador. 2. Generacin de cdigo mquina. En esta segunda fase se genera ya el cdigo mquina a partir de la representacin interna producida en el paso anterior. La generacin de cdigo no es una tarea trivial: cuando se disea el lenguaje hay que pensar en cmo se representarn en el cdigo mquina del microprocesador todas las caractersticas que forman parte del lenguaje. Cuanto ms complejo o de ms "alto nivel" sea el lenguaje, ms difcil ser traducirlo a cdigo mquina. Sin embargo, una vez que todas estas decisiones estn tomadas y se ha conseguido escribir esta parte del compilador, su ejecucin s es veloz, es decir se tarda menos en generar cdigo que en hacer el anlisis del cdigo fuente (fase 1). En este punto conviene recordar que en general diferentes microprocesadores tienen diferentes cdigos mquina asociados, y que stos en general no son compatibles entre s. Habitualmente olvidamos esto porque estamos acostumbrados a trabajar con ordenadores cuyos microprocesadores son compatibles (los Intel x86, Pentium, etc.). Pero si somos usuarios, por ejemplo de Mac, sabremos que los programas que se ejecutan en nuestro PC no se pueden ejecutar en el Mac. La razn no es tanto el uso de sistemas operativos diferentes sino que los cdigos mquinas de los microprocesadores no son compatibles.
En particular los navegadores ms usuales (explorer, Mozilla, Netscape) incluyen intrpretes de bytecodes. Ahora tambin resulta ms fcil de entender por qu se oye a menudo hablar de juegos en Java para telfonos mviles. El creador del juego no tiene por qu preocuparse de todos los modelos de telfono mvil del mercado: slo de escribir el juego y compilarlo generando los bytecodes. Es cada fabricante del telfono el que se encarga de incluir un pequeo intrprete de bytecodes, lo que garantiza que su telfono ser capaz de ejecutar juegos en
1 Primer programa
Nuestro primer programa se limita a mostrar una lnea de texto en pantalla: Hola.java
public class Hola { public static void main(String [] Args) { System.out.println("Soy pequen....mmame!"); } }
Vamos a ir analizando el programa lnea a lnea: public class Hola { En esta primera lnea se indica el nombre de la clase que estamos definiendo. public class indica que el fichero contiene una clase que se va a poder utilizar desde otras. A estas palabras reservadas les sigue el nombre que queremos poner a la clase, en este caso Hola. Aunque no es obligatorio, es una norma habitual en Java escribir siempre el nombre de una clase con un identificador que comience por una letra mayscula. Adems, cada clase debe, (casi) obligatoriamente, formar parte de un fichero con el mismo nombre que la clase y con extensin .java. Aunque ms adelante veremos que la cosa puede llegar a ser un poco ms complicada, conviene en principio que recordemos la siguiente correspondencia: Cada clase se almacena en un fichero que lleva su nombre (y extensin .java). Cada fichero .java contiene una nica clase pblica, cuyo nombre corresponde con el del fichero (sin la extensin). Aviso: Las maysculas s importan en Java! Si despus de escribir la clase Hola la utilizamos escribiendo hola en otro lugar, el compilador dar error indicando que el identificador no ha sido definido. Aunque en los temas posteriores veremos con detalle los conceptos de clases y paquetes no est de ms que veamos una primera (incompleta y burda) aproximacin:
Podemos explicar brevemente cada una de las partes de esta declaracin: public Esta palabra significa que el mtodo puede utilizarse desde fuera de la clase. Pero...tendra sentido escribir un mtodo que no pudiera utilizarse fuera de la clase? S, cuando se trata de mtodos auxiliares que sern utilizados desde otros mtodos de la clase pero no queremos (por seguridad o por esttica) que puedan ser "vistos" fuera de la clase. static La palabra static significa que para utilizar este mtodo no necesitamos declarar un objeto de la clase. Veremos que en general para utilizar una clase es necesario tener un objeto de dicha clase (una variable de ese tipo, dicho con otras palabras) como ocurra con el objeto lneas de la clase Vector, pero el mtodo main es un mtodo especial ya que es el punto de comienzo de la aplicacin. void Todos los mtodos deben devolver un resultado de algn tipo. En la cabecera hay
qu significa?
Aunque el programa Hola.java es correcto lo habitual es escribir comentarios que expliquen el cdigo: Hola.java
/** * Primera clase en Java. * @version 1.0, 24/12/04 * @author Rafa Caballero */ public class Hola {
Este cdigo hace exactamente lo mismo que el programa inicial slo que incluye comentarios. Los comentarios no alteran el funcionamiento del programa, se incluyen para que ste sea ms comprensible y para generar documentacin automtica. Java incluye 3 tipos de comentarios: 1. Comenzando con // . En este caso el compilador ignora todo lo que va desde // hasta el final de lnea. 2. Comenzando con /* y terminando con */. Estos comentarios pueden ocupar mltiples lneas. 3. Comenzando con /** y terminando con */. Igual que el anterior, slo que estos comentarios pueden ser utilizados por la herramienta javadoc para generar documentacin sobre la clase.
2 Variables (y constantes)
2.1 Qu es una variable? 2.2 Declaracin de variables 2.3 Operacin de asignacin 2.4 Constantes
Java tambin permite que varias variables del mismo tipo se declaren separadas por comas:
int nmero,b=3,c=4,suma=0,d; char letra;
Un ltimo aspecto a mencionar es que en Java las declaraciones de una variable se pueden hacer en cualquier lugar:
El operador + sirve aqu para concatenar el contenido de la variable al final de la cadena de caracteres.
Pregunta 1.b Qu escribir el programa? En particular esto permite la llamada asignacin mltiple:
public class Principal { public static void main(String[] args) { int a,b,c; a = b = c = 1; System.out.println(a); System.out.println(b); System.out.println(c); } // main
Pregunta 1.c Qu escribir el programa? A menudo y por comodidad utilizaremos esta asignacin mltiple. Observacin: La igualdad es una operacin que asocia por la derecha (ver tabla C).
2.4 Constantes
Las constantes son variables que no pueden modificarse. En Java se declaran anteponiendo la palabra reservada final a la declaracin de la variable: final tipoVariable nombreVariable = valorInicial; Ej.:
final char AMAYSCULA = 'a'; final double N = 299792.495;
Es necesario incluir la inicializacin junto con la declaracin, porque la operacin de asignacin no est permitida ms que en la declaracin:
final double PI = 3.141592; double a; a = PI +1; // esto es vlido PI = a +1; //NOOOO!!!!
Hace que aparezca por pantalla la secuencia de caracteres escrita entre comillas. En lugar de escribir la secuencia de caracteres directamente, tambin nos puede interesar almacenarla primero en una variable. El tipo de las secuencias de caracteres en Java se llama String. El siguiente cdigo declara una variable de este tipo y muestra su contenido por pantalla:
String s = "Nocturno y dulce revuelo";
Es importante observar aqu que el nombre de la variable no va entre comillas; si hubiramos escrito System.out.println("s"); en lugar de la frase el cdigo mostrara por pantalla simplemente s. println() es tan flexible que nos permite igualmente escribir enteros, caracteres o nmeros reales. Por ejemplo
System.out.println(124); System.out.println('a'); System.out.println(1.618033);
Pregunta 1.d Qu escribir el programa? Para acabar, decir que se puede usar print en lugar de println si se quiere que no se introduzca un salto de lnea tras escribir.
Este ejemplo incluye muchas novedades: import java.util.Scanner; Para leer de teclado se debe utilizar un objeto de la clase Scanner. Esta clase no es de las incluidas de forma automtica y por eso debe incluirse mediante la palabra clave import. Si la clase est definida en otro paquete se escribe el nombre "cualificado", precedido por el nombre del paquete. En este caso la clase Scanner es parte del paquete util que es a su vez parte de la clase java. Si se desean incluir varias clases se incluirn varias sentencias import:
import java.util.Scanner; import java.util.Vector;
Si se quieren incluir varias (o todas) clases del mismo paquete se puede usar el simbolo *:
import java.util.*; // importa Scanner, Vector y muchas ms
Para ver qu clases contiene cada paquete conviene consultar la ayuda de Java. Scanner sc = new Scanner(System.in); Esta instruccin declara e inicializa un objeto sc de tipo Scanner. En los captulos posteriores veremos los objetos en detalle, pero aqu tenemos un primer ejemplo de como se crea un objeto mediante new. El parmetro System.in indica de dnde se leer, en este caso de la entrada estndar pero igualmente se podra leer, por ejemplo de un fichero de texto de nombre "datos.txt":
Scanner sc = new Scanner(new File("datos.txt"));
int edad = sc.nextInt(); La llamada al mtodo nextInt(); devuelve el siguiente entero que se puede leer del objeto de tipo Scanner. Adems de enteros se pueden leer valores de otros tipos. Para leer una lnea completa se usar el mtodo nextLine(); que devuelve un valor de tipo String:
import java.util.Scanner; public class Principal { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("Cmo te llamas? "); String nombre = sc.nextLine(); // leer una cadena de caracteres System.out.println("Es un placer conocerte "+nombre); } // main
Observacin: A menudo en el terminal de texto las letras acentuadas, la y otros smbolos del alfabeto espaol no se muestran adecuadamente. Esto se solucionar ms adelante, cuando introduzcamos los programas con entrada/salida grfica.
4 Tipos Primitivos
4.1 Qu es un tipo? 4.2 Tipos Primitivos 4.3 Tipos enumerados 4.4 Conversiones de tipo
4.1 Qu es un tipo?
En principio se tiende a pensar en un tipo como un conjunto de valores, por ejemplo el tipo int estara formado por el conjunto de nmeros enteros aceptados por el lenguaje Java. Sin embargo esta visin es demasiado restrictiva. Si nos limitamos a usar los valores podemos hacer pocas cosas. Los valores slo son tiles cuando se combinan con las operaciones adecuadas. Por ello emplearemos la siguiente definicin: tipo = Valores + operaciones que manejan esos valores As el tipo int est formado por los valores enteros admitidos por el lenguaje Java junto con las operaciones +,-,*,/,=, .... Observacin: Hay veces que se usa el mismo smbolo para operaciones anlogas entre diferentes tipos. Por ejemplo, + representa la suma tanto de nmeros enteros como reales. Sin embargo, debemos recordar que se trata de dos operaciones diferentes, aunque estn representadas por el mismo smbolo. Se dice en este caso que el smbolo (por ejemplo +) est sobrecargado.
! : operador unario not; !true es false y !false es true exprb1 && exprb2 : true si los dos son true, false en otro caso exprb1 || exprb2 : true si alguno de los dos es true, false en otro caso a == b : true si a es igual a b, false en otro caso (no confundir con la asig. '=') a != b: true si a es distinto de b, false si son iguales.
Ejemplo
// operaciones entre booleanos boolean b1,b2; int x=5, y=x+3; b1= true && (x == y); // y = x; b2 = !b1 || (x != y); // System.out.println(b1); System.out.println(b2);
Pregunta 1.f Qu escribir este fragmento de programa? Los valores lgicos se pueden leer de teclado utilizando el mtodo nextBoolean(); de la clase Scanner:
Scanner sc = new Scanner(System.in); boolean b = sc.nextBoolean();
Enteros Hay 4 (sub)tipos de enteros: byte, short, int y long. La diferencia entre ellos es el rango de valores que admiten, y que se puede consultar en la tabla B al final del tema. El ms usado es el tipo int, pero las operaciones que vamos a ver son vlidas para todos ellos. Valores Los nmeros enteros se pueden escribir :
En decimal: -123, 666, 1024, 0 En octal: dgitos entre 0 y 6 comenzando siempre por un 0: 0612 En hexadecimal: dgitos y letras entre 'a' y 'f' (maysculas o minsculas, no importa) precedidas por 0x: 0xffff, 0x1A, 0xFabada.
Si se quiere indicar que un valor es de tipo long se aade tras el ltimo dgito una letra L (minscula o mayscula, no importa). Operaciones
Las operaciones aritmticas usuales: +,-,*, / (divisin entera) y % (resto de la divisin entera). Operadores de incremento (++) y decremento (--), que producen un nuevo valor entero. Ejemplo:
int x = 0; x = 5*8+1; x++; // es lo mismo que poner x=x+1
Operadores de relacin: >, <, <=, >=, == (comparacin, no confundir con la asignacin = ) y != (distinto). El resultado es un valor de tipo boolean, es decir true o false Ejemplo
import java.util.Scanner; // para leer de teclado public class Principal { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n1 = sc.nextInt(), n2=sc.nextInt(); boolean b1 = ((n2-n1) % 2) == 0; n1++; boolean b2 = n1 == n2; System.out.print(b1+" "); System.out.println(b2); } // main }
Pregunta 1.g 1. Qu escribir el programa cuando los valores de entrada son 9 y 11? 2. En qu casos escribir el programa false true? 3. En qu casos escribir el programa true true?
Ejemplo
public class Principal { public static void main(String[] args) { int x,y; x=y=2; x += 5; y *= x+1; System.out.println(x); System.out.println(y); } // main }
Observacin: La operacin potencia se hace mediante el mtodo pow(base,potencia) de la clase Math que veremos ms adelante.
Operaciones entre bits: & (AND), | (OR), ^ (XOR), >> (desplazamiento a la derecha), >> (desplazamiento a la derecha). Operan sobre los nmeros representados en binario. No demasiado utilizadas, por lo que no nos detenemos a explicarlas. Si alguien siente curiosidad puede probar el siguiente programa: Ejemplo:
public class Principal { public static void main(String[] args) { int x,y; x=4; // en binario 000...0100 y=1; // en binario 000...0001
Nmeros Reales Nmeros reales: float y double. Los literales que tienen un punto decimal son, por defecto, de tipo double, aunque si por el contexto se necesita indicar que un valor es de este tipo se puede escribir seguido de la letra d o D. Los literales del tipo float van seguidos de una F o f. Ej.: 123.45f En memoria tienen una longitud de 32 (float) y 64 (double) bits, respectivamente. Valores Los nmeros reales deben incluir bien un punto decimal '.' o una letra 'e' minscula (notacin exponencial): 5., .54, 1.33, -4e2, 5e-8. Por defecto estos valores son double, pero si se quiere indicar explcitamente se puede aadir inmediatamente tras el nmero una 'f' o 'F' o bien 'd' o 'D' (float o double). Operaciones Las operaciones son las mismas que en el caso de los nmeros enteros con la nica de que ahora '/' representa la divisin con decimales. Pueden leerse de teclado utilizando los mtodos nextDouble(),nextFloat() de la clase Scanner. Caracteres Valores {....'a','b',....,'z', '#', '$', '', '', .....'[', '@',.....} Los caracteres corresponden a la tabla Unicode, ms extensa que la tabla ASCII usada por otros lenguajes: la tabla ASCII extendida tiene 256 caracteres mientras que la tabla Unicode est compuesta por 65536 caracteres, incluyendo Kanji, cirlico, etc. A cada carcter le corresponde un cdigo nico entre 0 y 65535, cdigo que se puede ver forzando la conversin del carcter a entero (que se hace automticamente): Ejemplo
char c='?'; int codigoUnicode = c; System.out.println(codigoUnicode); // escribe el valor 936
Entre comillas simples: 'a', '', '%', '?'. Escribiendo entre comillas su cdigo Unicode en hexadecimal (4 dgitos): '\u0fa0'. Algunos caracteres especiales no imprimibles se escriben con \ seguido de un carcter. Como '\n', que representa el fin de lnea, o '\t' que representa el tabulador.
Operaciones Sobre un carcter se pueden aplicar las operaciones vlidas para los enteros, que actuarn sobre el cdigo Unicode del carcter. Es importante saber que en la tabla Unicode los cdigos de la 'A', 'B', 'C' ... van consecutivos, y que lo mismo sucede con 'a', 'b', 'c', ..., y con '0',...,'9'.
Como se ve los valores de tipo enumerado se pueden escribir por pantalla, lo que supone una mejora con respecto a C y C++.
Obtenemos un error de tipo en tiempo de compilacin. Idea: Recordando la imagen de las variables como "cajas", podemos imaginarnos que a cajas diferentes corresponden cajas de distintos tamaos. As un valor real (double) debe ser una caja en la que debe caber tanto un real como un entero, ya que los enteros son tambin nmeros reales, pero no al revs. Sin embargo, tambin es posible realizar conversiones de tipo explcita de un tipo "mayor" a un tipo "menor" (con la inevitable prdida de precisin), escribiendo (tipoMenor) expresinDeTipoMayor Como por ejemplo:
double a=5.99999; int b; b = (int)5.8; System.out.println(b); b = (int)a; System.out.println(b);
Aviso: Un error comn es pensar que al hacer un cast entre tipos numricos los valores se "redondean" al valor ms cercano del tipo destino, pero en realidad se truncan, es decir se pierde su parte decimal. Por supuesto hay tipos incompatibles entre los que no hay posible conversin. Por ejemplo si intentamos compilar:
public class Principal { public enum Estacin {PRIMAVERA, VERANO, OTOO, INVIERNO}; public static void main(String[] args) { Estacin mia; mia = Estacin.PRIMAVERA; int a = (int) mia; } }
5 Estructuras de Control
5.1 Instruccin de seleccin if 5.2 El operador ? 5.3 Instruccin de seleccin mltiple switch 5.4 Bucle while 5.5 Bucle for 5.6 Bucle do ... while
La parte else es opcional. Tanto Instruccin1 como Instruccin2 deben ser, o bien una instruccin simple acabada en ; o bien una instruccin compuesta entre llaves { ... }.
Ejemplo:
import java.util.Scanner; public class Principal { // muestra el mayor de entre dos enteros ledos de teclado public static void main(String[] args) { Scanner sc = new Scanner(System.in); int x=sc.nextInt(), y=sc.nextInt(); if (x>y) System.out.println(x); else System.out.println(y); } // main }
Ejemplo:
import java.util.Scanner; public class Principal { // lee dos enteros de teclado y los muestra ordenados de menor a mayor public static void main(String[] args) { Scanner sc = new Scanner(System.in); int x=sc.nextInt(), y=sc.nextInt(); int mximo, mnimo; if (x>y) { mximo = x; mnimo = y; } else { mximo = y; mnimo = x; } System.out.println(mnimo+" "+mximo);
Pregunta 1.k Cmo cambiar el comportamiento del programa anterior cambiamos la instruccin System.out.println(x+" "+y); por System.out.println(x+y);?
5.2 El operador ?
En Java (y en C++ y C) la instruccin condicional if se puede escribir en forma de expresin, utilizando el smbolo ? para separar la condicin de la parte if y el smbolo : antes de la parte else, como muestra el siguiente ejemplo: Ejemplo:
Scanner sc = new Scanner(System.in); int x=sc.nextInt(), y=sc.nextInt(); int z; // queremos que z tome el mayor de los valores entre x e y z = x > y ? x : y; // tambin if x>y then z=x else z=y System.out.println("El mayor es: "+z);
switch(expr) { case valor1: ... // instrucciones break; case valor2: ... // instrucciones break; ... ... // otros casos ... default: // instrucciones }
La expresin se evala y se ejecutan las instrucciones que corresponden al valor. Si ninguno de los casos se cumple se ejecutan las rdenes de la parte default (que es opcional).
Ejemplo:
Aviso: Un error habitual es olvidar modificar las variables que se encuentran en la condicin del bucle. Esto da lugar a programas que no terminan.
Pregunta 1.l Cmo se podra mejorar la condicin del bucle para que ste diera el menor nmero de iteraciones ("vueltas") posible?
Pregunta 1.m Sustituye la instruccin "if" por otra (u otras) que slo usen el operador "?" y que produzcan el mismo resultado
Observacin: La expresin1 suele contener la inicializacin de las variables que intervienen en el bucle. La expresin2 suele contener las instrucciones necesarias para actualizar parte de dichas variables. Ejemplo:
// contando del 1 al 10 int i; for (i=1; i<=10; i++) System.out.print(i); // escribir i
Cundo usar while y cundo for? En general se utiliza for cuando el nmero de iteraciones se puede determinar antes de comenzar, es decir no depende de valores que se obtienen en el bucle, y while en otro caso.
Observacin: Los valores de tipo String no se deben comparar con == porque String no es un tipo primitivo. Para ver si un String es igual a otro se usa el mtodo equals, que compara objetos tal y como ilustra el ejemplo.
finally native
continue for
synchronized enum
1.- Qu es un objeto?
1.1 Concepto de objeto 1.2 Acceso a los componentes de un objeto 1.3 Mtodos 1.4 Los dos puntos de vista
El conjunto de atributos de un objeto identifica su estado, que puede variar en el tiempo. Aunque al frenar la velocidad de mi bicicleta vare, o Bertoldo cumpla un ao ms, o movamos el rectngulo a otra posicin no se consideran objetos diferentes (un Budista Zen no estara de acuerdo). Por tanto el conjunto de atributos y mtodos es siempre el mismo, pero no el estado (contenido de los atributos), que ir cambiando a lo largo de la vida del objeto. Los objetos se representan en los programas mediante variables del tipo (clase) adecuados.
De igual manera se podra acceder a los atributos si estos se declaran como public pero salvo excepciones esto no se hace as. La razn es que pudiramos podramos llevar al objeto a un estado inconsistente.
Ejemplo 1: En el caso de la bicicleta podemos pensar que la velocidad se calcula a partir de la marcha que est seleccionada y del nmero de giros por minuto. Permitir que se cambie la velocidad arbitrariamente incumplira esta relacin y dara lugar a valores inconsistentes.
Ejemplo 2: Igualmente podemos pensar que la bicicleta tiene un nmero de marchas limitado. A travs del mtodo cambiaMarcha() podemos controlar que no se sobrepase este lmite: por ejemplo se puede mostrar un mensaje de error si se intenta superar el mximo, o simplemente ignorar la peticin; pero dejar que el usuario del objeto cambie la marcha directamente puede dar lugar a estados del objeto no permitidos, y por tanto a errores en el programa difciles de detectar.
A la posibilidad de ocultar partes del objeto del exterior se la conoce como encapsulacin. Para consultar y modificar los atributos se deben utilizar los mtodos del objeto.
1.3 Mtodos
En C, Pascal, Fortran y otros lenguajes similares las variables se pasan a los procedimientos, funciones, etc. que las utilizan. En los lenguajes orientados a objetos, los mtodos expresan acciones que los objetos pueden llevar a cabo.
Observacin: En programacin orientada a objetos se les pide a los objetos que efecten acciones llamando a sus mtodos.
Decir que la instruccin significa mostrar "ventana" no sera correcto; sera mejor decir que la instruccin le pide a "ventana" que se muestre. Nos fijamos ahora en la siguiente instruccin:
miBicicleta.cambiaMarcha(1);
Le pedimos a la bicicleta que cambie de marcha. Puede ser que la bicicleta no nos haga caso; por ejemplo si esta en la marcha 3 y necesita que se disminuya de una en una. Si es posible acceder a la peticin el mtodo modificar el estado del objeto, cambiando los atributos marcha y velocidad. Por ltimo:
bertoldo.prestameUnosEurosAnda(100);
Esta divisin genera dos puntos de vista, segn al lado de la barrera en el que nos situemos: El usuario del objeto. Ve el objeto desde fuera. Dado que los atributos no se pueden modificar, no importan. Slo se fija en los mtodos a los que s puede acceder.
Ejemplo: Al utilizar el objeto miBicicleta nos da igual si existe un atributo velocidad o si sta se calcula a travs de otros atributos cuanto hace falta; lo nico que importa es saber que existe un mtodo valorVelocidad() para obtener el valor de la velocidad, no cmo se las apaa el objeto para conseguirlo.
El diseador de la clase a la que pertenece el objeto. Se puede imaginar que se encuentra "dentro" del objeto, pudiendo acceder a sus atributos y modificarlos libremente, as como usar los mtodos. Debe pensar en los mtodos que debe proporcionar al usuario del objeto.
Ejemplo: Al disear el objeto miBicicleta hay que tomar decisiones tales como debe incluirse un atributo velocidad? debe ser un nmero entero o real? debe proporcionarse al usuario un mtodo para acceder al atributo, caso de incluirse?
Los dos puntos de vista pueden corresponder a la misma persona en diferentes momentos: nosotros seremos usuarios de los objetos que hemos diseado previamente. Esta dualidad (casi esquizofrenia) debe tenerse presente en todo momento.
Observacin : Java permite encapsular los atributos pero no obliga a hacerlo; deja la decisin al programador. En (raras) ocasiones se puede decidir que algn atributo (generalmente un atributo constante) no est encapsulado. Otras veces (ms frecuentemente) decidiremos que algunos mtodos estn encapsulados porque son internos a la clase y conceptualmente no deben ser visibles para el usuario.
Observacin : Para indicar que un atributo, mtodo o clase es accesible para el usuario (es decir no est encapsulado) se escribe precedido por la palabra public. Cuando s est encapsulado se
Observacin : Para distinguir mejor estos dos puntos de vista en el este captulo nos vamos a concentrar slo en el punto de vista del usuario de objetos. En el siguiente captulo nos centraremos en el de diseador.
Definicin: Una clase es una nocin abstracta. Define los atributos y mtodos comunes a un conjunto de objetos.
Por tanto en lugar de disear cada objeto por separado se escribe una clase que contendr la "idea" comn de todos los objetos del mismo tipo. Ejemplos:
miBicicleta podra ser un objeto de clase Bicicleta:
Observacin: Hay ciertas clases para las que no tiene sentido declarar objetos. Un ejemplo es la clase Math que veremos posteriormente. A estas clase se las llama estticas.
mecanica.movimiento
Class Particula
java.lang.Object mecanica.movimiento.Particula
Field Summary
private vx
Constructor Summary
Particula()
Method Summary
double getVx()
velocidad en x de la partcula
double getVy()
velocidad en y de la partcula
double getX()
coordenada x de la partcula
double getY()
coordenada y de la partcula
double mduloVelocidad()
modifica la posicin de la partcula suponiendo que se mueve a la velocidad actual durante t segundos y que parte de la posicin actual.
Indica si sta partcula puede chocar con la partcula p para algn tiempo t para algn t puede ser positivo, negativo o 0, es decir si las dos trayectorias se cruzan o si por el contrario son paralelas
void setVx(double nuevaVx)
Vamos a ver cmo aprovechar esta informacin para definir y manejar objetos de la clase: Paquete: Lo primero que debemos conocer es el paquete al que pertenece la clase para importarla. La nica excepcin son las clases que pertenecen al paquete del sistema java.lang que estn ya importadas por defecto. A este paquete pertenecen, entre otras, las clases System, String y Math, lo que explica que nunca tengamos que importarlas. Como hemos visto la clase Scanner pertence al paquete java.util, y vemos que la clase Particula pertenece a un paquete mecanica.movimiento. Por tanto una clase Principal que utilice estas dos clases comenzar:
import java.util.Scanner; import mecanica.movimiento.Particula; public class Principal {
Atributos pblicos: En ocasiones las clases disponen de atributos pblicos, en particular de constantes. Veremos ejemplos cuando estudiemos la construccin de interfaces grficos. Como vemos en la seccin Field Summary, la clase Particula tiene 4 atributos de tipo double: x,y,vx,vy. Las coordenadas (x,y) indican la posicin de la partcula, mientras que (vx,vy) indican su velocidad. Sin embargo se trata de atributos privados, por lo que no podemos acceder a ellos directamente, slo a travs de las constructoras y mtodos. Constructoras: Se trata de un tipo especial de mtodos que sirven para crear e inicializar objetos de una clase. Reciben como parmetro valores que permiten inicializar el objeto y su nombre coincide con el de la clase. Siempre se usan precedidos por la palabra reservada new. Ya hemos visto un primer ejemplo con la clase Scanner
Scanner sc = new Scanner(System.in);
En este caso la constructora recibe como parmetro el fichero del que se va a leer. Supongamos que nos dicen que la clase Partcula tiene las siguientes constructoras: Particula(): Constructora por defecto, crea una partcula situada en el origen de coordenadas y con velocidad (0,0). Partcula(double xIni, double yIni, double vxIni, double vyIni): Construye una partcula situada en el punto (xIni,yIni) origen de coordenadas y con velocidad (0,0). Entonces las siguientes declaraciones e inicializaciones de son vlidas:
Particula p1 = new Particula(); Particula p2 = new Particula(10,10,-5.5,8.2); p1
es por tanto la partcula situada en el punto (0,0) y con velocidad (0,0), mientras que p2 est situada sobre el punto (10,10) y se mueve con velocidad -5.5 en x y 8.2 en y. Tanto p1 como p2 son objetos de la clase Particula.
Observacin: En Java el programador se encarga de crear objetos, pero no de destruirlos. Esto lo hace Java automticamente cuando detecta que el objeto ya no puede ser utilizado. A este mecanismo se le llama recogida automtica de basura. Si en algn caso interesa forzar a Java a liberar un objeto podemos usar el mtodo System.gc().
Pregunta 2.b Aunque la clase Particula no hubiese ningn mtodo mduloVelocidad() nosotros, como usuarios de la clase, podramos calcular el mdulo apoyndonos en el resto de los mtodos. Demustralo completando el siguiente ejemplo:
import mecanica.movimiento.Particula; public class Principal { public static void main(String[] args) { Particula p; // por aqu se le da el valor a p // no importa cmo ni qu valor .........
Ayuda: Para calcular la raz cuadrada de un nmero real x se utiliza en Java una llamada de la forma Math.sqrt(x).
Mtodos modificadores: Cambian los atributos del objeto. En la clase Particula los mtodos setX, setY, setVx, setVy y posicin son modificadores. Un ejemplo de utilizacin de estos mtodos:
import mecanica.movimiento.Particula; public class Principal { public static void main(String[] args) { Particula p = new Particula(10,10, 2,0); // la partcula se mueve durante 20 segundos p.posicin(20); System.out.println("x: "+p.getX()+" y: "+p.getY()); } }
Observacin: La divisin entre mtodos observadores y mtodos modificadores es slo conceptual: algn mtodo puede ser las dos cosas o no encajar bien en ninguna de las dos.
figuras
Class Rectangulo
java.lang.Object figuras.Rectangulo
Clase que representa un rectngulo con lados paralelos a los ejes de coordenadas
Field Summary
private lx int ancho (lx) y alto (ly) del rectngulo private ly int ancho (lx) y alto (ly) del rectngulo private x int esquina superior izquierda del rectngulo private y int esquina superior izquierda del rectngulo
Constructor Summary
Method Summary
int rea()
cambia la esquina sup. izquierda del rectngulo Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
La idea abstracta de clase se concreta al definir un objeto particular. Como hemos visto las definiciones de los objetos se hacen igual que las de los tipos simples:
nombreDeTipo nombreDeVariable;
Muy Importante: El objeto tras ser declarado no est listo para ser usado. Antes necesita
ser inicializado.
Hay dos formas de inicializar un objeto: Mediante el operador new() . Por ejemplo:
a = new Rectngulo(10,10,20,20) v = new Frame("Una ventana");
En este caso se crea una nueva variable de tipo Rectngulo. Los valores entre parntesis corresponden a los argumentos de la csntructora declarada en la clase (en este caso son los valores iniciales de los atributos). Mediante la asignacin de una variable del mismo tipo que ha sido previamente inicializada.
b = a;
Observacin: Un mismo objeto puede ser inicializado varias veces a lo largo de un programa. Lo nico que hay que tener en cuenta es que al inicializarse se pierden los valores anteriores de sus atributos.
Aunque casi siempre hablaremos de la variable que contiene la referencia al objeto como si fuera el propio objeto, interesa recordar que se trata de conceptos diferentes. Esto es especialmente importante cuando se realiza una asignacin entre variables de tipo objeto. Veamos el siguiente programa:
Principal.java
import figuras.Rectngulo; public class Principal { public static void main(String[] args) { int a,b; a = -5; b = a; b = 10; System.out.println("a: "+a); Rectngulo r,s; r = new Rectngulo(0,0,50,80); s = r; s.mueve(30,20); System.out.println("r.x: "+r.getX()+" r.y: "+r.getY()); } }
Est claro que este programa comenzar escribiendo a: -5 , ya que la asignacin b=10 no modifica el valor de a, que nunca deja de ser -5. Sin embargo la segunda parte del programa ya no es tan inmediata, al ser r,s referencias a objetos. Tras la declaracin Rectngulo r,s; las dos referencias estn an sin inicializar y contienen un valor especial llamado null.
La instruccin s = r; inicializa s con el valor de r. Pero en este punto hay que recordar que r no contiene ningn objeto, sino una referencia a un objeto, y es la referencia lo que se copia a s:
De esta forma, a pesar de tener dos variables de tipo rectngulo inicializadas tenemos un nico objeto y no dos. En realidad se puede decir que tras la asignacin s y r son la misma variable. La instruccin s.mueve(30,20); llama al mtodo mueve del objeto referenciado por s, que modifica sus atributos x e y:
Al quedar modificado el objeto referenciado por s queda igualmente el referenciado por r, ya que son el mismo. Dicho de manera poco rigurosa pero que puede aclarar:
Aviso: El concepto de referencia es fundamental en Java. Muchos errores de programacin en este lenguaje provienen de olvidar que las variables tipo objeto son en realidad referencias a objetos.
Aviso: Si comparamos dos objetos con == estamos comparando si son referencias al mismo objeto. Para saber si se trata realmente de dos objetos con los mismos atributos debemos usar el mtodo equals de cualquiera de los dos objetos. Este mtodo siempre est definido.
Principal.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
import figuras.Rectngulo; public class Principal { public static void main(String[] args) { rec1 = new Rectngulo(3,4,5,6); Rectngulo a = new Rectngulo(0,0,5,10); Rectngulo b = new Rectngulo(0,0,20,30); Rectngulo c = b = a; Rectngulo d; System.out.println("c.x: "+c.x+ " b.x: "+b.x+ " a.x: "+a.x); System.out.println("c.x: "+c.getX()+ " b.x: "+b.getX()+ " a.x: "+a.getX()); d.mueve(80,80); d = a; d.mueve(80,80); System.out.println("a.x: "+a.getX()+ " a.y: "+a.getY()); System.out.println("d.x: "+d.getX()+ " d.y: "+d.getY()); d = new Rectngulo(0,0,0,0); System.out.println("a.x: "+a.getX()+ " a.y: "+a.getY()); System.out.println("d.x: "+d.getX()+ " d.y: "+d.getY()); } }
public class Matemticas { public static void main(String [] args) { double x = Math.PI/2; int a = -3; // valor absoluto System.out.println(Math.abs(x));// 1.5707963267948966 System.out.println(Math.abs(a));// 3 // redondeo al entero (largo) mas proximo System.out.println(Math.round(3.8));// 4 // redondeo al entero mas proximo repr. como double System.out.println(Math.rint(3.8));// 4.0 // exp(x) y log(x): e^x y ln x respect.
Estas son las clases para representar secuencias de caracteres. Las 2 clases forman parte del paquete java.lang un paquete que es importado en todas las clases sin necesidad de hacerlo explcitamente.
3.2.1 La clase String Se llaman strings a las secuencias de caracteres. Es un tipo muy importante que ya hemos estado utilizando, por ejemplo al escribir System.out.println("hola"), el valor "hola" es una constante de tipo String. En Java se definen dos clases diferentes para manipular cadenas de caracteres: la clase String y la clase StringBuffer. La diferencia es que una vez creado un objeto de tipo String no puede modificar su contenido. En cambio la clase
public class EjemploString { public static void main(String [] args) { // constructoras String s1 = new String("Nadie emprende"); String s2 = new String(); s2 = "este camino"; String s3 = "salvo el crepsculo de otoo"; System.out.println(s1); System.out.println(s2); System.out.println(s3); // longitud de un String (un entero) System.out.println(s2.length()); // 11 // carcter en una posicin determinada. // se comienza a contar desde 0 System.out.println(s1.charAt(0)); // N System.out.println(s1.charAt(1)); // a System.out.println(s3.charAt(s3.length()-1)); // ? System.out.println(s2.charAt(s2.length())); // ? // ----- COMPARACIN ------// esta igualdad pregunta que si son el mismo objeto String a="una cadena"; String b="una cadena"; System.out.println( a==b); // true !!!! // as se pregunta que si tienen la misma cadena System.out.println(a.equals(b)); // true System.out.println(a.equals("Una Cadena")); // ? // igual pero sin tener en cuenta las mayusculas/minusculas System.out.println(a.equalsIgnoreCase("Una Cadena"));// ? // -- BSQUEDA --// posicin que ocupa la primera aparicin del carcter System.out.println(s1.indexOf('e')); // 4 // posicin que ocupa la primera aparicin del carcter // empezando a mirar desde la posicin indicada System.out.println(s1.indexOf('e',5)); // ? // posicin que ocupa la ultima aparicin del carcter System.out.println(s1.lastIndexOf('e')); // 13 // posicin que ocupa la ultima aparicin del carcter // acabando de mirar en la posicin dada
} }
Observacin: El smbolo de concatenacin + puede utilizarse tambin con tipos numricos, como por ejemplo:
String s = "Un euro son " + 166.386 + " ex-pesetas";
Aunque a menudo no es necesario (el tipo String se puede utilizar para construir otros Strings) la clase StringBuffer incluye operaciones especficas para modificar su contenido. La clase BufferString incluye todos los mtodos que hemos visto para String (y que no repetimos en el ejemplo), con excepcin de los mtodos de concatenacin y las constructoras, que son diferentes:
EjemploStringBuffer.java
Observacin: Suele llamarse toString() al mtodo utilizado para convertir un objeto en String. Java hace que todos las clases incluyendo dicho mtodo sean compatibles con el tipo String.
4.- Arrays
4.1 Introduccin 4.2 Declaracin e Inicializacin de arrays 4.3 Acceso a los elementos de un array 4.4 Arrays multidimensionales
4.1 Introduccin
Los arrays, o matrices se sitan a medio camino entre los tipos simples y las clases. Una definicin inicial sera la siguiente: Un array es una coleccin, ordenada secuencialmente, de elementos del mismo tipo.
Al tipo de los elementos del array se le llama tipo base, y puede ser bien un tipo simple o el nombre de una clase. La posicin que ocupa cada elemento se llama ndice del elemento.
Observacin: Como es habitual en Java, el ndice del primer elemento ser el 0. Por tanto un array de n elementos estar definido para valores ndice entre 0 y n-1.
Ejemplos:
Particula []puntos; // array de partculas String []palabras; // array de strings boolean []lgicos; // array de valores booleanos
Observacin: A diferencia de otros lenguajes, el tamao del array no se indica en la declaracin. Dicho valor se fijar en la creacin del array.
Importante: Igual que sucede con los objetos, los arrays no pueden ser utilizados hasta que hayan sido inicializados (pueden imaginarse como referencias).
Hay 3 formas de inicializar un array: 1. Dar valores al declarar la variable Este mtodo se utiliza cuando los valores se conocen de antemano. El tamao queda fijado implcitamente por el nmero de elementos en la lista de inicializacin. tipoBase []nombreVariable = {valor1, ..., valorn}; Ejemplos:
2. Con el operador new Igual que se hace con los objetos, pero indicando el tamao del array, pero siguiendo la sintaxis: nombreVariableArray = new tipoBase[tamaoArray];
Ejemplos:
// se puede inicializar a la vez que se crea Particula []partculas = new Particula[5]; // o despus Particula []msPartculas; msPartculas = new Particula[100]; // se puede hacer new varias veces, como ocurre con los objetos // pero recordar al hacerlo se pierde el valor anterior particulas = new Particula[10];
3. Asignndole otro array ya inicializado Igual que hemos visto en el caso de los objetos Ejemplos:
Particula []partculas = {new Particula(3.5,2.4,-1.0,-1.0), new Particula(), new Particula()};
Las operaciones que se pueden hacer con la variable as obtenida son todas las que permita su tipo, que es el tipo base. Ejemplo: Usamos la clase Complejo que representa un nmero complejo de la forma x+yi, con constructora Complejo(double x, double y), mtodos de consulta valorX(), valorY(), toString() (que devuelve un String de la forma x+yi) y mtodos de modificacin
ponX(double), ponY(double)
Complejo
puntos[0].ponX(3); System.out.println(puntos[0]); Complejo c = new Complejo(10,10); puntos[2] = c; c.ponX(11); System.out.println(puntos[2].valorX()); puntos[2].ponX(puntos[2].valorX()+1)); System.out.println(c); puntos = new Complejo[10]; System.out.println(puntos[3]);
Importante: Si tratamos de acceder a una posicin fuera del lmite del array obtendremos una excepcin ArrayIndexOutofBoundsException.
int i; Complejo
// mostrar todos los elementos del array for (i=0; i<puntos.length; i++) System.out.println(puntos[i]); puntos = new Complejo[10]; for (i=0; i<puntos.length; i++) puntos[i] = new Complejo(i,i); // mostrar todos los elementos del array for (i=0; i<puntos.length; i++) System.out.println(puntos[i]); // esto NO se puede hacer, dara error al compilar // puntos.length++;
import complejos.Complejo; public class Principal { public static void main(String[] args) { // array de 3 por 2 complejos Complejo matriz[][] = { {new Complejo(1,1), new Complejo(2,2)}, {new Complejo(3,3), new Complejo(4,4)}, {new Complejo(5,5), new Complejo(6,6)}}; muestra(matriz); System.out.println(matriz[3][1]); // otra matriz de 3 por 2 Complejo otra[][] = new Complejo[3][2]; // escribir cdigo para que el contenido de la matriz sean los nmeros // 0+0i 0+1i // 1+0i 1+1i // 2+0i 2+1i .... .... .... .... muestra(otra); Complejo rara[][] = new Complejo[5][]; // 5 filas for (f=0; f<rara.length; f++) { // la fila f tendr f columnas con los numeros 0+0i....(f-1)+0i rara[f] = new Complejo[f]; for (c=0; c<rara[f].length; c++) rara[f][c] = new Complejo(c,0); } muestra(rara); } // main
public static void muestra(Complejo [][]t) { int fila, columna; for (fila=0; fila<t.length; fila++) { for (columna=0; columna<t[fila].length; columna++) System.out.print(t[fila][columna]+" "); System.out.println(""); } // for fila } // muestra
0.0i 0.0i 1.0 + 0.0i 0.0i 1.0 + 0.0i 2.0 + 0.0i 0.0i 1.0 + 0.0i 2.0 + 0.0i 3.0 + 0.0i
5.1 Introduccin
Vamos a ver en este apartado un conjunto de clases que se utilizan para representar los tipos primitivos como clases. Cada objeto de una de estas clases tendr un slo atributo: el valor de tipo primitivo que el objeto "envuelve". Estos tipos resultan tiles por dos razones: Utilizar mtodos especficos de cada tipo (casi siempre estticos). Convertir los tipos simples en objetos cuando resulte necesario. En relacin con el segundo punto slo es necesario saber que: Todas las clases "envoltura" tienen una constructora con un parmetro; el valor de tipo simple que queremos "envolver".
Principal.java
public class Principal { public static void main(String[] args) { Integer a = new Integer(3); // "envolvemos" el 3 System.out.println(a.intValue()); // "desenvolvemos" el 3 Character c = new Character('v'); System.out.println(c.charValue()); Double d = new Double(1.717225); System.out.println(d.doubleValue()); Boolean b = new Boolean(true); System.out.println(b.booleanValue()); } }
Aunque la utilidad de envolver un tipo simple no se ver hasta que tratemos los vectores, en el siguiente punto. Las siguientes secciones muestran algunos de los principales mtodos estticos incluidos en las clases envoltura.
5.2 Enteros
Vemos los mtodos principales de la clase Integer mediante un ejemplo:
Ejemplo
import java.io.*; // para BufferReader public class Principal { public static void main(String[] args) { int a = 19123; // cambios de base String aEnBinario = Integer.toBinaryString(a); String aEnOctal = Integer.toOctalString(a); String aEnHexadecimal = Integer.toHexString(a); // con toString se puede convertir a una base cualquiera
Observacin: Existen tambin las clases Byte, Short y Long, anlogas a la clase Integer
5.3 Caracteres
Dentro de la clase Character pueden interesarnos los siguientes mtodos:
static boolean isDigit(char c); // true si c es un dgito, false e.o.c. static boolean isLetter(char c); // true si c es una letra (minscula o mayscula), false e.o.c. static boolean isLetterorDigit(char c); static boolean isLowerCase(char c); // true si es minscula, false e.o.c. static boolean isUpperCase(char c); // true si es mayscula, false e.o.c. static char toLowerCase(char c); // convierte el carcter en minscula, o lo deja tal cual si no es una letra static char toUpperCase(char c); // convierte el carcter en mayscula, o lo deja tal cual si no es una letra
5.4 Reales
Dentro de la clase Double pueden interesarnos los siguientes mtodos:
5.5 Lgicos
Esta clase no contiene mtodos de inters.
5.6 Boxing
Desde la versin 1.5 de Java la conversin entre tipos envoltura y su correspondiente tipo bsico se hace automticamente como muestra el siguiente ejemplo:
Integer i = 5; // esto daba error en la versin 1.4 Integer j = new Integer(6); int x = j; // esto tambin daba error en la versin 1.4
6.1 Introduccin
Los arrays son muy tiles, pero tienen algunas desventajas:
No se puede variar su tamao dinmicamente. En particular no se pueden eliminar elementos ni insertar nuevos elementos.
Para superar estos inconvenientes, cuando resulte necesario, existe en java la clase Vector del paquete java.util.
Observacin: Los vectores son un ejemplo de coleccin. Adems de vectores Java permite otro tipo de colecciones como conjuntos (set) pilas (stack) o colas (queue) .
Observacin: En Java 1.5 tambin se puede declarar un vector sin especificar su tipo: Vector v = new Vector() pero se obtiene un aviso del compilador con la etiqueta warning.
dar un error de compilacin. Para declarar vectores (o en general cualquier clase genrica) que almacene valores de tipos primitivos se utilizan los tipos envoltura vistos en el punto anterior. Por ejemplo, el vector anterior se declara:
Vector<Integer> v = new Vector<Integer>();
Observacin: Internamente el vector es en realidad una clase con un atributo tipo array. Cuando le pedimos que cambie su tamao se declara un nuevo array, copiando la informacin que haga falta del antiguo al nuevo.
Ejemplos: Para representar una clase Complejo representando un nmero complejo sobre el plano necesitamos dos atributos de tipo real (para la parte real e imaginaria). La clase comenzar as:
public class Complejo { private double x; // parte real private double y; // parte imaginaria ..... }
Observacin: Las constructoras tienen 3 caractersticas que las distinguen del resto de los mtodos: Se llaman igual que la clase. No tienen tipo de salida (ni siquiera void). Slo se llaman una vez por objeto, cuando ste se cre con new. No pueden llamarse explcitamente (sin new).
A la hora de disear una clase es muy importante definir de qu constructoras dispondr la clase
Ejemplo:
En la clase Complejo podemos pensar en dos constructoras: una sin argumentos que construye el complejo 0+0i, y otra que recibe los dos valores
public class Complejo { private double x; // parte real private double y; // parte imaginaria // constructoras public Complejo() {x=y=0;} public Complejo(double laX, double laY) { x = laX; y = laY; } }
Aviso: Una vez incluida una constructora con argumentos, la constructora sin argumentos deja de existir, por lo que si queremos seguir usndola hay que incluirla explcitamente, como en el ejemplo anterior.
Ejemplos de uso:
Persona p1 = new Persona("Bertoldo","Gonslvez de la Cuaderna"); Persona p2 = new Persona("Casilda", "Bronciales", 22);
dara error de compilacin al no tener la clase Persona ninguna constructora sin parmetros.
En el juego de las 3 en raya hacemos que la constructora por defecto construya el tablero, con todas sus casillas vacas y fije el turno para el jugador 1:
// clase para representar el juego de las tres en raya public class TresEnRaya { // tipos auxiliares para representar los jugadores y los valores de la casilla private enum Jugadores {JUGADOR1,JUGADOR2}; private enum Casilla {VACA,FICHAJUG1,FICHAJUG2}; // tablero private Casilla tablero[][]; // jugador que tiene el turno private Jugadores jugConTurno; // constructora public TresEnRaya() { // creamos el array tablero = new Casilla[3][3]; // lo inicializamos for (int i=0;i<3;i++) for (int j=0; j<3; j++) tablero[i][j] = Casilla.VACA; // fijamos el turno jugConTurno = Jugadores.JUGADOR1; } }
Gracias a this el objeto puede referirse a si mismo como si de un objeto ms se tratara. Iremos viendo su utilidad poco a poco, pero podemos empezar por una de sus aplicaciones ms comunes (aunque no la ms interesante): permitir acceder a los atributos del objeto desde mtodos cuyas variables locales lo hacen invisible. Veamos un ejemplo:
Entonces, en la instruccin y=x*x; de cul de las dos x se est hablando? La norma general en Java es que en caso de duda tiene preferencia la variable definida en un mbito ms prximo (esto se explicar con detalle despus), por lo que se trata de la variable local. Para referirnos a la x atributo utilizamos la expresin this.x indicando de esta forma la x que es parte de este objeto (y que slo puede ser un atributo, nunca una variable local).
Observacin: A raz de esto surge una pregunta por qu no da el compilador error en this.x si x es una variable privada?. La respuesta es que Java permite a los objetos de una clase dada acceder a los componentes privados de otros objetos de la misma clase.
El ejemplo anterior puede parecer forzado; no sera mejor simplemente evitar la repeticin de nombres? Aunque esto es posible, a veces resulta ms cmodo utilizar nombres repetidos. Un caso tpico son los nombres de los argumentos que contienen los valores iniciales de los atributos, como en el siguiente ejemplo:
public class Complejo { private double x; // parte real private double y; // parte imaginaria // constructoras public Complejo() {x=y=0;} public Complejo(double x, double y) { this.x = x; this.y = y; } }
Observacin: Algunos autores recomiendan escribir siempre la palabra this delante del nombre de un atributo, aunque no haya posibles ambigedades.
Pregunta 3.b Qu valor tomar el atributo x tras crearse un objeto de la clase cuyo cdigo se muestra a continuacin?
public class Rarsima { private int x; public Rarsima() { x = 5; int x = 6; x = this.x + x; this.x += x; } }
La declaracin de la cabecera de un mtodo general perteneciente a una clase sera: tipoAcceso static abstract final native synchronized tipoSalida nombreMtodo(tipo1 arg1, ...., tipon argn) throws listaExcepciones
Las palabras en itlica son opcionales, mientras que las que estn en negrita son obligatorias. Normalmente la declaracin se simplificar a algo como: public tipoSalida nombre(tipo1 arg1, ...., tipon argn) (public es uno de los tipos de acceso). En los siguientes apartados y en captulos posteriores veremos muchas de las palabras opcionales con su significado. De momento, algunas observaciones: Si la lista de argumentos es vaca no se pone nada entre parntesis:
public double valorX() { return x; }
Es obligatorio que la funcin tenga un tipo de salida. Si no queremos que la funcin devuelva nada, o bien queremos que lo haga a travs de sus argumentos usaremos el tipo especial void como valor de salida. void es un tipo que no contiene ninguna constante, un tipo sin valores.
public void saluda() { System.out.println("Qu tal?"); return; // no es necesario, pero puede ponerse }
Tanto el tipo de salida como los tipos de los argumentos pueden referirse tanto a tipos simples como a objetos (i.e. a referencias a objetos). En la lista de argumentos slo se incluyen los nombres de los argumentos de llamada y su tipo, sin ningn calificador (ni var ni const ni &, ni nada). En los siguientes apartados veremos por qu.
Importante: El tipo de la expresin que se escribe tras return tiene que ser el mismo que el indicado como tipo de salida de la funcin en la cabecera.
Una excepcin es el caso de una funcin de tipo void, en la que no hace falta poner la palabra return:
public void cuentoCorto() { System.out.println("Nadie quera decirle a qu hora pasara el tren."); System.out.println("Le vean tan cargado de maletas que les daba pena"); System.out.println("explicarle que all no haba habido nunca"); System.out.println("ni vas ni estacin"); }
Aunque en este caso tambin puede escribirse, pero sin ninguna expresin al lado:
public void beso() { System.out.println("Un beso de amor aparta el tiempo"); return; }
package complejos; public class Complejo { // atributos, representan el nmero x+yi private double x,y; // constructoras public Complejo() { x=y=0;} public Complejo(double x, double y) {this.x=x; this.y=y;} // mtodos public void ponX(double nuevaX) { x = nuevaX;} public void ponY(double nuevaY) { y = nuevaY;} public double valorX() { return x; } public double valorY() { return y; } public double mdulo() { return Math.sqrt(x*x + y*y); }
Supongamos que queremos incluir un mtodo en la clase Complejo que permita calcular el conjugado. Tenemos 3 posibilidades:
b) Declarar el mtodo de tipo Complejo, y hacer que el objeto no quede modificado, sino que
devuelva un nuevo objeto con su conjugado.
public class Complejo { private double x,y: // x es la parte real, y la imaginaria // por aqu iran los otros mtodos de la clase .... .... // crear un nuevo nmero complejo, conjugado del actual // el actual no vara public Complejo conjugadoV2() { Complejo nuevo = new Complejo(); nuevo.ponX(x); nuevo.ponY(-y); return nuevo; } }
c) Declarar el mtodo de tipo Complejo, y hacer que el objeto quede modificado, y se devuelva a si
mismo como resultado:
package complejos; public class Complejo { private double x,y: // x es la parte real, y la imaginaria // por aqu iran los otros mtodos de la clase .... .... // crear un nuevo nmero complejo, conjugado del actual // el actual no vara public Complejo conjugadoV3() { y = -y; return this; } }
Aviso: Un error comn es pensar que toString tiene que escribir algo por pantalla. Slo tiene que devolver un valor de tipo String
Aviso: Si no definimos un mtodo toString el sistema incluye uno por defecto, que se encargar de devolver una cadena de caracteres representando la referencia contenida en el
equals Como vimos en el tema anterior no se debe usar el operador == para comparar objetos, ya que esta operacin slo comparar las referencias a dichos objetos, devolviendo true si se trata de dos referencias al mismo objeto, o false en caso contrario. Por ejemplo un programa como:
import complejos.Complejo; public class Principal { public static void main(String[] args) { Complejo c1 = new Complejo(3,4); Complejo c2 = new Complejo(3,4); System.out.println(c1==c2); } }
escribir false porque c1 y c2 se trata de dos referencias a objetos diferentes. Si lo que deseamos es saber si los dos objetos contienen el mismo nmero complejo se debe utilizar el mtodo equals, que debe ser definido de la forma adecuada en la cada clase. En el caso particular de la clase Complejo, un posible mtodo equals sera:
public boolean equals(Complejo c) { return this.x == c.x && this.y==c.y; }
Aviso: Siendo precisos, la definicin de equals del ejemplo para la clase Complejo no es del todo correcta: Java pide que equals sea capaz de comparar un objeto con cualquier otro, sea o no de su misma clase, mientras que el cdigo que hemos escrito slo permite comparaciones con otro nmero complejo. En captulos posteriores mejoraremos la deficin para que el mtodo admita objetos de otros tipos (en cuyo caso devolver true ).
clone Tambin hemos visto en el captulo precedente que una expresin de la forma c1=c2; con c1, c2 objetosm no hace que c2 sea una copia de c1, sino una nueva referencia a c1. Para conseguir crear nuevos objetos que sean copias de objetos ya existentes debemos definir y utilizar el mtodo clone. Una posible definicin de clone para la clase Complejo sera:
public Complejo clone() { return new Complejo(this.x,this.y); }
Una vez definido este mtodo podemos crear copias de objetos ya existentes:
import complejos.Complejo; public class Principal { public static void main(String[] args) { Complejo c1 = new Complejo(3,4); Complejo c2 = c1.clone(); c2.ponX(7.0); System.out.println(c1); System.out.println(c2); } }
Observacin: se puede pensar que las variables que aparecen en la cabecera son variables locales a la funcin, con la particularidad de que reciben sus valores desde fuera, mediante los valores de llamada.
Los argumentos de tipos bsicos no quedan modificados aunque se modifiquen en un mtodo, no importa si de la propia clase o de una clase diferente:
Tonto.java
public class Tonto { public static void main(String [] args) { int x=5; incrementa(x); System.out.println(x); } public static void incrementa(int a) { a =a+1; } }
En el caso de los objetos se procede de igual forma; se copia el contenido de la variable a la variable local declarada en la cabecera del mtodo. Sin embargo hay una diferencia muy importante:
Observacin: como hemos visto las variables de tipos no bsico no contienen en realidad los objetos, sino referencias a los objetos. La copia a la variable de un mtodo ser de la referencia, no del objeto, y por tanto podremos modificar el objeto.
import complejos.Complejo; public class Intercambio { public static void main(String [] args) { Complejo c = new Complejo(); c.ponX(3); c.ponY(2); intercambia(c); System.out.println(c.valorX()); System.out.println(c.valorY()); } public static void intercambia(Complejo c) { // 2 variables locales con las partes reales e imaginarias de c double x = c.valorX(); double y = c.valorY(); // ponemos en x el valor y, y viceversa c.ponX(y); c.ponY(x);
Y an un ejemplo ms:
Raro.java
import complejos.Complejo; public class Raro { public static void main(String [] args) { Complejo c = new Complejo(); c.ponX(3); c.ponY(2); ponACeroV1(c); System.out.println(c.valorX()); System.out.println(c.valorY()); ponACeroV2(c); System.out.println(c.valorX()); System.out.println(c.valorY()); } public static void ponACeroV1(Complejo c) { Complejo a = new Complejo(); a.ponX(0); a.ponY(0); c = a; } public static void ponACeroV2(Complejo c) { c.ponX(0); c.ponY(0); } }
Observacin: Cuando un objeto se queda sin referencias que lo apunten es destruido por el sistema y su memoria liberada. Es lo que en Java se llama recogida automtica de basura.
1 2 3 4 5 6 7 8 9 10 11 12
Pregunta 3.k Indica qu valor toman las variables en cada fase del programa y cundo se crea y se puede destruir cada objeto.
Al igual que sucede con los objetos, los arrays se pasan por referencia a los mtodos. Por tanto si un mtodo modifica el contenido de un array ste queda modificado tambin fuera del mtodo.
muestra(puntos); incrementaXs(puntos); muestra(puntos); Complejo []puntos2 = {new Complejo(1,2), new Complejo(6,7)}; muestra(puntos2); tresCeros(puntos2); muestra(puntos2); } // main public static void muestra(Complejo []t) { for (int j=0; j<t.length; j++) System.out.println(t[j]); } public static void incrementaXs(Complejo []t) { for (int j=0; j<t.length; j++) t[j].ponX( t[j].valorX()+1); } public static void tresCeros(Complejo []t) { t = new Complejo[3]; for (int j=0; j<t.length; j++) t[j] = new Complejo(0,0); muestra(t); } }
Los mtodos estticos pueden utilizarse sin declarar ningn objeto, directamente como parte de la clase:
Principal.java import operaciones.Operaciones; public class Principal { public static void main(String [] args) { int a,b; // esto estara mal si "cuadrado" no fuera esttico porque "Operaciones" // no es un objeto sino una clase. a = Operaciones.cuadrado(3); b = Operaciones.cubo(4); System.out.println(a); System.out.println(b); } }
Observacin: El uso de mtodos estticos "rompe" la filosofa de Java y slo deben usarse en casos muy especiales. S se utilizan bastante las constantes estticas.
2.7 Sobrecarga
Algunas clase (como Complejo) tienen dos o ms constructoras, todas con el mismo nombre (el de la clase) pero con distinto nmero de argumentos. Esto no es especfico de las constructoras, sino que se puede hacer con cualquier mtodo, como por ejemplo:
Incrementos.java package operaciones; public class Incrementos { private int x; public Incrementos(int laX) { x = laX; } public int f(int a) { return a+x; } public int f(int a, int b) { return a+b+x; } }
A la hora de utilizar un mtodo u otro el sistema se fija en el nmero y tipo de los parmetros y en el valor de salida:
Principal.java import operaciones.Incrementos; public class Principal { public static void main(String [] args) { Incrementos v = new Incrementos(3); System.out.println(v.f(1)); System.out.println(v.f(2,3));
3.1mbitos
Se llama mbito a la regin de cdigo en la que una variable est definida. Inicialmente distinguimos 3 mbitos para las variables en Java: Atributos, globales a toda la clase. Variables locales de un mtodo. Parmetros de un mtodo. Veamos cada uno por separado:
Atributos Los atributos se declaran al comienzo de la clase (normalmente) y duran todo el tiempo que "vive" el objeto. Son visibles por todos los mtodos del programa siempre y cuando stos no tengan un parmetro o variable local que los oculte. Pueden inicializarse en la declaracin para darles un valor diferente del valor por defecto:
public class .... { private Complejo c= new Complejo(1.1,2); private int a = 2; public int f(int x) { return x+a+c.valorX(); } }
Variables locales
Parmetros de un mtodo: Siguen las mismas normas que para las variables locales, con la diferencia de que no se pueden inicializar; se inicializan automticamente con el valor que se les pasa como argumento.
Ejemplo:
public class .... { private int x=3; public void f(int x) { System.out.println(x+1) } public void g() { f(x); } }
1.1 Introduccin
Supongamos que deseamos escribir una clase para representar puntos con color (pixels). El punto de color vendr determinado por:
Dos valores tipo double x, y representando las coordenadas del punto. Un valor de tipo Color (una clase de Java para representar colores).
Supongamos tambin que queremos aprovechar que ya tenemos hecha la clase Complejo, lo que nos permite para manejar y actualizar los valores de las coordenadas x,y, es decir queremos reutilizar el cdigo de la clase. La primera posibilidad que se nos puede ocurrir es copiar el cdigo necesario a la clase nueva Importante: Un principio fundamental de ingeniera del software es nunca duplicar cdigo: cada vez que aada, modifique o corrija algo del cdigo original tendremos que hacer lo mismo con la copia. Todos los lenguajes modernos incluyen mecanismos para resolver esta situacin reutilizando el cdigo que hemos escrito. Vamos a estudiar dos posibles soluciones:
import java.awt.Color; public class Pixel { private Complejo punto; private Color color; // constructoras public Pixel () { punto = new Complejo(0,0); color = Color.black; } public Pixel(double x, double y, Color color) { punto = new Complejo(x,y); this.color = color; } public Color valorColor() { return color; } public void ponColor(Color color) { this.color = color; } }
import java.awt.Color; public class Principal { public static void main(String[] args) { Pixel pix = new Pixel(4,5,Color.red); pix.ponColor(Color.blue);
Pregunta 4.a En este programa hay algo mal; qu es? Por tanto si incluimos el objeto como un atributo perdemos el acceso directo a sus mtodos. Para recuperarlo hay que escribir mtodos intermedios de acceso:
Pixel.java
import java.awt.Color; public class Pixel { private Complejo punto; private Color color; // constructoras public Pixel () { punto = new Complejo(0,0); color = Color.black; } public Pixel(double x, double y, Color color) { punto = new Complejo(x,y); this.color = color; } public Color valorColor() { return color; } public void ponColor(Color color) { this.color = color; } public double valorX() { return punto.valorX(); } public void ponX(double nuevaX) { punto.ponX(nuevaX); } ..... }
Como se ve esta tcnica resulta incmoda, al obligarnos a incluir las funciones que hacen de "intermediarias" con el atributo. Sin embargo puede ser til cuando se trata de ocultar algunos de los mtodos.
1.3 Herencia
Empezamos con una definicin informal de herencia: Definicin: Decimos que una clase B hereda de una clase A cuando todos los objetos de B son tambin objetos de A. En este caso, diremos que B es la clase hija o subclase, o clase derivada, y A la clase madre o superclase.
Ejemplo:
Est definicin "filosfica" nos debe guiar durante el diseo de subclases, y tambin para comprender las particularidades de la herencia. En Java se indica que B es subclase de A mediante la palabra reservada extends: public class B extends A { .....
El comportamiento de una clase derivada queda explicado de manera general por la siguiente observacin: Observacin: Los mtodos (o atributos) pblicos de una clase A son automticamente convertidos en mtodos (o atributos) pblicos (ms adelante detallaremos qu sucede con los mtodos o atributos privados o con otro tipo de modificador de acceso).
import java.awt.Color; public class Pixel extends Complejo { private Color color; // constructoras public Pixel () { ponX(0); ponY(0); color = Color.black; } public Pixel (double laX, double laY, Color elColor) { ponX(laX); ponY(laY); color = elColor; } public Color valorColor() { return color; } public void ponColor(Color color) { this.color = color; } }
import java.awt.Color; public class Principal { public static void main(String[] args) { Pixel pix = new Pixel(4,5,Color.red); pix.ponColor(Color.blue); System.out.println(pix.valorColor()); System.out.println(pix.valorX()); // esto funciona! } }
Aclaracin: La lnea java.awt.Color[r=0,g=0,b=255] es el resultado de llamar al mtodo toString de la clase Color, que escribe los colores como combinaciones de rojo (r), verde (g), y azul (b), con valores entre y 255). De esta forma hemos aprovechado el cdigo de la clase Complejo. Ms an, si mejoramos esta clase mejoraremos tambin, automticamente, la clase Pixel. Observacin: La idea bsica de la reutilizacin es: "definir una vez, utilizar muchas". La programacin orientada a objetos naci teniendo en cuenta este concepto.
1.4 La decisin
Para elegir una u otra opcin (incluir uno o ms atributos de la clase inicial o heredar de ella) se debe contestar a la pregunta: Es todo objeto de tipo B un objeto de tipo A? A veces resulta sencillo contestar a la pregunta; por ejemplo un pixel es un punto, y por tanto un nmero complejo. Igualmente si queremos representar la clase recta e identificamos la recta por sus puntos inicial o final es obvio que una recta no es un punto, y que para definirla no usaremos herencia:
public class Recta { private Complejo puntoInicial, puntoFinal; ....
Otras veces la cosa no est tan clara: Un moto es una bicicleta? En ocasiones puede llegarse a la conclusin de que ninguna de las dos soluciones es la adecuada y que lo que hay que hacer es una clase nueva. O incluso puede ser que creamos conveniente utilizar las dos. Ejemplo: Supongamos que las coordenadas del pixel son las del origen de la pantalla (que es siempre la 0,0), pero que tambin tenemos que tener en cuenta dnde se haya situado el origen de coordenadas terico:
y que el pixel debe "saber" siempre donde est dicho centro terico. Entonces podemos escribir una clase como la siguiente:
PixelCentro.java
import java.awt.Color; public class PixelCentro extends Complejo { private Color color; private Complejo centro; public PixelCentro(double x, double y, Color color) { ponX(x); ponY(y); this.color = color; // inicializamos el centro a (0,0) centro = new Complejo(); } public void ponCentro(Complejo centro) { this.centro = centro; } public Complejo valorCentro() { return centro; } public void ponColor(Color color) { this.color = color; } public Color valorColor() { return color; } }
import java.awt.Color;
Si suponemos que ya habamos definido la clase Pixel podemos utilizar herencia y definir:
PixelCentro.java import java.awt.Color; public class PixelCentro extends Pixel { private Complejo centro; public PixelCentro(double x, double y, Color color) { ponX(x); ponY(y); ponColor(color); // inicializamos el centro a (0,0) centro = new Complejo(); } public void ponCentro(Complejo centro) { this.centro = centro; } public Complejo valorCentro() { return centro; } }
A partir de aqu suponemos PixelCentro definida de esta forma. Los siguientes puntos tratan de las caractersticas de las clases derivadas.
Sin embargo, el mtodo mdulo heredado de Complejo no tiene el comportamiento deseado, porque un cdigo como:
PixelCentro pixel = new PixelCentro(51,50,Color.blue); Complejo centro = new Complejo(50,50); pixel.ponCentro(centro); System.out.println(pixel.mdulo());
Escribe 71.42... y no 1 nos gustara. En este caso la solucin es redefinir en PixelCentro la funcin mdulo: PixelCentro.java
import java.awt.Color; public class PixelCentro extends Pixel { Complejo centro; ... public double mdulo() { return Math.sqrt( Math.pow(valorX()centro.valorX(),2)+Math.pow(valorY()-centro.valorY(),2)); }
Y ahora el cdigo anterior s escribe en pantalla 1.0. Observacin: La clase derivada puede modificar los mtodos de su superclase. En otras ocasiones no queremos cambiar sino "aumentar" el comportamiento del mtodo de la superclase. Por ejemplo:
Pixel pixel = new Pixel(51,50,Color.blue); System.out.println(pixel);
y por tanto se muestra por pantalla 51.0 + 50.0i. Esto no est mal, pero nos gustara que tambin se mostrara el color. Podemos entonces redefinir toString en la clase Pixel pero reutilizando el cdigo toString de la clase Complejo. Esto se hace as:
public class Pixel extends Complejo { ... public String toString() { return super.toString()+" Color: "+valorColor(); } ..... }
Ahora el cdigo anterior escribir 51.0 + 50.0i Color: java.awt.Color[r=0,g=0,b=255]. Aviso: Se puede utilizar super para acceder a los mtodos de la clase madre, pero no super.super para acceder a los de la "abuela".
Aviso: Las constructoras no se heredan. La palabra reservada super tambin se utiliza para llamar a la constructora de la clase madre desde la constructora de la clase derivada. Debe incluirse como primera lnea de la constructora en la clase derivada. Vemoslo con un ejemplo:
public class Pixel extends Complejo { private Color color; ... public Pixel(double x, double y, Color color) { super(x,y); this.color = color; } ....
1.6 Polimorfismo
Observacin: Debido al polimorfismo, todos los objetos pueden verse como miembros de la clase Object. La clase Object contiene algunos mtodos interesantes: String toString() : Ya hemos hablado anteriormente de este mtodo, que devuelve la representacin como String de un objeto, y que habitualmente redefinimos en las clases que definimos. Object clone() : Devuelve una copia del objeto en el que estamos. Class getClass() : Devuelve informacin acerca de la clase del objeto en el que estamos. La clase Class (!!) se define en Java para representar informacin acerca de las clases y
true
escribir dos veces por pantalla la palabra Diferentes (suponiendo que no hemos redefinido el mtodo equals). Para solucionar esto (nos gustara que nos dijera que c1 y c2 son el mismo nmero complejo) debemos redefinir equals. Para hacerlo de forma correcta, Java nos pide que sigamos (entre otros) los siguientes principios:
equals debe ser un mtodo reflexivo: debe verificarse x.equals(x)==true para todo x!=null equals debe ser un mtodo simtrico: debe verificarse x.equals(y)== y.equals(x) para todo x!=null, y!=null equals debe ser un mtodo transitivo: dados x,y,z distintos de nullsi se cumple x.equals(y)==true y y.equals(z)==true debe cumplirse x.equals(z)==true. Para todo x!=null debe cumplirse x.equals(null)==false
A menudo a estas reglas (completadas con algunas ms que no escribimos por ser ms complicadas, pero que pueden encontrarse en la ayuda de Java), se las conoce como el contrato para equals. Es interesante observar que las 3 primeras especifican que la relacin binaria R definida como
x R y <==> x.equals(y)==true
es una relacin de equivalencia. Siguiendo estas ideas podemos escribir un mtodo equals para la clase complejo de la siguiente forma:
public class Complejo { .... // redefinicin de equals public boolean equals(Object obj) { boolean salida = false;
El if garantiza que el objeto con el que estamos comparando no es null y que pertenece a la misma clase que el objeto en el que nos encontramos (para esto utilizamos el mtodo equals de la clase Class). Ahora el programa:
import complejos.Complejo; public class Principal { public static void main(String[] args) { Complejo c1 = new Complejo(3,5); Complejo c2 = new Complejo(3,5); System.out.println(c1==c2 ? "Iguales" : "Diferentes"); System.out.println(c1.equals(c2) ? "Iguales" : "Diferentes"); } }
Escribe:
Diferentes Iguales
Por lo que equals funciona ahora como deseamos. Es importante recordar lo siguiente: Aviso: Nunca usar == para comparar objetos, utilizar en su lugar equals.
En Java todas las clases heredan de una y slo de una La herencia mltiple (heredar de ms de una clase a la vez) plantea una gran cantidad de problemas tericos (en caso de colisin de quin son los mtodos, problemas de polimorfismo, etc.), aunque en ocasiones puede darse. Es lo que se conoce como el problema del diamante (por la forma del grfico). Imaginemos por ejemplo que tenemos:
Y definimos: Animal.java
public class Animal { public void saluda() { } }
Rana.java
public class Rana extends Animal{ String tipo="Anfibio"; public void saluda() { System.out.println("Croack!"); } }
Dinosaurio.java
public class Dinosaurio extends Animal{ String tipo="Reptil"; public void saluda() { System.out.println("Hola, soy un dinosaurio, mucho gusto"); } }
Ranosaurio.java
Principal.java
public class Principal { public static void main(String[] args) { Animal a = new Animal(); Rana gustavo = new Rana(); Dinosaurio dino = new Dinosaurio(); Ranosaurio jurix = new Ranosaurio(); a.saluda(); gustavo.saluda(); dino.saluda(); jurix.saluda(); System.out.println(jurix.valorTipo()); } }
Si se pudiera escribir y compilar, este programa se planteara el problema de cual de las dos clases de las que se hereda tiene prioridad en caso de conflicto. Aunque no se pueda tener herencia mltiple directamente, Java permite simularla por medio de interfaces. Estas dos propiedades (existencia y unicidad de la superclase) hacen que la estructura de clases de Java tenga forma de rbol:
Una posibilidad menos "extrema" es no declarar la clase como final y hacer "finales" los mtodos que queremos proteger de una posible redefinicin por parte de sus subclases.
La palabra clase abstract indica que la clase contiene mtodos abstractos, es decir mtodos an no definidos. La clase est por tanto, incompleta, y no podemos declarar objetos de tipo PolgonoRegular:
Observacin: Las clases finales lo son por decisin del programador, pero las abstractas lo son porque el programador no es capaz de implementar alguno de los mtodos, pero an as cree que debe existir. S podemos, en cambio, hacer clases derivadas como la siguiente: Cuadrado.java
public class Cuadrado extends PolgonoRegular { public Cuadrado(double lado) { super(4,lado); } public double rea() { return lado * lado; } }
Aviso: La subclase de una clase abstracta debe incluir todos los mtodos declarados como abstractos (o ser ella misma abstracta).
3.-Interfaces
Los interfaces no son clases sino "plantillas": Definicin: Un interfaz indica un conjunto de mtodos que deben implementarse para realizar una tarea determinada o cumplir unas propiedades. El cuerpo de los mtodos no se especifica y debe ser desarrollado en la clase que implementa el interfaz. Como se ve la idea es similar a la de la clase abstracta, pero llevada al extremo, porque todo es abstracto: un interfaz slo puede tener atributos constantes, y no puede incluir el cdigo de ningn mtodo. Ser la clase que implementa (en los interfaces no se habla herencia sino de implementacin) se encargar de aadir el cdigo necesario. Para decir que una clase A implementa una interfaz B escribiremos: public class A implements B { ..... }
Aviso: La clase que implementa un interfaz debe incluir una definicin para todos los mtodos del interfaz.
Aviso: Al definir un interfaz no se puede incluir cdigo para ningn mtodo. Pueden existir atributos, pero tiene que estar definidos como static final. Combinando la utilizacin de la herencia y de los interfaces pdoemos simular la herencia mltiple. Ejemplo: Supongamos que tenemos un interfaz para los objetos que son capaces de 'pintarse' a s mismos.
Pintador.java
import java.awt.Graphic; // Graphic sirve para dibujar en un objeto public interface Pintador {
Ahora podemos hacer que la clase Cuadrado herede de PolgonoRegular y a la vez implemente Pintador:
Cuadrado.java
import java.awt.*; public class Cuadrado extends PolgonoRegular implements Pintador { public Cuadrado(double lado) { super(4,lado); // constructora de PolgonoRegular } public double rea() { return lado * lado; } public void pinta(Graphics g,int x, int y,Color color) { g.setColor(color); g.fillRect(x,y,(int)lado,(int)lado); } public void borra(Graphics g, int x, int y) { g.clearRect(x,y,(int)lado,(int)lado); } }
Para probar la nueva versin de la clase podemos escribir un programa principal (que utiliza los componentes grficos que veremosen el siguiente captulo) Principal.java
import java.awt.*; public class Principal { public static void main(String[] args) { Cuadrado c1 = new Cuadrado(40); // hacemos una ventana para pintar los cuadrados Frame ventana = new Frame("Ventana con cuadrados"); ventana.setLayout(new FlowLayout()); // le aadimos una etiqueta Label l = new Label(" "); l.setBackground(Color.yellow); ventana.add(l); ventana.setSize(300,200);
El resultado es el siguiente:
Este programa demuestra la ''doble naturaleza'' de Cuadrado: Por un lado hereda de PolgonoRegular, y por otro implementa el interfaz pintador. De esta forma hemos conseguido algo similar a la herencia mltiple.
En ocasiones nos interesa proteger algunos mtodos o atributos para que las clases hijas no puedan acceder a ellos y alteren el comportamiento de la clase. Esto tiene que ver con los modos de acceso que repasamos ahora brevemente y en general (no slo para la herencia). En Java hay 4 modos de acceso a mtodos y atributos: acceso private, acceso
5.1 Introduccin
La utilizacin de excepciones es el mecanismo utilizado por Java (y C++) para tratar situaciones inesperadas que pueden ocurrir durante la ejecucin de programa: errores en la apertura de ficheros, divisiones por 0, etc. Ejemplo:
int dividendo, divisor,cociente; // por aqu se les da valores a dividendo y divisor .... try { cociente = dividendo/divisor; } catch (ArithmeticException e) { System.out.println("Error: Division por 0"); cociente = 0; } // en cualquier caso el programa contina por aqu .....
El uso de excepciones permite manejar los errores de forma ms flexible y precisa. Adems, el uso de if no resuelve todas las situaciones.
Observaciones: La variable slo es visible en el bloque catch y se suele utilizar (aunque no siempre) para conocer informacin ms concreta acerca de la situacin excepcional que ha ocurrido. La idea es que la excepcin provocada dentro del cdigo try se captura dentro del bloque catch. Las sentencias try pueden anidarse:
try { bloque1 // cdigo que puede generar una excepcin
Generadas en bloque1 del tipo TipoExcepcin2. Generadas en bloque2 del tipo TipoExcepcin2 pero que no son del tipo TipoExcepcin1. Generadas en bloque3 del tipo TipoExcepcin2.
En el primer catch slo se podrn tratar excepciones generadas en bloque1 del tipo TipoExcepcin1 . Importante: Si un trozo de cdigo puede generar una excepcin que no se captura en un catch el mtodo en el que est incluido debe indicar que puede lanzar dicha excepcin, para que sea tratada en un bloque ms externo mediante una declaracin throws. Ejemplo:
static String quieroGalleta(String s) throws NullPointerException{ if (s.equals("Galleta")) return "Gracias!"; else return("Quiero una galleta!!!"); }
Sin embargo lo ms habitual es tratar la excepcin en el mismo sitio donde se produce: Ejemplo:
static String quieroGalleta(String s){ String resultado = ""; try { if (s.equals("Galleta")) resultado = "Gracias!"; else resultado = "Quiero una galleta!!!"; } catch (NullPointerException e) { System.out.println("argumento sin inicializar"); } return resultado; }
en este caso si se produce la excepcin el programa se "romper" y Java mostrar por pantalla la secuencia de llamadas que ha producido la excepcin:
Exception in thread "main" java.lang.NullPointerException at Principal.quieroGalleta(Principal.java:24) at Principal.main(Principal.java:19)
Informacin: Slo es obligatorio tratar (o declarar con throws las excepciones que tienen que ver con las operaciones de entrada/salida. Nosotros tambin podemos "lanzar" nuestras propias excepciones: Ejemplo:
public class Principal { public static void main(String[] args) { String s="tarta"; System.out.println(quieroGalleta(s)); } static String quieroGalleta(String s) throws IllegalArgumentException { if (s.equals("Galleta")) return "Gracias!"; else throw new IllegalArgumentException("Quiero una galleta!!!"); } }
Tambin se pueden crear nuevos tipos de excepciones, haciendo clases que hereden de la clase Exception.
La constructora por defecto. La constructora a la que se le pasa un String: el mensaje de error que se mostrar.
String getMessage(): Devuelve el mensaje relativo al error printStackTrace(): muestra por pantalla el mensaje de error, junto con el nmero de lnea en el que se ha producido y la secuencia de llamadas (muy til para depurar).
La jerarqua de excepciones es: java.lang.Exception // la madre de todas las excepciones java.lang.InterruptedException // forzosamente deben estar dentro de un try. java.lang.RunTimeException // no necesitan incluirse en un try . java.lang.ArithmeticException // por ejemplo una divisin por 0 . java.lang.ArrayStoreException // intento de introducir un valor de tipo incorrecto en una matriz . java.lang.IllegalArgumentException // parmetro no vlido . java.lang.IllegalThreadStateException // la hebra no est en un estado adecuado . java.lang.NumberFormatException // p.ej. a convertir un String en entero . java.lang.IndexOutofBoundsException // acceso a una posicin no vlida... . java.lang.ArrayIndexOutofBoundsException // en un array . java.lang.StringIndexOutofBoundsException // en un String . java.lang.NegativeArraySizeException // intento de dar tamao negativo a una matriz . java.lang.NullPointerException // referencia a objeto sin inicializar (tiene null como valor) . java.io.IOException // forzosamente deben estar dentro de un try . java.io.EOFException // se ha intentado leer (o moverse) ms all del fin de fichero . java.io.FileNotFoundException // intento de acceder a un fichero inexistente . java.io.InterruptedIOException // por ejemplo si se saca el diskette mientras est leyendo . java.net.MalformedURLException // URL mal construida .
Aunque no est recomendado, se puede aprovechar el polimorfismo para declarar cualquier excepcin como de tipo Exception, asegurndonos de que el catch recoger cualquier cualquier posible excepcin: Ejemplo:
try { .... cdigo .... } catch(Exception e) { // aqu se recogen todas, sin importar su tipo e.printStackTrace(); // para mostrar el error
1.- Introduccin
1.1 AWT y Swing 1.2 Un poco de filosofa 1.3 La jerarqua Component
La razn principal es que, a pesar de ser Swing ms fcil de manejar est basado en conceptos ms complejos, difciles de entender si primero no se conoce AWT; Swing contiene demasiado de AWT como para, simplemente, ignorarlo. La mayora de los autores piensa que es mejor seguir al estudiar el lenguaje la evolucin que han seguido sus diseadores. Por eso nos limitaremos aqu al estudio de AWT. Si se comprenden los conceptos de este tema pasar posteriormente a Swing no supondr ningn problema. Otro buena razn es que al ser AWT ms antiguo, los applets de internet escritos en AWT funcionan en muchos ms exploradores que los escritos con Swing. Por tanto usando AWT nos aseguramos una mayor compatibilidad. Observacin: Por cada componente en AWT, el correspondiente componente en Swing suele tener el mismo nombre pero precedido de una letra J. Por ejemplo, los botones se representan en AWT mediante objetos de la clase Button y en Swing mediante objetos de la clase JButton, las ventanas mediante las clases Frame y JFrame, y as sucesivamente.
Mtodo String getName() void setName(String) Dimension getSize() void setSize(int ancho, int alto) void setSize(Dimension) Color getBackground Color getForeground void setForeground(Color) Font getFont() void setFont(Font) Boolean getVisible() void setVisible(Boolean) Boolean getEnabled() void setEnabled(Boolean) Graphics getGraphics() repaint() repaint(int x, int y, int width, int height) void Paint(Graphics g) void Update(Graphics g)
2 1
Descripcin Devuelve el nombre del componente Para fijar el nombre del componente Devuelve el tamao del componente Para modificar el tamao del componente Anlogo al anterior Devuelve el color de fondo del componente Devuelve el color de primer plano del componente Fija el color de primer plano del componente Devuelve el tipo de letra asociado al componente Fija el tipo de letra del componente Indica si el componente es visible Muestra/oculta el componente (til para ventanas) Indica si el componente est activo Activa/desactiva el componente (til para botones y opciones de men) Devuelve el objeto tipo Graphics que puede dibujar en el componente Llamaremos a este mtodo para pedirle al componente que se redibuje Llamaremos a este mtodo para pedirle al componente que redibuje el rectngulo indicado Redefiniremos este mtodo (usando herencia) cuando queramos dibujar algo en el componente Mtodo que por defecto borra el componente y llama a paint() cuando hay que repintar un componente. Se utiliza sobre todo
void setLocation(int x, int y) Mueve el componente a la posicin indicada void setLocation(Point p) Container getParent()
Algunas observaciones sobre estos mtodos: 1. La clase Dimension de AWT sirve para almacenar el ancho y el alto de un componente. Sus mtodos ms importantes son double getWidth(), double getHeight() y sus correspondientes set. 2. La clase Font de AWT representa los tipos de letra. Es una clase compleja que no vamos a ver en profundidad. La forma ms habitual de uso es como en este ejemplo:
// Arial de 12 pts en negrita Font fuenteNegrita = new Font("Arial",Font.BOLD,12);
Las constantes de formato son: Font.PLAIN, Font.BOLD y Font.ITALIC. 3. La clase Point de AWT se utiliza para representar las coordenadas de un punto (x,y). Tiene una constructora Point(x,y) y mtodos tales como int getX(), int getY(), void setX(int x), void setY(int y) y void move(int x, int y).
Aunque no vamos a estudiarlas todas, conviene saber para qu sirve cada una de ellas, y referirnos a la ayuda de Java cuando sea necesario: Componentes Bsicos Clase Button Canvas Choice CheckBox Label List Scrollbar TextField TextArea Rectngulo para dibujar Lista desplegable (ej: lista de pases para elegir) Casillas cuadradas para marcar (como en un test) Etiqueta: caracteres que se muestran en un contenedor Lista, similar a Choice pero constantemente desplegada Barra de desplazamiento Campo de edicin que puede utilizar el usuario para introducir datos Similar a TextField pero permite introducir texto que ocupe varias lneas Descripcin Botones con un texto (Ej: Aceptar)
Frame(): Constructora sin parmetros; crea una ventana sin ttulo Frame(String): Crea una ventana con el ttulo que se le indica Por ejemplo:
Frame ventana = new Frame("Ventana de prueba");
Hay que observar que el tamao y la posicin dependen de la configuracin de la pantalla. Para conocer el tamao en pixels de la pantalla podemos utilizar el mtodo Toolkit.getDefaultToolkit().getScreenSize();, que devuelve un objeto de tipo Dimension. Por ejemplo, para que la ventana aparezca centrada y ocupe un tercio de la pantalla tanto en ancho como en alto podemos escribir:
Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); // calculamos el tamao de la ventana a partir del ancho de la pantalla int ancho=d.width/3; int alto=d.height/3; ventana.setSize(ancho, alto); ventana.setLocation(d.width/2-ancho/2,d.height/2-alto/2);
Otras inicializaciones (opcional) Tambin podemos fijar los colores, el tipo de letra, el ttulo (con void setTitle(String)) o el icono que mostrar la ventana al minimizarse (con void setImage(Image)). Por ejemplo:
ventana.setBackground(new Color(20,140,10)); ventana.setForeground(Color.blue); Font fuente = new Font("Arial", Font.PLAIN, 20); ventana.setFont(fuente); ventana.setTitle("Ejemplo de ventana ");
Fijar el estilo (opcional) Hablaremos de los "estilos" ms adelante. De momento baste con decir que el mtodo setLayout(Layout) determina el estilo de la ventana, es decir cmo se distribuyen los componentes en la ventana. Por ejemplo:
FlowLayout estilo = new FlowLayout(); ventana.setLayout(estilo);
har que los componentes se siten uno al lado del otro, de izquierda a derecha y de arriba a abajo. Observacin: Todos los estilos (como FlowLayout) son subclases de la clase Layout y por eso pueden ser utilizados como argumentos del mtodo setLayout. Es un ejemplo de polimorfismo. Incorporar los componentes En este paso se aaden los componentes que se desee incluir en la ventana. Para eso se utiliza el mtodo void add(Component) heredado de la clase Container. Por ejemplo:
Label etiq = new Label("Te estoy mirando...");
Observacin: Otro ejemplo de polimorfismo: etiq es de tipo Label, pero Label hereda de Component y por eso etiq puede ser argumento del mtodo add, cuyo argumento est declarado de tipo Component.
Aviso: Es importante que no olvidemos incorporar los componentes bsicos a un contenedor; en otro caso no podrn ser visibles. Mostrar la ventana Esto se hace con el mtodo setVisible heredado de Component.
ventana.setVisible(true);
Aviso: Un error habitual es olvidar este paso con lo que la ventana no se mostrar
Observacin: La utilizacin de setVisible permite "cambiar" de una ventana a otra, haciendo visible la que estaba oculta y viceversa.
WINDOW_LOST_FOCUS WINDOW_STATE_CHANGED
Para tener acceso a ellos debemos: Escribir una clase para atenderlos. Esta clase debe heredar de WindowAdapter o bien implementar el interfaz WindowListener Pasarle a la ventana un objeto de ese tipo a la ventana mediante el mtodo addWindowListener. La ventana llamar al mtodo adecuado correspondiente a cada evento. Los mtodos son:
void windowActivated(WindowEvent e) void windowClosed(WindowEvent e) void windowClosing(WindowEvent e) void windowDeactivated(WindowEvent e) void windowDeiconified(WindowEvent e) void windowIconified(WindowEvent e) void windowOpened(WindowEvent e)
De todos ellos el que nos interesa ahora es windowClosing que se utiliza cuando el usuario trata de cerrar la ventana. Para que al pulsar se cierre realmente tendremos que incluir una llamada a System.exit(0), que fuerza el fin de la aplicacin. La clase puede ser por ejemplo:
class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }
Observacin: Si en lugar de heredar de WindowAdapter hubiramos implementado su interfaz correspondiente (WindowListener) habramos tenido que incluir todos los mtodos anteriores en la clase, aunque slo estemos interesados en uno de ellos.
Observacin: En swing el componente correspondiente se llama JFrame, y permite indicar que se quiere salir de la aplicacin al cerrar la ventana sin necesidad de escribir un objeto escucha, simplemente con:
JFrame ventana = new ... ....
2.3 Ejemplo
El siguiente programa rene todos los conceptos anteriores:
Principal.java import java.awt.*; import java.awt.event.*; public class Principal { public static void main(String[] args) { // objeto de tipo ventana Frame ventana = new Frame("Ventana de prueba"); // ventana cuadrada centrada en la pantalla y // ocupando un tercio de la pantalla Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); // calculamos el tamao de la ventana a partir del ancho de la pantalla int ancho=d.width/3; int alto=d.height/3; ventana.setSize(ancho, alto); ventana.setLocation(d.width/2-ancho/2,d.height/2-alto/2); // colores, ttulo y fuente ventana.setBackground(new Color(20,140,10)); ventana.setForeground(Color.blue); Font fuente = new Font("Arial", Font.PLAIN, 20); ventana.setFont(fuente); ventana.setTitle("Ejemplo de ventana "); // estilo FlowLayout estilo = new FlowLayout(); ventana.setLayout(estilo); // componentes Label etiq = new Label("Te estoy mirando..."); ventana.add(etiq); // aadimos el "listener" para cerrar la ventana ParaAcabar acabar = new ParaAcabar(); ventana.addWindowListener(acabar); // hacemos la ventana visible ventana.setVisible(true); } } // clase escucha que se ejecuta al tratar de cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) {
Es interesante observar que la clase para cerrar la ventana se encuentra, por comodidad, en el mismo fichero que la clase principal. Esto es posible porque esta clase no es pblica. Observacin: En cada fichero .java puede haber una nica clase pblica, pero tambin se permite incluir otras clases -no pblicas- que sirvan de clases auxiliares de la clase pblica.
import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { public Ventana() { // ventana cuadrada centrada en la pantalla y // ocupando un tercio de la pantalla Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); // calculamos el tamao de la ventana a partir del ancho de la pantalla int ancho=d.width/3; int alto=d.height/3; setSize(ancho, alto); setLocation(d.width/2-ancho/2,d.height/2-alto/2); // colores, ttulo y fuente setBackground(new Color(20,140,10)); setForeground(Color.blue); Font fuente = new Font("Arial", Font.PLAIN, 20); setFont(fuente); setTitle("Ejemplo de ventana "); // estilo FlowLayout estilo = new FlowLayout(); setLayout(estilo); // componentes Label etiq = new Label("Te estoy mirando..."); add(etiq);
De esta forma la clase ventana tiene todos los mtodos de la clase Frame ms todos los que nosotros aadamos posteriormente. La clase principal queda simplemente:
Principal.java public class Principal { public static void main(String[] args) { // objeto de tipo ventana Ventana ventana = new Ventana(); // hacemos la ventana visible ventana.setVisible(true); } }
y en el resto del captulo a menudo la omitiremos para evitar repetir el cdigo, que es independiente de la ventana.
Label(): La constructora por defecto, crea una etiqueta con un String vaco.
Label(String etiq): Etiq es el String a mostrar. Label(String etiq, int alineamiento): Permite indicar si la etiqueta se mostrar en el espacio reservado para ella en el component alineada a la izquierda (constante Label.LEFT), a la derecha (Label.RIGHT) o centrada (Label.CENTER).
Mtodos Aparte de los mtodos heredados de Object y Component, esta clase tiene dos mtodos importantes:
setText(String etiq): Para modificar el contenido de la etiqueta. String getText(): Devuelve el contenido actual de la etiqueta.
Button(): Botn con un mensaje vaco. Button(String etiq): Etiq es el String a mostrar como mensaje.
Mtodos Algunos de los mtodos ms importantes, adems de los heredados de Component, son:
void setLabel(String label) : Cambia la etiqueta del botn. String getLabel() : Devuelve la etiqueta actual. void setActionCommand(String command): Asocia un String al botn. Este String no se mostrar por pantalla, sino que se utilizar como identificador del botn. void addActionListener(ActionListener l): Para aadir una escucha que pueda reaccionar cuando se pulsa el botn. Se explica en el apartado siguiente.
Vamos a ver un primer ejemplo. En este ejemplo se separa la aplicacin en dos clases independientes: la clase con el main y la clase con la ventana: Ventana.java
package ventanas; import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { Button botn;
System.exit(0); }
En este ejemplo aparece la ventana pero al pulsar el botn todava no hace nada. En el siguiente apartado veremos como hacer que el botn "reaccione" cuando es pulsado. Eventos La idea es que no ser el propio botn sino un objeto escucha el que ser informado por Java para que acte cuando el botn sea pulsado. Para lograr esto hay que: 1. Escribir una clase adecuada a la que pertenecer el objeto escucha. Esta clase debe, en el caso de los botones, implementar el interfaz java.awt.event.ActionListener. 2. Declarar un objeto del tipo anterior (normalmente en la constructora de la ventana, a la vez que se crea el botn). 3. Asociar el objeto de tipo escucha con el botn o, dicho con la terminologa habitual de Java, registrar el objeto como escucha del botn. Esto se hace utilizando el mtodo void addActionListener(ActionListener l). El interfaz ActionListener tiene un slo mtodo: void actionPerformed(ActionEvent e), al que se invocar cuando ocurra un evento sobre el botn (normalmente que ha sido pulsado). El objeto ActionEvent nos servir para saber ms informacin acerca del evento, y normalmente se us cuando el mismo objeto de tipo ActionListener se utiliza de escucha
String getActionCommand() . Object getSource(): Fuente del evento (objeto de tipo Button).
El siguiente ejemplo hace que el botn, al ser pulsado escriba por pantalla el mensaje "Gracias".
Ventana.java
package ventanas; import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { Button botn; Label etiq; // constructora public Ventana() { // titulo, estilo, tamao y posicin iniciales setTitle("Ejemplo de ventana con boton (v.2) "); setLayout(new FlowLayout()); setSize(300, 100); setLocation(100,50); // le damos un poco de color a la ventana setBackground(Color.yellow); // una etiqueta etiq = new Label("Un botn:"); add(etiq); // creamos el botn botn = new Button("Plsame"); botn.setBackground(Color.blue); botn.setForeground(Color.white); // lo incorporamos a la ventana // importante: si no se hace esto no sera visible add(botn); // preparamos la escucha del boton Escucha e = new Escucha(); // la registramos botn.addActionListener(e); // aadimos la escucha para cerrar la ventana addWindowListener(new ParaAcabar()); } }
Ejercicio: Hacer que el botn escriba al hacer click el nmero de veces que ha sido pulsado desde que ha comenzado la aplicacin (solucin en el siguiente apartado). Interaccin con otros componentes grficos Supongamos que pretendemos que el botn cambie de color de fondo cada vez que se le pulse. Para ello podemos utilizar el mtodo setBackground y generar un color aleatorio utilizando el mtodo Math.random(). Un primer intento consiste en modificar la clase Escucha de la siguiente forma:
// escucha del boton class Escucha implements ActionListener { public void actionPerformed(ActionEvent e) { // generamos un color aleatorio Color c = new Color((int)(Math.random()*256),(int)(Math.random()*256), (int)(Math.random()*256)); // cambiamos el color del boton boton.setBackground(c); } }
La razn es que la variable boton no es visible dentro de la clase Escucha. Afortunadamente podemos obtener el botn a partir de la variable ActionEvent e de la siguiente forma:
// escucha del boton class Escucha implements ActionListener { public void actionPerformed(ActionEvent e) { Button boton = (Button) e.getSource(); // generamos un color aleatorio
Esta solucin no se puede aplicar si queremos interactuar con otro componente distinto del botn. Ejemplo: Supongamos que queremos que al pulsar el botn se muestre en la etiqueta el nmero de veces que se ha pulsado el botn desde que comenz la aplicacin. En este caso no nos vale de nada la variable ActionEvent e; la etiqueta est definida en la clase ventana y debemos ''obtenerla'' de otra forma. Vamos a ver dos posibilidades: 1. Definir un atributo en la clase escucha que contendr una referencia al componente externo deseado. Este atributo se inicializar mediante la constructora. 2. En nuestro caso: 3. Ventana.java
4. 5. package ventanas; 6. 7. import java.awt.*; 8. 9. import java.awt.*; 10. import java.awt.event.*; 11. 12. public class Ventana extends Frame { 13. 14. // constructora 15. public Ventana() { 16. 17. // titulo, estilo, tamao y posicin iniciales 18. setTitle("Ejemplo de ventana con boton (v.3) "); 19. setLayout(new FlowLayout()); 20. setSize(300, 100); 21. setLocation(100,50); 22. 23. // le damos un poco de color a la ventana 24. setBackground(Color.yellow); 25. 26. // una etiqueta 27. Label etiq = new Label("An no has pulsado"); 28. add(etiq); 29. 30. // creamos el boton
81.
Esta solucin es ms sencilla; nos ahorramos la constructora, la copia de la referencia para acceder a los objetos, etc. A cambio es menos elegante y ms limitada; por ejemplo no nos permite definir la clase escucha en un fichero aparte, para poder compartirla por varias aplicaciones. Utilizando la misma escucha para varios botones Supongamos que queremos tener una etiqueta que haga de contador comenzando en 0. Incluiremos dos botones, uno para incrementar el contador y otro para decrementarlo. A la hora de establecer las escuchas hay dos posibilidades: 1. Escribir dos clases escucha, una para el botn de incrementar y otra para el de decrementar. 2. Utilizar la misma escucha para ambos. El segundo mtodo es, en este caso, ms cmodo, pero tenemos que ser capaces de distinguir dentro del mtodo actionPerformed cul de los dos botones ha sido pulsado, para as incrementar o decrementar el contador. Para esto podemos utilizar el mtodo setActionCommand de la clase Button y getActionCommand de ActionEvent, tal y como muestra el programa siguiente:
Ventana.java
package ventanas; import java.awt.*; import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { // constructora public Ventana() { // titulo, estilo, tamao y posicin iniciales setTitle("contadores "); setLayout(new FlowLayout()); setSize(200, 100);
TextField(): Constructora por defecto conteniendo la cadena vaca y con 0 columnas. TextField(int columnas): Contenido vaco pero longitud prefijada inicial. TextField(String texto) Campo de texto con un valor inicial. TextField(String texto, int columnas): Las dos anteriores combinadas.
Mtodos La clase TextField coincide con las clases anteriores en la definicin de los mtodos setText(String cadena) y String getText(). Algunos otros mtodos de inters:
setEchoChar(Char c): Indica el carcter que aparece cuando se introduce un valor y se usa para introducir palabras clave. setEchoChar(0) hace que el carcter que aparece sea el carcter pulsado. setEditable(boolean): Si se pone a false no se podr escribir sobre el campo de edicin. int getSelectionStart(), int getSelectionEnd(): Para saber el trozo de texto que ha sido seleccionado por el usuario. Muy til para las acciones de "Copiar", "Cortar" y "Pegar". void setSelectionStart(int inicio), void setSelectionEnd(int fin): Para marcar una porcin de texto. En realidad setSelectionEnd(int fin) indica una posicin ms all de la ltima a marcar. Por ejemplo, para marcar los caracteres 2,3 y 4 (tercer, cuarto y quinto carcter) se utilizara: texto.setSelectionStart(2);
texto.setSelectionEnd(5);
Eventos En cuanto a los eventos, la diferencia principal con la clase Button es que el mtodo ActionEvent de la clase escucha se utiliza cuando se pulsa Enter. Tambin se puede controlar cual es la tecla pulsada, como veremos al hablar de los eventos de teclado, pero estos eventos no son especficos de la clase TextField sino comunes a todos los Component. Ejemplo: Clase para representar una ventana de entrada a un sistema, con login y password:
PalabraClave.java
package claves; import java.awt.*; import java.awt.event.*; public class PalabraClave extends Frame { private Label etiq,etiq2,etiq3; private Button aceptar; private TextField login; private TextField pass; public PalabraClave() { // titulo, estilo, tamao y posicin iniciales setTitle("Entrada al Sistema"); setLayout(new FlowLayout()); // ventana centrada Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); int ancho=300, alto=200; setSize(ancho, alto); setLocation(d.width/2-ancho/2,d.height/2-alto/2); // tipo de letra Font fuente = new Font("Arial", Font.PLAIN, 18); setFont(fuente); // un poco de color setBackground(Color.cyan); // preparamos la entrada de datos etiq = new Label("Login: "); add(etiq); login = new TextField(8); add(login); etiq2 = new Label("Password:"); etiq2.setFont(fuente);
TextArea(): rea de texto con una cadena vaca. Tamao de alrededor de 55 filas por 15 columnas TextArea(int filas, int columnas): Fija el nmero de filas y columnas. Si el nmero excede el tamao del TextArea se incluyen automticamente las barras de desplazamiento. TextArea(String texto): Texto inicial. TextArea(String texto, int filas, int columnas): Texto inicial con filas y columnas prefijadas. TextArea(String texto, int filas, int columnas, int barras): Aade al anterior la posibilidad de controlar la existencia de barras de desplazamiento. Los posibles valores de barras son: o SCROLLBARS_BOTH o SCROLLBARS_HORIZONTAL_ONLY o SCROLLBARS_NONE o SCROLLBARS_VERTICAL_ONLY
Mtodos y Eventos Los mtodos y eventos son como los de TextField con algunos mtodos aadidos, entre los que podemos destacar:
void replaceRange(String str, int start, int end) : Cambia el texto entre las posiciones start y end por el texto str. insert(String str, int pos): Inserta el texto en la posicin indicada. append(String str): Aade el texto indicado al final.
El resultado es:
Casillas agrupadas Similar al anterior, pero agrupando las casillas por medio de un objeto tipo CheckboxGroup, para lo que se usa una tercera constructora que permite indicar el grupo al que pertenece la casilla, as como si est activa (cada grupo tendr como mximo una casilla marcada). Los mtodos de CheckboxGroup Checkbox getSelectedCheckbox() y void
El resultado es:
void keyPressed(KeyEvent e): Tecla pulsada. void keyReleased(KeyEvent e): Se dej de pulsar la tecla. void keyTyped(KeyEvent e): La combinacin de las dos anteriores.
Por su parte, el parmetro de tipo KeyEvent contiene los siguientes mtodos que nos ayudan a identificar la tecla concreta:
char getKeyChar(): Devuelve el carcter asociado a la tecla, si es una tecla normal (imprimible). Las teclas especiales devuelven la constante CHAR_UNDEFINED. boolean isActionKey(): Devuelve true si la tecla es una tecla especial o false si es imprimible. int getKeyCode(): Devuelve una constante identificando a la tecla si es una tecla especial. Algunas de estas constantes son: VK_ACCEPT, VK_ALT, VK_ALT_GRAPH, VK_BACK_QUOTE, VK_BACK_SLASH, VK_BACK_SPACE, VK_CANCEL, VK_CAPS_LOCK, VK_CLEAR, VK_CLOSE_BRACKET, VK_CODE_INPUT, VK_COLON, VK_COMMA, VK_COMPOSE, VK_CONTROL, VK_COPY, VK_CUT, VK_DELETE, VK_DOWN, VK_END, VK_ENTER, VK_ESCAPE, VK_EURO_SIGN, VK_F1, VK_F10, VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, VK_F19, VK_F2, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_FINAL, VK_FIND, VK_HELP, VK_HOME, VK_INSERT, VK_LEFT, VK_NUM_LOCK, VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, VK_NUMPAD8, VK_NUMPAD9, VK_O,
import java.awt.*; import java.awt.event.*; public class Teclas extends Frame { private Label etiq; // nico componente public Teclas() { // titulo, estilo, tamao y posicin iniciales setTitle("Teclas"); setLayout(new FlowLayout()); // ventana centrada Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); int ancho=300, alto=200; setSize(ancho, alto); setLocation(d.width/2-ancho/2,d.height/2-alto/2); // tipo de letra Font fuente = new Font("Arial", Font.PLAIN, 18); setFont(fuente); // un poco de color setBackground(Color.cyan); // preparamos la entrada de datos etiq = new Label("Pulsa 'S' para salir add(etiq); ");
// escucha de teclado para la ventana; // le pasamos como parmetro la etiqueta EscuchaTeclas e = new EscuchaTeclas(etiq); addKeyListener(e); // aadimos la escucha para cerrar la ventana addWindowListener(new ParaAcabar()); // si no hacemos esto el foco se lo queda la etiqueta!!! requestFocus(); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter {
void mouseClicked(MouseEvent e): Se ha pulsado el ratn. void mouseEntered(MouseEvent e): El ratn se ha situado sobre un componente (aunque no se haya pulsado). void mouseExited(MouseEvent e): El ratn abandona el componente sobre el que estaba situado. void mousePressed(MouseEvent e): Se ha pulsado un botn del ratn. void mouseReleased(MouseEvent e): Se ha soltado un botn del ratn que estaba pulsado.
int getX() : coordenada x del ratn. int getY() : : coordenada y del ratn. Point getPoint() : posicin del ratn. int getClickCount() : Informa sobre el nmero de pulsaciones, para distinguir el "doble-click". int getButton() : Informa sobre el botn que ha cambiado de estado. Puede devolver las constantes: BUTTON1, BUTTON2, BUTTON3.
Ejemplo: Vamos a mover un botn para que el usuario no pueda pulsarlo nunca:
CorreRaton.java
import java.awt.*; import java.awt.event.*; public class CorreRaton extends Frame { public CorreRaton() { // titulo, estilo, tamao y posicin iniciales setTitle("Botn tmido"); setLayout(new FlowLayout()); setBackground(Color.cyan); // ventana centrada Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); int ancho=300, alto=150; setSize(ancho, alto); setLocation(d.width/2-ancho/2,d.height/2-alto/2); // preparamos la entrada de datos Button botn = new Button("Plsame"); add(botn);
MouseMotionListener
void mouseMoved(MouseEvent e): El ratn se ha movido sin estar pulsado void mouseDragged(MouseEvent e): El ratn se ha movido estando pulsado.
5.- Estilos
5.1 Introduccin 5.2 Estilo FlowLayout 5.3 Estilo BorderLayout 5.4 Estilo GridLayout 5.5 Paneles
5.1 Introduccin
El estilo (o diseo) de un contenedor indica cmo se dispondrn los componentes bsicos en l. Se establece mediante el mtodo void setLayout(LayoutManager l) de la clase Container. La clase LayoutManager es la clase de la que heredan todos los estilos (layouts). Cada contenedor tiene un estilo por defecto. Por ejemplo, en el caso de Frame este es BorderLayout, y en el de Panel FlowLayout. Observacin: Aunque cada contenedor tiene un nico estilo, podemos mezclar estilos incorporando contenedores dentro de contenedores. La clase Panel est pensada con este propsito. Igual que en los puntos anteriores, aqu no vamos a ver todos los estilos de los que dispone Java (hay 21 estilos diferentes!), contentndonos con ver algunos de los ms comunes y esperando que sea suficiente para captar la "filosofa" y que a partir de stos comprender el resto sea ms sencillo.
FlowLayout(int alineamiento): Indica si cada fila aparecer alineada al centro, a la izquierda o a la derecha. Para ello define las constantes FlowLayout.CENTER, FlowLayout.LEFT y FlowLayout.RIGHT. FlowLayout(int alineamiento, int sepH, int sepV) : Como el anterior, pero permitiendo indicar, adems, la separacin entre columnas y entre filas.
Ejemplo: Aadimos 10 botones para ver como se colocan en la ventana con FlowLayout
EstiloFlowLayout.java
import java.awt.*; import java.awt.event.*; public class EstiloFlowLayout extends Frame { public EstiloFlowLayout() { // titulo, estilo, tamao y posicin iniciales setTitle("FlowLayout"); setBackground(Color.cyan); setSize(300,200); // componentes centrados a la derecha, con una distancia entre ellos // de 20 pixels en x y 30 en y setLayout(new FlowLayout(FlowLayout.RIGHT, 20,30)); // aadimos unos botones de pega for (int i=0; i<10; i++) add(new Button(" "+i+" ")); // aadimos la escucha para cerrar la ventana addWindowListener(new ParaAcabar()); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) {System.exit(0); } }
El resultado es:
BorderLayout(): Constructora por defecto. BorderLayout(int sepHorizontal, int sepVertical): Incluye la separacin en pixels entre los componentes.
Ejemplo
Ventana.java
import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { public Ventana() { // titulo, estilo, tamao y posicin iniciales setTitle("BorderLayout"); setBackground(Color.cyan); setSize(300,200); // componentes centrados a la derecha, con una distancia entre ellos // de 20 pixels en x y 30 en y setLayout(new BorderLayout());
El resultado es:
Observacin: Casi nunca se inserta un botn directamente en un componente con estilo BorderLayout. Lo normal es introducirlos en otro componente (por ejemplo en un Panel) que a su vez se inserta en el contenedor de estilo BorderLayout.
GridLayout(): Constructora por defecto: una sola fila y una sola columna; poco usada. GridLayout(int filas, int columnas): Nmero de filas y columnas. GridLayout(int filas, int columnas, int sepHorizontal, int sepVertical): Adems del tamao en filas y columnas indica la separacin horizontal y vertical entre los componentes.
Ejemplo
Grid.java
import java.awt.*; import java.awt.event.*; public class Grid extends Frame { public Grid() { // titulo, estilo, tamao y posicin iniciales setTitle("GridLayout"); setBackground(Color.yellow); setSize(250,150); // componentes en 4 filas, a 2 columnas, // 10 pixels de separacin horizontal entre componentes // y 5 pixels de separacin vertical setLayout(new GridLayout(4,2,10,5)); add(new Label("Nombre: ", Label.RIGHT)); TextField nombre = new TextField(10); add(nombre); add(new Label("Apellidos: ", Label.RIGHT)); TextField apellidos = new TextField(20); add(apellidos); add(new Label("Direccin: ", Label.RIGHT)); TextField direccin = new TextField(30); add(direccin); Button continuar = new Button("Siguiente"); add(continuar); Button abandonar = new Button("Cancelar"); add(abandonar);
El resultado es:
5.5 Paneles
La clase Panel representa un contenedor que no puede existir por su cuenta, slo insertado en otro contenedor (como por ejemplo en un Frame(). Su estilo por defecto es FlowLayout, aunque como en todos los contenedores se puede modificar con setLayout. Se utiliza a menudo para combinar diferentes estilos en una misma ventana. Observacin: Una fase importante al desarrollar aplicaciones con interfaz grficos es la del diseo del interfaz: qu paneles compondrn cada ventana y con qu estilos.
Ejemplo: Vamos a escribir el aspecto previo que tendra una aplicacin para jugar al ajedrez; incluyendo el tablero vaco, un ttulo inicial y botones para comenzar y salir. El resultado debe ser:
6.- Dibujando
6.1 Introduccin 6.2 La clase Canvas 6.3 La clase Graphics 6.4 Mostrando imgenes 6.5 Un poco de animacin
6.1 Introduccin
Cmo dibujar? Para dibujar en Java hay que conocer inicialmente los siguiente conceptos.
Los objetos capaces de dibujar son los de tipo Graphics (descritos en el punto 4.6.3). Contienen mtodos para dibujar lneas, rectngulos, imgenes ledas de un fichero (formato .gif o jpeg) etc. Todo componente grfico contiene un objeto de tipo Graphics, que es el que usa para "dibujarse" a si mismo. Todo componente grfico incluye un mtodo Graphics getGraphics()
import java.awt.*; import java.awt.event.*; public class Ventana extends Frame{ public Ventana() { // titulo, estilo, tamao y posicin iniciales setTitle("Botn con dibujo V.1"); setLayout(new FlowLayout()); Font fuente = new Font("Arial", Font.BOLD, 40); setFont(fuente); // ventana centrada Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); int ancho=200, alto=90; setSize(ancho, alto); setLocation(d.width/2-ancho/2,d.height/2-alto/2); Button botn = new Button("Aceptar"); add(botn); // aadimos el "listener" para cerrar la ventana addWindowListener(new ParaAcabar()); // la mostramos setVisible(true); // dibujamos sobre el botn Graphics g = botn.getGraphics(); g.setColor(Color.green); g.fill3DRect(5,40,70,10,true); g.fill3DRect(80,40,90,10,true); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }
El resultado es:
El problema est en que cada vez que se repinta el botn no se vuelve a pintar la lnea. De hecho el dibujo slo se hace una vez, al estar en la constructora, y cada vez que hay que pintar el botn. El mtodo paint Para arreglar este problema hay que saber algunas cosas ms.
Cuando un objeto necesita repintarse, llama a su mtodo public void update(Graphics g). El comportamiento por defecto de update es: o Borrar el componente. o Llamar al mtodo public void paint(Graphics g) para dibujarlo de nuevo. Nosotros no podemos llamar a estos mtodos directamente; pero podemos pedir a un componente que se "repinte" con el mtodo public void repaint().
As pues, la solucin est en sobreescribir el mtodo paint() del componente en el que queremos dibujar; y para ello deberemos hacer una nueva clase que herede de la clase de dicho componente, tal y como muestra el siguiente ejemplo: Ejemplo: Botn subrayado (segunda versin).
BotonSubrayado.java
import java.awt.*; public class BotonSubrayado extends Button { public BotonSubrayado(String nombre) { super(nombre); } public void paint(Graphics g) { // llamamos al pintar original super.paint(g); g.setColor(Color.green); g.fill3DRect(5,40,70,10,true); g.fill3DRect(80,40,90,10,true); } }
Ventana.java
import java.awt.*;
Ahora cada vez que haya que volver a pintar el botn se dibujar tambin la lnea
Ventana.java
import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { ...... public Ventana() { .... .... Lienzo l = new Lienzo(); add(l); ....... ...... } } ......
Principal.java
public class Principal { public static void main(String[] args) { new Ventana(); } }
Mtodos Principales
abstract clearRect(int x, int y, int width, int height) void Borra el rectngulo especificado por sus parmetros; es decir
lo pinta del
color de fondo.
abstract copyArea(int x, int y, int width, int height, int dx, int dy) void Copia el rea del componente especificada por los parmetros a una
distancia dx and dy. Si se quiere que se copie a la izquierda habr que dar un valor dx negativo. Anlogamente, para copiar ms arriba de la posicin actual habr que indicar un valor dy negativo.
void draw3DRect(int x, int y, int width, int height, boolean raised)
Dibuja un rectngulo al que se da aspecto de 3d, bien mostrndolo ligeramente elevado (si raised es true) o hundido (raised false)
abstract drawArc(int x, int y, int width, int height, int startAngle, void int arcAngle) Dibuja un arco (circular o elptico), empezando en el ngulo startAngle y finalizando en arcAngle. El arco estar inscrito en el rectngulo indicado
por los parmetros, con centro en el centro de dicho rectngulo. Ejemplo: El siguiente arco est escrito con la instruccin g.drawArc(50,50,150,100,0,260);. Tambin se muestra en el dibujo el rectngulo (dibujado con g.drawRect(50,50,150,100);).
abstract drawImage(Image img, int x, int y, Color bgcolor, boolean ImageObserver observer) Dibuja la imagen. Las coordenadas (x,y) marcan donde estar situada la esquina superior izquierda del dibujo y bgcolor el fondo que se mostrar en la parte transparente de la imagen. El parmetro observer indica un objeto
al que se va avisando cuando segn se va mostrando la imagen. Nosotros lo lo utilizaremos y lo pondremos a null.
abstract drawImage(Image img, int x, int y, ImageObserver observer) boolean Anlogo al anterior. El color de fondo no vara. abstract drawImage(Image img, int x, int y, int width, int height,
Anlogo a los anteriores con la salvedad de que el grfico se reescalar para ajustarse al rectngulo indicado.
abstract drawImage(Image img, int x, int y, int width, int height, boolean ImageObserver observer)
Anlogo al anterior.
abstract drawLine(int x1, int y1, int x2, int y2) void Dibuja una lnea, en el color actual, entre los dos puntos.
Observacin: Si el punto final es igual al inicial se dibuja un punto. Esto es importante porque no existe ningn mtodo para dibujar puntos, por lo que lo normal es utilizar drawLine(x,y,x,y).
abstract drawOval(int x, int y, int width, int height) void Dibuja un valo inscrito en el rectngulo indicado. Si width = height
se
Dibuja un rectngulo.
abstract drawRoundRect(int x, int y, int width, int height, int void arcWidth, int arcHeight)
inicial (marcada por un punto en la figura de abajo) para el primer carcter de la cadena.
actual.
abstract fillRoundRect(int x, int y, int width, int height, int void arcWidth, int arcHeight)
Para liberar la memoria requerida por un objeto Graphics que ya no es necesario. Esto se hace porque los objetos Graphics son muy costosos en cuanto a recursos de memoria.
abstract getColor() Color Devuelve el color actual. abstract getFont() Font Devuelve la
FontMetrics getFontMetrics()
Devuelve un valor de tipo FontMetrics representando las caractersticas mtricas de la fuente de letra actual. La clase FontMetrics contiene diversos mtodos para conocer las medidas de los caracteres dentro del tipo actual. Por ejemplo el mtodo stringWidth(String cadena) devolver la anchura en pixels requerida para mostrar la cadena.
abstract getFontMetrics(Font f) FontMetrics Devuelve las caractersticas
como parmetro.
abstract setColor(Color c) void Cambia el color actual
abstract setFont(Font font) void Establece la nueve fuente abstract setPaintMode() void Indica que al dibujar se
borra el fondo. Es el modo de actuacin por defecto. del color de fondo se cambian al color del
parmetro y viceversa.
String toString()
Ejemplo: Vamos a mostrar una secuencia de imgenes para producir el efecto de una animacin. Saluda.java
import java.awt.*; import javax.swing.*; public class Saluda extends Canvas Image t[]; // array de imgenes public Saluda() { t = new Image[10]; for } public void paint(Graphics g) { g.drawImage(t[0],0,0, 200,200, Color.white, null); } public void saluda() { Graphics g = getGraphics(); for (int i = 1; i<10; i++) { g.drawImage(t[i],0,0,200,200, Color.white, null); // perdemos un poco de tiempo para que se vea try{ Thread.sleep(150);} catch(Exception e) {} } repaint(); } (int i = 0; i<10; i++) t[i] = Toolkit.getDefaultToolkit().getImage("t"+(i+1)+".gif"); {
Ventana.java
import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { public Ventana() { // titulo, estilo, tamao y posicin iniciales setTitle("saluda a los seores"); // ventana centrada Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); int ancho=200, alto=250; setSize(ancho, alto); setLocation(d.width/2-ancho/2,d.height/2-alto/2); // el lienzo ir en el centro de la pantalla Saluda lienzo = new Saluda(); add(lienzo); // el botn con su escucha correspondiente Button boton = new Button("saluda!"); Escucha e = new Escucha(lienzo); boton.addActionListener(e); add(boton, BorderLayout.SOUTH); // aadimos el "listener" para cerrar la ventana addWindowListener(new ParaAcabar()); // la mostramos setVisible(true); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } // escucha del boton class Escucha implements ActionListener { Saluda lienzo;
Principal.java
public class Principal { public static void main(String[] args) { new Ventana(); } }
public class Principal { static public void main(String [] args) { new Ventana(); } }
Ventana.java
CorrePelota.java
import java.awt.*; public class CorrePelota extends Canvas { private final int radio = 30; int x = 20,y = 20; // pos. inicial int incX = 1, incY = 1; // dir. inicial public CorrePelota() { setBackground(Color.black); setForeground(Color.yellow);
El programa funciona, pero la pelota al moverse tiene un extrao "parpadeo". Vamos a ver como solucionarlo. Yo me lo pinto y yo me lo borro El problema es que antes de pintar el nuevo dibujo debe borrarse el anterior; y de eso se encarga update, que antes de llamar a paint borra el lienzo completo. Como esto tarda en hacerse en ocasiones el refresco de pantalla "pilla" a la animacin justo despus de borrar la figura pero antes de volver a dibujarla y eso provoca el parpadeo. Una solucin es impedir que update() borre la figura anterior y en su lugar hacerlo nosotros, que en lugar de borrar todo el grfico slo borraremos la figura anterior. Para hacer esto slo tenemos que modificar la clase CorrePelota: CorrePelota.java
import java.awt.*; public class CorrePelota extends Canvas { private final int radio = 30; int x = 20,y = 20; // pos. inicial int incX = 1, incY = 1; // dir. inicial int antx, anty; // posicin antigua de la pelota public CorrePelota() { setBackground(Color.black); setForeground(Color.yellow);
Aunque el parpadeo disminuye ligeramente sigue existiendo; se tarda demasiado en dibujar el valo. Doble buffer La idea es no dibujar ni borrar directamente en la pantalla, sino en un objeto de tipo Image que nos har de "buffer" o de copia del lienzo. Una vez que hayamos dibujado en el objeto slo tendremos que volcarlo a pantalla con drawImage. As el usuario no podr ver el proceso de borrado y dibujado; slo la figura en la nueva posicin. La nueva versin de la clase CorrePelota es: CorrePelota.java
import java.awt.*; public class CorrePelota extends Canvas { private final int radio = 30; int x = 20,y = 20; // pos. inicial
7.- Applets
7.1 Qu es un Applet? 7.2 Pginas WEB 7.3 Vida (y muerte) de un Applet 7.4 Ejemplo
7.1 Qu es un Applet?
Un applet es un programa Java que se ejecuta dentro de una pgina html. El cdigo (.class) viaja junto con la pgina al ordenador del usuario, donde es ejecutado por la mquina virtual del explorador correspondiente. Observacin: Para que se pueda ver el applet dentro de la pgina hay que tener activada la mquina virtual de Java del explorador Los applets son especialmente utilizados en pginas de tipo cientfico y pedaggicas, para ilustrar conceptos, simular experimentos. Un ejemplo tpico es cuando en nuestra pgina queremos mostrar un grfica que depende de ciertos parmetros introducidos por el usuario.
Podemos escribir este texto en un fichero (por ejemplo con el block de notas), grabarlo y abrirlo con el explorador. En general una pgina html puede contener:
Texto (se incluye el texto sin ms) Imgenes (Ej.: <img src="dibu.jpg"> para incluir dibu.jpg en la pgina ) Enlaces a otras pginas (Ej.: Si incluimos <a href="http://www.ucm.es">ucm</a> aparecer la palabra ucm y al pulsar sobre ella se saltar a la pgina de la universidad complutense).
Sin embargo no puede incluir acciones dinmicas, como por ejemplo pedir datos al usuario, procesarlos y mostrar el resultado, o mostrar una animacin Incluyendo Java en pginas WEB La llamada al cdigo java se introduce mediante el delimitador html applet
<html> <head> <title> Un mini-applet </title> </head > <body > Aqu incluimos una llamada al applet: <p> <applet code=Mini.class" width=150 Height=25></applet> <p> Y luego seguimos con el texto de la pgina </body> </html>
Importante: El cdigo java compilado (Mini.class en el ejemplo) debe encontrarse en la misma carpeta que la pgina html.
7.4 Ejemplo
El siguiente ejemplo mueve un dibujo ''cab.gif'' por la pantalla. Usa hebras (que no han sido explicadas en clase: interfaz Runnable y funcin run()).
import java.awt.*; import java.awt.event.*; import java.applet.*; public class Imagen extends Applet implements Runnable{ Image coche; int x=600,y=20; Thread corre = new Thread(this); //Inicializar el applet public void init() { MediaTracker tracker = new MediaTracker(this); coche = getImage(getCodeBase(),"cab.gif"); tracker.addImage(coche, 1); try { tracker.waitForAll();} catch(Exception e) {e.printStackTrace();} this.setBackground(Color.white); } public void run() { try { Thread.sleep(1000);
Dilogos modales: No se puede actuar sobre la aplicacin hasta que no se haya cerrado el dilogo. Son los ms comunes. Dilogos no modales: No necesitan cerrarse para seguir trabajando sobre la aplicacin.
Dado que los dilogos son un tipo especial de ventanas, no tenemos que describir sus mtodos, tan slo sus constructoras: Constructoras
Dialog(Frame prop): Crea un dilogo no visible (hasta que se haga setVisible(true)), no modal y con ttulo vaco. prop es el nombre del dilogo o la ventana propietaria. Si se desea se puede poner null para indicar que no tiene ventana "madre". Dialog(Frame prop, String titulo): Anlogo al anterior pero indicando el ttulo. Dialog(Frame prop, String titulo, boolean modal): Si modal es true crea una ventana modal.
Donde vent es la ventana madre, msg es el ttulo del cuadro de dilogo y mode debe ser o bien FileDialog.LOAD si el dilogo se utiliza para abrir un fichero o FileDialog.SAVE si se utiliza para grabar un fichero. Mtodos
String getDirectory(): Cadena con el directorio que contiene el fichero seleccionado. String getFile(): Cadena con el nombre del fichero seleccionado. FilenameFilter getFilenameFilter(): Filtro utilizado en la seleccin. int getMode(): Devuelve el modo: FileDialog.LOAD o FileDialog.SAVE. void setDirectory(String dir) : Establece el directorio inicial que se mostrar al abrir el dilogo. void setFile(String nombreFich): Nombre por defecto del fichero; se usa habitualmente en los dilogos de guardar. void setFilenameFilter(FilenameFilter f): Filtro que se utilizar para mostrar los archivos en el cuadro de dilogo. void setMode(int modo): Pone el modo a FileDialog.LOAD o FileDialog.SAVE.
Adems de estos mtodos es interesante conocer la constante File.separator que indica el separador de directorios (la barra inclinada hacia la derecha o la izquierda dependiendo del sistema operativo). El siguiente ejemplo ilustra como se puede utilizar este dilogo para abrir un fichero:
import java.awt.*; import java.awt.event.*; public class Ventana extends Frame {
showConfirmDialog: Dilogo para pedir confirmacin, como los tpicos dilogos con los botones si/no/cancelar. showInputDialog: Para pedir una entrada de datos al usuario. showMessageDialog: Informacin para el usuario, con un botn de aceptar. showOptionDialog: Combina las posibilidades de los tres anteriores.
Tambin hay 5 constantes que pueden utilizarse para indicar el tipo de mensaje que se est mostrando. La seleccin de la constante adecuada influir en el icono que se presentar en la ventana modal:
Por ltimo, aunque podemos incluir en el dilogo los botones que deseemos, hay 4 constantes que definen los conjuntos de botones ms usuales: DEFAULT_OPTION YES_NO_OPTION YES_NO_CANCEL_OPTION OK_CANCEL_OPTION El primero muestra slo un botn de aceptar (el significado del resto es obvio a partir del nombre). Vamos a ver algunos ejemplos en el siguiente programa:
import java.awt.*; import java.awt.event.*; import javax.swing.*; // para JOptionPane public class Ventana extends Frame { public Ventana() { setTitle("Entrada de datos"); setLayout(new FlowLayout()); setSize(200,100); setLocation(300,200); // el primer argumento es la ventana madre, // el segundo el mensaje a mostrar, el tercero el titulo // de la ventana y el cuarto el tipo de dialogo JOptionPane.showMessageDialog(this, "El fichero se ha grabado correctamente", "informacion", JOptionPane.INFORMATION_MESSAGE); // muestra el dialogo con un simbolo de interrogacion if (JOptionPane.showConfirmDialog(null, "desea salir de la aplicacion?", "aviso", JOptionPane.YES_NO_OPTION) == 0)
Este programa muestra las siguientes ventanas de dilogo (consecutivamente, cada una tras cerrar la anterior):
1 Introduccin
En este apartado vamos a ver muy sucintamente el paquete Swing, que como ya dijimos es la alternativa a AWT. La mayor parte de los conceptos vistos para AWT (componentes, contenedores, etc) son vlidos tambin para Swing. Y casi todas las clases vistas en AWT tienen su componente correspondiente en Swing: a la clase Button le corresponde JButton, a Frame JFrame, a Applet JApplet, etc, etc. Sin embargo Swing incluye otros componentes que no existen en AWT, como por ejemplo JTree para representar estructuras tipo rbol. Estos componentes, ms potentes y complejos, precisan de un estudio muy detallado, al que no nos vamos a dedicar aqu. Adems, Swing incluye conceptos nuevos, como la definicin de la apariencia genrica de las ventanas y componentes segn distintos estilos (el llamado Look and Feel ). A menudo los libros y tutoriales se refieren a todas las clases relacionadas con la creacin de aplicaciones grficas basadas en Swing como JFC o Java Foundation Class.
Los componentes bsicos no se aaden directamente a la ventana, sino a un panel que siempre existe asociado a la ventana y que se obtiene mediante el mtodo getContentPane(). Veamos estas diferencias por medio de un ejemplo:
// Crear la ventana JFrame ventana = new JFrame("Ventana Swing"); ventana.setDefaultCloseOperation(EXIT_ON_CLOSE); // Creamos un componente; aqu hay polimorfismo... JComponent comp = new JTextArea(); // un rea de texto // Aadir el componente al panel de la ventana ventana.getContentPane().add(comp, BorderLayout.CENTER);
3 Ejemplo
El siguiente programa pide un nmero n y realiza la suma de todos los enteros consecutivos desde 1 hasta n. Para mostrar la evolucin del proceso se va actualizando una barra de progreso. Una curiosidad de este cdigo es que las clases privadas se incluyen dentro de la clase de la ventana, antes de su ltima llave '}', como si fueran mtodos o atributos. Esto es habitual en Java (no importa si estamos usando Swing o AWT). La ventaja es que las clases as incluidas tienen acceso a los atributos de la clase ventana, al ser parte de la propia clase. Obsrvese igualmente que el modelo de eventos es el mismo de AWT.
VentanaProgreso.java
public class VentanaProgreso extends JFrame { private Container panelPrincipal = null; private JButton botonEmpezar, botonParar; private JTextField campoEntrada, campoResultado; private ProgressMonitor pMonitor = null; private Timer reloj = null; private int suma,contador; public VentanaProgreso() { suma = contador = 0; setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(400,100); // 1. Aadimos un grid layout al panel principal panelPrincipal = this.getContentPane(); panelPrincipal.setLayout(new GridLayout(2,1)); // 2. aadimos una caja horizontal al gridlayout Box caja = Box.createHorizontalBox(); panelPrincipal.add(caja); // 3. Rellenamos la caja horizontal caja.add(Box.createHorizontalGlue()); JLabel etiq1 = new JLabel("Suma del 1 al ", JLabel.LEFT);
Conviene recordar que para que esta clase pueda ser utilizada hacer falta escribir otra clase, la principal que se encargue de ''arrancarla'':
PruebaJFC.java
El resultado es:
El componente Reloj (de tipo Timer) es el que se encarga de ir actualizando la barra de progreso pMonitor (de tipo ProgressMonitor). Su escucha se llama automticamente por Java, aunque el usuario no haga nada, a intervalos constantes de tiempo. El nmero de milisegundos entre el fin de una llamada y la siguiente llamada se fija en la constructora. En este ejemplo hemos puesto el valor 10.