Anda di halaman 1dari 94

Derechos Reservados

HolaMundo.java
Ing. Pablo Augusto Sznajdleder

Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)


Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
1. INTRODUCCION

Que es exactamente Java ?

Simple
Orientado a Objetos
Distribuido
Interpretado
Robusto
Seguro
Multiplataforma
Portable
Multithreaded

Java es un lenguaje de programacin orientado a objetos cuya sintaxis es muy similar a la del lenguaje de
programacin C++. Es un lenguaje fuertemente tipado, sensitivo a maysculas y minsculas, etc.
La similitud con el lenguaje C hace que los programadores con conocimientos previos de C se sientan
familiarizados con el cdigo fuente. Pero Java es un lenguaje mucho mas simple que C y C++.
Para comenzar, en Java no existe la aritmtica de punteros de C. No es que en Java no existan los
punteros. Justamente todo lo contrario: todos los objetos en Java son punteros (o referencias) y como
todos los objetos son punteros no es necesario definirlos explcitamente (por ejemplo con * como en C)
logrando as un cdigo muy claro, prolijo y transparente (y sin los temidos asteriscos de C y C++).

Java proporciona las herramientas necesarias para programar orientado a objetos: encapsulamiento de
datos, sobrecarga de funciones, herencia y polimorfismo. Tiene un extenso rbol de clases que abarcan
desde manejo de cadenas de caracteres (String) hasta procesamiento distribuido, serializacin de objetos,
acceso a bases de datos, etc. Todo en Java son clases y objetos (excepto las variables de tipos de datos
primarios short, int, long, byte, char, float, double, boolean y las palabras reservadas).

La caracterstica mas importante de Java es ser un lenguaje multiplataforma, definiendo plataforma


como la suma del hardware mas el sistema operativo. As, una aplicacin Java puede correr (sin tener
siquiera que recompilarse) en plataformas como Ultra+Solaris, Intel+Windows95/NT, Intel+Linux,
Macintoch+MacOS, etc.

La multiplataforma se logra mediante la Maquina Virtual Java o JVM. La maquina virtual es quien,
partiendo de las complejidades propias de cada plataforma (set de instrucciones, registros, etc.) lleva a
todas las plataformas a una complejidad homognea sobre la cual los programas Java son ejecutados.
Es decir para poder ejecutar una aplicacin Java es necesario disponer de una JVM. Los sistemas
operativos modernos (Solaris, Linux, entre otros) traen incorporada la JVM como parte de lo que se llama
el Java Runtime Enviroment o JRE. Para los sistemas operativos que no lo tengan preinstalado, el JRE
puede bajarse gratuitamente desde la direccin http://java.sun.com e instalarse como cualquier aplicacin.

Otra caracterstica de Java (quiz la mas popular en los comienzos) es la posibilidad de desarrollar
Applets. Un applet es un programa Java que es ejecutado dentro de un navegador y distribuido on-
demand a travs de un web-server.
La posibilidad de tener programas completos, distribuidos on-demand y ejecutndose absolutamente en
la maquina del cliente potencializ el modelo webtop, ampliamente ventajoso respecto del modelo

1
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
descktop ya que en tal modelo se minimizan los costos de mantenimiento de soft, de hard, de datos y de
instalacin, as como los costos de licenciamiento y de distribucin.
En el caso de los applets la JVM es implementada por el navegador. As, el cliente no necesita
preocuparse por nada. Simplemente teniendo el navegador en su computadora ya esta habilitado para
acceder a paginas web que contengan applets.

Java implementa una serie de chequeos tanto en tiempo de compilacin como en tiempo de ejecucin que
facilitan al programador la tarea de depurar errores de lgica y le evitan cometer bugs, que por su
naturaleza seran muy difciles de depurar. A continuacin veremos un cuadro comparativo entre C y Java
en el que se exponen algunas situaciones habituales y muy desagradables para los programadores C.

En C los enteros tienen


valor booleano. Esto Existe el tipo de
C o C++ es ambiguo. Java datos boolean
int fin=0; boolean fin=false;
while ( !fin ) { ... } while ( !fin ) { ... }

C o C++ Error de lgica. Primero Java


La expresin a=5 es una
int a=4; asigna a=5 y luego evala int a=4 asignacin que no tiene
: el valor booleano del : valor booleano sino entero.
if( a=5 ) { ... } entero a. Como a vale 5 y if( a=5 ) { ... } Como el if() espera una
5 es distinto de 0 entonces expresin booleana se
la expresin anterior es genera un error en tiempo
siempre verdadera. de compilacin.

Otro ejemplo muy buen ejemplo es el recolector de residuos o Garbage Collector. el GC es un proceso
que dispara la JVM y se ocupa de revisar el estado de asignacin de memoria buscando bloques de
memoria desreferenciados. Cuando encuentra un bloque que no esta siendo referenciado por ningn
puntero simplemente lo libera.
En otros lenguajes el programador debe estar muy atento para ver en que situaciones puede estar dejando
memoria desreferenciada y entonces liberarla explcitamente. Por ejemplo en C usando la funcin free().

2
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
LA PLATAFORMA DE INTERNET

Las aplicaciones para Internet, por su naturaleza requieren una plataforma pensada en niveles o capas
como se ilustra en el siguiente grfico.

En la capa cliente el browser juega el papel principal. En la mayora de los casos la interface grfica o
front-end de las aplicaciones esta basada en HTML o Applets y es bajada o distribuida en el
momento en que el usuario enva el requerimiento. Las aplicaciones que requieren interfaces mas
complejas pueden desarrollarse e instalarse en el cliente independientemente del browser.

La capa del servidor de presentacin consiste en un web-server que maneja requerimientos HTTP y
genera dinmicamente cdigo de presentacin para ser visualizado en el cliente.

Los servidores de aplicacin son quienes albergan lgica de negocios, la que idealmente puede ser
reutilizada en diferentes clientes y aplicaciones. La lgica de negocios debe ser accesible desde clientes y
servidores para facilitar la integracin de aplicaciones. La capa se aplicacin tambin se encargar de
generar informes y anlisis de tipo gerencial.

Finalmente la capa de datos contiene bases de datos escalables, capaces de almacenar, manipular,
retribuir y analizar los requerimientos de las aplicaciones de Internet. Esta capa tambin puede contener
fuentes de datos externas como middle-wears, etc.

3
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
El modelo multicapa descripto anteriormente se ajusta a la especificacin Java2, Enterprise Edition
Application Programming Model propuesto por Sun Microsystems en http://java.sun.com/j2ee/apm/

Las interfaces HTML son generadas dinmicamente por los web-servers usando Java Server Pages (JSP)
y Servlets. Puede incrementarse la funcionalidad y la productividad ensamblando libreras reusables de
JavaBeans. Los clientes 100% puro Java pueden desarrollarse como applets, como aplicaciones o como
applets que puedan correr a su vez como aplicaciones independientes del browser.

Los application servers habilitados con Java contienen componentes de negocios distribuidos y reusables
tanto CORBA como EJB. Los componentes de negocios tpicamente encapsulan la datos y servicios e
interactuan con la persistencia de los mismos accediendo a las bases de datos va JDBC.

4
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
2. Hola Mundo !!!
Toda aplicacin Java es una clase. Cada clase
HolaMundo.java debe almacenarse en un archivo con extensin
.java y con el mismo nombre que la clase.
As, la clase HolaMundo debe estar en el
public class HolaMundo
archivo HolaMundo.java
{
public static void main(String args[])
{
System.out.println( HOLA MUNDO !!! );
}
}

Como podemos ver (al igual que en C) todo bloque de cdigo se delimita con { ... }. Al finalizar cada
instruccin se debe finalizar la lnea con ;
Estos trminos los analizaremos
cuando expliquemos los conceptos
 public Alcance del mtodo main(). de programacin orientada a
objetos.
 static Mtodo esttico o mtodo de la clase.
 void Tipo de dato del valor de retorno.
 String args[] Argumentos en lnea de comandos.

COMPILACION Y CORRIDA
Se deben respetar en todo momento las
maysculas y minsculas. Tanto en el
c:\> javac HolaMundo.java cdigo fuente como en el nombre del
c:\> java HolaMundo archivo, en la compilacin y en la
HOLA MUNDO !!! ejecucin.
c:\>

5
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
JEcho.java Programa que recibe
argumentos en lnea de
public class JEcho comandos y los escribe en la
{ standar output.
public static void main(String args[])
{
for( int i=0; i<args.length; i++ )
{
System.out.println( args[i] );
}
}
}

Los arrays tienen la propiedad length.


En el caso de args.length indica la cantidad de argumentos
que fueron pasados en lnea de comandos.

COMPILACION Y CORRIDA

c:\> javac JEcho.java


c:\> java JEcho uno dos tres cuatro cinco
uno
dos
tres cuatro
cinco
c:\>

6
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
A continuacin vemos la lista de palabras reservadas del lenguaje.

PALABRAS RESERVADAS
abstract do implements private throw
boolean double import protected throws
break else instanceof public transient
byte extends int return true
case false interface short try
catch final long static void
char finally native super while
class float new switch
continue for null synchronized
default if package this

las palabras reservadas se escriben en


minscula

La siguiente tabla indica la cantidad de bits que son asignados a las variables de cada tipo de datos. Dado
que los programas Java corren sobre la JVM estas longitudes son vlidas para todas las plataformas en las
que se implemente la maquina virtual. En C (por ejemplo) las longitudes dependen de la plataforma.

Enteros Longitud (bits) Sg. Rango


byte 8 X -27 ... +27-1
char 16 0 ... +216-1
short 16 X -215 ... +215-1
int 32 X -231 ... +231-1
long 64 X -263 ... +263-1

Flotantes Longitud (bits)


float 32
double 64

7
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Estructuras de Repeticin Como podemos ver, las estructuras de
control tanto de repeticin como de
decisin son las idnticas a las de C.
while( condicin ) do
{ {
: :
} } while( condicin )

for( int i=0 ; condicin ; i++ )


{
:
}

Estructuras de Decisin Igual que en C, los


break son necesarios al
finalizar cada case para
if( condicin ) switch( variable ) evitar que se pase al
{ { siguiente case.
: case c1:
} :
else break;
{ case c2:
: :
} break;
case cn:
:
break;
default:
:
break;
}

8
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
3. PROGRAMACION ORIENTADA A OBJETOS

Java es un lenguaje de programacin orientado a objetos. Dominar la teora de objetos no solo es


necesario para desarrollar nuestras propias aplicaciones sino tambin para poder entender, utilizar y
aprovechar al mximo las clases propias de Java.

Para entender los conceptos de la teora de objetos plantearemos una serie de ejemplos que iremos
desarrollando progresivamente.

ENCAPSULAMIENTO

Supongamos que tenemos que desarrollar una aplicacin para manejar nmeros complejos. Si pensamos
en programacin estructurada estaremos pensando en una estructura (struct de C o record de Pascal)
como la siguiente:

struct Complejo
{
int r; // componente real del numero complejo.
int i; // componente imaginario.
}

Una funcin main() que utilize esta estructura ser:

main( )
{
Complejo c;

c.r = 10; // asigno 10 al componente real


c.i = 3; // asigno 3 al componente imaginario

imprimir( c ); // imprimo por pantalla el numero complejo c


}

Lo anterior implica un doble problema para el programador de la funcin main(). Por un lado el problema
propio de manipular los nmeros complejos (su verdadero problema) pero por otro lado el programador
tiene que conocer de antemano como estn definidas las variables de la estructura complejo que
representan las componentes real e imaginaria. En este caso las variables son r e i respectivamente.

Este es uno de los vicios de la programacin estructurada. No permite al programador realizar


operaciones conceptuales y abstraerse de las cuestiones de implementacin.

Si en lugar de pensar la estructura complejo como struct Complejo la pensamos como class Complejo:

class Complejo
{
private int r; // componente real del numero complejo.
private int i; // componente imaginario.
}

las asignaciones c.r = 10 y c.i = 3 son incorrectas ya que las clases (por definicin) proveen
encapsulamiento para sus datos. Decimos entonces que los datos de la clase Complejo estn
encapsulados y la nica forma de accederlos es a travs de funciones que la misma clase provea.

9
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Entonces podemos decir que una clase es una estructura que combina datos con las funciones necesarias
para manipularlos. Llamamos Objeto a toda variable cuyo tipo de datos es una clase.

 Resumiendo
 Clase: estructura que combina datos con las funciones (o mtodos) necesarias para
accederlos.
 Objeto: variable cuyo tipo de datos es una clase.

La idea es que el usuario (en este caso el programador que utiliza la clase Complejo) no tenga que
preocuparse por la complejidad propia de la clase.
Las asignaciones anteriores implican conocer de antemano que los datos se almacenan en variables
llamadas r e i. Esto nos hace entrar en complejidades ajenas a nuestra incumbencia.

En programacin orientada a objetos la misma clase tiene que proveer los mtodos necesarios para
acceder a los datos; mtodos para asignar valor a los datos, para consultar el valor de los datos y para
efectuar operaciones entre los datos.

class Complejo
{
private int r; Atributos del nmero complejo. Como veremos
private int i; mas adelante tambin se dice que son variables de
instancia.
public void setReal(int re)
{
r = re; Una buena prctica es definir para
} cada dato (o atributo)
un mtodo set y un mtodo get.
public void setImag( int im)
{
i = im;
}

public int getReal()


{
return r;
}
public int getImag()
{
return i;
}

public void imprimir( )


{
System.out.println(Real=+ r + Imaginario=+ i );
}
}

Con este nuevo esquema, la funcin main() queda como sigue:

10
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
main( )
{
Complejo c = new Complejo( );
c.setReal(10); // asigno 10 al componente real
c.setImag(3); // asigno 3 al componente imaginario
c.imprimir( ); // imprimo por pantalla el numero complejo c
System.out.println( La componente real es=+c.getReal());
}

Un objeto en Java en realidad es un puntero a un rea de memoria, por lo tanto es necesario asignarle una
direccin vlida. Para esto utilizamos el operador new.
El operador new recibe como argumento el constructor de la clase. El constructor de la clase es un mtodo
ms pero que es llamado automticamente al momento de asignar memoria al objeto.
Toda clase tiene al menos un constructor. Si no lo programamos explcitamente, igual existe un
constructor nulo por default.

El constructor, para ser reconocido como tal debe llamarse exactamente igual que la clase y no debe
tener valor de retorno (ni siquiera void).

class Complejo El constructor Se llama igual que la clase y


{
no tiene valor de retorno
private int r;
private int i;

public Complejo( int re, int im )


{
r = re;
i = im;
}
:
:
}

pero como la clase Complejo tiene los mtodos setReal() y setImag() que se ocupan de realizar las
asignaciones, el constructor quedara mejor programado de la siguiente forma:

public Complejo( int re, int im )


{
setReal( re );
setImag( im );
}

y ahora la funcin main() ser:

main( )
{
Complejo c =new Complejo (10,3);
c.imprimir( );
}

11
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
SOBRECARGA

Supongamos que nuestra clase Complejo quedo terminada y esta en produccin. Muchas aplicaciones la
utilizan y no se registr ningn tipo de problema. Pero ahora surge la necesidad de que las aplicaciones
puedan construir nmeros complejos expresndolos como suma de sus componentes. Por ejemplo el
nmero complejo (10,3) = 10+3i. Cualquiera de las dos expresiones representan al mismo nmero
complejo. La sobrecarga permite agregar funcionalidad a la clase sin correr el riesgo de alterar lo que ya
esta funcionando sin problemas.

Sobrecargar un mtodo simplemente es escribirlo dos o mas veces (en la misma clase) pero con diferentes
prototipos y por supuesto diferentes cuerpos.

class Complejo
{
int r; El constructor esta sobrecargado: el primero
int i; recibe dos enteros. El segundo recibe un
String.
public Complejo( int re, int im )
{
setReal( re );
setImag( im );
}

public Complejo( String s )


{
setReal( s );
setImag( s );
}

:
:
}

