Sie sind auf Seite 1von 64

1. Orientacin a Objetos en Java 1.1. Introduccin a Java Java es un lenguaje de programacin desarrollado en los aos 90 por Sun Microsystems.

Su principal caracterstica es que se trata de un lenguaje multiplataforma, es decir, cualquier cdigo java puede correr sobre cualquier plataforma sin necesidad de introducir cambios ni recompilar el cdigo; dicho de otro modo; la portabilidad del cdigo Java es mxima (Write Once, Run Everywhere). Al compilar cdigo fuente java se obtiene cdigo neutro (bytescode) que debe ser ejecutado por una mquina virtual denominada Java Virtual Machine (JVM). Es la JVM quien interpreta el cdigo neutro y lo convierte a un cdigo ejecutable por la plataforma particular sobre la que est corriendo el programa java. As pues, toda la dependencia con la plataforma reside en la JVM; por lo que sta es distinta para cada plataforma. Por otro lado la JVM antes de interpretar cdigo neutro, somete a ste a un verificador el cual certifica que el cdigo es correcto, es decir, todos los bytescode se ajustan a la especificacin de la JVM, no se atenta contra la seguridad del sistema, no provoca desbordamiento de la pila, no se hacen conversiones de tipo no permitidas, etc: Todo esto da a la plataforma java gran robustez y seguridad. Todas estas verificaciones de cdigo hacen que la ejecucin se haga ms lenta y pesada; pero es imprescindible para garantizar un nivel de seguridad ptimo; a dems, estas operaciones slo se realizan en el momento que una clase es cargada en memoria, posteriormente, durante el uso de la clase, ya no son necesarias estas verificaciones de cdigo:

Cargador de clases

Verificador de cdigo Intrprete Ejecucin Generador de cdigo

Hardware
Como resumen, destacar que las dos caractersticas principales de java son la portabilidad y la seguridad.

En cuanto a los que se refiere a Orientacin a objetos, Java es un lenguaje orientado a objetos puro, es decir, todo cdigo java debe estar, necesariamente, encapsulado en una clase (la nica excepcin a esta regla son los tipo primitivos que no son objetos). 1.2. Clases y objetos en Java Una posible definicin de clase puede ser: Agrupacin de datos (atributos) y mtodos que operan sobre esos datos. Es la unidad de programacin en los lenguajes orientados a objetos:
public class MiClase { ... declaracin de atributos y mtodos }

Un objeto es una ocurrencia concreta de una clase. Se puede decir que una clase es un tipo de objeto. Para crear un objeto se debe usar el operador new seguido del nombre de la clase de la que se quiere crear un objeto:
MiClase unObjeto = new MiClase();

Toda clase pblica java debe escribirse en un fichero fuente java (archivo con extensin java) que se llame como la clase. Por ejemplo, la clase pblica MiClase debe estar contenida en un fichero llamado MiClase.java:
package misprogramas.utiles; import java.util.*; import java.io.PrintWriter; public class MiClase { ... declaracin de atributos y mtodos }

1.3. Miembro de una clase Java Los miembros de una clase Java los constituyen sus atributos o campos (estado del objeto) y sus mtodos (funciones para manipular/operar con el estado del objeto). 1.3.1. Variables miembros Las variables miembro de una clase Java son sus atributos o campos, es decir, los datos que contiene la clase. Los atributos de una clase pueden ser tipo primitivos (int, char, double...) o referencias a otros objetos. Dependiendo del mbito de visin de la variable miembro, sta se puede clasificar es: - Variable miembro pblica (public). Los atributos de este tipo pueden ser accedidos por cualquier otro objeto java. Por motivos de encapsulacin, no se recomienda declarar variables miembro pblicas, para evitar que otras clases accedan directamente a la estructura interna de la clase y con ello provocar una acoplamiento. - Variable miembro protegida (protected). Los atributos de este tipo pueden ser accedidos por cualquier clase que extienda de sta directa o indirectamente y por cualquier otra clase que pertenezca al mismo

paquete de la clase. Este tipo de mtodos son heredados mediante herencia. Variable miembro de mbito paquete (por defecto). Los atributos de este tipo slo pueden ser accedidos por las clases que pertenecen al mismo paquete Variable miembro privada (private). Los atributos de esta tipo slo pueden ser accedidos por la propia clase y sus inner class. Es el mbito de acceso ms restrictivo y el ms recomendable para conseguir un nivel del encapsulamiento adecuado.

Veamos un ejemplo de declaracin de atributos con diferentes mbitos de visin:


