Está en la página 1de 129

Introduccin al lenguaje JAVA

JAVA

Autor

Java desde el Principio Con sta comienzo una serie de notas sobre Java, especialmente para aquellos que quieren comenzar a conocerlo y usarlo !sto se origin en un inters que surgi en algunos de los suscriptores del mailing list de desarrolladores de "eb, y que pongo a disposicin tambin del de "ebmasters #eguramente muc$os de ustedes sabr%n muc$o m%s sobre Java que yo, y les agradecer todo tipo de comentarios o correcciones &a idea es dar una gu'a ordenada para el estudio de este lenguaje, muy poderoso y de gran co$erencia, aunque todav'a adolece de algunas limitaciones que seguramente se ir%n superando con el tiempo (u es Java Java es un lenguaje originalmente desarrollado por un grupo de ingenieros de #un, utilizado por )etscape posteriormente como base para Javascript #i bien su uso se destaca en el *eb, sirve para crear todo tipo de aplicaciones +locales, intranet o internet, Java es un lenguaje. de objetos . independiente de la plata/orma Algunas caracter'sticas notables. robusto . gestiona la memoria autom%ticamente . no permite el uso de tcnicas de programacin inadecuadas . multit$reading . cliente0servidor . mecanismos de seguridad incorporados . $erramientas de documentacin incorporadas &enguaje de 1bjetos Por qu puse 2de2 objetos y no 2orientado a2 objetos3 Para destacar que, al contrario de otros lenguajes como

C44, no es un lenguaje modi/icado para poder trabajar con objetos sino que es un lenguaje creado para trabajar con objetos desde cero 5e $ec$o, 6151 lo que $ay en Java son objetos (u es un objeto3 7ueno, se puede decir que todo puede verse como un objeto Pero seamos m%s claros 8n objeto, desde nuestro punto de vista, puede verse como una pieza de so/t"are que cumple con ciertas caracter'sticas. encapsulamiento . $erencia !ncapsulamiento signi/ica que el objeto es auto0contenido, o sea que la misma de/inicin del objeto incluye tanto los datos que ste usa +atributos, como los procedimientos +mtodos, que act9an sobre los mismos Cuando se utiliza programacin orientada a objetos, se de/inen clases +que de/inen objetos genricos, y la /orma en que los objetos interact9an entre ellos, a travs de mensajes Al crear un objeto de una clase dada, se dice que se crea una instancia de la clase, o un objeto propiamente dic$o Por ejemplo, una clase podr'a ser 2autos2, y un auto dado es una instancia de la clase &a ventaja de esto es que como no $ay programas que act9en modi/icando al objeto, ste se mantiene en cierto modo independiente del resto de la aplicacin #i es necesario modi/icar el objeto +por ejemplo, para darle m%s capacidades,, esto se puede $acer sin tocar el resto de la aplicacin: lo que a$orra muc$o tiempo de desarrollo y debugging; !n Java, inclusive, ni siquiera e<isten las variables globales; +Aunque parezca di/'cil de aceptar, esto es una gran ventaja desde el punto de vista del desarrollo, !n cuanto a la $erencia, simplemente signi/ica que se pueden crear nuevas clases que $ereden de otras pree<istentes= esto simpli/ica la programacin, porque las clases $ijas incorporan autom%ticamente los mtodos de las madres Por ejemplo, nuestra clase 2auto2 podr'a $eredar de otra m%s general, 2ve$'culo2, y simplemente rede/inir los mtodos para el caso particular de los automviles: lo que signi/ica que, con una buena biblioteca de clases, se puede reutilizar muc$o cdigo inclusive sin saber lo que tiene adentro 8n ejemplo simple Para ir teniendo una idea, vamos a poner un ejemplo de una clase Javapublic class Muestra extends Frame { // atributos de la clase Button si;

Button no; // mtodos de la clase: public Muestra () { Label comentario = new Label("Presione un botn", Label.CENTER); si = new Button("S"); no = new Button("No"); add("North", comentario); add("East", si); add("West", no); }}

!sta clase no est% muy completa as', pero da una idea: !s una clase $eredera de la clase >rame +un tipo de ventana, que tiene un par de botones y un te<to Contiene dos atributos +2si2 y 2no2,, que son dos objetos del tipo 7utton, y un 9nico mtodo llamado ?uestra +igual que la clase, por lo que es lo que se llama un constructor, Independiente de la plata/orma !sto es casi del todo cierto: !n realidad, Java podr'a $acerse correr $asta sobre una Commodore @A; &a realidad es que para utilizarlo en todo su potencial, requiere un sistema operativo multit$reading +como 8ni<, *indo"sBC, 1#DE:, Cmo es esto3 Porque en realidad Java es un lenguaje interpretado: al menos en principio Al compilar un programa Java, lo que se genera es un seudocdigo de/inido por #un, para una m%quina genrica &uego, al correr sobre una m%quina dada, el so/t"are de ejecucin Java simplemente interpreta las instrucciones, emulando a dic$a m%quina genrica Por supuesto esto no es muy e/iciente, por lo que tanto )etscape como Fotjava o !<plorer, al ejecutar el cdigo por primera vez, lo van compilando +mediante un JI6- Just In 6ime compiler,, de modo que al crear por ejemplo la segunda instancia de un objeto el cdigo ya est compilado espec'/icamente para la m%quina $usped Adem%s, #un e Intel se $an puesto de acuerdo para desarrollar procesadores que trabajen directamente en Java, con lo que planean $acer m%quinas muy baratas que puedan conectarse a la red y ejecutar aplicaciones Java cliente0servidor a muy bajo costo !l lenguaje de dic$a m%quina genrica es p9blico, y si uno quisiera $acer un intrprete Java para una Commodore slo tendr'a que implementarlo y pedirle a #un la aprobacin +para que veri/ique

que cumple con los requisitos de Java en cuanto a cmo interpreta cada instruccin, la seguridad, etc , Algunas caracter'sticas: !ntre las caracter'sticas que nombramos nos re/erimos a la robustez Justamente por la /orma en que est% diseGado, Java no permite el manejo directo del $ard"are ni de la memoria +inclusive no permite modi/icar valores de punteros, por ejemplo,= de modo que se puede decir que es virtualmente imposible colgar un programa Java !l intrprete siempre tiene el control Inclusive el compilador es su/icientemente inteligente como para no permitir un montn de cosas que podr'an traer problemas, como usar variables sin inicializarlas, modi/icar valores de punteros directamente, acceder a mtodos o variables en /orma incorrecta, utilizar $erencia m9ltiple, etc Adem%s, Java implementa mecanismos de seguridad que limitan el acceso a recursos de las m%quinas donde se ejecuta, especialmente en el caso de los Applets +que son aplicaciones que se cargan desde un servidor y se ejecutan en el cliente, 6ambin est% diseGado espec'/icamente para trabajar sobre una red, de modo que incorpora objetos que permiten acceder a arc$ivos en /orma remota +via 8H& por ejemplo, Adem%s, con el J5I +Java 5evelopment Iit, vienen incorporadas muc$as $erramientas, entre ellas un generador autom%tico de documentacin que, con un poco de atencin al poner los comentarios en las clases, crea inclusive toda la documentacin de las mismas en /ormato F6?&; !l Java 5evelopment Iit 6odo lo que puedan pedir para desarrollar aplicaciones en Java est% en. $ttp-DDjava sun comDaboutJavaDinde< $tml !n particular, deber'an bajarse el J5I y el API 5ocumentation de. $ttp-DDjava sun comDjava sun comDproductsDJ5IDJ K EDinde< $tml +6ambin les puede interesar en particular el 6ool 5ocumentation y alguno de los otros paquetes de la p%gina, )ota- en este site tambin $ay un tutorial de Java, aunque es un poco di/'cil de seguir para el principiante !l J5I +versin J K E, est% disponible para #PAHCD#olaris, <L@D#olaris, ?#0*indo"s BCD)6, y ?ac1# 6ambin est% disponible el /uente para el que quiera adaptarlo para otro sistema operativo, y $e le'do por a$' que $ay una versin dando vueltas para &inu< y FP08M

7%sicamente, el J5I consiste de. el compilador Java, javac . el intrprete Java, java . un visualizador de applets, appletvie"er . el debugger Java, jdb +que para trabajar necesita conectarse al server de #un, . el generador de documentacin, javadoc 6ambin se puede bajar del mismo site un bro"ser que soporta Java +y de $ec$o est% escrito totalmente en Java,, el Fotjava Para instalarlo simplemente $ay que descompactar el arc$ivo +sugiero que creen un directorio java para eso,, pero tengan en cuenta )1 5!#C1?PHI?IH el arc$ivo classes zip; Importante para los usuarios de *indo"sBC- todas estas aplicaciones deben ejecutarse desde una ventana 51# !n particular, utilizan nombres largos y distinguen may9sculas de min9sculas, as' que tengan en cuenta esto que es /uente de muc$os errores 8na cosa muy importante- para que todo ande bien aceitado, agreguen. el directorio de los programas en el pat$ +ej- c-NjavaNbin, . las variables de entorno. C&A##PA6FO =C-NjavaNlibNclasses zip . F1?!5HIV!OC. F1?!PA6FON . F1?!OC-N con los valores adecuados a su entorno )oten que en C&A##PA6F agregu el directorio actual + ,, para poder compilar y ejecutar desde cualquier directorio !mpecemos de una vez; 7ueno, suponiendo que $ayan instalado todo, y antes de comenzar a programar en Java, una pequeGa aclaracin !n realidad se puede decir que $ay tres Javas por a$'-

. Javascript- es una versin de Java directamente interpretada, que se incluye como parte de una p%gina F6?&, lo que lo $ace muy /%cil y cmodo para aplicaciones muy pequeGas, pero que en realidad tiene muc$as limitaciones. no soporta clases ni $erencia . no se precompila . no es obligatorio declarar las variables . veri/ica las re/erencias en tiempo de ejecucin . no tiene proteccin del cdigo, ya que se baja en ascii . no todos los bro"sers lo soportan completamente= !<plorer, por ejemplo, no soporta las 9ltimas adiciones de )etscape, como las im%genes animadas . Java standalone- programas Java que se ejecutan directamente mediante el intrprete java . Applets- programas Java que corren bajo el entorno de un bro"ser +o del appletvie"er, !n s' los dos 9ltimos son el mismo lenguaje, pero cambia un poco la /orma en que se implementa el objeto principal +la aplicacin, Vamos a ver cmo crear las aplicaciones para que, sin cambios, se puedan ejecutar casi igual en /orma standalone o como applet +en realidad $ay cosas que los applets no pueden $acer, como acceder a arc$ivos sin autorizacin, Javascript )o vamos a detenernos muc$o en Javascript, por las limitaciones antedic$as= si les interesa podemos dedicarnos un poco a este lenguaje en el /uturo Por a$ora, slo un ejemplo sencilloCalculadora en Javascript<HTML> <HEAD> <SCRIPT LANGUAJE="Javascript"> function calcula(form) { if (confirm("Est seguro?")) form.resultado.value = eval(form.expr.value) else alert("Vuelva a intentarlo...") }

</SCRIPT> </HEAD> <BODY> <FORM> Introduzca una expresin: <INPUT TYPE="text" NAME="expr" SIZE=15> <INPUT TYPE="button" NAME="Boton" VALUE="Calcular" ONCLICK="calcula(this.form)"> <BR> Resultado: <INPUT TYPE="text" NAME="resultado" SIZE=15> <BR> </FORM> </BODY> </HTML>

7%sicamente, el cdigo se encuadra entre los tags P#CHIP6Q:PD#CHIP6Q, y los par%metros se pasan al mismo mediante un /orm +P>1H?Q:PD>1H?Q, !l lenguaje utilizado es muy parecido al C44, y b%sicamente el cdigo se ejecuta mediante una accin de un botn +:1)C&ICIO2calcula+t$is /orm,2, Al presionar el botn, se llama a la /uncin calcula con el par%metro t$is /orm, que se re/iere al /orm al que pertenece el botn &a /uncin asigna al valor del campo resultado del /orm que se le pasa como par%metro +/orm resultado value, el resultado de evaluar el valor de la e<presin del campo e<pr de dic$o /orm +eval+/orm e<pr value,, Fay ?8CF1# ejemplos de Javascript en. $ttp-DD""" cE netDRandre""DjavascriptD Incluyendo decenas de calculadoras, juegos y otras yerbas; All' tambin encontrar%n la documentacin y un tutorial sobre Javascript &as clases en Java

7ueno, antes que nada conviene saber que en Java $ay un montn de clases ya de/inidas y utilizables Sstas vienen en las bibliotecas est%ndar. java lang 0 clases esenciales, n9meros, strings, objetos, compilador, runtime, seguridad y t$reads +es el 9nico paquete que se incluye autom%ticamente en todo programa Java, . java io 0 clases que manejan entradas y salidas . java util 0 clases 9tiles, como estructuras genricas, manejo de /ec$a, $ora y strings, n9mero aleatorios, etc . java net 0 clases para soportar redes- 8H&, 6CP, 85P, IP, etc . java a"t 0 clases para manejo de inter/ace gr%/ica, ventanas, etc . java a"t image 0 clases para manejo de im%genes . java a"t peer 0 clases que conectan la inter/ace gr%/ica a implementaciones dependientes de la plata/orma +moti/, "indo"s, . java applet 0 clases para la creacin de applets y recursos para reproduccin de audio Para que se den una idea, los n9meros enteros, por ejemplo, son 2instancias2 de una clase no rede/inible, Integer, que desciende de la clase )umber e implementa los siguientes atributos y mtodospublic final class java.lang.Integer extends java.lang.Number { // Atributos public final static int MAX_VALUE; public final static int MIN_VALUE; // Mtodos Constructores public Integer(int value); public Integer(String s); // Ms Mtodos public double doubleValue(); public boolean equals(Object obj); public float floatValue(); public static Integer getInteger(String nm);

public static Integer getInteger(String nm, int val); public static Integer getInteger(String nm, Integer val); public int hashCode(); public int intValue(); public long longValue(); public static int parseInt(String s); public static int parseInt(String s, int radix); public static String toBinaryString(int i); public static String toHexString(int i); public static String toOctalString(int i); public String toString(); public static String toString(int i); public static String toString(int i, int radix); public static Integer valueOf(String s); public static Integer valueOf(String s, int radix); }

?uc$o, no3 !sto tambin nos da algunas ideas. la estructura de una clase . caramba, $ay mtodos repetidos; 5e la estructura enseguida $ablaremos= en cuanto a los mtodos repetidos +como parseInt por ejemplo,, al llamarse al mtodo el compilador decide cu%l de las implementaciones del mismo usar bas%ndose en la cantidad y tipo de par%metros que le pasamos Por ejemplo, parseInt+2JTA2, y parseInt+2JTA2,J@,, al compilarse, generar%n llamados a dos mtodos distintos !structura de una clase 8na clase consiste enalgunas_palabras class nombre_de_la_clase [algo_ms] { [lista_de_atributos] [lista_de_mtodos]

&o que est% entre U y V es opcional: Wa veremos qu poner en 2algunasXpalabras2 y 2algoXm%s2, por a$ora sigamos un poco m%s &a lista de atributos +nuestras viejas variables locales, sigue el mismo /ormato de C- se de/ine primero el tipo y luego el nombre del atributo, y /inalmente el 2=2
public final static int MAX_VALUE;

6ambin tenemos 2algunasXpalabras2 adelante, pero en seguida las analizaremos !n cuanto a los mtodos, tambin siguen la sinta<is del C= un ejemplopublic int incContador() { // declaracin y apertura de { cnt++; // instrucciones, separadas por ";" return(cnt); } // cierre de }

>inalmente, se aceptan comentarios entre DY y YD, como en C, o bien usando DD al principio del comentario +el comentario termina al /inal de la l'nea, Veamos un ejemplo// Implementacin de un contador sencillo // GRABAR EN UN ARCHIVO "Contador.java" (OJO CON LAS MAYUSCULAS!) // COMPILAR CON: "javac Contador.java" (NO OLVIDAR EL .java!) // ESTA CLASE NO ES UNA APLICACION, pero nos va a servir enseguida public class Contador { // Se define la clase Contador // Atributos int cnt; // Un entero para guardar el valor actual // Constructor // Un mtodo constructor public Contador() { // lleva el mismo nombre que la clase cnt = 0; // Simplemente, inicializa (1) } // Mtodos public int incCuenta() { // Un mtodo para incrementar el contador

cnt++; // incrementa cnt return cnt; // y de paso devuelve el nuevo valor } public int getCuenta() { // Este slo devuelve el valor actual return cnt; // del contador } }

Cuando, desde una aplicacin u otro objeto, se crea una instancia de la clase Contador, mediante la instruccinnew Contador()

!l compilador busca un mtodo con el mismo nombre de la clase y que se corresponda con la llamada en cuanto al tipo y n9mero de par%metros 5ic$o mtodo se llama Constructor, y una clase puede tener m%s de un constructor +no as' un objeto o instancia, ya que una vez que /ue creado no puede recrearse sobre s' mismo, !n tiempo de ejecucin, al encontrar dic$a instruccin, el intrprete reserva espacio para el objetoDinstancia, crea su estructura y llama al constructor 1 sea que el e/ecto de ne" Contador+, es, precisamente, reservar espacio para el contador e inicializarlo en cero !n cuanto a los otros mtodos, se pueden llamar desde otros objetos +lo que incluye a las aplicaciones, del mismo modo que se llama una /uncin desde C Por ejemplo, usemos nuestro contador en un programa bien sencillo que nos muestre cmo evoluciona// Usemos nuestro contador en una mini-aplicacin // GRABAR EN UN ARCHIVO "Ejemplo1.java" (OJO CON LAS MAYUSCULAS!) // COMPILAR CON: "javac Ejemplo.java" (NO OLVIDAR EL .java!) // EJECUTAR CON: "java Ejemplo1" (SIN el .java) import java.io.*; // Uso la biblioteca de entradas/salidas public class Ejemplo1 { // IMPORTANTE: Nombre de la clase // igual al nombre del archivo! // entero para asignarle el valor del contador e imprimirlo

// aunque en realidad no me hace falta. static int n; // y una variable tipo Contador para instanciar el objeto static Contador laCuenta; // ESTE METODO, MAIN, ES EL QUE HACE QUE ESTO SE COMPORTE // COMO APLICACION. Es donde arranca el programa cuando ejecuto "java Ejemplo1" // NOTA: main debe ser public & static. public static void main ( String args[] ) { System.out.println ("Cuenta "); // Imprimo el ttulo laCuenta = new Contador(); // Creo una instancia del Contador System.out.println (laCuenta.getCuenta()); // 0 - Imprimo el valor actual (cero!) n = laCuenta.incCuenta(); // 1 - Asignacin e incremento System.out.println (n); // Ahora imprimo n laCuenta.incCuenta(); // 2 - Lo incremento (no uso el valor System.out.println (laCuenta.getCuenta()); // de retorno) y lo imprimo System.out.println (laCuenta.incCuenta()); // 3 - Ahora todo en un paso! } }

!n el cap'tulo III vamos a analizar este programa en detalle Por a$ora veamos la di/erencia con un applet que $aga lo mismo// Applet de accin similar a la aplicacin Ejemplo1 // GRABAR EN ARCHIVO: "Ejemplo2.java" // COMPILAR CON: "javac Ejemplo2.java" // PARA EJECUTAR: Crear una pgina HTML como se indica luego import java.applet.*; import java.awt.*; public class Ejemplo2 extends Applet {

static int n; static Contador laCuenta; // Constructor public Ejemplo2 () { laCuenta = new Contador(); } // El mtodo paint se ejecuta cada vez que hay que redibujar // NOTAR EL EFECTO DE ESTO CUANDO SE CAMBIA DE TAMAO LA // VENTANA DEL NAVEGADOR! public void paint (Graphics g) { g.drawString ("Cuenta...", 20, 20); g.drawString (String.valueOf(laCuenta.getCuenta()), 20, 35 ); n = laCuenta.incCuenta(); g.drawString (String.valueOf(n), 20, 50 ); laCuenta.incCuenta(); g.drawString (String.valueOf(laCuenta.getCuenta()), 20, 65 ); g.drawString (String.valueOf(laCuenta.incCuenta()), 20, 80 ); } }

A$ora es necesario crear una p%gina F6?& para poder visualizarlo Para esto, crear y luego cargar el arc$ivo ejemploE $tm con un bro"ser que soporte Java +o bien ejecutar en la ventana 51#2appletvie"er ejemploE $tm2,<HTML> <HEAD> <TITLE>Ejemplo 2 - Applet Contador</TITLE> </HEAD> <BODY> <applet code="Ejemplo2.class" width=170 height=150> </applet>

PD715WQ PDF6?&Q Para terminar este cap'tulo, observemos las di/erencias entre la aplicacin standalone y el applet. &a aplicacin usa un mtodo main, desde donde arranca . !l applet, en cambio, se arranca desde un constructor +mtodo con el mismo nombre que la clase, Adem%s. !n la aplicacin utilizamos #ystem out println para imprimir en la salida est%ndar . !n el applet necesitamos 2dibujar2 el te<to sobre un /ondo gr%/ico, por lo que usamos el mtodo g dra"#tring dentro del mtodo paint +que es llamado cada vez que es necesario redibujar el applet, Con poco trabajo se pueden combinar ambos casos en un solo objeto, de modo que la misma clase sirva para utilizarla de las dos maneras// Archivo: Ejemplo3.java // Compilar con: javac Ejemplo3.java import java.applet.*; import java.awt.*; import java.io.*; public class Ejemplo3 extends Applet { static int n; static Contador laCuenta; public Ejemplo3 () { laCuenta = new Contador(); } public static void main(String args[]) { laCuenta = new Contador(); paint(); } public static void paint () {

System.out.println ("Cuenta..."); System.out.println (laCuenta.getCuenta()); n = laCuenta.incCuenta(); System.out.println (n); laCuenta.incCuenta(); System.out.println (laCuenta.getCuenta()); System.out.println (laCuenta.incCuenta()); } public void paint (Graphics g) { g.drawString ("Cuenta...", 20, 20); g.drawString (String.valueOf(laCuenta.getCuenta()), 20, 35 ); n = laCuenta.incCuenta(); g.drawString (String.valueOf(n), 20, 50 ); laCuenta.incCuenta(); g.drawString (String.valueOf(laCuenta.getCuenta()), 20, 65 ); g.drawString (String.valueOf(laCuenta.incCuenta()), 20, 80 ); } }