En el ejemplo adems de sobrecargar el constructor se asume que los mtodos setReal() y setImag() estn
sobrecargados tambin. En el primer constructor se los invoca con un argumento de tipo int, mientras que
en el segundo con uno de tipo String.

La sobrecarga de setReal( ) ser:

public void setReal(String s)


{
int posmas = s.indexOf(+); una vez que tenemos el valor real como
String aux = s.substring( 0, posmas ); entero (variable valreal) podemos llamar
int valreal= Integer.toString( aux ); a la otra versin del mtodo setReal()
setReal( valreal ); para se termine el trabajo (asignar el
} valor en la variable r.

Notemos que el argumento s es de tipo String, y String es una clase. Por lo tanto decimos que s es un
objeto String y como tal tiene los mtodos necesarios para asignar, retribuir, y manipular su valor.

Un tratamiento de cadena anlogo ser necesario para la sobrecarga de setImag( ).

12
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
public void setImag(String s)
{
int posmas = s.indexOf(+);
String aux = s.substring( posmas+1, s.length()-1 );
int valimag = Integer.toString( aux );
setImag( valimag );
}

La versin final de la clase Complejo se muestra a continuacin.

Complejo.java

public class Complejo


{
private int real;
private int imaginario;

public Complejo(int r, int i)


{
setReal(r);
setImaginario(i);
}

public Complejo(String c)
{
setReal(c);
setImaginario(c);
}

public void setReal(int r)


{
real=r;
}

public void setReal(String s)


{
int posmas=s.indexOf('+');
String sr=s.substring(0,posmas);
int vr=Integer.parseInt(sr);
setReal(vr);
}

public void setImaginario(int i)


{
imaginario=i;
}

13
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
public void setImaginario(String s)
{
int posmas=s.indexOf('+');
String si=s.substring(posmas+1,s.length()-1);
int vi=Integer.parseInt(si);
setImaginario(vi);
}

public void imprimir()


{
System.out.println( real + + + imaginario + i );
}

public static void main(String args[])


{
Complejo c1,c2;
c1=new Complejo(10,3);
c2=new Complejo(4+5i);

c1.imprimir();
c2.imprimir();
}
}

API java.lang.String

public int indexOf(int caract)


public String substring(int desde, int hasta)

POLIMORFISMO

Vamos a explicar ahora el concepto mas importante del paradigma de objetos. Polimorfismo es el ncleo
de la teora de objetos y su comprensin resulta fundamental para encarar cualquier desarrollo.
Si este concepto no se logra comprender en su totalidad, todo lo dems (herencia, sobreescritura, clases
abstractas, etc. ) resultar anecdticos y carente de potencial.

14
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Supongamos que tenemos que realizar una aplicacin para el rea de RRHH de una empresa. Luego del
un anlisis decidimos disear la clase Empleado.

public class Empleado


{
private int leg; // legajo del empleado
private String nom; // nombre del empleado

public Empleado(int l, String n) // Constructor


{
leg = l;
nom = n;
}

public void imprimir( )


{
System.out.println(Legajo= + leg + Nombre= + nom);
}
}

Una funcin main() que utilice la clase Empleado ser:

main( )
{
Empleado e =new Empleado( 1010, Pedro Gomez );
e.imprimir( );
}

Siguiendo con el anlisis nos encontramos con un gerente. Es obvio que un gerente tiene los mismos
atributos que un empleado (legajo, nombre) y otros propios que lo caracterizan como tal. Por ejemplo un
Sector a Cargo.
Podemos decir entonces que un Gerente es un Empleado y por lo tanto tiene las mismas caractersticas.
La clase Gerente debe heredar las propiedades de la clase Empleado.

public class Gerente extends Empleado


{
private int sac; // sac = Sector a Cargo

public Gerente( int l, String n, int s )


{
super( l, n ); // invoca al constructor del padre (constructor de Empleado)
sac = s;
}
}

La funcin main() puede ser ahora:

main( )
{
Empleado e = new Empleado( 1010, Pedro Gomez);
Gerente g = new Gerente ( 1515, Pablo Perez, 20 );

e.imprimir( );
g.imprimir( );
}

15
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
En la funcin main() el objeto g (o la instancia g de la clase Gerente) utiliza el mtodo imprimir() que
hereda de la clase base Empleado. El problema es que el mtodo imprimir() que Gerente hereda no se
adapta por completo a las caractersticas de la clase. Digamos que le queda chico, ya que solo imprime
los datos propios de un empleado (legajo y nombre) y no tiene en cuenta los datos del gerente como ser
sac (sector a cargo).

La solucin es redefinir el mtodo imprimir() en la clase Gerente para que se adapte a los requerimientos
de la clase. En este caso decimos que sobreescribimos el mtodo imprimir().

public class Gerente extends Empleado Sobreescribir un mtodo es


{ escribirlo mas de una vez a lo
private int sac // sac = Sector a Cargo largo de una cadena de
herencia, pero respetando su
: prototipo (mismos argumentos,
public void imprimir( ) mismo valor de retorno).
{
super.imprimir( ); // llamo al imprimir del padre
System.out.println(Sector a cargo= + sac);
}
:
}

Notemos que la primera lnea del mtodo imprimir() de la clase Gerente llama a super.imprimir()
(mtodo de la clase base). Es decir que en imprimir() de Gerente solo tenemos que hacer el trabajo propio
para la impresin de los datos del gerente. La responsabilidad de la impresin los datos heredados queda
por cuenta del mtodo imprimir() del padre (Empleado).

Ahora si, en la funcin main() la sentencia g.imprimir() dar como salida:

Legajo=1515 Nombre=Pablo Perez


Sector a cargo=20

Seamos ahora un poco mas exigentes con la clase Gerente. Un gerente seguramente tendr gente a su
cargo. Podra ser muy til que el mtodo imprimir() de Gerente no solo imprima los datos del gerente,
sino tambin los datos de toda la gente a su cargo.

Para esto vamos a modificar la clase Gerente agregndole una estructura capaz de almacenar un conjunto
de empleados y un mtodo que permita agregar empleados a dicha estructura.

16
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
import java.util.Vector;

public class Gerente extends Empleado


{
private int sac // sac = Sector a Cargo
private Vector lga // lga = Lista de Gente a Cargo

public Gerente( int l, String n, int s )


{
super( l, n );
sac = s;
lga = new Vector( ); // luego de contruir el Gerente, se le podran agregar Empleados
}

public void ponerACargo(Empleado e)


{
lga.addElement( e );
}
:
}

Ahora en la funcin main() podemos hacer que un gerente est a cargo de un empleado.

main( )
{
Empleado e = new Empleado(1010, Mariano Chimiel);
Gerente g = new Gerente(2020, Gerardo Gebel);

g.ponerACargo( e );
}

El siguiente paso es modificar el mtodo imprimir() de la clase Gerente imprima la ficha de cada uno de
los empleados que el gerente tiene a su cargo.

public void imprimir( )


{
super.imprimir( );
System.out.println(Sector a cargo= + sac);

for( int i = 0; i < lga.size( ); i ++ )


{
( (Empleado) lga.elementAt( i ) ).imprimir( );
}
} casteamos a Empleado

Notemos que es necesario castear a Empleado el resultado del mtodo elementAt() del vector lga. Este
mtodo retorna una instancia (cuyo tipo es Object, no Empleado). Debemos notar tambin que el mtodo
addElement() en realidad espera un tipo de datos Object, no un Empleado. Sin embargo nosotros le
pasamos una instancia de Empleado y esto no es un error. En Java todas las clases heredan (o son
subclases) de la clase (base) Object.

En nuestro ejemplo: Gerente extends Empleado (Gerente es Empleado) y Empleado extends Object
(Empleado es Object) por lo tanto Gerente es Object.

Se dice entonces que Empleado matchea contra Object y puede utilizarse como argumento del mtodo.
Cuando invocamos el mtodo elementAt() y pretendemos que el vector nos devuelva los datos que le
ingresamos, resulta que dicho mtodo tiene como valor de retorno un Object y la clase Object no tiene
17
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
ningn mtodo llamado imprimir(). Casteando a Empleado podemos decir que recuperamos el objeto de
tipo Empleado que originalmente ingresamos en el vector mediante la funcin addElement().
Es muy importante comprender que gerente es un empleado y que un empleado es un object, por lo que
un gerente es un object.

Desarrollemos ahora una funcin main() completa para analizar la salida.

main( )
{
Empleado e1,e2,e3;
Gerente g1,g2;

e1 = new Empleado( 1010, Diego );


e2 = new Empleado( 1020, Christian );
e3 = new Empleado( 1030, Javier );

g1 = new Gerente( 5010, Pablo, 5 );


g2 = new Gerente( 5020, Augusto, 10 );

g1.ponerACargo( e1 );
g1.ponerACargo( e2 );
g2.ponerACargo( e3 );
g1.ponerACargo( g2 ); // recordemos que g2 es tambin un empleado

g1.imprimir( ); // ver anlisis


}

Analicemos la funcin imprimir:

i Objeto Accin Resultado


0 e1 ( (Empleado) lga.elementAt( i ) ).imprimir( ); e1.imprimir( )
1 e2 ( (Empleado) lga.elementAt( i ) ).imprimir( ); e2.imprimir( )
2 g2 ( (Empleado) lga.elementAt( i ) ).imprimir( ); g2.imprimir( )

A simple vista parece haber un problema. En la vuelta i=2 el elemento almacenado en el vector es un
objeto Gerente, pero para imprimir estamos casteando a Empleado. La pregunta es la siguiente: Que
imprimir se le aplica a g2: el de Gerente o el de Empleado? La respuesta es por polimorfismo se
ejecuta el imprimir de Gerente.

Podemos decir entonces que cada objeto sabe a que clase pertenece y por lo tanto sabe que mtodos tiene
disponibles (antes de tener que recurrir a las que hereda de su padre). La necesidad de castear se debe a
que por tratarse de un lenguaje fuertemente tipado los tipos de datos deben ser bien conocidos de
antemano por el compilador y debemos asegurarle a este que el dato que estamos sacando del vector
(como Object), en realidad tiene el mtodo imprimir() que le estamos aplicando. Es decir: nos hacemos
responsables ante el compilador de que el mtodo imprimir() existe en la instancia g2 (y en todos los
objetos que iremos sacando del vector).

Es importante destacar que si la clase Object tuviera un mtodo imprimir() el casteo no sera necesario.
Podramos aplicarle libremente el este mtodo a los objetos almacenados en el vector teniendo la
seguridad de que el imprimir() llamado siempre ser el adecuado.

La versin completa de las clases Empleado, Gerente y una clase TestEmpleados estn a continuacin.

18
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Empleado.java
public class Empleado
{
private int leg;
private String nom;
public Empleado(int l,String n)
{
leg=l;
nom=n;
}
public void imprimir()
{
System.out.println("Legajo="+leg+" Nombre="+nom);
}
}

Gerente.java
import java.util.Vector;
public class Gerente extends Empleado {
private int sac;
private Vector lga;
public Gerente(int l,String n,int s) {
super(l,n);
sac=s;

lga=new Vector();
}
public void ponerACargo(Empleado e) {
lga.addElement(e);
}
public void imprimir()
{
super.imprimir();
System.out.println(Sector=+sac);
for(int i=0; i<lga.size(); i++ )
{
( (Empleado)lga.elementAt(i) ).imprimir();
}
}
}

19
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
API java.util.Vector

public object elementAt(int index)


public void addElement(Object elm)
public int size()

AppEmpleados.java

public class AppEmpleados


{
public static void main(String args[])
{
Empleado e1,e2,e3;
Gerente g1,g2;

e1=new Empleado(10,"Juan");
e2=new Empleado(11,"Pedro");
e3=new Empleado(12,"Jose");

g1=new Gerente(50,"Analia",1);
g2=new Gerente(51,"Martin",2);

g1.ponerACargo( e1 );
g1.ponerACargo( e2 );
g2.ponerACargo( e3 );

g1.ponerACargo( g2 );

g1.imprimir();
}
}

COMPILACION Y CORRIDA
c:\> javac *.java
c:\> java AppEmpleados
Legajo=50 Nombre=Analia
Sector=1
Legajo=10 Nombre=Juan
Legajo=11 Nombre=Pedro
Legajo=51 Nombre=Martin
Sector=2
Legajo=12 Nombre=Jose
c:\>

20
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
CONVENCIONES DE NOMENCLATURA

Si bien no es obligatorio, por cuestiones de convencin es aconsejable respetar una serie de reglas de
nomenclatura para las clases, los mtodos, variables, y constantes. Todas las clases de la librera Java
fueron escritas respetando esta convencin de forma que conocindola ya no tendremos que preocuparnos
por recordar (por ejemplo) cuales caracteres del nombre de una clase son mayscula y cuales minscula.

NOMENCLATURA

Clases
Siempre comienzan con Mayscula. Si el nombre se compone de varias palabras
entonces cada inicial debe ser en Mayscula.

public class NombreDeLaClase


{
}

Mtodos
Siempre comienzan con minscula. Si el nombre se compone de varias palabras
entonces cada inicial debe ser en Mayscula.

public void nombreDelMetodo()


{
}

Constantes
Completamente en Mayscula. Si el nombre se compone de varias palabras
entonces cada palabra se separa de la anterior por medio del carcter _

public static final int NOMBRE_DE_LA_CTE = 1;

Variables
Nunca deben comenzar en Mayscula. Puede utilizarse la misma nomenclatura
definida para los mtodos.

private String nombreDeLaVariable;

21
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Como comentamos en la introduccin, en Java todos los objetos son punteros o referencias a bloques de
memoria previamente alocada por medio del operador new.
Definamos la clase X (lase equis grande) para utilizarla en una secuencia de ejemplo.

Instancias Desreferenciadas GC

class X
{ Variables de
private int a; Instancia
private int b;

public X(int a, int b)


{
this.a=a;
this.b=b;
}
}
x1 apunta a un rea de memoria en el
sean x1 y x2 que se almacenan los valores de las
variables de instancia. Las variables
instancias de X de la instancia x1.
X x1,x2;
a b
x1=new X(10,3); x1
10 3
Idem. x2.

a b
x2=new X(4,8); x2
4 8

En el siguiente paso haremos la asignacin x2=new X(...) haciendo apuntar a x2 a una nueva instancia
dejando la anterior sin referenciar (en otras palabras: ningn puntero la esta apuntando).

a b Instancia
x2=new X(5,9); x2 Desreferenciada
4 8

a b
5 9

Ahora, como la instancia (4,8) esta desreferenciada ser eliminada automticamente por el Garbage
Collector.

Antes de probar lo anterior explicaremos brevemente otro concepto de la teora de objetos: las variables
y los mtodos de clase.

22
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Modificador Variable Mtodo
static Variable de clase Mtodo de clase

double pi = Math.PI int a = Integer.parseInt(10)

El modificador static aplicado a una variable la convierte en variable de la clase. Esto quiere decir que es
una variable cuyo valor ser compartido por todas las instancias. As, si una instancia modifica su valor
automticamente las dems instancias vern alterado el valor de la variable. Simplemente porque la
comparten.

El mismo modificador aplicado a mtodos los convierte en mtodos de la clase. Un mtodo de clase
puede aplicarse directamente sobre la clase, sin tener que generar una instancia para utilizarlo. Ejemplos
de mtodos de clase son Integer.parseInt(...), Math.pow(...), Thread.sleep(...), etc.

El siguiente es un ejemplo interesante. La clase TestGC tiene la variable de clase contador que al
momento de definirla se inicializa en 0. Luego, cada vez que la clase es intanciada (en el constructor) se
incrementa su valor y se imprime. Recordemos que por ser una variable de clase las instancias sucesivas
vern el valor incrementado.
En la clase TestGC se sobreescribe el mtodo public void finalize(). Este mtodo esta definido en la
clase base Object y es invocado automticamente por el Garbage Collector antes de destruir una instancia
desreferenciada.
En nuestro ejemplo, sobreescribimos el mtodo finalize() para detectar el momento en que la instancia
ser eliminada y entonces decrementamos el valor de contador.
El mtodo main() simplemente dispara instancias continuamente y no las mantiene referenciadas.
En otros lenguajes este programa terminara con un error de tipo out of memory. Sin embargo, como
Java cuenta con el Garbage Collector la memoria que esta sin referenciar es liberada automticamente y
as el programa puede correr sin generar ningn tipo de error.

TestGC.java

public class TestGC {


private static int contador=0;

public TestGC() {
contador++;
System.out.println(contador);
}
El mtodo finalize() es invocado
automticamente por el Garbage
public void finalize() { Colector antes de eliminar una instancia
contador--; desreferenciada.
}

public static void main(String args[]) {


while( true ) {
new TestGC();
}
}
}

23
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
CORRIDA

c:\> java TestGC


1
2
:
2993
2994
1
2
:

CLASES ABSTRACTAS

Vamos a explicar ahora el concepto de clases abstractas, otro de los conceptos de la teora de objetos que
se relaciona fuertemente con el polimorfismo.

Pensemos en una clase para manejar figuras geomtricas: si bien para toda figura geomtrica se puede
calcular su rea, resulta que es imposible calcular el rea de una figura geomtrica sin saber previamente
de que figura estamos hablando. No es lo mismo calcular el rea para un crculo que para un rectngulo.
As y todo, podemos definir la clase FigGeom con el mtodo rea() como mtodo abstracto. Entonces
las subclases de FigGeom (Circulo, Tringulo, Rectngulo, etc.) debern sobreescribir adecuadamente el
mtodo rea().

Como la clase FigGeom tiene al menos un mtodo abstracto debe ser declarada como clase abstracta. Una
clase abstracta no puede ser instanciada. Veamos el cdigo de la clase FigGeom.

FigGeom.java Los mtodos abstractos terminan


con ; . No se resuelven.
public abstract class FigGeom
{
public abstract double rea();

public void printArea()


{
System.out.println(Area= + rea() );
}
}

Como podemos ver, en el mtodo printArea() se llama al mtodo rea(). Esto puede resultar confuso por
ser rea() un mtodo abstracto. Pero como las clases abstractas no pueden ser instanciadas, resulta que el
mtodo printArea() solo ser aplicado a instancias de las subclases de FigGeom, las que ya
sobreescribieron el mtodo rea(). As, por polimorfismo la referencia al mtodo rea() ser sobre la
subclase y nunca sobre la clase FigGeom.

Veamos como las clase Circulo y Rectangulo resuelven el mtodo rea() de la forma mas conveniente.

24
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Circulo.java

public class Circulo extends FigGeom


{
private double radio;

public Circulo(double r)
{
radio=r;
}

public double rea()


{
return Math.PI * Math.pow(radio,2);
}
}

Rectangulo.java
public class Rectangulo extends FigGeom {
private double base,altura;

public Rectangulo(double b,h) {


base=b;
altura=h;
}

public double rea()


{
return base*altura;
}
}

Ahora, podemos pensar en una clase TestAbstract que haga uso de las clases Circulo y Rectangulo.

25
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
TestAbstract.java
public class TestAbstract {
public static void main(String args[]){
Circulo c=new Circulo(3);
Rectangulo r=new Rectangulo(5,2); Recordemos que printArea() llama a
rea(), pero como lo estamos
c.printArea(); invocando desde instancias de Circulo
r.printArea(); y Rectangulo , por polimorfismo se
invocara al mtodo area() de Circulo y
Rectangulo respectivamente.
FigGeom fg[]=new FigGeom[2]; Podemos decir entonces que cada
fg[0]=c; figura sabe como resolver su propio
fg[1]=r; area.

double prom=areaPromedio(fg);
System.out.println( prom );
}

public static double areaPromedio( FigGeom fg[] ){


double suma=0;
for( int i=0; i<fg.length; i++ ) fg[i] es una instancia de alguna subclase
{ de FigGeom por lo tanto, por
suma+=fg[i].rea(); polimorfismo la invocacin al mtodo
rea() recaer sobre la clase a la que la
} instancia pertenece. As, podemos
return suma/fg.length; abstraernos de la complejidad del
} calculo del rea. Podemos decir que sea
} la figura que sea es capaz de resolver el
clculo de su rea.

Notemos como al desarrollar el mtodo areaPromedio() nos abstraemos de la particularidad de cada


figura geomtrica y simplemente nos manejamos al nivel de FigGeom. Como la clase FigGeom no puede
ser instanciada, resulta que fg[i] ser siempre una instancia de cualquier subclase de FigGeom. As, por
polimorfismo cuando le apliquemos el mtodo area() ser invocado el mtodo de la clase a la que
pertenece la instancia fg[i].

API java.lang.Math

public static final double PI


public static final double E
public static double pow(double base, double exponente)
public static int abs(int v)
public static int max(int v1,int v2)
public static int min(int v1,int v2)

26
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Modificador Msma clase Sub-clase Externa Msmo paquete
public X X X X
protected X X
private X
default X X

Modificador Variable Mtodo Clase


final Constante No se puede No se puede extender
sobreescribir

INTERFACES

El uso de interfaces potencializa enormemente el diseo y el desarrollo de sistemas.


Una clase abstracta es una clase que tiene al menos un mtodo abstracto. Una interface es una clase que
tiene todos los mtodos abstractos. Entonces no se las define como class. Se las define como interface.
Las interfaces no se extienden: se implementan. As, una clase puede extender a otra e implementar una
o varias interfaces heredando as todos sus mtodos abstractos.
La primer impresin que el programador se lleva de las interfaces es que permiten una especie de
herencia mltiple de mtodos abstractos. Y esto es verdad, pero utilizar interfaces tiene un potencial
enorme que pasaremos a ejemplificar.

En la figura vemos una instancia de la clase Monitor que es vista por instancias de las clases Usuario,
EmpleadoDelDeposito y MedicoDeOjos. Cada una de estas instancias esta interesada en aspectos
diferentes de la clase instancia de monitor. Por ejemplo: al usuario solo le interesa poder setearle el brillo,
el contraste y poder encenderlo y apagarlo. Al empleado del depsito le interesan aspectos relacionados
con las dimensiones para poder ver en que estantera lo va a depositar, si lo va a poder levantar o si va a
necesitar una gra, etc. Al medico de ojos le interesan aspectos relacionados con la salud. Por ejemplo
que redaccin emite.

getDimension()
setBrillo() getPeso()
setConstraste() getVolumen()
setEncendido() Instancia de
la clase
Monitor

esPantallaPlana()
getRadiacion() Instancia de
EmpleadoDelDeposito
Instancia de
Usuario
Instancia de
MedicoDeOjos

27
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Veamos el cdigo de las interfaces propuestas en el ejemplo.

public interface AspectosFuncionales


{
public void setBrillo(int b);
public void setContraste(int c);
public void setEncendido(boolean e);
}

public interface AspectosDimensionales


{
public Dimension getDimension();
public double getPeso();
public double getVolumen();
}

public interface AspectosMedicinales


{
public boolean esPantallaPlana();
public double getRadiacion();
}

Ahora vemos el cdigo de la clase Monitor que implementa las interfaces. Notemos que la clase monitor
extiende a la clase AparatosConCRT por lo que las interfaces no limitan la herencia.

public class Monitor extends AparatosConCRT


implements AspectosFuncionales, AepectosDimensionales, AspectosMedicinales
{
:

// implementacion de los metodos de AspectosFuncionales


public void setBrillo(int b) { ... };
public void setContraste(int c) { ... };
public void setEncendido(boolean e) { ... };

// implementacion de los metodos de AspectosDimensionales


public Dimension getDimension() { ... };
public double getPeso() { ... };
public double getVolumen() { ... };

// implementacion de los metodos de AspectosMedicinales


public boolean esPantallaPlana() { ... };
public double getRadiacion() { ... };

:
}

Ahora veamos las clases Usuario, MedicoDeOjos y EmpleadoDelDeposito.

28
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
public class Usuario
{
private AspectosFuncionales monitor;

public Usuario(AspectosFuncionales m)
{
monitor=m;
}
:
}

public class MedicoDeOjos


{
private AspectosMedicinales monitor;

public Usuario(AspectosMedicinales m)
{
monitor=m;
}
:
}

public class EmpleadoDelDeposito


{
private AspectosDimensionales monitor;

public Usuario(AspectosDimensionales m)
{
monitor=m;
}
:
}
Como vemos, la instancia de
Monitor matchea contra
Y ahora veamos una funcion main que utilize todo lo anterior. AspectosFuncionales,
AspectosMedicinales y contra
AspectosDimensionales. Obviamente
public static void main(String args[]) tambin contra Monitor y contra
{ AparatosConCRT.
Monitor monitor=new Monitor();

Usuario usuario=new Usuario(monitor);


EmpleadoDelDeposito empleado=new EmpleadoDelDeposito(monitor);
MedicoDeOjos medico=new MedicoDeOjos(monitor);
:
}

Pensando en un proyecto con varios programadores y analistas. El uso de interfaces es muy interesante.
Los analistas pueden definir (y escribir) las interfaces que deben implementar las clases que desarrollaran
los programadores. De esta forma se aseguran que los programadores respetaran 100% los nombres de
mtodos definidos ya que si se equivocan tan solo en una mayscula o minscula no podrn compilar.

Las intefaces permiten un nivel de abstraccin fundamental. Supongamos que nos encargan un mtodo
para ordenar elementos. No habra ningn problema si los elementos fueran enteros, caracteres o String.
Ya que estos tienen un orden natural. Pero que pasara si los elementos fueran monitores ???.
Los monitores no tienen un orden natural y el criterio de precedencia no es nico.

29
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
La solucin a este problema es definir una interface Ordenable con un mtodo:
public boolean precedeA(Object o);

As, la clase Monitor puede implementar esta interface y especificar el criterio de precedencia para los
monitores.

public interface Ordenable


{
public boolean precedeA(Object o);
}

public class Monitor extends AparatosConCRT


implements Ordenable, AspectosFuncionales, AepectosDimensionales, AspectosMedicinales
{
:
// metodos de la interface Ordenable
public boolean precedeA(Object monitor) Decidimos que el criterio de
{ precedencia ser el peso del
Monitor m=(Monitor) monitor; monitor.
return getPeso() < m.getPeso();
}
:
}

Ahora el mtodo que ordena puede abstraerse y solo recibir instancias de Ordenable. Lo incluiremos en
una clase Util que englobara mtodos (estticos) utilitarios.

public class Util


{
public static void ordenar(Ordenable[] elementos)
{
Ordenable aux:
Teniendo el mtodo precedeA()
boolean ordenado=false;
podemos implementar (por ejemplo)
el algoritmo de la burbuja.
while( !ordenado )
{
ordenado=true;
for( int i=0; i<elementos.length-1; i++ )
{
if( !elementos[i].precedeA(elementos[i+1]) )
{
aux = elementos[i];
elementos[i] = elementos[i+1];
elementos[i+1] = aux;
ordenado=false;
}
}
}
}
}

30
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Ahora en una funcin main podemos trabajar de la siguiente forma.

main()
{
Monitor monitores[]=new Monitor[10];

// generamos el array de monitores monitores matchea contra Ordenable[] ya que la


: clase Monitor implementa la interface Ordenable.
Ahora, un monitor sabe si precede o no a otro.
Util.ordenar(monitores);
}

Planteando la solucin de esta forma logramos abstraernos de las caractersticas propias de los elementos
a ordenar. Nos alcanza simplemente con que cada elemento pueda decidir sobre si precede o no a otro
elemento de su misma especie.
Con el mismo criterio podemos implementar la interface Ordenable en la clase Empleado y estaremos en
condiciones de ordenar empleados usando el mismo mtodo ordenar() de la clase Util.

public class Empleado implements Ordenable


{
private int leg;
private String nom; Dentro de una clase se puede accederse a
los miembros de los objetos de la misma
: clase aunque estos sean privados.
public boolean precedeA(Object o) Por supuesto que mas prolijo sera contar
con un mtodo getNombre()
{
Empleado otroemp=(Empleado)o;
return ( nom.compareTo( otroemp.nom ) <= 0 );
}
:
}

main()
{
Empleado empleados[]=new Empleado[10];

// generamos el array de empleados empleados matchea contra Ordenable[] ya que la


: clase Empleado implementa la interface Ordenable.
Ahora, un empleado sabe si precede o no a otro de
Util.ordenar(empleados); su misma especie.
}

As, desarrollamos un mtodo totalmente reusable que nos permite ordenar objetos sin tener en cuenta a
que clase pertenecen. Solo deben ser instancias vlidas de Ordenable.

31
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
4. MANEJO DE EXCEPCIONES
El manejo de excepciones es una forma de manejo de error orientado a objetos. La idea es mantener un
cdigo limpio y prudente. Esto es: intentar una secuencia de operaciones y en caso de que alguna falle
entonces emprender las acciones correctivas necesarias.

Cualquier ejemplo de la vida real puede ilustrar el uso de las excepciones. Supongamos que en este
momento me da sed. Muy bien, las acciones que debo realizar para saciar mi sed son las siguientes:

caminaraHastaLaPuerta()
abrirLaPuerta()
caminarHastaLaCocina()
servirmeAguaEnUnVaso()

Es obvio que si mientras camino hasta la puerta me tropiezo y me rompo una pierna entonces no voy a
intentar abrir la puerta ni mucho menos seguir caminando hasta la cocina. Voy a tratar de tomar el
telfono (como pueda) para llamar al mdico. Pero si logro llegar con xito hasta la puerta entonces la
intentare abrir. Claro que puede estar trabada entonces ni intento caminar hasta la cocina porque ser
intil. Mi problema ser lograr abrir la puerta.
As, generalmente se da que para una sucesin de mtodos, el mtodo i+1 debe realizarse si y solo s el
mtodo i finalizo con xito. A su vez, el mtodo i debi haberse ejecutado si y solo si el mtodo i-1
resulto exitoso. Veamos un cdigo que ilustre este ejemplo.
Si un mtodo falla al ser
Manejo de Excepciones invocado entonces dispara
una excepcin predefinida y
: el control del programa pasa
try al catch correspondiente.
{
caminarHastaLaPuerta();
abrirLaPuerta();
caminarHastaLaMaquinaDeAgua();
servirAgua();
}
catch(TropezonException ex)
{
System.out.println(Me tropeze !!!);
}
catch(PuertaNoAbreException ex)
{
System.out.println(Ohh nooo !!!);
}
catch(NoHayAguaException ex)
{
System.out.println(No hay agua en el bidn...);
}
catch(Exception ex)
{
System.out.println(Error inesperado);
ex.printStackTrace();
}
:

32
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
API java.lang.Exception
public Exception()
public Exception(String mssg)
public void printStackTrace()
public String getMessage()

CAPTURA O PROPAGACION EXCEPCIONES

Para tratar con excepciones tenemos dos posibilidades: una es capturar la excepcin que dispara el
mtodo utilizando la sentencia catch. Pero muchas veces no es nuestra responsabilidad emprender las
acciones correctivas. En ese caso simplemente debemos propagar el error (prototipando el mtodo con
la palabra throws) para que se haga cargo nuestro llamador. A su vez, si el puede tratar la excepcin lo
har mediante un bloque try-catch pero si no puede tratarlo entonces propagar el error y as
sucesivamente.

El siguiente ejemplo es una clase con tres mtodos: f1(), f2() y f3(). Si el mtodo f1() falla entonces
disparara una excepcin del tipo F1Exception. Anlogamente si f2() o f3() fallan dispararan F2Exception
y F3Exception respectivamente.

Los mtodos reciben un boolean error con el que indicaremos si queremos que el mtodo falle o no. Si
error=true entonces el mtodo disparara la excepcin que le corresponde. Si no finalizara con xito.

Un mtodo que eventualmente pueda disparar una excepcin debe prototiparse con la palabra throws.
Esto forzara al llamador del mtodo a encerrarlo en un bloque try-catch o bien a propagarlo el error.

SimpleException.java
public class SimpleException {
public void f1(boolean error) throws F1Exception
{
System.out.println("Comienza f1()"); Como error=true entonces
disparo una instancia de
F1Exception.
if( error )
{
throw new F1Exception();
}
System.out.println("Termina f1() ok!");
}
public void f2(boolean error) throws F2Exception
{
System.out.println("Comienza f2()");
if( error )
{
throw new F2Exception();
}

System.out.println("Termina f2() ok!");


}
33
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
public void f3(boolean error) throws F3Exception
{
System.out.println("Comienza f3()");

if( error ) {
throw new F3Exception();
}

System.out.println("Termina f3() ok!");


}
public static void main(String args[]) {
try {
boolean errorF1,errorF2,errorF3;

errorF1= Boolean.valueOf(args[0]).booleanValue();
errorF2= Boolean.valueOf(args[1]).booleanValue();
errorF3= Boolean.valueOf(args[2]).booleanValue();

SimpleException se=new SimpleException();


se.f1(errorF1);
se.f2(errorF2);
main() invoca a los mtodos f1(),
se.f3(errorF3); f2(), f3() por eso debe tener un
} bloque try-catch.
catch(F1Exception ex) {
ex.printStackTrace();
System.out.println(Error en el mtodo f1());
}
catch(F2Exception ex) {
ex.printStackTrace();
System.out.println(Error en el mtodo f2());
}
catch(F3Exception ex) {
ex.printStackTrace();
System.out.println(Error en el mtodo f3());
}
catch(Exception ex) {
ex.printStackTrace();
System.out.println( Error inesperado.
+ Probablemente esten mal pasados los
+ argumentos);
}
}
}

Las excepciones F1Exception, F2Exception y F3Exception son clases que debemos programar. Para
programar una excepcin simplemente debemos programar una clase que herede de la clase base
Exception.

34
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
F1Exception.java
De igual forma se
public class F1Exception extends Exception programan las clases
F2Exception y
{ F3Exception
}

COMPILACION Y CORRIDA

c:\> javac *.java


c:\> java SimpleException false true false
Comienza f1()
Termina f1() ok!
Fallar el mtodo f2()
Comienza f2()
exceptions.F2Exception
at exceptions.SimpleException.f2(SimpleException.java:23)
at exceptions.SimpleException.main(SimpleException.java:56)
Error en el mtodo f2()
c:\>

El ejemplo anterior esta pensado para que el lector pueda probar todos los casos haciendo variar los
parmetros de entrada (por lnea de comandos). Luego es recomendable que se pruebe programando la
funcin main() de la siguiente forma:
main() propaga el error,
as no es necesario un
public static void main(String args[]) throws Exception bloque try-catch
{
boolean errorF1,errorF2,errorF3;

errorF1= Boolean.valueOf(args[0]).booleanValue();
errorF2= Boolean.valueOf(args[1]).booleanValue();
errorF3= Boolean.valueOf(args[2]).booleanValue();

SimpleException se=new SimpleException();


se.f1(errorF1);
se.f2(errorF2);
se.f3(errorF3);
}

Para finalizar, analizaremos un fragmento de un programa servidor (el programa completo se estudiar en
el capitulo de networking).

35
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
public class SimpleServer
{
public static void main(String args[]) throws Exception
{
int port=5432;
int queve=10;

ServerSocket ss=new ServerSocket( port,queve );

Socket s1;
ObjectOutputStream oos; Si falla la creacin del
ServerSocket se propaga el error y
el programa finaliza aqu. Esto esta
while( true ) bien, ya que si fallo el
{ ServerSocket el servidor no tiene
try nada que hacer.
{
s1=ss.accept();
Este bloque try-catch
no sera necesario a
oos=new ObjectOutputStream(
los efectos de s1.getOutputStream() );
compilacin, pero si oos.writeObject( Hola NET Mundo);
a los efectos de la oos.close();
aplicacin. s1.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
}

En este ejemplo tenemos la creacin del ServerSocket que eventualmente podra disparar un IOException.
Es claro que si falla el new ServerSocket( ... ) el servidor no tiene sentido ya que no podr atender ningn
requerimiento. En este caso la excepcin ser propagada a travs de la sentencia throws colocada en el
prototipo del mtodo main().

Si el serverSocket se construyo con xito entonces se ingresa al while(true) dentro del cual se van a
recibir las conexiones de los clientes a travs del mtodo ss.accept(). Este mtodo eventualmente podra
fallar tambin y disparar un IOException. Si bien, al propagar el error en el mtodo main estamos
cubriendo esta posibilidad y a los efectos de compilacin estamos cubiertos, a los efectos de la aplicacin
no seria prudente aceptar esta situacin porque si ss.accept() falla en realidad esta fallando la conexin de
un cliente, pero es posible que el prximo cliente no falle. Por eso, al encerrar todo el cdigo en un bloque
try-catch tratamos puntualmente la excepcin originada con el cliente problemtico y no permitimos que
la excepcin sea propagada finalizando prematuramente el mtodo main().

36
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
5. APPLET
Los applets son aplicaciones Java embebidas en paginas html. As, el interprete del applet es el browser.
Por cuestiones de seguridad para el cliente (usuario del applet) los applets tienen una serie de
restricciones que les impiden ser destructivos. Por ejemplo no pueden tener ningn tipo de acceso al disco
rgido del cliente, no pueden tener mtodos nativos, no pueden convertirse en servidores y no pueden
conectarse a otro host que no sea el host desde el que provienen.

Object paint(Graphics g)
Component update(Graphics g)
Container repaint()
Window
Frame
Panel init()
Applet start()
Button stop()
Label destroy()
Choice getParameter(String param)
: getDocumentBase()

Veamos el HolaMundoApplet.

HolaMundoApplet.java
import java.awt.*;
import java.applet.*;

public class HolaMundoApplet extends Applet


{ Sobreescribimos el mtodo
public void paint(Graphics g) paint() heredado de
Component. El Graphics g
{ es un puntero al contexto
g.drawString(Hola Mundo !!!, 25, 25); grfico del componente
}
}

HolaMundoApplet.html
<applet code=HolaMundoApplet.class height=200 width=200>
</applet>

COMPILACION Y CORRIDA

c:\> javac HolaMundoApplet.java


c:\> appletviewer HolaMundoApplet.html

37
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Area del applet (color griz). El Graphics g
es un puntero a este rea. A travs de l
tenemos acceso grfico para, por ejemplo,
escribir un texto que diga Hola Mundo !!!

El siguiente ejemplo muestra como manejar imgenes. Las imgenes bajan desde la web utilizando el
mtodo getImage(). Este mtodo recibe un objeto URL que apunte al host desde donde fue enviado el
documento html. Ese URL se obtiene utilizando el mtodo getDocumentBase(). El segundo argumento de
getImage() es el imagename. Este es un String que indica el nombre de la imagen. Puede ser .gif o .jpg.
Inclusive un gif animado. El imagename puede incluir tambin el path. Por ejemplo imagenes/pp.gif.
Notemos que el path es relativo. Nunca debemos utilizar un path absoluto como /imagenes/pp.gif.
Tambin vemos que el imagename esta parametrizado. El paso de parmetros al applet se hace a travs de
la pgina html. Los parmetros son por nombre, no por posicin. El mtodo getParameter() recibe como
argumento el nombre del parmetro y devuelve el valor del mismo como String. El tag para pasar
parmetros lo podemos ver en ImagenApplet.html (a continuacin).

ImagenApplet.java
import java.awt.*;
import java.applet.*;
public class ImagenApplet extends Applet{
El nombre de la imagen
private Image img=null; esta parametrizado en la
pgina html.
public void init() {
try {
String imgname=getParameter(IMAGE_NAME);
img=getImage(getDocumentBase(),imgname);
MediaTracker mt=new MediaTracker(this);
mt.addImage(img,0);
mt.waitForAll();
} catch(Exception ex) { El MediaTracker
permite monitorear si las
ex.printStackTrace(); imgenes que bajamos
} con getImage() estn
} listas para ser utilizadas.
public void paint(Graphics g) {
g.drawImage(img,0,0,this);
}
}

38
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
ImagenApplet.html
<applet code=ImagenApplet.class height=300 width=300>
<param name=IMAGE_NAME value=imagenes/T1.gif>
</applet> Tag para pasarle parmetros al
applet. Se pueden poner tantas
lneas como esta como sea
API java.awt.Graphics necesario.

public void drawString(String texto, int x, int y)


public void drawImage(Image img
, int x
, int y
, ImageObserver imgobs)
public void drawRect(int x, int y, int ancho, int alto)
public void fillRect(int x, int y, int ancho, int alto)

API java.awt.MediaTracker
public void addImage(Image img, int id)
public boolean checkID(int id)
public boolean checkAll()
public boolean waitForID(int id)
public boolean waitForAll()

CAPTURA DE EVENTOS

Los componentes generan eventos de diferentes tipos. Por ejemplo cuando el usuario presiona un botn
(ya sea con el mouse o con la barra espaciadora) espera que ocurra alguna accin. Cuando se hace doble-
click en un tem de una lista se espera que ocurra una accin. Pero si se selecciona un tem de una lista
con un solo click no se espera que ocurra nada. Cuando se escribe en un campo de texto no espera
ninguna accin, pero cuando se presiona ENTER en el campo de texto luego de haber escrito el contenido
se espera una accin.
Es decir: existen eventos de action, de key, de tem, de mouse, de window, etc.
El componente genera eventos e informa a quienes estn interesados en ser notificados ante la ocurrencia
de los mismos. Las clases aptas para escuchar eventos se llaman listeners.

Siguiendo con el ejemplo ImagenApplet, vamos ver como detectar los eventos de mouse.

39
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
import java.awt.*;
import java.awt.event.*; Con este mtodo le pasamos al
import java.applet.*; applet una instancia de
EscuchaMouse para que cuando
public class ImagenApplet extends Applet genere algn evento de mouse la
{ notifique.
La clase EscuchaMouse es una
private Image img=null; inner class que implementa la
interface MouseListener.
public void init() {
try {
addMouseListener( new EscuchaMouse() );
:
Una inner class no es mas que una clase
} catch(Exception ex) { dentro de otra. La gran ventaja de estas clases
ex.printStackTrace(); es que pueden ver los mtodos y las variables
de la clase que las contiene como si fueran
} propios. Pero el hecho de que sean inner class
} no tiene absolutamente nada que ver con la
: herencia. En este caso, EscuchaMouse hereda
de Object e implementa MouseListener

class EscuchaMouse implements MouseListener


{
public void mouseClicked(MouseEvent e)
{
System.out.println(Click com el MOUSE !!!);
}
public void mousePressed(MouseEvent e){};
public void mouseReleased(MouseEvent e){};
public void mouseEntered(MouseEvent e){};
public void mouseExited(MouseEvent e){};
}
}
Por implementar MouseListener hereda cinco mtodos
abstractos (ver la documentacin). Cada uno de estos mtodos
representa un evento diferente de mouse. En este ejemplo solo
nos interesa el evento Click, pero igual tenemos que
sobreescribir los cuatro mtodos restantes y dejarlos vacos para
quitarles la abstraccin. De no hacerlo el compilador nos dir
que EscuchaMouse es una clase abstracta y como tal no puede
ser instanciada.

ADAPTERS

Los adapters son clases que implementan las interfaces listener y sobreescriben todos sus mtodos
dejndolos vacos. As le evitan al programador la tediosa tarea de sobreescribir mtodos que no va a
utilizar. Para cada listener existe un adapter.

40
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Interface definida en
ADAPTERS Ejemplo MouseAdapter java.awt.event.
Tiene cinco mtodos abstractos.
public interface MouseListener
{
public void mouseEntered(MouseEvent e);
Clase definida en java.awt.event.
public void mouseExited(MouseEvent e); Implementa MouseListener y
public void mousePressed(MouseEvent e); sobreescribe todos sus mtodos
public void mouseReleased(MouseEvent e); dejndolos vacos.
public void mouseClicked(MouseEvent e); Quien extienda a MouseAdapter
} matchea contra MouseListener y
no hereda ningn mtodo abstracto.

public class MouseAdapter implements MouseListener


{
public void mouseEntered(MouseEvent e){ }
public void mouseExited(MouseEvent e){ }
public void mousePressed(MouseEvent e){ }
public void mouseReleased(MouseEvent e){ }
Las instancias de EscuchaClick son
public void mouseClicked(MouseEvent e){ } listeners vlidos para eventos de
} mouse.

public class EscuchaClick extends MouseAdapter


{
public void mouseClicked(MouseEvent e)
{
System.out.println(Click !!!);
}
}

Ventajas Desventajas

XListener Si tipeamos mal el nombre de Debemos tipear todos los mtodos. Aunque
algn mtodo se genera un error en solo nos interese uno.
tiempo de compilacin.

XAdapter Sobreescribimos solo el mtodo Si nos equivocamos no genera un error en


que necesitamos. tiempo de compilacin porque no estamos
dejando de sobreescribir ningn mtodo
abstracto.

41
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
6. INTERFACE GRAFICA
Para armar una interface grfica (GUI) en Java tenemos tres elementos:

Los Componentes (clases que heredan de Component)


Los Containers (clases que heredan de Container)
Los Layouts (clases que implementan la interface LayoutManager)

El esquema es simple:

Un container contiene componentes. Los componentes son distribuidos (o acomodados) dentro del
container en funcin del layout que el container tenga especificado.

Existen cinco layouts (o distribuciones). FlowLayout, BorderLayout, GridLayout, CardLayout y


GridBagLayout.

LAYOUT MANAGER
Layout Size 1 Size 2

Flow
Arriba y centrado

Border
Se divide el
container en
cinco regiones.
Se puede colocar
un solo
componente en
cada regin

Grid (3,3)
Una grilla de n
filas y m
columnas. Se
coloca un
componente
por celda.

42
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Como podemos ver, a medida que la ventana es redimensionada los componentes se acomodan
proporcionalmente respetando la distribucin que le fue asignada.

El siguiente rbol muestra la estructura de las clases para armar GUIs en Java.

Object Vemos que Container hereda de


Component Component. Por lo tanto Un
Container container es un Component
Window
Frame
Panel
Applet
Button
Label
Choice
:

El siguiente ejemplo crea una ventana.

Ventana.java
import java.awt.*;

public class Ventana extends Frame {


public Ventana() El constructor de Frame
{ recibe el titlebar
super(Titulo);
setSize(300,300);
Mtodos heredados de
setVisible(true); Component
}
public static void main(String args[]) En general, el mtodo main() en las
{ aplicaciones grficas solo tendr una
new Ventana(); lnea: la que construye de la ventana
} principal.
}

API java.awt.Frame

public Frame(String titlebar) heredados de


Component
public void setSize(int ancho, int alto)
public String setVisible(boolean b)
public void setLayout(LayoutManager layout)
public Component add(Component c) heredados de
public Component add(Component c, int index) Container

43
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
TestGUI.java
import java.awt.*;
import java.awt.event.*;
public class TestGUI extends Frame
Recordemos que
{ FlowLayout distribuye
public TestGUI() los componentes arriba
{ y centrados
super(Test);
setLayout( new FlowLayout() );

Button b=new Button("Botn"); Agrega el Button b a la


ventana. Su ubicacin ser
add( b ); arriba y centrado.

addWindowListener( new EscuchaCerrar() );

setSize(380,260);
Esta instancia de EscuchaCerrar ser
setVisible(true); notificada cuando la ventana genere
} algn evento de ventana.

class EscuchaCerrar extends WindowAdapter


{
public void windowClosing(WindowEvent e)
{
setVisible(false); El mtodo
dispose(); windowClosing() es
System.exit(0); llamado cuando se
cierra la ventana.
}
}
}

API - java.awt.*
Component Mtodos
Label public Label(String texto)
Button public Button(String texto)
Checkbox public Checkbox(String texto)
public setState(boolean b)
public boolean getState()
TextField public TextField(int ancho)
public String getText()
public void setText(String texto)

44
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
TextArea public TextArea(int alto, int ancho)
public String getText()
public void setText(String texto)
public void append(String texto)
Choice public Choice()
public void addItem(String item)
public String getSelectedItem()
public int getSelectedIndex()
List public List()
public void add(String item)
public void setMultipleMode(boolean b)
public int getItemCount()
public String getSelectedItem()
public int getSelectedIndex()
public String[] getSelectedItems()
public int[] getSelectedIndexes()

Veamos ahora un ejemplo en el que se combinen los diferentes layout managers presentados para generar
una interface grfica til.

NORTH

CENTER

SOUTH

La funcionalidad de esta pantalla es la siguiente: cuando se presiona el botn Ok el texto que est tipeado
en el textfield superior pasara a la lista que esta en la parte central. Cuando se presiona el botn Limpiar
se borraran todos los tems de la lista.

45
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
ConsultaGUI.java

import java.awt.*;
import java.awt.event.*;

public class ConsultaGUI extends Frame


{
private TextField tf; Los componentes que sern
private List lst; interrogados en ms de un
mtodo deben ser globales
public ConsultaGUI()
{
super(Consulta);

Panel pnorth=new Panel( new BorderLayout() );


pnorth.add( new Label(Consulta), BorderLayout.WEST );
pnorth.add( tf=new TextField(), BorderLayout.CENTER );

NORTH Button bOk=new Button(Ok);


bOk.addActionListener( new EscuchaOk() );
pnorth.add( bOk,BorderLayout.EAST );
Cuando se presione el
add( pnorth, BorderLayout.NORTH ); botn Ok se notificara a la
instancia de EscuchaOk
add( lst=new List(), BorderLayout.CENTER );

Panel psouth;
psouth=new Panel( new FlowLayout(FlowLayout.LEFT) );
Button bLimpiar=new Button(Limpiar);
SOUTH bLimpiar.addActionListener( new EscuchaLimpiar() );
psouth.add( bLimpiar );
Cuando se presione el
add( psouth, BorderLayout.SOUTH ); botn Limpiar se
notificara a la instancia
addWindowListener( new EscuchaCerrar() ); de EscuchaLimpiar

setSize(380,260);
setVisible(true);
}

46
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
public static void main(String args[])
{
new ConsultaGUI();
}

class EscuchaOk implements ActionListener


{
public void actionPerformed(ActionEvent e)
{
lst.add( tf.getText() );
tf.setText();
tf.requestFocus();
}
}
class EscuchaLimpiar implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
lst.removeAll();
}
}
class EscuchaCerrar extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{
setVisible(false);
dispose();
System.exit(0);
}
}
}

47
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
7. MULTITHREAD
La multiprogramacin permite descomponer una aplicacin en diferentes tareas que se ejecutan
concurrentemente y cooperan entre s para lograr el objetivo de la aplicacin.
Un buen ejemplo de una aplicacin multithread es un Servidor. A su vez, para entender como trabaja un
servidor vamos a poner un ejemplo de la vida real.

Un servidor es un almacenero. El almacenero esta de 9 a 20 hs. detrs del mostrador esperando que
llegue algn cliente a comprarle algo. Cuando llega un cliente el almacenero comienza a atenderlo.
Si llega otro cliente y el almacenero todava esta atendiendo al cliente anterior, el nuevo cliente formara
una fila. Cuando llegue otro cliente se pondr al final de la fila y as sucesivamente.

Supongamos que el primer cliente no esta muy decidido sobre lo que va a comprar. No puede decidir
entre llevar kilo de galletitas o una bandeja de masitas. Mientras tanto, el segundo cliente (esta en la
cola) que solo quiere un atado de cigarrillos y tiene el importe justo tiene que esperar que el primer cliente
se decida. Esta situacin no es optima, ya que el segundo cliente que demorara unos 30 segundos tiene
que estar 15 minutos en la cola porque el almacenero esta atendiendo al indeciso que llego antes que el.

Como el almacenero ve que tiene muchos cliente y el negocio marcha muy bien decide contratar 5
empleados: Juan, Pablo, Jos, Ral y Felipe.
Cuando llega un cliente el almacenero le pide a alguno los empleados que lo atienda. Cuando llega otro
cliente el almacenero le indica a otro empleado que lo atienda y as sucesivamente.
Como podemos ver, cada empleado trabaja independientemente y entre todos cumplen el objetivo del
almacenero que es atender y despachar bien.

Sin embargo aparecen situaciones nuevas que no existan cuando el almacenero trabajaba solo. Por
ejemplo no pueden dos empleados utilizar la balanza al mismo tiempo. Porque si los dos ponen el
producto que quieren pesar en la balanza al mismo tiempo el resultado no seria correcto.

En el ejemplo el almacenero es la aplicacin (el servidor) y los empleados son tareas (thread). La balanza
es un recurso crtico cuyo acceso debe ser sincronizado.

Para comenzar nada mejor que un HolaMundoMT (HolaMundo MultiThread).

HolaMundoMT.java En Java los Thread son clases


public class HolaMundoMT extends Thread que extienden a la clase base
Thread.
{
private String name;

public HolaMundoMT(String n)
En el constructor recibe un String
{ name.
name=n;
}

48
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
El mtodo run() es a los Thread lo que
public void run() el mtodo main() es a las aplicaciones.
{ Escribir un thread es (entre otras
try cosas) sobreescribir este mtodo.
{
int delay=(int)(Math.random()*3000);
sleep(delay); El thread dormir un
tiempo aleatorio entre 0
System.out.println( y 3 segundos.
"Hola Mundo MT !!! "+name);
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public static void main(String args[])
{
HolaMundoMT t1=new HolaMundoMT("Pedro");
HolaMundoMT t2=new HolaMundoMT("Pablo");
HolaMundoMT t3=new HolaMundoMT("Juan");
start() llama al mtodo run(). No debe
t1.start();
llamarse a mano al mtodo run().
t2.start();
t3.start();
}
}

COMPILACION Y CORRIDA
Como podemos ver, en cada corrida del
c:\> javac HolaMundoMT.java programa el resultado es distinto porque
depende del tiempo que duerma cada
c:\> java HolaMundoMT thread. Cada thread duerme un tiempo
HOLA MUNDO MT !!! Pablo aleatorio y como son ejecutados
HOLA MUNDO MT !!! Juan concurrentemente no se puede predecir nada
HOLA MUNDO MT !!! Pedro sobre cual ser la salida del programa. En
cada corrida la salida puede variar.
Esto prueba que los thread corren
c:\> java HolaMundoMT concurrentemente porque si su ejecucin
HOLA MUNDO MT !!! Juan fuese secuencial entonces la salida del
HOLA MUNDO MT !!! Pedro programa siempre sera Pedro, Pablo, Juan.
HOLA MUNDO MT !!! Pablo

Pensemos ahora en una animacin. Una animacin es una sucesin continua de imagenes. O sea un
while(true){ ... } . Si en una interface grfica (sea un Frame o un Applet) ponemos un while( true ) lo
estaremos colgando. La ventana no se repintara, los botones quedaran apretados, etc. Sin embargo, para
desarrollar nuestra animacin necesitamos el while( true ).
La solucin es tener un thread que se ocupe del while( true ). Al ser independiente, no interferir con el
control de la aplicacin y el resultado ser el esperado.

49
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
La animacin esta planteada de la siguiente manera. Existen dos clases: una clase pasiva y una clase
activa.

clase Animacion (clase pasiva)


clase Animador (clase activa)

Decimos que la clase Animacion es pasiva porque se deja animar. Tiene un mtodo mostrarSiguiente()
que muestra la siguiente imagen. Es decir: se deja aplicar el mtodo mostrarSiguiente().
La clase Animador es la clase activa porque aplicara el mtodo mostrarSiguiente() a la clase Animacion.
Animador ser un thread en cuyo mtodo run() tendr un ciclo while( true ).

Animacion.java Canvas es un Component que se utiliza


como base para la creacin de nuevos
import java.awt.*;
componentes. En este ejemplo
estaremos creando el componente
public class Animacin extends Canvas Animacin. Al ser Animacin un
{ componente, ser distribuido en los
private Image imgenes[]; containers en funcin del layout
private int index=0; manager seteado.
private Animador thread;
private int delay;
thread es una instancia
public Animacin(Image imgs[],int d) throws Exception de Animador.
{
imagenes=imgs;
delay=d;
MediaTracker mt=new MediaTracker(this);
for(int i=0; i<imagenes.length; i++)
{
mt.addImage(imgenes[i],0);
}

mt.waitForAll();

int ancho=imagenes[0].getWidth(this);
int alto=imagenes[0].getHeight(this);
setSize(ancho,alto);
}
public void setMovimiento(boolean animar)
{
if( animar )
Para comenzar la animacin
{ hay que aplicarle el mtodo
(thread=new Animador()).start(); setMovimiento(true).
} Entonces construimos y
else comenzamos (start) el thread.
{ Si aplicamos el mtodo
setMovimiento(false)
thread.stop(); entonces se mata al thread
} con el mtodo stop().
}

50
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
public void paint(Graphics g)
{
g.drawImage(imgenes[index],0,0,this);
}

public void mostrarSiguiente()


{
index=++index % imagenes.length;
repaint();
}

class Animador extends Thread Animador es una inner class. Como


vemos, en el mtodo run() tenemos
{ un while(true) y por cada vuelta
public void run() aplicamos mostrarSiguiente()
{ (mtodo de la clase Animacin que
try contiene a esta inner class) y
{ dormimos un momento para que no
sea tan rpido el movimiento.
while( true )
{
mostrarSiguiente();
sleep(delay);
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
}

Hasta aqu hemos desarrollado el componente Animacin. Ahora desarrollaremos una clase que utilize
este componente y genere una ventana como la que se muestra a continuacin.

51
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
AnimacionTest.java
import java.awt.event.*;
import java.awt.*;

public class AnimacionTest extends Frame


{
private Animacin animacion;
private Button bcom;
private Button bfin;
public AnimacionTest() throws Exception {
super(Test de Animacin);
setLayout( new FlowLayout() );
EscuchaButtons escucha=new EscuchaButtons();
bcom=new Button(Comenzar);
bcom.addActionListener( escucha );
add( bcom );
Image imgs[]=new Image[10];
for( int i=0; i<10; i++ ) {
imgs[i]= getToolkit().getImage(imgenes/T+i+.gif);
}
animacion=new Animacin(imgs,180);
Como vemos, agregamos
add( animacion ); la animacin al container
como un componente mas.
bfin=new Button(Finalizar);
bfin.addActionListener( escucha );
add( bfin );

setSize(300,300);
setVisible(true);
}
public static void main(String args[]) throws Exception
{
new AnimacionTest();
}
class EscuchaButtons implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
animacion.setMovimiento( e.getSource().equals(bcom) );
}
}
}

52
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
THREAD LIFE CICLE Diagrama de los cinco estados

El diagrama precedente describe el ciclo de vida de un thread. El thread pasa por 5 estados a lo largo de
su evolucin. Cuando lo creamos con el operador new se dice esta en el estado new thread. Cuando le
aplicamos el mtodo start() decimos que el thread esta en cola de listos o ready to run. A partir de
entonces el thread pasara entre ese estado y el estado running. En running el thread esta haciendo uso
del procesador (CPU). La planificacin de CPU esta a cargo de un proceso de mas bajo nivel llamado
Scheduler. Cuando el thread intente una operacin den entrada/salida pasara a una cola de bloqueados
Blocked y de esta volver a la cola de listos. Cuando finalize el mtodo run() el thread pasara a su
ltimo estado: dead.

SINCRONIZACION DE THREADS

Para explicar este tema plantearemos el problema del productor-consumidor.


El productor produce caracteres y los deposita en un buffer finito. El consumidor consume los caracteres
depositados en el buffer por el productor. El acceso al buffer debe ser sincronizado y debemos evitar que
el productor ponga un carcter en el mismo momento que el consumidor lo intente sacar.
Como el buffer es finito, puede darse el caso de que el productor intente poner caracteres cuando el buffer
este lleno. Anlogamente el consumidor podra intentar sacar caracteres cuando el buffer este vaco.

La solucin a este problema est a continuacin. Son cuatro clases: Buffer, Producer, Consumer y
ProdConsTest.

53
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Buffer.java
public class Buffer {
private char buff[];
private int size=6, index=0;
private boolean lleno=false, vacio=true;
public Buffer() {
buff=new char[size];
}
public synchronized void poner(char c) throws Exception
{
while( lleno ) {
wait(); Mientras el buffer este lleno el
} productor que llamo a este mtodo
no podr poner el carcter. Entonces
buff[index++]=c; ser bloqueado hasta que sea
vacio=false; notificado mediante el mtodo
notify().
if( index>=size ) {
lleno=true; Es probable que algn consumidor este
} bloqueado esperando que este productor
produzca algn carcter. Con este
mtodo lo notificamos para
notify(); desbloquearlo.
return;
}

public synchronized char sacar() throws Exception


{
while( vacio ) {
wait();
}

char c=buff[--index];
lleno=false;

if( index == 0 ) {
vacio=true;
}
notify();
return c;
}
}

54
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Producer.java
public class Producer extends Thread {
private Buffer buffer;
private String alphabet=ABCDEFGHIJKLMNOPQRSTUVWXYZ;

public Producer(Buffer s){


buffer = s;
} Recibe un puntero al buffer.

public void run() {


try {
char c;
for (int i = 0; i < 20; i++) {
c = alphabet.charAt((int)(Math.random() * 26));
buffer.poner(c);
System.out.println(Produje -> + c);
sleep((int)(Math.random() * 3000));
}
} catch (Exception ex) { ex.printStackTrace(); }
}
}

Consumer.java
public class Consumer extends Thread{
private Buffer buffer;

public Consumer(Buffer s) {
buffer = s;
} Recibe un puntero al buffer.
Obviamente debe ser el mismo
buffer que se le paso al productor.
public void run() {
try {
char c;
for (int i = 0; i < 20; i++) {
c = buffer.sacar();
System.out.println(Saque = + c);
sleep((int)(Math.random() * 3000));
}
} catch (Exception ex) { ex.printStackTrace(); }
}
}

55
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
ProdConsTest.java

public class ProdConsTest


{
public static void main(String args[])
{
Buffer b = new Buffer();
Producer p = new Producer(b);
Consumer c = new Consumer(b);

p.start();
c.start();
}
}

56
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
8. ENTRADA/SALIDA
Veremos a continuacin algunas clases del paquete java.io.

HolaMundoIO.java
import java.io.*;
public class HolaMundoIO
{
public static void main(String args[]) throws Exception
{
File f=new File(pp.txt); La clase File permite acceder al header
de un archivo. Provee mtodos tales
if( !f.exists() ) como canRead(), canWrite(), length(),
{ exists(), etc.
_grabarArchivo(f);
}
else
{
_leerArchivo(f);
}
}

private static void _grabarArchivo(File f) throws Exception


{
FileOutputStream fos=new FileOutputStream( f );
String s=Hola Mundo IO;
byte buffer[]=s.getBytes();
fos.write(buffer);
El mtodo write() recibe un byte[] y grabara
fos.close();
en el archivo cada uno de los bytes
} contenidos en las celdas del array.

private static void _leerArchivo(File f) throws Exception


{
FileInputStream fis=new FileInputStream( f );
byte buffer[]=new byte[ (int) f.length() ];
fis.read( buffer );
fis.close(); El mtodo read() carga el byte[] buffer con
bytes que lee del archivo. Leer tantos bytes
String s=new String(buffer); cono posiciones tenga el array.
System.out.println( Leido=[ + s + ] );
}
}

57
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
API java.lang.String
public String(byte buffer[])
public byte[] getBytes()

API java.io.File
public File(String filename)
public boolean exists()
public long length()
public boolean canRead()
public boolean canWrite()
public boolean isFile()
public boolean isDirectory()

El siguiente rbol ilustra la jerarqua de algunas de las clases de input que pertenecen al paquete java.io.
Anlogamente existe un rbol similar para las clases de output.

public abstract int read()


InputStream public int read(byte[] b, int off, int len)
SequenceInputStream public void read(byte[] b)
PipedInputStream
FilterInputStream public int readInt()
public double readDouble()
DataInputStream public String readUTF()
BufferedInputStream public boolean readBoolean()
PushbackInputStream public byte readByte()
ObjectInputStream
ByteArrayInputStream public Object readObject()
FileInputStream

JEditor.java
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class JEditor extends Frame
{
private TextArea ta;
private String filename;
public JEditor(String filename) throws Exception {
super(JEditor +filename);
this.filename=filename;
add( ta=new TextArea(), BorderLayout.CENTER );
_leer( filename );
addWindowListener( new EscuchaCerrar() );
}

58
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
private void _leer(String filename) throws Exception
{
File f=new File(filename);
FileInputStream fis=new FileInputStream( f );
byte buffer[]=new byte[ (int) f.length() ];
fis.read( buffer );
fis.close();

ta.setText( new String(buffer) );


}
private void _guardar(String filename) throws Exception
{
FileOutputStream fos;
fos=new FileOutputStream( filename );
byte buffer[]=ta.getText().getBytes();
fos.write(buffer);
fos.close();
}
public static void main(String args[]) throws Exception
{
JEditor e=new JEditor(args[0]);
e.setSize(380,270);
e.setVisible(true);
}
class EscuchaCerrar extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{
try{
_guardar(filename);
setVisible(false);
dispose();
System.exit(0);
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
}

59
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
La clase FileDialog genera una caja de dilogo para seleccionar archivos y/o directorios.

API java.awt.FileDialog
public static final int SAVE
public static final int LOAD
public FileDialog(Frame owner, String titlebar, int mode)
public String getFile()
public String getDirectory()
public void setFile(String filename)
public void setDirectory(String dirname)

Incorporando el FileDialog Modificacin en _guardar()


private void _guardar(String filename) throws Exception
{
FileDialog fd;
fd=new FileDialog(this,Guardar como...,FileDialog.SAVE);
fd.setFile(filename);
fd.setVisible(true);
FileOutputStream fos;
String newfilename= fd.getFile();
fos=new FileOutputStream( newfilename);
byte buffer[]=ta.getText().getBytes();
fos.write(buffer);
fos.close();
}

60
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
9. NETWORKING
ARQUITECTURA CLIENTE SERVIDOR

Hablamos de cliente-servidor cuando existe un proceso que requiere un determinado servicio y acude a
otro proceso para que se lo brinde.
Cuando navegamos por Internet, utilizamos el navegador. El navegador es un Cliente del servicio de
pginas web. Cuando tipeamos la direccin de la pgina a la que queremos acceder le estamos indicando
al navegador (cliente) la direccin del Servidor que le proveer la pgina que necesitamos.

Un muy buen ejemplo de como funciona esta arquitectura es el almacenero que presentamos en el
capitulo de Multithread.

El almacenero (server) abre su almacn a las 9 de la maana y se queda detraes del mostrador esperando
la llegada de los clientes. Los clientes entran al negocio cuando necesitan alguno de los productos
(servicios) que el almacn ofrece. Notemos que el almacenero no sabe en que momento llegan los
clientes.
Cuando llega un cliente el almacenero lo comienza a atender. Se establece un dialogo (protocolo) entre el
cliente y el almacenero.

Cliente - Buen dia


Almacenero - Buen dia el almacenero se toma un
Cliente - Deme 100g de salchichon tiempo para cortar el
fiambre (procesar)
Almacenero - Sirvase, algo mas?
Cliente - No gracias, hasta luego
Almacenero - Hasta luego

Puede ser que cuando el cliente llega al almacn el almacenero esta atendiendo a otro cliente. El cliente
forma una fila (cola) y espera a que el almacenero despache al cliente que llego primero. Puede ser que el
almacenero se tome un tiempo excesivo para despachar al cliente (porque el cliente le pide demasiadas
cosas). Entonces el cliente que esta en la cola da media vuelta y se retira (timeout).
Por supuesto que seria mejor si el almacenero tuviera empleados (threads), entonces cada empleado se
ocupara de despachar a cada cliente.

SOCKET y PORT

Un Socket es un punto de intercomunicacin entre dos procesos (por ejemplo cliente y servidor). Los
procesos pueden estar en el mismo host (computadora) o no.
En un host pueden correr diferentes procesos brindando diferentes servicios. Por ejemplo servicio de
HTTP, de Telnet, de FTP, de SMTP, etc. Cada uno de estos procesos tiene una direccin que lo identifica
unvocamente respecto de los otros. Esta direccin se llama PORT.
Generalmente el servicio de HTTP se brinda en el port 80, el de Telnet en el 23, FTP en el 21 y SMTP en
el 25. Decimos entonces que un PORT es una direccin relativa. Identifica al proceso pero no identifica
al host en el que corre dicho proceso.
En una red TCP/IP como Internet cada host tiene una identificacin nica llamada nmero IP.
Un SOCKET es un nmero IP + un PORT. Por lo tanto es una direccin absoluta ya que identifica
unvocamente un proceso en toda la red.

61
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
SERVER CLIENTE
ServerSocket

accept()

Socket Socket

InputStream OutputStream
OutputStream InputStream

close close

Veamos como programar un cliente.

SimpleClient.java
import java.net.*;
import java.io.*;
public class SimpleClient
{
public static void main(String args[]) throws Exception
{
Socket s1=new Socket(127.0.0.1, 5432);
ObjectInputStream ois;
ois=new ObjectInputStream(s1.getInputStream());
String s=(String)ois.readObject();
El cliente abre un
ois.close(); InputStream. El server
s1.close(); abrir un OutputStream

System.out.println( s );
}
}

API java.net.Socket
public Socket(String hostname, int port)
public InputStream getInputStream()
public OutputStream getOutputStream()
public InetAddress getInetAddress()
public void setSoTimeout(int millis)
public String getInetAddress().getHostAddress()
public String getInetAddress().getHostName()

62
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
API java.io.ObjectInputStream
public ObjectInputStream(InputStream is)
public Object readObject()

API java.io.ObjectOutputStream
public ObjectOutputStream(OutputStream os)
public void writeObject(Object obj)

Veamos ahora como programar el servidor.

SimpleServer.java

import java.net.*;
import java.io.*;

public class SimpleServer


{
public static void main(String args[]) throws Exception
{
int port=5432;
int queve=10;

ServerSocket ss=new ServerSocket( port,queve );


Socket s1;
ObjectOutputStream oos; El programa se bloquea aqu y
continua cuando el cliente
while( true ) establece la conexin. Como
{ resultado de accept() tenemos
el socket para estar mano a
try mano con el cliente.
El server abre un
{
OutputStream (el s1=ss.accept();
cliente abri un oos=new ObjectOutputStream( s1.getOutputStream() );
InputStream) oos.writeObject( Hola NET Mundo);
oos.close();
s1.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
}

63
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Vamos a modificar el cliente y el servidor para que el dialogo sea ida y vuelta.

Modificacin en el Cliente
Socket s1=new Socket(127.0.0.1,5432);

ois=new ObjectInputStream(s1.getInputStream());
oos=new ObjectOutputStream(s1.getOutputStream());
Primero abre el InputStream y
String s=(String)ois.readObject(); luego el OutputStream.
System.out.println( s ); El server lo har al revs

oos.writeObject(GRACIAS SERVER !);

oos.close();
ois.close();
s1.close();

Modificacin en el Server
Socket s1=ss.accept();

oos=new ObjectOutputStream( s1.getOutputStream() );


ois=new ObjectInputStream( s1.getInputStream() );
oos.writeObject(Hola NET MT Mundo !!!);
Primero abre el OutputStream
String s=(String)ois.readObject(); y luego el InputStream.

ois.close();
oos.close();
s1.close();
System.out.println( s );

Como vemos, el cliente y el servidor deben estar perfectamente sincronizados. Si el cliente abre un
InputStream entonces el servidor debe abrir un OutputStream y si luego el cliente abre un OutputStream
el servidor debe abrir un InputStream.
Para cerrar los streams se deben tener en cuanta la misma consideracin. Si el cliente cierra el
InputStream entonces el server debe cerrar el OutputStream y biseversa.

SERVIDOR MULTITHREAD

Veremos ahora como modificar el servidor para hacerlo multithread.

64
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
SimpleServerMT.java
import java.net.*; El server ahora ser un Thread
import java.io.*;

public class SimpleServerMT extends Thread


{
Variables de instancia.
private ObjectInputStream ois;
Mantienen diferentes
private ObjectOutputStream oos; valores para cada instancia.
private Socket s1;

public SimpleServerMT(Socket s)
{
s1=s;
}
public static void main(String args[]) throws Exception
{
int port=5432;
int queve=10;

ServerSocket ss=new ServerSocket( port,queve );


Socket socket;
Cada cliente que llega lo derivo a una
while( true ) nueva instancia de SimpleServerMT
{ pasndole el socket para que pueda
try establecer el dialogo con el cliente.
{
socket=ss.accept();
( new SimpleServerMT(socket) ).start();
}
catch(Exception ex)
{
ex.printStackTrace(); start() llama a run().
}
}
}

65
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
public void run()
{
try
{
oos=new ObjectOutputStream( s1.getOutputStream() );
ois=new ObjectInputStream( s1.getInputStream() );
oos.writeObject(Hola NET MT Mundo !!!);
String s=(String)ois.readObject();
ois.close();
oos.close();
s1.close();
System.out.println(s);
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}

Para probar que efectivamente el servidor atiende concurrentemente los requerimientos de los diferentes
cliente se van conectando le haremos una pequea modificacin al cliente para que espere un tiempo
entre la lectura del Hola Mundo y la escritura del Gracias Server.
Primero dispararemos un cliente que demore 20 segundos y luego dispararemos un cliente que demore 3
segundos. Si el segundo cliente es despachado antes que el primero habremos probado que el servidor los
atendi concurrentemente, y mientras una instancia del server esta ocupada con el primer cliente que
demora 20 segundos, la otra se ocupo de despachar al segundo cliente que solo se tomo 3 segundos.

Modificacin en el Cliente
Socket s1=new Socket(127.0.0.1,5432);
ois=new ObjectInputStream(s1.getInputStream());
oos=new ObjectOutputStream(s1.getOutputStream());
// LEE
String s=(String)ois.readObject();
System.out.println( s );
// DUERME
Thread.sleep( Integer.parseInt(args[0]) );

// ESCRIBE
oos.writeObject(GRACIAS SERVER !);
oos.close();
ois.close();
s1.close();

66
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
COMPILACION Y CORRIDA

c:\> javac *.java Como argumento recibe la


cantidad de milisegundos que
c:\> start java SimpleServerMT demorara la comunicacin
c:\> start java SimpleClient 20000 con el server
c:\> start java SimpleClient 3000

APLICACION CHAT (Version 1)

Este es un buen momento para desarrollar una aplicacin que combine todos los temas analizados. La
aplicacin Chat utiliza interface grfica, multithread y networking en un esquema cliente-servidor.

Cliente: se acciona cuando se


presiona [ENTER] sobre el
TextField. El mensaje ser
enviado al host que se indique
en el Choice.

Server: est constantemente


escuchando los mensajes que
recibe y los muestra en el List

Esta aplicacin podemos desarrollarla fcilmente copiando y pegando cdigo de las clases
SimpleClient y SimpleServer desarrolladas anteriormente.
Cuando se presiona [ENTER] sobre el TextField (actionPerformed()) se debe enviar un mensaje al host
indicado en el Choice y con el texto que contenga el TextField. Esto simplemente implica crear un
Socket, crear un ObjectOutputStream, aplicarle writeObject() con el texto del TextField, cerrar el
ObjectOutputStream y cerrar el Socket.

Para implementar el server que reciba los mensajes debemos tener en cuanta que ya no tenemos el mtodo
main() a nuestra disposicin porque esta aplicacin. En esta aplicacin integra el cliente y el servidor por
lo tanto dicho mtodo solamente debe dedicarse a crear una instancia de la ventana.
Como el server debe estar continuamente recibiendo mensajes (while(true)) debe ser un Thread.

Veamos la solucin.

67
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
JChat.java Otra manera de manejar Threads.
Una instancia de Runnable
import java.awt.*; puede utilizarse para crear un
import java.awt.event.*; Thread.
import java.io.*; El mtodo run() esta definido en
import java.net.*; esta interface.
public class JChat extends Frame implements Runnable
{
private TextField tf;
private List lst;
private Choice ch;
public JChat(String hosts[])
{
super("JChat");
Panel pnorth=new Panel(new BorderLayout());
pnorth.add( new Label("Mensaje"), BorderLayout.WEST );
pnorth.add( tf=new TextField(), BorderLayout.CENTER );
tf.addActionListener( new EscuchaSend() );
ch=new Choice(); En lnea de comandos se
for( int i=0; i<hosts.length; i++ ) reciben todos los hostname
{ que participan en el chat.
ch.addItem(hosts[i]);
}
pnorth.add( ch, BorderLayout.EAST );
Disparo un Thread cuyo
add( pnorth, BorderLayout.NORTH ); mtodo run() ser en que se
add( lst=new List(), BorderLayout.CENTER ); define a continuacin. En
dicho mtodo se
( new Thread(this) ).start();
implementa el servidor de
addWindowListener( new EscuchaCerrar() ); recepcin de mensajes.
setSize(470,280);
setVisible(true);
}

private void _addLine(String line) {


lst.add(line);
lst.select( lst.getItemCount()-1 );
}

public static void main(String args[])


{
String hosts[];
if( !(args.length>0) )
{
hosts=new String[1];
hosts[0]="localhost";
}
else
{
hosts=args;
}

new JChat(hosts);
}

68
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Este mtodo viene de la interface
public void run()
Runnable.
{
try
{
ServerSocket ss=new ServerSocket( 5432,10 );
Socket s1;
ObjectInputStream ois; Notemos la similitud con
String mssg; el SimpleServer.
String hostfrom;
while( true )
{
s1=ss.accept();
ois=new ObjectInputStream( s1.getInputStream() );

// leo el ip o hostname de quien me envia el mensaje


hostfrom=s1.getInetAddress().getHostName();
// leo el mensaje
mssg=(String)ois.readObject();
ois.close();
s1.close();
_addLine("["+hostfrom+" dice] -> "+mssg);
}
}
catch(Exception ex)
{
_addLine( "ERROR:"+ex.getMessage() );
ex.printStackTrace();
}
}
class EscuchaSend implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
try {
String mssg=tf.getText().trim();
String host=ch.getSelectedItem();
// envio el mensaje
Socket s1=new Socket( host,5432 );
ObjectOutputStream oos;
oos=new ObjectOutputStream( s1.getOutputStream() );
oos.writeObject( mssg );
oos.close();
s1.close();
_addLine( "[para "+host+" ] -> "+mssg);
tf.selectAll();
tf.requestFocus();
}
catch(Exception ex) {
_addLine( "ERROR:"+ex.getMessage() );
ex.printStackTrace();
}
}
}

69
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
class EscuchaCerrar extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{
setVisible(false);
dispose();
System.exit(0);
}
}
}

La versin anterior no puede utilizarse como applet para chatear en Internet. El problema principal que
presenta es que establece conexiones directas entre diferentes hosts. Recordemos que una de las
restricciones que se le imponen a los applets es la imposibilidad de conectarse a otro host que no sea el
host desde donde llego. Adems, la versin anterior utiliza un ServerSocket, caracterstica tambin
restringida a los applets.
En el apndice analizaremos una segunda versin valida para correr en Internet.

PROCESAMIENTO DISTRIBUIDO

Java acepta dos tecnologas para crear entornos de procesamiento distribuido:

RMI Remote Method Invocation


CORBA Common Object Request Broker Architecture

RMI permite distribuir objetos Java entre los diferentes host de la red.
CORBA provee un entorno heterogneo en el cual pueden convivir objetos programados en diferentes
lenguajes de programacin como ser Java, C, C++, Cobol, etc.

Con RMI un programa cliente puede invocar mtodos de un objeto ubicado en un server remoto. Esto le
brinda al programador la posibilidad de distribuir el procesamiento permitiendo que cada tarea se ejecute
en el host mas conveniente.

En un esquema RMI intervienen tres partes: el cliente, el servidor y la interface de mtodos que el
servidor publicara y que podrn ser invocados por el cliente.

Esquema RMI Remote Method Invocation


Interface
Define los mtodos del servidor visible para el cliente.
Debe extender java.rmi.Remote.
Todos los mtodos deben propagar RemoteException.
Server
Extiende java.rmi.server.UnicastRemoteObject.
Implementa la interface.
Publica su instancia con Naming.rebind().
Se deben generar las clases stub y skel (con rmic).
Se publica mediante el rmiregistry.
Cliente
Obtiene una referencia al server con Naming.lookup().
Invoca los mtodos publicados por el server a travs de la referencia obtenida

70
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
InterfaceRMI.java
import java.rmi.*;
public interface InterfaceRMI extends Remote
{
public String getDato() throws RemoteException;
}

SimpleServerRMI.java
import java.rmi.server.*;
import java.rmi.*;

public class SimpleServerRMI


extends UnicastRemoteObject
implements InterfaceRMI
{
public SimpleServerRMI() throws RemoteException {
super();
}

public String getDato() throws RemoteException{


return Hola Mundo RMI!!!;
}
public static void main(String argv[]) throws Exception {
SimpleServerRMI server=new SimpleServerRMI();
Naming.rebind(SERVIDOR, server);
}
}

SimpleClientRMI.java
import java.rmi.*;
public class SimpleClientRMI {
public static void main(String argv[]) throws Exception
{
String url=rmi://localhost/SERVIDOR;
InterfaceRMI remoto;
remoto=(InterfaceRMI)Naming.lookup( url );
String dato=remoto.getDato();
System.out.println( dato );
}
}

71
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
COMPILACION Y CORRIDA

c:\> javac *.java


c:\> rmic SimpleServerRMI Genera las clases Stub y Skel. Estas dos
c:\> dir clases encapsulan la comunicacin entre
el cliente y el servidor.
SimpleServerRMI_Skel.class
SimpleServerRMI_Stub.class
Rmiregistry es un proceso que brinda un
: servicio de nombres. Por default atiende en el
c:\> start rmiregistry port 1099.
c:\> start java SimpleServerRMI
c:\> java SimpleClientRMI
Hola Mundo RMI !!!
c:\>

S
K
S E
CLIENTE T L SERVER
RMI U E RMI
B T
O
N

72
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
10. ACCESO A BASES DE DATOS
JDBC API - Java Database Connectivity Application Programming Interface

JDBC provee una interface estndar para acceder a bases de datos relacionales. Mediante las clases
incluidas en el paquete java.sql se pueden ejecutar querys, updates, llamar a stored procedures y ejecutar
sentencias preparadas.

JDBC

ORACLE,
Programa JDBC INFORMIX,
Java otras...

.dbf
JDBC ODBC .txt
.xls

JDBC

Instancia el driver
Class.forName()

Obtengo una Connection


DriverManager

Creo un sentencia
Connection con

Statement stm

Luego de ejecutar una


stm.executeQuery() consulta obtengo un
ResultSet
Puedo obtener datos de
los datos Por ejemplo
cantidad de columnas ResultSet rs
del resultado

ResultSetMetaData rsmd

73
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
SimpleSelect.java
import java.sql.*;
public class SimpleSelect
{
public static void main(String args[]) throws Exception
{
String user= scott;
String passwd= tiger;
String driver=oracle.jdbc.driver.OracleDriver;
String url=jdbc:oracle:thin:@localhost:1521:orcl;
// para acceder a ODBC se deben utilizar estas lineas
// String driver=sun.jdbc.odbc.JdbcOdbcDriver;
// String url=jdbc:odbc:DATA_SOURCE_NAME;
Class.forName(driver);
Connection con=DriverManager.getConnection(url,user,passwd);
Statement stmt=con.createStatement();
String query= SELECT * FROM dept;
ResultSet rs=stmt.executeQuery(query);
ResultSetMetaData rsmd=rs.getMetaData();
int cantCols=rsmd.getColumnCount();
String campoi;
En SQL todos los ndices
boolean more=rs.next(); comienzan desde 1.
while( more )
{
for( int i=1; i <= cantCols; i++ )
{
campoi=rs.getString(i);
System.out.print(campoi+((i<cantCols)?, : ));
}
System.out.println();
more=rs.next();
}
rs.close();
stmt.close();
con.close();
}
}

74
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
API java.sql.ResultSetMetaData
public int getColumnCount()
public String getColumnLabel(int columnindex)
public String getColumnName(int columnindex)
public int getColumnType(int columnindex)

API java.sql.Statement
public ResultSet executeQuery(String sqlquery)
public int executeUpdate(String sqlupdate)

SimpleUpdate.java
import java.sql.*;

public class SimpleUpdate


{
public static void main(String args[]) throws Exception
{
:
Class.forName(driver);
Connection con=DriverManager.getConnection(url,user,passwd);

Statement stmt=con.createStatement();
String update= args[0];
int rtdo=stmt.executeUpdate(update);

if( rtdo > 0 )


{
System.out.println(rtdo+ filas tocadas);
}

stm.close();
con.close();
}
}

API java.sql.Connection
JDBC por default tiene
public void commit() setAutoCommit()=true.
public void rollback()
public void setAutoCommit(boolean b)
public CallableStatement prepareCall(String prepcall)
public PreparedStatement prepareStatement(String prepstm)

75
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
SimplePrepared.java
import java.sql.*;

public class SimplePrepared


{
public static void main(String args[]) throws Exception
{
:
String sprep=;
sprep+= UPDATE dept set dname=pp ;
sprep+= WHERE deptno > ? ;
sprep+= AND deptno < ? ;

PreparedStatement pstm;
pstm=con.prepareStatement(sprep);
pstm.setInt(1,10);
pstm.setInt(2,50);
pstm.execute();

pstm.close();
:
}
}

API java.sql.PreparedStatement
public void setInt(int index, int intvalue)
public void setString(int index, String stringvalue)
public void setNull(int index, int sqltype)
public boolean execute()
public ResultSet executeQuery()
public int executeUpdate()

76
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
11. GENERACION DINAMICA DE PAGINAS WEB
El desarrollo de software tiende a que cada vez la capa de presentacin (para sistemas basados en web)
sea mas liviana. En lo posible se busca que sea solo texto HTML. Si bien los applets son extremadamente
livianos, resultan demasiado pesados comparados con texto HTML.
Las soluciones Java para la generacin dinmica de pginas web son:

Java Servlets
Java ServerPages

Los servlets son programas Java con un ciclo de vida comparable al de un applet pero corriendo del lado
del servidor. Un servlet es semejante a un programa CGI: recibe un requerimiento HTTP y devuelve una
respuesta HTTP. Pero aqu termina la comparacin. A diferencia de los CGI que expanden un nuevo
proceso de sistema operativo los servlets se desarrollan a travs de threads, que son ms livianos y
consumen menos recursos, y al ser programas Java son totalmente independientes de la plataforma.

JSP combina HTML o XML con cdigo Java que utiliza para generar dinmicamente partes de la pgina.
Las pginas JSP se compilan en servlets. Son un nivel mas alto de programacin que los servlets y
permiten fcilmente separar la lgica de presentacin de la lgica de la aplicacin.

JAVA SERVLETS

Veamos un HolaMundoServlet para luego poder explicar su funcionamiento.

HolaMundoServlet.java
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HolaMundoServlet extends HttpServlet


{
public void doGet( HttpServletRequest request ,HttpServletResponse response )
throws ServletException,IOException
{
response.setContentType(text/html);
PrintWriter out = new PrintWriter ( response.getOutputStream() );
out.println(<html>);
out.println(<body>); El objeto response encapsula la
respuesta que el servlet enviar al
out.println(<h1><center>);
browser. Todo lo que escribamos
out.println(HOLA MUNDO SERVLET !!!); mediante el objeto out
out.println(</h1></center>); (out=response.getWriter()) se enviara al
out.println(</body>); browser en forma de text/html
out.println(</html>); (response.setContentType(text/html)).
As, podemos generar dinmicamente el
out.close();
contenido de la pgina HTML.
}
}

77
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Para poder ejecutar este servlet necesitamos un web-server. Simplemente debemos copiar el .class al
directorio indicado (o configurado) para que residan los servlets y luego invocarlo desde un navegador
tipeando el URL correcto.

Bsicamente un servlet no es mas que una clase Java que implementa la interface Servlet. Muchas de las
tareas involucradas al responder a un requerimiento del cliente se resuelven automticamente. Por
ejemplo la multiprogramacin; los requerimientos concurrentes que surgen desde diferentes browsers
sobre el mismo servlet son derivados en threads.

As como un applet corre dentro del contexto del Web Browser, el Servlet corre dentro del contexto del
Servlet Engine (implementado por el web-server). Tanto el Browser como el Servlet Engine tienen una
Maquina Virtual Java corriendo continuamente. A diferencia de los applets, los servlets no usan ningn
tipo de interface grfica, como las clases del paquete java.awt pero tienen un acceso total al resto de la
API Java: JDBC, RMI, Sockets, Serializacin de Objetos, estructuras de datos como Vectores,
Hashtables, etc.

HTTP Servlets

En general nuestros servlets extendern a la clase HTTPServlet, que implementa la interface Servlet.
Heredando de esta clase los servlets adquieren una mayor funcionalidad. Por ejemplo se tiene fcil
acceso a los parmetros (GET o POST) pasados desde el browser al web-server. Similarmente, la salida
del servlet (pgina HTML generada dinmicamente) es enviada al Browser.

78
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
HolaMundoServlet2.java
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;

public class HolaMundoServlet2 extends HttpServlet


{
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType(text/html);
PrintWriter out = new PrintWriter (response.getOutputStream());
out.println(<html>);
out.println(<body>);
String sname=request.getParameter(nombre);
if( sname==null)
{
out.println(Ingrese su Nombre:);
out.println(<form method=\"GET\" action=\"http://192.168.4.1:8080/servlet/HolaMundoServlet2\">);
out.println(<input type=\TEXT\ name=\nombre\>);
out.println(<input type=\submit\ value=\Enviar\>);
out.println(</form>);
}
else
{
out.println(<h1><CENTER> HOLA MUNDO +sname);
}
out.println(</body>);
out.println(</html>);
out.close();
}
}

En el primer requerimiento a este servlet (invocndolo as: http://192.168.4.1:8080/servlet/HolaMundoServlet2 no


se le pasa ningn parmetro por lo tanto sname ser null. La salida ser una pgina (generada
dinmicamente) con un formulario cuyo procesamiento estar a cargo de este mismo servlet.
Al presionar el botn Enviar se vuelve a invocar al servlet pero pasndole el parmetro nombre. Por lo
que ahora sname no ser null y la salida generada dinmicamente ser un Hola Mundo personalizado.

El resultado es el que se muestra a continuacin.

79
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Aspectos Principales de los Servlets

El servlet se instancia una sola vez. Si recibe mltiples requerimientos simultneos sern delegados en
threads. El servlet engine mantiene una nica instancia de la clase resultando as un efecto de
persistencia de las variables de instancia. Mltiples requerimientos corrern en threads pero sobre la
misma instancia.

Contador1.java
public class Contador1 extends HttpServlet
{
private int contador=0;
public void doGet(
HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter out = new PrintWriter (response.getOutputStream());
out.println("<html>");
out.println("<body> Contador="+contador++);
out.println("</body></html>");
out.close();
}
}

El valor del contador se ira incrementando


cada vez que se presione refresh. Si desde
otro navegador se accede al mismo servlet el
contador continuara con su valor (no se
inicializar en 0) ya que mltiples
requerimientos son servidos con la misma
instancia del servlet.

80
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Ciclo de vida de un Servlet

El servlet tiene un ciclo de vida similar al de un Applet. Cuando es instanciado se le ejecuta el mtodo
init(). Mientras esta activo se ejecutaran sus mtodos doGet() o doPost() segn el mtodo HTTP que se
este utilizando. Por ltimo, cuando muere se ejecuta el mtodo destroy().
El servlet engine llama al mtodo destroy() cuando finalizaron todas las llamadas al mtodo service() o
bien al cabo de un cierto periodo de tiempo.

En principio podemos decir que el mtodo init() es un buen momento para tomar recursos tales como una
conexin la una base de datos, y que el mtodo destroy() es un buen momento para dejarlos. El problema
es que los diferentes requerimientos (muy posiblemente concurrentes) que le llegan al servlet son
manejados como threads sobre la misma instancia. Por lo tanto manejar un objeto de tipo Connection
(por ejemplo) como variable de instancia no es una buena idea. Recordemos que en la clase Connection
tenemos los mtodos commit() y rollback(). No habra problemas si solo utilizamos la conexin para
realizar consultas, pero si pretendemos realizar transacciones estaramos en un caso no thread safe
(inseguro para manejo de threads). Es decir: un thread podra estar insertando filas en diferentes tablas y
otro podra estar ejecutando el mtodo commit() simultneamente.

SingleThreadModel

Implementando esta interface (que no tiene mtodos) nos aseguramos de que el servlet manejar solo un
requerimiento a la vez. Java nos garantiza que no habr mas de un thread ejecutando el mtodo service()
del servlet a la vez. El servlet engine mantiene un pool de instancias del servlet y a cada requerimiento
concurrente le asigna una instancia distinta. Implementando esta interface el servlet ser thread safe.
Sin embargo no se resuelve el problema del acceso a los recursos comunes a todas las instancias como ser
las variables y mtodos estticos.

TestThread.java
public class TestThread extends HttpServlet implements SingleThreadModel
{
private static int continstancias=0; El servlet engine asignara una nueva
instancia del servlet para cada nuevo
public TestThread() requerimiento concurrente sobre el
{ mtodo service().
continstancias++;
} Cada vez que se cree una instancia
de esta clase incrementamos el
public void finalize() valor del contador
{
continstancias--; Cada vez que se elimine una
} instancia decrementamos el contador

public void doGet(HttpServletRequest request, HttpServletResponse response)


throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter out = new PrintWriter (response.getOutputStream());
out.println("<html>");
out.println("<body>");

81
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
String sdormir=request.getParameter(dormir);
if( sdormir==null)
{
out.println(Dormir (milisegundos):);
out.println(<form method=\"GET\" action=\"http://192.168.4.1:8080/servlet/TestThread\">);
out.println(<input type=\TEXT\ name=\dormir\>);
out.println(<input type=\submit\ value=\Enviar\>);
out.println(</form>);
}
else Duermo por sdormir milisegundos y
{ muestro el valor del contador.
try
{
Thread.sleep( Integer.parseInt(sdormir) );
out.println("<h1><CENTER> Cantidad de
instancias:"+continstancias+"</center></h1>");
}
catch( Exception ex)
{
ex.printStackTrace();
}
}
out.println("</body>");
out.println("</html>");
out.close();
}
}

Para probar este servlet debemos seguir los siguientes pasos:

1. Abrir el browser e invocar al servlet con una pequea cantidad de milisegundos. Veremos que el
contador esta en 1.
2. Recargar la pgina. Veremos que el contador sigue en 1. Esto quiere decir que no se creo una nueva
instancia. Evidentemente no fue necesario ya que hasta ahora no tuvimos requerimientos
concurrentes sobre el servlet.
3. Abrir otro browser e invocar al servlet con 30000 milisegundos (30 segundos). Mientras tanto en el
browser anterior vamos a invocar al servlet con 2000 milisegundos. Ahora si tendremos
requerimientos concurrentes. Veremos que el valor del contador se incremento.
4. Si abrimos otro browser y probamos con tres requerimientos concurrentes veremos que el servlet
engine creara una nueva instancia.

Al implementar la interface SingleThreadModel solucionamos el problema de thread safe pero


acarreamos otros problemas. Si bien ahora podramos tener una Connection a nivel de instancia, crearla
en el init() y cerrarla en el destroy(), estaramos ante una solucin no escalable: es decir que a medida
que se incrementen los requerimientos sobre nuestro servlet la performance caer notablemente.
Supongamos que en un momento llegan 1000 requerimientos simultneamente; tendremos 1000
instancias del servlet y por lo tanto 1000 conexiones a la base de datos.
Como programadores no tenemos el control de la cantidad de instancias que el servlet engine creara y por
lo tanto en la mayora de los casos no es una buena solucin implementar esta interface.

82
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
JAVA SERVER PAGES

Una pgina JSP permite combinar cdigo de marcacin como HTML o XML con lenguaje Java. En
principio, renombrando cualquier pgina .html como .jsp tenemos nuestra primer pgina JSP.

HolaMundo.jsp Los Scriptles permiten


embeber cdigo Java
<HTML>
<BODY>
<H2>Esto es una pgina JSP !!!</H2> <P>
<% out.println(HOLA MUNDO !!!); %> </P>
</BODY>
</HTML>

La pgina JSP reside en el web-server. Cuando se invoca por primera vez se genera como servlet, se
compilada y se instancia. Luego tiene un ciclo de vida anlogo al de los servlets. De hecho, es en servlet.

El siguiente ejemplo, al ser invocado muestra una pgina con los primeros 10 nmeros naturales.

Ejemplo2.jsp
out es uno de los objetos implcitos
<HTML> de los que disponemos dentro de los
<BODY> <center> <h1> scriptles.
Representa el PrintWriter out que
<% utilizamos en los servlets.
for( int i=0; i<10;i++)
{ Los objetos implcitos que existen
out.println( i + <br>); dentro de los scriptles son: request,
} response, out, exception y session
%>
</BODY> </center> </h1>
</HTML>

83
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
A continuacin veremos la versin JSP del servlet HolaMundoServlet2 que analizamos anteriormente. El
resultado es exactamente el mismo, pero el cdigo es mucho mas corto y mas simple.

HolaMundoJSP2.jsp
Declaraciones: permiten definir
<HTML> variables Java para utilizarlas a lo
largo de la pgina.
<BODY>
<%! String snombre; %> Request, otro de los objetos implcitos en los scriptles

<% snombre=request.getParameter(nombre); %>


Utilizo un scriptlet para
tomar una decisin
<% if( snombre == null ) { %>
Ingrese su Nombre
<form method=GET action=http://192.168.4.1:7070/HolaMundoJSP2.jsp>
<input type=TEXT name=nombre>
<input type=submit value=Enviar>
</form>
<% } else { %>
<h1><CENTER> HOLA MUNDO <%=snombre%> </center></h1>
<% } %>
Las expresiones permiten utilizar el
</BODY> valor string de las variables.
</HTML>

En este ejemplo estamos utilizando declaraciones, expresiones y scriptles. Son algunas de las
posibilidades que nos brinda JSP.

Marca Comentario

Declaraciones <%! ... %> Permiten definir variables Java para utilizarlas a lo largo de la pgina.

Permiten embeber cdigo Java para generar contenidos dinmicos.


Scriptles <% ... %>
Podemos utilizar toda la API Java incluyendo JDBC.
Dentro del scriptlet disponemos de 5 objetos implcitos
que detallaremos luego.

Expresiones <%= ... %> Permiten visualizar como texto el valor de una variable.

Pueden ser tipo include o page. Las primeras permiten incluir el


Directivas <%@ ... %>
contenido de otros archivos. Por ejemplo incluir una pgina .html, una
pgina .jps o bien un archivo de texto.
Con la directivas de pgina podemos especificar parmetros de la
pgina. Con estas directivas podemos importar cualquier paquete de la
API Java. Por ejemplo java.util, java.sql, etc.

JSP Y JavaBeans

El problema de los Servlets es que mezclan dos lenguajes: Java y HTML. Un diseador grfico no puede
escribir un servlet porque no tiene los conocimientos necesarios de Java. Anlogamente un programador
Java se ve limitado a la hora de escribir un servlet porque (muy probablemente) no tenga los
conocimientos necesarios de HTML y/o de diseo grfico para poder generar la salida del servlet.
JSP soluciona este problema permitiendo utilizar JavaBeans.

84
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
Un JavaBean (o simplemente un Bean) es un componente Java que encapsula cierta lgica de
programacin. Desde el punto de vista del programador, un bean no es mas que una clase Java que
respeta las convenciones de nomenclatura que explicamos en el capitulo programacin orientada a
objetos. Es decir:

El nombre de la clase debe comenzar con mayscula.


Los mtodos deben comenzar con minscula pero cada inicial subsiguiente con mayscula.
Para un atributo x de la clase se debe definir un mtodo setX() y un getX().
Debe existir un constructor que no reciba parmetros.

Cualquier clase Java que cumpla con estas condiciones pueden considerarse un Bean.

BeanCount.java
Como podemos ver no tiene
public class BeanCount absolutamente nada nuevo. Es
{ una clase como cualquier otra.
private int contador=0;
public int getContador()
{
return ++contador;
}
public void setContador(int c)
{
contador=c;
}
}

Para el bean anterior, cada vez que se le requiera la propiedad contador (mediante el mtodo
getContador()) retornara el valor incrementado del contador.
Veremos ahora como desde una pgina JSP se puede utilizar este bean sin tener que escribir ni una sola
lnea de cdigo Java.
Los posibles alcances son:
TestBean.jsp application, session, request
y page
<html>
<body>
<jsp:useBean id= mibean scope=session class=BeanCount/>
<jsp:setProperty name=mibean property=contador value=0 />
<h1><center>
<jsp:getProperty name=mibean property=contador />
</center></h1>
</body>
</html>

Como vemos, separamos totalmente la lgica de la aplicacin de la lgica de presentacin. Esto permite
maximizar la productividad ya que cada desarrollador puede concentrarse en lo suyo. El programador
Java solo trabaja con cdigo Java. El programador HTML solo trabaja con cdigo HTML.

85
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
A continuacin analizaremos los tags useBean, setProperty y getProperty.

<jsp:useBean id= mibean scope=session class=BeanCount/>

Nombre de la instancia. Duracin o alcance de Clase que se deber


Cuando utilizamos el tag la instancia. En este caso instanciar. (Si estuviera
useBean en realidad lo que mientras dure la sesin, la empaquetada sera
estamos haciendo es instancia del bean ser la paquete.classname)
generar una instancia de la misma y mantendr las
clase indicada en el propiedades que se le
parmetro class hayan asignado. En
nuestro ejemplo ser el
valor del contador.

<jsp:setProperty name=mibean property=contador value=0 />

Instancia a la que le Propiedad a la cual vamos a asignarle un


asignaremos la propiedad. valor. Obviamente en este ejemplo no era
necesario asignar ningn valor porque el
contador se inicializ en cero.

<jsp:getProperty name=mibean property=contador />

Nombre de la instancia Propiedad que queremos


(asignado en el tag displayar. Recordemos que
useBean). existe el mtodo getContador()

El siguiente ejemplo muestra como utilizando JSP, un programador HTML puede generar contenidos
dinmicos, accediendo a una base de datos sin conocer en detalle Java.

86
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
TestSQL.jsp
<html>
<body>
<jsp:useBean id=misql scope=session class=BeanSQL/>
<jsp:setProperty name=misql property=query value=select * from emp/>
<table border="2">
<% for( int i=0; i<misql.getCantFilas(); i++ ) { %>
<tr>
<% for( int j=0; j<misql.getCantColumnas(); j++ ) { %>
<td> <%= misql.getCelda(i,j) %> </td>
<% } %>
</tr>
<%} %>
</table>
</body>
</html>

Otra posibilidad de lograr exactamente el mismo resultado sera la siguiente.

TestSQL.jsp (versin 2)
<html>
<body>
<jsp:useBean id=misql scope=session class=BeanSQL/>
<jsp:setProperty name=misql property=query value=select * from emp/>
<%
for( int i=0; i<misql.getCantFilas(); i++ )
{
out.println(<table border=2>)

out.println(<tr>);
for( int j=0; j<misql.getCantColumnas(); j++ )
{
out.println(<td> + misql.getCelda(i,j) + </td>);
}
out.println(</tr>);
}
out.println(</table>);
%>
</body>
</html>

87
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
El resultado que obtenemos al invocar esta pgina es el siguiente.

Veamos ahora la clase BeanSQL.

BeanSQL.java
import java.sql.*;
import java.util.Vector;
public class BeanSQL
{
private Connection con=null;
private String query=null;
private int cantColumnas;
private Vector vResultado;
public BeanSQL() throws Exception
{
String url=jdbc:oracle:thin:@localhost:1521:oracl;
String user=scott;
String password=tiger;
String driver=oracle.jdbc.driver.OracleDriver;
Class.forName(driver);
con=DriverManager.getConnection(url,user,password);
}
public String getQuery() throws Exception { return query; }
public int getCantColumnas() { return cantColumnas; }
public int getCantFilas() { return vResultado.size(); }
public String getCelda(int f,int c) { return ((String[])vResultado.elementAt(f))[c]; }

88
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
public void finalize()
{
try{
con.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
public void setQuery(String q) throws Exception
{
query=q;
_ejecutar();
}
private void _ejecutar() throws Exception
{
vResultado=new Vector();
Statement stm=con.createStatement();
ResultSet rs=stm.executeQuery(query);
ResultSetMetaData rsmd=rs.getMetaData();
int cantCols=rsmd.getColumnCount();
cantColumnas=cantCols;
String reg[];
boolean more=rs.next();
while( more )
{
reg=new String[cantCols];
for( int i=1; i<=cantCols; i++ )
{
reg[i-1]=rs.getString(i);
}
vResultado.addElement(reg);
more=rs.next();
}
rs.close();
stm.close();
}
}

89
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
APENDICE SQLJ
SQLJ Cdigo SQL embebido en cdigo Java

Con SQLJ podemos embeber directamente cdigo SQL en el cdigo Java. Los archivos deben ser .sqlj.
El SQLJ translator precompila el archivo .sqlj generando un archivo .java con sentencias JDBC. Luego
se compila normalmente para obtener el .class.

ClassName.sqlj ClassName.java ClassName.class

Clase java con cdigo


Clase Java con Clase con formato
JDBC, generado
cdigo .class compilada
automticamente por el
SQL embebido normalmente.
procesador SQLJ.

SimpleSQL.sqlj
import sqlj.runtime.*;
import sqlj.runtime.ref.*;
import oracle.sqlj.runtime.*;
import java.sql.*;
public class SimpleSQL
{
public static void main(String args[]) throws Exception
{
String url="jdbc:oracle:thin:@localhost:1521:pablo";
String driver="oracle.jdbc.driver.OracleDriver";
String user="scott";
String passwd="tiger";
Class.forName(driver);
Connection con; con=DriverManager.getConnection(url,user,passwd);
String sname;
Especifica el contexto contra
Oracle.connect(con); el que se ejecutaran las
sentencias SQL
#sql { SELECT ename
INTO :sname
FROM emp
WHERE empno=7369 };
con.close();
System.out.println(sname);
}
}

90
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
COMPILACION Y CORRIDA
c:\> sqlj SimpleSQL.sqlj
The system detects that Oracle was installed under dir
D:\Oracle\Ora81
If it is correct, enter Y; Otherwise, enter N (Y/n) y
c:\> dir
SimpleSQL.class
SimpleSQL.java
SimpleSQL.sqlj
SimpleSQL_SJProfile0.ser
SimpleSQL_SJProfileKeys.class

JDBC SQLJ
Ventajas No requiere Cdigo muy simple.
precompilador. Puede precompilar verificando on-
Acepta SQL dinmico. line la consistencia del cdigo
contra la base de datos.

Desventajas Ms complicado. No permite SQL dinmico.


Requiere conocer bien Debe ser precompilado.
la API.

SQLJ permite verificar en tiempo de compilacin la sintaxis, la semntica y la consistencia de los


nombres de campos, nombres de tablas, etc. De esta forma se puede detectar en tiempo de compilacin
errores que generalmente son solo detectables en tiempo de ejecucin.

COMPILACION Y CORRIDA 2
c:\> sqlj user scott/tiger SimpleSQL.sqlj
SimpleSQL.sqlj:21.5-23.38: Warning: Unable to check WHERE clause. Error returned
by database is: ORA-00904: nombre de columna invlido

UPDATE
#sql { UPDATE emp SET sal=3000 WHERE ename= SCOTT };
#sql { COMMIT };

SELECT Y UPDATE
String name= SCOTT;
Double raise=new Double(1.08);
Double salary;
#sql { UPDATE emp SET sal=sal* :raise WHERE ename= :name };
#sql { SELECT sal INTO :salary FROM emp WHERE ename=:name};

91
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
EXPRESIONES JAVA CON SQL

String emps[]={ Scott, Miller, King };


double raises= { 1.10, 1.05 , 1.0 };

for( int i=0; i<emps.length; i++ )


{
#sql { UPDATE emp SET sal=sal* :(raises[i])
WHERE ename=:(emps[i].toUpperCase()) };
}

double []s=new double[emps.length];


int j=0;

while( j<emps.length )
{
#sql { SELECT sal INTO :(s[j]) FROM emp
WHERE ename=:(emps[j].toUpperCase()) };
}

FUNCIONES DE LA BASE DE DATOS


java.sql.Date today;
#sql today={ VALUES(SYSDATE) };
System.out.println(La base de datos dice que hoy es:+today.toString());

String en10dias;
#sql en10dias={ VALUES( DELTA_DATE(:today,10) ) };
System.out.println(y dentro de 10 dias sera:+en10dias);

STORED PROCEDURES
int x=10, y, z=20;
#sql { CALL MyProc( :x, :OUT y, :INOUT z) };

92
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar
CURSORES
#sql iterator NamedIterator(String ename,Double sal);
NamedIterator n;
#sql n = { SELECT ename, sal FROM emp };
while( n.next() )
{
System.out.println( Nombre=+n.ename() + Salario=+n.sal());
}
n.close();

String pnombre=null;
Double psal=null;
#sql iterator MyCursor(String , Double );

MyCursor n;
#sql n={ SELECT ename,sal FROM emp };
while( true )
{
#sql { FETCH :n INTO :pnombre,:psal };
if( n.endFetch() )
{
break;
}
System.out.println(pnombre + + psal);
}
n.close();

93
Pablo Augusto Sznajdleder cel. 15-4419-JAVA (5282)
Ing. en Sistemas de Informacin Cert i f i ed Devel oper e.mail. pablosz@pablosz.com.ar

Anda mungkin juga menyukai