public class ClaseConAtributos { public String cadena; protected int numero; double decimal; //ambito paquete private boolean logico; }

Para acceder a los atributos de un objeto se debe usar el operador .:


ClaseConAtributos obj = new ClaseConAtributos(); obj.cadena = Java es un lenguaje de programacin;

Java inicializa todos los atributos que son referencia a objetos a nulo y los atributos que son tipos primitivos los inicializa a 0, menos el tipo boolean que lo inicialza a false. Dependiendo de si el atributo es propio para cada objeto o si todos los objetos de la misma clase comparten el atributos, podemos clasificar las variables miembro en: - Variable miembro de instancia. Cada objeto distinto tendr su propia copia de este atributo. A no ser que se especifique lo contrario, todos los atributos de una clase son variables miembro de instancia. - Variable miembro de clase. Todos los objetos de una clase comparten el atributo (atributo esttico). Para especificar que un atributo esttico se debe anteponer la palabra reservada static en la declaracin del atributo:
public class ClaseConAtributoEstatico { public static String cadena; }

Para acceder a un atributo esttico de una clase no es necesario crear un objeto de dicha clase, ya que el atributo existe aunque no exista ningn objeto; as pues, se debe usar el nombre de la clase para acceder a sus atributos estticos:
String s = ClaseConAtributoEstatico.cadena;

1.3.2. Mtodos miembros Todo el cdigo Java de una clase debe estar encapsulado en mtodos. Slo hay una excepcin a esto: los bloques estticos o iniciaizadores. Los bloques estticos son bloques de cdigo java que se ejecutan cuando la clase es cargada por la JVM y se utilizan, normalmente, para inicializar atributos estticos:
public class ClaseConBloqueEstatico { public static String cadena; static { cadena=Clase inicializada; } }

Dependiendo del mbito de visin del mtodo, ste se puede clasificar es: - Mtodo pblico (public). Los mtodos de este tipo pueden ser accedidos por cualquier otro objeto java. Constituyen la interfaz pblica de la clase, es decir, la forma con la que el resto de objetos se comunicar con los objetos de esta clase. - Mtodo protegido (protected). Los mtodos de este tipo pueden ser accedidos por cualquier clase que extienda de sta directa o indirectamente y por cualquier otra clase que pertenezca al mismo paquete de la clase. - Mtodo de mbito paquete (por defecto). Los mtodos de este tipo slo pueden ser accedidos por las clases que pertenecen al mismo paquete. Este tipo de mtodos no son heredados mediante herencia. - Mtodo privado (private). Los mtodos de este tipo slo pueden ser accedidos por la propia clase y sus inner class. Es el mbito de acceso ms restrictivo y el ms recomendable para conseguir un nivel del encapsulamiento adecuado. Veamos un ejemplo de declaracin de mtodos con diferentes mbitos de visin:
public class ClaseConMetodos{ public String obtenerCadena(int numCaracteres) { ... } protected int getNumero() { ... } //ambito paquete double convierteADecimal(String cadena, int numDecimales) { ... } private boolean estaCorrecto() { ... }

Para acceder a los mtodos de un objeto se debe usar el operador .:


ClaseConMetodos obj = new ClaseConMetodos (); String cadena = obj.obtenerCadena(10);

Dependiendo de si el mtodo es propio para cada objeto o si todos los objetos de la misma clase comparten el mtodo, podemos clasificar los mtodos en: - Mtodo de instancia. Cada objeto distinto tendr su propia copia de este mtodo. Slo este tipo de mtodo puede acceder a las varibles miembro de instancia, es decir, a los atributos no estticos. A no ser que se especifique lo contrario, todos los mtodos de una clase son mtodos miembro de instancia. - Mtodo de clase. Todos los objetos de una clase comparten el mtodo (mtodo esttico). Este tipo de mtodo slo puede accder a los atributos estticos. Para especificar que un mtodo es esttico se debe anteponer la palabra reservada static en la declaracin del mtodo:
public class ClaseConMetodoEstatico { public static String obtenerCadena(int numCaracteres) { ... } }

Para acceder a un mtodo esttico de una clase no es necesario crear un objeto de dicha clase, ya que el mtodo existe aunque no exista ningn objeto; as pues, se debe usar el nombre de la clase para acceder a sus mtodos estticos:
String s = ClaseConMetodoEstatico.ObtenerCadena(10);

1.3.2.1. Sobrecarga de mtodos El nombre de un mtodo ms el tipo y orden de los parmetros que recibe, constituye lo que se denomina signatura del mtodo. En Java, no pueden existir en la misma clase dos mtodos con las misma signatura; pero si pueden existir dos mtodos que se llamen igual pero varen en el nmero, en el tipo y/o en el orden de los parmetros. Y a esto es lo que se denomina sobrecarga de mtodos: mtodos que se llaman igual; pero los parmetros que reciben varan en nmero, tipo y/o orden. Ntese que en la definicin de sobrecarga no aparece el tipo de retorno del mtodo. Vamos un ejemplo en el que aparecen sobrecargas vlidas y no vlidas.
public class ClaseConSobrecarga{ public String obtenerCadena(int numCaracteres) { ... } public String obtenerCadena(int numCaracteres, String valorInicial) { ...

} public String obtenerCadena(String valorDefecto,int numCaracteres) { ... } //sobrecarga no vlida public StringBuffer obtenerCadena(String valorDefecto,int numCaracteres) { ... }

La ltima sobrecarga no es vlida porque ya existe un mtodo con ese nombre y parmetros, aunque el tipo de retorno sea distinto. 1.3.2.2. Constructores Al crear un objeto se invoca a un tipo especial de mtodo llamado constructor. Los mtodos constructores de una clase se deben llamar igual que la clase y no tienen tipo de retorno:
public class MiClase { public MiClase() { System.out.println(Mtodo constructor por defecto); } }

Toda clase debe poseer, al menos, un constructor. Si al codificar una clase no se le aade un constructor; el compilador de java le aade un constructor sin parmetros (constructor por defecto). Los constructores no pueden ser invocados directamente, son invocados por la JVM cuando se crea un objeto nuevo mediante el operador new: MiClase obj = new MiClase(); Los constructores deben ser usados para inicializar correctamente el objeto y deben recibir como parmetros toda la informacin necesaria para su correcta inicializacin. Los constructores tambin se puede sobercargar y utilizando la palabra reservada this() se puede invocar desde un constructor a otro y de esta manera reutilizar el cdigo de inicialiacin que hace el otro constructor:
public class DosConstructores { private int miDato; public DosConstructores(int miDato) { this.miDato= miDato; } public DosConstructores() { this(1); //llamada a constructor sobrecargado } }

La sentencia this() debe ser la primera del constructor. 1.3.2.3.Finalizadores

En Java no es necesario destruir explcitamente los objetos que ya no se usan. La JVM dispone de un componente llamado Recolector de Basura que se encarga de encontrar aquellos objetos no accesibles desde ninguna parte de la Aplicacin y destruirlos para liberar la memoria que ocupan. El Recolector de Basura es invocado directamente por la JVM cuando sta se queda sin memoria. Mediante el mtodo esttico gc() de la clase System se puede forzar la llamada al Recolector de Basura:
//Se llama al Recolector de Basura System.gc();

Antes de que el Recolector de Basura destruya un objeto, ste invoca a su mtodo finalizador. El mtodo finalizador est definido en la clase Object de la siguiente manera:
protected void finalize() throws Throwable;

Este mtodo debe ser usado para liberar recursos que pudiera estar ocupando el objeto; como por ejemplo, ficheros, conexiones con la base de datos: import java.io.FileReader;
public class LectorFichero { private FileReader fichero; protected void finalize() throws Throwable { if(fichero!=null) { fichero.close(); } } }

El mtodo finalize() no hace nada en la clase Object. Si se lanza algn error en el mtodo finalize(), ste es ignorado y el objeto es destruido de todas formas. 1.3.2.4.Clases ejecutables: mtodo main() Para que una clase java sea ejecutable, debe contar con un mtodo llamado main() que reciba un nico parmetro de tipo array de String, que sea esttico y que no devuelva nada:
public static void main(String [] args);

Por ejemplo, el famoso programa HolaMundo en java sera:


public class HolaMundo { public static void main(String [] args) { System.out.println(Hola mundo); } } Para la ejecucin de este programa habra que escribir el comando: Java HolaMundo

Ante este comando, se arranca la JVM, la cual intenta localizar en su classpath una clase llamada HolaMundo; si la encuentra busca en la definicin de dicha clase un mtodo llamado main() que no devuelve nada, que sea esttico y que slo reciba un parmetro de tipo array de String, si lo encuentra ejecuta dicho mtodo y sino lanza una excepcin. El parmetro args contiene los parmetros con los que ha sido llamado el programa java; si ste no ha sido llamado con ninguno el parmetro args ser un array de longitud 0. 1.3.3. Modificador final El modificador final puede afectar tanto a clases como a atributos y mtodos: - Una clase con el modificador final, significa que no puede ser heredada; es decir, no puede ser superclase de ninguna clase. - Una atributo con el modificador final, significa que su valor no puede ser cambiado. Las variables que se definen en los mtodos as como los parmetros de dichos mtodos tambin se pueden declarar finales, y por lo tanto no pueden cambiar de valor. En Java los atributos declarados como estticos y finales se consideran constantes. - Un mtodo con el modificador final, significa que no puede ser sobrescrito por ninguna subclase. Veamos en un ejemplo el uso de este modificador:
public final class ClaseFinal{ private final String atributoFinal; public final String metodoFinal(int numCaracteres) { ... } public void metodo(final int numCaracteres) { } public void metodo2() { final String cadena=no se puede modificar; ... }

1.4. Paquetes en Java 1.4.1. La palabra resevada package Los paquetes son grupos relacionados de clases e interfaces que proporcionan un mecanismo conveniente para menejar un gran nmero de clases evitando los conflictos de nombres; adems, un paquete puede contener otros paquetes (subpaquetes); con lo que se crea una estructura en rbol que es muy apropiada para organizar las clases de un aplicacin java. Mediante la palabra reservada package se especifica a que paquete pertenece la clase:

package miaplicacion.accesobd; public class ConectorBD { }

En este ejemplo, la clase ConectorBD pertenece al paquete accesobd que a su vez pertenece al paquete miaplicacion La definicin de a qu paquete pertenece una clase debe ser la primera sentencia que se escriba en el fichero, antes de la definicin de la clase; como se puede ver en el ejemplo. Si no se especifica, mediante la sentencia packege a qu paquete pertenece una clase, Java la incluir en el paquete por defecto; por lo tanto toda clase o interfaz java siempre perteneces a una clase. La ruta de paquetes java debe corresponderse con una ruta de directorios en el disco, es decir la clase ConectorBD debe estar el el fichero: <directori_base>/miaplicacion/accesobd/ConectorBD.java Si esto no es as; Java dar un error de compilacin. 1.4.2. Nombre cualificado de una clase Como se indic anteriormente, los paquetes java son el mecanismo que se debe usar para organizar las clases de un proyecto y poder nombrarlas sin entrar en conflicto de nombres. Dicho de otro modo; dos clases que pertenezcan a paquetes distintos pueden llamarse igual; no hay conflito de nombres:
package miaplicacion.accesobd; public class ConectorBD { } package utiles.bd; public class ConectorBD { }

Esta definicin de clases es correcta, aunque las dos clases se llamen igual; ya que pertenecen a paquetes distintos. Esto es as porque Java, para localizar una clase no lo hace por el nombre simple de sta; sino por su nombre cualificado, es decir, el nombre de clase precedido por la ruta de paquetes en la que se encuentra. El nombre cualificado de una clase s que debe ser nico; ya que sino; ante dos clases con el mismo nombre cualificado, Java no sabra cual debe usar:
miaplicacion.accesobd.ConectorBD utiles.bd.ConectorBD

Como se puede ver, ambas clases del ejemplo tienen nombres cualificados distintos. 1.4.3. La palabra resevada import

Cuando desde cdigo Java se quiere hacer referencia a una clase, no se debe usar el nombre simple de sta; ya que no es nico y puede provocar ambigedad, sino que hay que usar el nombre cualificado de la clase; que se tiene garanta que es nico:
package utiles; public class FechaActual { public static void main(String [] args) { //Error de compilacin, en Java existen dos clases que se //llaman Date java no sabe cual debe usar Date fechaActual = new Date(); System.out.println(Fecha/hora actual: + fechaActual); } } package utiles; public class FechaActual { public static void main(String [] args) { //Se ha eliminado la ambigedad usando el nombre cualificado java.util.Date fechaActual = new java.util.Date(); System.out.println(Fecha/hora actual: + fechaActual); } }

Pero, como se ve en el ejemplo, trabajar con el nombre cualificado de las clases es demadiado engorroso. Para evitar esto, se debe usar la palabra reservada import, mediante la cual se especifica qu clases va a usar la clase que se est escribiendo; de tal manera que en el cdigo no se hace necesario usar el nombre cualificado de la clase; sino que se puede usar el simple:
package utiles; import java.util.Date; public class FechaActual { public static void main(String [] args) { //Se ha eliminado la ambigedad usando import Date fechaActual = new Date(); System.out.println(Fecha/hora actual: + fechaActual); } }

Se pueden especificar tantas sentencias import como se quiera. Las sentencias import debe ir justamente despuedes de la sentencia package; antes que comience la definicin de la clase o interfaz. El paquete java.lang (en el que se encuentran las clases base de java) se importa simpre por defecto; es decir, no es necesario especificar sentencias import para las clases de este paquete. Tampoco es necesario especificar sentencias import para clases que se encuentren en el mismo paquete que la clase que se est escribiendo. Se puede usar * para indicar que se quiere importar todas las clases de un determinado paquete: import java.util.Date; import java.util.Vector; import java.util.Iterator; Estas tres sentencias se pueden sustituir por: import java.util.*; Al utilizar * se importa todas las clases del paquete pero no las clases de los subpaquetes.

1.4.4. mbito paquete La organizacin en paquetes de las clases permite la definicin de un mbito de acceso propio de java: mbito paquete; que es el mbito que se establece por defecto, es decir, no hay una palabra reservada en Java para denominar este mbito de acceso. Una clase puede acceder a todo lo definido en otra clase del mismo paquete salvo lo que se haya declarado en sta como privado. Esto es as, porque el grado de acoplamiento que puede existir entre clases del mismo paquete puede ser alto. Dicho de otro modo en un mismo paquete deben encontrarse clases muy ligadas entre s y, que en general, se dediquen a una nica funcin conjunta; por ejemplo, en el paquete miaplicacion.accesobd se deben encontrar todas las clases de mi aplicacin destinadas al acceso a la base de datos. Vamos un ejemplo del mbito paquete:
package miaplicacion.emplados; public class Empleado { String nombre; ...

package miaplicacion.emplados; public class ListaEmpleado { private List empleados; public getNombre(int pos) { Empleado empleado = (Empleado) empleados.get(pos) return empleado.nombre; }

El atributo nombre de la clase Empleado est definido con mbito paquete (es el mbito por defecto, no tiene palabra reservada asociada); y por lo tanto puede ser accedido por cualquier otra clase de su mismo paquete. 1.5. La Herencia en Java La herencia en Java es simple, esto es, una clase slo puede tener una superclase directa. Una clase hereda de su superclase todos sus mtodos y atributos de mbito public y protected. Los constructores no se heredan. La herencia en java se especifica mediante la palabra reservada extends:
public MiClase extends SuperClase {...}

Colocando la palabra reservada final sobre una clase impide que la clase pueda ser especializada; es decir, que pueda ser superclase de alguna clase:
public final class MiClase {}

1.5.1. Sobrescritura de mtodos Como se ha indicado antes, en Java una clase hereda de su superclase todos los atributos y mtodos declarados con mbito protected y public. Pues bien, una clase puede volver a definir el cuerpo de uno de los mtodos que haya heredado y as de

esta manera, cambiar el comportamiento de la clase con respecto a la clase padre. A esto es lo que se conoce como sobrescritura:
public class EscritorMensaje { public void escritorMensaje(String msg) { System.out.println(msg); } } public class EscritorMensajeEntreComillas extends EscritorMensaje { public void escritorMensaje(String msg) {//sobrescritura System.out.println(+msg+); } }

Para que la sobrescritura sea vlida el mtodo debe ser especificado en la subclase con la misma signatura y tipo de retorno que en la clase padre. La palabra reservada final colocada sobre un mtodo impide que la implementacin de dicho mtodo sea sobrescrita por alguna subclase:
protected final int unMetodo() {...}

1.5.2. Los constructores en la herencia Los mtodos constructores no se heredan. Desde un constructor se puede especificar a qu constructor de la clase padre invocar mediante la palabra reservada super:
public Class ClasePadre { public ClasePadre(String cadena) { ... } } public Class ClaseHija extends ClasePadre { private int numero; public ClaseHija (int numero) { super(soy ClaseHija); ... } }

Si no se especifica a que constructor de la clase padre se invoca, la JVM supone que se est invocando al constructor por defecto y si la clase padre no tiene constructor por defecto, se producir un error de compilacin. Esta constructor:
public Class ClaseHija extends ClasePadre { public ClaseHija (int numero) { ... } }

Es equivalente a este otro:


public Class ClaseHija extends ClasePadre { public ClaseHija (int numero) { super(); //Error de compilacin ... }

Aunque nosotros no metamos la sentencia super(), el compilador la introduce y se produce un error de compilacin porque ClasePadre no tiene un constructor por defecto. La sentencia super() debe ser la primera del constructor y es incompatible con el uso de la sentencia this(), es decir, o se invoca a un constructor sobrecargado o se invoca a un constructor de la clase padre. 1.6. La clase java.lang.Object Toda clase java desciende directa o indirectamente de la clase Object, es decir, la clase Object se encuentra en el punto ms alto de toda jerarqua de clases java. El hecho de que toda clase descienda de la clase Object ofrece dos ventajas muy interesantes: - Toda clase tiene una funcionalidad mnima que ha heredado de la clase Object (toString(), hashCode()...) - Se pueden construir clases genricas que operan con objetos de la clase Object (por ejemplo la clase java.util.Vector) 1.7. Arrays en Java Un array es una coleccin de objetos o tipos primitivos. En un array slo se pueden guardar objetos del tipo (o subtipo) del que se ha declarado el array:
String [] arraysCadenas = new String[10];

De esta manera se est declarando un array de String con capacidad para 10 objetos de tipo String. Tras ejecutar esta lnea de cdigo la JVM reserva memoria para 10 referencias que estarn inicialmente apuntando a nulo. Para referirse a un elemento concreto del array se deben usar los los corchetes y el ndice del elemento; por ejemplo, para darle valor al quinto elemento del array anterior: arraysCadenas[4] = Una cadena; Como se puede ver en el ejemplo; los ndices vlidos para el array arraysCadenas van desde 0 a 9. Java tambin permite que un array se inicialice dndole valor a cada uno de los elementos que van a estar contenidos en el array:
String [] arraysCadenas = {yo, tu};

Este cdigo es equivalente a:


String [] arraysCadenas = new String[2]; ArraysCadenas[0] = yo; ArraysCadenas[0] = tu;

Como se ha indicado antes, los arrays en java pueden ser de tipos primitivos; por ejemplo:
int [] arraysNumeros = new int[5]; char [] arraysCaracteres = {J,A,V,A};

Los arrays en Java son objetos, es decir, en Java todo array desdiente directa o indirectamente de Object; por lo tanto el siguiente cdigo es correcto:
int [] arraysNumeros = new int[5]; String cadena = arrayNumeros.toString();

Todo array dispone de un atributo pblico llamado length que contiene la logitud del array. Para cada clase Java existe una clase de array asociada. Es decir, cuando se crea un clase Java, tambin se crea, implcitamente, una clase array del nuevo tipo creado. Esta clase array sigue la misma jerarqua de objetos que la clase que a la que est asociada. Por ejemplo, si se crea una clase A que extiende de una clase B, los arrays de objetos A, extienden de los arrays de objetos B, y a su vez, stos extienden de arrays de Object y por ltimo, stos extienden de Object. Los arrays de tipo primitivos no extienden de array de Object; sino directemente de Object. Veamos todo esto con un ejemplo, dada las siguientes clases:
public Empleado { ... } public class Jefe extends Empleado { ... }

El siguiente cdigo es correcto:


Jefe [] lista = new Jefe[3]; //Se puede hacer casting implcito a array de Empleado Empleado [] lista2 = lista; //Se puede hacer casting implcito a array de Objet Object [] lista3 = lista; //Se puede hacer casting implcito a Object Object objeto = lista;

Por ltimo indicar que mediante el mtodo esttico arraycopy() de la clase System, se puede copiar un array en otro. Por ejemplo, en el siguiente cdigo se crea un array copia de otro; pero que tiene el doble de capacidad:
String [] arrayCadenas = {cadena1,cadena2, cadena3}; String [] arrayCadenasCopia = new String [arrayCadenas.length*2]; System.arraycopy(arrayCadenas,0, arrayCadenasCopia,0,arrayCadenas.length);

arraycopy() recibe los siguientes parmetros: - Array fuente - Posicin inicial del array fuente desde donde empezar la copia - Array destino - Posicin inicial del array destino en donde se irn copiando los elementos - Nmero de elmentos que se van a copiar. 1.8. Clases Abstractas

Una clase abstracta es una clase que no puede ser instancia, es decir, no pueden crearse directamente objetos de dicha clase. Las clases abstractas necesitan ser especializadas para que puedan ser usadas; es decir, se precisa crear una nueva clase no abstracta que extienda de la clase abstracta. De esta nueva clase s se podr crear objetos (indirectamente tambin se crea un objeto de la superclase abstracta) y por lo tanto usar la funcionalidad tanto de esta clase como de su superclase abstracta. Para declarar una clase como abstracta hay que anteponerle la palabra reservada abstract en la declaracin de la clase:
public abstract ClaseAbstracta { ... }

Al ser la clase abstracta, la siguiente sentencia provocara error de compilacin:


ClaseAbstracta obj = new ClaseAbstracta(); //error

Las clases que incorporen algn mtodo abstracto deben, necesariamente declararse como clases abstractas, sino se producir un error de compilacin. Pero no necesariamente todas las clases abstractas deben tener algn mtodo abstracto, se pueden declarar abstractas clases completamente implementadas simplemente porque no tiene sentido que se puedan crear objetos de esa clase directamente. Si una clase extiende de una clase abstracta y no implementa sus mtodos abstractos, dicha clase tambin habr de ser declarada como abstracta o se producir un error de compilacin. 1.7.1. Mtodos abstractos Un mtodo abstracto es aquel para el que la clase slo aporta su definicin (signatura + tipo de retorno); pero no ofrece implementacin para dicho mtodo; sino que son las subclases las que estn obligadas a darle cuerpo al mtodo. Las clases que incorporen algn mtodo abstracto deben declararse obligaroriamente como abstractas. Slo los modificadores de acceso public y protected son vlidos para mtodos abstractos:
public abstract class ClaseAbstracta{ public abstract String obtenerCadena(); } public class ClaseConcreta extends ClaseAbstracta{ public String obtenerCadena() { return Clase Concreta; }

1.9. Interfaces Una interfaz tiene un nivel de abstraccin mayor que el de una clase abstracta; ya qu solo plantea una comportamiento (conjunto de mtodos abstractos) que alguna clase implementar. En las interfaces s se admite la herencia mltiple:

public interface MiInterfaz extends SuperInterfaz1, SuperInterfazN { declaracin de constantes declaracin de mtodos }

Ejemplo de interfaz:
public interface Lista { //constante public static final int NUM_MAX_ELEMENTOS=100; public void annadir(Object obj); public Object obtener(int pos); public void borrar(int pos); } public int getNumElementos();

Como se ha indicado antes, alguna clase debe implementar los mtodos definidos por el interfaz, ello se hace usando la palabra reservada implements:
public class MiClase implements MiInterfaz {...}

Una clase java puede extender directamente de una nica clase; pero implementar mltiples interfaces. As pues, las interfaces son una alternativa vlida a la herencia mltiple:
public class MiClase extends SuperClase implements Interfaz1,..., InterfazN { }

Al igual que ocurre con las clases abstractas, sino una clase implementa un interfaz determinado y no le da cuerpo a todos los mtodos definidos en el interfaz, entonces la clase debe ser declarada como abstracta o se producir un error de compilacin. 1.10. Perfiles de un objeto Java. Casting Un objeto se instancia de una clase concreta; pero puede ser apuntado por referencias de distinto tipo (perfiles del objeto). Por ejemplo, dada la siguiente definicin de clase:
public class MiClase extends SuperClase implements MiInterfaz { ... }

Son vlidas las siguientes referencias que se crean apuntando al mismo objeto de la clase MiClase:
MiClase ref1 = new MiClase(); SuperClase ref2 = ref1; MiInterfaz ref3 = ref2;

Las tres referencias estn apuntando al mismo objeto; pero las tres hacen que el objeto se vea con un perfil distinto. Con esto un objeto java puede ser apuntado por una referencia cuyo tipo sea: - El de la propia clase del objeto o de alguna de sus superclases - El de algn interfaz implementado por la clase del objeto o por alguna de sus superclases En el cdigo de arriba se est produciendo un casting implcito llamado upcasting. En java el casting implcito es vlido cuando se hace hacia arriba en la jerarqua de clases y debe ser explcito cuando se hace hacia abajo en la jerarqua:
MiClase ref1 = new MiClase(); SuperClase ref2 = ref1; MiInterfaz ref3 = ref1; MiClase ref4 = ref2; //error de compilacin

El cdigo de arriba provoca un error de compilacin porque se est haciendo un casting implcito cuando se precisa un casting explcito porque el casting se est haciendo hacia abajo en la jerarqua de clases:
MiClase ref1 = new MiClase(); SuperClase ref2 = ref1; MiInterfaz ref3 = ref1; MiCase ref4 = (MiClase) ref2; //cdigo correcto

Java cuenta con el operador intanceof para determinar, en tipo de ejecucin, si un determinado objeto puede o no verse con un determinado perfil. La sintaxis de este operador es la siguiente:
<referencia a un objeto> instanceof <nombre de clase o interface>

Por ejemplo:
if(ref2 instanceof MiClase) { System.out.println(Este if devuelve cierto); }

Resumiendo, el casting hacia arriba en la jerarqua de clases se denomina casting implcito o upcasting y el casting hacia abajo en la jerarqua de clases se denomina casting explcito y este tipo de casting puede provocar un error de conversin recogido en una excepcin de tipo ClassCastException:
MiClase ref1 = new MiClase(); SuperClase ref2 = ref1; //upcasting o cating implcito MiInterfaz ref3 = ref1; //upcasting o cating implcito MiCase ref4 = (MiClase) ref2; //casting explcito

1.11.

Palabras reservadas this y super La palabra reservada this es una referencia que apunta el objeto actual. Es la manera de poder referirse al objeto actual desde el cdigo de su clase. Tambin se puede usar para acceder a mtodos y atributos del objeto; aunque esto solo es necesario cuando hay ambigedades:

public class MiClase { int numero; public boolean iguales(int numero) { return this.numero==numero; } }

En este ejemplo el uso de la palabra reservada this es fundamental para eliminar la ambigedad, ya que hay dos variables que se llaman numero; una es el atributo interno de la clase y la otra es el parmetro de entrada que recibe el mtodo. La palabra reservada super se usa para acceder a mtodos y atributos de cualquiera de las superclases a los que la clase actual pueda acceder, es decir, aquellos cuyo mbito de visin sea public o protected. Al igual que la palabra reservada this sirve para romper ambigedades:
public class SuperClase { protected int numero; public SuperClase(int numero) { this.numero=numero; } public int suma(int sumando) { return this.numero+sumando; }

public class ClaseHija extends SuperClase { protected int numero; public SuperClase(int numero1, int numero2) { super(numer1); this.numero=numero2; } public int suma(int sumando) { return super.suma(sumando)+this.numero; } public int getNumero1() { super.numero; }

En el ejemplo anterior se ve el uso que se hace de la palabra reservada super para acceder a mtodos y atributos heredados de la clase padre y romper ambigedades. Las dos clases tiene definidos un atributo con el mismo nombre numero; en estos casos se dice que el atributo de la clase hija est enmascarando al atributo de la clase padre y es necesario el uso de la palabra reservada super para poder acceder al valor del atributo numero en la clase padre; si no hubiera enmascaramiento; no sera necesario el uso de super, el compilador sera capaz por s solo de resolver a qu se refiere la variable numero. El compilador intenta resolver las referencias de la siguiente manera: dado la siguiente sentencia Java se busca la definicin de la variable obj en el siguiente orden:

String cadena = obj.toString();

1.- Que exista un parmetro o variable local al mtodo llamado obj 2.- Que exista un atributo en la clase llamado obj 3.- Que exista un atributo en alguna superclase llamado obj. Con esto, se hace imprescindible el uso de las palabras reservadas this y super para indicar de manera explcita en que lugar se debe buscar la definicin de la variable:
public class SuperClase { protected String cadena; public SuperClase(String cadena) { this.cadena= cadena; }

public class ClaseHija extends SuperClase { protected String cadena; public ClaseHija (String cadena1, String cadena2) { super(cadena1); this.cadena= cadena2; } public String concatena(String cadena) { String res = cadena; //parmetro res+=this.cadena; //atributo cadena en ClaseHija res+=super.cadena; //atributo cadena en SuperClase return res; } }

El otro uso importante de la palabra reservada super es para acceder a la definicin de mtodos sobrescritos por las subclases, de esta manara, desde las subclases se puede reutilizar el cdigo de los mtodos sobrescritos y slo modificar lo que corresponda:
public int suma(int sumando) { return super.suma(sumando)+this.numero; }

1.12. Resolucin de referencias en Java Cuando se invoca a un mtodo de una clase, la JVM busca de definicin del mtodo (es decir, el cdigo que debe ejecutar) partiendo de la clase en la que ha sido instanciado el objeto. Por ejemplo, dado el siguiente conjunto de clases:
public class SuperClase { protected String cadena; public SuperClase(String cadena) { this.cadena= cadena;

} public char caracter() { return this.cadena.charAt(0); } } public class ClaseHija extends SuperClase { public ClaseHija (String cadena) { super(cadena); } public char caracter() { return this.cadena.charAt(this.cadena.length()-1); }

y el siguiente trozo de cdigo java:


ClaseHija obj1 = new ClaseHija(Cadena); SuperClase obj2 = obj1; char c = obj2.caracter();

El resultado que se obtendr ser a (ltimo carcter de cadena), ya que la JVM buscar el cdigo a ejecutar partiendo de la clase de la que ha sido instanciada obj2, es decir, buscar el cdigo partiendo de la clase ClaseHija y por lo tanto el cdigo que ejecutar ser:
public char caracter() { return this.cadena.charAt[this.cadena.length()-1]; }

Cuando se invoca a un mtodo sobrecargado, la JVM busca de definicin del mtodo (es decir, el cdigo que debe ejecutar) partiendo del tipo de las referencias que se pasan como parmetro al mtodo. Por ejemplo, dado el siguiente conjunto de clases:
public class SuperClase { } public class ClaseHija extends SuperClase { } public class ClaseOperador { public String opera(SuperClase obj) { return Metodo SuperClase; } public String opera(ClaseHija obj) { return Metodo ClaseHija; }

y el siguiente trozo de cdigo java:


ClaseHija obj1 = new ClaseHija(Cadena);

SuperClase obj2 = obj1; ClaseOperador co = new ClaseOperador(); String res = co.opera(obj2);

El resultado que se obtendr ser Mtodo SuperClase, ya que la JVM busca el mtodo a ejecutar partiendo del tipo del que son las referencias que se pasan como parmetro en la llamada al mtodo y la referencia obj2 es del tipo SuperClase; por lo tanto el cdigo que se ejecutar ser:
public String opera(SuperClase obj) { return Metodo SuperClase; }

1.13. Herramientas bsicas en el JSDK El JSDK (Java Standard Developer Kit), es el conjunto de herramientas bsicas necesarias para poder desarrollar en Java. Su funciones principales son: - Compilacin de clases Java - Ejecucin de clases Java Otras funciones son: - Generacin de documentacion (javadoc) - Crear ficheros jar - Ejecucin de Applets (appletviewer) - ... 1.12.1. Compilacin de una clase Java El comando javac compila cdigo fuente Java y lo convierte en bytecodes que ya son ejecutables por la mquina virtual. La sintaxis con la que se usa el comando es la siguiente: javac [opciones] fichero.java donde fichero.java es la ruta relativa o absoluta al fichero fuente java. Es importante no omitir la extensin del fichero. El compilador almacena los bytecodes resultantes en un fichero llamado nombredeclase.class. El compilador sita este fichero en el mismo directorio en el que estaba el fichero fuente (a menos que se especifique la opcin -d). Las opciones ms usuales son: classpath path.Especifica el path que javac utilizar para buscar las clases de las que depende la clase que se quiere compilar (no es necesario indicar las clases bsicas de java (todas aquellas que cuelgan del paquete java.) ya que la mquina virtual sabe localizarlas por si sola). Sobreescribe el path por defecto generado por la variable de entorno CLASSPATH. Los directorios o archivos jar, deben estar separados por puntos y comas. Por ejemplo:

javac -classpath .;C:\lib\utiles.jar;C:\tools\java\clases MiClase.java

d directorio. Especifica el directorio raiz en el que se crearan los ficheros .class. Por ejemplo:

javac -d c:\salida_java MiClase.java

Si la clase MiClase pertenece al paquete miaplicacion; har que se cree en el directorio salida_java un subdirectorio llamado miaplicacion y dentro de l se crear el fichero MiClase.class. Al especificar el nombre de la clase a compilar, se pueden especificar comodines (* y ?), de tal manera que se compilarn todos los ficheros que cumplan la condicin impuesta; y adems esta compilacin se har en orden; es decir, si por ejemplo la clase A y B dependen de la clase C y sta no depende de ninguna otra; primero se compilar la clase C y luego A y B. Por ejmplo:
javac *.java

Compila todas las clases del directorio. 1.12.2. Ejecucin de una clase Java El comando java ejecuta en una mquina virtual los bytescodes que el compilador ha generado para para una clase java. La sintaxis con la que se usa el comando es la siguiente: java [opciones] NombreClase [argumentos] NombreClase debe ser el nombre cualificado de la clase que se quiere ejecutar; la cual debe contener un mtodo main() esttico; sino la JVM dar una excepcin. Por ejemplo, supngase que se quiere ejecutar la clase MiClase, la cual pertenece a un paquete llamado aplicacion; y supngase tambin queel archivo compilado se encuentra, por ejemplo en c:\salida_java\aplicacion\MiClase.class, entonces para ejecutar la clase debemos situarnos en el directorio salida_java y escribir el siguiente comando: Java cp . aplicacion.Miclase Mediante la opcin cp . se le dice a la JVM que busque las clases en el directorio actual; esto es necesario hacerlo si en la variable de entorno CLASSPATH no se ha aadido el directorio actual. A dems, es implescidible que no situemos en el directorio salida_java para la JVM encuentre la clase, ya que el nombre cualificado de la clase le indica la ruta de directorios que debe seguir para encontrar la clase a ejecutar. Los argumentos con los que se ejecute la clase sern accesibles desde el mtodo main() a travs del atributo String [] args. Las opciones ms usuales son: cp path.Especifica el path que java utilizar para buscar las clases de las que depende la clase que se va a ejecutar (no es necesario indicar las clases bsicas de java (todas aquellas que cuelgan del paquete java) ya que la mquina virtual sabe localizarlas por s sola). Sobreescribe el path por defecto generado por la variable de entorno CLASSPATH. Los directorios o archivos jar, deben estar separados por puntos y comas. Por ejemplo:

java -cp .;C:\lib\utiles.jar;C:\tools\java\clases MiClase DnombrePropiedad=valor. Define o redefine un valor de una propiedad de sistema. nombrePropiedad es el nombre de la propiedad cuyo valor se quiere establecer o cambiar y valor es el valor que se le va a dar a la propiedad. Las propiedades de Sistema son accesibles desde la clase java.lang.System. En la documentacin en javadoc de esta clase aparecen algunas de las propiedades de Sistema que contiene. Por ejemplo, esta lnea de comando:
java -Duser.lang=es ...

Cambia el valor de la propiedad user.lang a es; es decir, se cambia el lenguaje de la mquina virual a espaol. Para acceder a la propiedad, desde una clase java:
String valorPropiedad = System.getProperty("user.lang");

jar NombreFicheroJar.jar. Ejecuta una aplicacin java contenida en un fichero jar. Un fichero jar es un conjunto de clases java comprimidas en un fichero en formato zip que tiene extensin .jar y que aparte de contener clases java; puede contener otros tipos de recursos (imgenes, ficheros de texto...). Los ficheros jar suelen contener un fichero especial llamado manifest.mf que debe encontrarse en un directorio llamado META-INF. Este fichero contiene diversas propiedades de la clases contenidas del jar. Una de estas propiedades es Main-Class: nombre_cualificado_clase que contiene el nombre de la clase que arranca la aplicacin contenida en el jar. Evidentemente dicha clase debe contener un mtodo main() esttico. Por ejemplo, supongamos una jar llamado MiAplicacin.jar y la propiedad Main-Class es la siguiente:
Main-Class: miaplicacion.Arranque

Para ejecutar el jar escribiramos el siguiente comando:


java jar MiAplicacion.jar

la JVM arrancara la aplicacin ejecutando el mtodo main() de la clase miaplicacion.Arranque. 1.14. Reglas de nombrado en Java Toda clase Java se recomienda que cumpla las reglas de nombrado que hay definidas. El cdigo Java que sigue las reglas de nombrado es ms fcil de entender por cualquier programador java que est acostumbrado a estas reglas de nombrado. Elemento Paquete Clase Regla Todo minscula La primera letra de cada palabra que forme parte del nombre de la clase en Ejemplo
package miaplicacion.accesobd; public class GeneradorFicherosAyuda {

mayscula y el resto de la palabra en minscula Variables miembro, Igual que la regla para las parmetros y variables clases, salvo que la primera palabra va entera en minscula. Mtodos miembro Igual que la regla de las variables Constantes Todo en mayscula, separando cada palabra que forme parte del nombre de la constante con un subrayado

private int numUsuariosConectados;

public int calculaMaximaRenta() { private int NUM_MAX_ELEMENTOS=100;

Tratamiento de errores en Java: Excepciones Las excepciones son objetos que representan errores en el funcionamiento de la aplicacin. Cuando ocurre un error durante la ejecucin de un determinado trozo cdigo se crea un objeto de alguna clase que extienda de la clase java.lang.Exception y se lanza usando el operador throw. 2.1. Captura de excepciones Cuando desde un mtodo se hace una llamada a otro mtodo que puede provocar excepciones, java obliga a que se capture la excepcin o que el propio mtodo tambin la lance. Para tratar excepciones se debe usar los bloques try-catch-finally. Un bloque try-catch-finally encierra un trozo de cdigo que puede provocar excepciones. La estructura del bloque es la siguiente:
try { ...cdigo que puede provocar excepciones }catch(ClaseExcepcion1 e1) { ...tratamiento de las excepciones de la clase ClaseExcepcion1 }catch(ClaseExcepcionN e1) { ...tratamiento de las excepciones de la clase ClaseExcepcionN }finally{ ...trozo de cdigo que siempre se ejecuta, incluso cuando se produce algn error }

2.

Si dentro del bloque try-catch no hay ninguna sentencia que pueda provocar alguna de las excepciones declaradas en la parte catch, java da un error de compilacin. El bloque finally contiene un conjunto de sentencias que la JVM garantizan que se ejecutan siempre; incluso si antes ha ocurrido un error o se ha ejecutado una sentencia return que termina la ejecucin del mtodo. 2.2. Declaracin de excepciones Como se ha dicho antes, un mtodo debe tratar o declarar todas las excepciones que se pueden producir en el cdigo del mtodo. Si dentro del cdigo de un mtodo se puede provocar alguna excepcin y el mtodo no la captura; entonces, en la cabecera del mtodo se debe declarar que el mtodo lanza la excepcin:
public int metodo() throws ClaseExcecion1, , ClaseExcecionN {...}

Si dentro del mtodo se puede producir alguna excepcin que ni es capturada y est declarada en la cabecera del mtodo como que se puede lanzar, entonces java da un error de compilacin. As pues, un mtodo java debe: Declarar todas las excepciones que pueda lanzar y no va a tratar Tratar todas las excepciones que pueda producir y que no son declaradas 2.3. Creacin de nuevos tipos de errores Java aporta un gran nmero de clases de Excepciones diferentes, representando , cada una de ellas, un tipo de error determinado. Pero las aplicaciones pueden desarrollar ellas mismas sus propios niveles de errores creando objetos que extiendan de la clase java.lang.Exception:
public class ClaseConExcepciones {

public int divide(int dividendo, int divisor) throws DivisionPorCeroException { if(divisor==0) { throw new DivisionPorCeroException(); }else { return dividendo/divisor; } } public void imprimirDivision(ind dividendo, int divisor) { try { int div = divide(dividendo,divisor); System.out.println(Resultado de la divisin: +div); }catch(DivisionPorCeroException dpce) { System.out.println(Se ha intentado dividir por cero); } } }

El primer mtodo divide() lanza un excepcin; que al no tratarla debe indicar que la lanza en su cabecera. Por su parte el mtodo imprimirDivision() posee un bloque trycatch para tratar las posibles excepciones que se lance con las llamadas al mtodo divide(). La clase DivisionPorCeroException es una excepcin personalizada y debe extender de la clase Exception:
public class DivisionPorCeroException extends Exception { }

Las clases que se usan para definir niveles de errores personalizados, son un poco especiales; porque extienden de una clase (en este caso Exception) a la que, en la mayora de los casos, no aportan funcionalidad adicional. Esto es as porque lo ms importante en las excepciones personalizadas es el nombre de sta, que ya de por s da mucha informacin del error ocurrido. 2.4. RuntimeException Existe un tipo especial de excepciones que son aquellas que desciende de la clase RuntimeException (NumberFormatException, NullPointerException...) que no necesitan ser ni declaradas en los mtodos ni capturadas, es decir, java no obliga ni a tratar ni a capturar este tipo de excepciones, como hace con el resto. Esto es as, porque estas excepciones pueden ocurrir en cualquier trozo de cdigo java y por lo tanto sera muy engorroso (prcticamente imposible) escribir un mtodo java. 2.5. java.lang.Error frente a java.lang.Exception Java propone dos niveles de errores que pueden ocurrir dentro de la JVM: Errores que pueden ocurrir ejecutando cdigo de la aplicacin, que son representados mediante objetos que extienden de la clase Exception, por ejemplo, el intento de acceder a un mtodo de una referencia que apunta a nulo provocara el lanzamiento de un NullPointException Errores internos, no en la ejecucin del cdigo de la aplicacin, sino dentro de la propia mquina virtual, que son representados mediante objetos que extienden de la clase Error; por ejemplo, si la mquina virtual se queda sin memoria, se lanza un OutOfMemoryError. A su vez, ambas clases extienden de la clase java.lang.Throwable; slo los objetos de esta clase pueden ser lanzados mediante el operador throw.

2.6. Principales mtodos de java.lang.Throwable Los principales mtodos de Throwable y por tanto de Exception y Error son: Mtodo Descripcin Devuelve el mensaje asociado al error void printStackTrace() Lanza por la salida estndar la pila de llamadas desde el mtodo que provoc el error hasta el mtodo inicial. void printStackTrace(PrintWriter Igual que el anterior, pero no por out) la salida estndar, sino por el PrintWriter que se le pasa como parmetro
String getMessage()

3. Entrada/Salida en Java La entrada/salida en java est basada en corrientes. Una corriente es un objeto por el que circula informacin. Las corrientes se pueden clasificar de varias maneras: - Segn la direccin: o Corrientes de entrada o Corrientes de salida - Segn el tipo de dato: o Corrientes de bytes o Corrientes de caracteres - Segn el origen de la informacin o Corrientes nodo o Corrientes filtro Las clases de entrada/salida se encuentran en el paquete java.io 3.1.Clases base de la entrada/salida La entrada/salida en java se basa en cuatro clases abstracta, independientes de dispositivo sobre las que se basan el resto de clases: - InputStream. Es la superclase directa o indirecta de todas las corrientes de entrada de bytes. Mtodos principales: - int read(). Lee un byte - int read(byte []). Lee un array de bytes. Lee tantos bytes como longitud tenga el array que se le pasa como parmetro - int read(byte[],int,int). Lee un array de bytes. Lee tantos bytes como se indique en el tercer parmetro y se graban en el array empezando en la posicin que marca el segundo parmetro. - OutputStream. Es la superclase directa o indirecta de todas las corrientes de salida de bytes. Mtodos principales: - void write(int b). Escribe un byte - void write(byte []). Escribe un array de bytes. Escribe tantos bytes como longitud tenga el array que se le pasa como parmetro - void write(byte[],int,int). Escribe un array de bytes. Escribe tantos bytes como se indique en el tercer parmetro y se leen del array empezando en la posicin que marca el segundo parmetro. - Reader. Es la superclase directa o indirecta de todas las corrientes de entrada de caracteres. Mtodos principales: - int read(). Lee un carcter - int read(char []).Lee un array de carcter. Lee tantos caracteres como longitud tenga el array que se le pasa como parmetro - int read(char[],int,int). Lee un array de carcter. Lee tantos caracteres como se indique en el tercer parmetro y se graban en el array empezando en la posicin que marca el segundo parmetro.
-

- Writer. Es la superclase directa o indirecta de todas las corrientes de salida de caracteres. Mtodos principales: - void write(int b). Escribe un carcter

void write(char []).Escribe un array de carcter. Escribe tantos

caracteres como longitud tenga el array que se le pasa como parmetro


void write(char[],int,int). Escribe un array de carcter. Escribe

tantos caracteres como se indique en el tercer parmetro y se graban en el array empezando en la posicin que marca el segundo parmetro. void write(String). Escribe una cadena. void write(String, int,int). Escribe una subcadena de la cadena que se le pasa como parmetro.

Todo error que se produzca en alguna operacin de entrada/salida se representa mediante una excepcin de la clase IOException. 3.2. Corrientes Nodo Son corrientes cuyo origen en un dispositivo fsico (fichero, memoria...). Por ejemplo: - FileInputStream. Corriente nodo cuyo origen en un fichero - SocketInputStream. Corriente nodo cuyo origen es un socket - StringReader. Corriente nodo cuyo origen es una cadena de texto - ByteArrayInputStream. Corriente nodo cuyo origen es un array en memoria 3.3. Corrientes Filtro Son corrientes cuyo origen es otra corriente. Amplan la funcionalidad de la corriente origen. Normalmente no se suele trabajar con corrientes nodo directamente, sino que sobre ellas se monta una corriente filtro que nos facilita el trabajo con la corriente nodo. A continuacin se presentan algunas corrientes filtro: - BufferedInputStream o Almacena datos que lee de un InputStream o Disminuye nmero de acceso al flujo origen - BufferedReader o Equivalente al anterior pero para Reader o Permite leer de un Reader lnea a lnea - BufferedOutputStream o Almacena datos que escribe en un OutputStream o Disminuye nmero de acceso al flujo origen - BufferedWriter o Equivalente al anterior pero para Writer - PrintWriter o Incorpora el mtodo println(String) que escribe en el Writer sobre el que se apoya la cadena que recibe como parmetro y a continuacin inserta un salto de lnea. 3.4. Ejemplo 1: Escritura de la hora en un fichero En este ejemplo se escribir en un fichero la fecha y hora actual del sistema. Como se indic anteriormente, se obtendr un flujo nodo (en este caso un FileWriter, ya que vamos a escribir en un fichero) y sobre l se montar un flujo filtro para facilitar el trabajo (en este caso un PrintWriter):

import java.io.FileWriter; import java.io.PrintWriter; import java.io.IOException; import java.util.Date; public class EscribirFechaHora { public static void main(String args[]) throws IOException{ String nombreFichero = C:\\FechaHora.txt; FileWriter fWriter = new FileWriter(nombreFichero); PrintWriter pOut = new PrintWriter(fWriter); Date fechaActual = new Date(); pOut.println(fechaActual.toString()); //para vaciar el PrintWriter hacia su Writer origen pOut.flush(); pOut.close();// es importante cerrar los flujos } }

3.5. Entrada/salida estndar La entrada/salida estndar en java, se encuentran en la clase java.lang.System como dos atributos pblicos y finales:
public final static PrintStream out; public final static InputStream in;

Por defecto, la entrada estndar es el teclado y la salida estndar el monitor. 3.6. Ejemplo 2: Presentacin por pantalla de un fichero En este ejemplo se presentar por pantalla el contenido de un fichero de texto cuyo nombre se recibir por parmetro. Como se indic anteriormente, se obtendr un flujo nodo (en este caso un FileReader, ya que vamos a leer de un fichero) y sobre l se montar un flujo filtro para facilitar el trabajo (en este caso un BufferedReader ya que permite leer lnea a lnea. Del mismo modo, para escribir en la salida estndar montaremos sobre dicha salida estndar un PrintWriter, que permite escribir lnea a lnea):
package sevinge.cursos.io; import import import import java.io.BufferedReader; java.io.FileReader; java.io.IOException; java.io.PrintWriter;

public class LeerFichero { public static void main(String[] args) throws IOException { if (args.length == 0) { System.out.println("Falta el nombre del fichero a mostrar"); return; } //Abrimos el fichero FileReader fIn = new FileReader(args[0]); //Montamos sobre este Reader un BufferedReader //para poder leer lnea a lnea BufferedReader lector = new BufferedReader(fIn); //Montamos sobre la salida estdar un PrintWriter //para poder escribir sobre ella lnea a lnea PrintWriter escritor = new PrintWriter(System.out); //Leemos el fichero a travs de lector //y lo escribimos a travs de escritor String linea = lector.readLine();

while(linea!=null) { escritor.println(linea); linea = lector.readLine(); } //para vaciar el PrintWriter hacia el flujo en el que est montado escritor.flush(); //cerramos los flujos lector.close(); escritor.close(); } }

4. Serializacin de Objetos Java La serializacin es un proceso que convierte un objeto java en una secuencia de bytes que son enviados a travs de un flujo de salida (OutputStream) cuyo destino final puede ser un fichero, un socket, etctera. La deserializacin es el proceso contrario, es decir, la reconstruccin de un objeto java a partir de una secuencia de bytes que proceden de un flujo de entrada (InputStream) cuyo origen inicial puede ser un fichero, un socket, etctera. La serializacin es una forma sencilla de conseguir persistencia de objetos y es la base para la comunicacin entre aplicaciones java (RMI, por ejemplo, se basa en la serializacin) 4.1 Interfaz java.io.Serializable Para que una clase java sea serializable debe implementar el interfaz java.io.Serializable este interfaz no define ningn mtodo que deba ser implementado; sino que es una simple marca para que la JVM sepa cuando un objeto es o no serializable. Si se intenta serializar un objeto que no lo es, se producir una excepcin del tipo java.io.NotSerializableException: import java.io.Serializable; public class ClaseSerializable implements Serializable { ... } Todos los tipos primitivos y las clases base sin serializables. 4.2 Serializacin de un objeto: java.io.ObjectOutputStream La serializacin de un objeto recae sobre la clase java.io.ObjectOutputStream que es un decorador de java.io.OutputStream aadiendo la funcionalidad de serializar objetos. Por ejemplo, supngase que se quiere serializar un objeto de la clase ClaseSerializable guardndolo en un fichero: ClaseSerialible obj = new ClaseSerialible(); OutputStream out = new FileOutputStream(c:\\ClaseSerializable.ser); ObjectOutputStream objectOut = new ObjectOutputStream(out); ObjectOut.writeObject(obj); ObjectOut.close(); Como se puede ver en el ejemplo, la creacin de un objeto del tipo ObjectOutputStream precisa del OutputStream al que se enve la secuencia de bytes en que se haya convertido el objeto serializado. La clase ObjetOutputStream cuenta con el mtodo writeObject(), que serializa el objeto que se le pasa como parmetro. La serializacin es recursiva, es decir al serializar un objeto se serializan todos sus atributos no transient; y al serializar cada uno de esos objetos, se serializan cada uno de sus atributos no transient; y as sucesivamente.

4.3 Deserializacin de un objeto: java.io.ObjectInputStream La deserializacin de un objeto recae sobre la clase java.io.ObjectInputStream que es un decorador de java.io.InputStream aadiendo la funcionalidad de deserializar objetos. Por ejemplo, supngase que se quiere deserializar un objeto de la clase ClaseSerializable a partir de la informacin contenida en un fichero: ClaseSerialible obj = new ClaseSerialible(); InputStream in = new FileInputStream(c:\\ClaseSerializable.ser); ObjectInputStream objectIn = new ObjectInputStream(in); ClaseSerialible obj=(ClaseSerialible) objectIn.readObject(); ObjectIn.close(); Como se puede ver en el ejemplo, la creacin de un objeto del tipo ObjectInputStream precisa del InputStream del que se obtenga la secuencia de bytes a partir de la cual se reconstruir el objeto. La clase ObjetInputStream cuenta con el mtodo readObject(), que crea un objeto a partir de la secuencia de bytes que lea del InputStream que tiene asociado. Este mtodo devuelve un Object, puesto que puede deserializar cualquier tipo de objeto serializable; con lo que se precisa un casting del objeto devuelto hacia la clase ClaseSerializable. La deserializacin es recursiva, es decir al deserializar un objeto se deserializan todos sus atributos no transient; y al deserializar cada uno de esos objetos, se deserializan cada uno de sus atributos no transient; y as sucesivamente. Durante la deserializacin de un objeto se comprueba que la versin de la clase del objeto serializado es compatible con la versin de la clase a la que actualmente puede acceder la JVM; si esto no es as se lanzar una excepcin de tipo: java.io.InvalidClassException Por ejemplo, supngase que se serializa un objeto de una clase que tiene un atributo de tipo String llamado nombre. Posteriormente se borra este atributo de la clase y dicha clase es recompilada. Si ahora se intenta deserializar el objeto, se producira un error, ya que en el objeto serializado existe valor para un atributo llamado nombre, que no existe en la clase actual. Del mismo modo si se deserializa un objeto que tiene un atributo de una clase desconocida para la JVM, tambin se lanzar una excepcin de tipo java.io.InvalidClassException. 4.4 Control de la serializacin: atributos transient Puede ocurrir que en una clase serializable no se quiera que se serialicen determinados atributos por seguridad; porque, por ejemplo, contienen claves o cdigos; o tambin puede ocurrir que otros atributos no se deban serializar porque su serializacin no tiene sentido; por ejemplo, un atributo que sea una conexin a un base de datos. Y por ltimo se tiene el caso de clases serializable que posee atributos internos de clases no serializable. Para evitar que estos atributos se serialicen, se debe colocar en su declaracin la palabra clave transient: import java.io.Serializable;
public class ClaseSerializable implements Serializable {

private transient String atributoNoSerializable; ...

Cuando se deseriliza una objeto, sus atributos transient se inicializan a nulo, como es lgico (los tipos primitivos se inicilizan a 0, salvo boolean que se inicializa a false). 4.5 Control de la serializacin: mtodos writeObject() y readObject() Una clase serializable puede implementar los mtodos writeObject() y readObject() con los que controlar el cdigo que se ejecuta durante la serializacin o deserializacin del objeto y de esta manera, por ejemplo, poder inicializar correctamente los atributos transient:
private void writeObject(ObjectOutputStream stream) throws IOException; private void readObject(ObjectInputStream stream) throws IOException;

Mediante el primer mtodo se puede especificar cdigo que se ejecute cuando el objeto vaya a ser serializado y con el segundo se puede especificar cdigo que se ejecute cuando se vaya a deserializar el objeto: import java.io.Serializable; import java.sql.Connection; public class ClaseSerializable implements Serializable { private String urlBaseDatos; private transient Connection conexion; ...
private void readObject(ObjectInputStream stream) throws IOException { stream.defaultReadObject(); this.conexion = ConnectionManager.getConnection(urlBaseDatos); }

} Realmente si una clase serializable implementa estos mtodos, la JVM no usa el algoritmo estndar de serializacin sobre los objetos de dicha clase; sino que delega dicho operacin en estos mtodos; por ello las clases ObjectInputStream y ObjetOutputStream cuentan con los mtodos defaultReadObject() y defaultWriteObject() respectivamente, para que se ejecute el algoritmo por defecto sobre el objeto y usar estos mtodos nicamente para especificar cdigo adicional que se ejecute durante la serializacin; como por ejemplo inicializar atributos transient. Tambin se puede usar estos mtodos para aadir informacin adicional en la serializacin:
import java.io.Serializable; import java.util.Date; public class ClaseSerializable implements Serializable { private String nombre; public ClaseSerializable(Stgring nombre) { this.nombre=nombre; } private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); stream.writeObject(new Date()); } private void readObject(ObjectInputStream stream) throws IOException {

stream.defaultReadObject(); Date fechaSerializacion = (Date) stream.readObject(); System.out.println(El objeto fue serializado el: +fechaSerializacion); } }

4.6 Externalizable Si una clase extiende de una clase no serializable; toda la informacin contenida en dicha clase no es serializada con el algoritmo por defecto; es decir, si se tiene la siguiente jerarqua de clases:
public static class Clase1 { protected String s1; public Clase1() { this.s1=""; } public Clase1(String s) { this.s1 = s; } } public static class Clase2 extends Clase1 implements Serializable { private String s2; public Clase2(String s1, String s2) { super(s1); this.s2 = s2; } public String toString() { return this.s1+"-"+this.s2; } }

Al serializar un objeto de la clase Clase2, no se serializar el atributo heredado de la clase padre s1. Para evitar esto, Java define el interfaz Externalizable que extiende de Serializable:
public interface Externalizable { public void writeExternal(ObjectOutput out) throws IOException; public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException; }

ObjectOutput y ObjectInput son los interfaces base que definen los mtodos para la escritura/lectura de objetos. Las clases ObjectOutputStream y ObjectInputStream implementan estos interfaces. Toda la responsabilidad de la serializacin recae en estos dos mtodos: writeExternal() es responsable de todo lo que se escribe y readExternal() debe ser capaz de leer todo lo que se ha escrito desde writeExternal(). Las clases que implementen este interfaz deben tener un constructor por defecto porque la JVM invoca a dicho constructor antes de invocar al mtodo readExternal():
public static class Clase2 extends Clase1 implements Externalizable { private String s2; public Clase2() { super(null); } public Clase2(String s1, String s2) { super(s1); this.s2 = s2;

} public String toString() { return this.s1+"-"+this.s2; } public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(this.s1); out.writeObject(this.s2); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.s1 = (String) in.readObject(); this.s2 = (String) in.readObject(); } }

5. Programacin Multi-Hilo en Java Un hilo es un flujo de ejecucin secuencial e independiente dentro de un programa que competir por los recursos del Sistema con el resto de hilos de ejecucin, sean o no del mismo programa. Partiendo del nmero de hilos en los que se ejecuta un programa, se pueden clasificar stos en dos: - Mono-hilos. Programas que se ejecutan en un nico hilo. Es decir, todo el cdigo del programa es ejecutado por un nico hilo. Este tipo de programas eran desarrollados principalmente en Sistemas Operativos que no tenan soporte al multi-hilo (por ejemplo MS-DOS). En estos Sistemas Operativos, el aprovechamiento los recursos CPU eran mnimos: cuando un programa se ejecutaba adquira plenamente la CPU; por lo que el tiempo que el programa no estuviera ejecutando cdigo (por ejemplo en espera de datos de E/S) la CPU estaba ociosa. - Multi-hilos. Programas que se ejecutan en varios hilos. Es decir, el cdigo del programa es ejecutado en hilos de ejecucin distintos que compiten entre s por la CPU. Este tipo de programas son ms modernos y se ejecutan sobre Sistemas Operativos con soporte al multi-hilo. En estos Sistemas Operativos, el control de ejecucin no recae sobre el programa (o hilo) que en estos momentos se est ejecutando; si no que es el propio Sistema Operativo el encargado de distribuir el tiempo de CPU entre los distintos hilos que compiten por ella (cambios de contexto); con el que el aprobechamiento del tiempo de CPU es mximo. 5.1. Multi-hilo en Java: java.lang.Thread Java es un lenguaje de programacin con soporte al multi-hilo; es decir, Java aporta los elementos necesarios para que un programa pueda ser desarrollado en multi-hilo. La base de dichos elementos es la clase java.lang.Thread.. Es la clase necesaria para crear un hilo de ejecucin en Java. Para lanzar en Java un hilo de ejecucin independiente, se debe crea un objeto de la clase Thread e invocar a su mtodo start(), en ese momento el hilo es lanzado y empezar su ejecucin independiente y compitiendo con los otros hilos por los recursos del Sistema, CPU incluida:
Thread miHilo = new Thread(); miHilo.start();

Cuando se ejecuta un programa Java a travs de la mquina virtual:


java MiPrograma

La mquina virtual busca en la clase especificada (MiPrograma) un mtodo llamado main() que debe ser esttico y recibir un nico parmetro que debe ser del tipo String[]. Si lo encuentra, crea un hilo de ejecucin (hilo principal del programa) en el que se ejecutar el cdigo de dicho mtodo main(). Cuando termina de ejecutarse dicho mtodo, la mquina virtual tambin termina su ejecucin y desaparece como proceso activo en el Sistema Operativo. Pero si dentro de la ejecucin del mtodo main() se crea algn hilo y se lanza; la mquina virtual no dejar de ejecutarse hasta que no terminen todos los hilos de ejecucin que se hayan lanzado, aunque el hilo principal haya terminado (es decir, termin de ejecutarse el mtodo main()).

5.2 Especificacin del cdigo de un hilo En el apartado anterior se ha visto como se debe crear y lanzar un hilo en Java; pero no se ha indicado de que forma se especifica el cdigo que se quiere ejecutar en el hilo. Java propone dos formas: Threads por derivacin Se debe crear una nueva clase que extienda de la clase Thread y sobrescriba el mtodo run() (el mtodo run() dentro de la clase Thread no hace nada). Dentro del mtodo run() se especificar el cdigo del hilo. Cuando se quiera lanzar el hilo se debe crear un objeto de dicha clase y ejecutar su mtodo start(); en ese momento, la JVM crea un nuevo hilo que ejecutar el cdigo contenido dentro del mtodo run():
public class SimpleThread extends Thread { public SimpleThread(String str) { super(str); } public void run() { System.out.println(Hola Mundo, soy: +getName()); }

public class SimpleThreadMain { public static void main(String [] args) { Thread miHilo = new SimpleThread(Mi primer hilo); miHilo.start(); }

Threads por implementacin Se debe crear una clase que implemente el interfaz java.lang.Runnable. Este interfaz nicamente define un nico mtodo llamado run(). Dentro de este mtodo se debe especificar el cdigo del hilo. Cuando se quiera lanzar el hilo, se debe crear un objeto de dicha clase, luego crear un objeto Thread al que se le asocia dicho objeto y por ltimo se invoca al mtodo start() del objeto Thread para que el hilo sea lanzado. En ese momento, la JVM crea un nuevo hilo que ejecutar el cdigo contenido dentro del mtodo run():
public class SimpleRunnable implements Runnable { private String nombre; public SimpleRunnable (String str) { this.nombre=str; } public void run() { System.out.println(Hola Mundo, soy: +nombre); }

public class SimpleRunnableMain { public static void main(String [] args) { Runnable miHilo = new SimpleRunnable(Mi primer hilo); Thread hilo = new Thread(miHilo);

hilo.start();

Java aporta la creacin de hilos por implementacin porque no soporta la herencia mltiple. Gracias al interfaz Runnable, se pueden crear hilos que extiendan de una clase distinta a la clase Thread. 5.3 Parada de un hilo Un hilo deja de ejecutarse cuando termina la ejecucin del mtodo run() que corresponda. En los ejemplos anteriores los hilos finalizaran tras mandar a la salida estndar el mensaje de saludo. En ocasiones se precisa que un hilo no termine, ya que se quiere est permanentemente realizando una determinada operacin (por ejemplo escuchar por un puerto a la espera de peticiones o envos de informacin desde otros Sistemas), en esos casos la operacin realizada por el hilo se suele incluir en un bucle de tal manera que el mtodo run no termine nunca:
public class HiloNoTerminaRunnable implements Runnable { public void run() { while(true) { <realizar_operacin_continuamente> } }

En este tipo de Thread, el problema es la detencin del hilo. La clase Thread, en versiones anteriores de Java, dispona del mtodo stop() que detena el hilo. El problema era que est detencin brusca del hilo podra provocar inestabilidad en la aplicacin e incluso en la JVM; por ello, en las versiones actuales de Java, este mtodo ha sido deprecado y actualmente no realiza ninguna accin; permanece en la clase Thread para que los programas que usaban anteriormente este mtodo sigan funcionando. As pues, la detencin del hilo debe ser responsabilidad del programador del Thread que debe proveer en el Thread los mecanismos necesarios para que ste se detenga de manera correcta. Una forma muy extendida consiste en colocar una guarda en el bucle, de tal manera que el valor de esta guarda pueda ser modificado desde fuera del Thread y de esta manera conseguir una detencin correcta del hilo:
public class ControlParadaThread extends Thread { private boolena parado=false; public void run() { while(parado) { <realizar_operacin_continuamente> } <codigo_liberar_recursos> } public boolean isParado() { return this.parado; } public void parar() { this.parado=true;

} public void arranzar() { this.parado=false; this.start(); } }

Invocando desde cualquier otra zona de la aplicacin al mtodo parar() podramos conseguir que el Thread se detuviera correctamente:
miHilo.parar();

Donde miHilo es un objeto de la clase ControlParadaThread que ha sido arrancado; es decir, que en algn momento se ha invocado a su mtodo start() o al mtodo arrancar().. Si quisiramos volver a arrancar el hilo no bastara con poner el atributo parado a false, ya que al poner el atributo a true, finaliz la ejecucin del mtodo run() y por lo tanto finaliz la ejecucin del hilo; por ello, el mtodo arrancar no slo pone el atributo parado a false; si no que invoca al mtodo start(); que es el que realmente provoca que el mtodo run() se ejecute en un hilo independiente. 5.4 Estados de Thread Un Thread Java puede estar en uno de los siguientes estados: Estado Creado Listo Ejecutndose Dormido Descripcin El objeto Thread ha sido creado pero an no ha sido lanzado El objeto Thread ha sido lanzado y est listo para ocupar la CPU que en estos momentos est ocupada por otro Thread. El Thread est en estos momentos ocupando la CPU. El Thread est durante un tiempo sin competir por la CPU, hasta que ese tiempo no pase el Thread no volver a ocupar la CPU aunque no haya ningn otro Thread disponible para ocuparla. El Thread est bloqueado esperando por un recurso (fichero, otro objeto, etc); hasta que el Thread no adquiera dicho recurso no podr volver a competir por la CPU (estado Listo) El Thread ha sido suspendido mediante la invocacin del mtodo suspend(). El Thread no volver a estado Listo (es decir, a competir por la CPU) hasta que otro Thread invoque al mtodo resume() del Thread suspendido. El objeto Thread ha concluido de ejecutar el mtodo run()

Bloqueado

Suspendido

Muerto

5.5 Sincronizacin de Threads Como se ha dicho anteriormente, el un Sistema multi-hilo, los distintos Threads compiten por ocupar los recursos del Sistema. Ciertos recursos no pueden ser accedidos por ms de un Thread a la vez; ya que esto no fuera as, provocara que el recurso no funcionara correctamente (por ejemplo, una impresora). As pues la sincronizacin de Threads garantiza el acceso nico a recursos compartidos; es decir, que en cualquier momento, slo un Thread est accediendo a dicho recurso compartido. 5.5.1 Monitores Java: Sincronizacin implcita La JVM no se tiene que preocupar de garantizar que el acceso a determinados recursos del Sistema es nico (impresoras, ficheros, etc), ya que de esto se encarga en Sistema Operativo. Pero dentro de un programa Java tambin hay recursos compartidos (objetos) cuya sincronizacin s es responsabilidad de la JVM. Por ejemplo supngase que en una aplicacin nicamente existe una instancia de una clase llamada ConsultorBD que es la que ejecuta todas las consultas contra la base de datos. Evidentemente dos Threads no podran acceder directamente a este objeto (recurso compartido) para ejecutar dos sentencias distintas ya que ConsultorBD mezclara ambas peticiones provocando errores. Para evitar esto, y facilitar la sincronizacin de Threads, la JVM asocia a cada objeto un monitor. Cuando un Thread accede a un objeto compartido, bloquea su monitor para, de esta manera, indicar que es l el que posee dicho recurso. Si se produjera un cambio de contexto (es decir, la CPU pasa a estar ocupada por otro Thread) y el nuevo Thread intenta acceder al recurso compartido; detectara que su monitor est bloqueado por otro Thread y por lo tanto este Thread pasara a estado Bloqueado hasta que el otro libere el objeto compartido. El monitor de un objeto no es bloqueado siempre que un Thread accede al objeto al que pertenece; si no que en el cdigo hay que indicar de manera explcita qu partes del objeto hay que sincronizar. Para ello se debe usar la palabra reservada synchronized, la cual puede colocarse en dos zonas distintas: - En la declaracin de un mtodo. Cualquier acceso a ese mtodo provocara que se bloqueara el monitor del objeto, entonces ningn otro Thread podra acceder a cualquier otra parte sincronizada del objeto, hasta que no termine de ejecutarse el mtodo sincronizado:
public synchronized String obtenerResultado() { ... }

A nivel de trozo de cdigo (seccin crtica). Se puede definir un trozo de cdigo de la siguiente manera:
... syncronized(objeto) { ... seccin crtica } ...

Cuando un Thread entra en una seccin crtica, ningn otro Thread podr ejecutar cdigo sincronizado del objeto que se indica al comienzo del bloque sincronizado hasta que no termine de ejecurtarse dicha seccin crtica.

5.5.2 Forzar bloqueos de Threads: sincronizacin explcita Puede ser que una aplicacin Java no precise que el acceso a un determinado recurso compartido (objeto) se haga de uno en uno; pero s que no ms de N Threads accedan directamente a dicho recurso; por ejemplo para controlar la carga que soporta parte de la aplicacin. Por ejemplo, supngase una aplicacin de Gestin de Empleados de una Empresa que una de sus funcionalidades es presentar un informe resumen de las actividades realizadas por cada empleado en un determinado periodo de tiempo. La generacin de dicho informe implica un consumo importante de recursos del sistema; de tal manera que no se aconseja que se lancen ms de 5 informes de este tipo a la vez. Para conseguir esto se podra usar el bloqueo explcito de Threads: cuando se pide un informe de este tipo, se comprueba el nmero de informes que se estn generando en este momento y si ese nmero es mayor o igual a 5; se bloquea el Thread que est haciendo la nueva peticin. Para conseguir esto todo objeto Java cuenta con los siguientes mtodos (son mtodos de la clase Object): - wait(). Fuerza el bloqueo de un Thread hasta que otro Thread le avise. Este mtodo slo puede ser invocado en bloques sincronizados, es decir, cuando el Thread posea el monitor del objeto. Evidentemente cuando el Thread se bloquea mediante el uso de wait() libera el monitor del objeto. El mtodo wait() cuenta con una sobrecarga en la que se puede especificar un tiempo mximo que se quiera que el Thread est bloqueado; si transcurrido dicho tiempo el Thread no es liberado; se desbloquea automticamente. - notify(). Despierta a un Thread que se bloque mediante la invocacin del mtodo wait() del mismo objeto. La JVM elige aleatoriamente uno de los Threads bloqueados por este objeto y lo despierta. Este mtodo tambin debe ser ejecutado en bloques sincronizados. El mtodo notifyAll(), libera a todos los Threads bloqueados por el objeto. Como ejemplo del uso de los mtodos wait() y notify() se presenta el cdigo de una clase que garantiza que no ms de N peticiones de informe son procesadas a la vez.
public class GeneradorInformes { private int concurrenciaMaxima; private int numPeticionesEnCurso; public GeneradorInformes(int concurrenciaMaxima) { this.concurrenciaMaxima= concurrenciaMaxima; this.numPeticionesEnCurso= numPeticionesEnCurso; } public synchronized void generaInforme() { if(numPeticionesEnCurso>= concurrenciaMaxima) { this.wait(); //concurrencia mxima alcanzada } //Siempre que se llegue a esta altura //del cdigo se tiene garanta que como mucho //hay concurrenciaMaxima 1 peticiones atendindose this.numPeticionesEnCurso++; generaInforme_();

//tras generar el informe, notificamos a algn Thread de los que //estn bloqueados para que contine su ejecucin this.numPeticionesEnCurso--; this.notify();

private void generaInforme_() { ... }

Como se puede observar en el cdigo el recurso compartido del ejemplo es el objeto de la clase GeneradorInformes. nicamente indicar que cuando un Thread es bloqueado mediante un mtodo wait(); para que vuelva a despertarse se debe invocar al mtodo notify() del mismo objeto; es decir, no basta que el monitor del objeto compartido quede libre. Del mismo modo si hay N Threads bloqueados por un objeto; ser preciso invocar N veces al mtodo notify() de dicho objeto para liberarlos a todos (a no se que se invoque al mtodo notifyAll()). 5.6 Prioridad en los Thread Con el fin de conseguir una correcta ejecucin de un programa se establecen prioridades en los threads, de forma que se produzca un reparto ms eficiente de los recursos disponibles. As, en un determinado momento, interesar que un determinado proceso acabe lo antes posible sus clculos, de forma que habr que otorgarle ms recursos (ms tiempo de CPU). Esto no significa que el resto de procesos no requieran tiempo de CPU, sino que necesitarn menos. La forma de llevar a cabo esto es gracias a las prioridades. Cuando se crea un nuevo thread, ste hereda la prioridad del thread desde el que ha sido inicializado. Las prioridades viene definidas por variables miembro de la clase Thread, que toman valores enteros que oscilan entre la mxima prioridad MAX_PRIORITY (normalmente tiene el valor 10) y la mnima prioridad MIN_PRIORITY (valor 1), siendo la prioridad por defecto NORM_PRIORITY (valor 5). Para modificar la prioridad de un thread se utiliza el mtodo setPriority(). Se obtiene su valor con getPriority(). El algoritmo de distribucin de recursos en Java escoge por norma general aquel thread que tiene una prioridad mayor, aunque no siempre ocurra as, para evitar que algunos procesos queden dormidos permanentemente. 5.7 Acceso al Thread actual La clase Thread cuenta con una serie de mtodos estticos cuyo efecto se veran sobre el Thread actual; es decir, el Thread sobre el que se est ejecutando el cdigo: Mtodo currentThread() sleep() Descripcin Devuelve una referencia al Thread actual. Duerme al Thread actual durante el tiempo que se indica. Durante dicho tiempo el Thread no compitir por la CPU, incluso cuando ningn otro Thread est ocupando la CPU.

yield()

Interrupted()

Hace que el Thread actual renuncie a la CPU y sta pase a estar ocupada por otro Thread. El Thread actual no es bloqueado; simplemente pierde la CPU pero est listo para volver a ocuparla Indica si el Thread actual ha sido interrumpido en algn momento. La invocacin de este mtodo limpia el estado de interrumpido del thread; por lo que si se vuelve a invocar este mtodo antes de que el Thread sea interrumpido, devolver false.

Los mtodos sleep() y yield() son muy tiles para conseguir un mejor reparto de CPU entre los distintos hilos de nuestro programa. Por ejemplo, cuando un thread debe estar continuamente ejecutndose para realizar una determinada operacin (como esperar peticiones en un puerto); puede ser que consuma demasiada CPU solamente esperando la llegada de una nueva peticin. Se podran usar los mtodos anteriores para conseguir una reparto ms equitativo:
public class ControlParadaThread extends Thread { private boolena parado=false; public void run() { while(parado) { if(recibidaPeticion()) { procesarPeticion(); }else { yield(); } } }

En este ejemplo, si no se ha recibido una nueva peticin, se cede la CPU a otro hilo; de esta forma se consigue un reparto ms equitativo del tiempo de la CPU.

6. Programacin Socket en Java Un socket es un punto final en un enlace de comunicacin de dos vas entre dos programas que se ejecutan en la red. Las clases Socket son utilizadas para representar conexiones entre un programa cliente y otro programa servidor. El paquete java.net proporciona dos clases; Socket y ServerSocket, que implementan los lados del cliente y del servidor de una conexin, respectivamente. Una aplicacin servidor normalmente escucha a un puerto especfico esperando una peticin de conexin de un cliente. Cuando llega una peticin de conexin, el cliente y el servidor establecen una conexin dedicada sobre la que poder comunicarse. Durante el proceso de conexin, el cliente es asignado a un nmero de puerto, y ata un socket a ella. El cliente habla al servidor escribiendo sobre el socket y obtiene informacin del servidor cuando lee de l. Igualmente, el servidor obtiene un nuevo nmero de puerto local (necesita un nuevo puerto para poder recibir nuevas peticiones de conexin a travs del puerto original.) El servidor tambin ata un socket a este puerto local y comunica con l mediante la lectura y escritura sobre l. El cliente y el servidor deben ponerse de acuerdo sobre el protocolo ,esto es, debe ponerse de acuerdo en el lenguaje para transferir la informacin de vuelta a travs del socket. 6.1 Socket en Cliente Cuando una aplicacin Java cliente precisa conectarse con otra aplicacin servidor (que no necesariamente tiene porque ser java), la cual espera recibir peticiones a travs de un puerto; debe establecer una conexin con la mquina-puerto en la que est escuchando la aplicacin servidor creando para ello un objeto de la clase java.net.Socket:
Socket cliente = new Socket(url_maquina_cliente,<num_puerto>);

En el momento en que se crea el objeto Socket, Java intenta establecer una conexin con la direccin y puerto que se especifica; si no se consigue se lanza una de las siguientes excepciones: - UnknownHostException. Host desconocido - IOException. Si hay cualquier otro problema al establecer la conexin; como por ejemplo que no hay ninguna aplicacin escuchando en el puerto especificado. La clase Socket cuenta con varios constructores distintos, mediante los cuales se puede especificar la url de la mquina a la que nos queremos conectar de formas distintas: - Usando un objeto String y un entero, que representan la url de la mquina (su direccin IP o su nombre) y el nmero de puerto. - Usando un objeto java.net.InetAddres y un entero, que representan la ip de la mquina y el nmero de puerto. - Usando dos objetoa java.net.SocketAddres que representan la direccin a la que nos queremos conectar y la direccin cliente. La clase SocketAddres es una clase abstracta que representa la direccin de una Socket de manera independiente del protocolo de comunicacin que se use. Si la creacin del objeto Socket no ha producido ninguna excepcin, significa que la aplicacin servidor ha aceptado nuestra peticin y que por lo tanto se ha establecido la

comunicacin entre ambas aplicaciones. A partir de este momento la aplicacin cliente, usando el objeto Socket podr mandar y recibir informacin de la aplicacin servidor. Por ltimo indicar que se pueden crear Socket usando el contructor por defecto; es decir, sin especificar a qu mquina-puerto se debe conectar el Socket y posteriormente usar el mtodo connect() para realizar la conexin a una mquina-puerto. 6.2 Lectura/Escritura de Socket Cliente Tras la creacin del objeto Socket, la conexin ha quedado establecida y, como se indic anteriormente, la aplicacin cliente puede mandar y recibir informacin de la aplicacin servidor. Para ello debe usar los siguientes mtodos de la clase Socket: - getInputStream(). Devuelve un objeto java.io.InputStream del que se podr recibir informacin de la aplicacin servidor. Sobre este InputStream se puede montar cualquier otro flujo que facilite la lectura de los datos; por ejemplo, si la informacin que se enva est en formato carcter se puede montar un java.io.BufferedReader que permite la lectura lnea a lnea:
Socket cliente = new Socket(url_maquina_cliente,<num_puerto>); InputStream in = cliente.getInputStream(); BufferedReader inLineas = new BufferedReader(new InputStreamReader(in));

getOutputStream(). Devuelve un objeto java.io.OutputStream con el que se podr mandar informacin a la aplicacin servidor. Sobre este OutputStream se puede montar cualquier otro flujo que facilite la escritura de los datos; por ejemplo, si la informacin que se enva est en formato carcter se puede montar un java.io.PrtinWriter que permite la escritura lnea a lnea:
Socket cliente = new Socket(url_maquina_cliente,<num_puerto>); OutputStream out = cliente.getOutputStream(); PrintWriter outLineas = new PrintWriter (new OutputStreamWriter(out));

La invocacin de cualquiera de estos mtodos probocar una excepcin de tipo java.io.IOException si el estado del Socket no es correcto (por ejemplo que el Socket ya este cerrado o que an no est conectado). Mediante los mtodos isClosed() y isConnected() se puede consultar si el Socket est cerrado o conectado. Cuando se realiza una operacin de lectura del socket y la aplicacin servidor an no ha mandado nada o no ha mandado lo suficiente como para que concluya la operacin de lectura, que se quiere realizar, se probocar un bloqueo en la aplicacin cliente, hasta que la aplicacin servidor mande la suficiente informacin como para que concluya la operacin de lectura que se quiere realizar o la aplicacin servidor se desconecte, por ejemplo, en este cdigo:
Socket cliente = new Socket(url_maquina_cliente,<num_puerto>); InputStream in = cliente.getInputStream(); Reader reader = new InputStreamReader(in); BufferedReader inLineas = new BufferedReader(reader); String linea = inLineas.readLine();

La ejecucin de la lnea de cdigo resaltada en negrita se bloquear hasta que la aplicacin servidor escriba un salto de lnea. Para evitar este bloqueo se puede utilizar el mtodo setSoTimeout(int milisegundos) para establecer el tiempo mximo que se puede esperar en el mtodo read() una peticin cliente. Si este tiempo trascurre y no se recibe ninguna peticin, el mtodo read() termina lanzando una excepcin del tipo java.net.SocketTimeoutException. 6.3 Socket en Servidor Cuando una aplicacin Java quiere poder atender peticiones remotas que realicen otras aplicaciones (que no necesariamente debe ser Java) a travs de un puerto, debe usar objeto java.net ServerSocket. Un objeto ServerSocket se ata a un puerto de la mquina a la espera de peticiones:
SocketServer servidor = new SocketServer(<num_puerto>);

Si no se puede atar el puerto al Socket, porque por ejemplo el puerto ya est acupado se lanza una excepcin del tipo java.io.IOException. Tras la creacin del objeto ServerSocket, la aplicacin ya est lista para recibir peticiones de los clientes:
Socket comunicacionCliente = servidor.accept();

El hilo de ejecucin de la aplicacin cliente queda bloqueado hasta que se reciba una peticin de un cliente. Antes de invocar al mtodo accept() se puede utilizar el mtodo setSoTimeout(int milisegundos) para establecer el tiempo mximo que se puede esperar en el mtodo accept() una peticin cliente. Si este tiempo trascurre y no se recibe ninguna peticin, el mtodo accept() termina lanzando una excepcin del tipo java.net.SocketTimeoutException. El mtodo accept() devuelve un objeto Socket que la aplicacin servidor debe usar para mandar y recibir informacin del cliente. Evidentemente este Socket se ata a un puerto distinto para que la aplicacin servidor pueda seguir atendiendo otras peticiones. Hasta que no se vuelva a invocar al mtodo accept(), cualquier peticin que se reciba se perder. Para evitar esto, tras la recepcin de una peticin, se crea un hilo independiente que la atiende y el hilo principal se pone nuevamente a esperar nuevas peticiones:
SocketServer servidor = new SocketServer(<num_puerto>); While(!terminar) { Socket s = servidor.accept(); ProcesadorPeticion procesador = new ProcesadorPeticion(s); Thread hilo = new Thread(procesador); Hilo.start(); } public class ProcesadorPeticion implemments Runnable { private Socket comunicacionCliente; public ProcesadorPeticion(Socket s) { comunicacionCliente=s; } public void run() {

<cdigo_procesar_peticion>

6.4 Cierre de un Socket Hasta que no se invoque al mtodo close() de la clase Socket o SocketServer, el puerto al que est atado el socket no es liberado y por lo tanto ninguna otra aplicacin podr usar dicho puerto. Por ello se recomienda que tras finalizar el uso de un socket (tanto cliente como servidor) ste sea cerrado:
socket.close();

Cualquier intento de usar un socket cerrado provocar una excepcin de tipo java.io.IOException. Como se indic anteriormente, mediante el mtodo isClosed() se puede consutar si el socket est o no cerrado.

7. Inner Class Las inner class (o clases anidadas o internas) son clases que se definen dentro del cuerpo de otra clase:
public class ClaseContenedora { public class ClaseContenida { } }

Se definen cuatro tipos de inner class: 1. Estticas. 2. Miembro 3. Locales 4. Annimas Hay que sealar que la JVM no sabe nada de inner classs, ya que el compilador convierte estas clases en clases normales, contenidas en ficheros *.class cuyo nombre es ClaseContenedora$ClaseInterna.class. 7.1 Inner class estticas Las inner class estticas se definen con el modificar static en la declaracin de la clase anidada:
public class ClaseContenedora { public static class ClaseContenida { } }

Para crea un objeto de una inner class no se precisa un objeto de la clase contenedora; sino que se pueden crear objetos de este tipo directamente. Estos objetos pueden acceder a toda la parte esttica (tanto pblica como privada) de la clase contenedora; pero no pueden acceder a la parte no esttica; ya que no se crean asociados a una instancia de la clase contenedora:
package listaelementos; public class Lista { private static int NUM_MAX_EMELEMNTOS=100; private Object [] elementos; public static class ElementoLista { private Object valor; public ElementoLista(Object valor) { this.valor=valor; } public getValor() { return this.valor; } public void metodoConErrores() { //acceso correcto int n = Lista.NUM_MAX_ELEMENTOS; //acceso incorrecto elementos no es essttico

Object primerElemento = Lista.elementos[0]; } }

public add(ElementoLista elemento) { ... }

Una inner class esttica podr ser usada desde fuera de la clase contenedora, si el modificador de acceso lo permite, por ejemplo:
package aplicacion; import listaelementos.Lista; import listaelementos.Lista.ElementoLista; public class GestionEmpleados { private Lista empleados; public void addEmpleado(String nombre){ ElementoCola elemento = new ElementoCola(nombre); empleados.add(elemento); } }

Como se puede ver, la peculiaridad para acceder a la clase anidada est en el import. Por ltimo indicar que Java permite definir interfaces anidados estticos 7.2 Inner class miembro Las inner class miembro (o simplemente inner class) se definen sin usar el modificar static en la declaracin de la clase anidada:
public class ClaseContenedora { public class ClaseContenida { } }

Toda inner class existe dentro de un objeto de la clase contenedora; es decir, no se pueden crear objetos de clases inner class miembro que no estn asociados a un objeto de la clase contenedora:
ClaseContenedora objClaseContenedora = new ClaseContenedora(); ClaseContenida objClaseContenida = objClaseContenedora.new ClaseContenida();

Como se puede observar, la creacin de un objeto de una clase anidada se debe hacer a travs de un objeto de la clase contenedora; al que queda asociado. Este objeto anidado puede acceder a todos los miembros de la clase contenedora (tanto pblicos como privados); del mismo modo la clase contenedora tambin puede acceder a todos los miembros de sus objetos anidados:
package listaelementos; public class Lista { private static int NUM_MAX_EMELEMNTOS=100; private Object [] elementos;

public static class ElementoLista { private Object valor; public ElementoLista(Object valor) { this.valor=valor; } public getValor() { return this.valor; } public void metodoSinErrores() { //acceso correcto int n = Lista.NUM_MAX_ELEMENTOS; //acceso correcto Object primerElemen = Lista.this.elementos[0]; } }

public add(ElementoLista elemento) { ... }

La palabra reservada this en una inner class hace referencia a los miembros de la propia clase; para referirse a los miembros de la clase contenedora, a la palabra this se debe anteponer el nombre de la clase contenedora; como se ve en el ejemplo:
Object primerElemen = Lista.this.elementos[0];

Una clase interna miembro puede contener otra clase interna miembro, hasta el nivel que se desee. Por ejemplo, C es una clase interna de B, que a su vez es una clase interna de A:
A a = new A();//se crea un objeto de la clase A A.B b = a.new B();//se crea un objeto de B dentro del objeto a A.B.C c = b.new C();//se crea un objeto de C dentro del objeto b

Las inner class miembro no pueden tener miembros estticos (ni atributos ni mtodos). 7.3 Inner class locales Las inner class locales se declaran dentro de un bloque de cdigo (conjunto de sentencias java contenidas entre llaves), por ejemplo un mtodo:
public class ClaseContenedora { public void metodo() { ... class InnerClassLocal { ... } ... InnerClassLocal icl = new InnerClassLocal(); ... } }

Caractersticas de las clases internas locales: 1. Como las variables locales, slo son visibles y utilizables en el bloque de cdigo en el que estn definidas. 2. Tiene acceso a todas las variables miembro y mtodos de la clase contenedora, si ha sido definida desde un mtodo no sttico de la clase contenedora; en ese caso, la palabra this se puede utilizar de la misma forma que en las clases internas miembro. Es decir, en esos casos la clase interna local queda asociada a la instancia de la clase contenedora:
public class ClaseContenedora { private String atributo; public void metodoNoEstatico() { ... class InnerClassLocal_1 { public void metodoInnerClass() { //acceso correcto String s = ClaseContenedora.this.atributo; } } ... } public static void metodoEstatico() { ... class InnerClassLocal_1 { public void metodoInnerClass() { //acceso incorrecto String s = ClaseContenedora.this.atributo; } } ... }

3. Pueden utilizar las variables locales y argumentos del mtodo en el que han sido definidas, pero slo si son final (esto es as porque en realidad la clase interna local trabaja con sus copias de las variables locales y por eso se exige que sean final y no se puedan cambiar).
public class ClaseContenedora { private String atributo; public void metodo (String param1, final String param2) { final int vble=0; class InnerClassLocal { public void metodoInnerClass() { //acceso incorrecto String s1 = param1; //acceso correcto String s2 = param2; //acceso correcto int n = vble; } } ... }

4. No pueden ser declaradas public, protected, private, pues su visibilidad es siempre la de las variables locales. 5. No pueden ser estticas y por lo tanto no pueden tener miembros estticos 7.4 Inner class annimas Las inner class annimas son muy similares a las inner class locales, pero sin nombre. En las clases internas locales primero se define la clase y luego se crea uno o ms objetos. En las clases internas annimas se unen estos dos pasos: como la clase no tiene nombre slo se puede crear un nico objeto. En el siguiente ejemplo se presenta una clase annima que sobrescribe el mtodo toString() de la clase Object:
public class ClaseContenedora { public void metodo() { ... Object o = new Object() { public String toString() { return super.toString()+" Clase anonima"; } }; } System.out.println("Inner class anonima: "+ o);

Las clases annimas requieren una extensin de la palabra clave new. Se definen en una expresin de Java que est incluida en una asignacin o que se pasa como parmetro a mtodo.Formas de definir una clase annima: 1. La palabra new seguida del nombre de la clase de la que hereda (sin extends) y la definicin de la clase annima entre llaves {}. El nombre de la super-clase puede ir seguido de argumentos para su constructor. 2. La palabra new seguida del nombre de la interface que implementa (sin implements) y ladefinicin de la clase annima entre llaves {}. En este caso la clase annima deriva de Object. El nombre de la interface va seguido por parntesis vacos, pues el constructor de Object no tiene argumentos.

8. Reflexin en Java La reflexin Java es un mecanismo que nos permite obtener informacin de las clases en tiempo de ejecucin; as como cargar y usar nuevas clases cuyos nombres no aparecen explcitamente en el cdigo de nuestra aplicacin. Mediante la reflexin se puede, por ejemplo, a partir de un objeto obtener que campos constructores y mtodos posee, invocar dichos mtodos, crear nuevas instancias de la clase del objeto.... 8.1 La base de la reflexin en Java: la clase java.lang.Class La base de la reflexin en Java la constituye la clase Class la cual contiene informacin de un clase (meta-clase). Para cada clase Java que la JVM carga se crea un objeto Class asociado a dicha clase que contiene la informacin de la clase que se acaba de cargar: mtodos, campos, constructores... El objeto Class asociado a una clase se puede obtener de forma esttica (en tiempo de compilacin) de dos maneras distintas: - Mediante la expresin <nombre_de_clase>.class se obtiene el objeto Class asociado a la clase:
Class classDeString = String.class

La clase Object cuenta con el mtodo getClass() que devuelve el objeto Class asociado a la clase de la que es instancia el objeto:
String cadena = new String(una cadena); Class classDeString = cadena.getString();

Ambas formas devuelve en mismo objeto, ya que todos los objetos de una misma clase llevan asociado el mismo objeto Class; incluso todos los objetos de una clase son creados a travs de dicho objeto Class. Realmente todo tipo Java lleva asociado un objeto Class, es decir no slo las clases llevan asociado un tipo Class; tambin las interfaces, arrays; incluso los tipos primitivos:
Class classDeInt = int.class;

A travs de la sentencia anterior se obtendra el objeto Class asociado al tipo primitivo int. La clase Class cuenta con el mtodo isPrimitive() que devuelve verdadero si el objeto Class est asociado a un tipo primitivo. Del mismo modo cuenta con el mtodo isArray() mediante el cual se puede identificar si el objeto Class est asociado a un array. 8.2 Obtencin de informacin sobre clases en tiempo de ejecucin: mtodo forName() Las dos formas anteriores que hemos visto de obtener un objeto Class son de forma esttica (en tiempo de compilacin), es decir tenemos que conocer de antemano la clase de la que queremos obtener el objeto Class.

Pero mediante el mtodo esttico forName() de la clase Class se puede obtener el objeto Class de una clase que no tiene porque conocerse en tiempo de compilacin. En esto reside la potencia de la reflexin java: en la carga y uso de clases que no tienen porque aparecer durante la compilacin; sino que son incorporadas a la JVM dinmicamente durante la ejecucin de la aplicacin y que nos permitirn variar sensiblemente el comportamiento de sta. La base de esto ltimo es el polimorfismo. Las aplicaciones se desarrollan partiendo de tipos base (generalmente interfaces o clases abstractas); pero sin conocer realmente las clases exactas que se usarn; ya que ests slo podrn ser conocidas en tiempo de ejecucin. Estas clases finales extienden de los tipos bsicos que s son conocidos por el programa y gracias a esto, nuestra aplicacin podr usarlos correctamente en tiempo de ejecucin. Los tipos base definen un interfaz (conjunto de mtodos) pblico que sus subclases implementarn y dicho interfaz es el que usa nuestra aplicacin para trabajar con estos elementos sin necesidad de conocerlos en tiempo de compilacin. Posteriormente, cuando la aplicacin se ejecute, dependiendo de qu tipo concreto se use, se obtendr uno u otro resultado. Por ejemplo, una pequea aplicacin que pinta figuras cuyas clases deben implementar el interfaz Figura:
public interface Figura { public void dibujar(); }

Es decir, nuestra aplicacin sabr manejar aquellas figuras que implementen este interfaz y usarlas correctamente para que se pinten. A continuacin se muestra el cdigo fuente de dos implementacin de este interfaz: las clases Triangulo y Cuadrado.
package sevinge.cursos.reflexion; public class Triangulo implements Figura { public void dibujar() { System.out.println(" a "); System.out.println(" a a "); System.out.println(" a a "); System.out.println(" a a "); System.out.println("aaaaaaaaa"); } } package sevinge.cursos.reflexion; public class Cuadrado implements Figura { public void dibujar() { System.out.println("aaaaaaaaa"); System.out.println("a a"); System.out.println("a a"); System.out.println("a a"); System.out.println("aaaaaaaaa"); }

Gracias a la reflexin la aplicacin PintarFigura no necesita conocer los tipos Cuadrado y Triangulo; ni ningn otro que implemente el interfaz Figura; slo necesita saber que los elementos que maneja son del tipo Figura y los usar a partir del interfaz pblico que ofrece este tipo:
package sevinge.cursos.reflexion; public class PintarFigura { public static void main(String[] args) throws ClassNotFoundException, ClassCastException, InstantiationException, IllegalAccessException { if (args.length == 0) { System.out.println("Falta el nombre de la clase a usar para pintar la figura"); return; } //Se obtiene un objeto Class de la clase que pinta figuras Class claseFigura = Class.forName(args[0]); //A partir del objeto Class se crea una instacia del objeto Figura a pintar Object objFigura = claseFigura.newInstance(); Figura figura = (Figura) objFigura; //Se pinta la figura figura.dibujar(); } }

El uso de la aplicacin sera, por ejemplo:


java cp . sevinge.cursos.reflexion.PintarFiguras sevinge.cursos.reflexion.Triangulo

Y la salida obtenida:
a a a a a a a aaaaaaaaa

El programa espera recibir como parmetro el nombre de la clase Figura que se desea pintar. A partir de este nombre de clase se procede a una carga dinmica de dicha clase utilizando el mtodo forName():
Class claseFigura = Class.forName(args[0]);

A partir de este objeto Class se crea una nueva instancia de la clase usando el mtodo newInstance():
Object objFigura = claseFigura.newInstance();

El mtodo newInstance() devuelve un objeto de la clase Object, pero la aplicacin PintarFigura sabe que debe ser de una clase que implemente el interfaz Figura; por lo que realiza un casting explcito:
Figura figura = (Figura) objFigura;

Y aqu es donde est la clave; la aplicacin PintarFigura no sabe de que tipo exacto es objFigura ni le interesa; pero si sabe que debe implementar el interfaz Figura, as que trabaja con el objeto usando los mtodos que ofrece este interfaz pero despreocupndose del tipo real del objeto (abstraccin). Una vez que se tiene un objeto de tipo Figura, la aplicacin puede trabajar con l:
figura.dibujar();

Como se puede observar, en el cdigo de PintarFigura no aparece ninguna referencia a las clases Triangulo y Cuadrado, la aplicacin PintarFigura est totalmente desacoplada de los tipos concretos de figuras que se definan, con lo que si se incorporarn nuevos tipos de figura, la aplicacin sera capaz de trabajar con ellos sin necesidad de recompilarla. Por ltimo se presenta en el siguiente cuadro los distintos tipos de errores que pueden ocurrir en la aplicacin y que estn declarados en la clusula throws del mtodo main() de PintarFigura: Tipo Descripcion Lnea de cdigo en PintarFigura
Class claseFigura = Class.forName(args[0]);

ClassNotFoundException Este error ocurre con la invocacin del mtodo esttico forName() de la clase Class si la clase que se quiere cargar no existe InstantiationException Este error ocurre con la invocacin del mtodo newInstance() de la clase Class si la clase de la que se quiere crear una nueva instancia no cuenta con un constructor por defecto IllegalAccessException Este error ocurre con la invocacin del mtodo newInstance() de la clase Class si la clase de la que se quiere crear una nueva instancia no tiene declarado como pblico el constructor por defecto ClassCastException Este error ocurre cuando se intenta efectuar un casting explcito no vlido

Object objFigura = claseFigura.newInstance();

Object objFigura = claseFigura.newInstance();

Figura figura = (Figura) objFigura;

8.3 Obtencin de informacin sobre clases en tiempo de ejecucin: Constructores La clase Class permite obtener los constructores pblicos de los que dispone la clase. Cada constructor es representado mediante un objeto de la clase java.lang.reflect.Constructor:
Class clase = Class.forName(<nombre_de_clase>); Constructor [] constructores = clase.getConstructors();

Mediante el mtodo getConstructors() se obtiene una array con todos los constructores pblicos que hay definidos en la clase. Si se devuelve un array vaco es que la clase no contiene ningn constructor pblico. De esta otra forma, se obtiene un constructor concreto:
Class clase = Class.forName(<nombre_de_clase>); Class [] clasesParametros = new Class[2]; clasesParametros[0] = String.class; clasesParametros[1] = int.class; Constructor constructor = clase.getConstructor(clasesParametros);

Se obtendra un constructor pblico de la clase que recibe como parmetro un objeto String y un entero. Se lanzar una excepcin del tipo NoSuchMethodException si no existe en la clase un constructor que reciba esos parmetros. Las principales funcionalidades que ofrece la clase Constructor son las siguientes: Mtodo
Object newInstance(Object[] initargs)

Class[] getExceptionTypes() Class[] getExceptionTypes()

Descripcin Crea un nuevo objeto de la clase a la que pertenece el constructor. El array de objetos que recibe como parmetro se corresponde con los parmetros que recibe el constructor. Para los tipos primitivos se debe usar la clase envoltura correspondiente. Devuelve una array con los tipos de los parmetros que recibe el constructor. Devuelve un array con los tipos deferentes de excepciones que puede lanzar el constructor.

Veamos un ejemplo en el que se crear un objeto de la clase Participante que cuenta con un nico constructor que recibe el nombre y la posicin del participante:
package sevinge.cursos.reflexion; public class Participante { private String nombre;

private int posicion; public Participante(String nombre, int posicion) { super(); this.nombre=nombre; this.posicion=posicion; } public String getNombre() { return this.nombre; } public int getPosicion() { return this.posicion; } public String toString() { return ""+this.posicion+" "+this.nombre; } }

La clase CreadorParticipante crea un objeto Participante, pero usando la reflexin java:


package sevinge.cursos.reflexion; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class CreadorParticipante { public static void main(String[] args) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, ClassNotFoundException { //Se obtiene el objeto Class Class claseParticipante = Class.forName("sevinge.cursos.reflexion.Participante"); //Se crea el array con los objetos Class que //representan los parmetros del constructor //que se quiere invocar Class [] clasesParametros = new Class[2]; clasesParametros[0] = String.class; clasesParametros[1] = int.class; //Se obtiene el constructor buscado Constructor constructor = claseParticipante.getConstructor(clasesParametros); //Se crea una instancia de Participante usando este constructor //Primero se crea el array de object con el valor de los parmetros Object [] parametros = new Object [2]; parametros[0] = "Francisco"; parametros[1] = new Integer(1); //se usa la clase envontura //Se invoca al mtodo newInstance para crear el objeto Participante participante = (Participante) constructor.newInstance(parametros); System.out.println("Participante: "+participante); } }

8.4 Obtencin de informacin sobre clases en tiempo de ejecucin: Campos La clase Class permite obtener los campos pblicos de los que dispone la clase. Cada campo es representado mediante un objeto de la clase java.lang.reflect.Field:
Class clase = Class.forName(<nombre_de_clase>); Field [] campos = clase.getFields();

Mediante el mtodo getFields() se obtiene una array con todos los campos pblicos que hay definidos en la clase. Si se devuelve un array vaco es que la clase no contiene ningn campo pblico. Se puede obtener un campo concreto de una clase a partir del nombre de dicho campo:
Class clase = Class.forName(<nombre_de_clase>); Field campo = clase.getField(<nombre_del_campo);

Se lanzar una excepcin del tipo NoSuchFieldException si no existe en la clase un campo con ese nombre. Las principales funcionalidades que ofrece la clase Field son las siguientes: Mtodo
Object get(Object obj)

void set(Object obj, Object value)

Class getType()

Descripcin Devuelve el valor de campo al que representa el objeto Field para el objeto que recibe como parmetro. Evidentemente este objeto debe ser de la clase a la que pertenece el campo. Existen mtodos equivalentes que devuelve tipos primitivos: getInt(), getBoolean()... Establece el valor de campo al que representa el objeto Field para el objeto que recibe como parmetro. Evidentemente este objeto debe ser de la clase a la que pertenece el campo. Existen mtodos equivalentes que establecen tipos primitivos: setInt(), setBoolean()... Devuelve el objeto Class asociado al tipo del campo

Supongamos que los campos de la clase Participante son pblicos, en el siguiente ejemplo, la clase EstablecerDatosParticipante cambia el valor de los atributos de un objeto Paticipante usando la reflexin Java:
package sevinge.cursos.reflexion; import java.lang.reflect.Field; public class EstablecerDatosParticipante { public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException { //Se crea el objeto Participante Participante participante = new Participante("Francisco",1); System.out.println("Participante (antes de la reflexion): "+participante);

//Se obtiene el objeto Class Class claseParticipante = participante.getClass(); //Se obtiene el campo nombre Field campoNombre = claseParticipante.getField("nombre"); //Se modifica el valor del campo nombre campoNombre.set(participante,"Carlos"); //Se obtiene el campo posicion Field campoPosicion = claseParticipante.getField("posicion"); //Se modifica el campo posicion campoPosicion.setInt(participante,2); System.out.println("Participante (despues de la reflexion): "+participante); } }

8.5 Obtencin de informacin sobre clases en tiempo de ejecucin: Mtodos La clase Class permite obtener los mtodos pblicos de los que dispone la clase. Cada mtodo es representado mediante un objeto de la clase java.lang.reflect.Method:
Class clase = Class.forName(<nombre_de_clase>); Method [] metodos = clase.getMethods();

Mediante el mtodo getMethods() se obtiene una array con todos los mtodos pblicos que hay definidos en la clase. Si se devuelve un array vaco es que la clase no contiene ningn mtodo pblico. Se puede obtener un mtodo concreto a partir del nombre de ste y los tipos (objetos Class) que recibe como parmetros, que es lo que constituye la signatura del mtodo:
Class clase = Class.forName(<nombre_de_clase>); Class [] clasesParametros = new Class[2]; clasesParametros[0] = String.class; clasesParametros[1] = int.class; Method metodo = clase.getMethod(<nombre_del_metodo>,clasesParametros);

Se obtendra un mtodo pblico de la clase llamado <nombre_del_metodo> que recibe como parmetro un objeto String y un entero. Se lanzar una excepcin del tipo NoSuchMethodException si no existe en la clase un mtodo con ese nombre que reciba esos parmetros. Si se quiere obtener un mtodo que no recibe parmetros, se pasar al mtodo getMethod() null como array con los tipos de los parmetros. Las principales funcionalidades que ofrece la clase Method son las siguientes: Mtodo
Object invoke(Object obj, Object[] args)

Descripcin Invoca al mtodo asociado al objeto Field para el objeto que recibe como parmetro. Evidentemente este objeto debe ser de la clase a la que pertenece el mtodo. El array de objetos que recibe como parmetro se corresponde con los parmetros que recibe el mtodo. Para los tipos primitivos se debe usar la clase envoltura

Class[] getExceptionTypes() Class[] getExceptionTypes()

correspondiente. Devuelve una array con los tipos de los parmetros que recibe el mtodo. Devuelve un array con los tipos deferentes de excepciones que puede lanzar el mtodo.

la clase MostrarDatosParticipante muestra los datos de un objeto Participante invocando a sus mtodo pblicos getNombre() y getPosicion() usando reflexin:
package sevinge.cursos.reflexion; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class MostrarDatosParticipante { public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { //Se crea el objeto Participante Participante participante = new Participante("Francisco",1); //Se obtiene el objeto Class Class claseParticipante = participante.getClass(); //Se obtiene el mtodo getNombre Method metodoGetNombre = claseParticipante.getMethod("getNombre",null); //Se invoca al mtodo String nombre = (String) metodoGetNombre.invoke(participante,null); //Se obtiene el mtodo getPosicion Method metodoGetPosicion = claseParticipante.getMethod("getPosicion",null); //Se invoca al mtodo Integer pos = (Integer) metodoGetPosicion.invoke(participante,null); System.out.println(""+pos+" "+nombre); } }

8.6 Obtencin de informacin sobre clases en tiempo de ejecucin: Obtencin de la parte no pblica de una clase La clase Class dispone de los mtodos: 1. 2. 3. 4. 5. 6.
Constructor[] getDeclaredConstructors() Constructor getDeclaredConstructor(Class[] parameterTypes) Field[] getDeclaredFields() Field getDeclaredField(String name) Method[] getDeclaredMethods() Method getDeclaredMethod(String name,Class[] parameterTypes)

Para acceder tanto a la parte pblica como privada de la clase (tambin se obtienen los miembros de mbito paquete y protegido). Evidentemente la parte no pblica de la clase no podr ser usada, es decir, si por ejemplo se intenta usar el mtodo invoke() de un mtodo privado se lanzar una excepcin de tipo IllegalAccessException.

8.7 Otras caractersticas de la clase Class Mediante la clase Class se pude obtener tambin qu intefaces implementa la clase y cual es sus superclase: 1. Class getSuperclass(). Devuelve el objeto Class asociado a la Superclase de la clase. Si el objeto Class est asociado a un tipo primitivo, este mtodo devuelve null. Si el objeto Class est asociado a una interface, tambin devuelve null; lo mismo que para el objeto Class asociado a la clase Object. 2. Class[] getInterfaces(). Devuelve una lista con todos los interfaces implementados por la clase. Si el objeto Class est asociado a un tipo primitivo devuelve un array vaco. Si el objeto Class est asociado a un interface, devuelve la lista de interfaces de los que extiende. Slo se devuelve los interfaces que directamente implementa la clase; es decir, si la clase extiende de otra clase que implementa otros interfaces, esos interfaces no son devueltos por este mtodo. La siguiente clase de ejemplo, mostrara por pantalla la jerarqua completa de la clase que se especifique por parmetro:
package sevinge.cursos.reflexion; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class JerarquiaClase { public static void main(String[] args) throws ClassNotFoundException { if (args.length == 0) { System.out.println("Falta el nombre de la clase de la que se debe mostrar la jerarqua"); return; } //Se obtiene un objeto Class de la clase que se ha recibido por parmetro Class clase = Class.forName(args[0]); //Se guarda en una lista la jerarqua de clases List listaJerarquiaClases = new ArrayList(); Class c = clase; while(c!=null) { listaJerarquiaClases.add(0,c); c = c.getSuperclass(); } //Se pintan las clases indentadas String indentancion =" "; Iterator i = listaJerarquiaClases.iterator(); while(i.hasNext()) { Class c2 = (Class) i.next(); System.out.println(indentancion+c2.getName()); //Se incrementa la indentacion indentancion+=indentancion; } } }

Con la llamada a la clase:


java cp . sevinge.cursos.reflexion.JerarquiaClase java.util.Vector

Se obtendra la salida:

java.lang.Object java.util.AbstractCollection java.util.AbstractList java.util.Vector

Tambin se pueden obtener los modificadores con los que ha sido declarada una clase, un constructor, un campo y un mtodo invocando al mtodo getModifiers() de la clase que corresponda (Class, Constructor, Field o Method). El mtodo getModifers() devuelve un entero donde estn codificados todos los modificadores de la declaracin del elemento. Mediante la clase java.lang.reflect.Modifier se puede decoficar lo devuelto por el mtodo getModifiers(). Esta clase cuenta con un conjunto de mtodos estticos, uno para cada modificador vlido, que devuelve bolean: isFinal(), isPublic()... Por ejemplo, el siguiente trozo de cdigo nos dice si el campo nombre de la clase Participante es o no final:
campo = claseParticipante.getField("nombre"); int modificadoresCampo = campo.getModifiers(); boolean esFinal = Modifier.isFinal(modificadoresCampo);

Por ltimo un cuadro con otros mtodos interesantes de la clase Class: Mtodo
boolean isArray()

boolean isInterface() boolean isPrimitive() boolean isInstance(Object obj)

String getName()

Descripcin Devuelve cierto si el objeto Class est asociado an array Devuelve cierto si el objeto Class est asociado an interface Devuelve cierto si el objeto Class est asociado an tipo primitivo Devuelve cierto si el objeto que recibe como parmetro es instancia de la clase a la que est asociada el objeto Class. Este mtodo es equivalente al operador instanceof. Devuelve el nombre cualificado (incluido paquetes) de la clase

Das könnte Ihnen auch gefallen