!sta clase puede ejecutarse tanto con 2java !jemploT2 en una ventana 51#, como cargarse desde una p%gina F6?& con<applet code="Ejemplo3.class" width=170 height=150> </applet>

)otar que conviene probar el applet con el appletvie"er +2appletvie"er ejemploT $tm2,, ya que ste indica en la ventana 51# si $ay alg9n error durante la ejecucin &os bro"sers dejan pasar muc$os errores, simplemente suprimiendo la salida a pantalla del cdigo errneo )otar que en todo este desarrollo de las clases !jemploJ, !jemploE y !jemploT, en ning9n momento volvimos a tocar la clase Contador; !structura de clases

Vamos a comenzar analizando la clase Contador, para ir viendo las partes que /orman una clase una por una y en detalle !ste cap'tulo va a ser un poco aburrido por lo e<$austivo +aunque algunos puntos m%s complicados como las e<cepciones y los t$reads los dejaremos para despus,, pero me parece bueno tener un resumen completo de la sinta<is desde a$ora &uego iremos armando pequeGas aplicaciones para probar cada cosa Hecordemos la de/inicin de la clase Contador// Implementacin de un contador sencillo public class Contador { // Atributos int cnt; // Constructor public Contador() { cnt = 0; } // Mtodos public int incCuenta() { cnt++; return cnt; } public int getCuenta() { return cnt; }}

5eclaracin de la clase &a clase se declara mediante la l'nea public class Contador !n el caso m%s general, la declaracin de una clase puede contener los siguientes elementosUpublicV U/inal Z abstractV class Clase Ue<tends Clase?adreV Uimplements Inter/aseJ U, Inter/aseE V:V o bien, para inter/acesUpublicV inter/ace Inter/ase Ue<tends Inter/ase?adreJ U, Inter/ase?adreE V:V

Como se ve, lo 9nico obligatorio es class y el nombre de la clase &as inter/ases son un caso de clase particular que veremos m%s adelante Public, /inal o abstract 5e/inir una clase como p9blica +public, signi/ica que puede ser usada por cualquier clase en cualquier paquete #i no lo es, solamente puede ser utilizada por clases del mismo paquete +m%s sobre paquetes luego= b%sicamente, se trata de un grupo de clases e inter/aces relacionadas, como los paquetes de biblioteca inclu'dos con Java, 8na clase /inal +/inal, es aquella que no puede tener clases que la $ereden !sto se utiliza b%sicamente por razones de seguridad +para que una clase no pueda ser reemplazada por otra que la $erede,, o por diseGo de la aplicacin 8na clase abstracta +abstract, es una clase que puede tener $erederas, pero no puede ser instanciada !s, literalmente, abstracta +como la clase )umber de/inida en java lang, [Para qu sirve3 Para modelar conceptos Por ejemplo, la clase )umber es una clase abstracta que representa cualquier tipo de n9meros +y sus mtodos no est%n implementados- son abstractos,= las clases descendientes de sta, como Integer o >loat, s' implementan los mtodos de la madre )umber, y se pueden instanciar Por lo dic$o, una clase no puede ser /inal y abstract a la vez +ya que la clase abstract requiere descendientes:, [8n poco complejo3 #e va a entender mejor cuando veamos casos particulares, como las inter/ases +que por de/inicin son abstractas ya que no implementan sus mtodos, !<tends &a instruccin e<tends indica de qu clase desciende la nuestra #i se omite, Java asume que desciende de la superclase 1bject Cuando una clase desciende de otra, esto signi/ica que $ereda sus atributos y sus mtodos +es decir que, a menos que los rede/inamos, sus mtodos son los mismos que los de la clase madre y pueden utilizarse en /orma transparente, a menos que sean privados en la clase madre o, para subclases de otros paquetes, protegidos o propios del paquete, Veremos la cali/icacin de mtodos muy pronto, a no desesperar; Implements 8na inter/ase +inter/ace, es una clase que declara sus mtodos pero no los implementa= cuando una clase implementa +implements, una o m%s inter/ases, debe contener la implementacin de todos los mtodos +con las mismas listas de par%metros, de dic$as inter/ases

!sto sirve para dar un ascendiente com9n a varias clases, oblig%ndolas a implementar los mismos mtodos y, por lo tanto, a comportarse de /orma similar en cuanto a su inter/ase con otras clases y subclases Inter/ace 8na inter/ase +inter/ace,, como se dijo, es una clase que no implementa sus mtodos sino que deja a cargo la implementacin a otras clases &as inter/ases pueden, asimismo, descender de otras inter/ases pero no de otras clases 6odos sus mtodos son por de/inicin abstractos y sus atributos son /inales +aunque esto no se indica en el cuerpo de la inter/ase, #on 9tiles para generar relaciones entre clases que de otro modo no est%n relacionadas +$aciendo que implementen los mismos mtodos,, o para distribuir paquetes de clases indicando la estructura de la inter/ase pero no las clases individuales +objetos annimos, #i bien di/erentes clases pueden implementar las mismas inter/ases, y a la vez descender de otras clases, esto no es en realidad $erencia m9ltiple ya que una clase no puede $eredar atributos ni mtodos de una inter/ace= y las clases que implementan una inter/ase pueden no estar ni siquiera relacionadas entre s' !l cuerpo de la clase !l cuerpo de la clase, encerrado entre \ y ], es la lista de atributos +variables, y mtodos +/unciones, que constituyen la clase )o es obligatorio, pero en general se listan primero los atributos y luego los mtodos 5eclaracin de atributos !n Java no $ay variables globales= todas las variables se declaran dentro del cuerpo de la clase o dentro de un mtodo &as variables declaradas dentro de un mtodo son locales al mtodo= las variables declaradas en el cuerpo de la clase se dice que son miembros de la clase y son accesibles por todos los mtodos de la clase Por otra parte, adem%s de los atributos de la propia clase se puede acceder a todos los atributos de la clase de la que desciende= por ejemplo, cualquier clase que descienda de la clase Polygon $ereda los atributos npoints, <points e ypoints >inalmente, los atributos miembros de la clase pueden ser atributos de clase o atributos de instancia= se dice que son atributos de clase si se usa la palabra clave static- en ese caso la variable es 9nica para todas las instancias +objetos, de la clase +ocupa un 9nico lugar en memoria, #i no se usa static, el sistema crea un lugar nuevo para esa variable con cada instancia +o sea que es independiente para cada objeto,

&a declaracin sigue siempre el mismo esquema[private |protected|public] [static] [final] [transient] [volatile] Tipo NombreVariable [= Valor];

Private, protected o public Java tiene A tipos de acceso di/erente a las variables o mtodos de una clase- privado, protegido, p9blico o por paquete +si no se especi/ica nada, 5e acuerdo a la /orma en que se especi/ica un atributo, objetos de otras clases tienen distintas posibilidades de accederlosAcceso desde- private protected public +pac^age, la propia clase # # # # subclase en el mismo paquete ) # # # otras clases en el mismo paquete )### subclases en otros paquetes ) M # ) otras clases en otros paquetes ) ) # ) #- puede acceder )- no puede acceder M- puede acceder al atributo en objetos que pertenezcan a la subclase, pero no en los que pertenecen a la clase madre !s un caso especial = m%s adelante veremos ejemplos de todo esto #tatic y /inal Como ya se vio, static sirve para de/inir un atributo como de clase, o sea 9nico para todos los objetos de la clase !n cuanto a /inal, como en las clases, determina que un atributo no pueda ser sobreescrito o rede/inido 1 sea- no se trata de una variable, sino de una constante

6ransient y volatile #on casos bastante particulares y que no $ab'an sido implementados en Java J K 6ransient denomina atributos que no se graban cuando se arc$iva un objeto, o sea que no /orman parte del estado permanente del mismo Volatile se utiliza con variables modi/icadas asincrnicamente por objetos en di/erentes t$reads +literalmente 2$ilos2, tareas que se ejecutan en paralelo,= b%sicamente esto implica que distintas tareas pueden intentar modi/icar la variable simult%neamente, y volatile asegura que se vuelva a leer la variable +por si /ue modi/icada, cada vez que se la va a usar +esto es, en lugar de usar registros de almacenamiento como bu//er, &os tipos de Java &os tipos de variables disponibles son b%sicamente T. tipos b%sicos +no son objetos, . arreglos +arrays, . clases e inter/ases Con lo que vemos que cada vez que creamos una clase o inter/ase estamos de/iniendo un nuevo tipo &os tipos b%sicos son6ipo 6amaGoD>ormato 5escripcin byte L0bit complemento a E !ntero de un byte s$ort J@0bit complemento a E !ntero corto int TE0bit complemento a E !ntero long @A0bit complemento a E !ntero largo /loat TE0bit I!!! _CA Punto /lotante, precisin simple double @A0bit I!!! _CA Punto /lotante, precisin doble c$ar J@0bit caracter 8nicode 8n caracter boolean true, /alse Valor booleano +verdadero o /also, &os arrays son arreglos de cualquier tipo +b%sico o no, Por ejemplo, e<iste una clase Integer= un arreglo de objetos de dic$a clase se notar'a-

Integer vector[ ];

&os arreglos siempre son din%micos, por lo que no es v%lido poner algo comoInteger cadena[5];

Aunque s' es v%lido inicializar un arreglo, como enint das[ ] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; char letras[ ] = { 'E', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D' }; String nombres[ ] = new String[12];

)ota al margen- no con/undir un #tring +cadena de caracteres, con un arreglo de caracteres; #on cosas bien distintas; Wa $ablaremos m%s adelante de las clases #tring y #tring7u//er !n Java, para todas las variables de tipo b%sico se accede al valor asignado a la misma directamente +no se conoce la direccin de memoria que ocupa, Para las dem%s +arrays, clases o inter/ases,, se accede a travs de un puntero a la variable !l valor del puntero no es accesible ni se puede modi/icar +como en C,= Java no necesita esto y adem%s eso atentar'a contra la robustez del lenguaje 5e $ec$o, en Java no e<isten los tipos pointer, struct o union 8n objeto es m%s que una estructura, y las uniones no se $acen necesarias con un mtodo de programacin adecuado +y adem%s se evita la posibilidad de acceder a los datos incorrectamente, Algo m%s respecto a los arreglos- ya que Java gestiona el manejo de memoria para los mismos, y lanza e<cepciones si se intenta violar el espacio asignado a una variable, se evitan problemas t'picos de C como acceder a lugares de memoria pro$ibidos o /uera del lugar de/inido para la variable +como cuando se usa un sub'ndice m%s grande que lo previsto para un arreglo:, W los mtodos: &os mtodos, como las clases, tienen una declaracin y un cuerpo &a declaracin es del tipo[private |protected|public] [static] [abstract] [final] [native ] [synchronized] TipoDevuelto NombreMtodo ( [tipo1 nombre1[, tipo2 nombre2 ]] ) [throws excepcin1 [,excepcin2] ]

A no preocuparse- poco a poco aclararemos todo con ejemplos 7%sicamente, los mtodos son como las /unciones de C- implementan, a travs de /unciones, operaciones y estructuras de control, el c%lculo de alg9n par%metro que es el que devuelven al

objeto que los llama #lo pueden devolver un valor +del tipo 6ipo5evuelto,, aunque pueden no devolver ninguno +en ese caso 6ipo5evuelto es void, Como ya veremos, el valor de retorno se especi/ica con la instruccin return, dentro del mtodo &os mtodos pueden utilizar valores que les pasa el objeto que los llama +par%metros,, indicados con tipoJ nombreJ, tipoE nombreE: en el esquema de la declaracin !stos par%metros pueden ser de cualquiera de los tipos ya vistos #i son tipos b%sicos, el mtodo recibe el valor del par%metro= si son arrays, clases o inter/ases, recibe un puntero a los datos +re/erencia, Veamos un pequeGo ejemplopublic int AumentarCuenta(int cantidad) { cnt = cnt + cantidad; return cnt; }

!ste mtodo, si lo agregamos a la clase Contador, le suma cantidad al acumulador cnt !n detalle. el mtodo recibe un valor entero +cantidad, . lo suma a la variable de instancia cnt . devuelve la suma +return cnt, [Cmo $ago si quiero devolver m%s de un valor3 Por ejemplo, supongamos que queremos $acer un mtodo dentro de una clase que devuelva la posicin del mouse &o siguiente no sirvevoid GetMousePos(int x, int y) { x = .; // esto no sirve! y = .; // esto tampoco! }

Porque el mtodo no puede modi/icar los par%metros < e y +que $an sido pasados por valor, o sea que el mtodo recibe el valor numrico pero no sabe dnde est%n las variables en memoria, &a solucin es utilizar, en lugar de tipos b%sicos, una claseclass MousePos { public int x, y; } y luego utilizar esa clase en nuestro mtodo: void GetMousePos( MousePos m ) {

m.x = ; m.y = ; }

!l resto de la declaracin Public, private y protected act9an e<actamente igual para los mtodos que para los atributos, as' que veamos el resto &os mtodos est%ticos +static,, son, como los atributos, mtodos de clase= si el mtodo no es static es un mtodo de instancia !l signi/icado es el mismo que para los atributos- un mtodo static es compartido por todas las instancias de la clase Wa $emos $ablado de las clases abstractas= los mtodos abstractos +abstract, son aquellos de los que se da la declaracin pero no la implementacin +o sea que consiste slo del encabezamiento, Cualquier clase que contenga al menos un mtodo abstracto +o cuya clase madre contenga al menos un mtodo abstracto que no est implementado en la $ija, es una clase abstracta !s /inal un mtodo que no puede ser rede/inido por ning9n descendiente de la clase &as clases native son aquellas que se implementan en otro lenguaje +por ejemplo C o C44, propio de la m%quina #un aconseja utilizarlas bajo riesgo propio, ya que en realidad son ajenas al lenguaje Pero la posibilidad de usar viejas bibliotecas que uno arm y no tiene ganas de reescribir e<iste; &as clases sync$ronized permiten sincronizar varios t$reads para el caso en que dos o m%s accedan concurrentemente a los mismos datos 5e nuevo, m%s detalles $abr% en el /uturo, cuando $ablemos de t$reads >inalmente, la cl%usula t$ro"s sirve para indicar que la clase genera determinadas e<cepciones !l cuerpo de los mtodos 1tra vez recordaremos nuestra vieja clase Contador// Implementacin de un contador sencillo public class Contador { .. public int incCuenta() { cnt++; return cnt; }

5entro de los mtodos pueden incluirse. 5eclaracin de variables locales . Asignaciones a variables . 1peraciones matem%ticas . &lamados a otros mtodos. dentro de la clase . de instancia, de otras clases . de clase, de cualquier clase . !structuras de control . !<cepciones +try, catc$, que veremos m%s adelante, 5eclaracin de variables locales &as variables locales se declaran igual que los atributos de la claseTipo NombreVariable [= Valor];

!j- int suma=


float precio; Contador laCuenta;

#lo que aqu' no se declaran private, public, etc , sino que las variables de/inidas dentro del mtodo slo son accesibles por l &as variables pueden inicializarse al crearseEj: int suma = 0; float precio = 12.3; Contador laCuenta = new Contador ( );

Asignaciones a variables #e asigna un valor a una variable mediante el signo OVariable = Constante | Expresin ;

Ej: suma = suma + 1; precio = 1.05 * precio; laCuenta.cnt = 0;

!l 9ltimo caso es v%lido si cnt es una variable p9blica de la clase Contador Personalmente no creo conveniente acceder directamente a variables de otro objeto, ya que /uturas modi/icaciones del objeto llamado o del que llama puede propender la di/usin de errores: !s mejor usar mtodos como getCuenta o un $ipottico inicializarContador para ello 5e $ec$o, algunos sugieren que todas las variables de una clase se declaren como private !n el primer caso, o sea en generalVariable O Variable 1perador !<presin= se puede escribir en /orma m%s sencillaVariable 1peradorO !<presin= Por ejemplo, suma O suma 4 B 0 cantidad= puede escribirse- suma 4O B0cantidad= y precio O precio Y K B_= como- precio YO K B_= 1peraciones matem%ticas Fay varios tipos de operadores8narios- 4 0 44 00 R ; +tipo, : etc #e colocan antes +o en algunos casos despus, de la constante o e<presin Por ejemplo- 0cnt= DD cambia de signo= por ejemplo si cnt es JE el resultado es 0JE= cnt no cambia 44cnt= DD equivale a cnt 4O J= cnt44= DD equivale a cnt 4OJ= veremos la di/erencia al $ablar de estructuras de control 00cnt= DD equivale a cnt 0O J= cnt00= DD equivale a cnt 0O J= 7inarios- 4 0 Y D ` : etc Van entre dos constantes o e<presiones o combinacin de ambas

Por ejemplo- cnt 4 E= DD debuelve la suma de ambos promedio 4 + valor D E,= DD como se ve, se pueden usar parntesis $oras D $ombres= DD divisin acumulado ` T= DD resto de la divisin entera entre ambos )ota- 4 sirve tambin para concatenar cadenas de caracteres= $ablaremos de #tring y #tring7u//er pronto Cuando se mezclan #trings y valores numricos, stos se convierten autom%ticamente a cadenas2&a /rase tiene 2 4 cant 4 2 letras2 se convierte en- 2&a /rase tiene J_ letras2 DD suponiendo que cant O J_ Precedencia de operadores en Java &a siguiente es la precedencia de los operadores en e<presiones compuestas 5e todos modos, como en todos los lenguajes, se recomienda usar parntesis en caso de duda Pos/ijos UV +params, e<pr44 e<pr00 1peradores unarios 44e<pr 00e<pr 4e<pr 0e<pr R ; Creacin y 2cast2 ne" +type, ?ultiplicativos Y D ` Aditivos 4 0 5esplazamiento PP QQ QQQ Helacionales P Q PO QO instanceo/ Igualdad OO ;O A)5 bit a bit a 1H e<clusivo bit a bit b 1H inclusivo bit a bit Z A)5 lgico aa 1H lgico ZZ Condicional 3 -

Asignacin O 4O 0O YO DO `O bO aO ZO PPO QQO QQQO Algunos ejemplosUV de/ine arreglos- int listaUV= +params, es la lista de par%metros cuando se llama a un mtodo- convertir+valor, base,= ne" permite crear una instancia de un objeto- ne" Contador+,= +type, cambia el tipo de una e<presin a otro- +/loat,+total ` JK,= QQ desplaza bit a bit un valor binario- base QQ T= PO devuelve 2true2 si un valor es menor o igual que otro- total PO ma<imo= instanceo/ devuelve 2true2 si el objeto es una instancia de la clase- papa instanceo/ Comida= ZZ devuelve 2true2 si cualquiera de las e<presiones es verdad- +aPC, ZZ +aQEK, &lamadas a mtodos #e llama a un mtodo de la misma clase simplemente con el nombre del mtodo y los par%metros entre parntesis, como se ve, entre otros, en el ejemplo en negrita// Archivo: Complejo.java // Compilar con: javac Complejo.java public final class Complejo extends Number { // atributos: private float x; private float y; // constructor: public Complejo(float rx, float iy) { x = rx; y = iy; } // mtodos: public float Norma() { return (float)Math.sqrt(x*x+y*y);

} // obligatorios (son abstractos en Number): public double doubleValue() { return (double)Norma( ); } public float floatValue() { return Norma(); } public int intValue() { return (int)Norma(); } public long longValue() { return (long)Norma(); } public String toString() { return "("+x+")+i("+y+")"; } }

Pueden probar la clase +m'nima, con el siguiente ejemplo de aplicacin= la l'nea en negrita es un ejemplo de un llamado a un mtodo de un objeto de otra clase )otar que es este caso, es necesario llamar al mtodo sobre un objeto +instancia, e<istente, por lo que se indicaNombre_del_Objeto<punto>Nombre_del_Mtodo(parmetros) // Archivo: Ejemplo4.java // Compilar con: javac Ejemplo4.java // Ejecutar con: java Ejemplo4 import java.io.*; public class Ejemplo4 { public static void main(String args[]) { Complejo numComp = new Complejo(4,-3);

System.out.println(numComp.toString()); System.out.println(numComp.Norma()); }}

!n la clase Complejo tenemos tambin un ejemplo de un llamado a un mtodo de clase, o sea staticreturn (float)Math.sqrt(x*x+y*y);

Como el mtodo es de clase, no $ace /alta llamarlo para un objeto en particular !n ese caso, en lugar del nombre de un objeto e<istente se puede utilizar directamente el nombre de la claseNombre_de_la_Clase<punto>Nombre_del_Mtodo(parmetros)

&as estructuras de control &as estructuras de control en Java son b%sicamente las misma que en C, con e<cepcin del goto, que no e<iste +al /in un lenguaje serio; ,
if[else]

&a m%s com9n de todas, permite ejecutar una instruccin +o secuencia de instrucciones, si se da una condicin dada +o, mediante la cl%usula else, ejecutar otra secuencia en caso contrario,
if (expresin_booleana) instruccin_si_true; [else instruccin_si_false;] o bien: if (expresin_booleana) { instrucciones_si_true; } else { instrucciones_si_false; }

Por ejemplopublic final String toString() { if (y<0) return x+"-i"+(-y); else

return +x+"+i"+y; }

#"itc$:case:bra^e:de/ault Permite ejecutar una serie de operaciones para el caso de que una variable tenga un valor entero dado &a ejecucin saltea todos los case $asta que encuentra uno con el valor de la variable, y ejecuta desde all' $asta el /inal del case o $asta que encuentre un brea^ , en cuyo caso salta al /inal del case !l de/ault permite poner una serie de instrucciones que se ejecutan en caso de que la igualdad no se de para ninguno de los case
switch (expresin_entera) { case (valor1): instrucciones_1; [break;] case (valor2): instrucciones_2; [break;] .. case (valorN): instrucciones_N; [break;] default: instrucciones_por_defecto; }

Por ejemploswitch (mes) { case (2): if (bisiesto()) dias=29; else dias=31; break; case (4): case (6): case (9): case (11): dias = 30; break; default: dias = 31;

*$ile Permite ejecutar un grupo de instrucciones mientras se cumpla una condicin dadawhile (expresin_booleana) { instrucciones }

Por ejemplowhile ( linea != null) { linea = archivo.LeerLinea(); System.out.println(linea); }

5o:"$ile #imilar al anterior, slo que la condicin se eval9a al /inal del ciclo y no al principiodo { instrucciones } while (expresin_booleana);

Por ejemplodo { linea = archivo.LeerLinea(); if (linea != null) System.out.println(linea); } while (linea != null);

>or 6ambin para ejecutar en /orma repetida una serie de instrucciones= es un poco m%s complejofor ( instrucciones_iniciales; condicin_booleana; instruccion_repetitiva_x ) { instrucciones }

#i bien las instrucciones pueden ser cualquiera +el bucle se repite mientras la condicin sea verdadera,, lo usual es utilizarlo para 2contar2 la cantidad de veces que se repiten las instrucciones= se podr'a indicar as'for ( contador = valor_inicial; contador < valor_final; contador++ ) { instrucciones }

Por ejemplofor ( i=0; i<10; i++ ) { System.out.println( i ); }

o, para contar $acia atr%sfor ( i=10; I>0; I-- ) { System.out.println( i ); }

7rea^ y continue !stas instrucciones permiten saltar al /inal de una ejecucin repetitiva +brea^, o al principio de la misma +continue, Por ejemplo, enimport java.io.*; class Bucles { public static void main (String argv[ ]) { int i=0; for (i=1; i<5; i++) { System.out.println("antes "+i); if (i==2) continue; if (i==3) break; System.out.println("despus "+i); } }

&a salida esantes J despus J antes E antes T Por qu3 2i2 comienza en J +imprime 2antes2 y 2despus2,= cuando pasa a E, el continue salta al principio del bucle +no imprime el 2despus2, >inalmente, cuando 2i2 vale T, el brea^ da por terminado el bucle /or 1tras Fay otras instrucciones que controlan el /lujo del programa. sync$ronized +para ver junto con los t$reads, . catc$, . t$ro", . try, . /inally +para ver con las e<cepciones, A$ora s', podemos usar todo nuestro conocimiento sobre Java para ir creando algunas aplicaciones y de paso ir viendo las bibliotecas est%ndar Fagamos algo 7ueno, vamos a $acer una pequeGa aplicacin para practicar un poco Para empezar, vamos a desarrollar un poquito una clase para trabajar con n9meros complejos &a clase Complejo
// grabar como Complejo.java // compilar con "javac Complejo.java" public final class Complejo extends Number { // atributos: private float x;

private float y; // constructores: public Complejo() { x = 0; y = 0; } public Complejo(float rx, float iy) { x = rx; y = iy; } // mtodos: // Norma public final float Norma() { return (float)Math.sqrt(x*x+y*y); } public final float Norma(Complejo c) { return (float)Math.sqrt(c.x*c.x+c.y*c.y); } // Conjugado public final Complejo Conjugado() { Complejo r = new Complejo(x,-y); return r; } public final Complejo Conjugado(Complejo c) { Complejo r = new Complejo(c.x,-c.y); return r; } // obligatorios (son abstractos en Number):

public final double doubleValue() { return (double)Norma(); } public final float floatValue() { return Norma(); } public final int intValue() { return (int)Norma(); } public final long longValue() { return (long)Norma(); } public final String toString() { if (y<0) return x+"-i"+(-y); else return x+"+i"+y; } // Operaciones matemticas public static final Complejo Suma(Complejo c1, Complejo c2) { return new Complejo(c1.x+c2.x,c1.y+c2.y); } public static final Complejo Resta(Complejo c1, Complejo c2) { return new Complejo(c1.x-c2.x,c1.y-c2.y); } public static final Complejo Producto(Complejo c1, Complejo c2) { return new Complejo(c1.x*c2.x-c1.y*c2.y,c1.x*c2.y+c1.y*c2.x); }

// Nos va a venir bien para aprender excepciones... // como divisin por cero! public static final Complejo DivEscalar(Complejo c, float f) { return new Complejo(c.x/ f,c.y/f); } public static final Complejo Cociente(Complejo c1, Complejo c2) { float x = c1.x*c2.x+c1.y*c2.y; float y = -c1.x*c2.y+c1.y*c2.x; float n = c2.x*c2.x+c2.y*c2.y; Complejo r = new Complejo(x,y); return DivEscalar(r,n); } }

Podemos $acer algunos comentarios Primero- no $ay include aqu', ya que la 9nica biblioteca que usamos es java lang y se incluye autom%ticamente #egundo- la clase es public /inal, lo que implica que cualquier clase en ste u otros paquetes puede utilizarla, pero ninguna clase puede $eredarla +o sea que es una clase estril , Fagamos un resumen de los atributos y mtodos de la clase// atributos: private float x; private float y;

#iendo privados, no podemos acceder a ellos desde el e<terior Como adem%s la clase es /inal, no $ay /orma de acceder a < e y Adem%s, al no ser static, cada instancia de la clase tendr% su propio < ey
// constructores: public Complejo() public Complejo(float rx, float iy)

&a clase tiene dos constructores, que se di/erencian por su 2/irma2 +signature,, o sea por la cantidad y tipo de par%metros !l primero nos sirve para crear un objeto de tipo Complejo y valor inde/inido +aunque en realidad el mtodo lo inicializa en cero,= con el segundo, podemos de/inir el valor al crearlo
// mtodos: public final float Norma() public final float Norma(Complejo c) public final Complejo Conjugado() public final Complejo Conjugado(Complejo c)

!stos mtodos tambin son duales= cuando los usamos sin par%metros devuelven la norma o el conjugado del objeto individual +instancia,v = miComplejo.Norma(); // por ejemplo otroComplejo = miComplejo.Conjugado();

Con par%metros, en cambio, devuelven la norma o el conjugado del par%metrov = unComplejo.Norma(miComplejo); otroComplejo = unComplejo.Conjugado(miComplejo);

)otar que lo siguiente es inv%lidootroComplejo = Complejo.Norma(miComplejo); // NO SE PUEDE!

porque el mtodo no es static, por lo tanto debe llamarse para una instancia en particular +en este caso, unComplejo,
// obligatorios (son abstractos en Number): public final double doubleValue() public final float floatValue() public final int intValue() public final long longValue()

!stos mtodos es obligatorio de/inirlos, ya que en la clase madre )umber son mtodos abstractos, o sea que debemos implementarlos aqu' Como todos los mtodos de esta clase son /inal, o sea que no puede ser rede/inido )o es importante en realidad puesto que la clase no puede tener descendientes
public final String toString()

!ste mtodo nos sirve para representar el complejo como una cadena de caracteres, de la /orma <4iy
// Operaciones matemticas public static final Complejo Suma(Complejo c1, Complejo c2) public static final Complejo Resta(Complejo c1, Complejo c2) public static final Complejo Producto(Complejo c1, Complejo c2) public static final Complejo DivEscalar(Complejo c, float f) public static final Complejo Cociente(Complejo c1, Complejo c2)

Aqu' de/inimos varias operaciones matem%ticas )otar que se $an de/inido como static, o sea que los mtodos son 9nicos independientemente de las instancias !sto permite que los podamos ejecutar sobre una instancia o directamente sobre la clasemiComplejo = unComplejo.Suma(comp1,comp2); // vale miComplejo = Complejo.Suma(comp1,comp2); // TAMBIEN VALE!

Por ejemplo, la siguiente aplicacin nos muestra cmo podemos usar algunos de estos mtodos// Archivo: Ejemplo5.java // Compilar con: javac Ejemplo5.java // Ejecutar con: java Ejemplo5 import java.io.*; public class Ejemplo5 { public static void main(String args[]) { Complejo c1 = new Complejo(4,-3); System.out.println(c1+"\tNorma="+c1.Norma()); Complejo c2 = new Complejo(-2,5); System.out.println(c2+"\tNorma="+c2.Norma()+"\n"); System.out.println("("+c1+")/4 :"+Complejo.DivEscalar(c1,4)); System.out.println("Suma : "+Complejo.Suma(c1,c2)); System.out.println("Resta : "+Complejo.Resta(c1,c2).toString()); System.out.println("Multip: "+Complejo.Producto(c1,c2).toString()); System.out.println("Divis : "+Complejo.Cociente(c1,c2).toString());

} }

Fay varias cosas para notar- por ejemplo, que podemos declarar las variables a la vez que las creamosComplejo c1 = new Complejo(4,-3);

cJ y cE son dos objetos +instancias, de la clase Complejo )otar tambin que no $ace /alta poner para imprimirSystem.out.println(c1.toString().......);

ya que println autom%ticamente usa el mtodo to#tring+, de la clase para imprimir 7asta con poner cJ, como en el programa, aunque cJ to#tring+, tambin es v%lido 6ambin se ve el uso de los mtodos static, accedindolos directamente por la clase, enSystem.out.println("Suma : "+Complejo.Suma(c1,c2));

W tampoco aqu' usamos to#tring+,, aunque no est% mal si se usa Complejo #uma+cJ,cE, to#tring+, Algo sobre los mtodos Analicemos un poco a$ora cmo implementamos los mtodos de la clase Complejo
public final int intValue() { return (int)Norma(); }

Wa que no podemos convertir as' nom%s un complejo en un entero, para implementar estos mtodos $emos elegido usar como valor de retorno la norma del complejo !n este caso, y dado que el mtodo )orma+, devuelve un /loat, usamos typecasting, es decir, lo convertimos en entero precedindolo con +int,
public final String toString() { if (y<0) return x+"-i"+(-y); else return x+"+i"+y; }

Aqu' representamos el complejo en /orma de cadena de caracteres Femos usado el i/ para representar adecuadamente el signo de la parte imaginaria )oten tambin la asombrosa ayuda

que nos brinda Java, al convertir autom%ticamente las variables < e y a #tring para la concatenacin +mediante el signo 242,;
public static final Complejo Cociente(Complejo c1, Complejo c2) { float x = c1.x*c2.x+c1.y*c2.y; float y = -c1.x*c2.y+c1.y*c2.x; float n = c2.x*c2.x+c2.y*c2.y; Complejo r = new Complejo(x,y); return DivEscalar(r,n); }

Aqu' tengan en cuenta que las variables < e y, de/inidas como /loat, no tienen nada que ver con las variables +atributos, de la clase que est%n de/inidas al principio de la misma, sino que son variables locales al mtodo Podemos usar return 5iv!scalar+r,n,, ya que 5iv!scalar es un mtodo propio de la clase= no $ace /alta poner Complejo 5iv!scalar (u pasa con r, el ne" Complejo+<,y, que creamos3 )ada= cuando un objeto no se usa m%s, el 2recogedor de basura2 de Java lo elimina autom%ticamente +tarde o temprano, de la memoria
public final float Norma(Complejo c) { return (float)Math.sqrt(c.x*c.x+c.y*c.y); }

Aqu' estamos usando otra clase, ?at$, que nos permite realizar varias operaciones matem%ticas !sta clase dispone de las constantes ! y PI, y los mtodosabs+<, valor absoluto acos+<, arco coseno asin+<, arco seno atan+<, arco tangente atanE+<,y, componente angular de la representacin polar de <,y ceil+<, menor entero mayor que < cos+<, coseno e<p+<, e<

/loor+<, mayor entero menor que < I!!!remainder+<,y, resto de la divisin <Dy seg9n el est%ndar I!!! _CA log+<, logaritmo natural ma<+<,y, el mayor de < e y min+<,y, el menor de < e y po"+<,y, <y random+, n9mero aleatorio entre K y J rint+<, entero m%s cercano a < +devuelve un doble, round+<, entero m%s cercano a < +devuelve un entero o un long, sin+<, seno sqrt+<, ra'z cuadrada tan+<, tangente Algunos de estos mtodos disparan e<cepciones, como sqrt o log de n9meros negativos ?%s adelante veremos cmo se usan las e<cepciones 1tra clase que $emos estado usando muc$o es la Print#tream, a la que pertenece el mtodo println !n #ystem out println+ , out es un atributo de la clase #ystem, del tipo +clase, Print#treampublic final class System extends Object { // Fields public static PrintStream err; public static InputStream in; public static PrintStream out; // Methods ............. }

Veremos otras bibliotecas +para entradaDsalida, gr%/icos, etc, muy pronto Java a travs de la ventana

Para $acer algo un poco m%s divertido, vamos a empezar a trabajar con la biblioteca java a"t, que es la que contiene todo un grupo de objetos para trabajar con ventanas y sus contenidos- botones, listas, etc )uestra primera ventana !n Java, la clase *indo" +descendiente de Container,, en la biblioteca java a"t, permite implementar ventanas 2peladas2, es decir, sin bordes ni men9s #on la base para cualquier tipo de ventanas +normales, popup, di%logos, etc , !l otro descendiente de Container, Panel, es m%s sencillo a9n y sirve como espacio para que una aplicacin incorpore dentro suyo otros elementos +incluyendo otros paneles, &a inter/ace Java dirige tanto a uno como a otro todos los eventos de teclado, mouse y /oco que los a/ecten +en seguida veremos cmo usar estos eventos, 5e la clase *indo" descienden 5ialog +para implementar di%logos, y >rame, que es una ventana algo m%s completa- ya tiene borde y men9, as' como los botones de cerrar, ma<imizar, etc !l siguiente ejemplo crea una ventana que no $ace nada pero contiene varios elementos= se puede usar directamente +desde la ventana 51# o 8ni< con java !jemplo_, o como applet dentro de una p%gina F6?& #i bien los elementos no disparan ninguna accin, se pueden utilizar con toda su /uncionalidad +por ejemplo, editar el te<to dentro de los cuadros de te<to o presionar el botn,
// grabar como "Ejemplo7.java" // compilar con "javac Ejemplo7.java" import java.awt.*; public class Ejemplo7 extends Frame { boolean inAnApplet = true; public static void main(String args[]) { Ejemplo7 window = new Ejemplo7(); window.inAnApplet = false; window.setTitle("Ejemplo"); window.pack(); window.show(); } public Ejemplo7() {

Panel panelAlto = new Panel(); panelAlto.add("West", new Label("Cartel", Label.CENTER)); panelAlto.add("East", new TextArea("Area de texto", 5, 20)); add("North", panelAlto); Panel panelBajo = new Panel(); panelBajo.add(new TextField("Campo de Texto")); panelBajo.add(new Button("Botn")); add("South",panelBajo); } public boolean handleEvent(Event ev) { if (ev.id == Event.WINDOW_DESTROY) { if (inAnApplet) { dispose(); } else { System.exit(0); } } return super.handleEvent(ev); } }

8n poco de detalle &a clase desciende de >rame +o sea que ser% una ventana con borde, aunque no le vamos a poner men9, Vamos a usar el /lag inAnApplet para saber si se arranc como applet o como aplicacin standalone +$ay que cerrarla en manera di/erente en cada caso,
public class Ejemplo7 extends Frame { boolean inAnApplet = true;

#i se llama como aplicacin standalone, lo primero que se ejecuta es main+ ,= en este caso la aplicacin crea una instancia de !jemplo_ +ejecutando el constructor !jemplo_+, a travs de ne",, de/ine que no es un applet, y llama a tres mtodos de la 2abuela2 "indo". set6itle que de/ine cu%l va a ser el t'tulo que aparece en la ventana . pac^ que dimensiona los elementos que componen la ventana a su tamaGo pre/erido . s$o" que muestra la ventana
public static void main(String args[]) { Ejemplo7 window = new Ejemplo7(); window.inAnApplet = false; window.setTitle("Ejemplo"); window.pack(); window.show(); }

1jo; )o con/undir el objeto +instancia, "indo" con la clase *indo"; #i se carga como applet, entonces se ejecuta el constructor !jemplo_+, como en el caso anteriorpublic Ejemplo7() { Panel panelAlto = new Panel(); panelAlto.add("West", new Label("Cartel", Label.CENTER)); panelAlto.add("East", new TextArea("Area de texto", 5, 20)); add("North", panelAlto); Panel panelBajo = new Panel(); panelBajo.add(new TextField("Campo de Texto")); panelBajo.add(new Button("Botn")); add("South",panelBajo); }

!ste constructor de/ine dos paneles que /orman el contenido de la ventana +panelAlto y panel7ajo,, los llena con un par de componentes y los pone dentro de la ventana +recordar que !jemplo_ es una ventana;, Para verlo m%s claro, se crea el panel +o espacio para contener objetos, con-

Panel panelAlto = new Panel();

#e agregan componentes al panel con el mtodo addpanelAlto.add("West", new Label("Cartel", Label.CENTER)); panelAlto.add("East", new TextArea("Area de texto", 5, 20));

#e agregan el panel dentro de nuestro objeto conadd("North", panelAlto);

que equivale athis.add("North", panelAlto);

lo que se puede ver +aunque es inv%lido porque la clase no es static, comoEjemplo7.add("North", panelAlto);

Como nuestra clase !jemplo_ desciende de >rame, sta de *indo", y sta de Container, el mtodo add lo est% $eredando de su bisabuela; Por otra parte, Panel es $ija de Container, y usa el mismo mtodo para agregar sus componentes Interesante, no3 Veamos la estructuraObject --- Component --- Container --+-- Panel | +-- Window --- Frame --- Ejemplo7 Noten que hemos usado dos mtodos add con diferente signature: panelAlto.add("West", new Label("Cartel", Label.CENTER)); .......... panelBajo.add(new Button("Botn"));

!l mtodo add+Component, agrega un componente al /inal= el mtodo add+#tring,Component, lo agrega en un lugar especi/icado por una palabra que depende del &ayout?anager, el objeto que se encarga de ordenar los componentes dentro del contenedor &ayout?anager es una inter/ace, y como tal debe implementarse a travs de objetos no abstractos de los que $ay varios prede/inidos en la librer'a java a"t- 7order&ayout, Card&ayout, >lo"&ayout, crid7ag&ayout y crid&ayout !l &ayout por de/ecto es 7order&ayout, que de/ine en el contenedor las %reas 2)ort$2, 2#out$2, 2*est2, 2!ast2 y 2 Center2 y es que usamos aqu' Card&ayout permite 2apilar2 los componentes como cartas y ver uno por vez, >lo"&ayout los ordena de izquierda a derec$a como un te<to, crid&ayout los ordena en una cuadr'cula donde cada componente tiene un tamaGo /ijo y crid7ag&ayout los pone en una cuadr'cula pero cada uno puede tener el tamaGo deseado

)oten que no $ace /alta llamar, en el caso del applet, a Pac^+, y #$o"+, W los eventos A$ora vamos a ver un mtodo que viene de la clase tatarabuela; Face /alta decir que me gusta esto de los objetos3 Vamos a rede/inir $andle!vent+!vent,, que es el mtodo que analiza los eventos dirigidos al componente y toma las acciones adecuadas &a clase !vent de/ine b%sicamente una serie de mtodos que permiten saber si $ay alguna tecla de control presionada y muc$as constantes que indican si se presion o movi el mouse, si se presion alguna tecla en particular, si se cambi el tamaGo de la ventana, etc !n particular $ay algunos atributos interesantes. id que indica el tipo de evento . target que indica sobre qu componente se produjo el evento . ^ey qu tecla se presion si /ue un evento de teclado etc !n los descendientes de Component, el mtodo $andle!vent se llama autom%ticamente cada vez que se produce un evento sobre el componente !n este caso, simplemente vamos a mirar si el evento +sobre nuestro objeto de clase !jemplo_, /ue 2cerrar la ventana2, que se identi/ica mediante event id O *I)51*X5!#6H1W +una constante est%tica de la clase !vent, y como tal la podemos usar con el nombre de la clase como !vent *I)51*X5!#6H1W,public boolean handleEvent(Event ev) { if (ev.id == Event.WINDOW_DESTROY) { if (inAnApplet) { dispose(); } else { System.exit(0); } } return super.handleEvent(event); }

!n ese caso, si nuestro ejemplo se dispar como aplicacin llamamos al mtodo #ystem e<it+K,, que cierra la aplicacin= y si era un applet llamamos a dispose+,, implementacin de un mtodo de la inter/ace ComponentPeer que se encarga de remover todos los componentes y la propia ventana )oten que cualquier otro tipo de evento deja seguir $asta return super $andle!vent+event,, que llama al mtodo $andle!vent de la clase madre- as' como el pre/ijo t$is se re/iere a un mtodo de la propia clase, el pre/ijo super llama al mtodo de la clase madre +aunque est rede/inido, !n este caso, la llamada se remonta $asta Component $andle!vent, que determina el tipo de evento y llama a uno de los mtodos action, got>ocus, lost>ocus, ^ey5o"n, ^ey8p, mouse!nter, mouse!<it, mouse?ove, mouse5rag, mouse5o"n o mouse8p seg9n sea apropiado +y devuelve true, #i ning9n mtodo es aplicable, devuelve /alse !s muy com9n, al rede/inir un mtodo, tener en cuenta llamar antes o despus al mtodo de la clase antecesora para inicializar o terminar alguna tarea 8na ventana con vida Antes que nada, vamos a crear una p%gina F6?& para cargar nuestra clase !jemploL, que ser% un applet +aunque tambin la podremos ejecutar en /orma standalone con 2java !jemploL2,, por ejemplo<!-- Archivo Ejemplo8.htm - HTML de ejemplo --> <HTML> <HEAD> <TITLE>Ejemplo 8 - Ventana de datos</TITLE> </HEAD> <BODY> Aqu&iacute; se tiene que abrir una ventana de entrada de datos <applet code="Ejemplo8.class" width=170 height=150> </applet> </BODY> </HTML>

)uestro applet ser% muy sencillo, ya que utilizar% clases que iremos de/iniendo en este cap'tulo= por empezar slo crear% una ventana que de/iniremos en la clase VentanaL// Archivo: Ejemplo8.java // Compilar con "javac Ejemplo8.java"

import java.awt.*; import java.applet.*; public class Ejemplo8 extends Applet { public static void main (String arg[]) { // para poder llamarla con "java Ejemplo8" new Ventana8("Ejemplo Standalone", true); } public void init() { // se ejecuta al abrirse un applet new Ventana8("Ejemplo Applet", false); } }

Con los par%metros que le pasamos a la clase VentanaL le indicamos el t'tulo de la ventana y si se carga como applet o no +ya que el mtodo de cierre var'a, Viajando con Java A$ora vamos a trabajar con nuestra clase VentanaL, una ventana que nos permita seleccionar una /ec$a y dos ciudades +desde y $asta, que simula una ventana de compra de pasajes de, por ejemplo, una terminal de mnibus !l ejemplo est% basado en uno del libro 2Programacin Java2 de ?acary y )icolas, aunque algo mejorado y ampliado !n nuestra ventana podremos entrar una /ec$a a mano o directamente mediante los botones Foy y ?aGana, elegiremos la ciudad de salida y la de llegada de dos listas, y presionaremos luego un botn que nos mostrar% los servicios disponibles, nos permitir% comprar los pasajes, etc A medida que entramos los datos, en el botn se ir% mostrando el detalle de lo que se /ue seleccionando )uestra ventana quedar% m%s o menos as'!mpecemos por armar la estructura de la clase VentanaLimport java.awt.*; class Ventana8 extends Frame { // hija de Frame // aqu agregaremos luego // algunas variables para guardar datos

// (ciudades de salida y llegada, fecha) button ok; // tambin el botn de compra de pasajes boolean enApplet; // y otra para indicar si es un applet o no Ventana8 (String titulo, boolean enApplet) { // un constructor super(titulo); // llama al de Frame this.enApplet = enApplet; // guardamos esto // aqu crearemos los botones, listas, etc // con sus valores iniciales // y los pondremos en la ventana. // por ejemplo: ok = new Button("Viaje: de ? a ? el ?/?/?"); add("South",ok); pack(); // dimensionamos la ventana show(); // y la mostramos! } public boolean handleEvent(Event e) { // para manejar los eventos if (e.id == Event.WINDOW_DESTROY) { // cerrar la ventana if (enApplet) dispose(); else System.exit(0); } // aqu miraremos si se presion un botn // o se eligi algo de una lista // y actuaremos en consecuencia return super.handleEvent(e); // los dems eventos los maneja Frame } void ActualizaBoton() { // aqu pondremos un mtodo que servir // para actualizar el botn de compra de pasajes,

// ya que el texto del mismo se actualiza cada // vez que se selecciona una ciudad o se cambia la fecha } void Activar() { // y aqu un mtodo para cuando se presione // dicho botn, que se supone que va a consultar // una base de datos y abrir una ventana // para vendernos el pasaje }}

)uestro programa ya /unciona; Aunque un poquito incompleto, claro Igual vamos a analizarlo un poco el constructor, que es lo m%s interesante aqu' Primero llamamos al constructor de la clase madre, que se encarga de crear la ventanaVentana8 (String titulo, boolean enApplet) { // un constructor super(titulo); // llama al de Frame

!sto ser'a como llamar a super >rame+titulo,, o bien >rame+titulo,, ya que el mtodo constructor tiene el mismo nombre de la clase &uego, conthis.enApplet = enApplet; // guardamos esto

asignamos a nuestra variable enApplet de la clase el valor del par%metro que se pas al constructor, que se llama igual !l pre/ijo t$is, que se re/iere a la instancia particular de la clase, permite di/erenciar uno de otro +esto es v%lido tanto para variables como para mtodos,
ok = new Button("Viaje: de ? a ? el ?/?/?"); add("South",ok);

Aqu' $emos creado un botn ubicado al pie de la ventana +por a$ora lo 9nico que pusimos,, y luego dimensionamos la ventana y la mostramospack(); // dimensionamos la ventana show(); // y la mostramos!

Preparando listas A$ora vamos a empezar a crear otros objetos para ir completando nuestra aplicacin Comencemos con las listas de ciudades

Para eso, vamos a crear un objeto descendiente de Panel que simplemente contenga una lista de ciudades prede/inidas y un t'tulo que diga 2#eleccione ciudad de2, y a continuacin 2salida2 o 2llegada2 6ambin agregaremos un mtodo
import java.awt.*; class SelecPueblo extends Panel { private List listaPueblos; SelecPueblo (String salidaOllegada) { setLayout (new BorderLayout (20,20)); // armamos el ttulo, que va a ser un Label: StringBuffer titulo = new StringBuffer(); titulo.append("Seleccione ciudad de "); titulo.append(salidaOllegada); titulo.append(": "); add("North", new Label(titulo.toString())); // armamos la lista de ciudades, que va a ser un List: listaPueblos = new List (4, false); listaPueblos.addItem("Buenos Aires"); listaPueblos.addItem("La Plata"); listaPueblos.addItem("Azul"); listaPueblos.addItem("Rosario"); listaPueblos.addItem("Cordoba"); listaPueblos.addItem("Baha Blanca"); add("South", listaPueblos); } public String getDescription() { return listaPueblos.getSelectedItem(); } }

)o $ay muc$o para analizar aqu', creo &a variable listaPueblos es privada, pero puede consultarse cu%l es la ciudad seleccionada mediante get5escription +que es public, !ste mtodo llama al mtodo get#electedItem de la lista, que devuelve el te<to seleccionado !n el constructor, armamos el te<to del t'tulo como un #tring7u//er &os objetos #tring7u//er son similares a los de clase #tring pero pueden ser modi/icados !n cambio los objetos #tring, una vez creados, no pueden ser modi/icados directamente- sus mtodos +concat, to&o"erCase, etc , simplemente crean un nuevo #tring con el nuevo valor !sto lo $icimos para introducir esta nueva clase= por supuesto $ubiera sido m%s /%cil poner, como pueden comprobar, con el mismo resultadoString tit = "Seleccione ciudad de "+salidaOllegada+": "; add("North", new Label(tit));

Por otra parte, creamos el objeto listaPueblos como ne" &ist+A, /alse,, que indica que la lista va a tener A renglones y slo se puede seleccionar un 'tem por vez Agregamos luego @ 'tems mediante addItem y la agregamos al panel A$ora ya podemos agregar las listas a nuestra ventana y poner un par de variables para guardarlasclass Ventana8 extends Frame { // hija de Frame SelecPueblo cs; // ciudad de salida SelecPueblo cl; // ciudad de llegada button ok; // tambin el botn de compra de pasajes boolean enApplet; // y otra para indicar si es un applet o no Ventana8 (String titulo, boolean enApplet) { // un constructor super(titulo); // llama al de Frame this.enApplet = enApplet; // guardamos esto cs = new SelecPueblo("SALIDA"); // CIUDAD DE SALIDA add ("Center", cs); cl = new SelecPueblo("LLEGADA"); // CIUDAD DE LLEGADA add ("East", cl); ok = new Button("Viaje: de ? a ? el ?/?/?"); add("South",ok); pack(); // dimensionamos la ventana

show(); // y la mostramos! } ...........................

Wa pueden ir probando cmo queda, aunque por a$ora muc$a /uncionalidad no tenemos Agregando /ec$as 1tro panel m%s nos servir% para seleccionar o entrar la /ec$aimport java.util.*; import java.awt.*; class DiaPartida extends Panel { private TextField elDia; private Button hoy; private Button diasiguiente; DiaPartida() { setLayout (new GridLayout (4,1)); elDia = new TextField(); elDia.setText(GetHoy()); hoy = new Button ("Hoy"); diasiguiente = new Button ("Maana"); add (new Label ("Da salida: ")); add (elDia); add (hoy); add (diasiguiente); } private String GetHoy() { Date d = new Date(); int dia = d.getDate(); int mes = d.getMonth(); int ano = d.getYear();

return dia+"/"+mes+"/"+ano; } private String GetManana() { Date d = new Date(); int dia = d.getDate(); int mes = d.getMonth(); int ano = d.getYear(); dia = dia++; switch (mes) { case (1): case (3): case (5): case (7): case (8): case (10): if (dia>31) { dia = 1; mes++; } break; case (12): if (dia>31) { dia = 1; mes = 1; ano++; } break; case (4): case (6): case (9):

case (11): if (dia>30) { dia = 1; mes++; } break; default: if (dia>28) { // ojo, hay que corregir para bisiestos! dia = 1; mes++; } } return dia+"/"+mes+"/"+ano; } public String getDescription() { return elDia.getText(); } public boolean handleEvent (Event e) { if (e.target == hoy) elDia.setText(GetHoy()); if (e.target == diasiguiente) elDia.setText(GetManana()); return super.handleEvent(e); } } Este es un poco ms largo pero no ms complejo. Vamos por parte: DiaPartida() { setLayout (new GridLayout (4,1)); elDia = new TextField(); elDia.setText(GetHoy());

hoy = new Button ("Hoy"); diasiguiente = new Button ("Maana"); add (new Label ("Da salida: ")); add (elDia); add (hoy); add (diasiguiente); }

!l constructor crea un panel con cuatro campos en /orma de grilla vertical, donde mostrar% el te<to 25'a salida- 2, el campo de entrada de te<to el5ia y los botones $oy y diasiguiente !l mtodo privado getFoy usa los mtodos get5ate, get?ont$ y getWear de la clase date para armar un #tring con la /ec$a actual !l mtodo privado get?anana $ace lo mismo para leer la /ec$a actual, y le suma J al d'a para tener el d'a siguiente !l s"itc$ siguiente veri/ica que si pas de /in de mes tome el primer d'a y el mes siguiente +o el primer d'a del aGo siguiente si es en diciembre, )otar que no se consideraron los aGos bisiestos en /ebrero para no complicar el mtodo, pero no es di/'cil de corregir 1tra manera ser'a armar un array con los d'as de cada mes, corregir los d'as de /ebrero para los aGos bisiestos, y comparar contra este array en lugar de usar un s"itc$ &a idea siempre es la misma- devolver un #tring con la /ec$a del d'a siguiente )otar algo interesante- como estas clases se cargan y ejecutan en la m%quina cliente, la /ec$a que aparece es la del cliente y no la del servidor +que puede ser di/erente depende la $ora y el lugar del mundo en que estn ambas m%quinas, !l mtodo get5escription es p9blico y se usa para acceder a la /ec$a que se $a ingresado desde las dem%s clases= simplemente devuelve el contenido del campo el5ia, de clase 6e<t>ield Aqu' $emos desarrollado tambin el mtodo $andle!ventpublic boolean handleEvent (Event e) { if (e.target == hoy) elDia.setText(GetHoy()); if (e.target == diasiguiente) elDia.setText(GetManana()); return super.handleEvent(e); }

!n caso de alguna accin sobre uno de los botones, el mtodo set6e<t +de la clase 6e<t>ield, pone en el campo de te<to el5ia el valor del d'a actual o el siguiente )otar que slo $emos considerado que $aya alg9n evento y no un tipo de evento en particular= en realidad el mtodo va a actuar por ejemplo tanto al presionar el mouse sobre el botn como al soltarlo Pero esto no nos molesta super $andle!vent se encarga de otros eventos dirigidos al panel, como la entrada de datos por teclado al campo de te<to por ejemplo Juntando todo $asta aqu' 7ueno, a$ora vamos a reunir las piezas que tenemos $asta a$ora agregando estos mtodos a nuestra clase VentanaL para ver cmo queda la ventana completaclass Ventana8 extends Frame { // hija de Frame SelecPueblo cs; // ciudad de salida SelecPueblo cl; // ciudad de llegada DiaPartida dp; // da de salida button ok; // botn de compra de pasajes boolean enApplet; // para indicar si es un applet o no Ventana8 (String titulo, boolean enApplet) { // un constructor super(titulo); // llama al de Frame this.enApplet = enApplet; // guardamos esto dp = new DiaPartida(); // DIA DE SALIDA add ("West", dp); cs = new SelecPueblo("SALIDA"); // CIUDAD DE SALIDA add ("Center", cs); cl = new SelecPueblo("LLEGADA"); // CIUDAD DE LLEGADA add ("East", cl); ok = new Button("Viaje: de ? a ? el ?/?/?"); add("South",ok); pack(); // dimensionamos la ventana show(); // y la mostramos!

Completando la ventana Vamos a empezar por completar nuestro mtodo Actualiza7oton, que modi/icar% el te<to del botn o^ a medida que seleccionemos las ciudades y la /ec$avoid ActualizaBoton() { StringBuffer b = new StringBuffer("Viaje: de "); if (cs.getDescription() != null) b.append(cs.getDescription()); else b.append("?"); b.append(" a "); if (cl.getDescription() != null) b.append(cl.getDescription()); else b.append("?"); b.append(" el "); if (dp.getDescription() != null) b.append(dp.getDescription()); else b.append("?/?/?"); ok.setLabel(b.toString()); }

)uestro mtodo comienza por crear un #tring7u//er con las palabras 2Viaje- de 2, y va agregando el resto. la ciudad de partida, llamando al mtodo get5escription de cs +ciudad de salida, . el te<to constante 2 a 2 . la ciudad de llegada, llamando al mtodo get5escription de cl +ciudad de llegada, . el te<to constante 2 el 2 . la /ec$a seleccionada, llamando al mtodo get5escription de dp +d'a de partida, #i en cualquier caso recibe un string nulo, pone un signo de pregunta +o 3D3D3 para la /ec$a, !l mtodo set&abel, sobre el objeto o^ de tipo &abel, modi/ica la 2etiqueta2 del botn Healmente nos devuelven null los mtodos que llamamos si no $ay seleccin $ec$a3 Veamosclass SelecPueblo extends Panel {

private List listaPueblos; ............................ public String getDescription() { return listaPueblos.getSelectedItem(); }}

!l mtodo get#electedItem de la clase &ist devuelve null si no $ay 'tems seleccionados, as' que ac% andamos bien !n cuanto a la clase 5iaPartida, de entrada inicializa el valor del te<to en la /ec$a actual, as' que aqu' no se dar'a nunca este caso Aunque al crear el objeto VentanaL estamos poniendo un te<to /ijo en el botn, y no el que devuelve el objeto dp #er'a mejor, para ser m%s consistente, modi/icar el constructor de VentanaL para que arme el te<to mediante el mtodo Actualiza7otnVentana8 (String titulo, boolean enApplet) { ........................................ ok = new Button("cualquiera"); ActualizaBoton(); add("South",ok); pack(); show(); }

!sto ya se ve mejor; W de paso probamos el mtodo 8n poquito de actividad A$ora s', pasemos a completar nuestro manejador de eventospublic boolean handleEvent(Event e) { if (e.id == Event.WINDOW_DESTROY) { if (enApplet) dispose(); else System.exit(0); } if ( (e.target==dp)||(e.target==cs)||(e.target==cl) ) ActualizaBoton();

if (e.target==ok) Activar(); } return super.handleEvent(e); }

#implemente, si detectamos un evento sobre alguno de nuestros paneles actualizamos el te<to del botn= y si se presiona dic$o botn llamamos al mtodo Activar que se supone que va a tomar los datos de la base de datos, indicarnos servicios disponibles, etc Algo importante a notar es que el simple $ec$o de mover el mouse sobre uno de los paneles ya llama a Actualiza7oton +se nota porque titila el te<to, sobre todo en una m%quina lenta, Adem%s, si $acen clic^ sobre el botn Foy o ?aGana sin mover el mouse, el te<to del botn o^ no se actualiza ya que el evento va dirigido al botn presionado y no al panel 8na /orma de /iltrar slo los eventos que nos interesan ser'a usar, por ejemploif ((e.target=cs.listaPueblos) && (e.id==Event.LIST_SELECT)) ActualizaBoton();

que est% dirigida a la lista y no al panel en general, y tiene en cuenta el tipo de evento &amentablemente, listaPueblos es privada dentro de la clase #elecPueblo y por lo tanto dentro de cs Pero es mejor as', porque declararla p9blica y leerla desde a/uera ser'a bastante sucio +as' como la leemos podr'amos escribirla, Fay varias /ormas de mejorar esto sin cometer la torpeza de declarar p9blica a listaPueblos 8na posibilidad es veri/icar, usando cs get5escription+,, si el te<to cambi +y slo en ese caso modi/icar el te<to del botn, 1tra, es $acer que los objetos de la clase #elecPueblo pasen a sus padres cualquier evento sobre ellos, o mejor solamente la seleccin de un elemento de la lista= para eso basta agregar a la clase #elecPueblopublic boolean handleEvent(Event e) { if ((e.target==listaPueblos) && (e.id==Event.LIST_SELECT)) { e.target=this; } return super.handleEvent(e); }

!n resumen- si el evento en el panel es una seleccin de la lista +tanto con mouse como moviendo la seleccin con las /lec$as,, cambio el target del evento para que indique el panel +y no la lista,= si no, lo paso a la clase antecesora &o mismo podemos $acer con $andle!vent para la clase 5iaPartidapublic boolean handleEvent (Event e) { if (e.target == hoy) { elDia.setText(GetHoy()); e.target=this; } if (e.target == diasiguiente) { elDia.setText(GetManana()); e.target=this; } if (e.target == elDia) { e.target=this; } return super.handleEvent(e); }

!sto no anda como esperar'amos; !l campo de te<to no se comporta muy bien !sto es porque el cdigo dependiente de la plata/orma procesa los eventos de mouse antes de llamar a $andle!vent , pero procesa los de teclado despus de llamar a $andle!vent &o que signi/ica que, en el caso del campo de te<to, $andle!vent +y por lo tanto Actualiza7otn, se llama antes de modi/icar el te<to; Para corregir esto, deber'amos procesar nosotros las teclas presionadas +lo que podr'amos aprovec$ar para veri/icar que se presiona una tecla v%lida, Cuidado; !n /uturas versiones de Java podr'a implementarse el mismo comportamiento para el mouse, y por lo tanto tendr'amos que repensar la estrategia Para colmo, slo los eventos que la plata/orma env'a llegan a Java= por ejemplo, ?oti/ no env'a eventos de movimiento de mouse dentro de un campo de te<to lo que signi/ica que nunca podr'amos capturar ese tipo de eventos #lo el componente Canvas pasa todos los eventos

Para simpli/icar, slo actualizaremos el te<to del botn cuando se presiona !nter +!vent ^eyOJK,if ((e.target == elDia)&&(e.id==Event.KEY_PRESS)) { if (e.key==10) e.target=this; }

A$ora debemos modi/icar el mtodo $andle!vent en nuestra clase VentanaL para que soporte todos estos eventospublic boolean handleEvent(Event e) { if (e.id == Event.WINDOW_DESTROY) { if (enApplet) dispose(); else System.exit(0); } if ( ((e.target==dp)&&((e.id==Event.ACTION_EVENT)||(e.id==Event.KEY_PRESS))) ||((e.target==cs)&&(e.id==Event.LIST_SELECT)) ||((e.target==cl)&&(e.id==Event.LIST_SELECT)) ) ActualizaBoton(); if (e.target==ok) Activar(); return super.handleEvent(e); }

1bviamente, procesar todas las teclas nosotros ser'a bastante m%s complicado de todos modos, el mtodo en 5iaPartida ser'a m%s o menos as'if ((e.target == elDia)&&(e.id==Event.KEY_PRESS)) { // 1- leer el contenido del campo con: elDia.getText() // 2- modificarlo de acuerdo a la tecla presionada: e.key // 3- poner el resultado en el campo con: elDia.setText(texto) // 4- modificar el objeto del evento al panel con: e.target=this; // 5- enviar el evento al objeto padre (no la clase padre), // en este caso Ventana8, mediante: getParent().deliverEvent(e)

// 6- evitar proceso posterior del evento mediante: result(true) }

?e a$orro e<plicar estos dos 9ltimos pasos= se complica bastante todo porque $ay que manejar la posicin del cursor dentro del campo de te<to, etctera Con lo que $icimos es bastante creo; W para terminar 7ueno, slo nos queda por de/inir el mtodo Activar+, Primero vamos a llamar a Actualiza7oton+, por si alguien lo 9ltimo que $izo /ue entrar un te<to sin presionar !nter, y dejo para otro d'a m%s tranquilo consultar un arc$ivo o base de datos con lo que vamos a mostrar al usuario de nuestro programa Por a$ora simplemente vamos a mostrar una ventana con la seleccin y un lindo botn de 1I Primero vamos a $acer una muy pequeGa modi/icacin a Actualiza7oton+, para que nos devuelva el valor del te<to del botn +para no calcularlo de nuevo,String ActualizaBoton() { StringBuffer b = new StringBuffer("Viaje: de "); .............................................. ok.setLabel(b.toString()); }

W a$ora vamos a de/inir nuestro mtodo, teniendo en cuenta que nuestro botn slo actuar% si se $an entrado todos los datosvoid Activar() { if ( (cs.getDescription() != null) && (cl.getDescription() != null) ) // tambin podramos verificar que la fecha sea vlida aqu Result8 resultado = new Result8("Resultado",ActualizaBoton()); else ok.setLabel("Especificacin incompleta!"); }

#lo nos /alta de/inir una sencilla clase HesultL para nuestra ventanita resultado// archivo Result8.java, compilar con javac Result8.java import java.awt.*; class Result8 extends Frame {

Button r_ok; Result8 (String titulo, String texto) { // constructor super(titulo); Label r_lbl = new Label(texto); r_ok = new Button("Ok"); add("Center", r_lbl); add("South", r_ok); pack(); show(); } public boolean handleEvent(Event e) { if ((e.id == Event.WINDOW_DESTROY)||(e.target==r_ok)) dispose(); // cierra esta ventana pero no la aplicacin return super.handleEvent(e); } }

)oten que us dispose y no #ystem e<it; !sto permite cerrar slo la ventana de resultado, y seguir usando la aplicacin $asta que se nos ocurra cerrarla mediante meta0>A, alt0>A, el men9 de sistema de la ventana, la cruz de *indo"s BC o lo que le resulte a su sistema operativo >inale con tutto !spero que se $aya entendido; !sta aplicacin cost bastante pero en el camino $emos tenido oportunidad de aprender unas cuantas cosas #i logran juntar todo el cdigo y generar las varias clases que de/inimos, todo tiene que andar sobre rieles e independientemente de la plata/orma Por las dudas, pueden probar esta aplicacin como applet cargando$ttp-DD""" amarillas comDroc^DjavaD!jemploL $tm 8n parntesis de !ntradaD#alida !n Java $ay muc$as clases para leer y escribir arc$ivos +u otros dispositivos de !D#, !st%n reunidos en la biblioteca java io

Vamos a empezar como siempre con un pequeGo ejemplo /uncional y en seguida nos meteremos en el necesario camino de las e<cepciones Primera &ectura
// archivo: Ejemplo9.java - compilar con "javac Ejemplo9.java", etc. etc. import java.io.*; public class Ejemplo9 { public static void main(String args[]) throws FileNotFoundException,IOException { FileInputStream fptr; DataInputStream f; String linea = null; fptr = new FileInputStream("Ejemplo9.java"); f = new DataInputStream(fptr); do { linea = f.readLine(); if (linea!=null) System.out.println(linea); } while (linea != null); fptr.close(); }}

+Caramba; [(u $ace ese t$ro"s a$'3, !l programa de ejemplo simplemente lee un arc$ivo de te<to y lo muestra en pantalla, algo as' como el type del 51# o el cat de 8ni< 5ejemos por a$ora el t$ro"s >ile)ot>ound!<ception,I1!<ception y vamos al cdigo
fptr = new FileInputStream("Ejemplo9.java");

&a clase >ileInput#tream +descendiente de Input#tream, nos sirve para re/erirnos a arc$ivos o cone<iones +soc^ets, de una m%quina Podemos accederlos pasando un #tring como aqu', un objeto de tipo >ile o uno de tipo >ile5escriptor, pero en esencia es lo mismo Al crear un objeto de este tipo estamos 2abriendo2 un arc$ivo, cl%sicamente $ablando #i el arc$ivo no e<iste +por ejemplo reemplacen 2!jemploB java2 por alguna otra cosa, como 2noe<iste t<t2,, al ejecutarlo nos aparece un error-

C-NjavaNcursoQjava !jemploB java io >ile)ot>ound!<ception- noe<iste t<t at java io >ileInput#tream PinitQ+>ileInput#tream java-CJ, at !jemploB main+!jemploB java-B, +Caramba; [5nde vi ese >ile)ot>oud!<ception antes3, Justamente, cuando el arc$ivo al que quiero acceder no e<iste, Java 2lanza2 una e<cepcin !sto es, un aviso de que algo /all y, si no se toma ninguna accin, detiene el programa &a clase >ileInput#tream puede 2lanzar2 +t$ro"s, la e<cepcin >ile)ot>ound!<ception [Cmo capturar y tratar las e<cepciones3 !n seguida= primero terminemos con nuestro programa
f = new DataInputStream(fptr);

&a clase 5ataInput#tream nos permite leer, en /orma independiente del $ard"are, tipos de datos de una 2corriente2 +stream, que, en este caso, es un arc$ivo !s descendiente de >ilterInput#tream e implementa 5ataInput, una inter/ace Al crear un objeto de tipo 5ataInput#tream lo re/erimos al arc$ivo, que le pasamos como par%metro +/ptr,= esta clase tiene toda una serie de mtodos para leer datos en distintos /ormatos !n nuestro programa usamos uno para leer l'neas, que devuelve null cuando se llega al /inal del arc$ivo o un #tring con el contenido de la l'neado { linea = f.readLine(); System.out.println(linea); } while (linea != null);

!n seguida de leer la l'nea la imprimimos, y repetimos esto mientras no nos devuelva null Al /inal, cerramos el arc$ivofptr.close();

6anto read&ine como close pueden lanzar la e<cepcin I1!<ception, en caso de error de lectura o cierre de arc$ivo !n realidad, podr'amos no $aber usado un 5ataInput#tream y trabajar en /orma m%s directaimport java.io.*; public class Ejemplo10 {

public static void main(String args[]) throws FileNotFoundException,IOException { FileInputStream fptr; int n; fptr = new FileInputStream("Ejemplo9.java"); do { n = fptr.read(); if (n!=-1) System.out.print((char)n); } while (n!=-1); fptr.close(); } }

Wa que la clase >ileInput#tream tambin dispone de mtodos para leer el arc$ivo #lo que son unos pocos mtodos que nos permiten leer un entero por vez o un arreglo de bytes 5ataInput#tream tiene mtodos para leer los datos de muc$as /ormas distintas, y en general resulta m%s cmodo Capturando e<cepciones A$ora s', vamos a ver cmo nos las arreglamos con las e<cepciones para que no se nos pare el programa con un mensaje tan poco esttico !n lugar de lanzar las e<cepciones al intrprete, vamos a procesarlas nosotros mediante la cl%usula catc$// Archivo: Ejemplo11.java // Compilar con: javac Ejemplo11.java // Ejecutar con: java Ejemplo11 <nombre_archivo> import java.io.*; public class Ejemplo11 { public static void main(String args[]) { FileInputStream fptr; DataInputStream f; String linea = null;

try { fptr = new FileInputStream(args[0]); f = new DataInputStream(fptr); do { linea = f.readLine(); if (linea!=null) System.out.println(linea); } while (linea != null); fptr.close(); } catch (FileNotFoundException e) { System.out.println("Hey, ese archivo no existe!\n"); } catch (IOException e) { System.out.println("Error de E/S!\n"); } }}

6ambin $icimos un cambio para elegir el arc$ivo a imprimir desde la l'nea de comandos, en lugar de entrarlo /ijo, utilizando para eso el argumento del mtodo main+argUV,, que consiste en una lista de #trings con los par%metros que se pasan en la l'nea a continuacin de java nombreXprograma Por ejemplo, si llamamos a este programa conjava Ejemplo11 archi.txt otro.xxx arg[0] contendr "archi.txt", arg[1] contendr "otro.xxx", y as sucesivamente.

Por supuesto, si llamamos a !jemploJJ sin par%metros se lanzar% otra e<cepcin al intentar accederloC-NjavaNcursoQjava !jemploJJ java lang ArrayInde<1ut1/7ounds!<ception- K at !jemploJJ main+!jemploJJ java-JK, Pero tambin podr'amos capturarla;

Veamos un poquito cmo es esto de capturar e<cepciones &a cl%usula try engloba una parte del programa donde se pueden lanzar e<cepciones #i una e<cepcin se produce, Java busca una instruccin catc$ +nombreXdeXlaXe<cepcin variable,, y, si la encuentra, ejecuta lo que sta engloba #i no encuentra un catc$ para esa e<cepcin, para el programa y muestra el error que se produjo Por ejemplo, para evitar este 9ltimo error bastar'a con agregarcatch (ArrayIndexOutOfBoundsException e) { System.out.println("Debe ingresar un nombre de archivo!"); System.out.println("Ej.: java Ejemplo11 pepe.txt"); }

Fay que notar que cuando se lanza una e<cepcin el programa igual se detiene, porque el cdigo que sigue al lanzamiento de la e<cepcin no se ejecuta Veremos luego cmo se comporta esto en un objeto que /ue creado por otro, y cmo usar la instruccin /inally para poner una parte de cdigo que se ejecute pase lo que pase &os applets y los arc$ivos
Veamos cmo se comporta esta aplicacin si la modificamos para usarla como applet. /* // ----- Archivo: Ejemplo12.java */ import java.io.*; import java.awt.*; import java.applet.*; public class Ejemplo12 extends Applet { public void init() { new Ventana12(); } } /* // -------- Esta clase es la que en realidad hace el trabajo

*/ class Ventana12 extends Frame { TextArea contenido; Button cerrar; Ventana12() { super("Ejemplo de E/S"); contenido = new TextArea(); cerrar = new Button("Cerrar"); CargarArchivo(); add("North",contenido); add("South",cerrar); pack(); show(); } public boolean handleEvent(Event e) { if ((e.id==Event.WINDOW_DESTROY)||(e.target==cerrar)) dispose(); return super.handleEvent(e); } void CargarArchivo() { FileInputStream fptr; DataInputStream f; String linea = null; try { fptr = new FileInputStream("Ejemplo12.java"); f = new DataInputStream(fptr); do { linea = f.readLine();

if (linea!=null) contenido.appendText(linea+"\n"); } while (linea != null); fptr.close(); } catch (FileNotFoundException e) { contenido.appendText("Hey, ese archivo no existe!\n"); } catch (IOException e) { contenido.appendText("Error de E/S!\n"); } }}

&o cargamos desde la p%gina !jemploJE $tml<HTML> <HEAD> <TITLE>Ejemplo 12 - Ejemplo con archivo</TITLE> </HEAD> <BODY> <applet code="Ejemplo12.class" width=170 height=150> </applet> </BODY> </HTML>

?ientras corramos esto en la misma m%quina, no $ay problema +anda muy bien;, Pero qu pasa si intentamos cargarlo desde la red3 Para los que no tengan server $tml puse una copia en$ttp-DD""" amarillas comDroc^DjavaD!jemploJE $tm !l arc$ivo no aparece; !n su lugar se produce una e<cepcin= en la l'nea de estado del ?icroso/t Internet !<plorer, por ejemplo, se leee<ception- com ms applet Applet#ecurity!<ception- security /ile read- !jemploJE java

!sto es debido a una restriccin de seguridad de Java- )1 #! P8!5!) CAHcAH AHCFIV1# (8! !#6!) !) 8)A ?A(8I)A 5I#6I)6A A A(8!&&A 5!#5! &A C8A& #! CAHc1 !& APP&!6 !l applet se corre en el cliente, e intenta acceder a un arc$ivo local !so es lo que provoca la e<cepcin +que, por supuesto, puede detectarse con un catc$ y tratarse , Por cuestiones de seguridad, los applets son m%s limitados que las aplicaciones Java locales &as pol'ticas de seguridad las manejan los bro"sers +no Java,, y generalmente los l'mites que se imponen a los applets son. 8n applet no puede cargar bibliotecas +libraries, ni de/inir mtodos nativos . )o puede leer o escribir normalmente arc$ivos en el cliente que lo carga desde otro server . )o puede establecer cone<iones de red, salvo al servidor del que proviene . )o puede arrancar programas en la m%quina donde se est% ejecutando . )o puede leer ciertas propiedades del sistema . !n las ventanas de los applets se indica que se trata de un applet #in embargo, pueden. Heproducir sonidos . Pueden establecer cone<iones con el servidor del que provienen . Pueden llamar /%cilmente p%ginas F6?& desde el bro"ser . Pueden invocar mtodos p9blicos de otros applets de la misma p%gina . #i se cargan desde la propia m%quina +localmente, no tienen ninguna de las restricciones anteriores . Pueden seguir corriendo aunque se cambie de p%gina en el bro"ser !n realidad, la especi/icacin de Java permite que los applets lean arc$ivos en otras m%quinas dando la 8H& completa= sin embargo, los bro"sers no lo permiten Veremos m%s adelante cmo intercambiar datos entre m%quinas para poder ver un arc$ivo del server, por ejemplo )uestro modesto 2!ditor2 Para terminar este cap'tulo, el siguiente applet nos permite cargar, editar y grabar arc$ivos ascii a eleccin Podemos usar inclusive las acciones 2cut a paste2 del "indo"s manager +Ctrl0C y Ctrl0V en *indo"s,; Cargarlo con 2appletvie"er !jemploJT2 luego de $aberlo compilado +o usar una p%gina $tml desde un bro"ser,-

/* // ----- Archivo: Ejemplo13.java */ import java.io.*; import java.awt.*; import java.applet.*; public class Ejemplo13 extends Applet { public void init() { new Ventana13(); } } /* // -------- Esta clase es la que en realidad hace el trabajo */ class Ventana13 extends Frame { TextArea contenido; Botones13pieVentana; Ventana13() { super("Ejemplo de E/S"); contenido = new TextArea(); pieVentana = new Botones13(); add("North",contenido); add("South",pieVentana); pack(); show(); } public boolean handleEvent(Event e) { if ((e.id==Event.WINDOW_DESTROY)||(e.id==2003))

dispose(); if (e.id==2001) CargarArchivo(pieVentana.toString()); if (e.id==2002) GrabarArchivo(pieVentana.toString()); return super.handleEvent(e); } void CargarArchivo(String nombre) { FileInputStream fptr; DataInputStream f; String linea = null; contenido.setText(""); try { fptr = new FileInputStream(nombre); f = new DataInputStream(fptr); do { linea = f.readLine(); if (linea!=null) contenido.appendText(linea+"\n"); } while (linea != null); fptr.close(); } catch (FileNotFoundException e) { new Error13("El archivo no existe!"); } catch (IOException e) { new Error13("Error leyendo archivo!"); } } void GrabarArchivo(String nombre) { FileOutputStream fptr;

DataOutputStream f; try { fptr = new FileOutputStream(nombre); f = new DataOutputStream(fptr); f.writeBytes(contenido.getText()); fptr.close(); } catch (IOException e) { new Error13("Error grabando archivo!"); } } } /* // -------- Esta es para los botones y el nombre del archivo */ class Botones13 extends Panel { TextField fname; Button cargar; Button grabar; Button cerrar; Botones13() { setLayout(new GridLayout(1,4)); fname = new TextField(); cargar = new Button("Cargar"); grabar = new Button("Grabar"); cerrar = new Button("Cerrar"); add(new Label("Archivo:")); add(fname);

add(cargar); add(grabar); add(cerrar); } public boolean handleEvent(Event e) { if ((e.id==Event.ACTION_EVENT)&&(e.target==cargar)) e.id=2001; if ((e.id==Event.ACTION_EVENT)&&(e.target==grabar)) e.id=2002; if ((e.id==Event.ACTION_EVENT)&&(e.target==cerrar)) e.id=2003; return super.handleEvent(e); } public String toString() { return fname.getText(); } } /* // ------- Para mostrar los errores... */ class Error13 extends Frame { Error13(String error) { add("Center",new Label(error)); add("South", new Button("Ok")); pack(); show(); } public boolean handleEvent(Event e) {

dispose(); return super.handleEvent(e); } }

Volviendo al A*6 Para aprender un poquito m%s sobre la biblioteca gr%/ica +A*6,, vamos a modi/icar nuestro 9ltimo programa para usar men9s Vamos a volver a poner todo el cdigo +que ampliamos para usar como applet o aplicacin local, marcando las di/erencias m%s notables/* // ----- Archivo: Ejemplo14.java */ import java.io.*; import java.awt.*; import java.applet.*; public class Ejemplo14 extends Applet { public void init() { new Ventana14(true); // con "true" avisamos que es applet } public static void main(String args[]) { // para usarlo como aplicacin Ventana14 v14 = new Ventana14(false); // con "false" avisamos que no es applet } } /* // -------- Esta clase es la que en realidad hace el trabajo */ class Ventana14 extends Frame { TextArea contenido;

boolean enApplet; // para indicar si lo llamamos como applet String nombreArchivo; // para guardar el nombre del archivo abierto MenuItem mArchivoAbrir; // ACA ESTAN LOS ITEMS DE LOS MENUS MenuItem mArchivoGrabar; // . MenuItem mArchivoSalir; // . MenuItem mEditCortar; // . MenuItem mEditCopiar; // . MenuItem mEditPegar; // . MenuItem mEditTodo; // v String clipboard; // buffer para cortar y pegar boolean editado = false; // ac indicamos si modificamos el archivo Ventana14(boolean enApp) { super("Ejemplo de E/S"); enApplet = enApp; // recordamos si es applet o no Menu menuArchivo = new Menu("&Archivo"); // CREAMOS LOS MENUS!!! mArchivoAbrir = new MenuItem("&Abrir..."); mArchivoGrabar = new MenuItem("&Grabar..."); mArchivoSalir = new MenuItem("&Salir"); menuArchivo.add(mArchivoAbrir); menuArchivo.add(mArchivoGrabar); menuArchivo.add(new MenuItem("-")); menuArchivo.add(mArchivoSalir); Menu menuEdit = new Menu("&Edit"); mEditCortar = new MenuItem("Cor&tar"); mEditCopiar = new MenuItem("&Copiar"); mEditPegar = new MenuItem("&Pegar"); mEditTodo = new MenuItem("&Seleccionar todo"); menuEdit.add(mEditCortar);

menuEdit.add(mEditCopiar); menuEdit.add(mEditPegar); menuEdit.add(new MenuItem("-")); menuEdit.add(mEditTodo); MenuBar barraMenu = new MenuBar(); barraMenu.add(menuArchivo); barraMenu.add(menuEdit); setMenuBar(barraMenu); contenido = new TextArea(); // solo pongo una ventana de texto add("Center",contenido); pack(); show(); clipboard = new String(""); // clipboard vaco, mEditPegar.disable(); // nada para pegar, mArchivoGrabar.disable(); // nada para grabar } public boolean handleEvent(Event e) { if ((e.id==Event.WINDOW_DESTROY)||(e.target==mArchivoSalir)) { if (editado) System.out.println("Pedir confirmacin!\n"); // debera confirmar // si se quiere ir sin grabar! if (enApplet) dispose(); else System.exit(0); } if (e.target==mArchivoAbrir) CargarArchivo(); // ac proceso selecciones if (e.target==mArchivoGrabar) GrabarArchivo(); // de men if (e.target==mEditCortar) { clipboard = contenido.getSelectedText();

mEditPegar.enable(); contenido.replaceText("",contenido.getSelectionStart(),contenido.getSelec tionEnd()); editado=true; } if (e.target==mEditCopiar) { clipboard = contenido.getSelectedText(); mEditPegar.enable(); } if (e.target==mEditPegar) { contenido.replaceText("",contenido.getSelectionStart(),contenido.getSelec tionEnd()); contenido.insertText(clipboard,contenido.getSelectionStart()); editado=true; } if (e.target==mEditTodo) contenido.selectAll(); if ((e.id==Event.KEY_PRESS)&&(e.target==contenido)) editado=true; mArchivoGrabar.enable(editado); return super.handleEvent(e); } void CargarArchivo() { FileInputStream fptr; DataInputStream f; String linea = null; if (editado) System.out.println("Pedir confirmacin!\n"); FileDialog fd = new FileDialog(this,"Abrir...",FileDialog.LOAD); // elijo archivo fd.show(); // usando el dilogo estndar del sistema! nombreArchivo = fd.getFile();

try { fptr = new FileInputStream(nombreArchivo); f = new DataInputStream(fptr); contenido.setText(""); // vaco la ventana antes de cargar nuevo archivo do { linea = f.readLine(); if (linea!=null) contenido.appendText(linea+"\n"); } while (linea != null); fptr.close(); editado=false; // archivo nuevo -> no editado } catch (FileNotFoundException e) { new Error14("El archivo no existe!"); } catch (IOException e) { new Error14("Error leyendo archivo!"); } catch (NullPointerException e) { ; } } void GrabarArchivo() { FileOutputStream fptr; DataOutputStream f; FileDialog fd = new FileDialog(this,"Grabar...",FileDialog.SAVE); // grabo archivo fd.setFile(nombreArchivo); // usando el dilogo estndar del sistema! fd.show(); nombreArchivo = fd.getFile();

try { fptr = new FileOutputStream(nombreArchivo); f = new DataOutputStream(fptr); f.writeBytes(contenido.getText()); fptr.close(); editado=false; // recin grabado -> no editado } catch (IOException e) { new Error14("Error grabando archivo!"); } catch (NullPointerException e) { ; } } } /* // ------- Para mostrar los errores... */ class Error14 extends Frame { Error14(String error) { add("Center",new Label(error)); add("South", new Button("Ok")); pack(); show(); } public boolean handleEvent(Event e) { dispose(); return super.handleEvent(e);

} }

?en9 a la Java 7ueno, lo primero que vamos a ver son los men9s &a barra de men9 est% compuesta por men9es, que a su vez est%n compuestos de 'tems +que pueden tambin ser men9es, Por ejemplo la barra de men9 la declaramos conMenuBar barraMenu = new MenuBar();

y le agregamos los men9es Arc$ivo y !dit +que $abremos creado previamente, conbarraMenu.add(menuArchivo); barraMenu.add(menuEdit);

>inalmente la declaramos como !& men9 de la ventana +>rame,setMenuBar(barraMenu);

Cada uno de los men9s los declaramos previamenteMenu menuArchivo = new Menu("&Archivo"); ... Menu menuEdit = new Menu("&Edit");

)oten que el 2a2 no se visualiza, sino que la letra que le sigue aparece subrayada- Arc$ivo, !dit !sto permite que se pueda seleccionar el men9 tanto con el mouse como con la tecla alt0 o meta0, seguida de la tecla subrayada A su vez, el mtodo add est% presente tambin en la clase ?en9 y nos permite agregar los 'temsmArchivoAbrir = new MenuItem("&Abrir..."); mArchivoGrabar = new MenuItem("&Grabar..."); mArchivoSalir = new MenuItem("&Salir"); menuArchivo.add(mArchivoAbrir); menuArchivo.add(mArchivoGrabar); menuArchivo.add(new MenuItem("-")); menuArchivo.add(mArchivoSalir);

A estos 'tems los $emos declarado como globales en la clase para usarlos luego en los eventos )oten adem%s que menuArc$ivo add+ne" ?enuItem+202,,= no agrega un 'tem al men9 sino una l'nea de separacin, y no necesitamos crearlo como objeto permanente #i miramos la arquitectura de las clases, tanto ?enu7ar como ?enuItem descienden de ?enuComponent A su vez, ?enu desciende de ?enuItem, por lo que implementa los mismos mtodos y vamos a lo que dec'amos antes- un men9 puede ser un 'tem de otro men9, y as' sucesivamente tantos subniveles de men9s como queramos >inalmente, en nuestro manejador de eventos simplemente necesitamos veri/icar si se eligi un 'tem probando si el evento ocurri sobre el 'tem determinadoif ((e.id==Event.WINDOW_DESTROY)||(e.target==mArchivoSalir)) { if (editado) System.out.println("Pedir confirmacin!\n"); if (enApplet) dispose(); else System.exit(0); } if (e.target==mArchivoAbrir) CargarArchivo(); ................ if (e.target==mEditTodo) contenido.selectAll();

!n resumen lo que $ago es. #i eligi Arc$ivoD#alir +o alt0>A o lo que sea, salgo del programa . #i eligi Arc$ivoDAbrir, llamo al mtodo CargarArc$ivo . #i eligi Arc$ivoDcrabar, llamo al mtodo crabarArc$ivo . #i eligi !ditDCortar copio el te<to seleccionado a mi clipboard y borro la seleccin . #i eligi !ditDCopiar slo copio el te<to seleccionado a mi clipboard . #i eligi !ditDPegar borro el te<to seleccionado e inserto el de mi clipboard . #i eligi !ditD#eleccionarXtodo marco todo el te<to !n todos los casos, si se modi/ica el te<to del contenido lo indico poniendo editado en true= lo mismo si presiono una tecla sobre el %rea de edicinif ((e.id==Event.KEY_PRESS)&&(e.target==contenido)) editado=true;

8n par de aclaraciones. get#election#tart+, y get#election!nd+, marcan los l'mites del te<to seleccionado +si no lo $ay, son iguales, . get#elected6e<t+, devuelve el te<to seleccionado en el 6e<tArea . replace6e<t+, reemplaza una parte +o todo, del 6e<tArea por un #tring . insert6e<t+, inserta un #tring en un lugar determinado del 6e<tArea . selectAll+, selecciona todo el te<to del 6e<tArea . ?enuItem enable+, $abilita un 'tem de men9 &o utilizo para $abilitar !ditDPegar slo luego de cortar o copiar algo a mi clipboard . !n el caso del 'tem Arc$ivoDcrabar, lo $abilito o no dependiendo de la variable editado, utilizando la otra /orma de enable- ?enuItem enable+boolean, 5i%logos !n Java disponemos de la clase 5ialog para crear di%logos, es decir, ventanitas temporarias para entradas de usuario, que dependen de otra +de $ec$o la clase 5ialog es $eredera de la clase *indo", #i bien podemos crear di%logos a medida usando la clase >rame, se supone que usar di%logos debe ser m%s /%cil &a realidad es que por a$ora no se puede usar muc$o m%s que los di%logos est%ndar +y el 9nico que vale la pena es >ile5ialog,, ya que las implementaciones actuales de Java tienen un problema- en algunas plata/ormas el programa que abre el di%logo sigue, en lugar de esperar que se cierre el di%logo y devuelva la respuesta Por eso $emos puesto solamente una indicacin adonde deber'a $aber un di%logo de con/irmacinif (editado) System.out.println("Pedir confirmacin!\n");

!n ese lugar deber'amos llamar por ejemplo a un di%logo que nos permita decidir por s' o por noif (editado) { sino = new ConfirmarDlg(this,"Archivo modificado!"); if (sino.getResponse()==true) ....; else ....; }

o algo as' !sto mismo lo podemos $acer de otras maneras, por ejemplo usando t$reads y comunicaciones entre procesos, pero se complica muc$o para esta altura del curso !speremos un poco m%s adelante, aunque #un me prometi que en la versin J J ya va a estar corregido +sale para /ines del dB@, Por lo pronto, veamos un caso simple con la clase >ile5ialogFileDialog fd = new FileDialog(this,"Abrir...",FileDialog.LOAD); fd.show(); nombreArchivo = fd.getFile();

Primero declaramos una variable de tipo >ile5ialog, y creamos la instancia con ne" Como par%metros se pasa el padre +t$is, o sea 2esta ventana2,, el t'tulo de la ventanita de di%logo, y una constante &1A5 o #AV! +son static, por lo que se denominan directamente con el nombre de la clase y no necesariamente de una instancia, que indica si el di%logo es para cargar o grabar un arc$ivo +1bviamente la tarea en s' de cargar o grabar el arc$ivo la tenenmos que $acer nosotros, el di%logo slo espera que elijamos un nombre, !l mtodo s$o"+, muestra el di%logo y espera que seleccionemos y presionemos 1^ o Cancel Aqu' es donde /allan los dem%s di%logos ya que es programa sigue sin esperar >inalmente, el di%logo se cierra pero no se elimina el objeto +posiblemente est% implementado usando el mtodo $ide+,, que lo oculta de la vista pero no se pierde $asta no salir del mtodo que lo cre, donde actuar'a el recogedor de basura de la memoria, !sto $ace que aunque no lo veamos podamos llamar al mtodo get>ile+, sobre este objeto, que nos devuelve el nombre del arc$ivo seleccionado +o null si se presion Cancel, 5ibuJava Adem%s de los componentes est%ndar +botones, listas, etc ,, $ay un componente para dibujo 2libre2 que nos permite implementar cualquier otro tipo de control- la clase Canvas 6'picamente se usa para dibujar, y corresponde a una zona rectangular dentro de una ventana &a clase en s' no $ace pr%cticamente nada= el programador debe de/inir una subclase de Canvas a la que el A*6 le env'a todos los eventos de mouse y teclado Hede/iniendo los mtodos got>ocus, lost>ocus, ^ey5o"n, ^ey8p, mouse!nter, mouse!<it, mouse?ove, mouse5rag, mouse5o"n y mouse8p, el programador puede $acer lo que se le ocurra dentro de ese rect%ngulo Vamos a $acer uso de un Canvas para generar un applet donde $abr% una zona rectangular dentro de la que, $aciendo clic^ con el mouse y movindolo sin soltar el botn, dibujaremos un rect%ngulo din%micamente !sto nos permitir% ver cmo usar un Canvas para dibujar, capturar eventos, etc !l borde tiembla un poco al redibujar, pero ya veremos cmo evitar eso

Canvas en accin Primero vamos a poner, como ya se est% $aciendo costumbre, el cdigo del applet +Hecordar que debe cargarse desde una p%gina $tml para verlo; Aqu' no creamos ninguna ventana y no podremos verlo como aplicacin standalone, y luego intentaremos e<plicar cmo /unciona
import java.awt.*; import java.applet.Applet; public class Ejemplo15 extends Applet { public void init() { Label label = new Label("Pique y arrastre con el mouse!"); miCanvas zonaDib = new miCanvas(); zonaDib.resize(new Dimension (200,200)); add("North", label); add("Center", zonaDib); resize(300,250); } } class miCanvas extends Canvas { Rectangle rectActual; public boolean mouseDown(Event e, int x, int y) { rectActual = new Rectangle(x, y, 0, 0); repaint(); return false; } public boolean mouseDrag(Event e, int x, int y) { rectActual.resize(x-rectActual.x, y-rectActual.y); repaint(); return false; } public boolean mouseUp(Event e, int x, int y) {

rectActual.resize(x-rectActual.x, y-rectActual.y); repaint(); return false; } public void paint(Graphics g) { Dimension d = size(); g.setColor(Color.red); g.drawRect(0, 0, d.width-1, d.height-1); g.setColor(Color.blue); if (rectActual != null) { Rectangle box = cortarRect(rectActual, d); g.drawRect(box.x, box.y, box.width-1, box.height-1); } } Rectangle cortarRect(Rectangle miRect, Dimension areaDib) { int x = miRect.x; int y = miRect.y; int ancho = miRect.width; int alto = miRect.height; if (ancho < 0) { ancho = -ancho; x = x - ancho + 1; if (x < 0) { ancho += x; x = 0; } } if (alto < 0) {

alto = -alto; y = y - alto + 1; if (y < 0) { alto += y; y = 0; } } if ((x + ancho) > areaDib.width) { ancho = areaDib.width - x; } if ((y + alto) > areaDib.height) { alto = areaDib.height - y; } return new Rectangle(x, y, ancho, alto); } }

!l applet0container !n primer lugar $emos tenido en cuenta que un Applet es un Panel, y por lo tanto tambin un Container, as' que en lugar de crear una ventana aparte simplemente le agregamos dos componentes- un &abel y un Canvas
zonaDib.resize(new Dimension (200,200)); add("North", label); add("Center", zonaDib); resize(300,250);

!l mtodo rezise, sobre la clase miCanvas, nos permite redimensionar el mismo al tamaGo deseado Igualmente, usamos resize sobre el applet para darle un tamaGo adecuado #i se modi/ica el tamaGo de la ventana en el appletvie"er se observar% un comportamiento algo e<traGo en cuanto al posicionamiento relativo del rect%ngulo y el cartel, pero para simpli/icar esto bastar%

)uestro Canvas a medida Como no vamos a tomar ninguna accin especial al crear el canvas, no $emos de/inido el constructor +se utiliza el constructor por de/ecto de la clase Canvas, #implemente $emos rede/inido algunos mtodos para actuar al presionar, arrastrar y soltar el mouse, para redibujar el %rea de dibujo +canvas, y para recortar el rect%ngulo dibujado si nos vamos con el mouse /uera del espacio que ocupa el canvas &a variable global rectActual, de la clase Hectangle, contendr% las coordenadas del rect%ngulo que estamos dibujando !l mtodo Paint se llama autom%ticamente cada vez que es necesario redibujar el componente, o si llamamos e<pl'citamente al mtodo repaint+,public void paint(Graphics g) { Dimension d = size(); g.setColor(Color.red); g.drawRect(0, 0, d.width-1, d.height-1); g.setColor(Color.blue); if (rectActual != null) { Rectangle box = cortarRect(rectActual, d); g.drawRect(box.x, box.y, box.width-1, box.height-1); } }

!n primer lugar le asignamos a una variable d el tamaGo del canvas usando el mtodo size+,, luego elegimos un color +rojo, para dibujar un borde y dibujamos un rect%ngulo del tamaGo del componenteDimension d = size(); g.setColor(Color.red); g.drawRect(0, 0, d.width-1, d.height-1);

5os atributos de la clase 5imension, "idt$ y $eig$t, se $an cargado con el tamaGo del canvas y son los que usamos para dar el tamaGo del rect%ngulo &uego, si se est% dibujando un rect%ngulo +rectActual ;O null, simplemente lo recortamos +en caso de que $ayamos arrastrado el mouse /uera del canvas, y lo dibujamos !l mtodo que lo recorta a los l'mites del canvas, cortarHect, asigna a cuatro variables las coordenadas del rect%ngulo +que se le pasaron como par%metro miHect al llamarlo,-

int x = miRect.x; int y = miRect.y; int ancho = miRect.width; int alto = miRect.height;

#i el anc$o +o el alto, es negativo, simplemente lo cambia de signo y toma como coordenada < +y, de origen el otro vrtice del rect%ngulo, que corresponder% al < que se pas menos el anc$o y m%s uno +recordar que el origen de coordenadas empieza en cero y no en uno, #i este vrtice est% /uera del canvas +<PK,, lo pone en cero y le resta al anc$o la parte recortada +notar que anc$o4O<, como < es negativo, es en realidad una resta,
if (ancho < 0) { ancho = -ancho; x = x - ancho + 1; if (x < 0) { ancho += x; x = 0; } }

#i nos vamos del %rea de dibujo por la derec$a +o por abajo,, simplemente le recortamos al anc$o +alto, el e<ceso de modo que llegue $asta el borde del %rea de dibujo +que tambin $emos pasado al mtodo como par%metro,if ((x + ancho) > areaDib.width) { ancho = areaDib.width - x; }

#lo nos quedan por ver los mtodos que responden al mouse Cuando presionamos el mouse dentro del canvas, comenzamos la creacin de un nuevo rect%ngulo de anc$o y alto cero que comienza en el punto en que $emos presionado el mouse, y redibujamos el canvaspublic boolean mouseDown(Event e, int x, int y) { rectActual = new Rectangle(x, y, 0, 0); repaint();

return false; }

Al mover el mouse, redimensionamos el rect%ngulo con anc$o < menos el origen de dibujo +y alto y menos el origen de dibujo,, y repintamospublic boolean mouseDrag(Event e, int x, int y) { rectActual.resize(x-rectActual.x, y-rectActual.y); repaint(); return false; }

>inalmente, al soltar el mouse, redimensionamos como antes y redibujamospublic boolean mouseUp(Event e, int x, int y) { rectActual.resize(x-rectActual.x, y-rectActual.y); repaint(); return false; }

Como no se toma ninguna medida para guardar el rect%ngulo dibujado, al crear uno nuevo +reasignando rectActual a un nuevo rect%ngulo,, el anterior se pierde 5ibuJava II Vamos a retocar un poquito nuestro ejemploJC para que no se borren los rect%ngulos cuando queremos dibujar uno nuevo Aprenderemos algo sobre la clase Vector, perteneciente al paquete java util Vectores en accin &os vectores nos permiten $acer arreglos de cualquier tipo de objeto, y re/erirnos individualmente a cualquier elemento del vector, aunque para utilizarlos +debido a que para java el vector contiene objetos genricos, tendremos que decirle qu clase de objeto es mediante un 2cast2 Vamos a ver cmo quedan nuestras clases !jemploJ@ +e< !jemploJC, y miCanvasimport java.awt.*; import java.util.*; import java.applet.Applet;

public class Ejemplo16 extends Applet { public void init() { ................ (esta parte no cambia)................ } } class miCanvas extends Canvas { Vector v = new Vector(); // inicializamos con tamao indeterminado // Java se encarga de manejar la me moria necesaria! public boolean mouseDown(Event e, int x, int y) { v.addElement( new Rectangle(x, y, 0, 0) ); // nuevo elemento! repaint(); return false; } public boolean mouseDrag(Event e, int x, int y) { Rectangle r = (Rectangle)v.lastElement(); // cast: v son rectngulos r.resize( x - r.x, y - r.y ); // (cre r slo por claridad) repaint(); return false; } public boolean mouseUp(Event e, int x, int y) { Rectangle r = (Rectangle)v.lastElement(); // cast: v son rectngulos r.resize( x - r.x, y - r.y ); // (cre r slo por claridad) repaint(); return false; } public void paint(Graphics g) { int i; // contador de rectngulos Dimension d = size();

g.setColor(Color.red); g.drawRect(0, 0, d.width-1, d.height-1); g.setColor(Color.blue); if (v.size() > 0) for (i=0; i<v.size(); i++) { Rectangle box = cortarRect( (Rectangle)v.elementAt( i ), d); g.drawRect(box.x, box.y, box.width-1, box.height-1); } } ........................ (el resto no cambia) ........................ }

&es sugiero utilizar un F6?& que reserve espacio su/iciente para ver todo el applet, como<HTML> <HEAD> <TITLE>Ejemplo 16 - Ejemplo con canvas</TITLE> </HEAD> <BODY> <applet code="Ejemplo16.class" width=300 height=250> </applet> </BODY> </HTML>

Veamos los pasos a$ora !n primer lugar creamos una variable +global a la clase, llamada v, de clase Vector, y sin asignarle un tamaGo de/inidoVector v = new Vector();

Al crear un nuevo rect%ngulo agregamos un elemento +objeto, al vector mediante el mtodo addv.addElement( new Rectangle(x, y, 0, 0) );

Para acceder a un atributo de un objeto del vector no basta utilizar directamente el vector, comov.lastElement().x

+last!lement+, nos permite acceder al 9ltimo elemento agregado al vector, !s necesario aclarar e<pl'citamente que el elemento en cuestin es un rect%ngulo, ya que el vector puede contener objetos de cualquier tipo Para eso usamos el casting(Rectangle)v.lastElement().x

!n nuestro cdigo original reemplazar'amos por(Rectangle)v.lastElement().resize( x - (Rectangle)v.lastElement().x, ......

Pero es m%s claro si usamos una variable local de clase Hectangle, le asignamos el mismo objeto que acabamos de agregar al vector, y lo usamos en su lugarRectangle r = (Rectangle)v.lastElement(); r.resize( x - r.x, y - r.y );

>inalmente, en el mtodo paint+, no podemos asignar el elemento $asta no saber que e<iste +originalmente el vector estaba vac'o;, As' que un i/ nos permite veri/icar que el tamaGo del vector es mayor que cero +tiene elementos,, y un /or nos permite dibujarlos uno por uno #e puede acceder a todos los elementos, uno por uno, mediante el mtodo elementAt+<,, que nos da el <simo elemento del vector !l mtodo size+, nos da la cantidad de elementos +el primero es el n9mero K, y as',if (v.size() > 0) for (i=0; i<v.size(); i++) { Rectangle box = cortarRect( (Rectangle)v.elementAt( i ), d); g.drawRect(box.x, box.y, box.width-1, box.height-1); }

Aqu' no $emos creado variables intermedias ya que igualmente es claro +eso creo , >lic^er molesto; 7ueno, el problema que nos queda es el molesto 2/lic^er2, o sea la manera en que titila el dibujo cuando movemos el mouse !sto es porque cada vez que se llama a paint+,, el /ondo se borra y se redibuja todo el canvas 7%sicamente, la manera de evitarlo es reescribiendo el mtodo update+,, que es el que borra el /ondo antes de llamar a paint+, para que no lo borre= otro mtodo +que es el que vamos a usar, es dibujar no sobre la pantalla sino sobre un 2bu//er2 gr%/ico, y luego copiar ese bu//er sobre la pantalla +lo que es muc$o m%s e/iciente que dibujar sobre la misma, Para eso vamos a crear un par de objetos-

class miCanvas extends Canvas { Vector v = new Vector(); Image imgBuff; Graphics grafBuff;

Image es una clase abstracta, madre de todas las clases que representan im%genes gr%/icas crap$ics es tambin abstracta y nos permite obtener un conte<to en el cual dibujar &o que vamos a $acer es modi/icar nuestro mtodo paint+, para que simplemente llame a update+,, y rede/inir el mtodo update+,public void paint(Graphics g) { update(g); }

!l mtodo update+, es el que $ar% todo el trabajo y b%sicamente es como nuestro viejo paint+, con algunos agregadospublic void update(Graphics g) { int i; Dimension d = size(); if (grafBuff == null) { imgBuff = createImage(d.width, d.height); grafBuff = imgBuff.getGraphics(); } grafBuff.setColor(getBackground()); grafBuff.fillRect(0, 0, d.width, d.height); grafBuff.setColor(Color.red); grafBuff.drawRect(0, 0, d.width-1, d.height-1); grafBuff.setColor(Color.blue); if (v.size() > 0) for (i=0; i<v.size(); i++) { Rectangle box = cortarRect((Rectangle)v.elementAt(i), d); grafBuff.drawRect(box.x, box.y, box.width-1, box.height-1);

} g.drawImage(imgBuff, 0, 0, this); }

!n negrita $emos indicado los agregados #i no est% creado todav'a +gra/7u//OOnull,, creamos nuestro bu//er de dibujo Para crear dic$o bu//er gr%/ico +de clase crap$ics,, primero creamos una imagen que en este caso tiene las mismas dimensiones que el canvas +d "idt$ < d $eig$t ,, y luego asignamos a gra/7u// el conte<to de dic$a imagen mediante el mtodo getcrap$ics+, Imag'nense que con createImage+ , crean una 2pantalla virtual2, y getcrap$ics+, nos da una /orma de acceder a esa pantalla como si /uera real 8tilizando dic$o conte<to, elegimos como color el mismo color de /ondo del applet +get7ac^ground+,, y dibujamos un rect%ngulo lleno +/illHect+ ,,, borrando as' cualquier cosa que $ubiera estado dibujada !n it%lica $emos indicado las modi/icaciones a nuestro mtodo anterior #implemente, en lugar de usar el conte<to de la pantalla +el par%metro g del mtodo,, dibujamos sobre nuestro conte<to0 pantalla virtual >inalmente, y para poder visualizar nuestro dibujo, usamos el mtodo dra"Image sobre el conte<to de la pantalla real +g,, que copia nuestro conte<to img7u// en las coordenadas +K,K, sobre la pantalla #e $ace tambin re/erencia al canvas + t$is,- el cuarto par%metro de dra"Image es un objeto de clase Image1bserver, una inter/ace que sirve para que el objeto dentro del cual se dibuja reciba mensajes asincrnicos que le indican cmo est% siendo construida la imagen, y cu%ndo est% lista Animate; #i bien puede ser un poco m%s complejo de entender que un dibujo directo sobre la pantalla, notar%n que la implementacin es directa y no trae ning9n problema !sta misma apro<imacin puede utilizarse para crear animaciones !n este ejemplo, para manejar la ejecucin cuadro a cuadro de la animacin, usamos 6$reads )o se preocupen por eso, lo veremos pronto enicamente tengan en cuenta que nuestro applet debe implementar la clase runnable, y el t$read se encarga de ejecutar el mtodo run+, que simplemente llama a repaint+, y espera JKK milisegundos entre cuadro y cuadro !l trabajo de c%lculo y dibujo lo $ace update+, #e los dejo para que lo estudien= no es nada complicado y tambin usa doble bu//ering +como el ejemplo anterior,
import java.awt.*; import java.util.*; import java.applet.Applet;

public class Ejemplo18 extends Applet implements Runnable { Thread animador; Image imgBuff; Graphics grafBuff; double ang = 0.0; public void init() { resize(new Dimension (200,200)); } public void start() { if (animador == null) animador = new Thread(this); animador.start(); } public void run() { while (Thread.currentThread() == animador) { repaint(); try { Thread.sleep(100); } catch (InterruptedException e) { break; } } } public void update(Graphics g) { int i; int dx, dy; Dimension d = size(); if (grafBuff == null) {

imgBuff = createImage(d.width, d.height); grafBuff = imgBuff.getGraphics(); } grafBuff.setColor(getBackground()); grafBuff.fillRect(0, 0, d.width, d.height); grafBuff.setColor(Color.red); grafBuff.drawRect(0, 0, d.width-1, d.height-1); grafBuff.setColor(Color.blue); dx = (int)(50 * Math.abs(Math.cos(ang))); dy = (int)(50 * Math.abs(Math.sin(ang))); ang = ang + 0.1; if (ang>2*Math.PI) ang = 0.0; grafBuff.drawRect(100-dx, 100-dy, 2*dx, 2*dy); g.drawImage(imgBuff, 0, 0, this); } }

Java en $ebras &a clase anterior usamos, en el 9ltimo ejemplo, un concepto al que vamos a dedicar a$ora nuestra atencinlos t$reads &a traduccin literal de t$read es $ilo o $ebra, y se utiliza tambin para re/erirse al $ilo de un discurso !l concepto de t$reads en los ambientes y sistemas operativos es un poco complejo de e<plicar pero sencillo de entender- independientemente del sistema elegido, puede pensarse que un t$read es algo as' como el lugar de ejecucin de un programa !n la mayor'a de los programas que $emos visto, $emos usado un solo t$read= es decir que un programa comienza y su ejecucin sigue un camino 9nico- como un monlogo Java es multit$reading !sto signi/ica algo as' como que tiene capacidad de di%logo, y m%s a9npuede ejecutar muc$os t$reads en paralelo, como si trat%ramos de una conversacin m9ltiple y simult%nea

)o con/undir aqu' multit$reading con la capacidad de ejecutar varios programas a la vez !sta es una posibilidad, pero tambin un mismo programa puede utilizar varios t$reads +2caminos de ejecucin23, simult%neamente !sto, por supuesto, depende /undamentalmente de la capacidad del sistema operativo para soportar multit$reading, y por esto Java no puede ejecutarse +al menos en /orma completa, en sistemas que no lo soporten !l uso de t$reads nos permite, por ejemplo, ejecutar simult%neamente varios programas que interact9en entre ellos= o, tambin, que un programa, mientras por ejemplo actualiza la pantalla, simult%neamente realice una serie de c%lculos sin tener que $acer esperar el usuario 8na /orma sencilla de verlo es imaginar que tenemos un grupo de microprocesadores que pueden ejecutar, cada uno, un solo t$read= y nosotros asignamos programas +o partes de programas, a cada uno de ellos Adem%s, podemos imaginar que esos microprocesadores comparten una memoria com9n y recursos comunes, de lo que surgir% una serie de problemas importantes a tener en cuenta cuando se usan t$reads &os pasos b%sicos Fay tres cosas a tener en cuenta para usar t$reads en un programa. &a clase que queremos asignar a un t$read debe implementar la inter/ace Hunnable . 5ebemos crear una variable +instancia, del tipo 6$read, que nos permitir%n acceder y manejar el t$read !n los applets, en el mtodo start+, simplemente crearemos el t$read +y, posiblemente, lo pondremos a ejecutar, . W por 9ltimo tenemos que crear un mtodo run+, que es el que ejecuta el cdigo del programa propiamente dic$o &a inter/ace Hunnable, simplemente de/inida comopublic interface java.lang.Runnable { // Methods public abstract void run(); }

le asegura al compilador que nuestra clase +la que utilizar% el t$read para ejecutarse, dispone de mtodo run+,

Vamos a ver un par de ejemplos, primero una aplicacin standalone y luego un applet Heunin de amigos !l siguiente ejemplo +!jemploJB java, usa t$reads para activar simult%neamente tres objetos de la misma clase, que comparten los recursos del procesador pele%ndose para escribir a la pantalla
class Ejemplo19 { public static void main(String argv[]) throws InterruptedException { Thread Juan = new Thread (new Amigo("Juan")); Thread Luis = new Thread (new Amigo("Luis")); Thread Nora = new Thread (new Amigo("Nora")); Juan.start(); Luis.start(); Nora.start(); Juan.join(); Luis.join(); Nora.join(); } } class Amigo implements Runnable { String mensaje; public Amigo(String nombre) { mensaje = "Hola, soy "+nombre+" y este es mi mensaje "; } public void run() { for (int i=1; i<6; i++) { String msg = mensaje+i; System.out.println(msg); }

} }

Como siempre, compilarlo con javac !jemploJB java y ejecutarlo con java !jemploJB !n un sistema operativo preemptivo, la salida ser% m%s o menos as'Fola, soy Juan y este es mi mensaje J Fola, soy Juan y este es mi mensaje E Fola, soy &uis y este es mi mensaje J Fola, soy &uis y este es mi mensaje E Fola, soy )ora y este es mi mensaje J Fola, soy )ora y este es mi mensaje E Fola, soy )ora y este es mi mensaje T Fola, soy Juan y este es mi mensaje T etc (u signi/ica que un sistema operativo es preemptivo3 Casos t'picos son 8ni< o *indo"s BC- cada tarea utiliza una parte del tiempo del procesador, y luego lo libera para que puedan ejecutarse otras tareas +otros t$reads, Por eso se mezclan los mensajes de salida #i el sistema operativo es no preemptivo, el procesador no se libera $asta que no termina con el t$read actual, y por lo tanto la salida ser'a as'Fola, soy Juan y este es mi mensaje J Fola, soy Juan y este es mi mensaje E Fola, soy Juan y este es mi mensaje T Fola, soy Juan y este es mi mensaje A Fola, soy Juan y este es mi mensaje C Fola, soy &uis y este es mi mensaje J Fola, soy &uis y este es mi mensaje E etc

#i ustedes est%n utilizando un sistema operativo no preemptivo, deben e<pl'citamente indicarle al procesador c9ando puede ejecutar +dar paso, a otra tarea= para eso simplemente modi/iquen el mtodo run+,public void run() { for (int i=1; i<6; i++) { String msg = mensaje+i; System.out.println(msg); Thread.yield(); } }

!n este ejemplo, tanto en sistemas preemptivos como no preemptivos la salida ser%Fola, soy Juan y este es mi mensaje J Fola, soy &uis y este es mi mensaje J Fola, soy )ora y este es mi mensaje J Fola, soy Juan y este es mi mensaje E Fola, soy &uis y este es mi mensaje E Fola, soy )ora y este es mi mensaje E Fola, soy Juan y este es mi mensaje T Fola, soy &uis y este es mi mensaje T etc !sto es porque en seguida de imprimir estamos liberando al procesador para que pase a otro t$read +si $ay alguno esperando, )oten la di/erencia con el primer caso, sin usar yield+,, para sistemas preemptivos- el procesador reparte su trabajo en /orma +aparentemente, impredecible, por eso el orden de los mensajes no ser% el mismo en cualquier m%quina o sistema operativo Wa lo vimos /uncionar, pero ser'a bueno que lo entendamos; Por eso, vamos paso a paso Creando 6$reads 6$read es una clase b%sica en Java, que implementa la inter/ace Hunnable y dispone de unos cuantos mtodos por de/ecto &o importante a tener en cuenta que, para usar 6$reads, debemos crearlas como instancias y ponerlas a 2andar2-

Thread Juan = new Thread (new Amigo("Juan")); .............. Juan.start(); .............. Juan.join();

8n t$read tiene cuatro estados posiblescreado- $a sido creado mediante ne"+,, pero no se $a puesto en marc$a todav'a activo- est% en ejecucin, ya sea porque arranc con start+, o /ue 2despertado2 con resume+, dormido- $a sido suspendida su ejecucin moment%neamente mediante "ait+,, sleep+, o suspend+, muerto- se $a detenido de/initivamente, ya sea porque se termin el programa o mediante el llamado a stop+, !n este ejemplo $emos creado un t$read asign%ndole simult%neamente un objeto que lo utiliza +ne" Amigo+2Juan2,,, y seguidamente lo $emos activado, llamando al mtodo start+, !ste mtodo se encarga de inicializar el t$read y, /inalmente, llamar al mtodo run+, que $emos implementado 5e este modo, todo ocurre como si los mtodos run+, de cada objeto se ejecutaran en paralelo, concurrentemente &a /orma de manejar esto depende del sistema operativo !l mtodo join+, que llamamos al /inal $ace que el programa principal espere $asta que este t$read est 2muerto2 +/inalizada su ejecucin, !ste mtodo puede disparar la e<cepcin Interrupted!<ception, por lo que lo $emos tenido en cuenta en el encabezamiento de la clase !n nuestro ejemplo, simplemente a cada instancia de Amigo+ , que creamos la $emos ligado a un t$read y puesto a andar Corren todas en paralelo $asta que mueren de muerte natural, y tambin el programa principal acaba Cuando usamos 6$read yield+, +que en rigor deber'a ser 6$read current6$read+, yield+,, pero siendo algo de uso muy com9n los desarrolladores de Java lo $an simpli/icado,, simplemente el t$read actual le permite al procesador dedicarse a otro +si es que $ay alguno deseando utilizar sus servicios, &a clase Amigo+, es muy simple y con lo que $emos visto $asta a$ora no creo que tengamos que e<plicar nada m%s W los applets 3

6ambin podemos usar estos conceptos en los applets Veamos un ejemplo para terminar la clase de $oy, muy similar al anterior, donde tres contadores cuentan +en un sistema preemptivo, en /orma simult%nea Hecuerden crear una p%gina F6?& con el tag
<applet code="Ejemplo20.class" width=300 height=100></applet>

para poder verlo en accin con el appletvie"er o su bro"ser /avorito +que desde ya supongo que soporta Java; !l programa es e<tremandamente sencillo, y pueden verlo en accin si lo desean cargando via Internet la p%gina$ttp-DD""" amarillas comDroc^DjavaD!jemploEK $tm
// Ejemplo de applet que usa multithreading import java.awt.*; import java.applet.*; public class Ejemplo20 extends Applet { TextField tfa,tfb,tfc; public void init() { setLayout(new GridLayout(3,2)); tfa = new TextField("0"); tfb = new TextField("0"); tfc = new TextField("0"); add(new Label("Contador A")); add(tfa); add(new Label("Contador B")); add(tfb); add(new Label("Contador B")); add(tfc); } public void start() { Thread A = new Thread (new Counter(tfa)); Thread B = new Thread (new Counter(tfb));

Thread C = new Thread (new Counter(tfc)); A.start(); B.start(); C.start(); } } class Counter implements Runnable { TextField texto; String s; public Counter(TextField txtf) { texto = txtf; } public void run() { for (int i=0; i<1000; i++) { texto.setText(s.valueOf(i)); } } }

&a liebre y la tortuga +y el guepardo, Java dispone de un mecanismo de prioridades para los t$reads, de modo de poder asignar m%s tiempo de CP8 a un t$read que a otro 6'picamente se asigna una prioridad de J a JK +JK es la mayor prioridad, mediante setPriority, como en el ejemplo que siguepublic class Ejemplo21 { static Animal tortuga; static Animal liebre; static Animal guepardo; public static void main(String argv[]) throws InterruptedException { tortuga = new Animal(2, "T");

liebre = new Animal(3, "L"); guepardo = new Animal(4, "G"); tortuga.start(); liebre.start(); guepardo.start(); tortuga.join(); liebre.join(); guepardo.join(); } } class Animal extends Thread { String nombre; public Animal(int prioridad, String nombre) { this.nombre = nombre; setPriority(prioridad); } public void run() { for (int x = 0; x < 30; x++) { System.out.print( nombre ); yield(); } System.out.println("\nLlega "+nombre ); } }

&a salida de este programa, ejecutado con java !jemploEJ, es por ejemploC-NjavaNcursoQjava !jemploEJ cccccccccccccccccccccccccccccc &lega c

&6&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &lega & 66666666666666666666666666666 &lega 6 Como se ve, a pesar de $aber arrancado antes la tortuga, casi todo el tiempo de CP8 lo usa primero el cuepardo, luego la &iebre +aunque algo queda para la pobre tortuga, como se ve en la 6 marcada,, y /inalmente para la 6ortuga )o todas las corridas ni todos los sistemas dan igual salida, ya que sta depende de la carga del procesador y de la implementacin de Java particular !ste programa simplemente crea tres animales +clase Animal,, asigna un t$read a cada uno y los ejecuta !ste ejemplo est% $ec$o en base a uno del libro 2Programacin Java2 de ?acary y )icolas #incronicemos los relojes 8n problema b%sico del multit$reading es cuando varios programas +o, para el caso, varios t$reads, acceden a los mismos datos- [cmo sabemos si uno de ellos no los modi/ica mientras los est% usando otro3 Veamos un ejemplo, donde suponemos que varios t$reads usan la variable valorImportanteif (valorImportante > 0 ) { ..... algo se procesa ac ........ valorImportante = valorImportante - 1; ..... sigue..................... }

[Cmo nos aseguramos que valorImportante no cambi entre el i/ y la l'nea resaltada3 1tros t$reads pueden $aberlo modi/icado mientras tanto Asimismo, puede suceder que dos t$reads estn ejecutando la misma porcin de cdigo, y se pierda uno de los decrementos Imaginen algo as'+antes, valorImportante O JK +t$read J, lee valorImportante O JK +t$read E, lee valorImportante O JK +t$read J, JK 0J O B +t$read E, JK 0J O B +t$read E, asigna B a valorImportante

+t$read J, asigna B a valorImportante +despus, valorImportante O B Como vemos, a pesar de $aber restado dos veces, $emos perdido una de las restas Aunque usemos 0O en vez de la resta es lo mismo, porque el cdigo igualmente se resuelve en varios pasos +varias operaciones atmicas, Para evitar esto, Java nos brinda la palabra clave #ync$ronized, que bloquea el acceso a una variable a todos los t$reads menos el que lo est% usando Vamos a ver un caso espec'/ico= se trata de dos contadores que usan el mismo sumador para sumar de a uno una cantidad a #upuestamente entre los dos deben llevar el sumador +a, $asta EKKKK
// Archivo Ejemplo22.java, compilar con javac Ejemplo22.java, ejecutar con java Ejemplo22 public class Ejemplo22 { public static void main(String argv[]) { Sumador A = new Sumador(); // un nico sumador Contador C1 = new Contador(A); // dos threads que lo usan... Contador C2 = new Contador(A); // ...para sumar C1.start(); C2.start(); try { C1.join(); C2.join(); } catch (Exception e) { System.out.println(e); } } } class Contador extends Thread { Sumador s;

Contador (Sumador sumador) { s = sumador; // le asigno un sumador a usar } public void run() { s.sumar(); // ejecuto la suma } } class Sumador { int a = 0; public void sumar() { for (int i=0; i<10000; i++ ) { if ( (i % 5000) == 0 ) { // "%" da el resto de la divisin: System.out.println(a); // imprimo cada 5000 } a += 1; } System.out.println(a); // imprimo el final } }

!jecutando esto nos da m%s o menos as' +cada corrida es di/erente, dependiendo de cmo se 2c$ocan2 los t$reads y la carga de la CP8,C-NjavaNcursoQjava !jemploEE K L_ LBE@ JKATA JAJCB J_LCC

!sto se debe justamente a lo que e<plic%bamos al principio- a veces los dos t$reads intentan ejecutar a 4O J simult%neamente, con lo que algunos incrementos se pierden Podemos solucionar esto modi/icando el mtodo run+,public void run() { synchronized (s) { s.sumar(); } }

Con esto, slo a uno de los dos t$reads se les permite ejecutar s sumar+, por vez, y se evita el problema Por supuesto, el otro t$read queda esperando, por lo que m%s vale no utilizar esto con mtodos muy largos ya que el programa se puede poner lento o a9n bloquearse &a salida a$ora ser%C-NjavaNcursoQjava !jemploEE KP CKKK P primer t$read JKKKK P JKKKK + JCKKK + segundo t$read EKKKK + &o mismo logramos +y en /orma m%s correcta, declarando como sync$ronized al mtodo sumar+,public synchronized void sumar() { .............

!sto es mejor porque la clase que llama a sumar+, no necesita saber que tiene que sincronizar el objeto antes de llamar al mtodo, y si otros objetos +en otros t$reads, lo llaman, no necesitamos preocuparnos ?%s sincronizacin 1tra manera de sincronizar el acceso de los t$reads a los mtodos, es lograr que stos se pongan de acuerdo entre s', esperando uno $asta que otro realiz alguna tarea dada Para esto se usan los mtodos "ait+, y noti/y+, Cuando un t$read llama a "ait+, en un mtodo de un objeto dado, queda detenido $asta que otro t$read llame a noti/y+, en alg9n mtodo del mismo objeto

Por ejemplo, vamos a suponer cuatro empleados que se encuentran con su je/e y lo saludan, pero slo luego de que ste los salude primero
public class Ejemplo23 { public static void main(String argv[]) { Saludo hola = new Saludo(); Personal pablo = new Personal(hola, "Pablo", false); Personal luis = new Personal(hola, "Luis", false); Personal andrea = new Personal(hola, "Andrea", false); Personal pedro = new Personal(hola, "Pedro", false); Personal jefe = new Personal(hola, "JEFE", true); pablo.start(); luis.start(); andrea.start(); pedro.start(); jefe.start(); try { pablo.join(); luis.join(); andrea.join(); pedro.join(); jefe.join(); } catch (Exception e) { System.out.println(e); } } } class Saludo {

synchronized void esperarJefe(String empleado) { try { wait(); System.out.println(empleado+"> Buenos dias jefe!"); } catch (InterruptedException e) { System.out.println(e.toString()); } } synchronized void saludoJefe() { System.out.println("JEFE> Buenos dias!"); notifyAll(); } } class Personal extends Thread { String nombre; Saludo saludo; boolean esJefe; Personal (Saludo s, String n, boolean j) { nombre = n; saludo = s; esJefe = j; } public void run() { System.out.println("("+nombre+" llega)"); if (esJefe) saludo.saludoJefe(); else

saludo.esperarJefe(nombre); } }

8s noti/yAll+, en lugar de noti/y+,, porque en el segundo caso slo se noti/icar'a al primer t$read +el primer empleado en llegar, y no a los dem%s, que se quedar'an en el "ait+, Como se ve en la salida, a pesar de que los empleados est%n en condiciones de saludar, no lo $acen $asta que no llega el je/eC-NjavaNcursoQjava !jemploET +Pablo llega, +&uis llega, +Andrea llega, +Pedro llega, +J!>! llega, J!>!Q 7uenos dias; &uisQ 7uenos dias je/e; PedroQ 7uenos dias je/e; AndreaQ 7uenos dias je/e; PabloQ 7uenos dias je/e; Aqu' $ice trampa- a veces, el je/e llega y saluda antes que alguno de los empleados, por lo que ese empleado se queda esperando inde/inidamente Prueben de modi/icar las clases para que el je/e no salude $asta que no estn todos los empleados presentes Cap'tulo MV 0 #olucin al problema propuesto !n /orma muy sencilla, modi/icando slo la clase Personal, podemos solucionar el problema de que el je/e llegue antes que un empleadoclass Personal extends Thread { ................ static int llegaron = 0; ................

public void run() { System.out.println("("+nombre+" llega)"); if (esJefe) { while (llegaron < 4) { System.out.println("(Esperando...)"); } saludo.saludoJefe(); } else { synchronized(this) { llegaron++; } saludo.esperarJefe(nombre); } } }

Preparamos una variable static +de clase, para contar todos los empleados que pasaron por aqu'= la incrementamos justo antes de ejecutar saludo esperarJe/e +sincronizando el t$read en el incremento para que no pasen los problemas que vimos en el cap'tulo, !n el caso del je/e, simplemente espera que el contador llegue a A Podr'amos modi/icar esto un poco, pasando la cantidad de empleados como par%metro para que sea m%s /le<ible Inclusive, podemos usar dos constructores distintos +uno para los empleados y otro para el je/e, y en este 9ltimo caso pasamos la cantidad de empleados a esperar, &es dejo el ejemplo para que lo estudien
public class Ejemplo23 { public static void main(String argv[]) { Saludo hola = new Saludo(); Personal jefe = new Personal(hola, "JEFE", 3); Personal pablo = new Personal(hola, "Pablo"); Personal luis = new Personal(hola, "Luis");

Personal andrea = new Personal(hola, "Andrea"); jefe.start(); pablo.start(); luis.start(); andrea.start(); try { pablo.join(); luis.join(); andrea.join(); jefe.join(); } catch (Exception e) { System.out.println(e); } } } class Saludo { synchronized void esperarJefe(String empleado) { try { wait(); System.out.println(empleado+"> Buenos dias jefe!"); } catch (InterruptedException e) { System.out.println(e.toString()); } } synchronized void saludoJefe() { System.out.println("JEFE> Buenos dias!");

notifyAll(); } } class Personal extends Thread { String nombre; Saludo saludo; boolean esJefe; static int llegaron = 0; int numEmp; Personal (Saludo s, String n) { esJefe = false; nombre = n; saludo = s; } Personal (Saludo s, String n, int x) { esJefe = true; nombre = n; saludo = s; numEmp = x; } public void run() { System.out.println("("+nombre+" llega)"); if (esJefe) { while (llegaron < numEmp) { System.out.println("(Esperando...)"); } saludo.saludoJefe(); } else { synchronized(this) { llegaron++; }

saludo.esperarJefe(nombre); } } }

?ultimedia; Java permite cargar y visualizar arc$ivos cI> o JP!c de imagen y A8 de audio +solamente en mono, L bits, LKKKFz de muestreo, Para el caso del sonido, un arc$ivo de audio se carga mediante un objeto de la clase AudioClip, mediante el mtodo getAudioClip+8H&, arc$ivo,, se ejecuta con los mtodos play+, o loop+, y se detiene con stop+, )oten esto; #i bien dijimos que un applet no puede acceder al disco de la m%quina cliente, #I puede leer arc$ivos del server desde donde se carg Por lo tanto, pas%ndole el 8H& de la m%quina desde donde se carg el applet, podemos leer cualquier tipo de arc$ivo a travs de la red &a /orma m%s segura de indicar dic$o 8H& es mediante el mtodo get5ocument7ase+,, que nos da el 8H& adecuado Por ejemplo, puedo cargar y reproducir audio con slo dos l'neas-

AudioClip sonido = getAudioClip( getDocumentBase(), "sonido.au" ); sonido.play();

Por otra parte, una /oto puede cargarse mediante un objeto de clase Image mediante el mtodo getImage+8H&, arc$ivo, &uego la mostramos en un objeto crap$ics correspondiente al applet +o al %rea de dibujo, mediante dra"Image+imagen, <, y, observador, 1bservador es un objeto que implementa la inter/ace Image1bserver= los applets, por descender de Component +que implementa dic$a inter/ace, tambin la implementan 6'picamente, la imagen se visualiza en el mtodo paint+ , del applet............. algunMetodo(...) { .......... Image imagen = getImage(getDocumentBase(), "imagen.gif"); ..........

} ........... public void paint(Graphics g) { g.drawImage(imagen, xOffset, yOffset, this); // "this" representa al applet } ...............

!l problema con las im%genes es asegurarse que /ue cargada antes de mostrarla Para eso se utiliza un ?edia6rac^er +tambin deber'a servir para los arc$ivos de audio, pero en esta versin a9n no est% implementado, ?ediante addImage+ imagen, grupo, se agrega una imagen a la lista del ?edia6rac^er, y $ay mtodos para esperar que sea cargada +como "ait>orAll+, o "ait>orI5+grupo,,, para veri/icar que se $aya cargado correctamente +como c$ec^All+,, c$ec^I5+grupo,, is!rrorAny+, ,, etctera !l siguiente applet utiliza estos conceptos para cargar una imagen y un arc$ivo de audio y mostrarlos// Ejemplo24.java import java.awt.*; import java.applet.*; public class Ejemplo24 extends Applet { MediaTracker supervisor; String archImagen, archAudio; Image imagen; AudioClip audio; Label titulo; Panel cuadro; public void init() { supervisor = new MediaTracker(this); archImagen = "javacero.gif"; archAudio = "tada.au"; // carga imagen

imagen = getImage(getDocumentBase(), archImagen); supervisor.addImage(imagen,0); try { supervisor.waitForID(0); // espero quese cargue } catch (InterruptedException e) { System.out.println("Error cargando imagen!"); } showStatus("Imagen cargada"); // carga sonido audio = getAudioClip(getDocumentBase(), archAudio); // arma layout setLayout(new BorderLayout()); titulo = new Label(archImagen); setFont(new Font("helvetica", Font.BOLD, 18)); add("South", titulo); } public void start() { repaint(); audio.play(); } public void paint(Graphics g) { if (supervisor.isErrorAny()) { g.setColor(Color.black); g.fillRect(0, 0, size().width, size().height); return; } g.drawImage(imagen, 0, 0, this);

} }

Para visualizarlo, como siempre, creamos un F6?&<HTML> <HEAD> <TITLE>Ejemplo 24 - Ejemplo Multimedia</TITLE> </HEAD> <BODY> <applet code="Ejemplo24.class" width=150 height=200> </applet> </BODY> </HTML>

Parametrizando un applet Vamos a aprovec$ar este ejemplo, modi/ic%ndolo un poco para indicarle desde el F6?& qu arc$ivos debe cargar, mediante par%metros )uestro F6?& modi/icado ser%<HTML> <HEAD> <TITLE>Ejemplo 24 - Multimedia</TITLE> </HEAD> <BODY> <applet code="Ejemplo24.class" width=150 height=200> <param name="imagen" value="javacero.gif"> <param name="sonido" value="tada.au"> </applet> </BODY> </HTML>

Para leer estos par%metros desde el applet, usamos el mtodo getParameter+nombrePar%metro,, as' que podemos modi/icar nuestro applet simplemente modi/icando un par de l'neas-

archImagen = getParameter("imagen"); archAudio = getParameter("sonido");

Voil%; Pueden probar de cargar este applet en $ttp-DD""" amarillas comDroc^DjavaD!jemploEA $tm 5e esta manera podemos pasar cualquier valor como par%metro para un applet, $acindolo m%s /le<ible W esto es todo por $oy; Con esto $emos visto una gran parte de lo que es Java )o $emos pro/undizado demasiado en cada punto, pero $emos $ec$o ejemplos que /uncionan para ilustrar cada cosa #in embargo, $emos dejado un punto importante y muy /uerte de Java, que es el de las comunicaciones entre aplicaciones y, especialmente, el uso de soc^ets y la programacin de aplicaciones cliente0servidor Paseando por la Hed !s muy sencillo acceder a arc$ivos en la red utilizando Java !l paquete java net dispone de varias clases e inter/ases a tal e/ecto !n primer lugar, la clase 8H& nos permite de/inir un recurso en la red de varias maneras, por ejemploURL url1 = new URL ("http://www.rockar.com.ar/index.html"); URL url2 = new URL ("http", "www.rockar.com.ar", "sbits.htm");

Por otra parte, podemos establecer una cone<in a un 8H& dado mediante openConnectionURLConnection conexion = url.openConnection();

8na vez lograda la cone<in, podemos leer y escribir datos utilizando streams +corrientes de datos,, como en el caso de manejo de arc$ivos comunes +ver cap'tulo M, 8n 5ataInput#tream nos permite leer datos que llegan a travs de la red, y un 5ata1utput#tream nos permite enviar datos al $ost Por ejemploDataInputStream datos = new DataInputStream( corrienteEntrada );

!n nuestro caso, la corriente de entrada de datos proviene de la cone<in al 8H& !l mtodo getInput#tream+, del objeto 8H&Connection nos provee tal corrienteDataInputStream datos = new DataInputStream(conex.getInputStream())

5e este modo podemos escribir un pequeGo programa para, por ejemplo, leer una p%gina F6?& desde una direccin arbitraria de internet !l programa, luego de compilarse mediante javac !jemploEC java, se ejecuta con java !jemploEC PurlQ= por ejemplo- java !jemploEC $ttp-DD""" roc^ar com arDinde< $tml
import java.io.*; import java.net.*; public class Ejemplo25 { public static void main(String argv[]) { String s; try { URL url = new URL (argv[0]); URLConnection conex = url.openConnection(); System.out.println("Cargando "+argv[0]); DataInputStream datos = new DataInputStream(conex.getInputStream()); do { s = datos.readLine(); if (s != null) System.out.println(s); } while (s != null); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Sintaxis: java Ejemplo25 <url>"); } catch (UnknownHostException e) { System.out.println("El host no existe o no responde"); } catch (Exception e) { e.printStackTrace(); } }

!ste programa muestra el F6?& como te<to en la pantalla, pero podr'amos grabarlo a un arc$ivo para guardarlo Inclusive, podr'amos procesarlo a medida que lo recibimos, identi/icar los tags PA FH!>OurlQ, guardarlos en un vector, y seguidamente conectarnos y bajar los lin^s que /iguran en la p%gina original $asta bajar un site completo )oten que esto no slo sirve para establecer cone<iones a p%ginas F6?& !n realidad, un 8H& puede re/erirse tambin a otros protocolos, como gop$er, /tp, etctera= si bien seg9n la implementacin de Java puede $aber problemas para conectarse a algunos tipos de 8H& Para ver los tipos de 8H& posibles les recomiendo leer la p%gina$ttp-DD""" ncsa uiuc eduDdemo"ebDurl0primer $tml &os #oc^ets &os soc^ets +zcalos, re/erido a los enc$u/es de cone<in de cables, son mecanismos de comunicacin entre programas a travs de una red 6CPDIP 5e $ec$o, al establecer una cone<in via Internet estamos utilizando soc^ets- los soc^ets realizan la inter/ase entre la aplicacin y el protocolo 6CPDIP 5ic$os mecanismos pueden tener lugar dentro de la misma m%quina o a travs de una red #e usan en /orma cliente0servidor- cuando un cliente y un servidor establecen una cone<in, lo $acen a travs de un soc^et Java proporciona para esto las clases #erver#oc^et y #oc^et &os soc^ets tienen asociado un port +puerto, !n general, las cone<iones via internet pueden establecer un puerto particular +por ejemplo, en $ttp-DD""" roc^ar com ar-LKDinde< $tml el puerto es el LK, !sto casi nunca se especi/ica porque ya $ay de/inidos puertos por de/ecto para distintos protocolos- EK para /tp0data, EJ para /tp, _B para /inger, etc Algunos servers pueden de/inir otros puertos, e inclusive pueden utilizarse puertos disponibles para establecer cone<iones especiales Justamente, una de las /ormas de crear un objeto de la clase 8H& permite especi/icar tambin el puertoURL url3 = new URL ("http", "www.rockar.com.ar", 80,"sbits.htm");

Para establecer una cone<in a travs de un soc^et, tenemos que programar por un lado el servidor y por otro los clientes !n el servidor, creamos un objeto de la clase #erver#oc^et y luego esperamos alg9n cliente +de clase #oc^et, mediante el mtodo accept+,ServerSocket conexion = new ServerSocket(5000); // 5000 es el puerto en este caso

Socket cliente = conexion.accept(); // espero al cliente

5esde el punto de vista del cliente, necesitamos un #oc^et al que le indiquemos la direccin del servidor y el n9mero de puerto a usarSocket conexion = new Socket ( direccion, 5000 );

8na vez establecida la cone<in, podemos intercambiar datos usando streams como en el ejemplo anterior Como la clase 8H&Connection, la clase #oc^et dispone de mtodos getInput#tream y get1utput#tream que nos dan respectivamente un Input#tream y un 1utput#tream a travs de los cuales trans/erir los datos 8n servidor atento Vamos a crear un servidor !jemploE@a java +que podemos correr en una ventana, que atender% a un cliente de la misma m%quina +lo vamos a correr en otra ventana, Para $acerlo simple, el servidor slo le enviar% un mensaje al cliente y ste terminar% la cone<in !l servidor quedar% entonces disponible para otro cliente !s importante notar que, para que el soc^et /uncione, los servicios 6CPDIP deben estar activos +aunque ambos programas corran en la misma m%quina, &os usuarios de *indo"s aseg9rense que $aya una cone<in 6CPDIP activa, ya sea a una red local o a Internet !l servidor correr% 2para siempre2, as' que para detenerlo presionen control0C
// servidor import java.io.*; import java.net.*; public class Ejemplo26a { public static void main(String argv[]) { ServerSocket servidor; Socket cliente; int numCliente = 0; try { servidor = new ServerSocket(5000); do { numCliente++;

cliente = servidor.accept(); System.out.println("Llega el cliente "+numCliente); PrintStream ps = new PrintStream(cliente.getOutputStream()); ps.println("Usted es mi cliente "+numCliente); cliente.close(); } while (true); } catch (Exception e) { e.printStackTrace(); } } }

8tilizamos un Print#tream para enviar los datos al cliente, ya que es sencillo de utilizar para mandar #trings !l mtodo Print#tream println maneja los datos como #ystem out println, simplemente $ay que indicarle el stream a travs del cual mandarlos al crearlo +en este caso, el 1utput#tream del cliente, que obtenemos con cliente get1utput#tream+,, !l cliente satis/ec$o A$ora vamos a crear la clase cliente, !jemploE@b java !l cliente simplemente establece la cone<in, lee a travs de un 5ataInput#tream +mediante el mtodo read&ine+,, lo que el servidor le manda, lo muestra y corta
// cliente: import java.io.*; import java.net.*; http://www.cybercursos.net Pgina 89 public class Ejemplo26b { public static void main(String argv[]) { InetAddress direccion;

Socket servidor; int numCliente = 0; try { direccion = InetAddress.getLocalHost(); // direccion local servidor = new Socket(direccion, 5000); DataInputStream datos = new DataInputStream(servidor.getInputStream()); System.out.println( datos.readLine() ); servidor.close(); } catch (Exception e) { e.printStackTrace(); } } }

Para probar esto, aseg9rense que los servicios 6CPDIP estn activos, corran java !jemploE@a en una ventana y corran varias veces java !jemploE@b en otra &as salidas ser%n m%s o menos as'Ventana servidorC-NjavaNcursoQjava !jemploE@a &lega el cliente J &lega el cliente E &lega el cliente T +00000 cortar con control0C 00000, Ventana clienteC-NjavaNcursoQjava !jemploE@b 8sted es mi cliente J C-NjavaNcursoQjava !jemploE@b

8sted es mi cliente E C-NjavaNcursoQjava !jemploE@b 8sted es mi cliente T +00000 aqu' cerramos el servidor 00000, C-NjavaNcursoQjava !jemploE@b java net #oc^et!<ception- connect at java net Plain#oc^etImpl doConnect+Plain#oc^etImpl java-EET, at java net Plain#oc^etImpl connect6oAddress+Plain#oc^etImpl java-JEL, at java net Plain#oc^etImpl connect+Plain#oc^etImpl java-JJC, at java net #oc^et PinitQ+#oc^et java-JEC, at java net #oc^et PinitQ+#oc^et java-JKJ, at !jemploE@b main+!jemploE@b java-JE, !sto es todo por a$ora !l ejemplo /ue lo m%s sencillo posible, pero mediante el mismo mtodo el servidor y los clientes pueden intercambiar datos escribiendo en ambas direcciones Inclusive, el servidor puede correr en una m%quina y los clientes en otras= adem%s, si bien en este caso utilizamos aplicaciones standalone, se pueden utilizar applets Por ejemplo, una aplicacin servidora puede correr constantemente en un server de Internet +por ejemplo, para buscar datos en una base de datos, y di/erentes clientes en distintas m%quinas, posioblemente applets Java, pueden conectarse a ella y consultarla